Skip to content

Commit

Permalink
Add support for SiFive Premier P550
Browse files Browse the repository at this point in the history
Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au>
  • Loading branch information
Ivan-Velickovic committed Feb 11, 2025
1 parent 1bc0e79 commit 1d2db31
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
34 changes: 34 additions & 0 deletions libplatsupport/plat_include/p550/platsupport/plat/serial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2023, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once
#include <autoconf.h>

/* The ESWIN EIC7700X SoC contains five 8250 compatible UARTs. */

enum chardev_id {
UART0,
UART1,
UART2,
UART3,
UART4,
PS_SERIAL_DEFAULT = UART0
};

#define UART0_PADDR 0x50900000
#define UART1_PADDR 0x50910000
#define UART2_PADDR 0x50920000
#define UART3_PADDR 0x50930000
#define UART4_PADDR 0x50940000

#define UART0_IRQ 100
#define UART1_IRQ 101
#define UART2_IRQ 102
#define UART3_IRQ 103
#define UART4_IRQ 104

#define DEFAULT_SERIAL_PADDR UART0_PADDR
#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ
47 changes: 47 additions & 0 deletions libplatsupport/src/plat/p550/chardev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2023, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include "../../chardev.h"
#include "../../common.h"
#include <utils/util.h>

static const int uart0_irqs[] = {UART0_IRQ, -1};
static const int uart1_irqs[] = {UART1_IRQ, -1};
static const int uart2_irqs[] = {UART2_IRQ, -1};
static const int uart3_irqs[] = {UART3_IRQ, -1};
static const int uart4_irqs[] = {UART4_IRQ, -1};

/*
* Despite each UART being 0x10000 in size (according to the device tree) we
* only need to map in the first page for the driver to functon.
*/
#define UART_DEFN(devid) { \
.id = UART##devid, \
.paddr = UART##devid##_PADDR, \
.size = BIT(12), \
.irqs = uart##devid##_irqs, \
.init_fn = &uart_init \
}

const struct dev_defn dev_defn[] = {
UART_DEFN(0),
UART_DEFN(1),
UART_DEFN(2),
UART_DEFN(3),
UART_DEFN(4),
};

struct ps_chardevice *
ps_cdev_init(enum chardev_id id, const ps_io_ops_t *o, struct ps_chardevice *d)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(dev_defn); i++) {
if (dev_defn[i].id == id) {
return (dev_defn[i].init_fn(dev_defn + i, o, d)) ? NULL : d;
}
}
return NULL;
}
75 changes: 75 additions & 0 deletions libplatsupport/src/plat/p550/serial.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2023, UNSW
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <stdlib.h>
#include <string.h>
#include <platsupport/serial.h>
#include <platsupport/plat/serial.h>
#include "../../chardev.h"

#define UART_THR 0x00 /* UART Transmit Holding Register */
#define UART_IER 0x04 /* UART Interrupt Enable Register */
#define UART_IER_ERDAI BIT(0) /* Enable Received Data Available Interrupt */
#define UART_LSR 0x14 /* UART Line Status Register */
#define UART_LSR_THRE 0x20 /* Transmit Holding Register Empty */

#define REG_PTR(base, off) ((volatile uint32_t *)((base) + (off)))

int uart_getchar(ps_chardevice_t *d)
{
while ((*REG_PTR(d->vaddr, UART_LSR) & BIT(0)));
return *REG_PTR(d->vaddr, UART_THR);
}

int uart_putchar(ps_chardevice_t *d, int c)
{
if (c == '\n' && (d->flags & SERIAL_AUTO_CR)) {
uart_putchar(d, '\r');
}

while ((*REG_PTR(d->vaddr, UART_LSR) & UART_LSR_THRE) == 0);

/* Add character to the buffer. */
*REG_PTR(d->vaddr, UART_THR) = c;

return c;
}

static void uart_handle_irq(ps_chardevice_t *dev)
{
/*
* This is currently only called when received data is available on the device.
* The interrupt will be acked to the device on the next read to the device.
* There's nothing else we need to do here.
*/
}

int uart_init(const struct dev_defn *defn,
const ps_io_ops_t *ops,
ps_chardevice_t *dev)
{
memset(dev, 0, sizeof(*dev));
void *vaddr = chardev_map(defn, ops);
if (vaddr == NULL) {
ZF_LOGE("Unable to map chardev");
return -1;
}

/* Set up all the device properties. */
dev->id = defn->id;
dev->vaddr = vaddr;
dev->read = &uart_read;
dev->write = &uart_write;
dev->handle_irq = &uart_handle_irq;
dev->irqs = defn->irqs;
dev->ioops = *ops;
dev->flags = SERIAL_AUTO_CR;

*REG_PTR(dev->vaddr, 0x8) = 1;
*REG_PTR(dev->vaddr, UART_IER) = UART_IER_ERDAI;

return 0;
}

0 comments on commit 1d2db31

Please sign in to comment.