source: rtems/bsps/aarch64/xilinx-zynqmp/console/console.c @ b296708

Last change on this file since b296708 was b296708, checked in by Joel Sherrill <joel@…>, on 06/06/23 at 22:33:08

xilinx-zynqmp: Include <rtems/libio.h> for rtems_termios_initialize()

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSBSPsAArch64XilinxZynqMP
7 *
8 * @brief This source file contains this BSP's console configuration.
9 */
10
11/*
12 * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
13 * Written by Kinsey Moore <kinsey.moore@oarcorp.com>
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include <rtems/console.h>
38#include <rtems/bspIo.h>
39#include <rtems/endian.h>
40#include <rtems/sysinit.h>
41#include <rtems/libio.h>   /* for rtems_termios_initialize */
42
43#include <bsp/aarch64-mmu.h>
44#include <bsp/fdt.h>
45#include <bsp/irq.h>
46
47#include <dev/serial/zynq-uart.h>
48
49#include <bspopts.h>
50#include <libfdt.h>
51
52#include <libchip/ns16550.h>
53
54uint32_t mgmt_uart_reg_shift = 0;
55static uint8_t get_register(uintptr_t addr, uint8_t i)
56{
57  volatile uint8_t *reg = (uint8_t *) addr;
58
59  i <<= mgmt_uart_reg_shift;
60  return reg [i];
61}
62
63static void set_register(uintptr_t addr, uint8_t i, uint8_t val)
64{
65  volatile uint8_t *reg = (uint8_t *) addr;
66
67  i <<= mgmt_uart_reg_shift;
68  reg [i] = val;
69}
70
71static ns16550_context zynqmp_mgmt_uart_context = {
72  .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Management UART 0"),
73  .get_reg = get_register,
74  .set_reg = set_register,
75  .port = 0,
76  .irq = 0,
77  .clock = 0,
78  .initial_baud = 0,
79};
80
81__attribute__ ((weak)) void zynqmp_configure_management_console(rtems_termios_device_context *base)
82{
83  /* This SLIP-encoded watchdog command sets timeouts to 0xFFFFFFFF seconds. */
84  const char mgmt_watchdog_cmd[] =
85    "\xc0\xda\x00\x00\xff\xff\xff\xff\xff\x00\xff\xff\xff\xffM#\xc0";
86
87  /* Send the system watchdog configuration command */
88  for (int i = 0; i < sizeof(mgmt_watchdog_cmd); i++) {
89    ns16550_polled_putchar(base, mgmt_watchdog_cmd[i]);
90  }
91}
92
93static void zynqmp_management_console_init(void)
94{
95  /* Find the management console in the device tree */
96  const void *fdt = bsp_fdt_get();
97  const uint32_t *prop;
98  uint32_t outprop[4];
99  int proplen;
100  int node;
101
102  const char *alias = fdt_get_alias(fdt, "mgmtport");
103  if (alias == NULL) {
104    return;
105  }
106  node = fdt_path_offset(fdt, alias);
107
108  prop = fdt_getprop(fdt, node, "clock-frequency", &proplen);
109  if ( prop == NULL || proplen != 4 ) {
110    zynqmp_mgmt_uart_context.port = 0;
111    return;
112  }
113  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
114  zynqmp_mgmt_uart_context.clock = outprop[0];
115
116  prop = fdt_getprop(fdt, node, "current-speed", &proplen);
117  if ( prop == NULL || proplen != 4 ) {
118    zynqmp_mgmt_uart_context.port = 0;
119    return;
120  }
121  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
122  zynqmp_mgmt_uart_context.initial_baud = outprop[0];
123
124  prop = fdt_getprop(fdt, node, "interrupts", &proplen);
125  if ( prop == NULL || proplen != 12 ) {
126    zynqmp_mgmt_uart_context.port = 0;
127    return;
128  }
129  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
130  outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
131  outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
132  /* proplen is in bytes, interrupt mapping expects a length in 32-bit cells */
133  zynqmp_mgmt_uart_context.irq = bsp_fdt_map_intr(outprop, proplen / 4);
134  if ( zynqmp_mgmt_uart_context.irq == 0 ) {
135    zynqmp_mgmt_uart_context.port = 0;
136    return;
137  }
138
139  prop = fdt_getprop(fdt, node, "reg", &proplen);
140  if ( prop == NULL || proplen != 16 ) {
141    zynqmp_mgmt_uart_context.port = 0;
142    return;
143  }
144  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
145  outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
146  outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
147  outprop[3] = rtems_uint32_from_big_endian((const uint8_t *) &prop[3]);
148  zynqmp_mgmt_uart_context.port = ( ( (uint64_t) outprop[0] ) << 32 ) | outprop[1];
149  uintptr_t uart_base = zynqmp_mgmt_uart_context.port;
150  size_t uart_size = ( ( (uint64_t) outprop[2] ) << 32 ) | outprop[3];
151
152  rtems_status_code sc = aarch64_mmu_map( uart_base,
153                                          uart_size,
154                                          AARCH64_MMU_DEVICE);
155  if ( sc != RTEMS_SUCCESSFUL ) {
156    zynqmp_mgmt_uart_context.port = 0;
157    return;
158  }
159
160  prop = fdt_getprop(fdt, node, "reg-offset", &proplen);
161  if ( prop == NULL || proplen != 4 ) {
162    zynqmp_mgmt_uart_context.port = 0;
163    return;
164  }
165  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
166  zynqmp_mgmt_uart_context.port += outprop[0];
167
168  prop = fdt_getprop(fdt, node, "reg-shift", &proplen);
169  if ( prop == NULL || proplen != 4 ) {
170    zynqmp_mgmt_uart_context.port = 0;
171    return;
172  }
173  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
174  mgmt_uart_reg_shift = outprop[0];
175
176  ns16550_probe(&zynqmp_mgmt_uart_context.base);
177
178  zynqmp_configure_management_console(&zynqmp_mgmt_uart_context.base);
179}
180
181RTEMS_SYSINIT_ITEM(
182  zynqmp_management_console_init,
183  RTEMS_SYSINIT_BSP_START,
184  RTEMS_SYSINIT_ORDER_FIRST
185);
186
187static zynq_uart_context zynqmp_uart_instances[2] = {
188  {
189    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "Zynq UART 0" ),
190    .regs = (volatile struct zynq_uart *) 0xff010000,
191    .irq = ZYNQMP_IRQ_UART_0
192  }, {
193    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "Zynq UART 1" ),
194    .regs = (volatile struct zynq_uart *) 0xff000000,
195    .irq = ZYNQMP_IRQ_UART_1
196  }
197};
198
199rtems_status_code console_initialize(
200  rtems_device_major_number major,
201  rtems_device_minor_number minor,
202  void *arg
203)
204{
205  size_t i;
206
207  rtems_termios_initialize();
208
209  for (i = 0; i < RTEMS_ARRAY_SIZE(zynqmp_uart_instances); ++i) {
210    char uart[] = "/dev/ttySX";
211
212    uart[sizeof(uart) - 2] = (char) ('0' + i);
213    rtems_termios_device_install(
214      &uart[0],
215      &zynq_uart_handler,
216      NULL,
217      &zynqmp_uart_instances[i].base
218    );
219
220    if (i == BSP_CONSOLE_MINOR) {
221      link(&uart[0], CONSOLE_DEVICE_NAME);
222    }
223  }
224
225  if ( zynqmp_mgmt_uart_context.port != 0 ) {
226    rtems_termios_device_install(
227      "/dev/ttyMGMT0",
228      &ns16550_handler_polled,
229      NULL,
230      &zynqmp_mgmt_uart_context.base
231    );
232  }
233
234  return RTEMS_SUCCESSFUL;
235}
236
237void zynqmp_debug_console_flush(void)
238{
239  zynq_uart_reset_tx_flush(&zynqmp_uart_instances[BSP_CONSOLE_MINOR]);
240}
241
242static void zynqmp_debug_console_out(char c)
243{
244  rtems_termios_device_context *base =
245    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
246
247  zynq_uart_write_polled(base, c);
248}
249
250static void zynqmp_debug_console_init(void)
251{
252  rtems_termios_device_context *base =
253    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
254
255  zynq_uart_initialize(base);
256  BSP_output_char = zynqmp_debug_console_out;
257}
258
259static void zynqmp_debug_console_early_init(char c)
260{
261  rtems_termios_device_context *base =
262    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
263
264  zynq_uart_initialize(base);
265  BSP_output_char = zynqmp_debug_console_out;
266  zynqmp_debug_console_out(c);
267}
268
269static int zynqmp_debug_console_in(void)
270{
271  rtems_termios_device_context *base =
272    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
273
274  return zynq_uart_read_polled(base);
275}
276
277BSP_output_char_function_type BSP_output_char = zynqmp_debug_console_early_init;
278
279BSP_polling_getchar_function_type BSP_poll_char = zynqmp_debug_console_in;
280
281RTEMS_SYSINIT_ITEM(
282  zynqmp_debug_console_init,
283  RTEMS_SYSINIT_BSP_START,
284  RTEMS_SYSINIT_ORDER_LAST_BUT_5
285);
Note: See TracBrowser for help on using the repository browser.