The NextThing CHIP comes with expansion boards called DIPs. These DIPs comes with a 1-Wire EEPROM used to enumerate and identify the DIPs currently attached.
Once we know what is connected, we need to do various things, such a load and apply an overlay if relevant, adjust the U-boot environment and the kernel command line, etc. Add support for this. Signed-off-by: Maxime Ripard <maxime.rip...@free-electrons.com> --- board/sunxi/Kconfig | 9 ++- board/sunxi/Makefile | 1 +- board/sunxi/board.c | 6 +- board/sunxi/dip.c | 227 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 243 insertions(+), 0 deletions(-) create mode 100644 board/sunxi/dip.c diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index e1d4ab148f08..1e70f3a2ed97 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -667,4 +667,13 @@ config SPL_STACK_R_ADDR default 0x4fe00000 if MACH_SUN4I || MACH_SUN5I || MACH_SUN6I || MACH_SUN7I || MACH_SUN8I || MACH_SUN50I default 0x2fe00000 if MACH_SUN9I +config CHIP_DIP + bool "Enable NextThing's CHIP DIP support" + depends on W1_GPIO + depends on EEPROM_DS2431 + ---help--- + The NextThing's CHIP allows to plug expansion boards. These boards can + be enumerated at runtime through a 1-Wire bus, each board having an + EEPROM connected to it, holding data to identify the board holding it. + endif diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index 43766e0ef482..0f0ac90ef185 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -9,6 +9,7 @@ # SPDX-License-Identifier: GPL-2.0+ # obj-y += board.o +obj-$(CONFIG_CHIP_DIP) += dip.o obj-$(CONFIG_SUNXI_GMAC) += gmac.o obj-$(CONFIG_SUNXI_AHCI) += ahci.o obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 53656383d512..8cb7267b0a10 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -719,6 +719,12 @@ int ft_board_setup(void *blob, bd_t *bd) */ setup_environment(blob); +#ifdef CONFIG_CHIP_DIP + r = chip_dip_dt_setup(blob); + if (r) + return r; +#endif + #ifdef CONFIG_VIDEO_DT_SIMPLEFB r = sunxi_simplefb_setup(blob); if (r) diff --git a/board/sunxi/dip.c b/board/sunxi/dip.c new file mode 100644 index 000000000000..af908917edfe --- /dev/null +++ b/board/sunxi/dip.c @@ -0,0 +1,227 @@ +/* + * (C) Copyright 2016 NextThing Co + * (C) Copyright 2016 Free Electrons + * + * Maxime Ripard <maxime.rip...@free-electrons.com> + * + * CHIP's DIP spec implementation in U-Boot + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <eeprom.h> +#include <w1.h> + +#include <asm/arch/gpio.h> + +#include <dm/device-internal.h> + + +#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 */ + +#define DIP_VID_NTC 0x9d011a +#define DIP_PID_NTC_POCKET 0x1 +#define DIP_PID_NTC_VGA 0x2 +#define DIP_PID_NTC_HDMI 0x3 + +struct dip_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 futre spec versions */ + u8 data[16]; /* user data, per-dip specific */ +} __packed; + +struct dip { + struct list_head list; + char file[64]; +}; + +enum disp_output { + DISPLAY_COMPOSITE, + DISPLAY_RGB_HDMI_BRIDGE, + DISPLAY_RGB_VGA_BRIDGE, + DISPLAY_RGB_POCKET, +}; + +static LIST_HEAD(dip_list); + +static void dip_setup_pocket_display(enum disp_output display) +{ + char kernel[128]; + char video[128]; + char *s, *kmode; + int x, y; + + s = getenv("dip-auto-video"); + if (s && !strcmp(s, "no")) { + printf("DIP: User disabled auto setup. Aborting.\n"); + return; + } + + switch (display) { + case DISPLAY_RGB_HDMI_BRIDGE: + strncpy(kernel, "video=HDMI-A-1:1024x768@60", sizeof(kernel)); + strncpy(video, "sunxi:1024x768-24@60,monitor=hdmi", + sizeof(video)); + break; + + case DISPLAY_RGB_VGA_BRIDGE: + strncpy(kernel, "video=VGA-1:1024x768@60", sizeof(kernel)); + strncpy(video, "sunxi:1024x768-24@60,monitor=vga", + sizeof(video)); + break; + + case DISPLAY_RGB_POCKET: + strncpy(video, "sunxi:480x272-16@60,monitor=lcd", + sizeof(video)); + break; + + default: + s = getenv("tv-mode"); + if (!s) + s = "ntsc"; + + if (!strcmp(s, "ntsc")) { + x = 720; + y = 480; + kmode = "NTSC"; + } else if (!strcmp(s, "pal")) { + x = 720; + y = 576; + kmode = "PAL"; + } else { + printf("DIP: Unknown TV format: %s\n", s); + return; + } + + snprintf(kernel, sizeof(kernel), "video=Composite-1:%s", + kmode); + snprintf(video, sizeof(video), + "sunxi:%dx%d-24@60,monitor=composite-%s,overscan_x=40,overscan_y=20", + x, y, s); + + break; + } + + setenv("kernelarg_video", kernel); + setenv("video-mode", video); +} + +static void dip_detect(void) +{ + struct udevice *bus, *dev; + u8 display = DISPLAY_COMPOSITE; + u32 vid; + u16 pid; + int ret; + + sunxi_gpio_set_pull(SUNXI_GPD(2), SUNXI_GPIO_PULL_UP); + + w1_get_bus(0, &bus); + + for (device_find_first_child(bus, &dev); dev; + device_find_next_child(&dev)) { + struct dip_header header; + struct dip *dip; + + 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; + } + + eeprom_read_buf(dev, 0, (u8 *)&header, sizeof(header)); + + if (header.magic != DIP_MAGIC) + continue; + + vid = dip_convert(header.vendor_id); + pid = dip_convert(header.product_id); + + printf("DIP: Found %s (0x%x) from %s (0x%x) detected\n", + header.product_name, pid, + header.vendor_name, vid); + + dip = calloc(sizeof(*dip), 1); + if (!dip) + return; + + snprintf(dip->file, sizeof(dip->file), "dip-%x-%x.dtbo", + vid, pid); + list_add_tail(&dip->list, &dip_list); + + if (vid == DIP_VID_NTC) { + switch (pid) { + case DIP_PID_NTC_POCKET: + display = DISPLAY_RGB_POCKET; + break; + + case DIP_PID_NTC_HDMI: + display = DISPLAY_RGB_HDMI_BRIDGE; + break; + + case DIP_PID_NTC_VGA: + display = DISPLAY_RGB_VGA_BRIDGE; + break; + } + } + } + + dip_setup_pocket_display(display); +} + +int board_video_pre_init(void) +{ + dip_detect(); + + return 0; +} + +int chip_dip_dt_setup(void) +{ + struct dip *dip, *next; + int ret; + char *cmd; + + cmd = getenv("dip_overlay_cmd"); + if (!cmd) + return 0; + + list_for_each_entry_safe(dip, next, &dip_list, list) { + printf("DIP: Applying dip overlay %s\n", dip->file); + setenv("dip_overlay_name", dip->file); + ret = run_command(cmd, 0); + + /* First remove the item from the list */ + list_del(&dip->list); + free(dip); + + /* And then check if there was an error */ + if (ret) + continue; + + ret = run_command("fdt apply $dip_addr_r", 0); + if (ret) + return ret; + } + + return 0; +} -- git-series 0.8.11 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot