1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "hardware/resets.h"
8 #include "hardware/clocks.h"
9 #include "hardware/spi.h"
10
spi_reset(spi_inst_t * spi)11 static inline void spi_reset(spi_inst_t *spi) {
12 invalid_params_if(HARDWARE_SPI, spi != spi0 && spi != spi1);
13 reset_block_num(spi == spi0 ? RESET_SPI0 : RESET_SPI1);
14 }
15
spi_unreset(spi_inst_t * spi)16 static inline void spi_unreset(spi_inst_t *spi) {
17 invalid_params_if(HARDWARE_SPI, spi != spi0 && spi != spi1);
18 unreset_block_num_wait_blocking(spi == spi0 ? RESET_SPI0 : RESET_SPI1);
19 }
20
spi_init(spi_inst_t * spi,uint baudrate)21 uint spi_init(spi_inst_t *spi, uint baudrate) {
22 spi_reset(spi);
23 spi_unreset(spi);
24
25 uint baud = spi_set_baudrate(spi, baudrate);
26 spi_set_format(spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
27 // Always enable DREQ signals -- harmless if DMA is not listening
28 hw_set_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
29
30 // Finally enable the SPI
31 hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
32
33 return baud;
34 }
35
spi_deinit(spi_inst_t * spi)36 void spi_deinit(spi_inst_t *spi) {
37 hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
38 hw_clear_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
39 spi_reset(spi);
40 }
41
spi_set_baudrate(spi_inst_t * spi,uint baudrate)42 uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) {
43 uint freq_in = clock_get_hz(clk_peri);
44 uint prescale, postdiv;
45 invalid_params_if(HARDWARE_SPI, baudrate > freq_in);
46
47 // Disable the SPI
48 uint32_t enable_mask = spi_get_hw(spi)->cr1 & SPI_SSPCR1_SSE_BITS;
49 hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
50
51 // Find smallest prescale value which puts output frequency in range of
52 // post-divide. Prescale is an even number from 2 to 254 inclusive.
53 for (prescale = 2; prescale <= 254; prescale += 2) {
54 if (freq_in < prescale * 256 * (uint64_t) baudrate)
55 break;
56 }
57 invalid_params_if(HARDWARE_SPI, prescale > 254); // Frequency too low
58
59 // Find largest post-divide which makes output <= baudrate. Post-divide is
60 // an integer in the range 1 to 256 inclusive.
61 for (postdiv = 256; postdiv > 1; --postdiv) {
62 if (freq_in / (prescale * (postdiv - 1)) > baudrate)
63 break;
64 }
65
66 spi_get_hw(spi)->cpsr = prescale;
67 hw_write_masked(&spi_get_hw(spi)->cr0, (postdiv - 1) << SPI_SSPCR0_SCR_LSB, SPI_SSPCR0_SCR_BITS);
68
69 // Re-enable the SPI
70 hw_set_bits(&spi_get_hw(spi)->cr1, enable_mask);
71
72 // Return the frequency we were able to achieve
73 return freq_in / (prescale * postdiv);
74 }
75
spi_get_baudrate(const spi_inst_t * spi)76 uint spi_get_baudrate(const spi_inst_t *spi) {
77 uint prescale = spi_get_const_hw(spi)->cpsr;
78 uint postdiv = ((spi_get_const_hw(spi)->cr0 & SPI_SSPCR0_SCR_BITS) >> SPI_SSPCR0_SCR_LSB) + 1;
79 return clock_get_hz(clk_peri) / (prescale * postdiv);
80 }
81
82 // Write len bytes from src to SPI. Simultaneously read len bytes from SPI to dst.
83 // Note this function is guaranteed to exit in a known amount of time (bits sent * time per bit)
__not_in_flash_func(spi_write_read_blocking)84 int __not_in_flash_func(spi_write_read_blocking)(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len) {
85 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
86
87 // Never have more transfers in flight than will fit into the RX FIFO,
88 // else FIFO will overflow if this code is heavily interrupted.
89 const size_t fifo_depth = 8;
90 size_t rx_remaining = len, tx_remaining = len;
91
92 while (rx_remaining || tx_remaining) {
93 if (tx_remaining && spi_is_writable(spi) && rx_remaining < tx_remaining + fifo_depth) {
94 spi_get_hw(spi)->dr = (uint32_t) *src++;
95 --tx_remaining;
96 }
97 if (rx_remaining && spi_is_readable(spi)) {
98 *dst++ = (uint8_t) spi_get_hw(spi)->dr;
99 --rx_remaining;
100 }
101 }
102
103 return (int)len;
104 }
105
106 // Write len bytes directly from src to the SPI, and discard any data received back
__not_in_flash_func(spi_write_blocking)107 int __not_in_flash_func(spi_write_blocking)(spi_inst_t *spi, const uint8_t *src, size_t len) {
108 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
109 // Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
110 // is full, PL022 inhibits RX pushes, and sets a sticky flag on
111 // push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
112 for (size_t i = 0; i < len; ++i) {
113 while (!spi_is_writable(spi))
114 tight_loop_contents();
115 spi_get_hw(spi)->dr = (uint32_t)src[i];
116 }
117 // Drain RX FIFO, then wait for shifting to finish (which may be *after*
118 // TX FIFO drains), then drain RX FIFO again
119 while (spi_is_readable(spi))
120 (void)spi_get_hw(spi)->dr;
121 while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
122 tight_loop_contents();
123 while (spi_is_readable(spi))
124 (void)spi_get_hw(spi)->dr;
125
126 // Don't leave overrun flag set
127 spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
128
129 return (int)len;
130 }
131
132 // Read len bytes directly from the SPI to dst.
133 // repeated_tx_data is output repeatedly on SO as data is read in from SI.
134 // Generally this can be 0, but some devices require a specific value here,
135 // e.g. SD cards expect 0xff
__not_in_flash_func(spi_read_blocking)136 int __not_in_flash_func(spi_read_blocking)(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len) {
137 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
138 const size_t fifo_depth = 8;
139 size_t rx_remaining = len, tx_remaining = len;
140
141 while (rx_remaining || tx_remaining) {
142 if (tx_remaining && spi_is_writable(spi) && rx_remaining < tx_remaining + fifo_depth) {
143 spi_get_hw(spi)->dr = (uint32_t) repeated_tx_data;
144 --tx_remaining;
145 }
146 if (rx_remaining && spi_is_readable(spi)) {
147 *dst++ = (uint8_t) spi_get_hw(spi)->dr;
148 --rx_remaining;
149 }
150 }
151
152 return (int)len;
153 }
154
155 // Write len halfwords from src to SPI. Simultaneously read len halfwords from SPI to dst.
__not_in_flash_func(spi_write16_read16_blocking)156 int __not_in_flash_func(spi_write16_read16_blocking)(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len) {
157 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
158 // Never have more transfers in flight than will fit into the RX FIFO,
159 // else FIFO will overflow if this code is heavily interrupted.
160 const size_t fifo_depth = 8;
161 size_t rx_remaining = len, tx_remaining = len;
162
163 while (rx_remaining || tx_remaining) {
164 if (tx_remaining && spi_is_writable(spi) && rx_remaining < tx_remaining + fifo_depth) {
165 spi_get_hw(spi)->dr = (uint32_t) *src++;
166 --tx_remaining;
167 }
168 if (rx_remaining && spi_is_readable(spi)) {
169 *dst++ = (uint16_t) spi_get_hw(spi)->dr;
170 --rx_remaining;
171 }
172 }
173
174 return (int)len;
175 }
176
177 // Write len bytes directly from src to the SPI, and discard any data received back
__not_in_flash_func(spi_write16_blocking)178 int __not_in_flash_func(spi_write16_blocking)(spi_inst_t *spi, const uint16_t *src, size_t len) {
179 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
180 // Deliberately overflow FIFO, then clean up afterward, to minimise amount
181 // of APB polling required per halfword
182 for (size_t i = 0; i < len; ++i) {
183 while (!spi_is_writable(spi))
184 tight_loop_contents();
185 spi_get_hw(spi)->dr = (uint32_t)src[i];
186 }
187
188 while (spi_is_readable(spi))
189 (void)spi_get_hw(spi)->dr;
190 while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
191 tight_loop_contents();
192 while (spi_is_readable(spi))
193 (void)spi_get_hw(spi)->dr;
194
195 // Don't leave overrun flag set
196 spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
197
198 return (int)len;
199 }
200
201 // Read len halfwords directly from the SPI to dst.
202 // repeated_tx_data is output repeatedly on SO as data is read in from SI.
__not_in_flash_func(spi_read16_blocking)203 int __not_in_flash_func(spi_read16_blocking)(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len) {
204 invalid_params_if(HARDWARE_SPI, 0 > (int)len);
205 const size_t fifo_depth = 8;
206 size_t rx_remaining = len, tx_remaining = len;
207
208 while (rx_remaining || tx_remaining) {
209 if (tx_remaining && spi_is_writable(spi) && rx_remaining < tx_remaining + fifo_depth) {
210 spi_get_hw(spi)->dr = (uint32_t) repeated_tx_data;
211 --tx_remaining;
212 }
213 if (rx_remaining && spi_is_readable(spi)) {
214 *dst++ = (uint16_t) spi_get_hw(spi)->dr;
215 --rx_remaining;
216 }
217 }
218
219 return (int)len;
220 }
221