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-linflex.h>
0035
0036 #include <bsp.h>
0037 #include <bsp/fatal.h>
0038 #include <bsp/irq.h>
0039
0040 #ifdef MPC55XX_HAS_LINFLEX
0041
0042 mpc55xx_linflex_context mpc55xx_linflex_devices [] = {
0043 {
0044 .regs = &LINFLEX0,
0045 .irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(0),
0046 .irq_txi = MPC55XX_IRQ_LINFLEX_TXI(0),
0047 .irq_err = MPC55XX_IRQ_LINFLEX_ERR(0),
0048 .tx_pcr_register = &((SIU_tag *) &SIUL)->PCR18,
0049 .tx_pa_value = 1,
0050 .rx_pcr_register = &((SIU_tag *) &SIUL)->PCR19,
0051 .rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI31,
0052 .rx_padsel_value = 0
0053 }, {
0054 .regs = &LINFLEX1,
0055 .irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(1),
0056 .irq_txi = MPC55XX_IRQ_LINFLEX_TXI(1),
0057 .irq_err = MPC55XX_IRQ_LINFLEX_ERR(1),
0058 .tx_pcr_register = &((SIU_tag *) &SIUL)->PCR94,
0059 .tx_pa_value = 1,
0060 .rx_pcr_register = &((SIU_tag *) &SIUL)->PCR95,
0061 .rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI32,
0062 .rx_padsel_value = 2
0063 }
0064 };
0065
0066 static void enter_init_mode(volatile LINFLEX_tag *regs)
0067 {
0068 LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
0069 cr1.B.SLEEP = 0;
0070 cr1.B.INIT = 1;
0071 regs->LINCR1.R = cr1.R;
0072 }
0073
0074 static void enter_active_mode(volatile LINFLEX_tag *regs)
0075 {
0076 LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
0077 cr1.B.SLEEP = 0;
0078 cr1.B.INIT = 0;
0079 regs->LINCR1.R = cr1.R;
0080 }
0081
0082 static void enter_sleep_mode(volatile LINFLEX_tag *regs)
0083 {
0084 LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
0085 cr1.B.SLEEP = 1;
0086 cr1.B.INIT = 0;
0087 regs->LINCR1.R = cr1.R;
0088 }
0089
0090 static void mpc55xx_linflex_poll_write(int minor, char c)
0091 {
0092 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0093 volatile LINFLEX_tag *regs = self->regs;
0094 const LINFLEX_UARTSR_32B_tag clear_dtf = { .B = { .DTF_TFF = 1 } };
0095 rtems_interrupt_level level;
0096 bool done = false;
0097 bool wait_for_transmit_done = false;
0098
0099 rtems_interrupt_disable(level);
0100 if (self->transmit_nest_level == 0) {
0101 LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
0102
0103 if (ier.B.DTIE != 0) {
0104 ier.B.DTIE = 0;
0105 regs->LINIER.R = ier.R;
0106 wait_for_transmit_done = !self->transmit_in_progress;
0107 self->transmit_nest_level = 1;
0108 }
0109 } else {
0110 ++self->transmit_nest_level;
0111 }
0112 rtems_interrupt_enable(level);
0113
0114 while (!done) {
0115 rtems_interrupt_disable(level);
0116 bool tx = self->transmit_in_progress;
0117 if (!tx || (tx && regs->UARTSR.B.DTF_TFF)) {
0118 regs->UARTSR.R = clear_dtf.R;
0119 regs->BDRL.B.DATA0 = c;
0120 self->transmit_in_progress = true;
0121 done = true;
0122 }
0123 rtems_interrupt_enable(level);
0124 }
0125
0126 done = false;
0127 while (!done) {
0128 rtems_interrupt_disable(level);
0129 if (wait_for_transmit_done) {
0130 if (regs->UARTSR.B.DTF_TFF) {
0131 regs->UARTSR.R = clear_dtf.R;
0132 self->transmit_in_progress = false;
0133 done = true;
0134 }
0135 } else {
0136 done = true;
0137 }
0138
0139 if (done && self->transmit_nest_level > 0) {
0140 --self->transmit_nest_level;
0141
0142 if (self->transmit_nest_level == 0) {
0143 LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
0144
0145 ier.B.DTIE = 1;
0146 regs->LINIER.R = ier.R;
0147 }
0148 }
0149 rtems_interrupt_enable(level);
0150 }
0151 }
0152
0153 static void mpc55xx_linflex_rx_interrupt_handler(void *arg)
0154 {
0155 mpc55xx_linflex_context *self = arg;
0156 volatile LINFLEX_tag *regs = self->regs;
0157 char c = regs->BDRM.B.DATA4;
0158 const LINFLEX_UARTSR_32B_tag clear_flags = { .B = { .RMB = 1, .DRF_RFE = 1 } };
0159
0160 regs->UARTSR.R = clear_flags.R;
0161
0162 rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
0163 }
0164
0165 static void mpc55xx_linflex_tx_interrupt_handler(void *arg)
0166 {
0167 mpc55xx_linflex_context *self = arg;
0168 volatile LINFLEX_tag *regs = self->regs;
0169
0170 regs->UARTSR.B.DTF_TFF = 1;
0171 self->transmit_in_progress = false;
0172
0173 rtems_termios_dequeue_characters(self->tty, 1);
0174 }
0175
0176
0177
0178
0179
0180
0181
0182
0183 static int mpc55xx_linflex_set_attributes(int minor, const struct termios *t)
0184 {
0185 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0186 volatile LINFLEX_tag *regs = self->regs;
0187 LINFLEX_UARTCR_32B_tag uartcr = { .R = 0 };
0188 LINFLEX_GCR_32B_tag gcr = { .R = 0 };
0189 LINFLEX_LINIER_32B_tag ier = { .R = 0 };
0190 rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
0191 LINFLEX_LINFBRR_32B_tag fbrr = { .R = 0 };
0192 LINFLEX_LINIBRR_32B_tag ibrr = { .R = 0 };
0193
0194 enter_init_mode(regs);
0195
0196
0197 uartcr.B.UART = 1;
0198 regs->UARTCR.R = uartcr.R;
0199
0200
0201 uartcr.B.TDFL_TFC = 0;
0202 uartcr.B.RDFL_RFC0 = 0;
0203 uartcr.B.RFBM = 0;
0204 uartcr.B.TFBM = 0;
0205
0206
0207 uartcr.B.RXEN = 1;
0208 uartcr.B.TXEN = 1;
0209
0210
0211 uartcr.B.WL1 = 0;
0212 if ((t->c_cflag & CSIZE) == CS8) {
0213 uartcr.B.WL0 = 1;
0214 } else if ((t->c_cflag & CSIZE) == CS7) {
0215 uartcr.B.WL0 = 0;
0216 } else {
0217 return -1;
0218 }
0219
0220
0221 uartcr.B.PCE = (t->c_cflag & PARENB) ? 1 : 0;
0222 uartcr.B.PC1 = 0;
0223 uartcr.B.PC0 = (t->c_cflag & PARODD) ? 1 : 0;
0224
0225
0226 gcr.B.STOP = (t->c_cflag & CSTOPB) ? 1 : 0;
0227
0228
0229 regs->UARTCR.R = uartcr.R;
0230 regs->GCR.R = gcr.R;
0231
0232
0233 ier.B.DTIE = 1;
0234 ier.B.DRIE = 1;
0235 regs->LINIER.R = ier.R;
0236
0237
0238 if (br > 0) {
0239 uint32_t lfdiv_mult_32 = bsp_clock_speed * 2 / br;
0240 if((lfdiv_mult_32 & 0x1) != 0) {
0241 ++lfdiv_mult_32;
0242 }
0243 fbrr.B.FBR = (lfdiv_mult_32 >> 1) & 0xF;
0244 ibrr.B.IBR = lfdiv_mult_32 >> 5;
0245 } else {
0246 return -1;
0247 }
0248 regs->LINFBRR.R = fbrr.R;
0249 regs->LINIBRR.R = ibrr.R;
0250
0251 enter_active_mode(regs);
0252
0253 return 0;
0254 }
0255
0256 static int mpc55xx_linflex_first_open(int major, int minor, void *arg)
0257 {
0258 rtems_status_code sc = RTEMS_SUCCESSFUL;
0259 int rv = 0;
0260 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0261 struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
0262 SIU_PCR_tag pcr = { .R = 0 };
0263 SIUL_PSMI_8B_tag psmi = { .R = 0 };
0264
0265 self->tty = tty;
0266
0267 pcr.B.IBE = 1;
0268 self->rx_pcr_register->R = pcr.R;
0269 psmi.B.PADSEL = self->rx_padsel_value;
0270 self->rx_psmi_register->R = psmi.R;
0271 pcr.R = 0;
0272 pcr.B.OBE = 1;
0273 pcr.B.PA = self->tx_pa_value;
0274 self->tx_pcr_register->R = pcr.R;
0275
0276 rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
0277 if (rv != 0) {
0278 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_BAUD);
0279 }
0280
0281 rv = mpc55xx_linflex_set_attributes(minor, &tty->termios);
0282 if (rv != 0) {
0283 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ATTRIBUTES);
0284 }
0285
0286 sc = mpc55xx_interrupt_handler_install(
0287 self->irq_rxi,
0288 "LINFlexD RXI",
0289 RTEMS_INTERRUPT_UNIQUE,
0290 MPC55XX_INTC_DEFAULT_PRIORITY,
0291 mpc55xx_linflex_rx_interrupt_handler,
0292 self
0293 );
0294 if (sc != RTEMS_SUCCESSFUL) {
0295 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_INSTALL);
0296 }
0297
0298 sc = mpc55xx_interrupt_handler_install(
0299 self->irq_txi,
0300 "LINFlexD TXI",
0301 RTEMS_INTERRUPT_UNIQUE,
0302 MPC55XX_INTC_DEFAULT_PRIORITY,
0303 mpc55xx_linflex_tx_interrupt_handler,
0304 self
0305 );
0306 if (sc != RTEMS_SUCCESSFUL) {
0307 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_INSTALL);
0308 }
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324 return 0;
0325 }
0326
0327 static int mpc55xx_linflex_last_close(int major, int minor, void* arg)
0328 {
0329 rtems_status_code sc = RTEMS_SUCCESSFUL;
0330 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0331 volatile LINFLEX_tag *regs = self->regs;
0332 SIU_PCR_tag pcr = { .R = 0 };
0333 SIUL_PSMI_8B_tag psmi = { .R = 0 };
0334
0335
0336 enter_init_mode(regs);
0337
0338
0339 regs->LINIER.R = 0;
0340
0341
0342 enter_sleep_mode(regs);
0343
0344 sc = rtems_interrupt_handler_remove(
0345 self->irq_rxi,
0346 mpc55xx_linflex_rx_interrupt_handler,
0347 self
0348 );
0349 if (sc != RTEMS_SUCCESSFUL) {
0350 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_REMOVE);
0351 }
0352
0353 sc = rtems_interrupt_handler_remove(
0354 self->irq_txi,
0355 mpc55xx_linflex_tx_interrupt_handler,
0356 self
0357 );
0358 if (sc != RTEMS_SUCCESSFUL) {
0359 bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_REMOVE);
0360 }
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373 pcr.B.IBE = 1;
0374 self->rx_pcr_register->R = pcr.R;
0375 self->tx_pcr_register->R = pcr.R;
0376 psmi.R = 0;
0377 self->rx_psmi_register->R = psmi.R;
0378
0379 self->tty = NULL;
0380
0381 return 0;
0382 }
0383
0384 static int mpc55xx_linflex_poll_read(int minor)
0385 {
0386 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0387 volatile LINFLEX_tag *regs = self->regs;
0388 rtems_interrupt_level level;
0389 int c = -1;
0390
0391 rtems_interrupt_disable(level);
0392 if (regs->UARTSR.B.DRF_RFE != 0) {
0393
0394 regs->UARTSR.B.DRF_RFE = 1;
0395
0396
0397 c = regs->BDRM.B.DATA4;
0398 }
0399 rtems_interrupt_enable(level);
0400
0401 return c;
0402 }
0403
0404 static int mpc55xx_linflex_write(int minor, const char *out, size_t n)
0405 {
0406 if (n > 0) {
0407 mpc55xx_linflex_context *self = console_generic_get_context(minor);
0408 volatile LINFLEX_tag *regs = self->regs;
0409
0410 regs->BDRL.B.DATA0 = out [0];
0411 self->transmit_in_progress = true;
0412
0413 }
0414
0415 return 0;
0416 }
0417
0418 const console_generic_callbacks mpc55xx_linflex_callbacks = {
0419 .termios_callbacks = {
0420 .firstOpen = mpc55xx_linflex_first_open,
0421 .lastClose = mpc55xx_linflex_last_close,
0422 .write = mpc55xx_linflex_write,
0423 .setAttributes = mpc55xx_linflex_set_attributes,
0424 .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
0425 },
0426 .poll_read = mpc55xx_linflex_poll_read,
0427 .poll_write = mpc55xx_linflex_poll_write
0428 };
0429
0430 #endif