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  * @brief Console ESCI implementation.
0007  */
0008 
0009 /*
0010  * Copyright (C) 2008, 2012 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include <bsp/console-esci.h>
0035 
0036 #include <bsp.h>
0037 #include <bsp/fatal.h>
0038 #include <bsp/irq.h>
0039 
0040 #ifdef MPC55XX_HAS_ESCI
0041 
0042 mpc55xx_esci_context mpc55xx_esci_devices [] = {
0043   {
0044     .regs = &ESCI_A,
0045     .irq = MPC55XX_IRQ_ESCI(0)
0046   }
0047   #ifdef ESCI_B
0048     , {
0049       .regs = &ESCI_B,
0050       .irq = MPC55XX_IRQ_ESCI(1)
0051     }
0052   #endif
0053   #ifdef ESCI_C
0054     , {
0055       .regs = &ESCI_C,
0056       .irq = MPC55XX_IRQ_ESCI(2)
0057     }
0058   #endif
0059   #ifdef ESCI_D
0060     , {
0061       .regs = &ESCI_D,
0062       .irq = MPC55XX_IRQ_ESCI(3)
0063     }
0064   #endif
0065 };
0066 
0067 static void mpc55xx_esci_poll_write(int minor, char c)
0068 {
0069   mpc55xx_esci_context *self = console_generic_get_context(minor);
0070   const union ESCI_SR_tag clear_tdre = { .B = { .TDRE = 1 } };
0071   volatile struct ESCI_tag *regs = self->regs;
0072   rtems_interrupt_level level;
0073   bool done = false;
0074   bool wait_for_transmit_done = false;
0075 
0076   rtems_interrupt_disable(level);
0077   if (self->transmit_nest_level == 0) {
0078     union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
0079 
0080     if (cr1.B.TIE != 0) {
0081       cr1.B.TIE = 0;
0082       regs->CR1.R = cr1.R;
0083       wait_for_transmit_done = !self->transmit_in_progress;
0084       self->transmit_nest_level = 1;
0085     }
0086   } else {
0087     ++self->transmit_nest_level;
0088   }
0089   rtems_interrupt_enable(level);
0090 
0091   while (!done) {
0092     rtems_interrupt_disable(level);
0093     bool tx = self->transmit_in_progress;
0094     if (!tx || (tx && regs->SR.B.TDRE)) {
0095       regs->SR.R = clear_tdre.R;
0096       regs->DR.B.D = c;
0097       self->transmit_in_progress = true;
0098       done = true;
0099     }
0100     rtems_interrupt_enable(level);
0101   }
0102 
0103   done = false;
0104   while (!done) {
0105     rtems_interrupt_disable(level);
0106     if (wait_for_transmit_done) {
0107       if (regs->SR.B.TDRE) {
0108         regs->SR.R = clear_tdre.R;
0109         self->transmit_in_progress = false;
0110         done = true;
0111       }
0112     } else {
0113       done = true;
0114     }
0115 
0116     if (done && self->transmit_nest_level > 0) {
0117       --self->transmit_nest_level;
0118 
0119       if (self->transmit_nest_level == 0) {
0120         union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
0121 
0122         cr1.B.TIE = 1;
0123         regs->CR1.R = cr1.R;
0124       }
0125     }
0126     rtems_interrupt_enable(level);
0127   }
0128 }
0129 
0130 static inline void mpc55xx_esci_interrupts_clear_and_enable(
0131   mpc55xx_esci_context *self
0132 )
0133 {
0134   volatile struct ESCI_tag *regs = self->regs;
0135   union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
0136   rtems_interrupt_level level;
0137 
0138   rtems_interrupt_disable(level);
0139   cr1.R = regs->CR1.R;
0140   cr1.B.RIE = 1;
0141   cr1.B.TIE = 1;
0142   regs->CR1.R = cr1.R;
0143   regs->SR.R = regs->SR.R;
0144   rtems_interrupt_enable(level);
0145 }
0146 
0147 static inline void mpc55xx_esci_interrupts_disable(mpc55xx_esci_context *self)
0148 {
0149   volatile struct ESCI_tag *regs = self->regs;
0150   union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
0151   rtems_interrupt_level level;
0152 
0153   rtems_interrupt_disable(level);
0154   cr1.R = regs->CR1.R;
0155   cr1.B.RIE = 0;
0156   cr1.B.TIE = 0;
0157   regs->CR1.R = cr1.R;
0158   rtems_interrupt_enable(level);
0159 }
0160 
0161 static void mpc55xx_esci_interrupt_handler(void *arg)
0162 {
0163   mpc55xx_esci_context *self = arg;
0164   volatile struct ESCI_tag *regs = self->regs;
0165   union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
0166   union ESCI_SR_tag active = MPC55XX_ZERO_FLAGS;
0167   rtems_interrupt_level level;
0168 
0169   /* Status */
0170   sr.R = regs->SR.R;
0171 
0172   /* Receive data register full? */
0173   if (sr.B.RDRF != 0) {
0174     active.B.RDRF = 1;
0175   }
0176 
0177   /* Transmit data register empty? */
0178   if (sr.B.TDRE != 0) {
0179     active.B.TDRE = 1;
0180   }
0181 
0182   /* Clear flags */
0183   rtems_interrupt_disable(level);
0184   regs->SR.R = active.R;
0185   self->transmit_in_progress = false;
0186   rtems_interrupt_enable(level);
0187 
0188   /* Enqueue */
0189   if (active.B.RDRF != 0) {
0190     char c = regs->DR.B.D;
0191     rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
0192   }
0193 
0194   /* Dequeue */
0195   if (active.B.TDRE != 0) {
0196     rtems_termios_dequeue_characters(self->tty, 1);
0197   }
0198 }
0199 
0200 static int mpc55xx_esci_set_attributes(int minor, const struct termios *t)
0201 {
0202   mpc55xx_esci_context *self = console_generic_get_context(minor);
0203   volatile struct ESCI_tag *regs = self->regs;
0204   union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
0205   union ESCI_CR2_tag cr2 = MPC55XX_ZERO_FLAGS;
0206   rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
0207 
0208   /* Enable module */
0209   cr2.B.MDIS = 0;
0210 
0211   /* Interrupts */
0212   cr1.B.TCIE = 0;
0213   cr1.B.ILIE = 0;
0214   cr2.B.IEBERR = 0;
0215   cr2.B.ORIE = 0;
0216   cr2.B.NFIE = 0;
0217   cr2.B.FEIE = 0;
0218   cr2.B.PFIE = 0;
0219 
0220   /* Disable receiver wake-up standby */
0221   cr1.B.RWU = 0;
0222 
0223   /* Disable DMA channels */
0224   cr2.B.RXDMA = 0;
0225   cr2.B.TXDMA = 0;
0226 
0227   /* Idle line type */
0228   cr1.B.ILT = 0;
0229 
0230   /* Disable loops */
0231   cr1.B.LOOPS = 0;
0232 
0233   /* Enable or disable receiver */
0234   cr1.B.RE = (t->c_cflag & CREAD) ? 1 : 0;
0235 
0236   /* Enable transmitter */
0237   cr1.B.TE = 1;
0238 
0239   /* Baud rate */
0240   if (br > 0) {
0241     br = bsp_clock_speed / (16 * br);
0242     br = (br > 8191) ? 8191 : br;
0243   } else {
0244     br = 0;
0245   }
0246   cr1.B.SBR = br;
0247 
0248   /* Number of data bits */
0249   if ((t->c_cflag & CSIZE) != CS8) {
0250     return -1;
0251   }
0252   cr1.B.M = 0;
0253 
0254   /* Parity */
0255   cr1.B.PE = (t->c_cflag & PARENB) ? 1 : 0;
0256   cr1.B.PT = (t->c_cflag & PARODD) ? 1 : 0;
0257 
0258   /* Stop bits */
0259   if (t->c_cflag & CSTOPB ) {
0260     /* Two stop bits */
0261     return -1;
0262   }
0263 
0264   /* Disable LIN */
0265   regs->LCR.R = 0;
0266 
0267   /* Set control registers */
0268   regs->CR2.R = cr2.R;
0269   regs->CR1.R = cr1.R;
0270 
0271   return 0;
0272 }
0273 
0274 static int mpc55xx_esci_first_open(int major, int minor, void *arg)
0275 {
0276   rtems_status_code sc = RTEMS_SUCCESSFUL;
0277   int rv = 0;
0278   mpc55xx_esci_context *self = console_generic_get_context(minor);
0279   struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
0280 
0281   self->tty = tty;
0282 
0283   rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
0284   if (rv != 0) {
0285     bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_BAUD);
0286   }
0287 
0288   rv = mpc55xx_esci_set_attributes(minor, &tty->termios);
0289   if (rv != 0) {
0290     bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_ATTRIBUTES);
0291   }
0292 
0293   sc = mpc55xx_interrupt_handler_install(
0294     self->irq,
0295     "eSCI",
0296     RTEMS_INTERRUPT_UNIQUE,
0297     MPC55XX_INTC_DEFAULT_PRIORITY,
0298     mpc55xx_esci_interrupt_handler,
0299     self
0300   );
0301   if (sc != RTEMS_SUCCESSFUL) {
0302     bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_IRQ_INSTALL);
0303   }
0304 
0305   mpc55xx_esci_interrupts_clear_and_enable(self);
0306   self->transmit_in_progress = false;
0307 
0308   return 0;
0309 }
0310 
0311 static int mpc55xx_esci_last_close(int major, int minor, void* arg)
0312 {
0313   mpc55xx_esci_context *self = console_generic_get_context(minor);
0314 
0315   mpc55xx_esci_interrupts_disable(self);
0316   self->tty = NULL;
0317 
0318   return 0;
0319 }
0320 
0321 static int mpc55xx_esci_poll_read(int minor)
0322 {
0323   mpc55xx_esci_context *self = console_generic_get_context(minor);
0324   volatile struct ESCI_tag *regs = self->regs;
0325   union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
0326   rtems_interrupt_level level;
0327   int c = -1;
0328 
0329   rtems_interrupt_disable(level);
0330   if (regs->SR.B.RDRF != 0) {
0331     /* Clear flag */
0332     sr.B.RDRF = 1;
0333     regs->SR.R = sr.R;
0334 
0335     /* Read */
0336     c = regs->DR.B.D;
0337   }
0338   rtems_interrupt_enable(level);
0339 
0340   return c;
0341 }
0342 
0343 static int mpc55xx_esci_write(int minor, const char *out, size_t n)
0344 {
0345   if (n > 0) {
0346     mpc55xx_esci_context *self = console_generic_get_context(minor);
0347 
0348     self->regs->DR.B.D = out [0];
0349     self->transmit_in_progress = true;
0350   }
0351 
0352   return 0;
0353 }
0354 
0355 const console_generic_callbacks mpc55xx_esci_callbacks = {
0356   .termios_callbacks = {
0357     .firstOpen = mpc55xx_esci_first_open,
0358     .lastClose = mpc55xx_esci_last_close,
0359     .write = mpc55xx_esci_write,
0360     .setAttributes = mpc55xx_esci_set_attributes,
0361     .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
0362   },
0363   .poll_read = mpc55xx_esci_poll_read,
0364   .poll_write = mpc55xx_esci_poll_write
0365 };
0366 
0367 #endif /* MPC55XX_HAS_ESCI */