Adds support for two LVDS panels and one RGB panel to the SABRE-Lite
board:
     Hannstar-XGA       - 1024 x 768 LVDS (Freescale part number MCIMX-LVDS1)
     wsvga-lvds         - 1024 x 600 LVDS (Boundary p/n Nit6X_1024x600)
     wvga-rgb           - 800 x 480 RGB (Boundary p/n Nit6X_800x480)

Auto-detects panel by probing the I2C touch controller of each.

Setting 'panel' environment variable to one of the names above will override
auto-detection.

Signed-off-by: Eric Nelson <eric.nel...@boundarydevices.com>
---
 board/freescale/mx6qsabrelite/mx6qsabrelite.c |  245 ++++++++++++++++++++++++-
 drivers/video/ipu_common.c                    |    2 +-
 include/configs/mx6qsabrelite.h               |   15 ++-
 3 files changed, 259 insertions(+), 3 deletions(-)

diff --git a/board/freescale/mx6qsabrelite/mx6qsabrelite.c 
b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
index 4b4e89b..d274d8c 100644
--- a/board/freescale/mx6qsabrelite/mx6qsabrelite.c
+++ b/board/freescale/mx6qsabrelite/mx6qsabrelite.c
@@ -36,6 +36,11 @@
 #include <micrel.h>
 #include <miiphy.h>
 #include <netdev.h>
+#include <linux/fb.h>
+#include <ipu_pixfmt.h>
+#include <asm/arch/crm_regs.h>
+#include <i2c.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #define UART_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |           \
@@ -372,14 +377,252 @@ int setup_sata(void)
 }
 #endif
 
