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