• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Chip Select Mode Register (csmode)
12 
13 #define FU740_SPI_CSMODE_AUTO 0
14 #define FU740_SPI_CSMODE_HOLD 2
15 #define FU740_SPI_CSMODE_OFF  3
16 
17 union fu740_spi_reg_sckmode {
18 	struct {
19 		uint32_t pha : 1;
20 		uint32_t pol : 1;
21 		uint32_t reserved : 30;
22 	};
23 	uint32_t raw_bits;
24 };
25 _ASSERT_SIZEOF(union fu740_spi_reg_sckmode, 4);
26 
27 union fu740_spi_reg_csmode {
28 	struct {
29 		uint32_t mode : 2;
30 		uint32_t reserved : 30;
31 	};
32 	uint32_t raw_bits;
33 };
34 _ASSERT_SIZEOF(union fu740_spi_reg_csmode, 4);
35 
36 union fu740_spi_reg_delay0 {
37 	struct {
38 		uint32_t cssck : 8;
39 		uint32_t reserved0 : 8;
40 		uint32_t sckcs : 8;
41 		uint32_t reserved1 : 8;
42 	};
43 	uint32_t raw_bits;
44 };
45 _ASSERT_SIZEOF(union fu740_spi_reg_delay0, 4);
46 
47 union fu740_spi_reg_delay1 {
48 	struct {
49 		uint32_t intercs : 8;
50 		uint32_t reserved0 : 8;
51 		uint32_t interxfr : 8;
52 		uint32_t reserved1 : 8;
53 	};
54 	uint32_t raw_bits;
55 };
56 _ASSERT_SIZEOF(union fu740_spi_reg_delay1, 4);
57 
58 union fu740_spi_reg_fmt {
59 	struct {
60 		uint32_t proto : 2;
61 		uint32_t endian : 1;
62 		uint32_t dir : 1;
63 		uint32_t reserved0 : 12;
64 		uint32_t len : 4;
65 		uint32_t reserved1 : 12;
66 	};
67 	uint32_t raw_bits;
68 };
69 _ASSERT_SIZEOF(union fu740_spi_reg_fmt, 4);
70 
71 union fu740_spi_reg_txdata {
72 	struct {
73 		uint32_t data : 8;
74 		uint32_t reserved : 23;
75 		uint32_t full : 1;
76 	};
77 	uint32_t raw_bits;
78 };
79 _ASSERT_SIZEOF(union fu740_spi_reg_txdata, 4);
80 
81 union fu740_spi_reg_rxdata {
82 	struct {
83 		uint32_t data : 8;
84 		uint32_t reserved : 23;
85 		uint32_t empty : 1;
86 	};
87 	uint32_t raw_bits;
88 };
89 _ASSERT_SIZEOF(union fu740_spi_reg_rxdata, 4);
90 
91 union fu740_spi_reg_txmark {
92 	struct {
93 		uint32_t txmark : 3;
94 		uint32_t reserved : 29;
95 	};
96 	uint32_t raw_bits;
97 };
98 _ASSERT_SIZEOF(union fu740_spi_reg_txmark, 4);
99 
100 union fu740_spi_reg_rxmark {
101 	struct {
102 		uint32_t rxmark : 3;
103 		uint32_t reserved : 29;
104 	};
105 	uint32_t raw_bits;
106 };
107 _ASSERT_SIZEOF(union fu740_spi_reg_rxmark, 4);
108 
109 union fu740_spi_reg_fctrl {
110 	struct {
111 		uint32_t en : 1;
112 		uint32_t reserved : 31;
113 	};
114 	uint32_t raw_bits;
115 };
116 _ASSERT_SIZEOF(union fu740_spi_reg_fctrl, 4);
117 
118 union fu740_spi_reg_ffmt {
119 	struct {
120 		uint32_t cmd_en : 1;
121 		uint32_t addr_len : 3;
122 		uint32_t pad_cnt : 4;
123 		uint32_t cmd_proto : 2;
124 		uint32_t addr_proto : 2;
125 		uint32_t data_proto : 2;
126 		uint32_t reserved : 2;
127 		uint32_t cmd_code : 8;
128 		uint32_t pad_code : 8;
129 	};
130 	uint32_t raw_bits;
131 };
132 _ASSERT_SIZEOF(union fu740_spi_reg_ffmt, 4);
133 
134 union fu740_spi_reg_ie {
135 	struct {
136 		uint32_t txwm : 1;
137 		uint32_t rxwm : 1;
138 		uint32_t reserved : 30;
139 	};
140 	uint32_t raw_bits;
141 };
142 _ASSERT_SIZEOF(union fu740_spi_reg_ie, 4);
143 
144 union fu740_spi_reg_ip {
145 	struct {
146 		uint32_t txwm : 1;
147 		uint32_t rxwm : 1;
148 		uint32_t reserved : 30;
149 	};
150 	uint32_t raw_bits;
151 };
152 _ASSERT_SIZEOF(union fu740_spi_reg_ip, 4);
153 
154 #undef _ASSERT_SIZEOF
155 
156 /**
157  * SPI control register memory map.
158  *
159  * All functions take a pointer to a SPI device's control registers.
160  */
161 struct fu740_spi_ctrl {
162 	uint32_t sckdiv;
163 	union fu740_spi_reg_sckmode sckmode;
164 	uint32_t reserved08;
165 	uint32_t reserved0c;
166 
167 	uint32_t csid;
168 	uint32_t csdef;
169 	union fu740_spi_reg_csmode csmode;
170 	uint32_t reserved1c;
171 
172 	uint32_t reserved20;
173 	uint32_t reserved24;
174 	union fu740_spi_reg_delay0 delay0;
175 	union fu740_spi_reg_delay1 delay1;
176 
177 	uint32_t reserved30;
178 	uint32_t reserved34;
179 	uint32_t reserved38;
180 	uint32_t reserved3c;
181 
182 	union fu740_spi_reg_fmt fmt;
183 	uint32_t reserved44;
184 	union fu740_spi_reg_txdata txdata;
185 	union fu740_spi_reg_rxdata rxdata;
186 
187 	union fu740_spi_reg_txmark txmark;
188 	union fu740_spi_reg_rxmark rxmark;
189 	uint32_t reserved58;
190 	uint32_t reserved5c;
191 
192 	union fu740_spi_reg_fctrl fctrl;
193 	union fu740_spi_reg_ffmt ffmt;
194 	uint32_t reserved68;
195 	uint32_t reserved6c;
196 
197 	union fu740_spi_reg_ie ie;
198 	union fu740_spi_reg_ip ip;
199 };
200 
201 /**
202  * Get smallest clock divisor that divides input_khz to a quotient less than or
203  * equal to max_target_khz;
204  */
205 static inline unsigned int
fu740_spi_min_clk_divisor(unsigned int input_khz,unsigned int max_target_khz)206 fu740_spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz)
207 {
208 	// f_sck = f_in / (2 * (div + 1)) => div = (f_in / (2*f_sck)) - 1
209 	//
210 	// The nearest integer solution for div requires rounding up as to not
211 	// exceed max_target_khz.
212 	//
213 	// div = ceil(f_in / (2*f_sck)) - 1
214 	//     = floor((f_in - 1 + 2*f_sck) / (2*f_sck)) - 1
215 	//
216 	// This should not overflow as long as (f_in - 1 + 2*f_sck) does not
217 	// exceed 2^32 - 1, which is unlikely since we represent frequencies
218 	// in kHz.
219 	unsigned int quotient =
220 		(input_khz + 2 * max_target_khz - 1) / (2 * max_target_khz);
221 	// Avoid underflow
222 	if (quotient == 0)
223 		return 0;
224 	return quotient - 1;
225 }
226 
227 #endif /* __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ */
228