source: rtems/bsps/arm/atsam/spi/atsam_spi_bus.c @ ba34ed9c

5
Last change on this file since ba34ed9c was ba34ed9c, checked in by Sebastian Huber <sebastian.huber@…>, on 03/11/19 at 06:12:38

bsp/atsam: Fix use after free

  • Property mode set to 100644
File size: 16.3 KB
RevLine 
[0ab86d09]1/* ---------------------------------------------------------------------------- */
2/*                  Atmel Microcontroller Software Support                      */
3/*                       SAM Software Package License                           */
4/* ---------------------------------------------------------------------------- */
5/* Copyright (c) 2015, Atmel Corporation                                        */
6/* Copyright (c) 2016, embedded brains GmbH                                     */
7/*                                                                              */
8/* All rights reserved.                                                         */
9/*                                                                              */
10/* Redistribution and use in source and binary forms, with or without           */
11/* modification, are permitted provided that the following condition is met:    */
12/*                                                                              */
13/* - Redistributions of source code must retain the above copyright notice,     */
14/* this list of conditions and the disclaimer below.                            */
15/*                                                                              */
16/* Atmel's name may not be used to endorse or promote products derived from     */
17/* this software without specific prior written permission.                     */
18/*                                                                              */
19/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
20/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
21/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
22/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
23/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
24/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
25/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
26/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
27/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
28/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
29/* ---------------------------------------------------------------------------- */
30
[3fbaaa8b]31#include <bsp/atsam-clock-config.h>
[0ab86d09]32#include <bsp/atsam-spi.h>
[6878519]33#include <bsp/iocopy.h>
[0ab86d09]34
[fca9132]35#include <rtems/thread.h>
36
[3afa95b]37#include <dev/spi/spi.h>
38
[b2ed712]39#include <string.h>
40
[0ab86d09]41#define MAX_SPI_FREQUENCY 50000000
42
[6878519]43#define DMA_NR_DESC_PER_DIR 3
44#define DMA_DESC_ALLIGNMENT 4
45
46#define DMA_BUF_RX 0
47#define DMA_BUF_TX 1
48#define DMA_BUF_DIRS 2
49
50struct atsam_spi_xdma_buf {
51  LinkedListDescriporView0 desc[DMA_NR_DESC_PER_DIR];
52  uint8_t leadbuf[CPU_CACHE_LINE_BYTES];
53  uint8_t trailbuf[CPU_CACHE_LINE_BYTES];
54};
55
[3afa95b]56typedef struct {
57  spi_bus base;
[fca9132]58  rtems_binary_semaphore sem;
[de7c171]59  const spi_ioc_transfer *msg_current;
[3afa95b]60  uint32_t msg_todo;
[de7c171]61  int msg_error;
[02926290]62  Spi *spi_regs;
[3afa95b]63  uint32_t dma_tx_channel;
64  uint32_t dma_rx_channel;
[6878519]65  struct atsam_spi_xdma_buf *dma_bufs;
66  size_t leadbuf_rx_buffered_len;
67  size_t trailbuf_rx_buffered_len;
[d1c771c]68  int transfer_in_progress;
[538a0a8]69  bool chip_select_decode;
[02926290]70  uint8_t spi_id;
[923a033f]71  uint32_t peripheral_clk_per_us;
72  uint32_t spi_mr;
[02926290]73  uint32_t spi_csr[4];
[3afa95b]74} atsam_spi_bus;
75
[de7c171]76static void atsam_spi_wakeup_task(atsam_spi_bus *bus)
[0ab86d09]77{
[fca9132]78  rtems_binary_semaphore_post(&bus->sem);
[0ab86d09]79}
80
[923a033f]81static uint8_t atsam_calculate_dlybcs(const atsam_spi_bus *bus)
[0ab86d09]82{
[923a033f]83  uint32_t dlybcs = bus->base.delay_usecs * bus->peripheral_clk_per_us;
84
85  if (dlybcs > 0xff) {
86    dlybcs = 0xff;
87  }
88
89  return dlybcs;
[0ab86d09]90}
91
[8e6cfcc]92static uint32_t atsam_calculate_scbr(uint32_t speed_hz)
93{
94  uint32_t scbr;
95
96  scbr = BOARD_MCK / speed_hz;
97  if (scbr > 0x0FF) {
98    /* Best estimation we can offer with the hardware. */
99    scbr = 0x0FF;
100  }
101  if (scbr == 0) {
102    /* SCBR = 0 isn't allowed. */
103    scbr = 1;
104  }
105
106  return scbr;
107}
108
[0ab86d09]109static void atsam_set_phase_and_polarity(uint32_t mode, uint32_t *csr)
110{
111  uint32_t mode_mask = mode & SPI_MODE_3;
112
113  switch(mode_mask) {
114    case SPI_MODE_0:
115      *csr |= SPI_CSR_NCPHA;
116      break;
117    case SPI_MODE_1:
118      break;
119    case SPI_MODE_2:
120      *csr |= SPI_CSR_NCPHA;
121      *csr |= SPI_CSR_CPOL;
122      break;
123    case SPI_MODE_3:
124      *csr |= SPI_CSR_CPOL;
125      break;
126  }
[24fe213]127  *csr |= SPI_CSR_CSAAT;
[0ab86d09]128}
129
130static void atsam_configure_spi(atsam_spi_bus *bus)
131{
[8e6cfcc]132  uint32_t scbr;
[0ab86d09]133  uint32_t csr = 0;
[923a033f]134  uint32_t mr;
[538a0a8]135  uint32_t cs = bus->base.cs;
[0ab86d09]136
[8e6cfcc]137  scbr = atsam_calculate_scbr(bus->base.speed_hz);
[0ab86d09]138
[923a033f]139  mr = bus->spi_mr;
140
[538a0a8]141  if (bus->chip_select_decode) {
[923a033f]142    mr |= SPI_MR_PCS(bus->base.cs);
143    mr |= SPI_MR_PCSDEC;
[538a0a8]144    cs /= 4;
145  } else {
[923a033f]146    mr |= SPI_PCS(bus->base.cs);
[538a0a8]147  }
148
[923a033f]149  bus->spi_regs->SPI_MR = mr;
[0ab86d09]150
[b934898]151  csr = bus->spi_csr[cs]
152    | SPI_CSR_SCBR(scbr)
153    | SPI_CSR_BITS(bus->base.bits_per_word - 8);
[0ab86d09]154
155  atsam_set_phase_and_polarity(bus->base.mode, &csr);
156
[02926290]157  SPI_ConfigureNPCS(bus->spi_regs, cs, csr);
158}
159
160static void atsam_reset_spi(atsam_spi_bus *bus)
161{
162  bus->spi_regs->SPI_CR = SPI_CR_SPIDIS;
163  bus->spi_regs->SPI_CR = SPI_CR_SWRST;
164  bus->spi_regs->SPI_CR = SPI_CR_SWRST;
165  bus->spi_regs->SPI_CR = SPI_CR_SPIEN;
[0ab86d09]166}
167
[6878519]168static void atsam_spi_check_alignment_and_set_up_dma_descriptors(
169  atsam_spi_bus *bus,
170  struct atsam_spi_xdma_buf *buf,
171  const uint8_t *start,
172  size_t len,
173  bool tx
174)
175{
176  LinkedListDescriporView0 *curdesc = buf->desc;
177  size_t misaligned_begin;
178  size_t misaligned_end;
179  size_t len_main;
180  const uint8_t *start_main;
181  const uint8_t *start_trail;
182
183  /* Check alignments. */
184  if (len < CPU_CACHE_LINE_BYTES) {
185    misaligned_begin = len;
186    misaligned_end = 0;
187    len_main = 0;
188  } else {
189    misaligned_begin = ((uint32_t) start) % CPU_CACHE_LINE_BYTES;
190    misaligned_end = (((uint32_t) start) + len) % CPU_CACHE_LINE_BYTES;
191    len_main = len - misaligned_begin - misaligned_end;
192  }
193  start_main = start + misaligned_begin;
194  start_trail = start_main + len_main;
195
196  /* Store length for copying data back. */
197  if (!tx) {
198    bus->leadbuf_rx_buffered_len = misaligned_begin;
199    bus->trailbuf_rx_buffered_len = misaligned_end;
200  }
201
202  /* Handle misalignment on begin. */
203  if (misaligned_begin != 0) {
204    if (tx) {
205      atsam_copy_to_io(buf->leadbuf, start, misaligned_begin);
206    }
207    curdesc->mbr_nda = (uint32_t) (&curdesc[1]);
208    curdesc->mbr_ta = (uint32_t) buf->leadbuf;
209    curdesc->mbr_ubc = misaligned_begin;
210  }
211
212  /* Main part */
213  if (len_main > 0) {
214    curdesc->mbr_ubc |= tx ? XDMA_UBC_NSEN_UPDATED : XDMA_UBC_NDEN_UPDATED;
215    curdesc->mbr_ubc |= XDMA_UBC_NVIEW_NDV0;
216    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_EN;
217    ++curdesc;
218
219    curdesc->mbr_nda = (uint32_t) (&curdesc[1]);
220    curdesc->mbr_ta = (uint32_t) start_main;
221    curdesc->mbr_ubc = len_main;
222    if (tx) {
223      rtems_cache_flush_multiple_data_lines(start_main, len_main);
224    } else {
225      rtems_cache_invalidate_multiple_data_lines(start_main, len_main);
226    }
227  }
228
229  /* Handle misalignment on end */
230  if (misaligned_end != 0) {
231    curdesc->mbr_ubc |= tx ? XDMA_UBC_NSEN_UPDATED : XDMA_UBC_NDEN_UPDATED;
232    curdesc->mbr_ubc |= XDMA_UBC_NVIEW_NDV0;
233    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_EN;
234    ++curdesc;
235
236    if (tx) {
237      atsam_copy_to_io(buf->trailbuf, start_trail, misaligned_end);
238    }
239    curdesc->mbr_nda = 0;
240    curdesc->mbr_ta = (uint32_t) buf->trailbuf;
241    curdesc->mbr_ubc = misaligned_end;
242    curdesc->mbr_ubc |= XDMA_UBC_NDE_FETCH_DIS;
243  }
244}
245
246static void atsam_spi_copy_back_rx_after_dma_transfer(
247  atsam_spi_bus *bus
248)
249{
250  if (bus->leadbuf_rx_buffered_len != 0) {
251    atsam_copy_from_io(
252      bus->msg_current->rx_buf,
253      bus->dma_bufs[DMA_BUF_RX].leadbuf,
254      bus->leadbuf_rx_buffered_len
255    );
256  }
257  if (bus->trailbuf_rx_buffered_len != 0) {
258    atsam_copy_from_io(
259      bus->msg_current->rx_buf + bus->msg_current->len -
260        bus->trailbuf_rx_buffered_len,
261      bus->dma_bufs[DMA_BUF_RX].trailbuf,
262      bus->trailbuf_rx_buffered_len
263    );
264  }
265}
266
[b52513b]267static void atsam_spi_start_dma_transfer(
268  atsam_spi_bus *bus,
269  const spi_ioc_transfer *msg
270)
271{
[8eb5fbb6]272  Xdmac *pXdmac = XDMAC;
[6878519]273
274  atsam_spi_check_alignment_and_set_up_dma_descriptors(
275    bus,
276    &bus->dma_bufs[DMA_BUF_RX],
277    msg->rx_buf,
278    msg->len,
279    false
280  );
281  atsam_spi_check_alignment_and_set_up_dma_descriptors(
282    bus,
283    &bus->dma_bufs[DMA_BUF_TX],
284    msg->tx_buf,
285    msg->len,
286    true
287  );
288
289  XDMAC_SetDescriptorAddr(
290    pXdmac,
291    bus->dma_rx_channel,
292    (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
293    0
294  );
295  XDMAC_SetDescriptorControl(
296    pXdmac,
297    bus->dma_rx_channel,
298    XDMAC_CNDC_NDVIEW_NDV0 |
299    XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
300    XDMAC_CNDC_NDE_DSCR_FETCH_EN
301  );
302  XDMAC_SetDescriptorAddr(
303    pXdmac,
304    bus->dma_tx_channel,
305    (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
306    0
307  );
308  XDMAC_SetDescriptorControl(
309    pXdmac,
310    bus->dma_tx_channel,
311    XDMAC_CNDC_NDVIEW_NDV0 |
312    XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
313    XDMAC_CNDC_NDE_DSCR_FETCH_EN
314  );
[b52513b]315
316  XDMAC_StartTransfer(pXdmac, bus->dma_rx_channel);
317  XDMAC_StartTransfer(pXdmac, bus->dma_tx_channel);
[0ab86d09]318}
319
[0396f60]320static int atsam_check_configure_spi(atsam_spi_bus *bus, const spi_ioc_transfer *msg)
[0ab86d09]321{
[0396f60]322  if (
323    msg->mode != bus->base.mode
324      || msg->speed_hz != bus->base.speed_hz
325      || msg->bits_per_word != bus->base.bits_per_word
326      || msg->cs != bus->base.cs
327  ) {
328    if (
[85d5f6c]329      (msg->bits_per_word != 8 && msg->bits_per_word != 16)
[0396f60]330        || msg->mode > 3
331        || msg->speed_hz > bus->base.max_speed_hz
[0ab86d09]332    ) {
[0396f60]333      return -EINVAL;
[0ab86d09]334    }
[0396f60]335
336    bus->base.mode = msg->mode;
337    bus->base.speed_hz = msg->speed_hz;
338    bus->base.bits_per_word = msg->bits_per_word;
339    bus->base.cs = msg->cs;
340    atsam_configure_spi(bus);
[0ab86d09]341  }
342
[0396f60]343  return 0;
[0ab86d09]344}
345
[de7c171]346static void atsam_spi_setup_transfer(atsam_spi_bus *bus)
[0ab86d09]347{
348  uint32_t msg_todo = bus->msg_todo;
349
[d1c771c]350  bus->transfer_in_progress = 2;
[0396f60]351
[de7c171]352  if (msg_todo > 0) {
[847638af]353    const spi_ioc_transfer *msg;
[de7c171]354    int error;
[3417070d]355
[847638af]356    msg = bus->msg_current;
[de7c171]357    error = atsam_check_configure_spi(bus, msg);
358    if (error == 0) {
[847638af]359      atsam_spi_start_dma_transfer(bus, msg);
[de7c171]360    } else {
361      bus->msg_error = error;
362      atsam_spi_wakeup_task(bus);
[0ab86d09]363    }
[de7c171]364  } else {
365    atsam_spi_wakeup_task(bus);
[0ab86d09]366  }
[de7c171]367}
[0396f60]368
[d1c771c]369static void atsam_spi_dma_callback(uint32_t channel, void *arg)
[de7c171]370{
371  atsam_spi_bus *bus = (atsam_spi_bus *)arg;
372
[d1c771c]373  --bus->transfer_in_progress;
[8dd83d3]374
[d1c771c]375  if (bus->transfer_in_progress == 0) {
[923a033f]376    const spi_ioc_transfer *msg = bus->msg_current;
377
378    if (msg->delay_usecs != bus->base.delay_usecs) {
379      uint32_t mr;
380      uint32_t mr_dlybcs;
381
382      bus->base.delay_usecs = msg->delay_usecs;
383      mr_dlybcs = SPI_MR_DLYBCS(atsam_calculate_dlybcs(bus));
384      bus->spi_mr = mr_dlybcs | SPI_MR_MSTR | SPI_MR_MODFDIS;
385
386      mr = bus->spi_regs->SPI_MR;
387      mr &= ~SPI_MR_DLYBCS_Msk;
388      mr |= mr_dlybcs;
389      bus->spi_regs->SPI_MR = mr;
390    }
391
[847638af]392    if (msg->cs_change) {
393      bus->spi_regs->SPI_CR = SPI_CR_LASTXFER;
394    }
395
[6878519]396    atsam_spi_copy_back_rx_after_dma_transfer(bus);
[847638af]397
398    bus->msg_current = msg + 1;
399    --bus->msg_todo;
400
[d1c771c]401    atsam_spi_setup_transfer(bus);
[de7c171]402  }
[0ab86d09]403}
404
405static int atsam_spi_transfer(
406  spi_bus *base,
407  const spi_ioc_transfer *msgs,
408  uint32_t msg_count
409)
410{
411  atsam_spi_bus *bus = (atsam_spi_bus *)base;
412
[847638af]413  bus->msg_current = msgs;
[0ab86d09]414  bus->msg_todo = msg_count;
[de7c171]415  bus->msg_error = 0;
416  atsam_spi_setup_transfer(bus);
[fca9132]417  rtems_binary_semaphore_wait(&bus->sem);
[de7c171]418  return bus->msg_error;
[0ab86d09]419}
420
421
422static void atsam_spi_destroy(spi_bus *base)
423{
424  atsam_spi_bus *bus = (atsam_spi_bus *)base;
[d1c771c]425  eXdmadRC rc;
[0ab86d09]426
[d1c771c]427  rc = XDMAD_SetCallback(
[02926290]428    &XDMAD_Instance,
[d1c771c]429    bus->dma_rx_channel,
430    XDMAD_DoNothingCallback,
431    NULL
432  );
433  assert(rc == XDMAD_OK);
[0ab86d09]434
[d1c771c]435  rc = XDMAD_SetCallback(
[02926290]436    &XDMAD_Instance,
[d1c771c]437    bus->dma_tx_channel,
438    XDMAD_DoNothingCallback,
439    NULL
440  );
441  assert(rc == XDMAD_OK);
442
[02926290]443  XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_rx_channel);
444  XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_tx_channel);
[0ab86d09]445
[02926290]446  SPI_Disable(bus->spi_regs);
447  PMC_DisablePeripheral(bus->spi_id);
[5dd02e9]448
[6878519]449  rtems_cache_coherent_free(bus->dma_bufs);
[fca9132]450  rtems_binary_semaphore_destroy(&bus->sem);
[ba34ed9c]451  spi_bus_destroy_and_free(&bus->base);
[0ab86d09]452}
453
454static int atsam_spi_setup(spi_bus *base)
455{
456  atsam_spi_bus *bus = (atsam_spi_bus *)base;
457
458  if (
[85d5f6c]459    bus->base.speed_hz > MAX_SPI_FREQUENCY
460      || (bus->base.bits_per_word != 8 && bus->base.bits_per_word != 16)
[0ab86d09]461  ) {
462      return -EINVAL;
463  }
464  atsam_configure_spi(bus);
465  return 0;
466}
467
[d1c771c]468static void atsam_spi_init_xdma(atsam_spi_bus *bus)
469{
470  sXdmadCfg cfg;
471  uint32_t xdmaInt;
472  uint8_t channel;
473  eXdmadRC rc;
[6878519]474  uint32_t xdma_cndc;
475
476  bus->dma_bufs = rtems_cache_coherent_allocate(
477    DMA_BUF_DIRS * sizeof(*(bus->dma_bufs)),
478    DMA_DESC_ALLIGNMENT,
479    0
480  );
481  assert(bus->dma_bufs != NULL);
[d1c771c]482
483  bus->dma_tx_channel = XDMAD_AllocateChannel(
[02926290]484    &XDMAD_Instance,
[d1c771c]485    XDMAD_TRANSFER_MEMORY,
[02926290]486    bus->spi_id
[d1c771c]487  );
488  assert(bus->dma_tx_channel != XDMAD_ALLOC_FAILED);
489
490  bus->dma_rx_channel = XDMAD_AllocateChannel(
[02926290]491    &XDMAD_Instance,
492    bus->spi_id,
[d1c771c]493    XDMAD_TRANSFER_MEMORY
494  );
495  assert(bus->dma_rx_channel != XDMAD_ALLOC_FAILED);
496
497  rc = XDMAD_SetCallback(
[02926290]498    &XDMAD_Instance,
[d1c771c]499    bus->dma_rx_channel,
500    atsam_spi_dma_callback,
501    bus
502  );
503  assert(rc == XDMAD_OK);
504
505  rc = XDMAD_SetCallback(
[02926290]506    &XDMAD_Instance,
[d1c771c]507    bus->dma_tx_channel,
508    atsam_spi_dma_callback,
509    bus
510  );
511  assert(rc == XDMAD_OK);
512
[02926290]513  rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_rx_channel);
[d1c771c]514  assert(rc == XDMAD_OK);
515
[02926290]516  rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_tx_channel);
[d1c771c]517  assert(rc == XDMAD_OK);
518
[6878519]519  /* Put all relevant interrupts on */
[d1c771c]520  xdmaInt =  (
521    XDMAC_CIE_BIE |
522    XDMAC_CIE_DIE |
523    XDMAC_CIE_FIE |
524    XDMAC_CIE_RBIE |
525    XDMAC_CIE_WBIE |
526    XDMAC_CIE_ROIE);
527
528  /* Setup RX */
529  memset(&cfg, 0, sizeof(cfg));
[02926290]530  channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_RX);
531  cfg.mbr_sa = (uint32_t)&bus->spi_regs->SPI_RDR;
[d1c771c]532  cfg.mbr_cfg =
533    XDMAC_CC_TYPE_PER_TRAN |
534    XDMAC_CC_MBSIZE_SINGLE |
535    XDMAC_CC_DSYNC_PER2MEM |
536    XDMAC_CC_CSIZE_CHK_1 |
537    XDMAC_CC_DWIDTH_BYTE |
538    XDMAC_CC_SIF_AHB_IF1 |
539    XDMAC_CC_DIF_AHB_IF1 |
540    XDMAC_CC_SAM_FIXED_AM |
541    XDMAC_CC_DAM_INCREMENTED_AM |
542    XDMAC_CC_PERID(channel);
[6878519]543  xdma_cndc = XDMAC_CNDC_NDVIEW_NDV0 |
544    XDMAC_CNDC_NDE_DSCR_FETCH_EN |
545    XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
546    XDMAC_CNDC_NDSUP_SRC_PARAMS_UNCHANGED;
[d1c771c]547  rc = XDMAD_ConfigureTransfer(
[02926290]548    &XDMAD_Instance,
[d1c771c]549    bus->dma_rx_channel,
550    &cfg,
[6878519]551    xdma_cndc,
552    (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
[d1c771c]553    xdmaInt
554  );
555  assert(rc == XDMAD_OK);
556
557  /* Setup TX  */
558  memset(&cfg, 0, sizeof(cfg));
[02926290]559  channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_TX);
560  cfg.mbr_da = (uint32_t)&bus->spi_regs->SPI_TDR;
[d1c771c]561  cfg.mbr_cfg =
562    XDMAC_CC_TYPE_PER_TRAN |
563    XDMAC_CC_MBSIZE_SINGLE |
564    XDMAC_CC_DSYNC_MEM2PER |
565    XDMAC_CC_CSIZE_CHK_1 |
566    XDMAC_CC_DWIDTH_BYTE |
567    XDMAC_CC_SIF_AHB_IF1 |
568    XDMAC_CC_DIF_AHB_IF1 |
569    XDMAC_CC_SAM_INCREMENTED_AM |
570    XDMAC_CC_DAM_FIXED_AM |
571    XDMAC_CC_PERID(channel);
[6878519]572  xdma_cndc = XDMAC_CNDC_NDVIEW_NDV0 |
573    XDMAC_CNDC_NDE_DSCR_FETCH_EN |
574    XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED |
575    XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED;
[d1c771c]576  rc = XDMAD_ConfigureTransfer(
[02926290]577    &XDMAD_Instance,
[d1c771c]578    bus->dma_tx_channel,
579    &cfg,
[6878519]580    xdma_cndc,
581    (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
[d1c771c]582    xdmaInt
583  );
584  assert(rc == XDMAD_OK);
585}
586
[0ab86d09]587int spi_bus_register_atsam(
[62e1e0ff]588  const char *bus_path,
[538a0a8]589  const atsam_spi_config *config
[0ab86d09]590)
591{
592  atsam_spi_bus *bus;
[b934898]593  size_t i;
[0ab86d09]594
595  bus = (atsam_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
596  if (bus == NULL) {
597    return -1;
598  }
599
[d1c771c]600  bus->base.transfer = atsam_spi_transfer;
601  bus->base.destroy = atsam_spi_destroy;
602  bus->base.setup = atsam_spi_setup;
603  bus->base.max_speed_hz = MAX_SPI_FREQUENCY;
[62e1e0ff]604  bus->base.bits_per_word = 8;
605  bus->base.speed_hz = bus->base.max_speed_hz;
606  bus->base.cs = 1;
[02926290]607  bus->spi_id = config->spi_peripheral_id;
608  bus->spi_regs = config->spi_regs;
[538a0a8]609  bus->chip_select_decode = config->chip_select_decode;
[923a033f]610  bus->peripheral_clk_per_us = BOARD_MCK / 1000000;
611  bus->spi_mr = SPI_MR_MSTR | SPI_MR_MODFDIS;
[0ab86d09]612
[b934898]613  for (i = 0; i < RTEMS_ARRAY_SIZE(bus->spi_csr); ++i) {
614    if (config->dlybs_in_ns[i] != 0) {
615      bus->spi_csr[i] |= SPI_DLYBS(config->dlybs_in_ns[i], BOARD_MCK);
616    }
617
618    if (config->dlybct_in_ns[i] != 0) {
619      bus->spi_csr[i] |= SPI_DLYBCT(config->dlybct_in_ns[i], BOARD_MCK);
620    }
621  }
622
[fca9132]623  rtems_binary_semaphore_init(&bus->sem, "ATSAM SPI");
[538a0a8]624  PIO_Configure(config->pins, config->pin_count);
625  PMC_EnablePeripheral(config->spi_peripheral_id);
[02926290]626  atsam_reset_spi(bus);
[62e1e0ff]627  atsam_configure_spi(bus);
[49b6931]628  atsam_spi_init_xdma(bus);
[0ab86d09]629
630  return spi_bus_register(&bus->base, bus_path);
631}
Note: See TracBrowser for help on using the repository browser.