blob: 461ec6e6ee9fc69ad571428bba8f6b6558327411 [file] [log] [blame]
Maximilian Brune2ccb8e72024-01-14 21:59:27 +06001/* 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
17union 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
27union 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
36union 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
47union 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
58union 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
71union 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
81union 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
91union 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
100union 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
109union 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
118union 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
134union 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
144union 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 */
161struct 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 */
205static inline unsigned int
206fu740_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__ */