+#if defined(CONFIG_VIDEO_IPUV3)
+static struct fb_videomode videomodes[] = {{
+               .name           = "Hannstar-XGA",
+               .refresh        = 60,
+               .xres           = 1024,
+               .yres           = 768,
+               .pixclock       = 15385,
+               .left_margin    = 220,
+               .right_margin   = 40,
+               .upper_margin   = 21,
+               .lower_margin   = 7,
+               .hsync_len      = 60,
+               .vsync_len      = 10,
+               .sync           = FB_SYNC_EXT, /* a.k.a. LVDS */
+               .vmode          = FB_VMODE_NONINTERLACED
+       }, {
+               .name           = "wsvga-lvds",
+               .refresh        = 60,
+               .xres           = 1024,
+               .yres           = 600,
+               .pixclock       = 15385,
+               .left_margin    = 220,
+               .right_margin   = 40,
+               .upper_margin   = 21,
+               .lower_margin   = 7,
+               .hsync_len      = 60,
+               .vsync_len      = 10,
+               .sync           = FB_SYNC_EXT, /* a.k.a. LVDS */
+               .vmode          = FB_VMODE_NONINTERLACED
+       }, {
+               .name           = "wvga-rgb",
+               .refresh        = 57,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = 37037,
+               .left_margin    = 40,
+               .right_margin   = 60,
+               .upper_margin   = 10,
+               .lower_margin   = 10,
+               .hsync_len      = 20,
+               .vsync_len      = 10,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED
+} };
+
+#define IS_LVDS(m) (FB_SYNC_EXT & (m).sync)
+
+struct i2c_display {
+       int bus;
+       int addr;
+       char const *name;
+};
+
+static struct i2c_display const i2c_displays[] = {
+{
+       .bus            = 2,
+       .addr           = 0x4,
+       .name           = "Hannstar-XGA",
+}, {
+       .bus            = 2,
+       .addr           = 0x38,
+       .name           = "wsvga-lvds",
+}, {
+       .bus            = 2,
+       .addr           = 0x48,
+       .name           = "wvga-rgb",
+} };
+
+static iomux_v3_cfg_t rgb_pads[] = {
+       MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK,
+       MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15,
+       MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2,
+       MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3,
+       MX6Q_PAD_DI0_PIN4__GPIO_4_20,
+       MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0,
+       MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1,
+       MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2,
+       MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3,
+       MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4,
+       MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5,
+       MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6,
+       MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7,
+       MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8,
+       MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9,
+       MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10,
+       MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11,
+       MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12,
+       MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13,
+       MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14,
+       MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15,
+       MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16,
+       MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17,
+       MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18,
+       MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19,
+       MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20,
+       MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21,
+       MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22,
+       MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23,
+};
+
+static iomux_v3_cfg_t backlight_pads[] = {
+       /* Backlight on RGB connector: J15 */
+       MX6Q_PAD_SD1_DAT3__GPIO_1_21 | MUX_PAD_CTRL(NO_PAD_CTRL),
+#define RGB_BACKLIGHT_GP IMX_GPIO_NR(1, 21)
+
+       /* Backlight on LVDS connector: J6 */
+       MX6Q_PAD_SD1_CMD__GPIO_1_18 | MUX_PAD_CTRL(NO_PAD_CTRL),
+#define LVDS_BACKLIGHT_GP IMX_GPIO_NR(1, 18)
+};
+
+int board_video_skip(void)
+{
+       int i;
+       int ret;
+       char const *panel = getenv("panel");
+       if (!panel) {
+               for (i = 0; i < ARRAY_SIZE(i2c_displays); i++) {
+                       struct i2c_display const *dev = i2c_displays+i;
+                       if ((0 == i2c_set_bus_num(dev->bus))
+                            &&
+                           (0 == i2c_probe(dev->addr))) {
+                               panel = dev->name;
+                               printf("auto-detected panel %s\n", panel);
+                               break;
+                       }
+               }
+               if (!panel) {
+                       panel = videomodes[0].name;
+                       printf("No panel detected: default to %s\n", panel);
+               }
+       }
+       for (i = 0; i < ARRAY_SIZE(videomodes); i++) {
+               if (!strcmp(panel, videomodes[i].name))
+                       break;
+       }
+       if (i < ARRAY_SIZE(videomodes)) {
+               ret = ipuv3_fb_init(videomodes+i, 0, IPU_PIX_FMT_RGB666);
+               if (!ret) {
+                       if (IS_LVDS(videomodes[i]))
+                               gpio_direction_output(LVDS_BACKLIGHT_GP, 1);
+                       else {
+                               imx_iomux_v3_setup_multiple_pads(
+                                       rgb_pads,
+                                        ARRAY_SIZE(rgb_pads));
+                               gpio_direction_output(RGB_BACKLIGHT_GP, 1);
+                       }
+                       printf("Display: %s (%ux%u)\n",
+                              videomodes[i].name,
+                              videomodes[i].xres,
+                              videomodes[i].yres);
+               } else
+                       printf("LCD %s cannot be configured: %d\n",
+                              videomodes[i].name, ret);
+       } else {
+               printf("unsupported panel %s\n", panel);
+               ret = -EINVAL;
+       }
+       return (0 != ret);
+}
+
+void lcd_iomux(void)
+{
+       struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+       struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
+       struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
+
+       int reg;
+
+       /* Turn on LDB0,IPU,IPU DI0 clocks */
+       reg = __raw_readl(&mxc_ccm->CCGR3);
+       reg |=   MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET
+               |MXC_CCM_CCGR3_LDB_DI0_MASK;
+       writel(reg, &mxc_ccm->CCGR3);
+
+       /* set PFD1_FRAC to 0x13 == 455 MHz (480*18)/0x13 */
+       writel(ANATOP_PFD_480_PFD1_FRAC_MASK, &anatop->pfd_480_clr);
+       writel(0x13<<ANATOP_PFD_480_PFD1_FRAC_SHIFT, &anatop->pfd_480_set);
+
+       /* set LDB0, LDB1 clk select to 011/011 */
+       reg = readl(&mxc_ccm->cs2cdr);
+       reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
+                |MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
+       reg |= (3<<MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
+             |(3<<MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
+       writel(reg, &mxc_ccm->cs2cdr);
+
+       reg = readl(&mxc_ccm->cscmr2);
+       reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV;
+       writel(reg, &mxc_ccm->cscmr2);
+
+       reg = readl(&mxc_ccm->chsccdr);
+       reg &= ~(MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK
+               |MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK
+               |MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK);
+       reg |= (CHSCCDR_CLK_SEL_LDB_DI0
+               <<MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET)
+             |(CHSCCDR_PODF_DIVIDE_BY_3
+               <<MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET)
+             |(CHSCCDR_IPU_PRE_CLK_540M_PFD
+               <<MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET);
+       writel(reg, &mxc_ccm->chsccdr);
+
+       reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
+            |IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
+            |IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
+            |IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
+            |IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
+            |IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
+            |IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
+            |IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED
+            |IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
+       writel(reg, &iomux->gpr[2]);
+
+       reg = readl(&iomux->gpr[3]);
+       reg = (reg & ~IOMUXC_GPR3_LVDS0_MUX_CTL_MASK)
+           | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
+              <<IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET);
+       writel(reg, &iomux->gpr[3]);
+
+       /* backlights off until needed */
+       imx_iomux_v3_setup_multiple_pads(backlight_pads,
+                                        ARRAY_SIZE(backlight_pads));
+       gpio_direction_input(LVDS_BACKLIGHT_GP);
+       gpio_direction_input(RGB_BACKLIGHT_GP);
+}
+#endif
+
 int board_early_init_f(void)
 {
        setup_iomux_uart();
        setup_buttons();
-
+#if defined(CONFIG_VIDEO_IPUV3)
+       lcd_iomux();
+#endif
        return 0;
 }
 
+/*
+ * Do not overwrite the console
+ * Use always serial for U-Boot console
+ */
+int overwrite_console(void)
+{
+       return 1;
+}
+
 int board_init(void)
 {
        /* address of boot parameters */
diff --git a/drivers/video/ipu_common.c b/drivers/video/ipu_common.c
index cc8f881..5f0a1a8 100644
--- a/drivers/video/ipu_common.c
+++ b/drivers/video/ipu_common.c
@@ -218,7 +218,7 @@ static struct clk ipu_clk = {
 #else
        .enable_reg = (u32 *)(CCM_BASE_ADDR +
                offsetof(struct mxc_ccm_reg, CCGR3)),
-       .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET,
+       .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_MASK,
 #endif
        .enable = clk_ipu_enable,
        .disable = clk_ipu_disable,
diff --git a/include/configs/mx6qsabrelite.h b/include/configs/mx6qsabrelite.h
index 72d0154..d0c3e0a 100644
--- a/include/configs/mx6qsabrelite.h
+++ b/include/configs/mx6qsabrelite.h
@@ -39,7 +39,7 @@
 #define CONFIG_REVISION_TAG
 
 /* Size of malloc() pool */
-#define CONFIG_SYS_MALLOC_LEN         (CONFIG_ENV_SIZE + 2 * 1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN         (10 * 1024 * 1024)
 
 #define CONFIG_BOARD_EARLY_INIT_F
 #define CONFIG_MISC_INIT_R
@@ -121,6 +121,19 @@
 /* Miscellaneous commands */
 #define CONFIG_CMD_BMODE
 
+/* Framebuffer and LCD */
+#define CONFIG_VIDEO
+#define CONFIG_VIDEO_IPUV3
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_VGA_AS_SINGLE_DEVICE
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+#define CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
+#define CONFIG_VIDEO_BMP_RLE8
+#define CONFIG_SPLASH_SCREEN
+#define CONFIG_BMP_16BPP
+#define CONFIG_VIDEO_LOGO
+#define CONFIG_IPUV3_CLK 260000000
+
 /* allow to overwrite serial and ethaddr */
 #define CONFIG_ENV_OVERWRITE
 #define CONFIG_CONS_INDEX             1
-- 
1.7.9

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to