Skip to content

Commit

Permalink
libplatsupport/morello: Add basic drivers for fvp
Browse files Browse the repository at this point in the history
This is mostly derived from the existing FVP platform; the
main changes are the UART and timer addresses and IRQ IDs.
Just two drivers are supported, PL011 for the console and
SP804 for user-level timers.

Signed-off-by: Hesham Almatary <hesham.almatary@cl.cam.ac.uk>
  • Loading branch information
heshamelmatary committed Jan 30, 2024
1 parent 5a0472c commit 56980b1
Show file tree
Hide file tree
Showing 9 changed files with 619 additions and 0 deletions.
20 changes: 20 additions & 0 deletions libplatsupport/plat_include/morello-fvp/platsupport/plat/clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

enum clk_id {
CLK_MASTER,
/* ----- */
NCLOCKS,
/* Custom clock */
CLK_CUSTOM,
};

enum clock_gate {
NCLKGATES
};

12 changes: 12 additions & 0 deletions libplatsupport/plat_include/morello-fvp/platsupport/plat/i2c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

enum i2c_id {
NI2C
};

22 changes: 22 additions & 0 deletions libplatsupport/plat_include/morello-fvp/platsupport/plat/serial.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
* Copyright (c) 2024, Capabilities Ltd <heshamalmatary@capabilitieslimited.co.uk>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#define UART0_PADDR 0x2a400000
#define UART0_IRQ 95

enum chardev_id {
PL001_UART0,
/* Aliases */
PS_SERIAL0 = PL001_UART0,
/* defaults */
PS_SERIAL_DEFAULT = PL001_UART0
};

#define DEFAULT_SERIAL_PADDR UART0_PADDR
#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ
79 changes: 79 additions & 0 deletions libplatsupport/plat_include/morello-fvp/platsupport/plat/sp804.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
* Copyright (c) 2024, Capabilities Ltd <heshamalmatary@capabilitieslimited.co.uk>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once

#include <platsupport/timer.h>
#include <platsupport/ltimer.h>
#include <platsupport/fdt.h>

/* Each SP804 has two timers, but we only use one timer on eace device page.
* This is because the two timers on the same page share the same interrupt,
* and using one timer on each page saves us from identifying the sources of
* interrupts.
* */
#define SP804_TIMER1_PATH "/timer@1c110000"
#define SP804_TIMER2_PATH "/timer@1c120000"

#define SP804_REG_CHOICE 0
#define SP804_IRQ_CHOICE 0

static UNUSED timer_properties_t sp804_timer_props = {
.upcounter = false,
.timeouts = true,
.absolute_timeouts = false,
.relative_timeouts = true,
.periodic_timeouts = true,
.bit_width = 32,
.irqs = 1
};

typedef volatile struct sp804_regs {
uint32_t load;
uint32_t value;
uint32_t control;
uint32_t intclr;
uint32_t ris;
uint32_t mis;
uint32_t bgload;
} sp804_regs_t;

typedef struct {
/* set in init */
ps_io_ops_t ops;
ltimer_callback_fn_t user_cb_fn;
void *user_cb_token;
ltimer_event_t user_cb_event; /* what are we being used for? */

/* set in fdt helper */
volatile sp804_regs_t *sp804_map;
pmem_region_t pmem;
irq_id_t irq_id;

/* set in setup */
uint32_t time_h;
} sp804_t;

typedef struct {
const char *fdt_path;
ltimer_callback_fn_t user_cb_fn;
void *user_cb_token;
ltimer_event_t user_cb_event;
} sp804_config_t;

int sp804_init(sp804_t *sp804, ps_io_ops_t ops, sp804_config_t config);
/* convert between dmt ticks and ns */
uint64_t sp804_ticks_to_ns(uint64_t ticks);
/* return true if an overflow irq is pending */
bool sp804_is_irq_pending(sp804_t *sp804);
int sp804_set_timeout_ticks(sp804_t *timer, uint32_t ticks, bool periodic, bool irqs);
/* set a timeout in nano seconds */
int sp804_set_timeout(sp804_t *timer, uint64_t ns, bool periodic, bool irqs);
int sp804_start(sp804_t *timer);
int sp804_stop(sp804_t *timer);
uint64_t sp804_get_time(sp804_t *timer);
uint64_t sp804_get_ticks(sp804_t *timer);
void sp804_destroy(sp804_t *sp804);
42 changes: 42 additions & 0 deletions libplatsupport/src/plat/morello-fvp/chardev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/

/**
* Contains the definition for all character devices on this platform.
* Currently this is just a simple patch.
*/

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

#include "../../chardev.h"

static const int uart0_irqs[] = {UART0_IRQ, -1};

#define UART_DEFN(devid) { \
.id = PL001_UART##devid, \
.paddr = UART##devid##_PADDR, \
.size = BIT(12), \
.irqs = uart##devid##_irqs, \
.init_fn = &uart_init \
}

