xref: /aosp_15_r20/external/coreboot/src/soc/sifive/fu540/spi_internal.h (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #ifndef __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__
3 #define __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__
4 
5 #include <stdint.h>
6 
7 #define _ASSERT_SIZEOF(type, size) _Static_assert( \
8 		sizeof(type) == (size), \
9 		#type " must be " #size " bytes wide")
10 
11 #define FU540_SPI_CSMODE_AUTO	0
12 #define FU540_SPI_CSMODE_HOLD	2
13 #define FU540_SPI_CSMODE_OFF	3
14 
15 typedef union {
16 	struct {
17 		uint32_t pha : 1;
18 		uint32_t pol : 1;
19 		uint32_t reserved : 30;
20 	};
21 	uint32_t raw_bits;
22 } spi_reg_sckmode;
23 _ASSERT_SIZEOF(spi_reg_sckmode, 4);
24 
25 typedef union {
26 	struct {
27 		uint32_t mode : 2;
28 		uint32_t reserved : 30;
29 	};
30 	uint32_t raw_bits;
31 } spi_reg_csmode;
32 _ASSERT_SIZEOF(spi_reg_csmode, 4);
33 
34 typedef union {
35 	struct {
36 		uint32_t cssck : 8;
37 		uint32_t reserved0 : 8;
38 		uint32_t sckcs : 8;
39 		uint32_t reserved1 : 8;
40 	};
41 	uint32_t raw_bits;
42 } spi_reg_delay0;
43 _ASSERT_SIZEOF(spi_reg_delay0, 4);
44 
45 typedef union {
46 	struct {
47 		uint32_t intercs : 8;
48 		uint32_t reserved0 : 8;
49 		uint32_t interxfr : 8;
50 		uint32_t reserved1 : 8;
51 	};
52 	uint32_t raw_bits;
53 } spi_reg_delay1;
54 _ASSERT_SIZEOF(spi_reg_delay1, 4);
55 
56 typedef union {
57 	struct {
58 		uint32_t proto : 2;
59 		uint32_t endian : 1;
60 		uint32_t dir : 1;
61 		uint32_t reserved0 : 12;
62 		uint32_t len : 4;
63 		uint32_t reserved1 : 12;
64 	};
65 	uint32_t raw_bits;
66 } spi_reg_fmt;
67 _ASSERT_SIZEOF(spi_reg_fmt, 4);
68 
69 typedef union {
70 	struct {
71 		uint32_t data : 8;
72 		uint32_t reserved : 23;
73 		uint32_t full : 1;
74 	};
75 	uint32_t raw_bits;
76 } spi_reg_txdata;
77 _ASSERT_SIZEOF(spi_reg_txdata, 4);
78 
79 typedef union {
80 	struct {
81 		uint32_t data : 8;
82 		uint32_t reserved : 23;
83 		uint32_t empty : 1;
84 	};
85 	uint32_t raw_bits;
86 } spi_reg_rxdata;
87 _ASSERT_SIZEOF(spi_reg_rxdata, 4);
88 
89 typedef union {
90 	struct {
91 		uint32_t txmark : 3;
92 		uint32_t reserved : 29;
93 	};
94 	uint32_t raw_bits;
95 } spi_reg_txmark;
96 _ASSERT_SIZEOF(spi_reg_txmark, 4);
97 
98 typedef union {
99 	struct {
100 		uint32_t rxmark : 3;
101 		uint32_t reserved : 29;
102 	};
103 	uint32_t raw_bits;
104 } spi_reg_rxmark;
105 _ASSERT_SIZEOF(spi_reg_rxmark, 4);
106 
107 typedef union {
108 	struct {
109 		uint32_t en : 1;
110 		uint32_t reserved : 31;
111 	};
112 	uint32_t raw_bits;
113 } spi_reg_fctrl;
114 _ASSERT_SIZEOF(spi_reg_fctrl, 4);
115 
116 typedef union {
117 	struct {
118 		uint32_t cmd_en : 1;
119 		uint32_t addr_len : 3;
120 		uint32_t pad_cnt : 4;
121 		uint32_t command_proto : 2;
122 		uint32_t addr_proto : 2;
123 		uint32_t data_proto : 2;
124 		uint32_t reserved : 2;
125 		uint32_t command_code : 8;
126 		uint32_t pad_code : 8;
127 	};
128 	uint32_t raw_bits;
129 } spi_reg_ffmt;
130 _ASSERT_SIZEOF(spi_reg_ffmt, 4);
131 
132 typedef union {
133 	struct {
134 		uint32_t txwm : 1;
135 		uint32_t rxwm : 1;
136 		uint32_t reserved : 30;
137 	};
138 	uint32_t raw_bits;
139 } spi_reg_ie;
140 typedef spi_reg_ie spi_reg_ip;
141 _ASSERT_SIZEOF(spi_reg_ie, 4);
142 _ASSERT_SIZEOF(spi_reg_ip, 4);
143 
144 #undef _ASSERT_SIZEOF
145 
146 /**
147  * SPI control register memory map.
148  *
149  * All functions take a pointer to a SPI device's control registers.
150  */
151 struct spi_ctrl {
152 	uint32_t sckdiv;
153 	spi_reg_sckmode sckmode;
154 	uint32_t reserved08;
155 	uint32_t reserved0c;
156 
157 	uint32_t csid;
158 	uint32_t csdef;
159 	spi_reg_csmode csmode;
160 	uint32_t reserved1c;
161 
162 	uint32_t reserved20;
163 	uint32_t reserved24;
164 	spi_reg_delay0 delay0;
165 	spi_reg_delay1 delay1;
166 
167 	uint32_t reserved30;
168 	uint32_t reserved34;
169 	uint32_t reserved38;
170 	uint32_t reserved3c;
171 
172 	spi_reg_fmt fmt;
173 	uint32_t reserved44;
174 	spi_reg_txdata txdata;
175 	spi_reg_rxdata rxdata;
176 
177 	spi_reg_txmark txmark;
178 	spi_reg_rxmark rxmark;
179 	uint32_t reserved58;
180 	uint32_t reserved5c;
181 
182 	spi_reg_fctrl fctrl;
183 	spi_reg_ffmt ffmt;
184 	uint32_t reserved68;
185 	uint32_t reserved6c;
186 
187 	spi_reg_ie ie;
188 	spi_reg_ip ip;
189 };
190 
191 /**
192  * Get smallest clock divisor that divides input_khz to a quotient less than or
193  * equal to max_target_khz;
194  */
195 static inline unsigned int
spi_min_clk_divisor(unsigned int input_khz,unsigned int max_target_khz)196 spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz)
197 {
198 	// f_sck = f_in / (2 * (div + 1)) => div = (f_in / (2*f_sck)) - 1
199 	//
200 	// The nearest integer solution for div requires rounding up as to not
201 	// exceed max_target_khz.
202 	//
203 	// div = ceil(f_in / (2*f_sck)) - 1
204 	//     = floor((f_in - 1 + 2*f_sck) / (2*f_sck)) - 1
205 	//
206 	// This should not overflow as long as (f_in - 1 + 2*f_sck) does not
207 	// exceed 2^32 - 1, which is unlikely since we represent frequencies
208 	// in kHz.
209 	unsigned int quotient =
210 		(input_khz + 2 * max_target_khz - 1) / (2 * max_target_khz);
211 	// Avoid underflow
212 	if (quotient == 0)
213 		return 0;
214 	return quotient - 1;
215 }
216 
217 #endif /* __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ */
218