Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:42

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsAArch64XilinxZynqMP
0007  *
0008  * @brief This source file contains the management console implementation.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2024 On-Line Applications Research Corporation (OAR)
0013  * Written by Kinsey Moore <kinsey.moore@oarcorp.com>
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <bsp/aarch64-mmu.h>
0038 #include <bsp/fdt.h>
0039 
0040 #include <libchip/ns16550.h>
0041 #include <libfdt.h>
0042 
0043 #include <rtems/endian.h>
0044 #include <rtems/sysinit.h>
0045 
0046 uint32_t mgmt_uart_reg_shift = 0;
0047 
0048 static uint8_t get_register(uintptr_t addr, uint8_t i)
0049 {
0050   volatile uint8_t *reg = (uint8_t *) addr;
0051 
0052   i <<= mgmt_uart_reg_shift;
0053   return reg [i];
0054 }
0055 
0056 static void set_register(uintptr_t addr, uint8_t i, uint8_t val)
0057 {
0058   volatile uint8_t *reg = (uint8_t *) addr;
0059 
0060   i <<= mgmt_uart_reg_shift;
0061   reg [i] = val;
0062 }
0063 
0064 static ns16550_context zynqmp_mgmt_uart_context = {
0065   .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Management UART 0"),
0066   .get_reg = get_register,
0067   .set_reg = set_register,
0068   .port = 0,
0069   .irq = 0,
0070   .clock = 0,
0071   .initial_baud = 0,
0072 };
0073 
0074 __attribute__ ((weak)) void zynqmp_configure_management_console(rtems_termios_device_context *base)
0075 {
0076   /* This SLIP-encoded watchdog command sets timeouts to 0xFFFFFFFF seconds. */
0077   const char mgmt_watchdog_cmd[] =
0078     "\xc0\xda\x00\x00\xff\xff\xff\xff\xff\x00\xff\xff\xff\xffM#\xc0";
0079 
0080   /* Send the system watchdog configuration command */
0081   for (int i = 0; i < sizeof(mgmt_watchdog_cmd); i++) {
0082     ns16550_polled_putchar(base, mgmt_watchdog_cmd[i]);
0083   }
0084 }
0085 
0086 static void zynqmp_management_console_init(void)
0087 {
0088   /* Find the management console in the device tree */
0089   const void *fdt = bsp_fdt_get();
0090   const uint32_t *prop;
0091   uint32_t outprop[4];
0092   int proplen;
0093   int node;
0094 
0095   const char *alias = fdt_get_alias(fdt, "mgmtport");
0096   if (alias == NULL) {
0097     return;
0098   }
0099   node = fdt_path_offset(fdt, alias);
0100 
0101   prop = fdt_getprop(fdt, node, "clock-frequency", &proplen);
0102   if ( prop == NULL || proplen != 4 ) {
0103     zynqmp_mgmt_uart_context.port = 0;
0104     return;
0105   }
0106   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0107   zynqmp_mgmt_uart_context.clock = outprop[0];
0108 
0109   prop = fdt_getprop(fdt, node, "current-speed", &proplen);
0110   if ( prop == NULL || proplen != 4 ) {
0111     zynqmp_mgmt_uart_context.port = 0;
0112     return;
0113   }
0114   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0115   zynqmp_mgmt_uart_context.initial_baud = outprop[0];
0116 
0117   prop = fdt_getprop(fdt, node, "interrupts", &proplen);
0118   if ( prop == NULL || proplen != 12 ) {
0119     zynqmp_mgmt_uart_context.port = 0;
0120     return;
0121   }
0122   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0123   outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
0124   outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
0125   /* proplen is in bytes, interrupt mapping expects a length in 32-bit cells */
0126   zynqmp_mgmt_uart_context.irq = bsp_fdt_map_intr(outprop, proplen / 4);
0127   if ( zynqmp_mgmt_uart_context.irq == 0 ) {
0128     zynqmp_mgmt_uart_context.port = 0;
0129     return;
0130   }
0131 
0132   prop = fdt_getprop(fdt, node, "reg", &proplen);
0133   if ( prop == NULL || proplen != 16 ) {
0134     zynqmp_mgmt_uart_context.port = 0;
0135     return;
0136   }
0137   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0138   outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
0139   outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
0140   outprop[3] = rtems_uint32_from_big_endian((const uint8_t *) &prop[3]);
0141   zynqmp_mgmt_uart_context.port = ( ( (uint64_t) outprop[0] ) << 32 ) | outprop[1];
0142   uintptr_t uart_base = zynqmp_mgmt_uart_context.port;
0143   size_t uart_size = ( ( (uint64_t) outprop[2] ) << 32 ) | outprop[3];
0144 
0145   rtems_status_code sc = aarch64_mmu_map( uart_base,
0146                                           uart_size,
0147                                           AARCH64_MMU_DEVICE);
0148   if ( sc != RTEMS_SUCCESSFUL ) {
0149     zynqmp_mgmt_uart_context.port = 0;
0150     return;
0151   }
0152 
0153   prop = fdt_getprop(fdt, node, "reg-offset", &proplen);
0154   if ( prop == NULL || proplen != 4 ) {
0155     zynqmp_mgmt_uart_context.port = 0;
0156     return;
0157   }
0158   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0159   zynqmp_mgmt_uart_context.port += outprop[0];
0160 
0161   prop = fdt_getprop(fdt, node, "reg-shift", &proplen);
0162   if ( prop == NULL || proplen != 4 ) {
0163     zynqmp_mgmt_uart_context.port = 0;
0164     return;
0165   }
0166   outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
0167   mgmt_uart_reg_shift = outprop[0];
0168 
0169   ns16550_probe(&zynqmp_mgmt_uart_context.base);
0170 
0171   zynqmp_configure_management_console(&zynqmp_mgmt_uart_context.base);
0172 }
0173 
0174 RTEMS_SYSINIT_ITEM(
0175   zynqmp_management_console_init,
0176   RTEMS_SYSINIT_BSP_START,
0177   RTEMS_SYSINIT_ORDER_FIRST
0178 );
0179 
0180 void zynqmp_management_console_termios_init(void)
0181 {
0182   if ( zynqmp_mgmt_uart_context.port != 0 ) {
0183     rtems_termios_device_install(
0184       "/dev/ttyMGMT0",
0185       &ns16550_handler_interrupt,
0186       NULL,
0187       &zynqmp_mgmt_uart_context.base
0188     );
0189   }
0190 }