Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsPowerPCQorIQUartBridge
0007  *
0008  * @brief UART bridge slave implementation.
0009  */
0010 
0011 /*
0012  * Copyright (c) 2011 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <assert.h>
0037 
0038 #include <libchip/sersupp.h>
0039 
0040 #include <bspopts.h>
0041 #include <bsp/uart-bridge.h>
0042 
0043 #define TRANSMIT_EVENT RTEMS_EVENT_13
0044 
0045 static rtems_mode disable_preemption(void)
0046 {
0047   rtems_status_code sc = RTEMS_SUCCESSFUL;
0048   rtems_mode prev_mode = 0;
0049 
0050   sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode);
0051   assert(sc == RTEMS_SUCCESSFUL);
0052 
0053   return prev_mode;
0054 }
0055 
0056 static void restore_preemption(rtems_mode prev_mode)
0057 {
0058   rtems_status_code sc = RTEMS_SUCCESSFUL;
0059 
0060   sc = rtems_task_mode (prev_mode, RTEMS_PREEMPT_MASK, &prev_mode);
0061   assert(sc == RTEMS_SUCCESSFUL);
0062 }
0063 
0064 static void uart_bridge_slave_service(intercom_packet *packet, void *arg)
0065 {
0066   uart_bridge_slave_context *ctx = arg;
0067   struct rtems_termios_tty *tty = ctx->tty;
0068 
0069   /* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
0070   rtems_mode prev_mode = disable_preemption();
0071 
0072   rtems_termios_enqueue_raw_characters(tty, packet->data, (int) packet->size);
0073   qoriq_intercom_free_packet(packet);
0074 
0075   restore_preemption(prev_mode);
0076 }
0077 
0078 static void transmit_task(rtems_task_argument arg)
0079 {
0080   rtems_status_code sc = RTEMS_SUCCESSFUL;
0081   uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) arg;
0082   rtems_chain_control *fifo = &ctx->transmit_fifo;
0083   struct rtems_termios_tty *tty = ctx->tty;
0084 
0085   while (true) {
0086     intercom_packet *packet = NULL;
0087     sc = rtems_chain_get_with_wait(
0088       fifo,
0089       TRANSMIT_EVENT,
0090       RTEMS_NO_TIMEOUT,
0091       (rtems_chain_node **) &packet
0092     );
0093     assert(sc == RTEMS_SUCCESSFUL);
0094 
0095     /* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
0096     rtems_mode prev_mode = disable_preemption();
0097 
0098     size_t size = packet->size;
0099     qoriq_intercom_send_packet(QORIQ_UART_BRIDGE_MASTER_CORE, packet);
0100     rtems_termios_dequeue_characters(tty, (int) size);
0101 
0102     restore_preemption(prev_mode);
0103   }
0104 }
0105 
0106 static void create_transmit_task(
0107   uart_bridge_slave_context *ctx
0108 )
0109 {
0110   rtems_status_code sc = RTEMS_SUCCESSFUL;
0111   rtems_id task = RTEMS_ID_NONE;
0112   char index = (char) ('0' + ctx->type - INTERCOM_TYPE_UART_0);
0113 
0114   sc = rtems_task_create(
0115     rtems_build_name('U', 'B', 'T', index),
0116     QORIQ_UART_BRIDGE_TASK_PRIORITY,
0117     0,
0118     RTEMS_DEFAULT_MODES,
0119     RTEMS_DEFAULT_ATTRIBUTES,
0120     &task
0121   );
0122   assert(sc == RTEMS_SUCCESSFUL);
0123 
0124   sc = rtems_task_start(
0125     task,
0126     transmit_task,
0127     (rtems_task_argument) ctx
0128   );
0129   assert(sc == RTEMS_SUCCESSFUL);
0130 
0131   ctx->transmit_task = task;
0132 }
0133 
0134 static bool first_open(
0135   struct rtems_termios_tty *tty,
0136   rtems_termios_device_context *base,
0137   struct termios *term,
0138   rtems_libio_open_close_args_t *args
0139 )
0140 {
0141   uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
0142   intercom_type type = ctx->type;
0143 
0144   ctx->tty = tty;
0145   rtems_termios_set_initial_baud(tty, 115200);
0146   create_transmit_task(ctx);
0147   qoriq_intercom_service_install(type, uart_bridge_slave_service, ctx);
0148 
0149   return true;
0150 }
0151 
0152 static void last_close(
0153   struct rtems_termios_tty *tty,
0154   rtems_termios_device_context *base,
0155   rtems_libio_open_close_args_t *args
0156 )
0157 {
0158   uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
0159 
0160   qoriq_intercom_service_remove(ctx->type);
0161 }
0162 
0163 static void write_with_interrupts(
0164   rtems_termios_device_context *base,
0165   const char *buf,
0166   size_t len
0167 )
0168 {
0169   if (len > 0) {
0170     rtems_status_code sc = RTEMS_SUCCESSFUL;
0171     uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
0172     intercom_packet *packet = qoriq_intercom_allocate_packet(
0173       ctx->type,
0174       INTERCOM_SIZE_64
0175     );
0176 
0177     packet->size = len;
0178     memcpy(packet->data, buf, len);
0179 
0180     /*
0181      * Due to the lovely Termios implementation we have to hand this over to
0182      * another context.
0183      */
0184     sc = rtems_chain_append_with_notification(
0185       &ctx->transmit_fifo,
0186       &packet->glue.node,
0187       ctx->transmit_task,
0188       TRANSMIT_EVENT
0189     );
0190     assert(sc == RTEMS_SUCCESSFUL);
0191   }
0192 }
0193 
0194 static bool set_attributes(
0195   rtems_termios_device_context *base,
0196   const struct termios *term
0197 )
0198 {
0199   return false;
0200 }
0201 
0202 const rtems_termios_device_handler qoriq_uart_bridge_slave = {
0203   .first_open = first_open,
0204   .last_close = last_close,
0205   .write = write_with_interrupts,
0206   .set_attributes = set_attributes,
0207   .mode = TERMIOS_IRQ_DRIVEN
0208 };