static const struct dev_defn dev_defn[] = {
UART_DEFN(0)
};

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;
}
19 changes: 19 additions & 0 deletions libplatsupport/src/plat/morello-fvp/clock_mux.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <platsupport/mux.h>
#include <utils/attribute.h>
#include <platsupport/clock.h>

int clock_sys_init(ps_io_ops_t *io_ops, clock_sys_t *clk_sys)
{
return 0;
}

int mux_sys_init(ps_io_ops_t *io_ops, UNUSED void *dependencies, mux_sys_t *mux)
{
return 0;
}
152 changes: 152 additions & 0 deletions libplatsupport/src/plat/morello-fvp/ltimer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdio.h>
#include <assert.h>

#include <utils/util.h>
#include <utils/time.h>

#include <platsupport/ltimer.h>
#include <platsupport/plat/sp804.h>
#include <platsupport/io.h>

#include "../../ltimer.h"

/*
* We use two sp804 timers: one to keep track of an absolute time, the other for timeouts.
*/

typedef struct {
/* fvp sp804 have 2 timers per frame, we just use one per each */
sp804_t sp804_timeout;
sp804_t sp804_timestamp;
ps_io_ops_t ops;
} fvp_ltimer_t;

static int get_time(void *data, uint64_t *time)
{
fvp_ltimer_t *fvp_ltimer = data;
assert(data != NULL);
assert(time != NULL);

*time = sp804_get_time(&fvp_ltimer->sp804_timestamp);
return 0;
}

int set_timeout(void *data, uint64_t ns, timeout_type_t type)
{
if (type == TIMEOUT_ABSOLUTE) {
uint64_t time;
int error = get_time(data, &time);
if (error) {
return error;
}
if (time > ns) {
return ETIME;
}
ns -= time;
}

fvp_ltimer_t *fvp_ltimer = data;
return sp804_set_timeout(&fvp_ltimer->sp804_timeout, ns, type == TIMEOUT_PERIODIC, true);
}

static int reset(void *data)
{
fvp_ltimer_t *fvp_ltimer = data;
/* restart the rtc */
sp804_stop(&fvp_ltimer->sp804_timeout);
sp804_start(&fvp_ltimer->sp804_timeout);
return 0;
}

static void destroy(void *data)
{
assert(data != NULL);
fvp_ltimer_t *fvp_ltimer = data;
sp804_destroy(&fvp_ltimer->sp804_timeout);
sp804_destroy(&fvp_ltimer->sp804_timestamp);
ps_free(&fvp_ltimer->ops.malloc_ops, sizeof(fvp_ltimer_t), fvp_ltimer);
}

int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token)
{
int error;

if (ltimer == NULL) {
ZF_LOGE("ltimer cannot be NULL");
return EINVAL;
}

error = create_ltimer_simple(
ltimer, ops, sizeof(fvp_ltimer_t),
get_time, set_timeout, reset, destroy
);
if (error) {
ZF_LOGE("Failed to create ltimer simple");
return error;
}

fvp_ltimer_t *fvp_ltimer = ltimer->data;
fvp_ltimer->ops = ops;

/* set up an SP804 for timeouts */
sp804_config_t sp804_config = {
.fdt_path = SP804_TIMER1_PATH,
.user_cb_fn = callback,
.user_cb_token = callback_token,
.user_cb_event = LTIMER_TIMEOUT_EVENT
};

error = sp804_init(&fvp_ltimer->sp804_timeout, ops, sp804_config);
if (error) {
ZF_LOGE("Failed to init timeout timer");
destroy(&fvp_ltimer);
return error;
}

error = sp804_start(&fvp_ltimer->sp804_timeout);
if (error) {
ZF_LOGE("Failed to start timeout timer");
destroy(&fvp_ltimer);
return error;
}

/* another for timestamps */
sp804_config.fdt_path = SP804_TIMER2_PATH;
sp804_config.user_cb_event = LTIMER_OVERFLOW_EVENT;

error = sp804_init(&fvp_ltimer->sp804_timestamp, ops, sp804_config);
if (error) {
ZF_LOGE("Failed to init timestamp timer");
destroy(&fvp_ltimer);
return error;
}

error = sp804_start(&fvp_ltimer->sp804_timestamp);
if (error) {
ZF_LOGE("Failed to start timestamp timer");
destroy(&fvp_ltimer);
return error;
}

error = sp804_set_timeout_ticks(&fvp_ltimer->sp804_timestamp, UINT32_MAX, true, true);
if (error) {
ZF_LOGE("Failed to set timeout ticks for timer");
destroy(&fvp_ltimer);
return error;
}

return 0;
}

/* This function is intended to be deleted,
* this is just left here for now so that stuff can compile */
int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops)
{
ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid");
return EINVAL;
}
Loading

0 comments on commit 56980b1

Please sign in to comment.