mirror of https://gitee.com/openkylin/qemu.git
hw/arm/sysbus-fdt: helpers for clock node generation
Some passthrough'ed devices depend on clock nodes. Those need to be generated in the guest device tree. This patch introduces some helpers to build a clock node from information retrieved in the host device tree. - copy_properties_from_host copies properties from a host device tree node to a guest device tree node - fdt_build_clock_node builds a guest clock node and checks the host fellow clock is a fixed one. fdt_build_clock_node will become static as soon as it gets used. A dummy pre-declaration is needed for compilation of this patch. Signed-off-by: Eric Auger <eric.auger@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
58e71097ce
commit
9481cf2e5f
|
@ -22,6 +22,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include <libfdt.h>
|
||||||
#include "hw/arm/sysbus-fdt.h"
|
#include "hw/arm/sysbus-fdt.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/device_tree.h"
|
#include "sysemu/device_tree.h"
|
||||||
|
@ -57,6 +58,125 @@ typedef struct NodeCreationPair {
|
||||||
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
|
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
|
||||||
} NodeCreationPair;
|
} NodeCreationPair;
|
||||||
|
|
||||||
|
/* helpers */
|
||||||
|
|
||||||
|
typedef struct HostProperty {
|
||||||
|
const char *name;
|
||||||
|
bool optional;
|
||||||
|
} HostProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy_properties_from_host
|
||||||
|
*
|
||||||
|
* copies properties listed in an array from host device tree to
|
||||||
|
* guest device tree. If a non optional property is not found, the
|
||||||
|
* function asserts. An optional property is ignored if not found
|
||||||
|
* in the host device tree.
|
||||||
|
* @props: array of HostProperty to copy
|
||||||
|
* @nb_props: number of properties in the array
|
||||||
|
* @host_dt: host device tree blob
|
||||||
|
* @guest_dt: guest device tree blob
|
||||||
|
* @node_path: host dt node path where the property is supposed to be
|
||||||
|
found
|
||||||
|
* @nodename: guest node name the properties should be added to
|
||||||
|
*/
|
||||||
|
static void copy_properties_from_host(HostProperty *props, int nb_props,
|
||||||
|
void *host_fdt, void *guest_fdt,
|
||||||
|
char *node_path, char *nodename)
|
||||||
|
{
|
||||||
|
int i, prop_len;
|
||||||
|
const void *r;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < nb_props; i++) {
|
||||||
|
r = qemu_fdt_getprop(host_fdt, node_path,
|
||||||
|
props[i].name,
|
||||||
|
&prop_len,
|
||||||
|
props[i].optional ? &err : &error_fatal);
|
||||||
|
if (r) {
|
||||||
|
qemu_fdt_setprop(guest_fdt, nodename,
|
||||||
|
props[i].name, r, prop_len);
|
||||||
|
} else {
|
||||||
|
if (prop_len != -FDT_ERR_NOTFOUND) {
|
||||||
|
/* optional property not returned although property exists */
|
||||||
|
error_report_err(err);
|
||||||
|
} else {
|
||||||
|
error_free(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clock properties whose values are copied/pasted from host */
|
||||||
|
static HostProperty clock_copied_properties[] = {
|
||||||
|
{"compatible", false},
|
||||||
|
{"#clock-cells", false},
|
||||||
|
{"clock-frequency", true},
|
||||||
|
{"clock-output-names", true},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_build_clock_node
|
||||||
|
*
|
||||||
|
* Build a guest clock node, used as a dependency from a passthrough'ed
|
||||||
|
* device. Most information are retrieved from the host clock node.
|
||||||
|
* Also check the host clock is a fixed one.
|
||||||
|
*
|
||||||
|
* @host_fdt: host device tree blob from which info are retrieved
|
||||||
|
* @guest_fdt: guest device tree blob where the clock node is added
|
||||||
|
* @host_phandle: phandle of the clock in host device tree
|
||||||
|
* @guest_phandle: phandle to assign to the guest node
|
||||||
|
*/
|
||||||
|
void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
|
||||||
|
uint32_t host_phandle,
|
||||||
|
uint32_t guest_phandle);
|
||||||
|
void fdt_build_clock_node(void *host_fdt, void *guest_fdt,
|
||||||
|
uint32_t host_phandle,
|
||||||
|
uint32_t guest_phandle)
|
||||||
|
{
|
||||||
|
char *node_path = NULL;
|
||||||
|
char *nodename;
|
||||||
|
const void *r;
|
||||||
|
int ret, node_offset, prop_len, path_len = 16;
|
||||||
|
|
||||||
|
node_offset = fdt_node_offset_by_phandle(host_fdt, host_phandle);
|
||||||
|
if (node_offset <= 0) {
|
||||||
|
error_setg(&error_fatal,
|
||||||
|
"not able to locate clock handle %d in host device tree",
|
||||||
|
host_phandle);
|
||||||
|
}
|
||||||
|
node_path = g_malloc(path_len);
|
||||||
|
while ((ret = fdt_get_path(host_fdt, node_offset, node_path, path_len))
|
||||||
|
== -FDT_ERR_NOSPACE) {
|
||||||
|
path_len += 16;
|
||||||
|
node_path = g_realloc(node_path, path_len);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg(&error_fatal,
|
||||||
|
"not able to retrieve node path for clock handle %d",
|
||||||
|
host_phandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = qemu_fdt_getprop(host_fdt, node_path, "compatible", &prop_len,
|
||||||
|
&error_fatal);
|
||||||
|
if (strcmp(r, "fixed-clock")) {
|
||||||
|
error_setg(&error_fatal,
|
||||||
|
"clock handle %d is not a fixed clock", host_phandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
nodename = strrchr(node_path, '/');
|
||||||
|
qemu_fdt_add_subnode(guest_fdt, nodename);
|
||||||
|
|
||||||
|
copy_properties_from_host(clock_copied_properties,
|
||||||
|
ARRAY_SIZE(clock_copied_properties),
|
||||||
|
host_fdt, guest_fdt,
|
||||||
|
node_path, nodename);
|
||||||
|
|
||||||
|
qemu_fdt_setprop_cell(guest_fdt, nodename, "phandle", guest_phandle);
|
||||||
|
|
||||||
|
g_free(node_path);
|
||||||
|
}
|
||||||
|
|
||||||
/* Device Specific Code */
|
/* Device Specific Code */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue