Merge branch '2021-05-13-extension-board-detection-and-DT-overlay-application'
- Improve support for various forms of extension boards and add DT overlay application support.
This commit is contained in:
		
						commit
						530c8d4af2
					
				| 
						 | 
					@ -121,6 +121,7 @@ config SANDBOX
 | 
				
			||||||
	select SUPPORT_OF_CONTROL
 | 
						select SUPPORT_OF_CONTROL
 | 
				
			||||||
	select SYSRESET_CMD_POWEROFF
 | 
						select SYSRESET_CMD_POWEROFF
 | 
				
			||||||
	select IRQ
 | 
						select IRQ
 | 
				
			||||||
 | 
						select SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
	imply BITREVERSE
 | 
						imply BITREVERSE
 | 
				
			||||||
	select BLOBLIST
 | 
						select BLOBLIST
 | 
				
			||||||
	imply CMD_DM
 | 
						imply CMD_DM
 | 
				
			||||||
| 
						 | 
					@ -165,6 +166,7 @@ config SANDBOX
 | 
				
			||||||
	imply BOOTARGS_SUBST
 | 
						imply BOOTARGS_SUBST
 | 
				
			||||||
	imply PHY_FIXED
 | 
						imply PHY_FIXED
 | 
				
			||||||
	imply DM_DSA
 | 
						imply DM_DSA
 | 
				
			||||||
 | 
						imply CMD_EXTENSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config SH
 | 
					config SH
 | 
				
			||||||
	bool "SuperH architecture"
 | 
						bool "SuperH architecture"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@ config TARGET_AM335X_EVM
 | 
				
			||||||
	select DM_GPIO
 | 
						select DM_GPIO
 | 
				
			||||||
	select DM_SERIAL
 | 
						select DM_SERIAL
 | 
				
			||||||
	select TI_I2C_BOARD_DETECT
 | 
						select TI_I2C_BOARD_DETECT
 | 
				
			||||||
 | 
						select SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
	imply CMD_DM
 | 
						imply CMD_DM
 | 
				
			||||||
	imply SPL_DM
 | 
						imply SPL_DM
 | 
				
			||||||
	imply SPL_DM_SEQ_ALIAS
 | 
						imply SPL_DM_SEQ_ALIAS
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,6 +220,7 @@ void enable_basic_clocks(void)
 | 
				
			||||||
		&cmper->gpio2clkctrl,
 | 
							&cmper->gpio2clkctrl,
 | 
				
			||||||
		&cmper->gpio3clkctrl,
 | 
							&cmper->gpio3clkctrl,
 | 
				
			||||||
		&cmper->i2c1clkctrl,
 | 
							&cmper->i2c1clkctrl,
 | 
				
			||||||
 | 
							&cmper->i2c2clkctrl,
 | 
				
			||||||
		&cmper->cpgmac0clkctrl,
 | 
							&cmper->cpgmac0clkctrl,
 | 
				
			||||||
		&cmper->spi0clkctrl,
 | 
							&cmper->spi0clkctrl,
 | 
				
			||||||
		&cmrtc->rtcclkctrl,
 | 
							&cmrtc->rtcclkctrl,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@ config TARGET_AM57XX_EVM
 | 
				
			||||||
	select CMD_DDR3
 | 
						select CMD_DDR3
 | 
				
			||||||
	select DRA7XX
 | 
						select DRA7XX
 | 
				
			||||||
	select TI_I2C_BOARD_DETECT
 | 
						select TI_I2C_BOARD_DETECT
 | 
				
			||||||
 | 
						select SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
	imply DM_THERMAL
 | 
						imply DM_THERMAL
 | 
				
			||||||
	imply SCSI
 | 
						imply SCSI
 | 
				
			||||||
	imply SPL_THERMAL
 | 
						imply SPL_THERMAL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1089,3 +1089,12 @@ config BLUETOOTH_DT_DEVICE_FIXUP
 | 
				
			||||||
	  flipped elsewise.
 | 
						  flipped elsewise.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config CHIP_DIP_SCAN
 | 
				
			||||||
 | 
						bool "Enable DIPs detection for CHIP board"
 | 
				
			||||||
 | 
						select SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
 | 
						select W1
 | 
				
			||||||
 | 
						select W1_GPIO
 | 
				
			||||||
 | 
						select W1_EEPROM
 | 
				
			||||||
 | 
						select W1_EEPROM_DS24XXX
 | 
				
			||||||
 | 
						select CMD_EXTENSION
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ else
 | 
				
			||||||
dtb-$(CONFIG_SANDBOX) += sandbox.dtb
 | 
					dtb-$(CONFIG_SANDBOX) += sandbox.dtb
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
dtb-$(CONFIG_UT_DM) += test.dtb
 | 
					dtb-$(CONFIG_UT_DM) += test.dtb
 | 
				
			||||||
 | 
					dtb-$(CONFIG_CMD_EXTENSION) += overlay0.dtbo overlay1.dtbo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
