Changeset a5f84c6a in rtems


Ignore:
Timestamp:
Mar 19, 2019, 9:04:33 AM (5 weeks ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
dad6fd4
Parents:
5f813694
git-author:
Sebastian Huber <sebastian.huber@…> (03/19/19 09:04:33)
git-committer:
Sebastian Huber <sebastian.huber@…> (03/19/19 10:29:24)
Message:

bsp/atsam: Fix SPI driver DMA support

File:
1 edited

Legend:

Unmodified
Added
Removed
  • bsps/arm/atsam/spi/atsam_spi_bus.c

    r5f813694 ra5f84c6a  
    4141#define MAX_SPI_FREQUENCY 50000000
    4242
    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 
    50 struct 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 };
     43typedef struct {
     44  volatile LinkedListDescriporView0 tx_desc;
     45  volatile LinkedListDescriporView0 rx_desc[3];
     46  uint8_t rx_bounce_head_buf[CPU_CACHE_LINE_BYTES];
     47  uint8_t rx_bounce_tail_buf[CPU_CACHE_LINE_BYTES];
     48} atsam_spi_dma;
    5549
    5650typedef struct {
     
    5953  const spi_ioc_transfer *msg_current;
    6054  uint32_t msg_todo;
    61   int msg_error;
     55  int error;
    6256  Spi *spi_regs;
    6357  uint32_t dma_tx_channel;
    6458  uint32_t dma_rx_channel;
    65   struct atsam_spi_xdma_buf *dma_bufs;
    66   size_t leadbuf_rx_buffered_len;
    67   size_t trailbuf_rx_buffered_len;
     59  atsam_spi_dma *dma;
     60  size_t rx_bounce_head_len;
     61  size_t rx_bounce_tail_len;
    6862  int transfer_in_progress;
    6963  bool chip_select_decode;
     
    166160}
    167161
    168 static void atsam_spi_check_alignment_and_set_up_dma_descriptors(
     162static void atsam_spi_copy_rx_bounce_bufs(
     163  const atsam_spi_bus *bus,
     164  const spi_ioc_transfer *msg
     165)
     166{
     167  if (bus->rx_bounce_head_len > 0) {
     168    atsam_copy_from_io(
     169      msg->rx_buf,
     170      bus->dma->rx_bounce_head_buf,
     171      bus->rx_bounce_head_len
     172    );
     173  }
     174
     175  if (bus->rx_bounce_tail_len > 0) {
     176    atsam_copy_from_io(
     177      msg->rx_buf + msg->len - bus->rx_bounce_tail_len,
     178      bus->dma->rx_bounce_tail_buf,
     179      bus->rx_bounce_tail_len
     180    );
     181  }
     182}
     183
     184static void atsam_spi_setup_rx_dma_desc(
    169185  atsam_spi_bus *bus,
    170   struct atsam_spi_xdma_buf *buf,
    171   const uint8_t *start,
    172   size_t len,
    173   bool tx
     186  atsam_spi_dma *dma,
     187  const uint8_t *buf,
     188  size_t n
    174189)
    175190{
    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;
     191  volatile LinkedListDescriporView0 *desc;
     192  uintptr_t m;
     193  uintptr_t b;
     194  uintptr_t a;
     195  uintptr_t ae;
     196  uintptr_t e;
     197
     198  desc = &dma->rx_desc[0];
     199  m = CPU_CACHE_LINE_BYTES - 1;
     200  b = (uintptr_t) buf;
     201  e = b + n;
     202  a = (b + m) & ~m;
     203  ae = e & ~m;
     204
     205  if (n <= m) {
     206    bus->rx_bounce_head_len = n;
     207    bus->rx_bounce_tail_len = 0;
     208
     209    desc[0].mbr_ta = (uint32_t) dma->rx_bounce_head_buf;
     210    desc[0].mbr_ubc = n;
    188211  } 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);
     212    bus->rx_bounce_head_len = a - b;
     213    bus->rx_bounce_tail_len = e & m;
     214
     215    if ((b & m) == 0) {
     216      if ((n & m) == 0) {
     217        desc[0].mbr_ta = a;
     218        desc[0].mbr_ubc = n;
     219      } else {
     220        desc[0].mbr_ta = a;
     221        desc[0].mbr_ubc = (ae - a) | XDMA_UBC_NDEN_UPDATED
     222          | XDMA_UBC_NVIEW_NDV0
     223          | XDMA_UBC_NDE_FETCH_EN;
     224        desc[1].mbr_ta = (uint32_t) dma->rx_bounce_tail_buf;
     225        desc[1].mbr_ubc = n & m;
     226      }
    224227    } 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 
    246 static void atsam_spi_copy_back_rx_after_dma_transfer(
    247   atsam_spi_bus *bus
     228      if ((e & m) == 0) {
     229        desc[0].mbr_ta = (uint32_t) dma->rx_bounce_head_buf;
     230        desc[0].mbr_ubc = (a - b) | XDMA_UBC_NDEN_UPDATED
     231          | XDMA_UBC_NVIEW_NDV0
     232          | XDMA_UBC_NDE_FETCH_EN;
     233        desc[1].mbr_ta = a;
     234        desc[1].mbr_ubc = ae - a;
     235      } else if ((ae - a) == 0) {
     236        bus->rx_bounce_head_len = n;
     237        bus->rx_bounce_tail_len = 0;
     238
     239        desc[0].mbr_ta = (uint32_t) dma->rx_bounce_head_buf;
     240        desc[0].mbr_ubc = n;
     241      } else {
     242        desc[0].mbr_ta = (uint32_t) dma->rx_bounce_head_buf;
     243        desc[0].mbr_ubc = (a - b) | XDMA_UBC_NDEN_UPDATED
     244          | XDMA_UBC_NVIEW_NDV0
     245          | XDMA_UBC_NDE_FETCH_EN;
     246        desc[1].mbr_ta = a;
     247        desc[1].mbr_ubc = (ae - a) | XDMA_UBC_NDEN_UPDATED
     248          | XDMA_UBC_NVIEW_NDV0
     249          | XDMA_UBC_NDE_FETCH_EN;
     250        desc[2].mbr_ta = (uint32_t) dma->rx_bounce_tail_buf;
     251        desc[2].mbr_ubc = e - ae;
     252      }
     253    }
     254
     255    rtems_cache_invalidate_multiple_data_lines((void *) a, ae - a);
     256  }
     257}
     258
     259static void atsam_spi_setup_tx_dma_desc(
     260  atsam_spi_dma *dma,
     261  const uint8_t *buf,
     262  size_t n
    248263)
    249264{
    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  volatile LinkedListDescriporView0 *desc;
     266
     267  desc = &dma->tx_desc;
     268  desc->mbr_ta = (uint32_t) buf;
     269  desc->mbr_ubc = n;
     270
     271  rtems_cache_flush_multiple_data_lines(buf, n);
    265272}
    266273
     
    270277)
    271278{
    272   Xdmac *pXdmac = XDMAC;
    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   );
     279  atsam_spi_dma *dma;
     280  Xdmac *pXdmac;
     281
     282  dma = bus->dma;
     283  pXdmac = XDMAC;
     284
     285  bus->transfer_in_progress = 2;
     286
     287  atsam_spi_setup_rx_dma_desc(bus, dma, msg->rx_buf, msg->len);
     288  atsam_spi_setup_tx_dma_desc(dma, msg->tx_buf, msg->len);
    288289
    289290  XDMAC_SetDescriptorAddr(
    290291    pXdmac,
    291292    bus->dma_rx_channel,
    292     (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
     293    (uint32_t) &dma->rx_desc[0],
    293294    0
    294295  );
     
    303304    pXdmac,
    304305    bus->dma_tx_channel,
    305     (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
     306    (uint32_t) &dma->tx_desc,
    306307    0
    307308  );
     
    327328  ) {
    328329    if (
    329       (msg->bits_per_word != 8 && msg->bits_per_word != 16)
     330      msg->bits_per_word != 8
    330331        || msg->mode > 3
    331332        || msg->speed_hz > bus->base.max_speed_hz
     
    348349  uint32_t msg_todo = bus->msg_todo;
    349350
    350   bus->transfer_in_progress = 2;
    351 
    352351  if (msg_todo > 0) {
    353352    const spi_ioc_transfer *msg;
     
    359358      atsam_spi_start_dma_transfer(bus, msg);
    360359    } else {
    361       bus->msg_error = error;
     360      bus->error = error;
    362361      atsam_spi_wakeup_task(bus);
    363362    }
     
    367366}
    368367
    369 static void atsam_spi_dma_callback(uint32_t channel, void *arg)
    370 {
    371   atsam_spi_bus *bus = (atsam_spi_bus *)arg;
     368static void atsam_spi_dma_callback(uint32_t ch, void *arg, uint32_t status)
     369{
     370  atsam_spi_bus *bus;
     371  uint32_t dma_errors;
     372
     373  bus = arg;
     374  dma_errors = XDMAC_CIE_DIE | XDMAC_CIE_FIE | XDMAC_CIE_RBIE | XDMAC_CIE_WBIE
     375    | XDMAC_CIE_ROIE;
     376
     377  if ((status & dma_errors) != 0) {
     378    bus->error = -EIO;
     379  }
    372380
    373381  --bus->transfer_in_progress;
     
    394402    }
    395403
    396     atsam_spi_copy_back_rx_after_dma_transfer(bus);
     404    atsam_spi_copy_rx_bounce_bufs(bus, msg);
    397405
    398406    bus->msg_current = msg + 1;
    399407    --bus->msg_todo;
    400408
    401     atsam_spi_setup_transfer(bus);
     409    if (bus->error == 0) {
     410      atsam_spi_setup_transfer(bus);
     411    } else {
     412      atsam_spi_wakeup_task(bus);
     413    }
    402414  }
    403415}
     
    413425  bus->msg_current = msgs;
    414426  bus->msg_todo = msg_count;
    415   bus->msg_error = 0;
     427  bus->error = 0;
    416428  atsam_spi_setup_transfer(bus);
    417429  rtems_binary_semaphore_wait(&bus->sem);
    418   return bus->msg_error;
     430  return bus->error;
    419431}
    420432
     
    447459  PMC_DisablePeripheral(bus->spi_id);
    448460
    449   rtems_cache_coherent_free(bus->dma_bufs);
     461  rtems_cache_coherent_free(bus->dma);
    450462  rtems_binary_semaphore_destroy(&bus->sem);
    451463  spi_bus_destroy_and_free(&bus->base);
     
    458470  if (
    459471    bus->base.speed_hz > MAX_SPI_FREQUENCY
    460       || (bus->base.bits_per_word != 8 && bus->base.bits_per_word != 16)
     472      || bus->base.bits_per_word != 8
    461473  ) {
    462474      return -EINVAL;
     
    468480static void atsam_spi_init_xdma(atsam_spi_bus *bus)
    469481{
     482  atsam_spi_dma *dma;
    470483  sXdmadCfg cfg;
    471484  uint32_t xdmaInt;
     
    474487  uint32_t xdma_cndc;
    475488
    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);
     489  dma = rtems_cache_coherent_allocate(sizeof(*dma), 0, 0);
     490  assert(dma != NULL);
     491  bus->dma = dma;
     492
     493  dma->tx_desc.mbr_nda = 0;
     494  dma->rx_desc[0].mbr_nda = (uint32_t) &dma->rx_desc[1];
     495  dma->rx_desc[1].mbr_nda = (uint32_t) &dma->rx_desc[2];
     496  dma->rx_desc[2].mbr_nda = 0;
    482497
    483498  bus->dma_tx_channel = XDMAD_AllocateChannel(
     
    518533
    519534  /* Put all relevant interrupts on */
    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);
     535  xdmaInt = XDMAC_CIE_LIE | XDMAC_CIE_DIE | XDMAC_CIE_FIE | XDMAC_CIE_RBIE
     536    | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE;
    527537
    528538  /* Setup RX */
     
    550560    &cfg,
    551561    xdma_cndc,
    552     (uint32_t) bus->dma_bufs[DMA_BUF_RX].desc,
     562    (uint32_t) &bus->dma->rx_desc[0],
    553563    xdmaInt
    554564  );
     
    579589    &cfg,
    580590    xdma_cndc,
    581     (uint32_t) bus->dma_bufs[DMA_BUF_TX].desc,
     591    (uint32_t) &bus->dma->tx_desc,
    582592    xdmaInt
    583593  );
Note: See TracChangeset for help on using the changeset viewer.