mirror of
https://github.com/riscv-software-src/opensbi.git
synced 2025-08-24 15:31:22 +01:00
platform: fpga/common: Add a fdt parsing helper functions
Different DT based platforms from the sam family may reuse IP blocks with different configurations. These different configurations can be obtained by parsing the device tree. Add a FDT parser framework that can parse various device configurations from device tree. Currently, the parsing algorithms doesn't cover all the use cases or possible combination of DT configurations. It will be improved over time. Signed-off-by: Atish Patra <atish.patra@wdc.com> Reviewed-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
@@ -9,6 +9,26 @@
|
||||
#ifndef __FDT_HELPER_H__
|
||||
#define __FDT_HELPER_H__
|
||||
|
||||
struct platform_uart_data {
|
||||
unsigned long addr;
|
||||
unsigned long freq;
|
||||
unsigned long baud;
|
||||
};
|
||||
|
||||
struct platform_plic_data {
|
||||
unsigned long addr;
|
||||
unsigned long num_src;
|
||||
};
|
||||
|
||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||
const char *compatible);
|
||||
|
||||
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
|
||||
const char *compatible);
|
||||
|
||||
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
|
||||
const char *compatible);
|
||||
|
||||
/**
|
||||
* Fix up the CPU node in the device tree
|
||||
*
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <sbi/sbi_console.h>
|
||||
#include <sbi/sbi_platform.h>
|
||||
#include <sbi/sbi_scratch.h>
|
||||
#include <sbi_utils/fdt/fdt_helper.h>
|
||||
|
||||
void fdt_cpu_fixup(void *fdt)
|
||||
{
|
||||
@@ -198,3 +199,118 @@ void fdt_fixups(void *fdt)
|
||||
|
||||
fdt_reserved_memory_fixup(fdt);
|
||||
}
|
||||
|
||||
static int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr,
|
||||
unsigned long *size)
|
||||
{
|
||||
int parent, len, i;
|
||||
int cell_addr, cell_size;
|
||||
const fdt32_t *prop_addr, *prop_size;
|
||||
uint64_t temp = 0;
|
||||
|
||||
parent = fdt_parent_offset(fdt, node);
|
||||
if (parent < 0)
|
||||
return parent;
|
||||
cell_addr = fdt_address_cells(fdt, parent);
|
||||
if (cell_addr < 1)
|
||||
return SBI_ENODEV;
|
||||
|
||||
cell_size = fdt_size_cells(fdt, parent);
|
||||
if (cell_size < 0)
|
||||
return SBI_ENODEV;
|
||||
|
||||
prop_addr = fdt_getprop(fdt, node, "reg", &len);
|
||||
if (!prop_addr)
|
||||
return SBI_ENODEV;
|
||||
prop_size = prop_addr + cell_addr;
|
||||
|
||||
if (addr) {
|
||||
for (i = 0; i < cell_addr; i++)
|
||||
temp = (temp << 32) | fdt32_to_cpu(*prop_addr++);
|
||||
*addr = temp;
|
||||
}
|
||||
temp = 0;
|
||||
|
||||
if (size) {
|
||||
for (i = 0; i < cell_size; i++)
|
||||
temp = (temp << 32) | fdt32_to_cpu(*prop_size++);
|
||||
*size = temp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_parse_uart8250(void *fdt, struct platform_uart_data *uart,
|
||||
const char *compatible)
|
||||
{
|
||||
int nodeoffset, len, rc;
|
||||
fdt32_t *val;
|
||||
unsigned long reg_addr, reg_size;
|
||||
|
||||
/**
|
||||
* TODO: We don't know how to handle multiple nodes with the same
|
||||
* compatible sring. Just return the first node for now.
|
||||
*/
|
||||
|
||||
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
||||
if (nodeoffset < 0)
|
||||
return nodeoffset;
|
||||
|
||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
||||
if (rc < 0 || !reg_addr || !reg_size)
|
||||
return SBI_ENODEV;
|
||||
uart->addr = reg_addr;
|
||||
|
||||
/**
|
||||
* UART address is mandaotry. clock-frequency and current-speed may not
|
||||
* be present. Don't return error.
|
||||
*/
|
||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "clock-frequency", &len);
|
||||
if (len > 0 && val)
|
||||
uart->freq = fdt32_to_cpu(*val);
|
||||
|
||||
val = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "current-speed", &len);
|
||||
if (len > 0 && val)
|
||||
uart->baud = fdt32_to_cpu(*val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_parse_plic(void *fdt, struct platform_plic_data *plic,
|
||||
const char *compatible)
|
||||
{
|
||||
int nodeoffset, len, rc;
|
||||
const fdt32_t *val;
|
||||
unsigned long reg_addr, reg_size;
|
||||
|
||||
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
||||
if (nodeoffset < 0)
|
||||
return nodeoffset;
|
||||
|
||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, ®_addr, ®_size);
|
||||
if (rc < 0 || !reg_addr || !reg_size)
|
||||
return SBI_ENODEV;
|
||||
plic->addr = reg_addr;
|
||||
|
||||
val = fdt_getprop(fdt, nodeoffset, "riscv,ndev", &len);
|
||||
if (len > 0)
|
||||
plic->num_src = fdt32_to_cpu(*val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fdt_parse_clint(void *fdt, unsigned long *clint_addr,
|
||||
const char *compatible)
|
||||
{
|
||||
int nodeoffset, rc;
|
||||
|
||||
nodeoffset = fdt_node_offset_by_compatible(fdt, -1, compatible);
|
||||
if (nodeoffset < 0)
|
||||
return nodeoffset;
|
||||
|
||||
rc = fdt_get_node_addr_size(fdt, nodeoffset, clint_addr, NULL);
|
||||
if (rc < 0 || !clint_addr)
|
||||
return SBI_ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user