File indexing completed on 2025-05-11 08:24:07
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
0035
0036
0037
0038
0039 #include <bsp.h>
0040 #include <stdlib.h>
0041 #include <assert.h>
0042 #include <rtems/bspIo.h>
0043 #include <string.h>
0044 #include <stdio.h>
0045
0046 #include <drvmgr/drvmgr.h>
0047 #include <grlib/ambapp_bus.h>
0048 #include <grlib/apbuart.h>
0049 #include <grlib/ambapp.h>
0050 #include <grlib/io.h>
0051 #include <grlib/cons.h>
0052 #include <rtems/termiostypes.h>
0053 #include <grlib/apbuart_cons.h>
0054
0055 #ifdef LEON3
0056 #include <bsp/leon3.h>
0057 #endif
0058
0059
0060
0061 #ifdef DEBUG
0062 #define DBG(x...) printk(x)
0063 #else
0064 #define DBG(x...)
0065 #endif
0066
0067
0068 enum {
0069 CAP_FIFO = 0x01,
0070 CAP_DI = 0x02,
0071 };
0072 struct apbuart_priv {
0073 struct console_dev condev;
0074 struct drvmgr_dev *dev;
0075 apbuart *regs;
0076 struct rtems_termios_tty *tty;
0077 char devName[52];
0078 volatile int sending;
0079 int mode;
0080 int cap;
0081 };
0082
0083
0084
0085 static struct console_dev *base_get_condev(rtems_termios_device_context *base)
0086 {
0087 return (struct console_dev *) base;
0088 }
0089
0090 static struct apbuart_priv *condev_get_priv(struct console_dev *condev)
0091 {
0092 return (struct apbuart_priv *) condev;
0093 }
0094
0095 static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base)
0096 {
0097 return condev_get_priv(base_get_condev(base));
0098 }
0099
0100
0101 static bool first_open(
0102 rtems_termios_tty *tty,
0103 rtems_termios_device_context *base,
0104 struct termios *term,
0105 rtems_libio_open_close_args_t *args
0106 );
0107 static void last_close(
0108 rtems_termios_tty *tty,
0109 rtems_termios_device_context *base,
0110 rtems_libio_open_close_args_t *args
0111 );
0112 static void write_interrupt(
0113 rtems_termios_device_context *base,
0114 const char *buf,
0115 size_t len
0116 );
0117 static bool set_attributes(
0118 rtems_termios_device_context *base,
0119 const struct termios *t
0120 );
0121 static void get_attributes(
0122 rtems_termios_device_context *base,
0123 struct termios *t
0124 );
0125 static int read_polled(rtems_termios_device_context *base);
0126 static int read_task(rtems_termios_device_context *base);
0127 static void write_polled(
0128 rtems_termios_device_context *base,
0129 const char *buf,
0130 size_t len
0131 );
0132
0133 static void apbuart_cons_isr(void *arg);
0134 int apbuart_get_baud(struct apbuart_priv *uart);
0135
0136 int apbuart_init1(struct drvmgr_dev *dev);
0137 #ifdef APBUART_INFO_AVAIL
0138 static int apbuart_info(
0139 struct drvmgr_dev *dev,
0140 void (*print_line)(void *p, char *str),
0141 void *p, int, char *argv[]);
0142 #define APBUART_INFO_FUNC apbuart_info
0143 #else
0144 #define APBUART_INFO_FUNC NULL
0145 #endif
0146
0147 struct drvmgr_drv_ops apbuart_ops =
0148 {
0149 .init = {apbuart_init1, NULL, NULL, NULL},
0150 .remove = NULL,
0151 .info = APBUART_INFO_FUNC
0152 };
0153
0154 static struct amba_dev_id apbuart_ids[] =
0155 {
0156 {VENDOR_GAISLER, GAISLER_APBUART},
0157 {0, 0}
0158 };
0159
0160 static struct amba_drv_info apbuart_drv_info =
0161 {
0162 {
0163 DRVMGR_OBJ_DRV,
0164 NULL,
0165 NULL,
0166 DRIVER_AMBAPP_GAISLER_APBUART_ID,
0167 "APBUART_DRV",
0168 DRVMGR_BUS_TYPE_AMBAPP,
0169 &apbuart_ops,
0170 NULL,
0171 0,
0172 sizeof(struct apbuart_priv),
0173 },
0174 &apbuart_ids[0]
0175 };
0176
0177 void apbuart_cons_register_drv (void)
0178 {
0179 DBG("Registering APBUART Console driver\n");
0180 drvmgr_drv_register(&apbuart_drv_info.general);
0181 }
0182
0183 static const rtems_termios_device_handler handler_interrupt = {
0184 .first_open = first_open,
0185 .last_close = last_close,
0186 .write = write_interrupt,
0187 .set_attributes = set_attributes,
0188 .mode = TERMIOS_IRQ_DRIVEN
0189 };
0190
0191 static const rtems_termios_device_handler handler_task = {
0192 .first_open = first_open,
0193 .last_close = last_close,
0194 .poll_read = read_task,
0195 .write = write_interrupt,
0196 .set_attributes = set_attributes,
0197 .mode = TERMIOS_TASK_DRIVEN
0198 };
0199
0200 static const rtems_termios_device_handler handler_polled = {
0201 .first_open = first_open,
0202 .last_close = last_close,
0203 .poll_read = read_polled,
0204 .write = write_polled,
0205 .set_attributes = set_attributes,
0206 .mode = TERMIOS_POLLED
0207 };
0208
0209
0210
0211
0212
0213
0214 static int probecap(apbuart *regs)
0215 {
0216 int cap = 0;
0217 uint32_t ctrl;
0218
0219
0220 ctrl = grlib_load_32(®s->ctrl);
0221 if (ctrl & APBUART_CTRL_FA) {
0222 cap |= CAP_FIFO;
0223
0224
0225 ctrl |= APBUART_CTRL_DI;
0226 grlib_store_32(®s->ctrl, ctrl);
0227 ctrl = grlib_load_32(®s->ctrl);
0228 if (ctrl & APBUART_CTRL_DI) {
0229 ctrl &= ~APBUART_CTRL_DI;
0230 grlib_store_32(®s->ctrl, ctrl);
0231 cap |= CAP_DI;
0232 }
0233 }
0234
0235 return cap;
0236 }
0237
0238 int apbuart_init1(struct drvmgr_dev *dev)
0239 {
0240 struct apbuart_priv *priv;
0241 struct amba_dev_info *ambadev;
0242 struct ambapp_core *pnpinfo;
0243 union drvmgr_key_value *value;
0244 char prefix[32];
0245 unsigned int db;
0246 static int first_uart = 1;
0247 uint32_t ctrl;
0248
0249
0250
0251
0252
0253
0254
0255
0256 #if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
0257 if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
0258 drvmgr_keys_get(dev, NULL) != 0) {
0259
0260 return DRVMGR_EBUSY;
0261 }
0262 #endif
0263
0264 DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0265
0266 priv = dev->priv;
0267 if (!priv)
0268 return DRVMGR_NOMEM;
0269 priv->dev = dev;
0270
0271
0272 ambadev = (struct amba_dev_info *)priv->dev->businfo;
0273 if (ambadev == NULL)
0274 return -1;
0275 pnpinfo = &ambadev->info;
0276 priv->regs = (apbuart *)pnpinfo->apb_slv->start;
0277
0278
0279 grlib_store_32(&priv->regs->status, 0);
0280
0281 ctrl = grlib_load_32(&priv->regs->ctrl);
0282
0283
0284
0285
0286 db = 0;
0287 #ifdef LEON3
0288 if (priv->regs == leon3_debug_uart) {
0289 db = ctrl & (APBUART_CTRL_RE |
0290 APBUART_CTRL_TE |
0291 APBUART_CTRL_PE |
0292 APBUART_CTRL_PS);
0293 }
0294 #endif
0295
0296
0297
0298
0299
0300
0301
0302 if (ctrl & APBUART_CTRL_FL) {
0303 db |= ctrl & (APBUART_CTRL_DB |
0304 APBUART_CTRL_LB | APBUART_CTRL_FL);
0305 }
0306
0307 grlib_store_32(&priv->regs->ctrl, db);
0308
0309 priv->cap = probecap(priv->regs);
0310
0311
0312
0313
0314
0315
0316
0317 if (drvmgr_on_rootbus(dev) && first_uart) {
0318 priv->condev.flags = CONSOLE_FLAG_SYSCON;
0319 first_uart = 0;
0320 } else {
0321 priv->condev.flags = 0;
0322 }
0323
0324 value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT);
0325 if (value) {
0326 if (value->i)
0327 priv->condev.flags |= CONSOLE_FLAG_SYSCON;
0328 else
0329 priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
0330 }
0331
0332
0333 value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
0334 if (value)
0335 priv->mode = value->i;
0336 else
0337 priv->mode = TERMIOS_POLLED;
0338
0339 if (priv->mode == TERMIOS_IRQ_DRIVEN) {
0340 priv->condev.handler = &handler_interrupt;
0341 } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
0342 priv->condev.handler = &handler_task;
0343 } else {
0344 priv->condev.handler = &handler_polled;
0345 }
0346
0347 priv->condev.fsname = NULL;
0348
0349 prefix[0] = '\0';
0350 if (drvmgr_get_dev_prefix(dev, prefix) == DRVMGR_OK) {
0351
0352
0353
0354 sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
0355 priv->condev.fsname = priv->devName;
0356 } else {
0357 sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv);
0358 }
0359
0360
0361
0362
0363 console_dev_register(&priv->condev);
0364
0365 return DRVMGR_OK;
0366 }
0367
0368 #ifdef APBUART_INFO_AVAIL
0369 static int apbuart_info(
0370 struct drvmgr_dev *dev,
0371 void (*print_line)(void *p, char *str),
0372 void *p, int argc, char *argv[])
0373 {
0374 struct apbuart_priv *priv = dev->priv;
0375 char *str1;
0376 char buf[64];
0377
0378 if (dev->priv == NULL)
0379 return -DRVMGR_EINVAL;
0380
0381 if (priv->mode == TERMIOS_POLLED)
0382 str1 = "TERMIOS_POLLED";
0383 else if (priv->mode == TERMIOS_IRQ_DRIVEN)
0384 str1 = "TERMIOS_IRQ_DRIVEN";
0385 else if (priv->mode == TERMIOS_TASK_DRIVEN)
0386 str1 = "TERMIOS_TASK_DRIVEN";
0387 else
0388 str1 = "BAD MODE";
0389
0390 sprintf(buf, "UART Mode: %s", str1);
0391 print_line(p, buf);
0392 if (priv->condev.fsname) {
0393 sprintf(buf, "FS Name: %s", priv->condev.fsname);
0394 print_line(p, buf);
0395 }
0396 sprintf(buf, "STATUS REG: 0x%x", grlib_load_32(&priv->regs->status));
0397 print_line(p, buf);
0398 sprintf(buf, "CTRL REG: 0x%x", grlib_load_32(&priv->regs->ctrl));
0399 print_line(p, buf);
0400 sprintf(buf, "SCALER REG: 0x%x baud rate %d",
0401 grlib_load_32(&priv->regs->scaler),
0402 apbuart_get_baud(priv));
0403 print_line(p, buf);
0404
0405 return DRVMGR_OK;
0406 }
0407 #endif
0408
0409 static bool first_open(
0410 rtems_termios_tty *tty,
0411 rtems_termios_device_context *base,
0412 struct termios *term,
0413 rtems_libio_open_close_args_t *args
0414 )
0415 {
0416 struct apbuart_priv *uart = base_get_priv(base);
0417 apbuart *regs = uart->regs;
0418 uint32_t ctrl;
0419
0420 uart->tty = tty;
0421
0422
0423 if (uart->condev.flags & CONSOLE_FLAG_SYSCON_GRANT) {
0424 get_attributes(base, term);
0425 term->c_oflag |= ONLCR;
0426 set_attributes(base, term);
0427 }
0428
0429
0430 ctrl = grlib_load_32(®s->ctrl);
0431 ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
0432
0433 if (uart->mode != TERMIOS_POLLED) {
0434 int ret;
0435
0436
0437 ret = drvmgr_interrupt_register(
0438 uart->dev, 0, uart->devName, apbuart_cons_isr, tty
0439 );
0440 if (ret) {
0441 return false;
0442 }
0443
0444 uart->sending = 0;
0445
0446
0447 ctrl |= APBUART_CTRL_RI;
0448 if (uart->cap & CAP_DI) {
0449
0450 ctrl |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
0451 }
0452 }
0453
0454 grlib_store_32(®s->ctrl, ctrl);
0455
0456 return true;
0457 }
0458
0459 static void last_close(
0460 rtems_termios_tty *tty,
0461 rtems_termios_device_context *base,
0462 rtems_libio_open_close_args_t *args
0463 )
0464 {
0465 struct apbuart_priv *uart = base_get_priv(base);
0466 apbuart *regs = uart->regs;
0467 rtems_interrupt_lock_context lock_context;
0468 uint32_t ctrl;
0469
0470 if (uart->mode != TERMIOS_POLLED) {
0471
0472 rtems_termios_device_lock_acquire(base, &lock_context);
0473 ctrl = grlib_load_32(®s->ctrl);
0474 ctrl &= ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
0475 grlib_store_32(®s->ctrl, ctrl);
0476 rtems_termios_device_lock_release(base, &lock_context);
0477
0478
0479 while (uart->sending) {
0480
0481 }
0482 while (
0483 (grlib_load_32(®s->ctrl) & APBUART_CTRL_TE) &&
0484 !(grlib_load_32(®s->status) & APBUART_STATUS_TS)
0485 ) {
0486
0487 }
0488
0489
0490 drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
0491 }
0492
0493 #ifdef LEON3
0494
0495 if (regs != leon3_debug_uart) {
0496 ctrl = grlib_load_32(®s->ctrl);
0497 ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
0498 grlib_store_32(®s->ctrl, ctrl);
0499 }
0500 #endif
0501 }
0502
0503 static int read_polled(rtems_termios_device_context *base)
0504 {
0505 struct apbuart_priv *uart = base_get_priv(base);
0506
0507 return apbuart_inbyte_nonblocking(uart->regs);
0508 }
0509
0510
0511 static int read_task(rtems_termios_device_context *base)
0512 {
0513 rtems_interrupt_lock_context lock_context;
0514 struct apbuart_priv *uart = base_get_priv(base);
0515 apbuart *regs = uart->regs;
0516 int cnt;
0517 char buf[33];
0518 struct rtems_termios_tty *tty;
0519 uint32_t ctrl;
0520 uint32_t ctrl_add;
0521
0522 ctrl_add = APBUART_CTRL_RI;
0523 if (uart->cap & CAP_DI) {
0524 ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
0525 }
0526 tty = uart->tty;
0527 do {
0528 cnt = 0;
0529 while (
0530 (grlib_load_32(®s->status) & APBUART_STATUS_DR) &&
0531 (cnt < sizeof(buf))
0532 ) {
0533 buf[cnt] = grlib_load_32(®s->data);
0534 cnt++;
0535 }
0536 if (0 < cnt) {
0537
0538 rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
0539 }
0540
0541
0542
0543
0544
0545
0546 rtems_termios_device_lock_acquire(base, &lock_context);
0547 ctrl = grlib_load_32(®s->ctrl);
0548 ctrl |= ctrl_add;
0549 grlib_store_32(®s->ctrl, ctrl);
0550 rtems_termios_device_lock_release(base, &lock_context);
0551 } while (grlib_load_32(®s->status) & APBUART_STATUS_DR);
0552
0553 return EOF;
0554 }
0555
0556 int apbuart_get_baud(struct apbuart_priv *uart)
0557 {
0558 unsigned int core_clk_hz;
0559 unsigned int scaler;
0560
0561
0562 scaler = grlib_load_32(&uart->regs->scaler);
0563
0564
0565 drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
0566
0567
0568 return core_clk_hz / ((scaler + 1) * 8);
0569 }
0570
0571 static bool set_attributes(
0572 rtems_termios_device_context *base,
0573 const struct termios *t
0574 )
0575 {
0576 unsigned int core_clk_hz;
0577 unsigned int scaler;
0578 unsigned int ctrl;
0579 int baud;
0580 struct apbuart_priv *uart = base_get_priv(base);
0581 rtems_interrupt_lock_context lock_context;
0582
0583 switch(t->c_cflag & CSIZE) {
0584 default:
0585 case CS5:
0586 case CS6:
0587 case CS7:
0588
0589 return false;
0590 case CS8:
0591 break;
0592 }
0593
0594 rtems_termios_device_lock_acquire(base, &lock_context);
0595
0596
0597 ctrl = grlib_load_32(&uart->regs->ctrl);
0598
0599 switch(t->c_cflag & (PARENB|PARODD)){
0600 case (PARENB|PARODD):
0601
0602 ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
0603 break;
0604
0605 case PARENB:
0606
0607 ctrl &= ~APBUART_CTRL_PS;
0608 ctrl |= APBUART_CTRL_PE;
0609 break;
0610
0611 default:
0612 case 0:
0613 case PARODD:
0614
0615 ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
0616 }
0617
0618 if (!(t->c_cflag & CLOCAL))
0619 ctrl |= APBUART_CTRL_FL;
0620 else
0621 ctrl &= ~APBUART_CTRL_FL;
0622
0623
0624 grlib_store_32(&uart->regs->ctrl, ctrl);
0625
0626 rtems_termios_device_lock_release(base, &lock_context);
0627
0628
0629 baud = rtems_termios_baud_to_number(t->c_ospeed);
0630 if (baud > 0){
0631
0632 drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
0633
0634
0635 scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
0636
0637
0638 grlib_store_32(&uart->regs->scaler, scaler);
0639 }
0640
0641 return true;
0642 }
0643
0644 static void get_attributes(
0645 rtems_termios_device_context *base,
0646 struct termios *t
0647 )
0648 {
0649 struct apbuart_priv *uart = base_get_priv(base);
0650 unsigned int ctrl;
0651
0652 t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
0653
0654
0655 t->c_cflag |= CS8;
0656
0657
0658 ctrl = grlib_load_32(&uart->regs->ctrl);
0659 if (ctrl & APBUART_CTRL_PE) {
0660 if (ctrl & APBUART_CTRL_PS)
0661 t->c_cflag |= PARENB|PARODD;
0662 else
0663 t->c_cflag |= PARENB;
0664 }
0665
0666 if ((ctrl & APBUART_CTRL_FL) == 0)
0667 t->c_cflag |= CLOCAL;
0668
0669 rtems_termios_set_best_baud(t, apbuart_get_baud(uart));
0670 }
0671
0672 static void write_polled(
0673 rtems_termios_device_context *base,
0674 const char *buf,
0675 size_t len
0676 )
0677 {
0678 struct apbuart_priv *uart = base_get_priv(base);
0679 int nwrite = 0;
0680
0681 while (nwrite < len) {
0682 apbuart_outbyte_polled(uart->regs, *buf++);
0683 nwrite++;
0684 }
0685 }
0686
0687 static void write_interrupt(
0688 rtems_termios_device_context *base,
0689 const char *buf,
0690 size_t len
0691 )
0692 {
0693 struct apbuart_priv *uart = base_get_priv(base);
0694 apbuart *regs = uart->regs;
0695 int sending;
0696 unsigned int ctrl;
0697
0698 ctrl = grlib_load_32(®s->ctrl);
0699
0700 if (len > 0) {
0701
0702
0703
0704
0705
0706 ctrl |= APBUART_CTRL_TI;
0707 grlib_store_32(®s->ctrl, ctrl);
0708
0709 if (ctrl & APBUART_CTRL_FA) {
0710
0711 sending = 0;
0712 while (
0713 ((grlib_load_32(®s->status) & APBUART_STATUS_TF) == 0) &&
0714 (sending < len)
0715 ) {
0716 grlib_store_32(®s->data, *buf);
0717 buf++;
0718 sending++;
0719 }
0720 } else {
0721
0722 grlib_store_32(®s->data, *buf);
0723
0724 sending = 1;
0725 }
0726 } else {
0727
0728 ctrl &= ~APBUART_CTRL_TI;
0729 grlib_store_32(®s->ctrl, ctrl);
0730
0731
0732 sending = 0;
0733 }
0734
0735 uart->sending = sending;
0736 }
0737
0738
0739 static void apbuart_cons_isr(void *arg)
0740 {
0741 rtems_termios_tty *tty = arg;
0742 rtems_termios_device_context *base;
0743 struct console_dev *condev = rtems_termios_get_device_context(tty);
0744 struct apbuart_priv *uart = condev_get_priv(condev);
0745 apbuart *regs = uart->regs;
0746 unsigned int status;
0747 char buf[33];
0748 int cnt;
0749
0750 if (uart->mode == TERMIOS_TASK_DRIVEN) {
0751 if ((status = grlib_load_32(®s->status)) & APBUART_STATUS_DR) {
0752 rtems_interrupt_lock_context lock_context;
0753 uint32_t ctrl;
0754
0755
0756 base = rtems_termios_get_device_context(tty);
0757 rtems_termios_device_lock_acquire(base, &lock_context);
0758 ctrl = grlib_load_32(®s->ctrl);
0759 ctrl &=
0760 ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
0761 APBUART_CTRL_RF);
0762 grlib_store_32(®s->ctrl, ctrl);
0763 rtems_termios_device_lock_release(base, &lock_context);
0764
0765 rtems_termios_rxirq_occured(tty);
0766 }
0767 } else {
0768
0769
0770
0771
0772
0773 cnt = 0;
0774 while (
0775 ((status=grlib_load_32(®s->status)) & APBUART_STATUS_DR) &&
0776 (cnt < sizeof(buf))
0777 ) {
0778 buf[cnt] = grlib_load_32(®s->data);
0779 cnt++;
0780 }
0781 if (0 < cnt) {
0782
0783 rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
0784 }
0785 }
0786
0787 if (uart->sending && (status & APBUART_STATUS_TE)) {
0788
0789 cnt = uart->sending;
0790
0791
0792
0793
0794
0795
0796
0797 rtems_termios_dequeue_characters(tty, cnt);
0798 }
0799 }
0800