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

Last change on this file since efe8c370 was efe8c370, checked in by Kinsey Moore <kinsey.moore@…>, on 11/17/22 at 18:18:18

bsps/zynqmp: Use direct fdt_* calls

This changes the ZynqMP device tree parsing over to direct libfdt calls
to avoid inclusion of malloc() in the base BSP which currently causes
sp01 to fail due to unexpected use of TLS space.

  • Property mode set to 100644
File size: 8.3 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
42#include <bsp/aarch64-mmu.h>
43#include <bsp/fdt.h>
44#include <bsp/irq.h>
45
46#include <dev/serial/zynq-uart.h>
47
48#include <bspopts.h>
49#include <libfdt.h>
50
51#include <libchip/ns16550.h>
52
53uint32_t mgmt_uart_reg_shift = 0;
54static uint8_t get_register(uintptr_t addr, uint8_t i)
55{
56  volatile uint8_t *reg = (uint8_t *) addr;
57
58  i <<= mgmt_uart_reg_shift;
59  return reg [i];
60}
61
62static void set_register(uintptr_t addr, uint8_t i, uint8_t val)
63{
64  volatile uint8_t *reg = (uint8_t *) addr;
65
66  i <<= mgmt_uart_reg_shift;
67  reg [i] = val;
68}
69
70static ns16550_context zynqmp_mgmt_uart_context = {
71  .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("Management UART 0"),
72  .get_reg = get_register,
73  .set_reg = set_register,
74  .port = 0,
75  .irq = 0,
76  .clock = 0,
77  .initial_baud = 0,
78};
79
80__attribute__ ((weak)) void zynqmp_configure_management_console(rtems_termios_device_context *base)
81{
82  /* This SLIP-encoded watchdog command sets timeouts to 0xFFFFFFFF seconds. */
83  const char mgmt_watchdog_cmd[] =
84    "\xc0\xda\x00\x00\xff\xff\xff\xff\xff\x00\xff\xff\xff\xffM#\xc0";
85
86  /* Send the system watchdog configuration command */
87  for (int i = 0; i < sizeof(mgmt_watchdog_cmd); i++) {
88    ns16550_polled_putchar(base, mgmt_watchdog_cmd[i]);
89  }
90}
91
92static void zynqmp_management_console_init(void)
93{
94  /* Find the management console in the device tree */
95  const void *fdt = bsp_fdt_get();
96  const uint32_t *prop;
97  uint32_t outprop[4];
98  int proplen;
99  int node;
100
101  const char *alias = fdt_get_alias(fdt, "mgmtport");
102  if (alias == NULL) {
103    return;
104  }
105  node = fdt_path_offset(fdt, alias);
106
107  prop = fdt_getprop(fdt, node, "clock-frequency", &proplen);
108  if ( prop == NULL || proplen != 4 ) {
109    zynqmp_mgmt_uart_context.port = 0;
110    return;
111  }
112  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
113  zynqmp_mgmt_uart_context.clock = outprop[0];
114
115  prop = fdt_getprop(fdt, node, "current-speed", &proplen);
116  if ( prop == NULL || proplen != 4 ) {
117    zynqmp_mgmt_uart_context.port = 0;
118    return;
119  }
120  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
121  zynqmp_mgmt_uart_context.initial_baud = outprop[0];
122
123  prop = fdt_getprop(fdt, node, "interrupts", &proplen);
124  if ( prop == NULL || proplen != 12 ) {
125    zynqmp_mgmt_uart_context.port = 0;
126    return;
127  }
128  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
129  outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
130  outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
131  /* proplen is in bytes, interrupt mapping expects a length in 32-bit cells */
132  zynqmp_mgmt_uart_context.irq = bsp_fdt_map_intr(outprop, proplen / 4);
133  if ( zynqmp_mgmt_uart_context.irq == 0 ) {
134    zynqmp_mgmt_uart_context.port = 0;
135    return;
136  }
137
138  prop = fdt_getprop(fdt, node, "reg", &proplen);
139  if ( prop == NULL || proplen != 16 ) {
140    zynqmp_mgmt_uart_context.port = 0;
141    return;
142  }
143  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
144  outprop[1] = rtems_uint32_from_big_endian((const uint8_t *) &prop[1]);
145  outprop[2] = rtems_uint32_from_big_endian((const uint8_t *) &prop[2]);
146  outprop[3] = rtems_uint32_from_big_endian((const uint8_t *) &prop[3]);
147  zynqmp_mgmt_uart_context.port = ( ( (uint64_t) outprop[0] ) << 32 ) | outprop[1];
148  uintptr_t uart_base = zynqmp_mgmt_uart_context.port;
149  size_t uart_size = ( ( (uint64_t) outprop[2] ) << 32 ) | outprop[3];
150
151  rtems_status_code sc = aarch64_mmu_map( uart_base,
152                                          uart_size,
153                                          AARCH64_MMU_DEVICE);
154  if ( sc != RTEMS_SUCCESSFUL ) {
155    zynqmp_mgmt_uart_context.port = 0;
156    return;
157  }
158
159  prop = fdt_getprop(fdt, node, "reg-offset", &proplen);
160  if ( prop == NULL || proplen != 4 ) {
161    zynqmp_mgmt_uart_context.port = 0;
162    return;
163  }
164  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
165  zynqmp_mgmt_uart_context.port += outprop[0];
166
167  prop = fdt_getprop(fdt, node, "reg-shift", &proplen);
168  if ( prop == NULL || proplen != 4 ) {
169    zynqmp_mgmt_uart_context.port = 0;
170    return;
171  }
172  outprop[0] = rtems_uint32_from_big_endian((const uint8_t *) &prop[0]);
173  mgmt_uart_reg_shift = outprop[0];
174
175  ns16550_probe(&zynqmp_mgmt_uart_context.base);
176
177  zynqmp_configure_management_console(&zynqmp_mgmt_uart_context.base);
178}
179
180RTEMS_SYSINIT_ITEM(
181  zynqmp_management_console_init,
182  RTEMS_SYSINIT_BSP_START,
183  RTEMS_SYSINIT_ORDER_FIRST
184);
185
186static zynq_uart_context zynqmp_uart_instances[2] = {
187  {
188    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "Zynq UART 0" ),
189    .regs = (volatile struct zynq_uart *) 0xff010000,
190    .irq = ZYNQMP_IRQ_UART_0
191  }, {
192    .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "Zynq UART 1" ),
193    .regs = (volatile struct zynq_uart *) 0xff000000,
194    .irq = ZYNQMP_IRQ_UART_1
195  }
196};
197
198rtems_status_code console_initialize(
199  rtems_device_major_number major,
200  rtems_device_minor_number minor,
201  void *arg
202)
203{
204  size_t i;
205
206  rtems_termios_initialize();
207
208  for (i = 0; i < RTEMS_ARRAY_SIZE(zynqmp_uart_instances); ++i) {
209    char uart[] = "/dev/ttySX";
210
211    uart[sizeof(uart) - 2] = (char) ('0' + i);
212    rtems_termios_device_install(
213      &uart[0],
214      &zynq_uart_handler,
215      NULL,
216      &zynqmp_uart_instances[i].base
217    );
218
219    if (i == BSP_CONSOLE_MINOR) {
220      link(&uart[0], CONSOLE_DEVICE_NAME);
221    }
222  }
223
224  if ( zynqmp_mgmt_uart_context.port != 0 ) {
225    rtems_termios_device_install(
226      "/dev/ttyMGMT0",
227      &ns16550_handler_polled,
228      NULL,
229      &zynqmp_mgmt_uart_context.base
230    );
231  }
232
233  return RTEMS_SUCCESSFUL;
234}
235
236void zynqmp_debug_console_flush(void)
237{
238  zynq_uart_reset_tx_flush(&zynqmp_uart_instances[BSP_CONSOLE_MINOR]);
239}
240
241static void zynqmp_debug_console_out(char c)
242{
243  rtems_termios_device_context *base =
244    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
245
246  zynq_uart_write_polled(base, c);
247}
248
249static void zynqmp_debug_console_init(void)
250{
251  rtems_termios_device_context *base =
252    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
253
254  zynq_uart_initialize(base);
255  BSP_output_char = zynqmp_debug_console_out;
256}
257
258static void zynqmp_debug_console_early_init(char c)
259{
260  rtems_termios_device_context *base =
261    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
262
263  zynq_uart_initialize(base);
264  BSP_output_char = zynqmp_debug_console_out;
265  zynqmp_debug_console_out(c);
266}
267
268static int zynqmp_debug_console_in(void)
269{
270  rtems_termios_device_context *base =
271    &zynqmp_uart_instances[BSP_CONSOLE_MINOR].base;
272
273  return zynq_uart_read_polled(base);
274}
275
276BSP_output_char_function_type BSP_output_char = zynqmp_debug_console_early_init;
277
278BSP_polling_getchar_function_type BSP_poll_char = zynqmp_debug_console_in;
279
280RTEMS_SYSINIT_ITEM(
281  zynqmp_debug_console_init,
282  RTEMS_SYSINIT_BSP_START,
283  RTEMS_SYSINIT_ORDER_LAST_BUT_5
284);
Note: See TracBrowser for help on using the repository browser.