File indexing completed on 2025-05-11 08:22:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <bsp/atsam-clock-config.h>
0032 #include <bsp/atsam-spi.h>
0033 #include <bsp/iocopy.h>
0034
0035 #include <rtems/thread.h>
0036
0037 #include <dev/spi/spi.h>
0038
0039 #include <string.h>
0040
0041 #define MAX_SPI_FREQUENCY 50000000
0042
0043 typedef struct {
0044 volatile LinkedListDescriporView2 tx_desc;
0045 volatile LinkedListDescriporView2 rx_desc[3];
0046 uint8_t rx_bounce_head_buf[CPU_CACHE_LINE_BYTES];
0047 uint8_t rx_bounce_tail_buf[CPU_CACHE_LINE_BYTES];
0048 } atsam_spi_dma;
0049
0050 typedef struct {
0051 spi_bus base;
0052 rtems_binary_semaphore sem;
0053 const spi_ioc_transfer *msg_current;
0054 uint32_t msg_todo;
0055 int error;
0056 Spi *spi_regs;
0057 uint32_t dma_tx_channel;
0058 uint32_t dma_rx_channel;
0059 atsam_spi_dma *dma;
0060 size_t rx_bounce_head_len;
0061 size_t rx_bounce_tail_len;
0062 int transfer_in_progress;
0063 bool chip_select_decode;
0064 uint8_t spi_id;
0065 uint32_t peripheral_clk_per_us;
0066 uint32_t spi_mr;
0067 uint32_t spi_csr[4];
0068 } atsam_spi_bus;
0069
0070 static const uint32_t atsam_spi_dummy_write_data = 0xffffffff;
0071
0072 static void atsam_spi_wakeup_task(atsam_spi_bus *bus)
0073 {
0074 rtems_binary_semaphore_post(&bus->sem);
0075 }
0076
0077 static uint8_t atsam_calculate_dlybcs(const atsam_spi_bus *bus)
0078 {
0079 uint32_t dlybcs = bus->base.delay_usecs * bus->peripheral_clk_per_us;
0080
0081 if (dlybcs > 0xff) {
0082 dlybcs = 0xff;
0083 }
0084
0085 return dlybcs;
0086 }
0087
0088 static uint32_t atsam_calculate_scbr(uint32_t speed_hz)
0089 {
0090 uint32_t scbr;
0091
0092 scbr = BOARD_MCK / speed_hz;
0093 if (scbr > 0x0FF) {
0094
0095 scbr = 0x0FF;
0096 }
0097 if (scbr == 0) {
0098
0099 scbr = 1;
0100 }
0101
0102 return scbr;
0103 }
0104
0105 static void atsam_set_phase_and_polarity(uint32_t mode, uint32_t *csr)
0106 {
0107 uint32_t mode_mask = mode & SPI_MODE_3;
0108
0109 switch(mode_mask) {
0110 case SPI_MODE_0:
0111 *csr |= SPI_CSR_NCPHA;
0112 break;
0113 case SPI_MODE_1:
0114 break;
0115 case SPI_MODE_2:
0116 *csr |= SPI_CSR_NCPHA;
0117 *csr |= SPI_CSR_CPOL;
0118 break;
0119 case SPI_MODE_3:
0120 *csr |= SPI_CSR_CPOL;
0121 break;
0122 }
0123 *csr |= SPI_CSR_CSAAT;
0124 }
0125
0126 static void atsam_configure_spi(atsam_spi_bus *bus)
0127 {
0128 uint32_t scbr;
0129 uint32_t csr = 0;
0130 uint32_t mr;
0131 uint32_t cs = bus->base.cs;
0132
0133 scbr = atsam_calculate_scbr(bus->base.speed_hz);
0134
0135 mr = bus->spi_mr;
0136
0137 if (bus->chip_select_decode) {
0138 mr |= SPI_MR_PCS(bus->base.cs);
0139 mr |= SPI_MR_PCSDEC;
0140 cs /= 4;
0141 } else {
0142 mr |= SPI_PCS(bus->base.cs);
0143 }
0144
0145 bus->spi_regs->SPI_MR = mr;
0146
0147 csr = bus->spi_csr[cs]
0148 | SPI_CSR_SCBR(scbr)
0149 | SPI_CSR_BITS(bus->base.bits_per_word - 8);
0150
0151 atsam_set_phase_and_polarity(bus->base.mode, &csr);
0152
0153 SPI_ConfigureNPCS(bus->spi_regs, cs, csr);
0154 }
0155
0156 static void atsam_reset_spi(atsam_spi_bus *bus)
0157 {
0158 bus->spi_regs->SPI_CR = SPI_CR_SPIDIS;
0159 bus->spi_regs->SPI_CR = SPI_CR_SWRST;
0160 bus->spi_regs->SPI_CR = SPI_CR_SWRST;
0161 bus->spi_regs->SPI_CR = SPI_CR_SPIEN;
0162 }
0163
0164 static void atsam_spi_copy_rx_bounce_bufs(
0165 const atsam_spi_bus *bus,
0166 const spi_ioc_transfer *msg
0167 )
0168 {
0169 if (bus->rx_bounce_head_len > 0) {
0170 atsam_copy_from_io(
0171 msg->rx_buf,
0172 bus->dma->rx_bounce_head_buf,
0173 bus->rx_bounce_head_len
0174 );
0175 }
0176
0177 if (bus->rx_bounce_tail_len > 0) {
0178 atsam_copy_from_io(
0179 msg->rx_buf + msg->len - bus->rx_bounce_tail_len,
0180 bus->dma->rx_bounce_tail_buf,
0181 bus->rx_bounce_tail_len
0182 );
0183 }
0184 }
0185
0186 static void atsam_spi_setup_real_rx_dma_desc(
0187 atsam_spi_bus *bus,
0188 atsam_spi_dma *dma,
0189 const uint8_t *buf,
0190 size_t n
0191 )
0192 {
0193 volatile LinkedListDescriporView2 *desc;
0194 uintptr_t m;
0195 uintptr_t b;
0196 uintptr_t a;
0197 uintptr_t ae;
0198 uintptr_t e;
0199
0200 desc = &dma->rx_desc[0];
0201 m = CPU_CACHE_LINE_BYTES - 1;
0202 b = (uintptr_t) buf;
0203 e = b + n;
0204 a = (b + m) & ~m;
0205 ae = e & ~m;
0206
0207
0208 desc[0].mbr_cfg =
0209 (desc[0].mbr_cfg & ~XDMAC_CC_DAM_Msk) | XDMAC_CC_DAM_INCREMENTED_AM;
0210 if (n <= m) {
0211 bus->rx_bounce_head_len = n;
0212 bus->rx_bounce_tail_len = 0;
0213
0214 desc[0].mbr_da = (uint32_t) dma->rx_bounce_head_buf;
0215 desc[0].mbr_ubc = n | XDMA_UBC_NVIEW_NDV2;
0216 } else {
0217 bus->rx_bounce_head_len = a - b;
0218 bus->rx_bounce_tail_len = e & m;
0219
0220 if ((b & m) == 0) {
0221 if ((n & m) == 0) {
0222 desc[0].mbr_da = a;
0223 desc[0].mbr_ubc = n | XDMA_UBC_NVIEW_NDV2;
0224 } else {
0225 desc[0].mbr_da = a;
0226 desc[0].mbr_ubc = (ae - a) | XDMA_UBC_NDEN_UPDATED
0227 | XDMA_UBC_NVIEW_NDV2
0228 | XDMA_UBC_NDE_FETCH_EN;
0229 desc[1].mbr_da = (uint32_t) dma->rx_bounce_tail_buf;
0230 desc[1].mbr_ubc = n & m | XDMA_UBC_NVIEW_NDV2;
0231 }
0232 } else {
0233 if ((e & m) == 0) {
0234 desc[0].mbr_da = (uint32_t) dma->rx_bounce_head_buf;
0235 desc[0].mbr_ubc = (a - b) | XDMA_UBC_NDEN_UPDATED
0236 | XDMA_UBC_NVIEW_NDV2
0237 | XDMA_UBC_NDE_FETCH_EN;
0238 desc[1].mbr_da = a;
0239 desc[1].mbr_ubc = ae - a | XDMA_UBC_NVIEW_NDV2;
0240 } else if ((ae - a) == 0) {
0241 bus->rx_bounce_head_len = n;
0242 bus->rx_bounce_tail_len = 0;
0243
0244 desc[0].mbr_da = (uint32_t) dma->rx_bounce_head_buf;
0245 desc[0].mbr_ubc = n | XDMA_UBC_NVIEW_NDV2;
0246 } else {
0247 desc[0].mbr_da = (uint32_t) dma->rx_bounce_head_buf;
0248 desc[0].mbr_ubc = (a - b) | XDMA_UBC_NDEN_UPDATED
0249 | XDMA_UBC_NVIEW_NDV2
0250 | XDMA_UBC_NDE_FETCH_EN;
0251 desc[1].mbr_da = a;
0252 desc[1].mbr_ubc = (ae - a) | XDMA_UBC_NDEN_UPDATED
0253 | XDMA_UBC_NVIEW_NDV2
0254 | XDMA_UBC_NDE_FETCH_EN;
0255 desc[2].mbr_da = (uint32_t) dma->rx_bounce_tail_buf;
0256 desc[2].mbr_ubc = e - ae | XDMA_UBC_NVIEW_NDV2;
0257 }
0258 }
0259
0260 rtems_cache_invalidate_multiple_data_lines((void *) a, ae - a);
0261 }
0262 }
0263
0264 static void atsam_spi_setup_dummy_rx_dma_desc(
0265 atsam_spi_bus *bus,
0266 atsam_spi_dma *dma,
0267 size_t n
0268 )
0269 {
0270 volatile LinkedListDescriporView2 *desc;
0271
0272 desc = &dma->rx_desc[0];
0273
0274
0275 bus->rx_bounce_head_len = 0;
0276 bus->rx_bounce_tail_len = 0;
0277
0278
0279 desc[0].mbr_da = (uint32_t) dma->rx_bounce_head_buf;
0280 desc[0].mbr_ubc = n | XDMA_UBC_NVIEW_NDV2;
0281 desc[0].mbr_cfg =
0282 (desc[0].mbr_cfg & ~XDMAC_CC_DAM_Msk) | XDMAC_CC_DAM_FIXED_AM;
0283 }
0284
0285 static void atsam_spi_setup_rx_dma_desc(
0286 atsam_spi_bus *bus,
0287 atsam_spi_dma *dma,
0288 const uint8_t *buf,
0289 size_t n
0290 )
0291 {
0292 if (buf != NULL) {
0293 atsam_spi_setup_real_rx_dma_desc(bus, dma, buf, n);
0294 } else {
0295 atsam_spi_setup_dummy_rx_dma_desc(bus, dma, n);
0296 }
0297 }
0298
0299 static void atsam_spi_setup_tx_dma_desc(
0300 atsam_spi_dma *dma,
0301 const uint8_t *buf,
0302 size_t n
0303 )
0304 {
0305 volatile LinkedListDescriporView2 *desc;
0306
0307 desc = &dma->tx_desc;
0308 desc->mbr_ubc = n | XDMA_UBC_NVIEW_NDV2;
0309 if (buf != NULL) {
0310 desc->mbr_sa = (uint32_t) buf;
0311 desc->mbr_cfg =
0312 (desc->mbr_cfg & ~XDMAC_CC_SAM_Msk) | XDMAC_CC_SAM_INCREMENTED_AM;
0313 rtems_cache_flush_multiple_data_lines(buf, n);
0314 } else {
0315 desc->mbr_sa = (uint32_t)&atsam_spi_dummy_write_data;
0316 desc->mbr_cfg =
0317 (desc->mbr_cfg & ~XDMAC_CC_SAM_Msk) | XDMAC_CC_SAM_FIXED_AM;
0318 }
0319 }
0320
0321 static void atsam_spi_start_dma_transfer(
0322 atsam_spi_bus *bus,
0323 const spi_ioc_transfer *msg
0324 )
0325 {
0326 atsam_spi_dma *dma;
0327 Xdmac *pXdmac;
0328
0329 dma = bus->dma;
0330 pXdmac = XDMAC;
0331
0332 bus->transfer_in_progress = 2;
0333
0334 atsam_spi_setup_rx_dma_desc(bus, dma, msg->rx_buf, msg->len);
0335 atsam_spi_setup_tx_dma_desc(dma, msg->tx_buf, msg->len);
0336
0337 XDMAC_SetDescriptorAddr(
0338 pXdmac,
0339 bus->dma_rx_channel,
0340 (uint32_t) &dma->rx_desc[0],
0341 0
0342 );
0343 XDMAC_SetDescriptorControl(
0344 pXdmac,
0345 bus->dma_rx_channel,
0346 XDMAC_CNDC_NDVIEW_NDV2 |
0347 XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
0348 XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
0349 XDMAC_CNDC_NDE_DSCR_FETCH_EN
0350 );
0351 XDMAC_SetDescriptorAddr(
0352 pXdmac,
0353 bus->dma_tx_channel,
0354 (uint32_t) &dma->tx_desc,
0355 0
0356 );
0357 XDMAC_SetDescriptorControl(
0358 pXdmac,
0359 bus->dma_tx_channel,
0360 XDMAC_CNDC_NDVIEW_NDV2 |
0361 XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
0362 XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
0363 XDMAC_CNDC_NDE_DSCR_FETCH_EN
0364 );
0365
0366 XDMAC_StartTransfer(pXdmac, bus->dma_rx_channel);
0367 XDMAC_StartTransfer(pXdmac, bus->dma_tx_channel);
0368 }
0369
0370 static int atsam_check_configure_spi(atsam_spi_bus *bus, const spi_ioc_transfer *msg)
0371 {
0372 if (
0373 msg->mode != bus->base.mode
0374 || msg->speed_hz != bus->base.speed_hz
0375 || msg->bits_per_word != bus->base.bits_per_word
0376 || msg->cs != bus->base.cs
0377 ) {
0378 if (
0379 msg->bits_per_word != 8
0380 || msg->mode > 3
0381 || msg->speed_hz > bus->base.max_speed_hz
0382 ) {
0383 return -EINVAL;
0384 }
0385
0386 bus->base.mode = msg->mode;
0387 bus->base.speed_hz = msg->speed_hz;
0388 bus->base.bits_per_word = msg->bits_per_word;
0389 bus->base.cs = msg->cs;
0390 atsam_configure_spi(bus);
0391 }
0392
0393 return 0;
0394 }
0395
0396 static void atsam_spi_setup_transfer(atsam_spi_bus *bus)
0397 {
0398 uint32_t msg_todo = bus->msg_todo;
0399
0400 if (msg_todo > 0) {
0401 const spi_ioc_transfer *msg;
0402 int error;
0403
0404 msg = bus->msg_current;
0405 error = atsam_check_configure_spi(bus, msg);
0406 if (error == 0) {
0407 atsam_spi_start_dma_transfer(bus, msg);
0408 } else {
0409 bus->error = error;
0410 atsam_spi_wakeup_task(bus);
0411 }
0412 } else {
0413 atsam_spi_wakeup_task(bus);
0414 }
0415 }
0416
0417 static void atsam_spi_dma_callback(uint32_t ch, void *arg, uint32_t status)
0418 {
0419 atsam_spi_bus *bus;
0420 uint32_t dma_errors;
0421
0422 bus = arg;
0423 dma_errors = XDMAC_CIE_DIE | XDMAC_CIE_FIE | XDMAC_CIE_RBIE | XDMAC_CIE_WBIE
0424 | XDMAC_CIE_ROIE;
0425
0426 if ((status & dma_errors) != 0) {
0427 bus->error = -EIO;
0428 }
0429
0430 --bus->transfer_in_progress;
0431
0432 if (bus->transfer_in_progress == 0) {
0433 const spi_ioc_transfer *msg = bus->msg_current;
0434
0435 if (msg->delay_usecs != bus->base.delay_usecs) {
0436 uint32_t mr;
0437 uint32_t mr_dlybcs;
0438
0439 bus->base.delay_usecs = msg->delay_usecs;
0440 mr_dlybcs = SPI_MR_DLYBCS(atsam_calculate_dlybcs(bus));
0441 bus->spi_mr = mr_dlybcs | SPI_MR_MSTR | SPI_MR_MODFDIS;
0442
0443 mr = bus->spi_regs->SPI_MR;
0444 mr &= ~SPI_MR_DLYBCS_Msk;
0445 mr |= mr_dlybcs;
0446 bus->spi_regs->SPI_MR = mr;
0447 }
0448
0449 if (msg->cs_change) {
0450 bus->spi_regs->SPI_CR = SPI_CR_LASTXFER;
0451 }
0452
0453 atsam_spi_copy_rx_bounce_bufs(bus, msg);
0454
0455 bus->msg_current = msg + 1;
0456 --bus->msg_todo;
0457
0458 if (bus->error == 0) {
0459 atsam_spi_setup_transfer(bus);
0460 } else {
0461 atsam_spi_wakeup_task(bus);
0462 }
0463 }
0464 }
0465
0466 static int atsam_spi_transfer(
0467 spi_bus *base,
0468 const spi_ioc_transfer *msgs,
0469 uint32_t msg_count
0470 )
0471 {
0472 atsam_spi_bus *bus = (atsam_spi_bus *)base;
0473
0474 bus->msg_current = msgs;
0475 bus->msg_todo = msg_count;
0476 bus->error = 0;
0477 atsam_spi_setup_transfer(bus);
0478 rtems_binary_semaphore_wait(&bus->sem);
0479 return bus->error;
0480 }
0481
0482
0483 static void atsam_spi_destroy(spi_bus *base)
0484 {
0485 atsam_spi_bus *bus = (atsam_spi_bus *)base;
0486 eXdmadRC rc;
0487
0488 rc = XDMAD_SetCallback(
0489 &XDMAD_Instance,
0490 bus->dma_rx_channel,
0491 XDMAD_DoNothingCallback,
0492 NULL
0493 );
0494 assert(rc == XDMAD_OK);
0495
0496 rc = XDMAD_SetCallback(
0497 &XDMAD_Instance,
0498 bus->dma_tx_channel,
0499 XDMAD_DoNothingCallback,
0500 NULL
0501 );
0502 assert(rc == XDMAD_OK);
0503
0504 XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_rx_channel);
0505 XDMAD_FreeChannel(&XDMAD_Instance, bus->dma_tx_channel);
0506
0507 SPI_Disable(bus->spi_regs);
0508 PMC_DisablePeripheral(bus->spi_id);
0509
0510 rtems_cache_coherent_free(bus->dma);
0511 rtems_binary_semaphore_destroy(&bus->sem);
0512 spi_bus_destroy_and_free(&bus->base);
0513 }
0514
0515 static int atsam_spi_setup(spi_bus *base)
0516 {
0517 atsam_spi_bus *bus = (atsam_spi_bus *)base;
0518
0519 if (
0520 bus->base.speed_hz > MAX_SPI_FREQUENCY
0521 || bus->base.bits_per_word != 8
0522 ) {
0523 return -EINVAL;
0524 }
0525 atsam_configure_spi(bus);
0526 return 0;
0527 }
0528
0529 static void atsam_spi_init_xdma(atsam_spi_bus *bus)
0530 {
0531 atsam_spi_dma *dma;
0532 sXdmadCfg cfg;
0533 uint32_t xdmaInt;
0534 uint8_t channel;
0535 eXdmadRC rc;
0536 uint32_t xdma_cndc;
0537 uint32_t tx_da;
0538 uint32_t rx_sa;
0539 uint32_t tx_cfg;
0540 uint32_t rx_cfg;
0541
0542 tx_da = (uint32_t)&bus->spi_regs->SPI_TDR;
0543 rx_sa = (uint32_t)&bus->spi_regs->SPI_RDR;
0544
0545 channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_TX);
0546 tx_cfg =
0547 XDMAC_CC_TYPE_PER_TRAN |
0548 XDMAC_CC_MBSIZE_SINGLE |
0549 XDMAC_CC_DSYNC_MEM2PER |
0550 XDMAC_CC_CSIZE_CHK_1 |
0551 XDMAC_CC_DWIDTH_BYTE |
0552 XDMAC_CC_SIF_AHB_IF1 |
0553 XDMAC_CC_DIF_AHB_IF1 |
0554 XDMAC_CC_SAM_INCREMENTED_AM |
0555 XDMAC_CC_DAM_FIXED_AM |
0556 XDMAC_CC_PERID(channel);
0557
0558 channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_RX);
0559 rx_cfg =
0560 XDMAC_CC_TYPE_PER_TRAN |
0561 XDMAC_CC_MBSIZE_SINGLE |
0562 XDMAC_CC_DSYNC_PER2MEM |
0563 XDMAC_CC_CSIZE_CHK_1 |
0564 XDMAC_CC_DWIDTH_BYTE |
0565 XDMAC_CC_SIF_AHB_IF1 |
0566 XDMAC_CC_DIF_AHB_IF1 |
0567 XDMAC_CC_SAM_FIXED_AM |
0568 XDMAC_CC_DAM_INCREMENTED_AM |
0569 XDMAC_CC_PERID(channel);
0570
0571 dma = rtems_cache_coherent_allocate(sizeof(*dma), 0, 0);
0572 assert(dma != NULL);
0573 bus->dma = dma;
0574
0575 dma->tx_desc.mbr_nda = 0;
0576 dma->tx_desc.mbr_sa = 0;
0577 dma->tx_desc.mbr_da = tx_da;
0578 dma->tx_desc.mbr_cfg = tx_cfg;
0579 dma->rx_desc[0].mbr_nda = (uint32_t) &dma->rx_desc[1];
0580 dma->rx_desc[0].mbr_sa = rx_sa;
0581 dma->rx_desc[0].mbr_da = 0;
0582 dma->rx_desc[0].mbr_cfg = rx_cfg;
0583 dma->rx_desc[1].mbr_nda = (uint32_t) &dma->rx_desc[2];
0584 dma->rx_desc[1].mbr_sa = rx_sa;
0585 dma->rx_desc[1].mbr_da = 0;
0586 dma->rx_desc[1].mbr_cfg = rx_cfg;
0587 dma->rx_desc[2].mbr_nda = 0;
0588 dma->rx_desc[2].mbr_sa = rx_sa;
0589 dma->rx_desc[2].mbr_da = 0;
0590 dma->rx_desc[2].mbr_cfg = rx_cfg;
0591
0592 bus->dma_tx_channel = XDMAD_AllocateChannel(
0593 &XDMAD_Instance,
0594 XDMAD_TRANSFER_MEMORY,
0595 bus->spi_id
0596 );
0597 assert(bus->dma_tx_channel != XDMAD_ALLOC_FAILED);
0598
0599 bus->dma_rx_channel = XDMAD_AllocateChannel(
0600 &XDMAD_Instance,
0601 bus->spi_id,
0602 XDMAD_TRANSFER_MEMORY
0603 );
0604 assert(bus->dma_rx_channel != XDMAD_ALLOC_FAILED);
0605
0606 rc = XDMAD_SetCallback(
0607 &XDMAD_Instance,
0608 bus->dma_rx_channel,
0609 atsam_spi_dma_callback,
0610 bus
0611 );
0612 assert(rc == XDMAD_OK);
0613
0614 rc = XDMAD_SetCallback(
0615 &XDMAD_Instance,
0616 bus->dma_tx_channel,
0617 atsam_spi_dma_callback,
0618 bus
0619 );
0620 assert(rc == XDMAD_OK);
0621
0622 rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_rx_channel);
0623 assert(rc == XDMAD_OK);
0624
0625 rc = XDMAD_PrepareChannel(&XDMAD_Instance, bus->dma_tx_channel);
0626 assert(rc == XDMAD_OK);
0627
0628
0629 xdmaInt = XDMAC_CIE_LIE | XDMAC_CIE_DIE | XDMAC_CIE_FIE | XDMAC_CIE_RBIE
0630 | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE;
0631
0632
0633 memset(&cfg, 0, sizeof(cfg));
0634 channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_RX);
0635 cfg.mbr_sa = rx_sa;
0636 cfg.mbr_cfg = rx_cfg;
0637 xdma_cndc = XDMAC_CNDC_NDVIEW_NDV2 |
0638 XDMAC_CNDC_NDE_DSCR_FETCH_EN |
0639 XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
0640 XDMAC_CNDC_NDSUP_SRC_PARAMS_UNCHANGED;
0641 rc = XDMAD_ConfigureTransfer(
0642 &XDMAD_Instance,
0643 bus->dma_rx_channel,
0644 &cfg,
0645 xdma_cndc,
0646 (uint32_t) &bus->dma->rx_desc[0],
0647 xdmaInt
0648 );
0649 assert(rc == XDMAD_OK);
0650
0651
0652 memset(&cfg, 0, sizeof(cfg));
0653 channel = XDMAIF_Get_ChannelNumber(bus->spi_id, XDMAD_TRANSFER_TX);
0654 cfg.mbr_da = tx_da;
0655 cfg.mbr_cfg = tx_cfg;
0656 xdma_cndc = XDMAC_CNDC_NDVIEW_NDV2 |
0657 XDMAC_CNDC_NDE_DSCR_FETCH_EN |
0658 XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED |
0659 XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED;
0660 rc = XDMAD_ConfigureTransfer(
0661 &XDMAD_Instance,
0662 bus->dma_tx_channel,
0663 &cfg,
0664 xdma_cndc,
0665 (uint32_t) &bus->dma->tx_desc,
0666 xdmaInt
0667 );
0668 assert(rc == XDMAD_OK);
0669 }
0670
0671 int spi_bus_register_atsam(
0672 const char *bus_path,
0673 const atsam_spi_config *config
0674 )
0675 {
0676 atsam_spi_bus *bus;
0677 size_t i;
0678
0679 bus = (atsam_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
0680 if (bus == NULL) {
0681 return -1;
0682 }
0683
0684 bus->base.transfer = atsam_spi_transfer;
0685 bus->base.destroy = atsam_spi_destroy;
0686 bus->base.setup = atsam_spi_setup;
0687 bus->base.max_speed_hz = MAX_SPI_FREQUENCY;
0688 bus->base.bits_per_word = 8;
0689 bus->base.speed_hz = bus->base.max_speed_hz;
0690 bus->base.cs = 1;
0691 bus->spi_id = config->spi_peripheral_id;
0692 bus->spi_regs = config->spi_regs;
0693 bus->chip_select_decode = config->chip_select_decode;
0694 bus->peripheral_clk_per_us = BOARD_MCK / 1000000;
0695 bus->spi_mr = SPI_MR_MSTR | SPI_MR_MODFDIS;
0696
0697 for (i = 0; i < RTEMS_ARRAY_SIZE(bus->spi_csr); ++i) {
0698 if (config->dlybs_in_ns[i] != 0) {
0699 bus->spi_csr[i] |= SPI_DLYBS(config->dlybs_in_ns[i], BOARD_MCK);
0700 }
0701
0702 if (config->dlybct_in_ns[i] != 0) {
0703 bus->spi_csr[i] |= SPI_DLYBCT(config->dlybct_in_ns[i], BOARD_MCK);
0704 }
0705 }
0706
0707 rtems_binary_semaphore_init(&bus->sem, "ATSAM SPI");
0708 PIO_Configure(config->pins, config->pin_count);
0709 PMC_EnablePeripheral(config->spi_peripheral_id);
0710 atsam_reset_spi(bus);
0711 atsam_configure_spi(bus);
0712 atsam_spi_init_xdma(bus);
0713
0714 return spi_bus_register(&bus->base, bus_path);
0715 }