blob: 96124c1fdfba5efd2f5f6762eb163881a457a264 [file] [log] [blame]
Angel Pons5de47d02020-04-04 18:51:30 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Xiang Wangf4e15832019-05-29 15:39:48 +08002#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
15typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080025typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080034typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080045typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080056typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080069typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080079typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080089typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +080098typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +0800107typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +0800116typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +0800132typedef 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;
140typedef 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
Xiang Wangf4e15832019-05-29 15:39:48 +0800146/**
147 * SPI control register memory map.
148 *
149 * All functions take a pointer to a SPI device's control registers.
150 */
151struct 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 */
195static inline unsigned int
196spi_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__ */