Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libplatsupport/morello: Add basic drivers for fvp #175

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 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,19 @@
/*
* 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
};
11 changes: 11 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,11 @@
/*
* 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