targets += $(dtb-y)
 | 
					targets += $(dtb-y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					/dts-v1/;
 | 
				
			||||||
 | 
					/plugin/;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					&{/buttons} {
 | 
				
			||||||
 | 
						btn3 {
 | 
				
			||||||
 | 
							gpios = <&gpio_a 5 0>;
 | 
				
			||||||
 | 
							label = "button3";
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					/dts-v1/;
 | 
				
			||||||
 | 
					/plugin/;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					&{/buttons} {
 | 
				
			||||||
 | 
						btn4 {
 | 
				
			||||||
 | 
							gpios = <&gpio_a 5 0>;
 | 
				
			||||||
 | 
							label = "button4";
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,9 @@
 | 
				
			||||||
#include <asm/global_data.h>
 | 
					#include <asm/global_data.h>
 | 
				
			||||||
#include <asm/test.h>
 | 
					#include <asm/test.h>
 | 
				
			||||||
#include <asm/u-boot-sandbox.h>
 | 
					#include <asm/u-boot-sandbox.h>
 | 
				
			||||||
 | 
					#include <malloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <extension_board.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Pointer to initial global data area
 | 
					 * Pointer to initial global data area
 | 
				
			||||||
| 
						 | 
					@ -79,6 +82,26 @@ int ft_board_setup(void *fdt, struct bd_info *bd)
 | 
				
			||||||
	return fdt_add_mem_rsv(fdt, 0x00d02000, 0x4000);
 | 
						return fdt_add_mem_rsv(fdt, 0x00d02000, 0x4000);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_CMD_EXTENSION
 | 
				
			||||||
 | 
					int extension_board_scan(struct list_head *extension_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct extension *extension;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < 2; i++) {
 | 
				
			||||||
 | 
							extension = calloc(1, sizeof(struct extension));
 | 
				
			||||||
 | 
							snprintf(extension->overlay, sizeof(extension->overlay), "overlay%d.dtbo", i);
 | 
				
			||||||
 | 
							snprintf(extension->name, sizeof(extension->name), "extension board %d", i);
 | 
				
			||||||
 | 
							snprintf(extension->owner, sizeof(extension->owner), "sandbox");
 | 
				
			||||||
 | 
							snprintf(extension->version, sizeof(extension->version), "1.1");
 | 
				
			||||||
 | 
							snprintf(extension->other, sizeof(extension->other), "Fictionnal extension board");
 | 
				
			||||||
 | 
							list_add_tail(&extension->list, extension_list);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_BOARD_LATE_INIT
 | 
					#ifdef CONFIG_BOARD_LATE_INIT
 | 
				
			||||||
int board_late_init(void)
 | 
					int board_late_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,3 +11,4 @@ obj-$(CONFIG_SUN7I_GMAC)	+= gmac.o
 | 
				
			||||||
obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i_auto.o
 | 
					obj-$(CONFIG_MACH_SUN4I)	+= dram_sun4i_auto.o
 | 
				
			||||||
obj-$(CONFIG_MACH_SUN5I)	+= dram_sun5i_auto.o
 | 
					obj-$(CONFIG_MACH_SUN5I)	+= dram_sun5i_auto.o
 | 
				
			||||||
obj-$(CONFIG_MACH_SUN7I)	+= dram_sun5i_auto.o
 | 
					obj-$(CONFIG_MACH_SUN7I)	+= dram_sun5i_auto.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_CHIP_DIP_SCAN)	+= chip.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) Copyright 2021
 | 
				
			||||||
 | 
					 * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					 * Based on initial code from Maxime Ripard
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <common.h>
 | 
				
			||||||
 | 
					#include <malloc.h>
 | 
				
			||||||
 | 
					#include <dm.h>
 | 
				
			||||||
 | 
					#include <w1.h>
 | 
				
			||||||
 | 
					#include <w1-eeprom.h>
 | 
				
			||||||
 | 
					#include <dm/device-internal.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/arch/gpio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <extension_board.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_w1_device(b, d) \
 | 
				
			||||||
 | 
						for (device_find_first_child(b, d); *d; device_find_next_child(d))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define dip_convert(field)						\
 | 
				
			||||||
 | 
						(								\
 | 
				
			||||||
 | 
							(sizeof(field) == 1) ? field :				\
 | 
				
			||||||
 | 
							(sizeof(field) == 2) ? be16_to_cpu(field) :		\
 | 
				
			||||||
 | 
							(sizeof(field) == 4) ? be32_to_cpu(field) :		\
 | 
				
			||||||
 | 
							-1							\
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DIP_MAGIC	0x50494843	/* CHIP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct dip_w1_header {
 | 
				
			||||||
 | 
						u32     magic;                  /* CHIP */
 | 
				
			||||||
 | 
						u8      version;                /* spec version */
 | 
				
			||||||
 | 
						u32     vendor_id;
 | 
				
			||||||
 | 
						u16     product_id;
 | 
				
			||||||
 | 
						u8      product_version;
 | 
				
			||||||
 | 
						char    vendor_name[32];
 | 
				
			||||||
 | 
						char    product_name[32];
 | 
				
			||||||
 | 
						u8      rsvd[36];               /* rsvd for future spec versions */
 | 
				
			||||||
 | 
						u8      data[16];               /* user data, per-dip specific */
 | 
				
			||||||
 | 
					} __packed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int extension_board_scan(struct list_head *extension_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct extension *dip;
 | 
				
			||||||
 | 
						struct dip_w1_header w1_header;
 | 
				
			||||||
 | 
						struct udevice *bus, *dev;
 | 
				
			||||||
 | 
						u32 vid;
 | 
				
			||||||
 | 
						u16 pid;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int num_dip = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sunxi_gpio_set_pull(SUNXI_GPD(2), SUNXI_GPIO_PULL_UP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = w1_get_bus(0, &bus);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							printf("one wire interface not found\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_w1_device(bus, &dev) {
 | 
				
			||||||
 | 
							if (w1_get_device_family(dev) != W1_FAMILY_DS2431)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = device_probe(dev);
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								printf("Couldn't probe device %s: error %d",
 | 
				
			||||||
 | 
								       dev->name, ret);
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							w1_eeprom_read_buf(dev, 0, (u8 *)&w1_header, sizeof(w1_header));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (w1_header.magic != DIP_MAGIC)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vid = dip_convert(w1_header.vendor_id);
 | 
				
			||||||
 | 
							pid = dip_convert(w1_header.product_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							printf("DIP: %s (0x%x) from %s (0x%x)\n",
 | 
				
			||||||
 | 
							       w1_header.product_name, pid,
 | 
				
			||||||
 | 
							       w1_header.vendor_name, vid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dip = calloc(1, sizeof(struct extension));
 | 
				
			||||||
 | 
							if (!dip) {
 | 
				
			||||||
 | 
								printf("Error in memory allocation\n");
 | 
				
			||||||
 | 
								return num_dip;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snprintf(dip->overlay, sizeof(dip->overlay), "dip-%x-%x.dtbo",
 | 
				
			||||||
 | 
								 vid, pid);
 | 
				
			||||||
 | 
							strncpy(dip->name, w1_header.product_name, 32);
 | 
				
			||||||
 | 
							strncpy(dip->owner, w1_header.vendor_name, 32);
 | 
				
			||||||
 | 
							list_add_tail(&dip->list, extension_list);
 | 
				
			||||||
 | 
							num_dip++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return num_dip;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,7 @@
 | 
				
			||||||
#include <env_internal.h>
 | 
					#include <env_internal.h>
 | 
				
			||||||
#include <watchdog.h>
 | 
					#include <watchdog.h>
 | 
				
			||||||
#include "../common/board_detect.h"
 | 
					#include "../common/board_detect.h"
 | 
				
			||||||
 | 
					#include "../common/cape_detect.h"
 | 
				
			||||||
#include "board.h"
 | 
					#include "board.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECLARE_GLOBAL_DATA_PTR;
 | 
					DECLARE_GLOBAL_DATA_PTR;
 | 
				
			||||||
| 
						 | 
					@ -77,8 +78,10 @@ static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
 | 
				
			||||||
void do_board_detect(void)
 | 
					void do_board_detect(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	enable_i2c0_pin_mux();
 | 
						enable_i2c0_pin_mux();
 | 
				
			||||||
 | 
						enable_i2c2_pin_mux();
 | 
				
			||||||
#if !CONFIG_IS_ENABLED(DM_I2C)
 | 
					#if !CONFIG_IS_ENABLED(DM_I2C)
 | 
				
			||||||
	i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
 | 
						i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
 | 
				
			||||||
 | 
						i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED2, CONFIG_SYS_OMAP24_I2C_SLAVE2);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
 | 
						if (ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
 | 
				
			||||||
				 CONFIG_EEPROM_CHIP_ADDRESS))
 | 
									 CONFIG_EEPROM_CHIP_ADDRESS))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,5 +93,6 @@ void enable_uart3_pin_mux(void);
 | 
				
			||||||
void enable_uart4_pin_mux(void);
 | 
					void enable_uart4_pin_mux(void);
 | 
				
			||||||
void enable_uart5_pin_mux(void);
 | 
					void enable_uart5_pin_mux(void);
 | 
				
			||||||
void enable_i2c0_pin_mux(void);
 | 
					void enable_i2c0_pin_mux(void);
 | 
				
			||||||
 | 
					void enable_i2c2_pin_mux(void);
 | 
				
			||||||
void enable_board_pin_mux(void);
 | 
					void enable_board_pin_mux(void);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,6 +124,14 @@ static struct module_pin_mux i2c1_pin_mux[] = {
 | 
				
			||||||
	{-1},
 | 
						{-1},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct module_pin_mux i2c2_pin_mux[] = {
 | 
				
			||||||
 | 
						{OFFSET(uart1_ctsn), (MODE(3) | RXACTIVE |
 | 
				
			||||||
 | 
								PULLUDEN | PULLUP_EN | SLEWCTRL)},	/* I2C_DATA */
 | 
				
			||||||
 | 
						{OFFSET(uart1_rtsn), (MODE(3) | RXACTIVE |
 | 
				
			||||||
 | 
								PULLUDEN | PULLUP_EN | SLEWCTRL)},	/* I2C_SCLK */
 | 
				
			||||||
 | 
						{-1},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct module_pin_mux spi0_pin_mux[] = {
 | 
					static struct module_pin_mux spi0_pin_mux[] = {
 | 
				
			||||||
	{OFFSET(spi0_sclk), (MODE(0) | RXACTIVE | PULLUDEN)},	/* SPI0_SCLK */
 | 
						{OFFSET(spi0_sclk), (MODE(0) | RXACTIVE | PULLUDEN)},	/* SPI0_SCLK */
 | 
				
			||||||
	{OFFSET(spi0_d0), (MODE(0) | RXACTIVE |
 | 
						{OFFSET(spi0_d0), (MODE(0) | RXACTIVE |
 | 
				
			||||||
| 
						 | 
					@ -308,6 +316,11 @@ void enable_i2c0_pin_mux(void)
 | 
				
			||||||
	configure_module_pin_mux(i2c0_pin_mux);
 | 
						configure_module_pin_mux(i2c0_pin_mux);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enable_i2c2_pin_mux(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						configure_module_pin_mux(i2c2_pin_mux);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * The AM335x GP EVM, if daughter card(s) are connected, can have 8
 | 
					 * The AM335x GP EVM, if daughter card(s) are connected, can have 8
 | 
				
			||||||
 * different profiles.  These profiles determine what peripherals are
 | 
					 * different profiles.  These profiles determine what peripherals are
 | 
				
			||||||
| 
						 | 
					@ -367,6 +380,7 @@ void enable_board_pin_mux(void)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
		configure_module_pin_mux(mmc1_pin_mux);
 | 
							configure_module_pin_mux(mmc1_pin_mux);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
							configure_module_pin_mux(i2c2_pin_mux);
 | 
				
			||||||
	} else if (board_is_gp_evm()) {
 | 
						} else if (board_is_gp_evm()) {
 | 
				
			||||||
		/* General Purpose EVM */
 | 
							/* General Purpose EVM */
 | 
				
			||||||
		unsigned short profile = detect_daughter_board_profile();
 | 
							unsigned short profile = detect_daughter_board_profile();
 | 
				
			||||||
| 
						 | 
					@ -411,6 +425,7 @@ void enable_board_pin_mux(void)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
		configure_module_pin_mux(mmc1_pin_mux);
 | 
							configure_module_pin_mux(mmc1_pin_mux);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
							configure_module_pin_mux(i2c2_pin_mux);
 | 
				
			||||||
	} else if (board_is_pb()) {
 | 
						} else if (board_is_pb()) {
 | 
				
			||||||
		configure_module_pin_mux(mii1_pin_mux);
 | 
							configure_module_pin_mux(mii1_pin_mux);
 | 
				
			||||||
		configure_module_pin_mux(mmc0_pin_mux);
 | 
							configure_module_pin_mux(mmc0_pin_mux);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
#include <hang.h>
 | 
					#include <hang.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "../common/board_detect.h"
 | 
					#include "../common/board_detect.h"
 | 
				
			||||||
 | 
					#include "../common/cape_detect.h"
 | 
				
			||||||
#include "mux_data.h"
 | 
					#include "mux_data.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SUPPORT_EMMC_BOOT
 | 
					#ifdef CONFIG_SUPPORT_EMMC_BOOT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,12 @@ config EEPROM_CHIP_ADDRESS
 | 
				
			||||||
	default 0x50
 | 
						default 0x50
 | 
				
			||||||
	depends on TI_I2C_BOARD_DETECT
 | 
						depends on TI_I2C_BOARD_DETECT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config CAPE_EEPROM_BUS_NUM
 | 
				
			||||||
 | 
						int "Cape EEPROM's I2C bus address"
 | 
				
			||||||
 | 
						range 0 8
 | 
				
			||||||
 | 
						default 2
 | 
				
			||||||
 | 
						depends on CMD_EXTENSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config TI_COMMON_CMD_OPTIONS
 | 
					config TI_COMMON_CMD_OPTIONS
 | 
				
			||||||
	bool "Enable cmd options on TI platforms"
 | 
						bool "Enable cmd options on TI platforms"
 | 
				
			||||||
	imply CMD_ASKENV
 | 
						imply CMD_ASKENV
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,3 +2,4 @@
 | 
				
			||||||
# Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
 | 
					# Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-${CONFIG_TI_I2C_BOARD_DETECT} += board_detect.o
 | 
					obj-${CONFIG_TI_I2C_BOARD_DETECT} += board_detect.o
 | 
				
			||||||
 | 
					obj-${CONFIG_CMD_EXTENSION} += cape_detect.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,96 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) Copyright 2021
 | 
				
			||||||
 | 
					 * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <common.h>
 | 
				
			||||||
 | 
					#include <malloc.h>
 | 
				
			||||||
 | 
					#include <i2c.h>
 | 
				
			||||||
 | 
					#include <extension_board.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "cape_detect.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sanitize_field(char *text, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *c = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (c = text; c < text + (int)size; c++) {
 | 
				
			||||||
 | 
							if (*c == 0xFF)
 | 
				
			||||||
 | 
								*c = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int extension_board_scan(struct list_head *extension_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct extension *cape;
 | 
				
			||||||
 | 
						struct am335x_cape_eeprom_id eeprom_header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int num_capes = 0;
 | 
				
			||||||
 | 
						int ret, i;
 | 
				
			||||||
 | 
						struct udevice *dev;
 | 
				
			||||||
 | 
						unsigned char addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char process_cape_part_number[17] = {'0'};
 | 
				
			||||||
 | 
						char process_cape_version[5] = {'0'};
 | 
				
			||||||
 | 
						uint8_t cursor = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (addr = CAPE_EEPROM_FIRST_ADDR; addr <= CAPE_EEPROM_LAST_ADDR; addr++) {
 | 
				
			||||||
 | 
							ret = i2c_get_chip_for_busnum(CONFIG_CAPE_EEPROM_BUS_NUM, addr, 1, &dev);
 | 
				
			||||||
 | 
							if (ret)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Move the read cursor to the beginning of the EEPROM */
 | 
				
			||||||
 | 
							dm_i2c_write(dev, 0, &cursor, 1);
 | 
				
			||||||
 | 
							ret = dm_i2c_read(dev, 0, (uint8_t *)&eeprom_header,
 | 
				
			||||||
 | 
									  sizeof(struct am335x_cape_eeprom_id));
 | 
				
			||||||
 | 
							if (ret) {
 | 
				
			||||||
 | 
								printf("Cannot read i2c EEPROM\n");
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (eeprom_header.header != CAPE_MAGIC)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sanitize_field(eeprom_header.board_name, sizeof(eeprom_header.board_name));
 | 
				
			||||||
 | 
							sanitize_field(eeprom_header.version, sizeof(eeprom_header.version));
 | 
				
			||||||
 | 
							sanitize_field(eeprom_header.manufacturer, sizeof(eeprom_header.manufacturer));
 | 
				
			||||||
 | 
							sanitize_field(eeprom_header.part_number, sizeof(eeprom_header.part_number));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Process cape part_number */
 | 
				
			||||||
 | 
							memset(process_cape_part_number, 0, sizeof(process_cape_part_number));
 | 
				
			||||||
 | 
							strncpy(process_cape_part_number, eeprom_header.part_number, 16);
 | 
				
			||||||
 | 
							/* Some capes end with '.' */
 | 
				
			||||||
 | 
							for (i = 15; i >= 0; i--) {
 | 
				
			||||||
 | 
								if (process_cape_part_number[i] == '.')
 | 
				
			||||||
 | 
									process_cape_part_number[i] = '\0';
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Process cape version */
 | 
				
			||||||
 | 
							memset(process_cape_version, 0, sizeof(process_cape_version));
 | 
				
			||||||
 | 
							strncpy(process_cape_version, eeprom_header.version, 4);
 | 
				
			||||||
 | 
							for (i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
								if (process_cape_version[i] == 0)
 | 
				
			||||||
 | 
									process_cape_version[i] = '0';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							printf("BeagleBone Cape: %s (0x%x)\n", eeprom_header.board_name, addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cape = calloc(1, sizeof(struct extension));
 | 
				
			||||||
 | 
							if (!cape) {
 | 
				
			||||||
 | 
								printf("Error in memory allocation\n");
 | 
				
			||||||
 | 
								return num_capes;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snprintf(cape->overlay, sizeof(cape->overlay), "%s-%s.dtbo",
 | 
				
			||||||
 | 
								 process_cape_part_number, process_cape_version);
 | 
				
			||||||
 | 
							strncpy(cape->name, eeprom_header.board_name, 32);
 | 
				
			||||||
 | 
							strncpy(cape->version, process_cape_version, 4);
 | 
				
			||||||
 | 
							strncpy(cape->owner, eeprom_header.manufacturer, 16);
 | 
				
			||||||
 | 
							list_add_tail(&cape->list, extension_list);
 | 
				
			||||||
 | 
							num_capes++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return num_capes;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0+ */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) Copyright 2021
 | 
				
			||||||
 | 
					 * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __CAPE_DETECT_H
 | 
				
			||||||
 | 
					#define __CAPE_DETECT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct am335x_cape_eeprom_id {
 | 
				
			||||||
 | 
						unsigned int header;
 | 
				
			||||||
 | 
						char eeprom_rev[2];
 | 
				
			||||||
 | 
						char board_name[32];
 | 
				
			||||||
 | 
						char version[4];
 | 
				
			||||||
 | 
						char manufacturer[16];
 | 
				
			||||||
 | 
						char part_number[16];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAPE_EEPROM_FIRST_ADDR	0x54
 | 
				
			||||||
 | 
					#define CAPE_EEPROM_LAST_ADDR	0x57
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAPE_EEPROM_ADDR_LEN 0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CAPE_MAGIC 0xEE3355AA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int extension_board_scan(struct list_head *extension_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __CAPE_DETECT_H */
 | 
				
			||||||
							
								
								
									
										12
									
								
								cmd/Kconfig
								
								
								
								
							
							
						
						
									
										12
									
								
								cmd/Kconfig
								
								
								
								
							| 
						 | 
					@ -332,6 +332,18 @@ config CMD_FDT
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Do FDT related setup before booting into the Operating System.
 | 
						  Do FDT related setup before booting into the Operating System.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
 | 
						bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config CMD_EXTENSION
 | 
				
			||||||
 | 
						bool "Extension board management command"
 | 
				
			||||||
 | 
						select CMD_FDT
 | 
				
			||||||
 | 
						depends on SUPPORT_EXTENSION_SCAN
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Enables the "extension" command, which allows to detect
 | 
				
			||||||
 | 
						  extension boards connected to the system, and apply
 | 
				
			||||||
 | 
						  corresponding Device Tree overlays.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config CMD_GO
 | 
					config CMD_GO
 | 
				
			||||||
	bool "go"
 | 
						bool "go"
 | 
				
			||||||
	default y
 | 
						default y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,6 +54,7 @@ obj-$(CONFIG_CMD_DIAG) += diag.o
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
obj-$(CONFIG_CMD_ADTIMG) += adtimg.o
 | 
					obj-$(CONFIG_CMD_ADTIMG) += adtimg.o
 | 
				
			||||||
obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o
 | 
					obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_CMD_EXTENSION) += extension_board.o
 | 
				
			||||||
obj-$(CONFIG_CMD_ECHO) += echo.o
 | 
					obj-$(CONFIG_CMD_ECHO) += echo.o
 | 
				
			||||||
obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
 | 
					obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
 | 
				
			||||||
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
 | 
					obj-$(CONFIG_CMD_EEPROM) += eeprom.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,167 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) Copyright 2021
 | 
				
			||||||
 | 
					 * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <common.h>
 | 
				
			||||||
 | 
					#include <command.h>
 | 
				
			||||||
 | 
					#include <malloc.h>
 | 
				
			||||||
 | 
					#include <extension_board.h>
 | 
				
			||||||
 | 
					#include <mapmem.h>
 | 
				
			||||||
 | 
					#include <linux/libfdt.h>
 | 
				
			||||||
 | 
					#include <fdt_support.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static LIST_HEAD(extension_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int extension_apply(struct extension *extension)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char *overlay_cmd;
 | 
				
			||||||
 | 
						ulong extrasize, overlay_addr;
 | 
				
			||||||
 | 
						struct fdt_header *blob;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!working_fdt) {
 | 
				
			||||||
 | 
							printf("No FDT memory address configured. Please configure\n"
 | 
				
			||||||
 | 
							       "the FDT address via \"fdt addr <address>\" command.\n");
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						overlay_cmd = env_get("extension_overlay_cmd");
 | 
				
			||||||
 | 
						if (!overlay_cmd) {
 | 
				
			||||||
 | 
							printf("Environment extension_overlay_cmd is missing\n");
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						overlay_addr = env_get_hex("extension_overlay_addr", 0);
 | 
				
			||||||
 | 
						if (!overlay_addr) {
 | 
				
			||||||
 | 
							printf("Environment extension_overlay_addr is missing\n");
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						env_set("extension_overlay_name", extension->overlay);
 | 
				
			||||||
 | 
						if (run_command(overlay_cmd, 0) != 0)
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						extrasize = env_get_hex("filesize", 0);
 | 
				
			||||||
 | 
						if (!extrasize)
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fdt_shrink_to_minimum(working_fdt, extrasize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						blob = map_sysmem(overlay_addr, 0);
 | 
				
			||||||
 | 
						if (!fdt_valid(&blob))
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* apply method prints messages on error */
 | 
				
			||||||
 | 
						if (fdt_overlay_apply_verbose(working_fdt, blob))
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_RET_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_extension_list(struct cmd_tbl *cmdtp, int flag,
 | 
				
			||||||
 | 
								     int argc, char *const argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i = 0;
 | 
				
			||||||
 | 
						struct extension *extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (list_empty(&extension_list)) {
 | 
				
			||||||
 | 
							printf("No extension registered - Please run \"extension scan\"\n");
 | 
				
			||||||
 | 
							return CMD_RET_SUCCESS;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry(extension, &extension_list, list) {
 | 
				
			||||||
 | 
							printf("Extension %d: %s\n", i++, extension->name);
 | 
				
			||||||
 | 
							printf("\tManufacturer: \t\t%s\n", extension->owner);
 | 
				
			||||||
 | 
							printf("\tVersion: \t\t%s\n", extension->version);
 | 
				
			||||||
 | 
							printf("\tDevicetree overlay: \t%s\n", extension->overlay);
 | 
				
			||||||
 | 
							printf("\tOther information: \t%s\n", extension->other);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return CMD_RET_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_extension_scan(struct cmd_tbl *cmdtp, int flag,
 | 
				
			||||||
 | 
								     int argc, char *const argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct extension *extension, *next;
 | 
				
			||||||
 | 
						int extension_num;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(extension, next, &extension_list, list) {
 | 
				
			||||||
 | 
							list_del(&extension->list);
 | 
				
			||||||
 | 
							free(extension);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						extension_num = extension_board_scan(&extension_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (extension_num < 0)
 | 
				
			||||||
 | 
							return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("Found %d extension board(s).\n", extension_num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_RET_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_extension_apply(struct cmd_tbl *cmdtp, int flag,
 | 
				
			||||||
 | 
								      int argc, char *const argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct extension *extension = NULL;
 | 
				
			||||||
 | 
						struct list_head *entry;
 | 
				
			||||||
 | 
						int i = 0, extension_id, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argc < 2)
 | 
				
			||||||
 | 
							return CMD_RET_USAGE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (strcmp(argv[1], "all") == 0) {
 | 
				
			||||||
 | 
							list_for_each_entry(extension, &extension_list, list) {
 | 
				
			||||||
 | 
								ret = extension_apply(extension);
 | 
				
			||||||
 | 
								if (ret != CMD_RET_SUCCESS)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							extension_id = simple_strtol(argv[1], NULL, 10);
 | 
				
			||||||
 | 
							list_for_each(entry, &extension_list) {
 | 
				
			||||||
 | 
								if (i == extension_id) {
 | 
				
			||||||
 | 
									extension = list_entry(entry, struct extension,  list);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								i++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!extension) {
 | 
				
			||||||
 | 
								printf("Wrong extension number\n");
 | 
				
			||||||
 | 
								return CMD_RET_FAILURE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ret = extension_apply(extension);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct cmd_tbl cmd_extension[] = {
 | 
				
			||||||
 | 
						U_BOOT_CMD_MKENT(scan, 1, 1, do_extension_scan, "", ""),
 | 
				
			||||||
 | 
						U_BOOT_CMD_MKENT(list, 1, 0, do_extension_list, "", ""),
 | 
				
			||||||
 | 
						U_BOOT_CMD_MKENT(apply, 2, 0, do_extension_apply, "", ""),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_extensionops(struct cmd_tbl *cmdtp, int flag, int argc,
 | 
				
			||||||
 | 
								   char *const argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cmd_tbl *cp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Drop the extension command */
 | 
				
			||||||
 | 
						argc--;
 | 
				
			||||||
 | 
						argv++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cp = find_cmd_tbl(argv[0], cmd_extension, ARRAY_SIZE(cmd_extension));
 | 
				
			||||||
 | 
						if (cp)
 | 
				
			||||||
 | 
							return cp->cmd(cmdtp, flag, argc, argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_RET_USAGE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U_BOOT_CMD(extension, 3, 1, do_extensionops,
 | 
				
			||||||
 | 
						"Extension board management sub system",
 | 
				
			||||||
 | 
						"scan - scan plugged extension(s) board(s)\n"
 | 
				
			||||||
 | 
						"extension list - lists available extension(s) board(s)\n"
 | 
				
			||||||
 | 
						"extension apply <extension number|all> - applies DT overlays corresponding to extension boards\n"
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
							
								
								
									
										49
									
								
								cmd/fdt.c
								
								
								
								
							
							
						
						
									
										49
									
								
								cmd/fdt.c
								
								
								
								
							| 
						 | 
					@ -27,7 +27,6 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
DECLARE_GLOBAL_DATA_PTR;
 | 
					DECLARE_GLOBAL_DATA_PTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int fdt_valid(struct fdt_header **blobp);
 | 
					 | 
				
			||||||
static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);
 | 
					static int fdt_parse_prop(char *const*newval, int count, char *data, int *len);
 | 
				
			||||||
static int fdt_print(const char *pathp, char *prop, int depth);
 | 
					static int fdt_print(const char *pathp, char *prop, int depth);
 | 
				
			||||||
static int is_printable_string(const void *data, int len);
 | 
					static int is_printable_string(const void *data, int len);
 | 
				
			||||||
| 
						 | 
					@ -732,54 +731,6 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/****************************************************************************/
 | 
					/****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * fdt_valid() - Check if an FDT is valid. If not, change it to NULL
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @blobp: Pointer to FDT pointer
 | 
					 | 
				
			||||||
 * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL)
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int fdt_valid(struct fdt_header **blobp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const void *blob = *blobp;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (blob == NULL) {
 | 
					 | 
				
			||||||
		printf ("The address of the fdt is invalid (NULL).\n");
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = fdt_check_header(blob);
 | 
					 | 
				
			||||||
	if (err == 0)
 | 
					 | 
				
			||||||
		return 1;	/* valid */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Be more informative on bad version.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (err == -FDT_ERR_BADVERSION) {
 | 
					 | 
				
			||||||
			if (fdt_version(blob) <
 | 
					 | 
				
			||||||
			    FDT_FIRST_SUPPORTED_VERSION) {
 | 
					 | 
				
			||||||
				printf (" - too old, fdt %d < %d",
 | 
					 | 
				
			||||||
					fdt_version(blob),
 | 
					 | 
				
			||||||
					FDT_FIRST_SUPPORTED_VERSION);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (fdt_last_comp_version(blob) >
 | 
					 | 
				
			||||||
			    FDT_LAST_SUPPORTED_VERSION) {
 | 
					 | 
				
			||||||
				printf (" - too new, fdt %d > %d",
 | 
					 | 
				
			||||||
					fdt_version(blob),
 | 
					 | 
				
			||||||
					FDT_LAST_SUPPORTED_VERSION);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		printf("\n");
 | 
					 | 
				
			||||||
		*blobp = NULL;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/****************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Parse the user's input, partially heuristic.  Valid formats:
 | 
					 * Parse the user's input, partially heuristic.  Valid formats:
 | 
				
			||||||
 * <0x00112233 4 05>	- an array of cells.  Numbers follow standard
 | 
					 * <0x00112233 4 05>	- an array of cells.  Numbers follow standard
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1904,3 +1904,49 @@ int fdt_overlay_apply_verbose(void *fdt, void *fdto)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * fdt_valid() - Check if an FDT is valid. If not, change it to NULL
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @blobp: Pointer to FDT pointer
 | 
				
			||||||
 | 
					 * @return 1 if OK, 0 if bad (in which case *blobp is set to NULL)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int fdt_valid(struct fdt_header **blobp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const void *blob = *blobp;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!blob) {
 | 
				
			||||||
 | 
							printf("The address of the fdt is invalid (NULL).\n");
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = fdt_check_header(blob);
 | 
				
			||||||
 | 
						if (err == 0)
 | 
				
			||||||
 | 
							return 1;	/* valid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Be more informative on bad version.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (err == -FDT_ERR_BADVERSION) {
 | 
				
			||||||
 | 
								if (fdt_version(blob) <
 | 
				
			||||||
 | 
								    FDT_FIRST_SUPPORTED_VERSION) {
 | 
				
			||||||
 | 
									printf(" - too old, fdt %d < %d",
 | 
				
			||||||
 | 
									       fdt_version(blob),
 | 
				
			||||||
 | 
									       FDT_FIRST_SUPPORTED_VERSION);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (fdt_last_comp_version(blob) >
 | 
				
			||||||
 | 
								    FDT_LAST_SUPPORTED_VERSION) {
 | 
				
			||||||
 | 
									printf(" - too new, fdt %d > %d",
 | 
				
			||||||
 | 
									       fdt_version(blob),
 | 
				
			||||||
 | 
									       FDT_LAST_SUPPORTED_VERSION);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							printf("\n");
 | 
				
			||||||
 | 
							*blobp = NULL;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
CONFIG_ARM=y
 | 
					CONFIG_ARM=y
 | 
				
			||||||
CONFIG_ARCH_SUNXI=y
 | 
					CONFIG_ARCH_SUNXI=y
 | 
				
			||||||
CONFIG_SPL=y
 | 
					CONFIG_SPL=y
 | 
				
			||||||
 | 
					CONFIG_CHIP_DIP_SCAN=y
 | 
				
			||||||
CONFIG_MACH_SUN5I=y
 | 
					CONFIG_MACH_SUN5I=y
 | 
				
			||||||
CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
 | 
					CONFIG_DRAM_TIMINGS_DDR3_800E_1066G_1333J=y
 | 
				
			||||||
CONFIG_USB0_VBUS_PIN="PB10"
 | 
					CONFIG_USB0_VBUS_PIN="PB10"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ CONFIG_MISC_INIT_F=y
 | 
				
			||||||
# CONFIG_CMD_BOOTD is not set
 | 
					# CONFIG_CMD_BOOTD is not set
 | 
				
			||||||
# CONFIG_CMD_BOOTM is not set
 | 
					# CONFIG_CMD_BOOTM is not set
 | 
				
			||||||
# CONFIG_CMD_ELF is not set
 | 
					# CONFIG_CMD_ELF is not set
 | 
				
			||||||
 | 
					# CONFIG_CMD_EXTENSION is not set
 | 
				
			||||||
CONFIG_BOOTP_DNS2=y
 | 
					CONFIG_BOOTP_DNS2=y
 | 
				
			||||||
# CONFIG_CMD_DATE is not set
 | 
					# CONFIG_CMD_DATE is not set
 | 
				
			||||||
CONFIG_OF_CONTROL=y
 | 
					CONFIG_OF_CONTROL=y
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					.. SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					.. Copyright 2021, Kory Maincent <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U-Boot extension board usage (CONFIG_EXTENSION)
 | 
				
			||||||
 | 
					===============================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Synopsis
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extension scan
 | 
				
			||||||
 | 
					    extension list
 | 
				
			||||||
 | 
					    extension apply <extension number|all>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Description
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The "extension" command proposes a generic U-Boot mechanism to detect
 | 
				
			||||||
 | 
					extension boards connected to the HW platform, and apply the appropriate
 | 
				
			||||||
 | 
					Device Tree overlays depending on the detected extension boards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The "extension" command comes with three sub-commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - "extension scan" makes the generic code call the board-specific
 | 
				
			||||||
 | 
					   extension_board_scan() function to retrieve the list of detected
 | 
				
			||||||
 | 
					   extension boards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - "extension list" allows to list the detected extension boards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - "extension apply <number>|all" allows to apply the Device Tree
 | 
				
			||||||
 | 
					   overlay(s) corresponding to one, or all, extension boards
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The latter requires two environment variables to exist:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - extension_overlay_addr: the RAM address where to load the Device
 | 
				
			||||||
 | 
					   Tree overlays
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 - extension_overlay_cmd: the U-Boot command to load one overlay.
 | 
				
			||||||
 | 
					   Indeed, the location and mechanism to load DT overlays is very setup
 | 
				
			||||||
 | 
					   specific.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to enable this mechanism, board-specific code must implement
 | 
				
			||||||
 | 
					the extension_board_scan() function that fills in a linked list of
 | 
				
			||||||
 | 
					"struct extension", each describing one extension board. In addition,
 | 
				
			||||||
 | 
					the board-specific code must select the SUPPORT_EXTENSION_SCAN Kconfig
 | 
				
			||||||
 | 
					boolean.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage example
 | 
				
			||||||
 | 
					-------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Make sure your devicetree is loaded and set as the working fdt tree.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => run loadfdt
 | 
				
			||||||
 | 
					    => fdt addr $fdtaddr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Prepare the environment variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => setenv extension_overlay_addr 0x88080000
 | 
				
			||||||
 | 
					    => setenv extension_overlay_cmd 'load mmc 0:1 ${extension_overlay_addr} /boot/${extension_overlay_name}'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Detect the plugged extension board
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => extension scan
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. List the plugged extension board information and the devicetree
 | 
				
			||||||
 | 
					   overlay name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => extension list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. Apply the appropriate devicetree overlay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For apply the selected overlay:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => extension apply 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For apply all the overlays:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    => extension apply all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Simple extension_board_scan function example
 | 
				
			||||||
 | 
					--------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int extension_board_scan(struct list_head *extension_list)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        struct extension *extension;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        extension = calloc(1, sizeof(struct extension));
 | 
				
			||||||
 | 
					        snprintf(extension->overlay, sizeof(extension->overlay), "overlay.dtbo");
 | 
				
			||||||
 | 
					        snprintf(extension->name, sizeof(extension->name), "extension board");
 | 
				
			||||||
 | 
					        snprintf(extension->owner, sizeof(extension->owner), "sandbox");
 | 
				
			||||||
 | 
					        snprintf(extension->version, sizeof(extension->version), "1.1");
 | 
				
			||||||
 | 
					        snprintf(extension->other, sizeof(extension->other), "Extension board information");
 | 
				
			||||||
 | 
					        list_add_tail(&extension->list, extension_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -53,3 +53,10 @@ U_BOOT_DRIVER(ds24xxx) = {
 | 
				
			||||||
	.ops		= &ds24xxx_ops,
 | 
						.ops		= &ds24xxx_ops,
 | 
				
			||||||
	.probe		= ds24xxx_probe,
 | 
						.probe		= ds24xxx_probe,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					u8 family_supported[] = {
 | 
				
			||||||
 | 
						W1_FAMILY_DS24B33,
 | 
				
			||||||
 | 
						W1_FAMILY_DS2431,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U_BOOT_W1_DEVICE(ds24xxx, family_supported);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,3 +243,9 @@ U_BOOT_DRIVER(ds2502) = {
 | 
				
			||||||
	.ops		= &ds2502_ops,
 | 
						.ops		= &ds2502_ops,
 | 
				
			||||||
	.probe		= ds2502_probe,
 | 
						.probe		= ds2502_probe,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					u8 family_supported[] = {
 | 
				
			||||||
 | 
						W1_FAMILY_DS2502,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U_BOOT_W1_DEVICE(ds2502, family_supported);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,37 +37,6 @@ int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
 | 
				
			||||||
	return ops->read_buf(dev, offset, buf, count);
 | 
						return ops->read_buf(dev, offset, buf, count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int w1_eeprom_register_new_device(u64 id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u8 family = id & 0xff;
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
	struct udevice *dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev);
 | 
					 | 
				
			||||||
	     !ret && dev;
 | 
					 | 
				
			||||||
	     uclass_next_device(&dev)) {
 | 
					 | 
				
			||||||
		if (ret || !dev) {
 | 
					 | 
				
			||||||
			debug("cannot find w1 eeprom dev\n");
 | 
					 | 
				
			||||||
			return ret;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (dev_get_driver_data(dev) == family) {
 | 
					 | 
				
			||||||
			struct w1_device *w1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			w1 = dev_get_parent_plat(dev);
 | 
					 | 
				
			||||||
			if (w1->id) /* device already in use */
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			w1->id = id;
 | 
					 | 
				
			||||||
			debug("%s: Match found: %s:%s %llx\n", __func__,
 | 
					 | 
				
			||||||
			      dev->name, dev->driver->name, id);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	debug("%s: No matches found: error %d\n", __func__, ret);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int w1_eeprom_get_id(struct udevice *dev, u64 *id)
 | 
					int w1_eeprom_get_id(struct udevice *dev, u64 *id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct w1_device *w1 = dev_get_parent_plat(dev);
 | 
						struct w1_device *w1 = dev_get_parent_plat(dev);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,9 +4,11 @@
 | 
				
			||||||
 * Copyright (c) 2015 Free Electrons
 | 
					 * Copyright (c) 2015 Free Electrons
 | 
				
			||||||
 * Copyright (c) 2015 NextThing Co.
 | 
					 * Copyright (c) 2015 NextThing Co.
 | 
				
			||||||
 * Copyright (c) 2018 Microchip Technology, Inc.
 | 
					 * Copyright (c) 2018 Microchip Technology, Inc.
 | 
				
			||||||
 | 
					 * Copyright (c) 2021 Bootlin
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Maxime Ripard <maxime.ripard@free-electrons.com>
 | 
					 * Maxime Ripard <maxime.ripard@free-electrons.com>
 | 
				
			||||||
 * Eugen Hristev <eugen.hristev@microchip.com>
 | 
					 * Eugen Hristev <eugen.hristev@microchip.com>
 | 
				
			||||||
 | 
					 * Kory Maincent <kory.maincent@bootlin.com>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +28,76 @@ struct w1_bus {
 | 
				
			||||||
	u64	search_id;
 | 
						u64	search_id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int w1_bus_find_dev(const struct udevice *bus, u64 id, struct udevice
 | 
				
			||||||
 | 
					**devp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct udevice *dev;
 | 
				
			||||||
 | 
						u8 family = id & 0xff;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev);
 | 
				
			||||||
 | 
							!ret && dev;
 | 
				
			||||||
 | 
							uclass_next_device(&dev)) {
 | 
				
			||||||
 | 
							if (ret || !dev) {
 | 
				
			||||||
 | 
								debug("cannot find w1 eeprom dev\n");
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (dev_get_driver_data(dev) == family) {
 | 
				
			||||||
 | 
								*devp = dev;
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -ENODEV;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int w1_register_new_device(u64 id, struct udevice *bus)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u8 family = id & 0xff;
 | 
				
			||||||
 | 
						int n_ents, ret = 0;
 | 
				
			||||||
 | 
						struct udevice *dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct w1_driver_entry *start, *entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						start = ll_entry_start(struct w1_driver_entry, w1_driver_entry);
 | 
				
			||||||
 | 
						n_ents = ll_entry_count(struct w1_driver_entry, w1_driver_entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (entry = start; entry != start + n_ents; entry++) {
 | 
				
			||||||
 | 
							const u8 *match_family;
 | 
				
			||||||
 | 
							const struct driver *drv;
 | 
				
			||||||
 | 
							struct w1_device *w1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (match_family = entry->family; match_family;
 | 
				
			||||||
 | 
							     match_family++) {
 | 
				
			||||||
 | 
								if (*match_family != family)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ret = w1_bus_find_dev(bus, id, &dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* If nothing in the device tree, bind a device */
 | 
				
			||||||
 | 
								if (ret == -ENODEV) {
 | 
				
			||||||
 | 
									drv = entry->driver;
 | 
				
			||||||
 | 
									ret = device_bind(bus, drv, drv->name,
 | 
				
			||||||
 | 
											  NULL, ofnode_null(), &dev);
 | 
				
			||||||
 | 
									if (ret)
 | 
				
			||||||
 | 
										return ret;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								device_probe(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								w1 = dev_get_parent_plat(dev);
 | 
				
			||||||
 | 
								w1->id = id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						debug("%s: No matches found: error %d\n", __func__, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int w1_enumerate(struct udevice *bus)
 | 
					static int w1_enumerate(struct udevice *bus)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct w1_ops *ops = device_get_ops(bus);
 | 
						const struct w1_ops *ops = device_get_ops(bus);
 | 
				
			||||||
| 
						 | 
					@ -97,8 +169,8 @@ static int w1_enumerate(struct udevice *bus)
 | 
				
			||||||
			debug("%s: Detected new device 0x%llx (family 0x%x)\n",
 | 
								debug("%s: Detected new device 0x%llx (family 0x%x)\n",
 | 
				
			||||||
			      bus->name, rn, (u8)(rn & 0xff));
 | 
								      bus->name, rn, (u8)(rn & 0xff));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* attempt to register as w1-eeprom device */
 | 
								/* attempt to register as w1 device */
 | 
				
			||||||
			w1_eeprom_register_new_device(rn);
 | 
								w1_register_new_device(rn, bus);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0+ */
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * (C) Copyright 2021
 | 
				
			||||||
 | 
					 * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __EXTENSION_SUPPORT_H
 | 
				
			||||||
 | 
					#define __EXTENSION_SUPPORT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct extension {
 | 
				
			||||||
 | 
						struct list_head list;
 | 
				
			||||||
 | 
						char name[32];
 | 
				
			||||||
 | 
						char owner[32];
 | 
				
			||||||
 | 
						char version[32];
 | 
				
			||||||
 | 
						char overlay[32];
 | 
				
			||||||
 | 
						char other[32];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * extension_board_scan - Add system-specific function to scan extension board.
 | 
				
			||||||
 | 
					 * @param extension_list	List of extension board information to update.
 | 
				
			||||||
 | 
					 * @return the number of extension.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function is called if CONFIG_CMD_EXTENSION is defined.
 | 
				
			||||||
 | 
					 * Needs to fill the list extension_list with elements.
 | 
				
			||||||
 | 
					 * Each element need to be allocated to an extension structure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int extension_board_scan(struct list_head *extension_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __EXTENSION_SUPPORT_H */
 | 
				
			||||||
| 
						 | 
					@ -352,6 +352,8 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int fdt_overlay_apply_verbose(void *fdt, void *fdto);
 | 
					int fdt_overlay_apply_verbose(void *fdt, void *fdto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int fdt_valid(struct fdt_header **blobp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * fdt_get_cells_len() - Get the length of a type of cell in top-level nodes
 | 
					 * fdt_get_cells_len() - Get the length of a type of cell in top-level nodes
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,5 @@ int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int w1_eeprom_dm_init(void);
 | 
					int w1_eeprom_dm_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int w1_eeprom_register_new_device(u64 id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int w1_eeprom_get_id(struct udevice *dev, u64 *id);
 | 
					int w1_eeprom_get_id(struct udevice *dev, u64 *id);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								include/w1.h
								
								
								
								
							
							
						
						
									
										17
									
								
								include/w1.h
								
								
								
								
							| 
						 | 
					@ -15,6 +15,23 @@ struct udevice;
 | 
				
			||||||
#define W1_FAMILY_DS2502	0x09
 | 
					#define W1_FAMILY_DS2502	0x09
 | 
				
			||||||
#define W1_FAMILY_EEP_SANDBOX	0xfe
 | 
					#define W1_FAMILY_EEP_SANDBOX	0xfe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct w1_driver_entry {
 | 
				
			||||||
 | 
						struct driver	*driver;
 | 
				
			||||||
 | 
						u8		*family;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* U_BOOT_W1_DEVICE() tells U-Boot to create a one-wire device.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @__name: Device name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
 | 
				
			||||||
 | 
					 * @__driver: Driver name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
 | 
				
			||||||
 | 
					 * @__family: Family code number of the one-wire
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define U_BOOT_W1_DEVICE(__name, __family)				\
 | 
				
			||||||
 | 
						ll_entry_declare(struct w1_driver_entry, __name, w1_driver_entry) = { \
 | 
				
			||||||
 | 
							.driver = llsym(struct driver, __name, driver),		\
 | 
				
			||||||
 | 
							.family = __family,					\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct w1_device {
 | 
					struct w1_device {
 | 
				
			||||||
	u64	id;
 | 
						u64	id;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					# SPDX-License-Identifier:  GPL-2.0+
 | 
				
			||||||
 | 
					# Copyright (c) 2020
 | 
				
			||||||
 | 
					# Author: Kory Maincent <kory.maincent@bootlin.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test U-Boot's "extension" commands.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					import u_boot_utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					overlay_addr = 0x1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SANDBOX_DTB='arch/sandbox/dts/sandbox.dtb'
 | 
				
			||||||
 | 
					OVERLAY_DIR='arch/sandbox/dts/'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_dtb(u_boot_console):
 | 
				
			||||||
 | 
					    u_boot_console.log.action('Loading devicetree to RAM...')
 | 
				
			||||||
 | 
					    u_boot_console.run_command('host load hostfs - $fdt_addr_r %s' % (os.path.join(u_boot_console.config.build_dir, SANDBOX_DTB)))
 | 
				
			||||||
 | 
					    u_boot_console.run_command('fdt addr $fdt_addr_r')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.buildconfigspec('cmd_fdt')
 | 
				
			||||||
 | 
					@pytest.mark.boardspec('sandbox')
 | 
				
			||||||
 | 
					def test_extension(u_boot_console):
 | 
				
			||||||
 | 
					    """Test the 'extension' command."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    load_dtb(u_boot_console)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('extension list')
 | 
				
			||||||
 | 
					    assert('No extension' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('extension scan')
 | 
				
			||||||
 | 
					    assert output == 'Found 2 extension board(s).'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('extension list')
 | 
				
			||||||
 | 
					    assert('overlay0.dtbo' in output)
 | 
				
			||||||
 | 
					    assert('overlay1.dtbo' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u_boot_console.run_command_list([
 | 
				
			||||||
 | 
					        'setenv extension_overlay_addr %s' % (overlay_addr),
 | 
				
			||||||
 | 
					        'setenv extension_overlay_cmd \'host load hostfs - ${extension_overlay_addr} %s${extension_overlay_name}\'' % (os.path.join(u_boot_console.config.build_dir, OVERLAY_DIR))])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('extension apply 0')
 | 
				
			||||||
 | 
					    assert('bytes read' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('fdt print')
 | 
				
			||||||
 | 
					    assert('button3' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('extension apply all')
 | 
				
			||||||
 | 
					    assert('bytes read' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output = u_boot_console.run_command('fdt print')
 | 
				
			||||||
 | 
					    assert('button4' in output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue