--- bsps/include/ofw/ofw.h | 534 ++++++++++++++++++++++++++++++++ bsps/shared/ofw/ofw.c | 654 ++++++++++++++++++++++++++++++++++++++++ spec/build/bsps/obj.yml | 4 + 3 files changed, 1192 insertions(+) create mode 100644 bsps/include/ofw/ofw.h create mode 100644 bsps/shared/ofw/ofw.c
diff --git a/bsps/include/ofw/ofw.h b/bsps/include/ofw/ofw.h new file mode 100644 index 0000000000..2ca5328abc --- /dev/null +++ b/bsps/include/ofw/ofw.h @@ -0,0 +1,534 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup ofw + * + * RTEMS FDT implementation of OpenFirmWare Interface. + * + * RTEMS OFW is a FDT only implementation of the OpenFirmWare interface. + * This API is created to be compatible with FreeBSD OpenFirmWare interface. + * The main intention is to make porting of FreeBSD drivers to RTEMS easier. + */ + +/* + * Copyright (C) 2020 Niteesh Babu G S <niteesh...@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OFW_H +#define _OFW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stddef.h> + +/** + * Represents a node in the device tree. The offset from fdtp to node is used + * instead of fdt offset to make sure this is compatible with OF interface in + * FreeBSD. + */ +typedef uint32_t phandle_t; +/** + * Represents the effective phandle of the node. + */ +typedef uint32_t ihandle_t; +/** + * Represents the data type of the buffer. + */ +typedef uint32_t pcell_t; + +/** + * @struct rtems_ofw_memory_area + * + * This is used to represent elements(FDT properties) that define + * region of memory address. + */ +typedef struct { + /** The start address of the memory region. */ + uint32_t start; + /** The size of the memory region. */ + uint32_t size; +} rtems_ofw_memory_area; + +/** + * @struct rtems_ofw_ranges + * + * This is used to represent the ranges property in the device tree. + */ +typedef struct { + /** The physical address within the child bus address space */ + uint32_t child_bus; + /** The physical address within the parent bus address space */ + uint32_t parent_bus; + /** The size of the range in the child’s address space */ + uint32_t size; +} rtems_ofw_ranges; + +/** + * @brief Gets the node that is next to @a node. + * + * @param[in] node Node offset + * + * @retval Peer node offset Successful operation. + * @retval 0 No peer node or invalid node handle + */ +phandle_t rtems_ofw_peer( + phandle_t node +); + +/** + * @brief Gets the node that is the child of @a node. + * + * @param[in] node Node offset + * + * @retval child node offset Successful operation. + * @retval 0 No child node or invalid node handle + */ +phandle_t rtems_ofw_child( + phandle_t node +); + +/** + * @brief Gets the node that is the parent of @a node. + * + * @param[in] node Node offset + * + * @retval child node offset Successful operation. + * @retval 0 No child node or invalid node handle + */ +phandle_t rtems_ofw_parent( + phandle_t node +); + +/** + * @brief Gets the length of the property mentioned in @a propname. + * + * @param[in] node Node offset + * @param[in] prop Property name + * + * @retval -1 Invalid node or property + * @retval Length of property on successful operation + */ +size_t rtems_ofw_get_prop_len( + phandle_t node, + const char *propname +); + +/** + * @brief Gets the value of property mentioned in @a propname. + * + * @param[in] node Node offset + * @param[in] prop Property name + * @param[out] buf The property value gets stored in this buffer (Pre-allocated) + * @param[in] len Length of the buffer + + * @retval -1 Invalid node or property + * @retval Length of property on successful operation + */ +size_t rtems_ofw_get_prop( + phandle_t node, + const char *propname, + void *buf, + size_t len +); + +/** + * @brief Gets the value of property mentioned in @a prop. + * + * Gets the value of property of @a node and converts the value into the host's + * endianness. + * + * @param[in] node Node offset + * @param[in] prop Property name + * @param[out] buf The property value gets stored in this buffer(Pre-allocated) + * after converted to the host's endianness + * @param[in] len Length of the buffer + * + * @retval -1 Invalid node or property + * @retval Length of property on successful operation + */ +size_t rtems_ofw_get_enc_prop( + phandle_t node, + const char *prop, + pcell_t *buf, + size_t len +); + +/** + * @brief Checks if the property @a propname is present in @a node. + * + * @param[in] node Node offset + * @param[in] propname Property name + * + * @retval 0 Property not present. + * @retval 1 Property is present. + */ +int rtems_ofw_has_prop( + phandle_t node, + const char *propname +); + +/** + * @brief Searches for property @a propname in @a node. + * + * Searches the node and its parent recursively for the property and fills the + * buffer with the first found value. + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[out] buf The property value gets stored in this buffer (Pre-allocated) + * @param[in] len Length of the buffer + * + * @retval Length of the property if property is found. + * @retval -1 Property is not found. + */ +size_t rtems_ofw_search_prop( + phandle_t node, + const char *propname, + void *buf, + size_t len +); + +/** + * @brief Searches for property @a propname in @a node. + * + * Searches the node and its parent recursively for the property and fills the + * buffer with the first value found after converting it to the endianness of + * the host. + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[out] buf The property value gets stored in this buffer(Pre-allocated) + * after converted to the host's endianness + * @param[in] len Length of the buffer + * + * @retval Length of the property if property is found. + * @retval -1 Property is not found. + */ +size_t rtems_ofw_search_enc_prop( + phandle_t node, + const char *propname, + pcell_t *buf, + size_t len +); + +/** + * @brief Gets the value of property mentioned in @a propname. + * + * Same as rtems_ofw_getprop, but the @a buf is allocated in this routine and + * the user is responsible for freeing it. + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[out] buf The buffer is allocated in this routine and user is + * responsible for freeing. + * + * @retval -1 Property is not found. + * @retval Length of the property if property is found. + */ +size_t rtems_ofw_get_prop_alloc( + phandle_t node, + const char *propname, + void **buf +); + +/** + * @brief Gets multiple values of the property @a propname. + * + * Same as rtems_ofw_getprop_alloc but it can read properties with multiple + * values. + * For eg: reg = <0x1000 0x10 0x2000 0x20> + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[in] elsz Size of the single value + * @param[out] buf The buffer is allocated in this routine and user is + * responsible for freeing. + * + * @retval -1 Property is not found. + * @retval Number of values read. + */ +size_t rtems_ofw_get_prop_alloc_multi( + phandle_t node, + const char *propname, + int elsz, + void **buf +); + +/** + * @brief Gets the value of property mentioned in @a propname. + * + * Same as rtems_ofw_getprop_alloc but the value stored in the buffer is + * converted into the host's endianness. + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[out] buf The buffer is allocated in this routine and user is + * responsible for freeing. + * + * @retval -1 Property is not found. + * @retval Length of the property if property is found. + */ +size_t rtems_ofw_get_enc_prop_alloc( + phandle_t node, + const char *propname, + void **buf +); + +/** + * @brief Gets multiple values of the property @a propname. + * + * Same as rtems_ofw_getprop_alloc_multi but the values stored in the buffer + * are converted to the host's endianness. + * + * @param[in] node Node offset + * @param[in] propname Property name + * @param[in] elsz Size of the single value + * @param[out] buf The buffer is allocated in this routine and user is + * responsible for freeing. + * + * @retval -1 Property is not found. + * @retval Number of values read. + */ +size_t rtems_ofw_get_enc_prop_alloc_multi( + phandle_t node, + const char *propname, + int elsz, + void **buf +); + +/** + * @brief Free's the buffers allocated by the rtems_ofw_*_alloc functions. + * + * @param[in] buf Buffer to be freed + */ +void rtems_ofw_free( + void *buf +); + +/** + * @brief Finds the next property of @a node. + * + * Finds the next property of the node and when @a propname is NULL it returns + * the value in the first property. + * + * @param[in] node Node offset + * @param[in] previous Previous property name + * @param[out] buf The value of the next property gets stored in this buffer + * (Pre-allocated) + * @param[in] len Length of the buffer + * + * @retval -1 node or previous property does not exist + * @retval 0 no more properties + * @retval 1 success + */ +int rtems_ofw_next_prop( + phandle_t node, + const char *previous, + char *buf, + size_t len +); + +/** + * @brief Sets the property @name of @a node to @a buf. + * + * @param[in] node Node offset + * @param[in] name Property name + * @param[in] buf Buffer contains the value to be set. + * @param[in] len Length of the buffer + * + * @retval -1 node does not exist + * @retval 0 on success + * @retval libFDT error codes on unsuccessful setting operation + */ +int rtems_ofw_set_prop( + phandle_t node, + const char *name, + const void *buf, + size_t len +); + +/** + * @brief Converts a device specifier to a fully qualified path name. + * + * @param[in] dev device specifier + * @param[out] buf The path is filled into the buffer(Pre-allocated) + * @param[in] length of the buffer + * + * @retval -1 always. Unimplemented. + */ +size_t rtems_ofw_canon( + const char *dev, + char *buf, + size_t len +); + +/** + * @brief Finds the node at the given path + * + * @param[in] path to the node from root + * + * @retval -1 node does not exist + * @retval node handle on success + */ +phandle_t rtems_ofw_find_device( + const char *path +); + +/** + * @brief This routine converts effective phandle @a xref to node offset. + * + * @param[in] xref Node phandle + * + * @retval Node offset on success + * @retval Node phandle on failure + */ +phandle_t rtems_ofw_node_from_xref( + phandle_t xref +); + +/** + * @brief This routine converts node offset to effective phandle of @a node. + * + * @retval Node phandle on success + * @retval Node offset on failure + */ +phandle_t rtems_ofw_xref_from_node( + phandle_t node +); + +/* + * instance handles(ihandle_t) as same as phandles in the FDT implementation + * of OF interface. + */ + +/** + * @brief Converts @a instance handle to phandle. + * + * instance are same as node offsets in FDT. + * + * @param[in] instance Node offset + * + * @retval phandle of node on success. + * @retval instance of node on failure. + */ +phandle_t rtems_ofw_instance_to_package( + ihandle_t instance +); + +/** + * @brief Find the node's path from phandle. + * + * @param[in] node Node offset + * @param[out] buf Path is filled into this buffer(Pre-allocated). + * @param[in] len Length of the buffer. + * + * @retval -1 always. Unimplemented. + */ +size_t rtems_ofw_package_to_path( + phandle_t node, + char *buf, + size_t len +); + +/** + * @brief Find the node's path from ihandle. + * + * @param[in] instance Node offset + * @param[out] buf Path is filled into this buffer(Pre-allocated). + * @param[in] len Length of the buffer. + * + * @retval -1 always. Unimplemented. + */ +size_t rtems_ofw_instance_to_path( + ihandle_t instance, + char *buf, + size_t len +); + +/** + * @brief Queries the node's reg value. + * + * This routine fills the buffer @a buf with the values in reg property of node + * @a node. It reads all the values of the property and fills the buffer to max + * size. + * This routine is local to RTEMS OFW and does not have an corresponding + * FreeBSD OFW pair. + * + * @param[in] node Node offset + * @param[out] buf Register values are stored in this buffer(Pre-allocated). + * @param[in] size Length of the buffer. + * + * @retval -1 If reg property is missing. + * @retval Length of the reg property in bytes. + */ +int rtems_ofw_get_reg( + phandle_t node, + rtems_ofw_memory_area *buf, + size_t size +); + +/** + * @brief Queries the node's interrupt value. + * + * This routine fills the buffer @a buf with the interrupt number. In case of + * multiple numbers it fills the buffer to its full extent. + * This routine is local to RTEMS OFW and does not have an corresponding + * FreeBSD OFW pair. + * + * @param[in] node Node offset + * @param[out] buf Interrupt values are stored in this buffer(Pre-allocated). + * @param[in] size Length of the buffer. + * + * @retval -1 If interrupts property is missing. + * @retval Length of the interrupts property in bytes. + */ +int rtems_ofw_get_interrupts( + phandle_t node, + void *buf, + size_t size +); + +/** + * @brief Queries the node's status. + * + * This routine is local to RTEMS OFW and does not have an corresponding + * FreeBSD OFW pair. + * + * @param[in] node Node offset + * + * @retval true Status is OK or empty. + * @retval false Status is not OK or missing. + */ +bool rtems_ofw_node_status( phandle_t node ); + +#ifdef __cplusplus +} +#endif + +#endif /* _OFW_H */ \ No newline at end of file diff --git a/bsps/shared/ofw/ofw.c b/bsps/shared/ofw/ofw.c new file mode 100644 index 0000000000..57423e62fc --- /dev/null +++ b/bsps/shared/ofw/ofw.c @@ -0,0 +1,654 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup ofw + */ + +/* + * Copyright (C) 2020 Niteesh Babu G S <niteesh...@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <bsp/fdt.h> +#include <sys/param.h> +#include <ofw/ofw.h> +#include <libfdt.h> +#include <assert.h> +#include <rtems/sysinit.h> + +const void *fdtp = NULL; + +static phandle_t rtems_fdt_offset_to_phandle( int offset ) +{ + if (offset < 0) { + return 0; + } + + return (phandle_t)offset + fdt_off_dt_struct(fdtp); +} + +static int rtems_fdt_phandle_to_offset( phandle_t handle ) +{ + int off; + int fdt_off; + + off = (int) handle; + fdt_off = fdt_off_dt_struct(fdtp); + + if (off < fdt_off) { + return -1; + + } + + return off - fdt_off; +} + +static void rtems_ofw_init( void ) { + int rv; + const void *fdt; + + fdt = bsp_fdt_get(); + + rv = fdt_check_header(fdt); + + /* + * Is assert a good option to handle error? + * AFIAK there is no other way to recover from invalid FDT. + * On providing an invalid FDT most driver's will fail/crash anyway. + */ + assert(rv == 0); + + fdtp = fdt; +} + +RTEMS_SYSINIT_ITEM( + rtems_ofw_init, + RTEMS_SYSINIT_BSP_PRE_DRIVERS, + RTEMS_SYSINIT_ORDER_FIRST +); + +phandle_t rtems_ofw_peer( phandle_t node ) +{ + int offset; + + if (node == 0) { + int root = fdt_path_offset(fdtp, "/"); + return rtems_fdt_offset_to_phandle(root); + } + + offset = rtems_fdt_phandle_to_offset(node); + if (offset < 0) { + return 0; + } + + offset = fdt_next_subnode(fdtp, offset); + return rtems_fdt_offset_to_phandle(offset); +} + +phandle_t rtems_ofw_child( phandle_t node ) +{ + int offset; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) { + return 0; + } + + offset = fdt_first_subnode(fdtp, offset); + return rtems_fdt_offset_to_phandle(offset); +} + +phandle_t rtems_ofw_parent( phandle_t node ) +{ + int offset; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) { + return 0; + } + + offset = fdt_parent_offset(fdtp, offset); + return rtems_fdt_offset_to_phandle(offset); +} + +size_t rtems_ofw_get_prop_len( + phandle_t node, + const char *propname +) +{ + int offset; + int len; + const void *prop; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) { + return -1; + } + + prop = fdt_getprop(fdtp, offset, propname, &len); + + if (prop == NULL && strcmp(propname, "name") == 0) { + fdt_get_name(fdtp, offset, &len); + return len + 1; + } + + if (prop == NULL && strcmp(propname, "/chosen") == 0) { + if (strcmp(propname, "fdtbootcpu") == 0) + return sizeof(pcell_t); + if (strcmp(propname, "fdtmemreserv") == 0) + return 2 * sizeof(uint64_t) * fdt_num_mem_rsv(fdtp); + } + + if (prop == NULL) { + return -1; + } + + return len; +} + +size_t rtems_ofw_get_prop( + phandle_t node, + const char *propname, + void *buf, + size_t bufsize +) +{ + int offset; + int len; + const void *prop; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) { + return -1; + } + + prop = fdt_getprop(fdtp, offset, propname, &len); + + if (prop == NULL && strcmp(propname, "name") == 0) { + fdt_get_name(fdtp, offset, &len); + return len + 1; + } + + if (prop == NULL && strcmp(propname, "/chosen") == 0) { + if (strcmp(propname, "fdtbootcpu") == 0) + return sizeof(pcell_t); + if (strcmp(propname, "fdtmemreserv") == 0) + return 2 * sizeof(uint64_t) * fdt_num_mem_rsv(fdtp); + } + + if (prop == NULL) { + return -1; + } + + bcopy(prop, buf, MIN(len, bufsize)); + + return len; +} + +size_t rtems_ofw_get_enc_prop( + phandle_t node, + const char *prop, + pcell_t *buf, + size_t len +) +{ + size_t rv; + + assert(len % 4 == 0); + rv = rtems_ofw_get_prop(node, prop, buf, len); + + if (rv < 0) { + return rv; + } + + for (int i = 0; i < (len / 4); i++) { + buf[i] = fdt32_to_cpu(buf[i]); + } + + return rv; +} + +int rtems_ofw_has_prop( + phandle_t node, + const char *propname +) +{ + size_t rv; + + rv = rtems_ofw_get_prop_len(node, propname); + return rv >= 0 ? 1 : 0; +} + +size_t rtems_ofw_search_prop( + phandle_t node, + const char *propname, + void *buf, + size_t len +) +{ + size_t rv; + + for (; node != 0; node = rtems_ofw_parent(node)) { + if ((rv = rtems_ofw_get_prop(node, propname, buf, len) != -1)) { + return rv; + } + } + + return -1; +} + +size_t rtems_ofw_search_enc_prop( + phandle_t node, + const char *propname, + pcell_t *buf, + size_t len +) +{ + size_t rv; + + for (; node != 0; node = rtems_ofw_parent(node)) { + if ((rv = rtems_ofw_get_enc_prop(node, propname, buf, len) != -1)) { + return rv; + } + } + + return -1; +} + +size_t rtems_ofw_get_prop_alloc( + phandle_t node, + const char *propname, + void **buf +) +{ + size_t len; + + if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) { + return -1; + } + + *buf = NULL; + + if (len > 0) { + *buf = malloc(len); + + if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) { + rtems_ofw_free(buf); + *buf = NULL; + return -1; + } + } + + return len; +} + +size_t rtems_ofw_get_prop_alloc_multi( + phandle_t node, + const char *propname, + int elsz, + void **buf +) +{ + size_t len; + + if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 || + (len % elsz != 0)) { + return -1; + } + + *buf = NULL; + + if (len > 0) { + *buf = malloc(len); + + if (rtems_ofw_get_prop(node, propname, *buf, len) == -1) { + rtems_ofw_free(buf); + *buf = NULL; + return -1; + } + } + + return (len / elsz); +} + +size_t rtems_ofw_get_enc_prop_alloc( + phandle_t node, + const char *propname, + void **buf +) +{ + size_t len; + + if ((len = rtems_ofw_get_prop_len(node, propname)) == -1) { + return -1; + } + + *buf = NULL; + + if (len > 0) { + *buf = malloc(len); + + if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) { + rtems_ofw_free(buf); + *buf = NULL; + return -1; + } + } + + return len; +} + +size_t rtems_ofw_get_enc_prop_alloc_multi( + phandle_t node, + const char *propname, + int elsz, + void **buf +) +{ + size_t len; + + if ((len = rtems_ofw_get_prop_len(node, propname)) == -1 || + (len % elsz != 0)) { + return -1; + } + + *buf = NULL; + + if (len > 0) { + *buf = malloc(len); + + if (rtems_ofw_get_enc_prop(node, propname, *buf, len) == -1) { + rtems_ofw_free(buf); + *buf = NULL; + return -1; + } + } + + return (len / elsz); +} + +void rtems_ofw_free( void *buf ) +{ + free(buf); +} + +int rtems_ofw_next_prop( + phandle_t node, + const char *previous, + char *buf, + size_t len +) +{ + const void *name; + const void *prop; + int offset; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) { + return -1; + } + + if (previous == NULL) { + offset = fdt_first_property_offset(fdtp, offset); + } else { + fdt_for_each_property_offset(offset, fdtp, offset) { + prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name, NULL); + if (prop == NULL) + return -1; + + if (strcmp(previous, name) != 0) + continue; + + offset = fdt_next_property_offset(fdtp, offset); + break; + } + } + + if (offset < 0) + return 0; + + prop = fdt_getprop_by_offset(fdtp, offset, (const char **)&name, &offset); + if (prop == NULL) + return -1; + + strncpy(buf, name, len); + + return 1; +} + +int rtems_ofw_set_prop( + phandle_t node, + const char *name, + const void *buf, + size_t len +) +{ + int offset; + + offset = rtems_fdt_phandle_to_offset(node); + + if (offset < 0) + return -1; + + if (fdt_setprop_inplace(fdtp, offset, name, buf, len) != 0) + return (fdt_setprop(fdtp, offset, name, buf, len)); + + return 0; +} + +phandle_t rtems_ofw_find_device( const char *path ) +{ + int offset; + + offset = fdt_path_offset(fdtp, path); + if (offset < 0) + return -1; + + return rtems_fdt_offset_to_phandle(offset); +} + +static phandle_t rtems_ofw_get_effective_phandle( + phandle_t node, + phandle_t xref +) +{ + phandle_t child; + phandle_t ref; + + for (child = rtems_ofw_child(node); child != 0; child = rtems_ofw_peer(node)) { + ref = rtems_ofw_get_effective_phandle(child, xref); + if (ref != -1) + return ref; + + if (rtems_ofw_get_enc_prop(child, "phandle", &ref, sizeof(ref)) == -1 && + rtems_ofw_get_enc_prop(child, "ibm,phandle", &ref, sizeof(ref)) == -1 && + rtems_ofw_get_enc_prop(child, "linux,phandle", &ref, sizeof(ref)) == -1 + ) { + continue; + } + + if (ref == xref) + return child; + } + + return -1; +} + +phandle_t rtems_ofw_node_from_xref( phandle_t xref ) +{ + phandle_t node; + + if ((node = rtems_ofw_get_effective_phandle(rtems_ofw_peer(0), xref)) == -1) + return xref; + + return node; +} + +phandle_t rtems_ofw_xref_from_node( phandle_t node ) +{ + phandle_t ref; + + if (rtems_ofw_get_enc_prop(node, "phandle", &ref, sizeof(ref)) == -1 && + rtems_ofw_get_enc_prop(node, "ibm,phandle", &ref, sizeof(ref)) == -1 && + rtems_ofw_get_enc_prop(node, "linux,phandle", &ref, sizeof(ref)) == -1) + { + return node; + } + + return ref; +} + +phandle_t rtems_ofw_instance_to_package( ihandle_t instance ) +{ + return rtems_ofw_node_from_xref(instance); +} + +size_t rtems_ofw_package_to_path( + phandle_t node, + char *buf, + size_t len +) +{ + int offset; + int rv; + + offset = rtems_fdt_phandle_to_offset(node); + + rv = fdt_get_path(fdtp, offset, buf, len); + if (rv != 0) + return -1; + + return rv; +} + +size_t rtems_ofw_instance_to_path( + ihandle_t instance, + char *buf, + size_t len +) +{ + int offset; + int rv; + + offset = rtems_ofw_instance_to_package(instance); + offset = rtems_fdt_phandle_to_offset(offset); + + rv = fdt_get_path(fdtp, offset, buf, len); + if (rv != 0) + return -1; + + return rv; +} + +int rtems_ofw_get_reg( + phandle_t node, + rtems_ofw_memory_area *buf, + size_t size +) +{ + int len; + int offset; + int nranges; + int nregs; + phandle_t parent; + rtems_ofw_ranges range; + const rtems_ofw_ranges *ptr; + + len = rtems_ofw_get_enc_prop(node, "reg", (pcell_t *)buf, size); + if (len <= 0) { + return len; + } + + nregs = MIN(len, size) / sizeof(rtems_ofw_memory_area); + + for (parent = rtems_ofw_parent(node); parent > 0; + parent = rtems_ofw_parent(parent)) { + + offset = rtems_fdt_phandle_to_offset(parent); + ptr = fdt_getprop(fdtp, offset, "ranges", &len); + + if (len < 0) { + break; + } + + nranges = len / sizeof(rtems_ofw_ranges); + + offset = 0; + for (int i=0; i < nregs; i++) { + for (int j=0; j < nranges; j++) { + + range.parent_bus = fdt32_to_cpu(ptr[j].parent_bus); + range.child_bus = fdt32_to_cpu(ptr[j].child_bus); + range.size = fdt32_to_cpu(ptr[j].size); + + if (buf[i].start >= range.child_bus && + buf[i].start < range.child_bus + range.size) { + offset = range.parent_bus - range.child_bus; + break; + } + + } + buf[i].start += offset; + } + } + + return nregs; +} + +int rtems_ofw_get_interrupts( + phandle_t node, + void *buf, + size_t size +) +{ + int rv; + + rv = rtems_ofw_get_enc_prop(node, "interrupts", buf, size); + return rv; +} + +bool rtems_ofw_node_status( phandle_t node ) +{ + int len; + const char buf[10]; + + len = rtems_ofw_get_prop(node, "status", &buf[0], sizeof(buf)); + if ((len == -1) || + (strncmp(buf, "okay", MIN(5, len)) == 0) || + (strncmp(buf, "ok", MIN(3, len)) == 0)) { + return true; + } + + return false; +} diff --git a/spec/build/bsps/obj.yml b/spec/build/bsps/obj.yml index 8809238057..141ba25f5e 100644 --- a/spec/build/bsps/obj.yml +++ b/spec/build/bsps/obj.yml @@ -24,6 +24,9 @@ install: - bsps/include/bsp/u-boot.h - bsps/include/bsp/uart-output-char.h - bsps/include/bsp/utility.h +- destination: ${BSP_INCLUDEDIR}/ofw + source: + - bsps/include/ofw/ofw.h - destination: ${BSP_INCLUDEDIR}/libchip source: - bsps/include/libchip/am29lv160.h @@ -104,4 +107,5 @@ source: - bsps/shared/dev/serial/z85c30_reg.c - bsps/shared/start/bootcard.c - bsps/shared/rtems-version.c +- bsps/shared/ofw/ofw.c type: build -- 2.17.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel