Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:54

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup mpc55xx_dspi
0007  *
0008  * @brief Source file for the LibI2C bus driver for the Deserial Serial Peripheral Interface (DSPI).
0009  */
0010 
0011 /*
0012  * Copyright (c) 2008 embedded brains GmbH & Co. KG
0013  * Redistribution and use in source and binary forms, with or without
0014  * modification, are permitted provided that the following conditions
0015  * are met:
0016  * 1. Redistributions of source code must retain the above copyright
0017  *    notice, this list of conditions and the following disclaimer.
0018  * 2. Redistributions in binary form must reproduce the above copyright
0019  *    notice, this list of conditions and the following disclaimer in the
0020  *    documentation and/or other materials provided with the distribution.
0021  *
0022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0023  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0025  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0026  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0027  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0028  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0029  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0030  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0032  * POSSIBILITY OF SUCH DAMAGE.
0033  */
0034 
0035 #include <mpc55xx/regs.h>
0036 #include <mpc55xx/dspi.h>
0037 #include <mpc55xx/mpc55xx.h>
0038 
0039 #include <bsp/irq.h>
0040 
0041 #include <libcpu/powerpc-utility.h>
0042 
0043 #define RTEMS_STATUS_CHECKS_USE_PRINTK
0044 
0045 #include <rtems/status-checks.h>
0046 
0047 #include <inttypes.h>
0048 
0049 #define MPC55XX_DSPI_FIFO_SIZE 4
0050 
0051 #define MPC55XX_DSPI_CTAR_NUMBER 8
0052 
0053 #define MPC55XX_DSPI_CTAR_DEFAULT 0
0054 
0055 #define MPC55XX_DSPI_EDMA_MAGIC_SIZE 128
0056 
0057 #define MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE 63
0058 
0059 typedef struct {
0060     uint32_t scaler : 26;
0061     uint32_t pbr : 2;
0062     uint32_t br : 4;
0063 } mpc55xx_dspi_baudrate_scaler_entry;
0064 
0065 static const mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_baudrate_scaler_table [MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE] = {
0066     { 4, 0, 0 },
0067     { 6, 1, 0 },
0068     { 8, 0, 1 },
0069     { 10, 2, 0 },
0070     { 12, 1, 1 },
0071     { 14, 3, 0 },
0072     { 16, 0, 3 },
0073     { 18, 1, 2 },
0074     { 20, 2, 1 },
0075     { 24, 1, 3 },
0076     { 28, 3, 1 },
0077     { 30, 2, 2 },
0078     { 32, 0, 4 },
0079     { 40, 2, 3 },
0080     { 42, 3, 2 },
0081     { 48, 1, 4 },
0082     { 56, 3, 3 },
0083     { 64, 0, 5 },
0084     { 80, 2, 4 },
0085     { 96, 1, 5 },
0086     { 112, 3, 4 },
0087     { 128, 0, 6 },
0088     { 160, 2, 5 },
0089     { 192, 1, 6 },
0090     { 224, 3, 5 },
0091     { 256, 0, 7 },
0092     { 320, 2, 6 },
0093     { 384, 1, 7 },
0094     { 448, 3, 6 },
0095     { 512, 0, 8 },
0096     { 640, 2, 7 },
0097     { 768, 1, 8 },
0098     { 896, 3, 7 },
0099     { 1024, 0, 9 },
0100     { 1280, 2, 8 },
0101     { 1536, 1, 9 },
0102     { 1792, 3, 8 },
0103     { 2048, 0, 10 },
0104     { 2560, 2, 9 },
0105     { 3072, 1, 10 },
0106     { 3584, 3, 9 },
0107     { 4096, 0, 11 },
0108     { 5120, 2, 10 },
0109     { 6144, 1, 11 },
0110     { 7168, 3, 10 },
0111     { 8192, 0, 12 },
0112     { 10240, 2, 11 },
0113     { 12288, 1, 12 },
0114     { 14336, 3, 11 },
0115     { 16384, 0, 13 },
0116     { 20480, 2, 12 },
0117     { 24576, 1, 13 },
0118     { 28672, 3, 12 },
0119     { 32768, 0, 14 },
0120     { 40960, 2, 13 },
0121     { 49152, 1, 14 },
0122     { 57344, 3, 13 },
0123     { 65536, 0, 15 },
0124     { 81920, 2, 14 },
0125     { 98304, 1, 15 },
0126     { 114688, 3, 14 },
0127     { 163840, 2, 15 },
0128     { 229376, 3, 15 },
0129 };
0130 
0131 static void mpc55xx_dspi_edma_done( edma_channel_context *ctx, uint32_t error_status)
0132 {
0133     const mpc55xx_dspi_edma_entry *e = (const mpc55xx_dspi_edma_entry *) ctx;
0134     rtems_semaphore_release( e->id);
0135 
0136     if (error_status != 0) {
0137         RTEMS_SYSLOG_ERROR( "eDMA error: 0x%08" PRIx32 "\n", error_status);
0138     }
0139 }
0140 
0141 static mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_search_baudrate_scaler( uint32_t scaler, int min, int mid, int max)
0142 {
0143     if (scaler <= mpc55xx_dspi_baudrate_scaler_table [mid].scaler) {
0144         max = mid;
0145     } else {
0146         min = mid;
0147     }
0148     mid = (min + max) / 2;
0149     if (mid == min) {
0150         return mpc55xx_dspi_baudrate_scaler_table [max];
0151     } else {
0152         return mpc55xx_dspi_search_baudrate_scaler( scaler, min, mid, max);
0153     }
0154 }
0155 
0156 static uint32_t mpc55xx_dspi_push_data [8 * MPC55XX_DSPI_NUMBER] __attribute__ ((aligned (32)));
0157 
0158 static inline void mpc55xx_dspi_store_push_data( mpc55xx_dspi_bus_entry *e)
0159 {
0160     mpc55xx_dspi_push_data [e->table_index * 8] = e->push_data.R;
0161     rtems_cache_flush_multiple_data_lines( &mpc55xx_dspi_push_data [e->table_index * 8], 4);
0162 }
0163 
0164 static inline uint32_t mpc55xx_dspi_push_data_address( mpc55xx_dspi_bus_entry *e)
0165 {
0166     return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8];
0167 }
0168 
0169 static inline uint32_t mpc55xx_dspi_nirvana_address( mpc55xx_dspi_bus_entry *e)
0170 {
0171     return (uint32_t) &mpc55xx_dspi_push_data [e->table_index * 8 + 1];
0172 }
0173 
0174 static rtems_status_code mpc55xx_dspi_init( rtems_libi2c_bus_t *bus)
0175 {
0176     rtems_status_code sc = RTEMS_SUCCESSFUL;
0177     mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
0178     union DSPI_MCR_tag mcr = MPC55XX_ZERO_FLAGS;
0179     union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
0180     union DSPI_RSER_tag rser = MPC55XX_ZERO_FLAGS;
0181     struct tcd_t tcd_push = EDMA_TCD_DEFAULT;
0182     int i = 0;
0183 
0184     /* eDMA receive */
0185     sc = rtems_semaphore_create (
0186         rtems_build_name ( 'S', 'P', 'I', 'R'),
0187         0,
0188         RTEMS_SIMPLE_BINARY_SEMAPHORE,
0189         0,
0190         &e->edma_receive.id
0191     );
0192     RTEMS_CHECK_SC( sc, "create receive update semaphore");
0193 
0194     sc = mpc55xx_edma_obtain_channel( &e->edma_receive.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
0195     RTEMS_CHECK_SC( sc, "obtain receive eDMA channel");
0196 
0197     /* eDMA transmit */
0198     sc = rtems_semaphore_create (
0199         rtems_build_name ( 'S', 'P', 'I', 'T'),
0200         0,
0201         RTEMS_SIMPLE_BINARY_SEMAPHORE,
0202         0,
0203         &e->edma_transmit.id
0204     );
0205     RTEMS_CHECK_SC( sc, "create transmit update semaphore");
0206 
0207     sc = mpc55xx_edma_obtain_channel( &e->edma_transmit.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
0208     RTEMS_CHECK_SC( sc, "obtain transmit eDMA channel");
0209 
0210     sc = mpc55xx_edma_obtain_channel( &e->edma_push.edma, MPC55XX_INTC_DEFAULT_PRIORITY);
0211     RTEMS_CHECK_SC( sc, "obtain push eDMA channel");
0212 
0213     tcd_push.SADDR = mpc55xx_dspi_push_data_address( e);
0214     tcd_push.SDF.B.SSIZE = 2;
0215     tcd_push.SDF.B.SOFF = 0;
0216     tcd_push.DADDR = (uint32_t) &e->regs->PUSHR.R;
0217     tcd_push.SDF.B.DSIZE = 2;
0218     tcd_push.CDF.B.DOFF = 0;
0219     tcd_push.NBYTES = 4;
0220     tcd_push.CDF.B.CITER = 1;
0221     tcd_push.BMF.B.BITER = 1;
0222 
0223     *e->edma_push.edma.edma_tcd = tcd_push;
0224 
0225     /* Module Control Register */
0226     mcr.B.MSTR = e->master ? 1 : 0;
0227     mcr.B.CONT_SCKE = 0;
0228     mcr.B.DCONF = 0;
0229     mcr.B.FRZ = 0;
0230     mcr.B.MTFE = 0;
0231     mcr.B.PCSSE = 0;
0232     mcr.B.ROOE = 0;
0233     mcr.B.PCSIS0 = 1;
0234     mcr.B.PCSIS1 = 1;
0235     mcr.B.PCSIS2 = 1;
0236     mcr.B.PCSIS3 = 1;
0237     mcr.B.PCSIS5 = 1;
0238     mcr.B.MDIS = 0;
0239     mcr.B.DIS_TXF = 0;
0240     mcr.B.DIS_RXF = 0;
0241     mcr.B.CLR_TXF = 0;
0242     mcr.B.CLR_RXF = 0;
0243     mcr.B.SMPL_PT = 0;
0244     mcr.B.HALT = 0;
0245 
0246     e->regs->MCR.R = mcr.R;
0247 
0248     /* Clock and Transfer Attributes Register */
0249     ctar.B.DBR = 0;
0250     ctar.B.FMSZ = 0x7;
0251     ctar.B.CPOL = 0;
0252     ctar.B.CPHA = 0;
0253     ctar.B.LSBFE = 0;
0254     ctar.B.PCSSCK = 0;
0255     ctar.B.PASC = 0;
0256     ctar.B.PDT = 0;
0257     ctar.B.PBR = 0;
0258     ctar.B.CSSCK = 0;
0259     ctar.B.ASC = 0;
0260     ctar.B.DT = 0;
0261     ctar.B.BR = 0;
0262 
0263     for (i = 0; i < MPC55XX_DSPI_CTAR_NUMBER; ++i) {
0264         e->regs->CTAR [i].R = ctar.R;
0265     }
0266 
0267     /* DMA/Interrupt Request Select and Enable Register */
0268     rser.B.TFFFRE = 1;
0269     rser.B.TFFFDIRS = 1;
0270     rser.B.RFDFRE = 1;
0271     rser.B.RFDFDIRS = 1;
0272 
0273     e->regs->RSER.R = rser.R;
0274 
0275     return RTEMS_SUCCESSFUL;
0276 }
0277 
0278 static rtems_status_code mpc55xx_dspi_send_start( rtems_libi2c_bus_t *bus)
0279 {
0280     mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
0281 
0282     /* Reset chip selects */
0283     e->push_data.B.PCS0 = 0;
0284     e->push_data.B.PCS1 = 0;
0285     e->push_data.B.PCS2 = 0;
0286     e->push_data.B.PCS3 = 0;
0287     e->push_data.B.PCS4 = 0;
0288     e->push_data.B.PCS5 = 0;
0289     mpc55xx_dspi_store_push_data( e);
0290 
0291     return RTEMS_SUCCESSFUL;
0292 }
0293 
0294 static rtems_status_code mpc55xx_dspi_send_stop( rtems_libi2c_bus_t *bus)
0295 {
0296     return RTEMS_SUCCESSFUL;
0297 }
0298 
0299 static rtems_status_code mpc55xx_dspi_send_addr( rtems_libi2c_bus_t *bus, uint32_t addr, int rw)
0300 {
0301     mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
0302     union DSPI_SR_tag sr = MPC55XX_ZERO_FLAGS;
0303 
0304     /* Flush transmit and receive FIFO */
0305     e->regs->MCR.B.CLR_TXF = 1;
0306     e->regs->MCR.B.CLR_RXF = 1;
0307 
0308     /* Clear status flags */
0309     sr.B.EOQF = 1;
0310     sr.B.TFFF = 1;
0311     sr.B.RFDF = 1;
0312     e->regs->SR.R = sr.R;
0313 
0314     /* Frame command */
0315     e->push_data.R = 0;
0316     e->push_data.B.CONT = 0;
0317     e->push_data.B.CTAS = MPC55XX_DSPI_CTAR_DEFAULT;
0318     e->push_data.B.EOQ = 0;
0319     e->push_data.B.CTCNT = 0;
0320     switch (addr) {
0321         case 0:
0322             e->push_data.B.PCS0 = 1;
0323             break;
0324         case 1:
0325             e->push_data.B.PCS1 = 1;
0326             break;
0327         case 2:
0328             e->push_data.B.PCS2 = 1;
0329             break;
0330         case 3:
0331             e->push_data.B.PCS3 = 1;
0332             break;
0333         case 4:
0334             e->push_data.B.PCS4 = 1;
0335             break;
0336         case 5:
0337             e->push_data.B.PCS5 = 1;
0338             break;
0339         default:
0340             return -RTEMS_INVALID_ADDRESS;
0341     }
0342     mpc55xx_dspi_store_push_data( e);
0343 
0344     return RTEMS_SUCCESSFUL;
0345 }
0346 
0347 /* FIXME, TODO */
0348 extern uint32_t bsp_clock_speed;
0349 
0350 static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_libi2c_tfr_mode_t *mode)
0351 {
0352     mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
0353     union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS;
0354 
0355     if (mode->bits_per_char != 8) {
0356         return -RTEMS_INVALID_NUMBER;
0357     }
0358 
0359     e->idle_char = mode->idle_char;
0360 
0361     ctar.R = e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R;
0362 
0363     ctar.B.PCSSCK = 0;
0364     ctar.B.CSSCK = 0;
0365     ctar.B.PASC = 0;
0366     ctar.B.ASC = 0;
0367 
0368     ctar.B.LSBFE = mode->lsb_first ? 1 : 0;
0369     ctar.B.CPOL = mode->clock_inv ? 1 : 0;
0370     ctar.B.CPHA = mode->clock_phs ? 1 : 0;
0371 
0372     if (mode->baudrate != e->baud) {
0373         uint32_t scaler = bsp_clock_speed / mode->baudrate;
0374         mpc55xx_dspi_baudrate_scaler_entry bse = mpc55xx_dspi_search_baudrate_scaler( scaler, 0, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE / 2, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE);
0375 
0376         ctar.B.PBR = bse.pbr;
0377         ctar.B.BR = bse.br;
0378 
0379         e->baud = mode->baudrate;
0380     }
0381 
0382     e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R = ctar.R;
0383 
0384     return 0;
0385 }
0386 
0387 /**
0388  * @brief Writes @a n characters from @a out to bus @a bus and synchronously stores the received data in @a in.
0389  *
0390  * eDMA channel usage for transmission:
0391  * @dot
0392  * digraph push {
0393  *  push [label="Push Register"];
0394  *  push_data [label="Push Data"];
0395  *  idle_push_data [label="Idle Push Data"];
0396  *  out [shape=box,label="Output Buffer"];
0397  *  edge [color=red,fontcolor=red];
0398  *  push -> idle_push_data [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"];
0399  *  push -> out [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"];
0400  *  out -> push_data [label="Channel Link",URL="\ref mpc55xx_dspi_bus_entry::edma_push"];
0401  *  edge [color=blue,fontcolor=blue];
0402  *  out -> push_data [label="Data"];
0403  *  push_data -> push [label="Data"];
0404  *  idle_push_data -> push [label="Data"];
0405  * }
0406  * @enddot
0407  *
0408  * eDMA channel usage for receiving:
0409  * @dot
0410  * digraph pop {
0411  *  pop [label="Pop Register"];
0412  *  nirvana [label="Nirvana"];
0413  *  in [shape=box,label="Input Buffer"];
0414  *  edge [color=red,fontcolor=red];
0415  *  pop -> nirvana [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"];
0416  *  pop -> in [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"];
0417  *  edge [color=blue,fontcolor=blue];
0418  *  pop -> nirvana [label="Data"];
0419  *  pop -> in [label="Data"];
0420  * }
0421  * @enddot
0422  */
0423 static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, const unsigned char *out, int n)
0424 {
0425     mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus;
0426 
0427     /* Non cache aligned characters */
0428     int n_nc = n;
0429 
0430     /* Cache aligned characters */
0431     int n_c = 0;
0432 
0433     /* Register addresses */
0434     volatile void *push = &e->regs->PUSHR.R;
0435     volatile void *pop = &e->regs->POPR.R;
0436     volatile union DSPI_SR_tag *status = &e->regs->SR;
0437 
0438     /* Push and pop data */
0439     union DSPI_PUSHR_tag push_data = e->push_data;
0440     union DSPI_POPR_tag pop_data;
0441 
0442     /* Status register */
0443     union DSPI_SR_tag sr;
0444 
0445     /* Read and write indices */
0446     int r = 0;
0447     int w = 0;
0448 
0449     if (n == 0) {
0450         return 0;
0451     } else if (in == NULL && out == NULL) {
0452         return -RTEMS_INVALID_ADDRESS;
0453     }
0454 
0455     if (n > MPC55XX_DSPI_EDMA_MAGIC_SIZE) {
0456         n_nc = (int) mpc55xx_non_cache_aligned_size( in);
0457         n_c = (int) mpc55xx_cache_aligned_size( in, (size_t) n);
0458         if (n_c > EDMA_TCD_BITER_LINKED_SIZE) {
0459             RTEMS_SYSLOG_WARNING( "buffer size out of range, cannot use eDMA\n");
0460             n_nc = n;
0461             n_c = 0;
0462         } else if (n_nc + n_c != n) {
0463             RTEMS_SYSLOG_WARNING( "input buffer not proper cache aligned, cannot use eDMA\n");
0464             n_nc = n;
0465             n_c = 0;
0466         }
0467     }
0468 
0469 #ifdef DEBUG
0470     if (e->regs->SR.B.TXCTR != e->regs->SR.B.RXCTR) {
0471         RTEMS_SYSLOG_WARNING( "FIFO counter not equal\n");
0472     }
0473 #endif /* DEBUG */
0474 
0475     /* Direct IO */
0476     if (out == NULL) {
0477         push_data.B.TXDATA = e->idle_char;
0478         while (r < n_nc || w < n_nc) {
0479             /* Wait for available FIFO */
0480             do {
0481                 sr.R = status->R;
0482             } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
0483 
0484             /* Write */
0485             if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
0486                 ++w;
0487                 ppc_write_word( push_data.R, push);
0488             }
0489 
0490             /* Read */
0491             if (r < n_nc && sr.B.RXCTR != 0) {
0492                 pop_data.R = ppc_read_word( pop);
0493                 in [r] = (unsigned char) pop_data.B.RXDATA;
0494                 ++r;
0495             }
0496         }
0497     } else if (in == NULL) {
0498         while (r < n_nc || w < n_nc) {
0499             /* Wait for available FIFO */
0500             do {
0501                 sr.R = status->R;
0502             } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
0503 
0504             /* Write */
0505             if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
0506                 push_data.B.TXDATA = out [w];
0507                 ++w;
0508                 ppc_write_word( push_data.R, push);
0509             }
0510 
0511             /* Read */
0512             if (r < n_nc && sr.B.RXCTR != 0) {
0513                 pop_data.R = ppc_read_word( pop);
0514                 ++r;
0515             }
0516         }
0517     } else {
0518         while (r < n_nc || w < n_nc) {
0519             /* Wait for available FIFO */
0520             do {
0521                 sr.R = status->R;
0522             } while (sr.B.TXCTR == MPC55XX_DSPI_FIFO_SIZE && sr.B.RXCTR == 0);
0523 
0524             /* Write */
0525             if (w < n_nc && (w - r) < MPC55XX_DSPI_FIFO_SIZE && sr.B.TXCTR != MPC55XX_DSPI_FIFO_SIZE) {
0526                 push_data.B.TXDATA = out [w];
0527                 ++w;
0528                 ppc_write_word( push_data.R, push);
0529             }
0530 
0531             /* Read */
0532             if (r < n_nc && sr.B.RXCTR != 0) {
0533                 pop_data.R = ppc_read_word( pop);
0534                 in [r] = (unsigned char) pop_data.B.RXDATA;
0535                 ++r;
0536             }
0537         }
0538     }
0539 
0540     /* eDMA transfers */
0541     if (n_c > 0) {
0542         rtems_status_code sc = RTEMS_SUCCESSFUL;
0543         unsigned char *in_c = in + n_nc;
0544         const unsigned char *out_c = out + n_nc;
0545         struct tcd_t tcd_transmit = EDMA_TCD_DEFAULT;
0546         struct tcd_t tcd_receive = EDMA_TCD_DEFAULT;
0547 
0548         /* Cache operations */
0549         rtems_cache_flush_multiple_data_lines( out_c, (size_t) n_c);
0550         rtems_cache_invalidate_multiple_data_lines( in_c, (size_t) n_c);
0551 
0552         /* Set transmit TCD */
0553         if (out == NULL) {
0554             e->push_data.B.TXDATA = e->idle_char;
0555             mpc55xx_dspi_store_push_data( e);
0556             tcd_transmit.SADDR = mpc55xx_dspi_push_data_address( e);
0557             tcd_transmit.SDF.B.SSIZE = 2;
0558             tcd_transmit.SDF.B.SOFF = 0;
0559             tcd_transmit.DADDR = (uint32_t) push;
0560             tcd_transmit.SDF.B.DSIZE = 2;
0561             tcd_transmit.CDF.B.DOFF = 0;
0562             tcd_transmit.NBYTES = 4;
0563             tcd_transmit.CDF.B.CITER = n_c;
0564             tcd_transmit.BMF.B.BITER = n_c;
0565         } else {
0566             unsigned push_channel = mpc55xx_edma_channel_by_tcd( e->edma_push.edma.edma_tcd);
0567             mpc55xx_edma_clear_done( e->edma_transmit.edma.edma_tcd);
0568             tcd_transmit.SADDR = (uint32_t) out_c;
0569             tcd_transmit.SDF.B.SSIZE = 0;
0570             tcd_transmit.SDF.B.SOFF = 1;
0571             tcd_transmit.DADDR = mpc55xx_dspi_push_data_address( e) + 3;
0572             tcd_transmit.SDF.B.DSIZE = 0;
0573             tcd_transmit.CDF.B.DOFF = 0;
0574             tcd_transmit.NBYTES = 1;
0575             tcd_transmit.CDF.B.CITERE_LINK = 1;
0576             tcd_transmit.BMF.B.BITERE_LINK = 1;
0577             tcd_transmit.BMF.B.MAJORLINKCH = push_channel;
0578             tcd_transmit.CDF.B.CITER = EDMA_TCD_LINK_AND_BITER( push_channel, n_c);
0579             tcd_transmit.BMF.B.BITER = EDMA_TCD_LINK_AND_BITER( push_channel, n_c);
0580             tcd_transmit.BMF.B.MAJORE_LINK = 1;
0581         }
0582         tcd_transmit.BMF.B.D_REQ = 1;
0583         tcd_transmit.BMF.B.INT_MAJ = 1;
0584         *e->edma_transmit.edma.edma_tcd = tcd_transmit;
0585 
0586         /* Set receive TCD */
0587         if (in == NULL) {
0588             tcd_receive.CDF.B.DOFF = 0;
0589             tcd_receive.DADDR = mpc55xx_dspi_nirvana_address( e);
0590         } else {
0591             tcd_receive.CDF.B.DOFF = 1;
0592             tcd_receive.DADDR = (uint32_t) in_c;
0593         }
0594         tcd_receive.SADDR = (uint32_t) pop + 3;
0595         tcd_receive.SDF.B.SSIZE = 0;
0596         tcd_receive.SDF.B.SOFF = 0;
0597         tcd_receive.SDF.B.DSIZE = 0;
0598         tcd_receive.NBYTES = 1;
0599         tcd_receive.BMF.B.D_REQ = 1;
0600         tcd_receive.BMF.B.INT_MAJ = 1;
0601         tcd_receive.CDF.B.CITER = n_c;
0602         tcd_receive.BMF.B.BITER = n_c;
0603         *e->edma_receive.edma.edma_tcd = tcd_receive;
0604 
0605         /* Clear request flags */
0606         sr.R = 0;
0607         sr.B.TFFF = 1;
0608         sr.B.RFDF = 1;
0609         status->R = sr.R;
0610 
0611         /* Enable hardware requests */
0612         mpc55xx_edma_enable_hardware_requests( e->edma_receive.edma.edma_tcd);
0613         mpc55xx_edma_enable_hardware_requests( e->edma_transmit.edma.edma_tcd);
0614 
0615         /* Wait for transmit update */
0616         sc = rtems_semaphore_obtain( e->edma_transmit.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0617         RTEMS_CHECK_SC_RV( sc, "transmit update");
0618 
0619         /* Wait for receive update */
0620         sc = rtems_semaphore_obtain( e->edma_receive.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0621         RTEMS_CHECK_SC_RV( sc, "receive update");
0622     }
0623 
0624     return n;
0625 }
0626 
0627 /**
0628  * @brief Reads @a n characters from bus @a bus and stores it in @a in.
0629  *
0630  * Writes idle characters to receive data.
0631  *
0632  * @see mpc55xx_dspi_read_write().
0633  */
0634 static int mpc55xx_dspi_read( rtems_libi2c_bus_t *bus, unsigned char *in, int n)
0635 {
0636     return mpc55xx_dspi_read_write( bus, in, NULL, n);
0637 }
0638 
0639 /**
0640  * @brief Writes @a n characters from @a out to bus @a bus.
0641  *
0642  * Discards the synchronously received data.
0643  *
0644  * @see mpc55xx_dspi_read_write().
0645  */
0646 static int mpc55xx_dspi_write( rtems_libi2c_bus_t *bus, unsigned char *out, int n)
0647 {
0648     return mpc55xx_dspi_read_write( bus, NULL, out, n);
0649 }
0650 
0651 static int mpc55xx_dspi_ioctl( rtems_libi2c_bus_t *bus, int cmd, void *arg)
0652 {
0653     int rv = -1;
0654     switch (cmd) {
0655         case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0656             rv = mpc55xx_dspi_set_transfer_mode( bus, (const rtems_libi2c_tfr_mode_t *) arg);
0657             break;
0658         case RTEMS_LIBI2C_IOCTL_READ_WRITE:
0659             rv = mpc55xx_dspi_read_write(
0660                 bus,
0661                 ((rtems_libi2c_read_write_t *) arg)->rd_buf,
0662                 ((rtems_libi2c_read_write_t *) arg)->wr_buf,
0663                 ((rtems_libi2c_read_write_t *) arg)->byte_cnt
0664             );
0665             break;
0666         default:
0667             rv = -RTEMS_NOT_DEFINED;
0668             break;
0669     }
0670     return rv;
0671 }
0672 
0673 static const rtems_libi2c_bus_ops_t mpc55xx_dspi_ops = {
0674     .init        = mpc55xx_dspi_init,
0675     .send_start  = mpc55xx_dspi_send_start,
0676     .send_stop   = mpc55xx_dspi_send_stop,
0677     .send_addr   = mpc55xx_dspi_send_addr,
0678     .read_bytes  = mpc55xx_dspi_read,
0679     .write_bytes = mpc55xx_dspi_write,
0680     .ioctl       = mpc55xx_dspi_ioctl
0681 };
0682 
0683 mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = {
0684     {
0685         /* DSPI A */
0686         .bus = {
0687             .ops = &mpc55xx_dspi_ops,
0688             .size = sizeof( mpc55xx_dspi_bus_entry)
0689         },
0690         .table_index = 0,
0691         .bus_number = 0,
0692         .regs = &DSPI_A,
0693         .master = true,
0694         .push_data = MPC55XX_ZERO_FLAGS,
0695         .edma_transmit = {
0696             .edma = {
0697                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_A_SR_TFFF),
0698                 .done = mpc55xx_dspi_edma_done
0699             },
0700             .id = RTEMS_ID_NONE
0701         },
0702         .edma_push = {
0703             .edma = {
0704                 .edma_tcd = &EDMA.TCD [43],
0705                 .done = mpc55xx_dspi_edma_done
0706             },
0707             .id = RTEMS_ID_NONE
0708         },
0709         .edma_receive = {
0710             .edma = {
0711                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_A_SR_RFDF),
0712                 .done = mpc55xx_dspi_edma_done
0713             },
0714             .id = RTEMS_ID_NONE
0715         },
0716         .idle_char = 0xffffffff,
0717         .baud = 0
0718     }, {
0719         /* DSPI B */
0720         .bus = {
0721             .ops = &mpc55xx_dspi_ops,
0722             .size = sizeof( mpc55xx_dspi_bus_entry)
0723         },
0724         .table_index = 1,
0725         .bus_number = 0,
0726         .regs = &DSPI_B,
0727         .master = true,
0728         .push_data = MPC55XX_ZERO_FLAGS,
0729         .edma_transmit = {
0730             .edma = {
0731                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_B_SR_TFFF),
0732                 .done = mpc55xx_dspi_edma_done
0733             },
0734             .id = RTEMS_ID_NONE
0735         },
0736         .edma_push = {
0737             .edma = {
0738                 .edma_tcd = &EDMA.TCD [10],
0739                 .done = mpc55xx_dspi_edma_done
0740             },
0741             .id = RTEMS_ID_NONE
0742         },
0743         .edma_receive = {
0744             .edma = {
0745                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_B_SR_RFDF),
0746                 .done = mpc55xx_dspi_edma_done
0747             },
0748             .id = RTEMS_ID_NONE
0749         },
0750         .idle_char = 0xffffffff,
0751         .baud = 0
0752     }, {
0753         /* DSPI C */
0754         .bus = {
0755             .ops = &mpc55xx_dspi_ops,
0756             .size = sizeof( mpc55xx_dspi_bus_entry)
0757         },
0758         .table_index = 2,
0759         .bus_number = 0,
0760         .regs = &DSPI_C,
0761         .master = true,
0762         .push_data = MPC55XX_ZERO_FLAGS,
0763         .edma_transmit = {
0764             .edma = {
0765                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_C_SR_TFFF),
0766                 .done = mpc55xx_dspi_edma_done
0767             },
0768             .id = RTEMS_ID_NONE
0769         },
0770         .edma_push = {
0771             .edma = {
0772                 .edma_tcd = &EDMA.TCD [11],
0773                 .done = mpc55xx_dspi_edma_done
0774             },
0775             .id = RTEMS_ID_NONE
0776         },
0777         .edma_receive = {
0778             .edma = {
0779                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_C_SR_RFDF),
0780                 .done = mpc55xx_dspi_edma_done
0781             },
0782             .id = RTEMS_ID_NONE
0783         },
0784         .idle_char = 0xffffffff,
0785         .baud = 0
0786 #ifdef DSPI_D
0787     }, {
0788         /* DSPI D */
0789         .bus = {
0790             .ops = &mpc55xx_dspi_ops,
0791             .size = sizeof( mpc55xx_dspi_bus_entry)
0792         },
0793         .table_index = 3,
0794         .bus_number = 0,
0795         .regs = &DSPI_D,
0796         .master = true,
0797         .push_data = MPC55XX_ZERO_FLAGS,
0798         .edma_transmit = {
0799             .edma = {
0800                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_D_SR_TFFF),
0801                 .done = mpc55xx_dspi_edma_done
0802             },
0803             .id = RTEMS_ID_NONE
0804         },
0805         .edma_push = {
0806             .edma = {
0807                 .edma_tcd = &EDMA.TCD [18],
0808                 .done = mpc55xx_dspi_edma_done
0809             },
0810             .id = RTEMS_ID_NONE
0811         },
0812         .edma_receive = {
0813             .edma = {
0814                 .edma_tcd = EDMA_TCD_BY_CHANNEL_INDEX(EDMA_DSPI_D_SR_RFDF),
0815                 .done = mpc55xx_dspi_edma_done
0816             },
0817             .id = RTEMS_ID_NONE
0818         },
0819         .idle_char = 0xffffffff,
0820         .baud = 0
0821 #endif
0822     }
0823 };