altos/stmf0: Complain if the SPI configuration isn't complete
[fw/altos] / src / stmf0 / ao_spi_stm.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20
21 struct ao_spi_stm_info {
22         uint8_t miso_dma_index;
23         uint8_t mosi_dma_index;
24         struct stm_spi *stm_spi;
25 };
26
27 static uint8_t          ao_spi_mutex[STM_NUM_SPI];
28 static uint8_t          ao_spi_index[STM_NUM_SPI];
29
30 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
31         {
32                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
33                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
34                 &stm_spi1
35         },
36         {
37                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
38                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
39                 &stm_spi2
40         }
41 };
42
43 static uint8_t  spi_dev_null;
44
45 #define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) |                           \
46                  (0 << STM_SPI_CR2_LDMA_RX) |                           \
47                  (1 << STM_SPI_CR2_FRXTH) |                             \
48                  (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) |                 \
49                  (0 << STM_SPI_CR2_TXEIE) |                             \
50                  (0 << STM_SPI_CR2_RXNEIE) |                            \
51                  (0 << STM_SPI_CR2_ERRIE) |                             \
52                  (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) |        \
53                  (0 << STM_SPI_CR2_NSSP) |                              \
54                  (0 << STM_SPI_CR2_SSOE))
55
56 #define SPI_CR2_DMA     (SPI_CR2 |                      \
57                          (1 << STM_SPI_CR2_TXDMAEN) |   \
58                          (1 << STM_SPI_CR2_RXDMAEN))
59
60 #define SPI_CR2_SYNC    (SPI_CR2 |                      \
61                          (0 << STM_SPI_CR2_TXDMAEN) |   \
62                          (0 << STM_SPI_CR2_RXDMAEN))
63
64 #if DEBUG
65 static struct {
66         uint8_t task;
67         uint8_t which;
68         AO_TICK_TYPE tick;
69         uint16_t len;
70 } spi_tasks[64];
71 static uint8_t  spi_task_index;
72
73 static void
74 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
75 {
76         uint32_t        sr = stm_spi->sr;
77
78         if (stm_spi != &stm_spi2)
79                 return;
80         spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
81         spi_tasks[spi_task_index].which = which;
82         spi_tasks[spi_task_index].tick = ao_time();
83         spi_tasks[spi_task_index].len = len;
84         spi_task_index = (spi_task_index + 1) & (63);
85         if (sr & (1 << STM_SPI_SR_FRE))
86                 ao_panic(0x40 | 1);
87         if (sr & (1 << STM_SPI_SR_BSY))
88                 ao_panic(0x40 | 2);
89         if (sr & (1 << STM_SPI_SR_OVR))
90                 ao_panic(0x40 | 3);
91         if (sr & (1 << STM_SPI_SR_MODF))
92                 ao_panic(0x40 | 4);
93         if (sr & (1 << STM_SPI_SR_UDR))
94                 ao_panic(0x40 | 5);
95         if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
96                 ao_panic(0x40 | 6);
97         if (sr & (1 << STM_SPI_SR_RXNE))
98                 ao_panic(0x40 | 7);
99         if (which != 5 && which != 6 && which != 13)
100                 if (ao_cur_task->task_id != ao_spi_mutex[1])
101                         ao_panic(0x40 | 8);
102 }
103 #else
104 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
105 #endif
106
107 static void
108 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
109 {
110         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
111         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
112         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
113
114         validate_spi(stm_spi, which, len);
115
116         stm_spi->cr2 = SPI_CR2_DMA;
117
118         ao_dma_start(miso_dma_index);
119         ao_dma_start(mosi_dma_index);
120
121         ao_arch_critical(
122                 while (!ao_dma_done[miso_dma_index])
123                         ao_sleep(&ao_dma_done[miso_dma_index]);
124                 );
125
126         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
127         while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
128
129         validate_spi(stm_spi, which+1, len);
130
131         stm_spi->cr2 = 0;
132
133         ao_dma_done_transfer(mosi_dma_index);
134         ao_dma_done_transfer(miso_dma_index);
135 }
136
137 void
138 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
139 {
140         uint8_t         id = AO_SPI_INDEX(spi_index);
141         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
142         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
143         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
144
145         /* Set up the transmit DMA to deliver data */
146         ao_dma_set_transfer(mosi_dma_index,
147                             &stm_spi->dr,
148                             (void *) block,
149                             len,
150                             (0 << STM_DMA_CCR_MEM2MEM) |
151                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
152                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
153                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
154                             (1 << STM_DMA_CCR_MINC) |
155                             (0 << STM_DMA_CCR_PINC) |
156                             (0 << STM_DMA_CCR_CIRC) |
157                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
158                             (0 << STM_DMA_CCR_TCIE));
159
160         /* Set up the receive DMA -- when this is done, we know the SPI unit
161          * is idle. Without this, we'd have to poll waiting for the BSY bit to
162          * be cleared
163          */
164         ao_dma_set_transfer(miso_dma_index,
165                             &stm_spi->dr,
166                             &spi_dev_null,
167                             len,
168                             (0 << STM_DMA_CCR_MEM2MEM) |
169                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
170                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
171                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
172                             (0 << STM_DMA_CCR_MINC) |
173                             (0 << STM_DMA_CCR_PINC) |
174                             (0 << STM_DMA_CCR_CIRC) |
175                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
176                             (1 << STM_DMA_CCR_TCIE));
177
178         ao_spi_run(id, 1, len);
179 }
180
181 void
182 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
183 {
184         uint8_t         id = AO_SPI_INDEX(spi_index);
185         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
186         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
187         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
188
189         /* Set up the transmit DMA to deliver data */
190         ao_dma_set_transfer(mosi_dma_index,
191                             &stm_spi->dr,
192                             &value,
193                             len,
194                             (0 << STM_DMA_CCR_MEM2MEM) |
195                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
196                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
197                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
198                             (0 << STM_DMA_CCR_MINC) |
199                             (0 << STM_DMA_CCR_PINC) |
200                             (0 << STM_DMA_CCR_CIRC) |
201                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
202                             (0 << STM_DMA_CCR_TCIE));
203
204         /* Set up the receive DMA -- when this is done, we know the SPI unit
205          * is idle. Without this, we'd have to poll waiting for the BSY bit to
206          * be cleared
207          */
208         ao_dma_set_transfer(miso_dma_index,
209                             &stm_spi->dr,
210                             &spi_dev_null,
211                             len,
212                             (0 << STM_DMA_CCR_MEM2MEM) |
213                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
214                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
215                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
216                             (0 << STM_DMA_CCR_MINC) |
217                             (0 << STM_DMA_CCR_PINC) |
218                             (0 << STM_DMA_CCR_CIRC) |
219                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
220                             (1 << STM_DMA_CCR_TCIE));
221
222         ao_spi_run(id, 3, len);
223 }
224
225 void
226 ao_spi_start_bytes(uint8_t spi_index)
227 {
228         uint8_t         id = AO_SPI_INDEX(spi_index);
229         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
230
231         stm_spi->cr2 = SPI_CR2_SYNC;
232         validate_spi(stm_spi, 5, 0xffff);
233 }
234
235 void
236 ao_spi_stop_bytes(uint8_t spi_index)
237 {
238         uint8_t         id = AO_SPI_INDEX(spi_index);
239         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
240
241         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
242                 ;
243         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
244                 ;
245         /* Clear the OVR flag */
246         (void) stm_spi->dr;
247         (void) stm_spi->sr;
248         validate_spi(stm_spi, 6, 0xffff);
249         stm_spi->cr2 = 0;
250 }
251
252 void
253 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
254 {
255         uint8_t         id = AO_SPI_INDEX(spi_index);
256         const uint8_t   *b = block;
257         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
258
259         stm_spi->cr2 = SPI_CR2_SYNC;
260
261         validate_spi(stm_spi, 7, len);
262         while (len--) {
263                 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
264                 stm_spi->dr = *b++;
265         }
266         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
267                 ;
268         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
269                 ;
270         /* Clear the OVR flag */
271         (void) stm_spi->dr;
272         (void) stm_spi->sr;
273         validate_spi(stm_spi, 8, len);
274 }
275
276 void
277 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
278 {
279         uint8_t         id = AO_SPI_INDEX(spi_index);
280         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
281         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
282         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
283
284         spi_dev_null = 0xff;
285
286         /* Set up transmit DMA to make the SPI hardware actually run */
287         ao_dma_set_transfer(mosi_dma_index,
288                             &stm_spi->dr,
289                             &spi_dev_null,
290                             len,
291                             (0 << STM_DMA_CCR_MEM2MEM) |
292                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
293                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
294                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
295                             (0 << STM_DMA_CCR_MINC) |
296                             (0 << STM_DMA_CCR_PINC) |
297                             (0 << STM_DMA_CCR_CIRC) |
298                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
299                             (0 << STM_DMA_CCR_TCIE));
300
301         /* Set up the receive DMA to capture data */
302         ao_dma_set_transfer(miso_dma_index,
303                             &stm_spi->dr,
304                             block,
305                             len,
306                             (0 << STM_DMA_CCR_MEM2MEM) |
307                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
308                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
309                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
310                             (1 << STM_DMA_CCR_MINC) |
311                             (0 << STM_DMA_CCR_PINC) |
312                             (0 << STM_DMA_CCR_CIRC) |
313                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
314                             (1 << STM_DMA_CCR_TCIE));
315
316         ao_spi_run(id, 9, len);
317 }
318
319 void
320 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
321 {
322         uint8_t         id = AO_SPI_INDEX(spi_index);
323         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
324         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
325         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
326
327         /* Set up transmit DMA to send data */
328         ao_dma_set_transfer(mosi_dma_index,
329                             &stm_spi->dr,
330                             out,
331                             len,
332                             (0 << STM_DMA_CCR_MEM2MEM) |
333                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
334                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
335                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
336                             (1 << STM_DMA_CCR_MINC) |
337                             (0 << STM_DMA_CCR_PINC) |
338                             (0 << STM_DMA_CCR_CIRC) |
339                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
340                             (0 << STM_DMA_CCR_TCIE));
341
342         /* Set up the receive DMA to capture data */
343         ao_dma_set_transfer(miso_dma_index,
344                             &stm_spi->dr,
345                             in,
346                             len,
347                             (0 << STM_DMA_CCR_MEM2MEM) |
348                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
349                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
350                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
351                             (1 << STM_DMA_CCR_MINC) |
352                             (0 << STM_DMA_CCR_PINC) |
353                             (0 << STM_DMA_CCR_CIRC) |
354                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
355                             (1 << STM_DMA_CCR_TCIE));
356
357         ao_spi_run(id, 11, len);
358 }
359
360 static void
361 ao_spi_disable_index(uint8_t spi_index)
362 {
363         /* Disable current config
364          */
365         switch (spi_index) {
366         case AO_SPI_1_PA5_PA6_PA7:
367                 stm_gpio_set(&stm_gpioa, 5, 1);
368                 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
369                 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
370                 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
371                 break;
372         case AO_SPI_1_PB3_PB4_PB5:
373                 stm_gpio_set(&stm_gpiob, 3, 1);
374                 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
375                 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
376                 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
377                 break;
378         case AO_SPI_2_PB13_PB14_PB15:
379                 stm_gpio_set(&stm_gpiob, 13, 1);
380                 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
381                 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
382                 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
383                 break;
384         }
385 }
386
387 static void
388 ao_spi_enable_index(uint8_t spi_index)
389 {
390         switch (spi_index) {
391         case AO_SPI_1_PA5_PA6_PA7:
392                 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
393                 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
394                 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
395                 break;
396         case AO_SPI_1_PB3_PB4_PB5:
397                 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
398                 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
399                 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
400                 break;
401         case AO_SPI_2_PB13_PB14_PB15:
402                 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
403                 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
404                 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
405                 break;
406         }
407 }
408
409 static void
410 ao_spi_config(uint8_t spi_index, uint32_t speed)
411 {
412         uint8_t         id = AO_SPI_INDEX(spi_index);
413         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
414
415         if (spi_index != ao_spi_index[id]) {
416
417                 /* Disable old config
418                  */
419                 ao_spi_disable_index(ao_spi_index[id]);
420
421                 /* Enable new config
422                  */
423                 ao_spi_enable_index(spi_index);
424
425                 /* Remember current config
426                  */
427                 ao_spi_index[id] = spi_index;
428         }
429         stm_spi->cr2 = SPI_CR2;
430         stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
431                         (0 << STM_SPI_CR1_BIDIOE) |
432                         (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
433                         (0 << STM_SPI_CR1_CRCNEXT) |
434                         (0 << STM_SPI_CR1_CRCL) |
435                         (0 << STM_SPI_CR1_RXONLY) |
436                         (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
437                         (1 << STM_SPI_CR1_SSI) |                        /*  ... */
438                         (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
439                         (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
440                         (speed << STM_SPI_CR1_BR) |                     /* baud rate to pclk/4 */
441                         (1 << STM_SPI_CR1_MSTR) |
442                         (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
443                         (0 << STM_SPI_CR1_CPHA));
444 }
445
446 uint8_t
447 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
448 {
449         uint8_t         id = AO_SPI_INDEX(spi_index);
450
451         if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
452                 return 0;
453         ao_spi_config(spi_index, speed);
454         return 1;
455 }
456
457 void
458 ao_spi_get(uint8_t spi_index, uint32_t speed)
459 {
460         uint8_t         id = AO_SPI_INDEX(spi_index);
461         ao_mutex_get(&ao_spi_mutex[id]);
462         ao_spi_config(spi_index, speed);
463 }
464
465 void
466 ao_spi_put(uint8_t spi_index)
467 {
468         uint8_t         id = AO_SPI_INDEX(spi_index);
469         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
470
471         stm_spi->cr1 = 0;
472         ao_mutex_put(&ao_spi_mutex[id]);
473 }
474
475 static void
476 ao_spi_channel_init(uint8_t spi_index)
477 {
478         uint8_t         id = AO_SPI_INDEX(spi_index);
479         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
480
481         ao_spi_disable_index(spi_index);
482
483         stm_spi->cr1 = 0;
484         stm_spi->cr2 = SPI_CR2_SYNC;
485
486         /* Clear any pending data and error flags */
487         (void) stm_spi->dr;
488         (void) stm_spi->sr;
489 }
490
491 #if DEBUG
492 void
493 ao_spi_dump_cmd(void)
494 {
495         int s;
496
497         for (s = 0; s < 64; s++) {
498                 int i = (spi_task_index + s) & 63;
499                 if (spi_tasks[i].which) {
500                         int t;
501                         const char *name = "(none)";
502                         for (t = 0; t < ao_num_tasks; t++)
503                                 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
504                                         name = ao_tasks[t]->name;
505                                         break;
506                                 }
507                         printf("%2d: %5d task %2d which %2d len %5d %s\n",
508                                s,
509                                spi_tasks[i].tick,
510                                spi_tasks[i].task,
511                                spi_tasks[i].which,
512                                spi_tasks[i].len,
513                                name);
514                 }
515         }
516         for (s = 0; s < STM_NUM_SPI; s++) {
517                 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
518
519                 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
520                        s, ao_spi_mutex[s], ao_spi_index[s],
521                        ao_spi_stm_info[s].miso_dma_index,
522                        ao_spi_stm_info[s].mosi_dma_index);
523                 printf(" cr1 %04x cr2 %02x sr %03x\n",
524                        spi->cr1, spi->cr2, spi->sr);
525         }
526
527 }
528
529 static const struct ao_cmds ao_spi_cmds[] = {
530         { ao_spi_dump_cmd,      "S\0Dump SPI status" },
531         { 0, NULL }
532 };
533 #endif
534
535 void
536 ao_spi_init(void)
537 {
538 #if HAS_SPI_1
539 #ifndef SPI_1_PA5_PA6_PA7
540 #error SPI_1_PA5_PA6_PA7 undefined
541 #endif
542 # if SPI_1_PA5_PA6_PA7
543         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
544         stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
545         stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
546         stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
547 # endif
548 # ifndef SPI_1_PB3_PB4_PB5
549 # error SPI_1_PB3_PB4_PB5 undefined
550 # endif
551 # if SPI_1_PB3_PB4_PB5
552         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
553         stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
554         stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
555         stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
556 # endif
557         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
558         ao_spi_index[0] = AO_SPI_CONFIG_NONE;
559         ao_spi_channel_init(STM_SPI_INDEX(1));
560 #endif
561
562 #if HAS_SPI_2
563 # if SPI_2_PB10_PB13_PB14
564         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
565         stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
566         stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
567         stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
568 # endif
569         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
570         ao_spi_index[1] = AO_SPI_CONFIG_NONE;
571         ao_spi_channel_init(STM_SPI_INDEX(2));
572 #endif
573 #if DEBUG
574         ao_cmd_register(&ao_spi_cmds[0]);
575 #endif
576 }