forked from Mirrors/opensbi

This allows the compiler to generate significantly better code, because it does not have to maintain either the loop counter or loop limit. Plus there are half as many symbols to relocate. This also simplifies passing carray arrays to helper functions. Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Anup Patel <anup@brainfault.org>
88 lines
1.9 KiB
C
88 lines
1.9 KiB
C
/*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
|
*
|
|
* Authors:
|
|
* Anup Patel <anup.patel@wdc.com>
|
|
*/
|
|
|
|
#include <libfdt.h>
|
|
#include <sbi/sbi_error.h>
|
|
#include <sbi/sbi_scratch.h>
|
|
#include <sbi_utils/fdt/fdt_helper.h>
|
|
#include <sbi_utils/serial/fdt_serial.h>
|
|
|
|
/* List of FDT serial drivers generated at compile time */
|
|
extern struct fdt_serial *const fdt_serial_drivers[];
|
|
|
|
int fdt_serial_init(const void *fdt)
|
|
{
|
|
const void *prop;
|
|
struct fdt_serial *drv;
|
|
const struct fdt_match *match;
|
|
int pos, noff = -1, len, coff, rc;
|
|
|
|
/* Find offset of node pointed to by stdout-path */
|
|
coff = fdt_path_offset(fdt, "/chosen");
|
|
if (-1 < coff) {
|
|
prop = fdt_getprop(fdt, coff, "stdout-path", &len);
|
|
if (prop && len) {
|
|
const char *sep, *start = prop;
|
|
|
|
/* The device path may be followed by ':' */
|
|
sep = strchr(start, ':');
|
|
if (sep)
|
|
noff = fdt_path_offset_namelen(fdt, prop,
|
|
sep - start);
|
|
else
|
|
noff = fdt_path_offset(fdt, prop);
|
|
}
|
|
if (-1 < noff) {
|
|
if (!fdt_node_is_enabled(fdt, noff))
|
|
noff = -1;
|
|
}
|
|
}
|
|
|
|
/* First check DT node pointed by stdout-path */
|
|
for (pos = 0; fdt_serial_drivers[pos] && -1 < noff; pos++) {
|
|
drv = fdt_serial_drivers[pos];
|
|
|
|
match = fdt_match_node(fdt, noff, drv->match_table);
|
|
if (!match)
|
|
continue;
|
|
|
|
/* drv->init must not be NULL */
|
|
if (drv->init == NULL)
|
|
return SBI_EFAIL;
|
|
|
|
rc = drv->init(fdt, noff, match);
|
|
if (rc == SBI_ENODEV)
|
|
continue;
|
|
return rc;
|
|
}
|
|
|
|
/* Lastly check all DT nodes */
|
|
for (pos = 0; fdt_serial_drivers[pos]; pos++) {
|
|
drv = fdt_serial_drivers[pos];
|
|
|
|
noff = -1;
|
|
while ((noff = fdt_find_match(fdt, noff,
|
|
drv->match_table, &match)) >= 0) {
|
|
if (!fdt_node_is_enabled(fdt, noff))
|
|
continue;
|
|
|
|
/* drv->init must not be NULL */
|
|
if (drv->init == NULL)
|
|
return SBI_EFAIL;
|
|
|
|
rc = drv->init(fdt, noff, match);
|
|
if (rc == SBI_ENODEV)
|
|
continue;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return SBI_ENODEV;
|
|
}
|