mirror of
				https://github.com/riscv-software-src/opensbi
				synced 2025-11-04 14:00:31 +00:00 
			
		
		
		
	A final check of all DT nodes does not necessarily find a match, so SBI_ENODEV needs to be returned. Optimize removal of current_driver. Signed-off-by: Xiang W <wxjstz@126.com> Reviewed-by: Anup Patel <anup@brainfault.org>
		
			
				
	
	
		
			83 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			83 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 *fdt_serial_drivers[];
 | 
						|
extern unsigned long fdt_serial_drivers_size;
 | 
						|
 | 
						|
int fdt_serial_init(void)
 | 
						|
{
 | 
						|
	const void *prop;
 | 
						|
	struct fdt_serial *drv;
 | 
						|
	const struct fdt_match *match;
 | 
						|
	int pos, noff = -1, len, coff, rc;
 | 
						|
	void *fdt = fdt_get_address();
 | 
						|
 | 
						|
	/* 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);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* First check DT node pointed by stdout-path */
 | 
						|
	for (pos = 0; pos < fdt_serial_drivers_size && -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; pos < fdt_serial_drivers_size; pos++) {
 | 
						|
		drv = fdt_serial_drivers[pos];
 | 
						|
 | 
						|
		noff = fdt_find_match(fdt, -1, drv->match_table, &match);
 | 
						|
		if (noff < 0)
 | 
						|
			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;
 | 
						|
}
 |