-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libplatsupport/morello: Add basic drivers for morello-soc
This is a Morello hardware platform also known as morello-sdp board. 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 <[email protected]>
- Loading branch information
1 parent
5a0472c
commit 23adae6
Showing
9 changed files
with
624 additions
and
0 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
libplatsupport/plat_include/morello-soc/platsupport/plat/clock.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
11
libplatsupport/plat_include/morello-soc/platsupport/plat/i2c.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
}; |
30 changes: 30 additions & 0 deletions
30
libplatsupport/plat_include/morello-soc/platsupport/plat/serial.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) | ||
* Copyright (c) 2024, Capabilities Ltd <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
||
#pragma once | ||
|
||
// AP UARTs | ||
#define UART0_PADDR 0x2a400000 | ||
#define UART1_PADDR 0x2a410000 // Secure mode | ||
|
||
#define UART0_IRQ 95 | ||
#define UART1_IRQ 96 | ||
|
||
enum chardev_id { | ||
PL001_UART0, | ||
PL001_UART1, | ||
|
||
/* Aliases */ | ||
PS_SERIAL0 = PL001_UART0, | ||
PS_SERIAL1 = PL001_UART1, | ||
|
||
/* defaults */ | ||
PS_SERIAL_DEFAULT = PL001_UART0 | ||
}; | ||
|
||
#define DEFAULT_SERIAL_PADDR UART0_PADDR | ||
#define DEFAULT_SERIAL_INTERRUPT UART0_IRQ |
75 changes: 75 additions & 0 deletions
75
libplatsupport/plat_include/morello-soc/platsupport/plat/sp804.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) | ||
* Copyright (c) 2024, Capabilities Ltd <[email protected]> | ||
* | ||
* 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. */ | ||
#define SP804_TIMER1_PATH "/timer@1c0d0000" | ||
#define SP804_TIMER2_PATH "/timer@1c0e0000" | ||
|
||
#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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* 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}; | ||
static const int uart1_irqs[] = {UART1_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), | ||
UART_DEFN(1) | ||
}; | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
* 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 { | ||
/* morello_iofpga 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; | ||
} morello_iofpga_ltimer_t; | ||
|
||
static int get_time(void *data, uint64_t *time) | ||
{ | ||
morello_iofpga_ltimer_t *morello_iofpga_ltimer = data; | ||
assert(data != NULL); | ||
assert(time != NULL); | ||
|
||
*time = sp804_get_time(&morello_iofpga_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; | ||
} | ||
|
||
morello_iofpga_ltimer_t *morello_iofpga_ltimer = data; | ||
return sp804_set_timeout(&morello_iofpga_ltimer->sp804_timeout, ns, type == TIMEOUT_PERIODIC, true); | ||
return 0; | ||
} | ||
|
||
static int reset(void *data) | ||
{ | ||
morello_iofpga_ltimer_t *morello_iofpga_ltimer = data; | ||
/* restart the rtc */ | ||
sp804_stop(&morello_iofpga_ltimer->sp804_timeout); | ||
sp804_start(&morello_iofpga_ltimer->sp804_timeout); | ||
|
||
return 0; | ||
} | ||
|
||
static void destroy(void *data) | ||
{ | ||
assert(data != NULL); | ||
morello_iofpga_ltimer_t *morello_iofpga_ltimer = data; | ||
sp804_destroy(&morello_iofpga_ltimer->sp804_timeout); | ||
sp804_destroy(&morello_iofpga_ltimer->sp804_timestamp); | ||
ps_free(&morello_iofpga_ltimer->ops.malloc_ops, sizeof(morello_iofpga_ltimer_t), morello_iofpga_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(morello_iofpga_ltimer_t), | ||
get_time, set_timeout, reset, destroy | ||
); | ||
if (error) { | ||
ZF_LOGE("Failed to create ltimer simple"); | ||
return error; | ||
} | ||
|
||
morello_iofpga_ltimer_t *morello_iofpga_ltimer = ltimer->data; | ||
morello_iofpga_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(&morello_iofpga_ltimer->sp804_timeout, ops, sp804_config); | ||
if (error) { | ||
ZF_LOGE("Failed to init timeout timer"); | ||
destroy(&morello_iofpga_ltimer); | ||
return error; | ||
} | ||
|
||
error = sp804_start(&morello_iofpga_ltimer->sp804_timeout); | ||
if (error) { | ||
ZF_LOGE("Failed to start timeout timer"); | ||
destroy(&morello_iofpga_ltimer); | ||
return error; | ||
} | ||
|
||
/* another for timestamps */ | ||
sp804_config.fdt_path = SP804_TIMER2_PATH; | ||
sp804_config.user_cb_event = LTIMER_OVERFLOW_EVENT; | ||
|
||
error = sp804_init(&morello_iofpga_ltimer->sp804_timestamp, ops, sp804_config); | ||
if (error) { | ||
ZF_LOGE("Failed to init timestamp timer"); | ||
destroy(&morello_iofpga_ltimer); | ||
return error; | ||
} | ||
|
||
error = sp804_start(&morello_iofpga_ltimer->sp804_timestamp); | ||
if (error) { | ||
ZF_LOGE("Failed to start timestamp timer"); | ||
destroy(&morello_iofpga_ltimer); | ||
return error; | ||
} | ||
|
||
error = sp804_set_timeout_ticks(&morello_iofpga_ltimer->sp804_timestamp, UINT32_MAX, true, true); | ||
if (error) { | ||
ZF_LOGE("Failed to set timeout ticks for timer"); | ||
destroy(&morello_iofpga_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; | ||
} |
Oops, something went wrong.