loader/u-boot: Use FDT serial info to create uart
* drop my fdt tests * we have to call fdt parsing code *after* cpu_init (why?) * pass fdt pointer to all FDT support calls to avoid confusion once we get into the kernel land * look for PL011 compatible uart and use it * Add some saftey checks to serial putc code to avoid null* * fdt_node_check_compatible returns 0 on success not 1 * fdt_get_device_reg needs to add the SOC base to the result * fdt_get_device_reg might need to add the second range cell instead of reg?
This commit is contained in:
parent
3d02d66b03
commit
c6a4fee579
19
headers/private/kernel/platform/u-boot/fdt_serial.h
Normal file
19
headers/private/kernel/platform/u-boot/fdt_serial.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2012-2015, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors
|
||||
* Alexander von Gluck IV, kallisti5@unixzen.com
|
||||
*/
|
||||
#ifndef __FDT_SERIAL_H
|
||||
#define __FDT_SERIAL_H
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <arch/generic/debug_uart.h>
|
||||
|
||||
|
||||
DebugUART * debug_uart_from_fdt(const void *fdt);
|
||||
|
||||
|
||||
#endif /*__FDT_SERIAL_H*/
|
@ -13,11 +13,12 @@
|
||||
|
||||
|
||||
void dump_fdt(const void *fdt);
|
||||
status_t fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells);
|
||||
status_t fdt_get_cell_count(const void* fdt, int node,
|
||||
int32 &addressCells, int32 &sizeCells);
|
||||
|
||||
phys_addr_t fdt_get_device_reg(int node);
|
||||
phys_addr_t fdt_get_device_reg_byname(const char* name);
|
||||
phys_addr_t fdt_get_device_reg_byalias(const char* alias);
|
||||
phys_addr_t fdt_get_device_reg(const void* fdt, int node);
|
||||
phys_addr_t fdt_get_device_reg_byname(const void* fdt, const char* name);
|
||||
phys_addr_t fdt_get_device_reg_byalias(const void* fdt, const char* alias);
|
||||
|
||||
|
||||
#endif /*__FDT_SUPPORT_H*/
|
||||
|
@ -600,7 +600,7 @@ find_physical_memory_ranges(uint64 &total)
|
||||
|
||||
int32 regAddressCells = 1;
|
||||
int32 regSizeCells = 1;
|
||||
fdt_get_cell_count(node, regAddressCells, regSizeCells);
|
||||
fdt_get_cell_count(gFDT, node, regAddressCells, regSizeCells);
|
||||
|
||||
prop = fdt_getprop(gFDT, node, "reg", &len);
|
||||
if (prop == NULL) {
|
||||
@ -671,10 +671,6 @@ mmu_init(void)
|
||||
dprintf("total physical memory = %" B_PRId64 "MB\n", total / (1024 * 1024));
|
||||
}
|
||||
|
||||
// XXX: A simple test.
|
||||
fdt_get_device_reg_byname("/soc/gpio");
|
||||
fdt_get_device_reg_byalias("gpio");
|
||||
|
||||
// see if subpages are disabled
|
||||
if (mmu_read_C1() & (1 << 23))
|
||||
sSmallPageType = ARM_MMU_L2_TYPE_SMALLNEW;
|
||||
|
@ -2,17 +2,23 @@
|
||||
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2012, Alexander von Gluck, kallisti5@unixzen.com
|
||||
* Copyright 2012-2015, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
* Alexander von Gluck IV, kallisti5@unixzen.com
|
||||
*/
|
||||
|
||||
|
||||
#include "serial.h"
|
||||
|
||||
#include <debug_uart_8250.h>
|
||||
#include <arch/generic/debug_uart_8250.h>
|
||||
|
||||
#if defined(__ARM__)
|
||||
#include <arch_uart_pl011.h>
|
||||
#include <arch/arm/arch_uart_pl011.h>
|
||||
#endif
|
||||
|
||||
#include <board_config.h>
|
||||
#include <boot/platform.h>
|
||||
#include <arch/cpu.h>
|
||||
@ -26,8 +32,8 @@ extern "C" {
|
||||
#include <libfdt_env.h>
|
||||
};
|
||||
|
||||
#include "fdt_serial.h"
|
||||
|
||||
extern "C" DebugUART *debug_uart_from_fdt(const void *fdt);
|
||||
|
||||
DebugUART* gUART;
|
||||
|
||||
@ -39,6 +45,9 @@ static uint32 sBufferPosition;
|
||||
static void
|
||||
serial_putc(char c)
|
||||
{
|
||||
if (gUART == NULL || sSerialEnabled <= 0)
|
||||
return;
|
||||
|
||||
gUART->PutChar(c);
|
||||
}
|
||||
|
||||
@ -46,6 +55,9 @@ serial_putc(char c)
|
||||
extern "C" int
|
||||
serial_getc(bool wait)
|
||||
{
|
||||
if (gUART == NULL || sSerialEnabled <= 0)
|
||||
return 0;
|
||||
|
||||
return gUART->GetChar(wait);
|
||||
}
|
||||
|
||||
@ -112,16 +124,16 @@ serial_init(const void *fdt)
|
||||
// first try with hints from the FDT
|
||||
gUART = debug_uart_from_fdt(fdt);
|
||||
|
||||
#ifdef BOARD_UART_DEBUG
|
||||
// fallback to hardcoded board UART
|
||||
// fallback to known board UARTs
|
||||
#if defined(BOARD_UART_DEBUG) && defined(BOARD_UART_CLOCK)
|
||||
if (gUART == NULL) {
|
||||
#if defined(BOARD_UART_PL011)
|
||||
#ifdef BOARD_UART_PL011
|
||||
gUART = arch_get_uart_pl011(BOARD_UART_DEBUG, BOARD_UART_CLOCK);
|
||||
#else
|
||||
gUART = arch_get_uart_8250(BOARD_UART_DEBUG, BOARD_UART_CLOCK);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (gUART == NULL)
|
||||
return;
|
||||
|
@ -214,16 +214,19 @@ start_gen(int argc, const char **argv, struct image_header *uimage, void *fdt)
|
||||
gFDT = args.platform.fdt_data;
|
||||
}
|
||||
|
||||
// We have to cpu_init *before* calling FDT functions
|
||||
cpu_init();
|
||||
|
||||
#if defined(__ARM__)
|
||||
arch_mailbox_init();
|
||||
#endif
|
||||
serial_init(gFDT);
|
||||
|
||||
console_init();
|
||||
serial_init(gFDT);
|
||||
|
||||
// initialize the OpenFirmware wrapper
|
||||
of_init(NULL);
|
||||
|
||||
cpu_init();
|
||||
|
||||
// if we get passed an FDT, check /chosen for initrd and bootargs
|
||||
if (gFDT != NULL) {
|
||||
int node = fdt_path_offset(gFDT, "/chosen");
|
||||
|
@ -11,9 +11,7 @@
|
||||
#include <arch/arm/reg.h>
|
||||
#include <arch/generic/debug_uart.h>
|
||||
#include <arch/arm/arch_uart_pl011.h>
|
||||
//#include <board_config.h>
|
||||
#include <new>
|
||||
//#include <target/debugconfig.h>
|
||||
|
||||
|
||||
#define PL01x_DR 0x00 // Data read or written
|
||||
|
@ -1,17 +1,26 @@
|
||||
/*
|
||||
* Copyright 2012, François Revol, revol@free.fr.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* François Revol, revol@free.fr
|
||||
* Alexander von Gluck IV, kallisti5@unixzen.com
|
||||
*/
|
||||
|
||||
#include "fdt_serial.h"
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <ByteOrder.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <arch/generic/debug_uart.h>
|
||||
#include <arch/generic/debug_uart_8250.h>
|
||||
|
||||
#ifdef __ARM__
|
||||
#include <arch/arm/arch_uart_pl011.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <fdt.h>
|
||||
#include <libfdt.h>
|
||||
@ -21,14 +30,13 @@ extern "C" {
|
||||
#include "fdt_support.h"
|
||||
|
||||
|
||||
extern "C" DebugUART *debug_uart_from_fdt(const void *fdt);
|
||||
// If we dprintf before the UART is initalized there will be no output
|
||||
|
||||
|
||||
DebugUART *
|
||||
DebugUART*
|
||||
debug_uart_from_fdt(const void *fdt)
|
||||
{
|
||||
const char *name;
|
||||
//const char *type;
|
||||
int node;
|
||||
int len;
|
||||
phys_addr_t regs;
|
||||
@ -52,36 +60,45 @@ debug_uart_from_fdt(const void *fdt)
|
||||
return NULL;
|
||||
|
||||
node = fdt_path_offset(fdt, name);
|
||||
//dprintf("serial: using '%s', node %d\n", name, node);
|
||||
|
||||
if (node < 0)
|
||||
return NULL;
|
||||
|
||||
// determine the MMIO address
|
||||
regs = fdt_get_device_reg(node);
|
||||
regs = fdt_get_device_reg(fdt, node);
|
||||
|
||||
if (regs == 0)
|
||||
return NULL;
|
||||
|
||||
dprintf("serial: using '%s', node %d @ %" B_PRIxPHYSADDR "\n",
|
||||
name, node, regs);
|
||||
|
||||
// get the UART clock rate
|
||||
prop = fdt_getprop(fdt, node, "clock-frequency", &len);
|
||||
if (prop && len == 4) {
|
||||
clock = fdt32_to_cpu(*(uint32_t *)prop);
|
||||
//dprintf("serial: clock %ld\n", clock);
|
||||
dprintf("serial: clock %ld\n", clock);
|
||||
}
|
||||
|
||||
// get current speed (XXX: not yet passed over)
|
||||
prop = fdt_getprop(fdt, node, "current-speed", &len);
|
||||
if (prop && len == 4) {
|
||||
speed = fdt32_to_cpu(*(uint32_t *)prop);
|
||||
//dprintf("serial: speed %ld\n", speed);
|
||||
dprintf("serial: speed %ld\n", speed);
|
||||
}
|
||||
|
||||
if (fdt_node_check_compatible(fdt, node, "ns16550a") == 1
|
||||
|| fdt_node_check_compatible(fdt, node, "ns16550") == 1) {
|
||||
// fdt_node_check_compatible returns 0 on match.
|
||||
|
||||
if (fdt_node_check_compatible(fdt, node, "ns16550a") == 0
|
||||
|| fdt_node_check_compatible(fdt, node, "ns16550") == 0) {
|
||||
dprintf("serial: Found 8250 serial UART!\n");
|
||||
uart = arch_get_uart_8250(regs, clock);
|
||||
//dprintf("serial: using 8250\n");
|
||||
// XXX:assume speed is already set
|
||||
(void)speed;
|
||||
#ifdef __ARM__
|
||||
} else if (fdt_node_check_compatible(fdt, node, "arm,pl011") == 0
|
||||
|| fdt_node_check_compatible(fdt, node, "arm,primecell") == 0) {
|
||||
dprintf("serial: Found pl011 serial UART!\n");
|
||||
uart = arch_get_uart_pl011(regs, clock);
|
||||
#endif
|
||||
} else {
|
||||
// TODO: handle more UART types
|
||||
return NULL;
|
||||
@ -89,4 +106,3 @@ debug_uart_from_fdt(const void *fdt)
|
||||
|
||||
return uart;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ void dump_fdt(const void *fdt)
|
||||
|
||||
|
||||
static uint64
|
||||
fdt_get_range_offset(int32 node)
|
||||
fdt_get_range_offset(const void* fdt, int32 node)
|
||||
{
|
||||
// Obtain the offset of the device by searching
|
||||
// for the first ranges start in parents.
|
||||
@ -141,18 +141,18 @@ fdt_get_range_offset(int32 node)
|
||||
// It could be possible that there are multiple
|
||||
// offset ranges in several parents + children.
|
||||
// Lets hope that no system designer is that insane.
|
||||
int depth = fdt_node_depth(gFDT, node);
|
||||
int depth = fdt_node_depth(fdt, node);
|
||||
int32 examineNode = node;
|
||||
uint64 pathOffset = 0x0;
|
||||
|
||||
while (depth > 0) {
|
||||
int len;
|
||||
const void* prop;
|
||||
prop = fdt_getprop(gFDT, examineNode, "ranges", &len);
|
||||
prop = fdt_getprop(fdt, examineNode, "ranges", &len);
|
||||
if (prop) {
|
||||
int32 regAddressCells = 1;
|
||||
int32 regSizeCells = 1;
|
||||
fdt_get_cell_count(examineNode, regAddressCells, regSizeCells);
|
||||
fdt_get_cell_count(fdt, examineNode, regAddressCells, regSizeCells);
|
||||
|
||||
const uint32 *p = (const uint32 *)prop;
|
||||
// All we are interested in is the start offset
|
||||
@ -162,19 +162,20 @@ fdt_get_range_offset(int32 node)
|
||||
pathOffset = fdt32_to_cpu(*(uint32_t *)p);
|
||||
break;
|
||||
}
|
||||
int32 parentNode = fdt_parent_offset(gFDT, examineNode);
|
||||
depth = fdt_node_depth(gFDT, parentNode);
|
||||
int32 parentNode = fdt_parent_offset(fdt, examineNode);
|
||||
depth = fdt_node_depth(fdt, parentNode);
|
||||
examineNode = parentNode;
|
||||
}
|
||||
|
||||
dprintf("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset);
|
||||
TRACE("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset);
|
||||
|
||||
return pathOffset;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells)
|
||||
fdt_get_cell_count(const void* fdt, int node,
|
||||
int32 &addressCells, int32 &sizeCells)
|
||||
{
|
||||
// It would be nice if libfdt provided this.
|
||||
|
||||
@ -182,7 +183,7 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells)
|
||||
// #address-cells and #size-cells matches the number of 32-bit 'cells'
|
||||
// representing the length of the base address and size fields
|
||||
|
||||
// TODO: assert !gFDT || !pathOffset?
|
||||
// TODO: assert !fdt || !pathOffset?
|
||||
|
||||
int len;
|
||||
if (node < 0) {
|
||||
@ -191,10 +192,10 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells)
|
||||
}
|
||||
|
||||
const void *prop;
|
||||
prop = fdt_getprop(gFDT, node, "#address-cells", &len);
|
||||
prop = fdt_getprop(fdt, node, "#address-cells", &len);
|
||||
if (prop && len == sizeof(uint32))
|
||||
addressCells = fdt32_to_cpu(*(uint32_t *)prop);
|
||||
prop = fdt_getprop(gFDT, node, "#size-cells", &len);
|
||||
prop = fdt_getprop(fdt, node, "#size-cells", &len);
|
||||
if (prop && len == sizeof(uint32))
|
||||
sizeCells = fdt32_to_cpu(*(uint32_t *)prop);
|
||||
|
||||
@ -211,18 +212,18 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells)
|
||||
|
||||
|
||||
phys_addr_t
|
||||
fdt_get_device_reg(int node)
|
||||
fdt_get_device_reg(const void* fdt, int node)
|
||||
{
|
||||
const void *prop;
|
||||
int len;
|
||||
|
||||
int32 regAddressCells = 1;
|
||||
int32 regSizeCells = 1;
|
||||
fdt_get_cell_count(node, regAddressCells, regSizeCells);
|
||||
fdt_get_cell_count(fdt, node, regAddressCells, regSizeCells);
|
||||
|
||||
// TODO: check for virtual-reg, and don't -= fdt_get_range_offset?
|
||||
|
||||
prop = fdt_getprop(gFDT, node, "reg", &len);
|
||||
prop = fdt_getprop(fdt, node, "reg", &len);
|
||||
|
||||
if (!prop) {
|
||||
dprintf("%s: reg property not found on node in FDT!\n", __func__);
|
||||
@ -231,41 +232,55 @@ fdt_get_device_reg(int node)
|
||||
|
||||
const uint32 *p = (const uint32 *)prop;
|
||||
uint64 baseDevice = 0x0;
|
||||
uint64 size = 0x0;
|
||||
|
||||
// soc base address cells
|
||||
if (regAddressCells == 2)
|
||||
baseDevice = fdt64_to_cpu(*(uint64_t *)p);
|
||||
else
|
||||
baseDevice = fdt32_to_cpu(*(uint32_t *)p);
|
||||
p += regAddressCells;
|
||||
//p += regAddressCells;
|
||||
|
||||
// size (atm, we don't pass this back :-\)
|
||||
if (regSizeCells == 2)
|
||||
size = fdt64_to_cpu(*(uint64_t *)p);
|
||||
else if (regSizeCells == 1)
|
||||
size = fdt32_to_cpu(*(uint32_t *)p);
|
||||
// we can have 0 size cells
|
||||
//p += regSizeCells;
|
||||
// subtract the range offset (X) on the parent node (ranges = X Y Z)
|
||||
baseDevice -= fdt_get_range_offset(fdt, node);
|
||||
|
||||
baseDevice -= fdt_get_range_offset(node);
|
||||
// find the start of the parent (X) and add to base (regs = X Y)
|
||||
int parentNode = fdt_parent_offset(fdt, node);
|
||||
if (!parentNode)
|
||||
return baseDevice;
|
||||
|
||||
fdt_get_cell_count(fdt, parentNode, regAddressCells, regSizeCells);
|
||||
prop = fdt_getprop(fdt, parentNode, "reg", &len);
|
||||
|
||||
if (!prop)
|
||||
return baseDevice;
|
||||
p = (const uint32 *)prop;
|
||||
|
||||
uint64 parentReg = 0x0;
|
||||
// soc base address cells
|
||||
if (regAddressCells == 2)
|
||||
parentReg = fdt64_to_cpu(*(uint64_t *)p);
|
||||
else
|
||||
parentReg = fdt32_to_cpu(*(uint32_t *)p);
|
||||
|
||||
// add parent reg base to property
|
||||
baseDevice += parentReg;
|
||||
|
||||
return baseDevice;
|
||||
}
|
||||
|
||||
|
||||
phys_addr_t
|
||||
fdt_get_device_reg_byname(const char* name)
|
||||
fdt_get_device_reg_byname(const void* fdt, const char* name)
|
||||
{
|
||||
// Find device in FDT
|
||||
int node = fdt_path_offset(gFDT, name);
|
||||
int node = fdt_path_offset(fdt, name);
|
||||
|
||||
if (node < 0) {
|
||||
dprintf("%s: %s not found in FDT!\n", __func__, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t deviceReg = fdt_get_device_reg(node);
|
||||
addr_t deviceReg = fdt_get_device_reg(fdt, node);
|
||||
if (deviceReg > 0) {
|
||||
//TRACE("%s: %s found @ 0x%" B_PRIx64 " , size: 0x%" B_PRIx64 "\n",
|
||||
// __func__, name, deviceReg, size);
|
||||
@ -280,15 +295,15 @@ fdt_get_device_reg_byname(const char* name)
|
||||
|
||||
|
||||
phys_addr_t
|
||||
fdt_get_device_reg_byalias(const char* alias)
|
||||
fdt_get_device_reg_byalias(const void* fdt, const char* alias)
|
||||
{
|
||||
const char* name = fdt_get_alias(gFDT, alias);
|
||||
const char* name = fdt_get_alias(fdt, alias);
|
||||
|
||||
if (name == NULL) {
|
||||
dprintf("%s: No alias found for %s!\n", __func__, alias);
|
||||
return 0;
|
||||
}
|
||||
|
||||
phys_addr_t deviceReg = fdt_get_device_reg_byname(name);
|
||||
phys_addr_t deviceReg = fdt_get_device_reg_byname(fdt, name);
|
||||
return deviceReg;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user