Skip to content

Commit d05358a

Browse files
libplatsupport/morello: Add basic drivers for fvp
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>
1 parent 5a0472c commit d05358a

9 files changed

Lines changed: 617 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
enum clk_id {
10+
CLK_MASTER,
11+
/* ----- */
12+
NCLOCKS,
13+
/* Custom clock */
14+
CLK_CUSTOM,
15+
};
16+
17+
enum clock_gate {
18+
NCLKGATES
19+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
enum i2c_id {
10+
NI2C
11+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
* Copyright (c) 2024, Capabilities Ltd <heshamalmatary@capabilitieslimited.co.uk>
4+
*
5+
* SPDX-License-Identifier: BSD-2-Clause
6+
*/
7+
8+
#pragma once
9+
10+
#define UART0_PADDR 0x2a400000
11+
#define UART0_IRQ 95
12+
13+
enum chardev_id {
14+
PL001_UART0,
15+
/* Aliases */
16+
PS_SERIAL0 = PL001_UART0,
17+
/* defaults */
18+
PS_SERIAL_DEFAULT = PL001_UART0
19+
};
20+
21+
#define DEFAULT_SERIAL_PADDR UART0_PADDR
22+
#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
* Copyright (c) 2024, Capabilities Ltd <heshamalmatary@capabilitieslimited.co.uk>
4+
*
5+
* SPDX-License-Identifier: BSD-2-Clause
6+
*/
7+
#pragma once
8+
9+
#include <platsupport/timer.h>
10+
#include <platsupport/ltimer.h>
11+
#include <platsupport/fdt.h>
12+
13+
/* Each SP804 has two timers, but we only use one timer on eace device page.
14+
* This is because the two timers on the same page share the same interrupt,
15+
* and using one timer on each page saves us from identifying the sources of
16+
* interrupts.
17+
* */
18+
#define SP804_TIMER1_PATH "/timer@1c110000"
19+
#define SP804_TIMER2_PATH "/timer@1c120000"
20+
21+
#define SP804_REG_CHOICE 0
22+
#define SP804_IRQ_CHOICE 0
23+
24+
static UNUSED timer_properties_t sp804_timer_props = {
25+
.upcounter = false,
26+
.timeouts = true,
27+
.absolute_timeouts = false,
28+
.relative_timeouts = true,
29+
.periodic_timeouts = true,
30+
.bit_width = 32,
31+
.irqs = 1
32+
};
33+
34+
typedef volatile struct sp804_regs {
35+
uint32_t load;
36+
uint32_t value;
37+
uint32_t control;
38+
uint32_t intclr;
39+
uint32_t ris;
40+
uint32_t mis;
41+
uint32_t bgload;
42+
} sp804_regs_t;
43+
44+
typedef struct {
45+
/* set in init */
46+
ps_io_ops_t ops;
47+
ltimer_callback_fn_t user_cb_fn;
48+
void *user_cb_token;
49+
ltimer_event_t user_cb_event; /* what are we being used for? */
50+
51+
/* set in fdt helper */
52+
volatile sp804_regs_t *sp804_map;
53+
pmem_region_t pmem;
54+
irq_id_t irq_id;
55+
56+
/* set in setup */
57+
uint32_t time_h;
58+
} sp804_t;
59+
60+
typedef struct {
61+
const char *fdt_path;
62+
ltimer_callback_fn_t user_cb_fn;
63+
void *user_cb_token;
64+
ltimer_event_t user_cb_event;
65+
} sp804_config_t;
66+
67+
int sp804_init(sp804_t *sp804, ps_io_ops_t ops, sp804_config_t config);
68+
/* convert between dmt ticks and ns */
69+
uint64_t sp804_ticks_to_ns(uint64_t ticks);
70+
/* return true if an overflow irq is pending */
71+
bool sp804_is_irq_pending(sp804_t *sp804);
72+
int sp804_set_timeout_ticks(sp804_t *timer, uint32_t ticks, bool periodic, bool irqs);
73+
/* set a timeout in nano seconds */
74+
int sp804_set_timeout(sp804_t *timer, uint64_t ns, bool periodic, bool irqs);
75+
int sp804_start(sp804_t *timer);
76+
int sp804_stop(sp804_t *timer);
77+
uint64_t sp804_get_time(sp804_t *timer);
78+
uint64_t sp804_get_ticks(sp804_t *timer);
79+
void sp804_destroy(sp804_t *sp804);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
/**
8+
* Contains the definition for all character devices on this platform.
9+
* Currently this is just a simple patch.
10+
*/
11+
12+
#include "../../chardev.h"
13+
#include "../../common.h"
14+
#include <utils/util.h>
15+
16+
#include "../../chardev.h"
17+
18+
static const int uart0_irqs[] = {UART0_IRQ, -1};
19+
20+
#define UART_DEFN(devid) { \
21+
.id = PL001_UART##devid, \
22+
.paddr = UART##devid##_PADDR, \
23+
.size = BIT(12), \
24+
.irqs = uart##devid##_irqs, \
25+
.init_fn = &uart_init \
26+
}
27+
28+
static const struct dev_defn dev_defn[] = {
29+
UART_DEFN(0)
30+
};
31+
32+
struct ps_chardevice *
33+
ps_cdev_init(enum chardev_id id, const ps_io_ops_t *o, struct ps_chardevice *d)
34+
{
35+
unsigned int i;
36+
for (i = 0; i < ARRAY_SIZE(dev_defn); i++) {
37+
if (dev_defn[i].id == id) {
38+
return (dev_defn[i].init_fn(dev_defn + i, o, d)) ? NULL : d;
39+
}
40+
}
41+
return NULL;
42+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <platsupport/mux.h>
8+
#include <utils/attribute.h>
9+
#include <platsupport/clock.h>
10+
11+
int clock_sys_init(ps_io_ops_t *io_ops, clock_sys_t *clk_sys)
12+
{
13+
return 0;
14+
}
15+
16+
int mux_sys_init(ps_io_ops_t *io_ops, UNUSED void *dependencies, mux_sys_t *mux)
17+
{
18+
return 0;
19+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
#include <stdio.h>
7+
#include <assert.h>
8+
9+
#include <utils/util.h>
10+
#include <utils/time.h>
11+
12+
#include <platsupport/ltimer.h>
13+
#include <platsupport/plat/sp804.h>
14+
#include <platsupport/io.h>
15+
16+
#include "../../ltimer.h"
17+
18+
/*
19+
* We use two sp804 timers: one to keep track of an absolute time, the other for timeouts.
20+
*/
21+
22+
typedef struct {
23+
/* fvp sp804 have 2 timers per frame, we just use one per each */
24+
sp804_t sp804_timeout;
25+
sp804_t sp804_timestamp;
26+
ps_io_ops_t ops;
27+
} fvp_ltimer_t;
28+
29+
static int get_time(void *data, uint64_t *time)
30+
{
31+
fvp_ltimer_t *fvp_ltimer = data;
32+
assert(data != NULL);
33+
assert(time != NULL);
34+
35+
*time = sp804_get_time(&fvp_ltimer->sp804_timestamp);
36+
return 0;
37+
}
38+
39+
int set_timeout(void *data, uint64_t ns, timeout_type_t type)
40+
{
41+
if (type == TIMEOUT_ABSOLUTE) {
42+
uint64_t time;
43+
int error = get_time(data, &time);
44+
if (error) {
45+
return error;
46+
}
47+
if (time > ns) {
48+
return ETIME;
49+
}
50+
ns -= time;
51+
}
52+
53+
fvp_ltimer_t *fvp_ltimer = data;
54+
return sp804_set_timeout(&fvp_ltimer->sp804_timeout, ns, type == TIMEOUT_PERIODIC, true);
55+
}
56+
57+
static int reset(void *data)
58+
{
59+
fvp_ltimer_t *fvp_ltimer = data;
60+
/* restart the rtc */
61+
sp804_stop(&fvp_ltimer->sp804_timeout);
62+
sp804_start(&fvp_ltimer->sp804_timeout);
63+
return 0;
64+
}
65+
66+
static void destroy(void *data)
67+
{
68+
assert(data != NULL);
69+
fvp_ltimer_t *fvp_ltimer = data;
70+
sp804_destroy(&fvp_ltimer->sp804_timeout);
71+
sp804_destroy(&fvp_ltimer->sp804_timestamp);
72+
ps_free(&fvp_ltimer->ops.malloc_ops, sizeof(fvp_ltimer_t), fvp_ltimer);
73+
}
74+
75+
int ltimer_default_init(ltimer_t *ltimer, ps_io_ops_t ops, ltimer_callback_fn_t callback, void *callback_token)
76+
{
77+
int error;
78+
79+
if (ltimer == NULL) {
80+
ZF_LOGE("ltimer cannot be NULL");
81+
return EINVAL;
82+
}
83+
84+
error = create_ltimer_simple(
85+
ltimer, ops, sizeof(fvp_ltimer_t),
86+
get_time, set_timeout, reset, destroy
87+
);
88+
if (error) {
89+
ZF_LOGE("Failed to create ltimer simple");
90+
return error;
91+
}
92+
93+
fvp_ltimer_t *fvp_ltimer = ltimer->data;
94+
fvp_ltimer->ops = ops;
95+
96+
/* set up an SP804 for timeouts */
97+
sp804_config_t sp804_config = {
98+
.fdt_path = SP804_TIMER1_PATH,
99+
.user_cb_fn = callback,
100+
.user_cb_token = callback_token,
101+
.user_cb_event = LTIMER_TIMEOUT_EVENT
102+
};
103+
104+
error = sp804_init(&fvp_ltimer->sp804_timeout, ops, sp804_config);
105+
if (error) {
106+
ZF_LOGE("Failed to init timeout timer");
107+
destroy(&fvp_ltimer);
108+
return error;
109+
}
110+
111+
error = sp804_start(&fvp_ltimer->sp804_timeout);
112+
if (error) {
113+
ZF_LOGE("Failed to start timeout timer");
114+
destroy(&fvp_ltimer);
115+
return error;
116+
}
117+
118+
/* another for timestamps */
119+
sp804_config.fdt_path = SP804_TIMER2_PATH;
120+
sp804_config.user_cb_event = LTIMER_OVERFLOW_EVENT;
121+
122+
error = sp804_init(&fvp_ltimer->sp804_timestamp, ops, sp804_config);
123+
if (error) {
124+
ZF_LOGE("Failed to init timestamp timer");
125+
destroy(&fvp_ltimer);
126+
return error;
127+
}
128+
129+
error = sp804_start(&fvp_ltimer->sp804_timestamp);
130+
if (error) {
131+
ZF_LOGE("Failed to start timestamp timer");
132+
destroy(&fvp_ltimer);
133+
return error;
134+
}
135+
136+
error = sp804_set_timeout_ticks(&fvp_ltimer->sp804_timestamp, UINT32_MAX, true, true);
137+
if (error) {
138+
ZF_LOGE("Failed to set timeout ticks for timer");
139+
destroy(&fvp_ltimer);
140+
return error;
141+
}
142+
143+
return 0;
144+
}
145+
146+
/* This function is intended to be deleted,
147+
* this is just left here for now so that stuff can compile */
148+
int ltimer_default_describe(ltimer_t *ltimer, ps_io_ops_t ops)
149+
{
150+
ZF_LOGE("get_(nth/num)_(irqs/pmems) are not valid");
151+
return EINVAL;
152+
}

0 commit comments

Comments
 (0)