[U-Boot] [PATCH RESEND 8/9] sunxi: Add CHIP's DIP support
Maxime Ripard
maxime.ripard at free-electrons.com
Tue Nov 8 11:19:28 CET 2016
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.ripard at 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.ripard at 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 at 60", sizeof(kernel));
+ strncpy(video, "sunxi:1024x768-24 at 60,monitor=hdmi",
+ sizeof(video));
+ break;
+
+ case DISPLAY_RGB_VGA_BRIDGE:
+ strncpy(kernel, "video=VGA-1:1024x768 at 60", sizeof(kernel));
+ strncpy(video, "sunxi:1024x768-24 at 60,monitor=vga",
+ sizeof(video));
+ break;
+
+ case DISPLAY_RGB_POCKET:
+ strncpy(video, "sunxi:480x272-16 at 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 at 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
More information about the U-Boot
mailing list