File indexing completed on 2025-05-11 08:23:54
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
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
0170 sr.R = regs->SR.R;
0171
0172
0173 if (sr.B.RDRF != 0) {
0174 active.B.RDRF = 1;
0175 }
0176
0177
0178 if (sr.B.TDRE != 0) {
0179 active.B.TDRE = 1;
0180 }
0181
0182
0183 rtems_interrupt_disable(level);
0184 regs->SR.R = active.R;
0185 self->transmit_in_progress = false;
0186 rtems_interrupt_enable(level);
0187
0188
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
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
0209 cr2.B.MDIS = 0;
0210
0211
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
0221 cr1.B.RWU = 0;
0222
0223
0224 cr2.B.RXDMA = 0;
0225 cr2.B.TXDMA = 0;
0226
0227
0228 cr1.B.ILT = 0;
0229
0230
0231 cr1.B.LOOPS = 0;
0232
0233
0234 cr1.B.RE = (t->c_cflag & CREAD) ? 1 : 0;
0235
0236
0237 cr1.B.TE = 1;
0238
0239
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
0249 if ((t->c_cflag & CSIZE) != CS8) {
0250 return -1;
0251 }
0252 cr1.B.M = 0;
0253
0254
0255 cr1.B.PE = (t->c_cflag & PARENB) ? 1 : 0;
0256 cr1.B.PT = (t->c_cflag & PARODD) ? 1 : 0;
0257
0258
0259 if (t->c_cflag & CSTOPB ) {
0260
0261 return -1;
0262 }
0263
0264
0265 regs->LCR.R = 0;
0266
0267
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
0332 sr.B.RDRF = 1;
0333 regs->SR.R = sr.R;
0334
0335
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