blob: b3f1854186167e9857a3249114e8f38609616812 [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
* Copyright (C) 2021, Hensoldt Cyber GmbH
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
#include <platsupport/gpio.h>
#include <platsupport/plat/gpio.h>
#include <platsupport/serial.h>
#include <platsupport/plat/serial.h>
#include "serial.h"
#include "mini_serial.h"
#include "pl011_serial.h"
typedef struct {
int (*uart_init)(const struct dev_defn *defn,
const ps_io_ops_t *ops,
ps_chardevice_t *dev);
int (*uart_getchar)(ps_chardevice_t *d);
int (*uart_putchar)(ps_chardevice_t *d, int c);
} uart_funcs_t;
uart_funcs_t uart_funcs;
int uart_getchar(ps_chardevice_t *d)
{
uart_funcs.uart_getchar(d);
}
int uart_putchar(ps_chardevice_t *d, int c)
{
uart_funcs.uart_putchar(d, c);
}
/*
* Configure UART GPIO pins.
*
* On the RPi4, there are 6 UARTs: One miniUART (UART1) and 5 PL011 UARTs (UART0
* + UART2-5). There is also a possibility to configure these pins via the
* config.txt file statically. Since these pins might be used for other
* functionality than UART, it might be best to configure these pins here
* dynamically.
*
* BCM2711 TRM, Section 11.3. Primary UART Inputs and Outputs.
*/
int uart_gpio_configure(enum chardev_id id, const ps_io_ops_t *o)
{
gpio_sys_t gpio_sys;
gpio_t gpio;
// We only configure the TX/RX pins for each UART peripheral and ignore flow
// control (CTS/RTS pins) for now.
int tx_pin = -1;
int rx_pin = -1;
int alt_function = -1;
/*
* GPIO pin configuration
*
* GPIO pins 14/15 are mapped accordingly: https://pinout.xyz/pinout/pin8_gpio14#
*
* This means:
* UART0: these pins are RX/TX lines; pins must be configured for ALT0
* UART1: these pins are RX/TX lines; pins must be configured for ALT5
* UART5: these pins are CTS/RTS lines; we ignore cts/rts for now
*/
switch (id) {
case 0:
// UART 0 uses GPIO pins 14-15
tx_pin = 14;
rx_pin = 15;
alt_function = BCM2711_GPIO_FSEL_ALT0;
case 1:
// UART 1 uses GPIO pins 14-15
tx_pin = 14;
rx_pin = 15;
alt_function = BCM2711_GPIO_FSEL_ALT5;
case 2:
// UART 2 uses GPIO pins 0-3
tx_pin = 0;
rx_pin = 1;
alt_function = BCM2711_GPIO_FSEL_ALT4;
break;
case 3:
// UART 3 uses GPIO pins 4-7
tx_pin = 4;
rx_pin = 5;
alt_function = BCM2711_GPIO_FSEL_ALT4;
break;
case 4:
// UART 4 uses GPIO pins 8-11
tx_pin = 8;
rx_pin = 9;
alt_function = BCM2711_GPIO_FSEL_ALT4;
break;
case 5:
// UART 5 uses GPIO pins 12-13
tx_pin = 12;
rx_pin = 13;
alt_function = BCM2711_GPIO_FSEL_ALT4;
break;
default:
ZF_LOGD("No pin configuration required!");
return 0;
break;
}
if (tx_pin < 0 || rx_pin < 0) {
ZF_LOGE("TX/RX pins wrongly configured!");
return -1;
}
if (alt_function < 0) {
ZF_LOGE("ALT function wrongly configured!");
return -1;
}
// GPIO initialization
int ret = gpio_sys_init((ps_io_ops_t *)o, &gpio_sys);
if (ret) {
ZF_LOGE("gpio_sys_init() failed: ret = %i", ret);
return -1;
}
// configure tx pin
gpio_sys.init(&gpio_sys, tx_pin, 0, &gpio);
bcm2711_gpio_fsel(&gpio, alt_function);
// configure rx pin
gpio_sys.init(&gpio_sys, rx_pin, 0, &gpio);
bcm2711_gpio_fsel(&gpio, alt_function);
return 0;
}
int uart_init(const struct dev_defn *defn,
const ps_io_ops_t *ops,
ps_chardevice_t *dev)
{
switch (defn->id) {
case 1:
uart_funcs.uart_init = &mini_uart_init;
uart_funcs.uart_getchar = &mini_uart_getchar;
uart_funcs.uart_putchar = &mini_uart_putchar;
break;
case 0:
case 2:
case 3:
case 4:
case 5:
uart_funcs.uart_init = &pl011_uart_init;
uart_funcs.uart_getchar = &pl011_uart_getchar;
uart_funcs.uart_putchar = &pl011_uart_putchar;
break;
default:
ZF_LOGE("UART with id %d does not exist!", defn->id);
return -1;
break;
}
uart_gpio_configure(defn->id, ops);
uart_funcs.uart_init(defn, ops, dev);
return 0;
}