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

Reply via email to