This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM437X: LCD support in U-boot

Part Number: AM4378
Other Parts Discussed in Thread: SYSCONFIG

Hi,All:

    Is there support of LCD in u-boot for AM437X board?

  Thanks!

  • Hi,

    The answer is no. You can use the guidelines from this thread if you want to add this feature: e2e.ti.com/.../849350 Note that this guide is for AM335X, you will need to apply it for AM437X.
  • Hi Biser Gatchev-XID,

    Does the uboot in ti-processor-sdk-linux-am437x-evm-03.01.00.06 support LCD driver?

    If yes, how to enable the LCD driver?

    We need to display the boot logo in uboot...

    Thanks!

  • Hi Biser Gatchev-XID,
    I found drivers/video/omap3_dss.c in uboot source, does it support for am437x dss?
    Thanks.
  • Hello user4552302,

    Please, refer to this post.

    Best regards,
    Kemal

  • Part Number: AM4378

    Tool/software: Linux

    Hi,

    For AM437x EVM u-boot LCD logo display,
    work finished.(test done for 24 bit bitmap)

    1. configs/am43xx_evm_defconfig : modify
    CONFIG_SYS_EXTRA_OPTIONS="CONS_INDEX=1,NAND,SPLASH"

    2. include/configs/am43xx_evm.h : added

    #if 1 // added
    /* Splash scrren support */
    #ifdef CONFIG_SPLASH
    /*#define CONFIG_AM335X_LCD*/
    #define CONFIG_LCD
    #define CONFIG_LCD_NOSTDOUT
    #define CONFIG_SYS_WHITE_ON_BLACK
    #define LCD_BPP LCD_COLOR32

    #define CONFIG_VIDEO_BMP_GZIP
    #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE  (1280*800*4 + 64)
    #define CONFIG_CMD_UNZIP
    #define CONFIG_CMD_BMP
    #define CONFIG_BMP_16BPP
    #define CONFIG_BMP_24BMP
    #define CONFIG_BMP_32BPP

    #define CONFIG_CONSOLE_SCROLL_LINES     5
    #endif
    #endif

    3. board/ti/am43xx/mux.c

    #if 1 // added
    static struct module_pin_mux lcd_pin_mux[] = {
            {OFFSET(lcd_data0), (MODE(0) | PULLUDDIS)},     /* LCD-Data(0) */
            {OFFSET(lcd_data1), (MODE(0) | PULLUDDIS)},     /* LCD-Data(1) */
            {OFFSET(lcd_data2), (MODE(0) | PULLUDDIS)},     /* LCD-Data(2) */
            {OFFSET(lcd_data3), (MODE(0) | PULLUDDIS)},     /* LCD-Data(3) */
            {OFFSET(lcd_data4), (MODE(0) | PULLUDDIS)},     /* LCD-Data(4) */
            {OFFSET(lcd_data5), (MODE(0) | PULLUDDIS)},     /* LCD-Data(5) */
            {OFFSET(lcd_data6), (MODE(0) | PULLUDDIS)},     /* LCD-Data(6) */
            {OFFSET(lcd_data7), (MODE(0) | PULLUDDIS)},     /* LCD-Data(7) */
            {OFFSET(lcd_data8), (MODE(0) | PULLUDDIS)},     /* LCD-Data(8) */
            {OFFSET(lcd_data9), (MODE(0) | PULLUDDIS)},     /* LCD-Data(9) */
            {OFFSET(lcd_data10), (MODE(0) | PULLUDDIS)},    /* LCD-Data(10) */
            {OFFSET(lcd_data11), (MODE(0) | PULLUDDIS)},    /* LCD-Data(11) */
            {OFFSET(lcd_data12), (MODE(0) | PULLUDDIS)},    /* LCD-Data(12) */
            {OFFSET(lcd_data13), (MODE(0) | PULLUDDIS)},    /* LCD-Data(13) */
            {OFFSET(lcd_data14), (MODE(0) | PULLUDDIS)},    /* LCD-Data(14) */
            {OFFSET(lcd_data15), (MODE(0) | PULLUDDIS)},    /* LCD-Data(15) */
            {OFFSET(gpmc_ad8), (MODE(1) | PULLUDDIS)},      /* LCD-Data(16) */
            {OFFSET(gpmc_ad9), (MODE(1) | PULLUDDIS)},      /* LCD-Data(17) */
            {OFFSET(gpmc_ad10), (MODE(1) | PULLUDDIS)},     /* LCD-Data(18) */
            {OFFSET(gpmc_ad11), (MODE(1) | PULLUDDIS)},     /* LCD-Data(19) */
            {OFFSET(gpmc_ad12), (MODE(1) | PULLUDDIS)},     /* LCD-Data(20) */
            {OFFSET(gpmc_ad13), (MODE(1) | PULLUDDIS)},     /* LCD-Data(21) */
            {OFFSET(gpmc_ad14), (MODE(1) | PULLUDDIS)},     /* LCD-Data(22) */
            {OFFSET(gpmc_ad15), (MODE(1) | PULLUDDIS)},     /* LCD-Data(23) */
            {OFFSET(lcd_vsync), (MODE(0) | PULLUDDIS)},     /* LCD-VSync */
            {OFFSET(lcd_hsync), (MODE(0) | PULLUDDIS)},     /* LCD-HSync */
            {OFFSET(lcd_ac_bias_en), (MODE(0) | PULLUDDIS)},/* LCD-DE */
            {OFFSET(lcd_pclk), (MODE(0) | PULLUDDIS)},      /* LCD-CLK */

            {-1},
    };
    #endif

    #if defined(CONFIG_NAND)
                    configure_module_pin_mux(nand_pin_mux);
    #elif defined(CONFIG_EMMC_BOOT)
                    configure_module_pin_mux(mmc1_pin_mux);
    #endif
    #if 1 // added
                    configure_module_pin_mux(lcd_pin_mux);
    #endif
            } else if (board_is_sk() || board_is_idk()) {
                    configure_module_pin_mux(rgmii1_pin_mux);

    4. board/ti/am43xx/omap3_dss.c : created

    #include <asm/io.h>
    /*#include <asm/arch/dss.h>*/
    #include <video_fb.h>

    #ifndef DSS_H
    #define DSS_H

    /* DSS Base Registers */
    #define OMAP3_DSS_BASE          0x4832A000
    #define OMAP3_DISPC_BASE        0x4832A400
    /*#define OMAP3_VENC_BASE         0x48320C00*/
    #define OMAP3_RFBI_BASE         0x4832A800

    /* DSS Registers */
    struct dss_regs {
            u32 revision;                           /* 0x00 */
            u8 res1[12];                            /* 0x04 */
            u32 sysconfig;                          /* 0x10 */
            u32 sysstatus;                          /* 0x14 */
            u32 irqstatus;                          /* 0x18 */
            u8 res2[36];                            /* 0x1C */
            u32 control;                            /* 0x40 */
            u32 sdi_control;                        /* 0x44 */
            u32 pll_control;                        /* 0x48 */
    };

    /* DISPC Registers */
    struct dispc_regs {
            u32 revision;                           /* 0x00 */
            u8 res1[12];                            /* 0x04 */
            u32 sysconfig;                          /* 0x10 */
            u32 sysstatus;                          /* 0x14 */
            u32 irqstatus;                          /* 0x18 */
            u32 irqenable;                          /* 0x1C */
            u8 res2[32];                            /* 0x20 */
            u32 control;                            /* 0x40 */
            u32 config;                             /* 0x44 */
            u32 reserve_2;                          /* 0x48 */
            u32 default_color0;                     /* 0x4C */
            u32 default_color1;                     /* 0x50 */
            u32 trans_color0;                       /* 0x54 */
            u32 trans_color1;                       /* 0x58 */
            u32 line_status;                        /* 0x5C */
            u32 line_number;                        /* 0x60 */
            u32 timing_h;                           /* 0x64 */
            u32 timing_v;                           /* 0x68 */
            u32 pol_freq;                           /* 0x6C */
            u32 divisor;                            /* 0x70 */
            u32 global_alpha;                       /* 0x74 */
            u32 size_dig;                           /* 0x78 */
            u32 size_lcd;                           /* 0x7C */
            u32 gfx_ba0;                            /* 0x80 */
            u32 gfx_ba1;                            /* 0x84 */
            u32 gfx_position;                       /* 0x88 */
            u32 gfx_size;                           /* 0x8C */
            u8 unused[16];                          /* 0x90 */
            u32 gfx_attributes;                     /* 0xA0 */
            u32 gfx_fifo_threshold;                 /* 0xA4 */
            u32 gfx_fifo_size_status;               /* 0xA8 */
            u32 gfx_row_inc;                        /* 0xAC */
            u32 gfx_pixel_inc;                      /* 0xB0 */
            u32 gfx_window_skip;                    /* 0xB4 */
            u32 gfx_table_ba;                       /* 0xB8 */
    };

    /* Few Register Offsets */
    #define TFTSTN_SHIFT                            3
    #define DATALINES_SHIFT                         8

    #define GFX_ENABLE                              1
    #define GFX_FORMAT_SHIFT                        1
    #define LOADMODE_SHIFT                          1

    #define DSS_SOFTRESET                           (1 << 1)
    #define DSS_RESETDONE                           1

    /* Enabling Display controller */
    #define LCD_ENABLE                              1
    #define DIG_ENABLE                              (1 << 1)
    #define GO_LCD                                  (1 << 5)
    #define GO_DIG                                  (1 << 6)
    #define GP_OUT0                                 (1 << 15)
    #define GP_OUT1                                 (1 << 16)

    /* LCD display type */
    #define PASSIVE_DISPLAY                 0
    #define ACTIVE_DISPLAY                  1

    /* TFTDATALINES */
    #define LCD_INTERFACE_12_BIT    0
    #define LCD_INTERFACE_16_BIT    1
    #define LCD_INTERFACE_18_BIT    2
    #define LCD_INTERFACE_24_BIT    3

    /* Polarity */
    #define DSS_IVS         (1 << 12)
    #define DSS_IHS         (1 << 13)
    #define DSS_IPC         (1 << 14)
    #define DSS_IEO         (1 << 15)
    #define DSS_ONOFF       (1 << 17)

    /* GFX format */
    #define GFXFORMAT_BITMAP1               (0x0 << 1)
    #define GFXFORMAT_BITMAP2               (0x1 << 1)
    #define GFXFORMAT_BITMAP4               (0x2 << 1)
    #define GFXFORMAT_BITMAP8               (0x3 << 1)
    #define GFXFORMAT_RGB12                 (0x4 << 1)
    #define GFXFORMAT_ARGB16                (0x5 << 1)
    #define GFXFORMAT_RGB16                 (0x6 << 1)
    #define GFXFORMAT_RGB24_UNPACKED        (0x8 << 1)
    #define GFXFORMAT_RGB24_PACKED          (0x9 << 1)
    #define GFXFORMAT_ARGB32                (0xC << 1)
    #define GFXFORMAT_RGBA32                (0xD << 1)
    #define GFXFORMAT_RGBx32                (0xE << 1)

    /* Panel Configuration */
    struct panel_config {
            u32 timing_h;
            u32 timing_v;
            u32 pol_freq;
            u32 divisor;
            u32 lcd_size;
            u32 panel_type;
            u32 data_lines;
            u32 load_mode;
            u32 panel_color;
            u32 gfx_format;
            void *frame_buffer;
    };

    #define DSS_HBP(bp)    (((bp) - 1) << 20)
    #define DSS_HFP(fp)    (((fp) - 1) << 8)
    #define DSS_HSW(sw)    ((sw) - 1)
    #define DSS_VBP(bp)    ((bp) << 20)
    #define DSS_VFP(fp)    ((fp) << 8)
    #define DSS_VSW(sw)    ((sw) - 1)

    #define PANEL_TIMING_H(bp, fp, sw) (DSS_HBP(bp) | DSS_HFP(fp) | DSS_HSW(sw))
    #define PANEL_TIMING_V(bp, fp, sw) (DSS_VBP(bp) | DSS_VFP(fp) | DSS_VSW(sw))
    #define PANEL_LCD_SIZE(xres, yres) ((yres - 1) << 16 | (xres - 1))
    #endif

    /*     
     * Configure Timings for DVI D
     */
    static const struct panel_config dvid_cfg = {
            .timing_h       = 0x01d0631d, /* Horizontal timing */
            .timing_v       = 0x00a00a02, /* Vertical timing */
            .pol_freq       = 0x00027000, /* Pol Freq */
            .divisor        = 0x00010002, /* 72Mhz Pixel Clock */
            .lcd_size       = 0x031f04ff, /* 1280x800 */
            .panel_type     = 0x01, /* TFT */
            .data_lines     = 0x03, /* 24 Bit RGB */
            .load_mode      = 0x02, /* Frame Mode */
            .panel_color    = 0, /* BLACK */
            .gfx_format     = GFXFORMAT_RGB24_UNPACKED,
    };

    void omap3_dss_panel_config(const struct panel_config *panel_cfg)
    {
            struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
            struct dss_regs *dss = (struct dss_regs *) OMAP3_DSS_BASE;

            writel(DSS_SOFTRESET, &dss->sysconfig);
            while (!(readl(&dss->sysstatus) & DSS_RESETDONE))
                    ;

    //printf("%s: called, dispc->sysconfig = 0x%x.\n", __FUNCTION__,  readl(&dispc->sysconfig));
            writel(0x00002015, &dispc->sysconfig);

            writel(panel_cfg->timing_h, &dispc->timing_h);
            writel(panel_cfg->timing_v, &dispc->timing_v);
            writel(panel_cfg->pol_freq, &dispc->pol_freq);
            writel(panel_cfg->divisor, &dispc->divisor);
            writel(panel_cfg->lcd_size, &dispc->size_lcd);
            writel(panel_cfg->load_mode << LOADMODE_SHIFT, &dispc->config);
            writel( GP_OUT0 | GP_OUT1 |
                    panel_cfg->panel_type << TFTSTN_SHIFT |
                    panel_cfg->data_lines << DATALINES_SHIFT, &dispc->control);
            writel(panel_cfg->panel_color, &dispc->default_color0);
            writel((u32) panel_cfg->frame_buffer, &dispc->gfx_ba0);
            writel((u32) panel_cfg->frame_buffer, &dispc->gfx_ba1);

    #if 0
    printf("%s: dispc->config = 0x%x\n", __FUNCTION__, readl(&dispc->config));
    printf("%s: dispc->control = 0x%x\n", __FUNCTION__, readl(&dispc->control));
    printf("%s: panel_cfg->framebuffer = 0x%p\n", __FUNCTION__, panel_cfg->frame_buffer);
    #endif

            if (!panel_cfg->frame_buffer)
                    return;

            writel(0xa0 | panel_cfg->gfx_format | GFX_ENABLE, &dispc->gfx_attributes);

            writel(1, &dispc->gfx_row_inc);
            writel(1, &dispc->gfx_pixel_inc);
            writel(panel_cfg->lcd_size, &dispc->gfx_size);
    }

    /* Enable LCD and DIGITAL OUT in DSS */
    void omap3_dss_enable(void)
    {
            struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
            u32 l;

            l = readl(&dispc->control);
    #if 0
            l |= LCD_ENABLE | GO_LCD | DIG_ENABLE | GO_DIG | GP_OUT0 | GP_OUT1;
    #else
            l |= LCD_ENABLE | GO_LCD;
    #endif
            writel(l, &dispc->control);
    #if 0
    printf("%s: dispc->config = 0x%x\n", __FUNCTION__, readl(&dispc->config));
    printf("%s: dispc->control = 0x%x\n", __FUNCTION__, l);
    #endif
    }

    5. board/ti/am43xx/board.c

    #if 1   // added
    #include <mmc.h>
    #include <fat.h>
    #include <lcd.h>
    #endif


    static void enable_lcd_power(void)
    {
            u32 temp;

            puts("enable_lcd_power, 2.5V\n");

            /* enable module */
            writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO3_BASE + OMAP_GPIO_CTRL);
            /* enable output for GPIO3_17 */
            writel(GPIO_SETDATAOUT(17), AM33XX_GPIO3_BASE + OMAP_GPIO_SETDATAOUT);
            temp = readl(AM33XX_GPIO3_BASE + OMAP_GPIO_OE);
            temp = temp & ~(GPIO_OE_ENABLE(17));
            writel(temp, AM33XX_GPIO3_BASE + OMAP_GPIO_OE);

            udelay(200000);

            puts("enable_lcd_power\n");

            /* enable module */
            writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO0_BASE + OMAP_GPIO_CTRL);
            /* enable output for GPIO0_24 */
            writel(GPIO_SETDATAOUT(24), AM33XX_GPIO0_BASE + OMAP_GPIO_SETDATAOUT);
            temp = readl(AM33XX_GPIO0_BASE + OMAP_GPIO_OE);
            temp = temp & ~(GPIO_OE_ENABLE(24));
            writel(temp, AM33XX_GPIO0_BASE + OMAP_GPIO_OE);

            udelay(1000);

            {
                    // PRCM_CM_PER_DSS_CLKCTRL (0xa20)
                    writel(0x2, 0x44df8800 + 0xa20);

    printf("%s: Display PLL setup.\n", __FUNCTION__);
                    // Display PLL setup
                    {
                            // PRCM_CM_CLKMODE_DPLL_DISP (0x620); ST_MN_BYPASS
                            writel(0x4, 0x44df2800 + 0x620);
                            while (!(readl( 0x44df2800 + 0x624) & (0x1<<8)))
                                    ;

                            // PRCM_CM_CLKSEL_DPLL_DISP (0x62c) : DPLL_MULT & DPLL_DIV
                            writel(0xED27, 0x44df2800 + 0x62c);
                            // PRCM_CM_DIV_M2_DPLL_DISP(0x630) : DPLL_CLKOUT_DIV
                            writel(0x1, 0x44df2800 + 0x630);

                            // PRCM_CM_CLKMODE_DPLL_DISP (0x620) : ST_DPLL_CLK
                            writel(0x7, 0x44df2800 + 0x620);
                            while (!(readl( 0x44df2800 + 0x624) & 0x1))
                                    ;
                    }
    printf("%s: Display PLL setup done.\n", __FUNCTION__);

    #if 0
                    // CM_PER : 0x44DF8800 (Clock Module Peripheral Registers)
                    printf("PRCM_CM_PER_LCDC_CLKSTCTRL = 0x%x\n", readl( 0x44df8800 + 0x800));      // 0x2
                    printf("PRCM_CM_PER_DSS_CLKSTCTRL = 0x%x\n", readl( 0x44df8800 + 0xa00));       // 0xE02
                    printf("PRCM_CM_PER_DSS_CLKCTRL = 0x%x\n", readl( 0x44df8800 + 0xa20));         // 0x2
                    printf("\n");

                    // CM_WKUP : 0x44DF2800 (Clock Module Wakeup Registers)
                    printf("PRCM_CM_CLKMODE_DPLL_DISP = 0x%x\n", readl( 0x44df2800 + 0x620));       // 0x7
                    printf("PRCM_CM_IDLEST_DPLL_DISP = 0x%x\n", readl( 0x44df2800 + 0x624));        // 0x1
                    printf("PRCM_CM_CLKSEL_DPLL_DISP = 0x%x\n", readl( 0x44df2800 + 0x62c));        // 0xED27
                    printf("PRCM_CM_DIV_M2_DPLL_DISP = 0x%x\n", readl( 0x44df2800 + 0x630));        // 0x201
                    printf("\n");
    #endif
            }
    }

    void lcd_backlight_1(void)
    {
            u32 temp;

            puts("enable backlight power\n");

            /* enable module */
            writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO0_BASE + OMAP_GPIO_CTRL);
            /* enable output for GPIO0_7 */
            temp = readl(AM33XX_GPIO0_BASE + OMAP_GPIO_OE);
            temp = temp & ~(GPIO_OE_ENABLE(7));
            writel(temp, AM33XX_GPIO0_BASE + OMAP_GPIO_OE);

            /* enable module */
            writel(GPIO_CTRL_ENABLEMODULE, AM33XX_GPIO0_BASE + OMAP_GPIO_CTRL);
            /* enable output for GPIO0_3 */
            writel(GPIO_SETDATAOUT(3), AM33XX_GPIO0_BASE + OMAP_GPIO_SETDATAOUT);
            temp = readl(AM33XX_GPIO0_BASE + OMAP_GPIO_OE);
            temp = temp & ~(GPIO_OE_ENABLE(3));
            writel(temp, AM33XX_GPIO0_BASE + OMAP_GPIO_OE);
    }

    // added
    #if defined(CONFIG_LCD) && !defined(CONFIG_SPL_BUILD)

    #include "./omap3_dss.c"

    void dss_init(void);

    void lcdbacklight(int on)
    {
            enable_lcd_power();
    }

    vidinfo_t       panel_info = {
                    .vl_col = 1280,
                    .vl_row = 800,
                    .vl_bpix = 5,
                    .priv = 0
    };

    // call from common/lcd.c
    void lcd_ctrl_init(void *lcdbase)
    {
            lcdbacklight(1);
            dss_init();

            /* Modify panel into to real resolution */
            panel_info.vl_col = 1280;
            panel_info.vl_row = 800;

            lcd_set_flush_dcache(1);
    }

    // call from common/lcd.c
    void lcd_enable(void)
    {
    }

    void splash_screen(void)
    {
            struct mmc      *mmc = NULL;
            int             err;

            printf("%s: read splash.bmp.gz from device [mmc 0:1].\n", __FUNCTION__);

            mmc = find_mmc_device(0);
            if (!mmc)
                    printf("Error finding mmc device\n");

            mmc_init(mmc);

            err = fat_register_device(&mmc->block_dev,
                                            CONFIG_SYS_MMCSD_FS_BOOT_PARTITION);

            if (!err) {
                    err = file_fat_read("splash.bmp.gz", (void *)0x82000000, 0);
                    if (err < 0) {
                            printf("%s: can't found \"splash.bmp.gz\" from [mmc 0:1].\n", __FUNCTION__);
                    }
                    else {
                            bmp_display(0x82000000, 0, 0);
                    }
            }
            else {
                    printf("%s %s: mmc device not found.\n", __FILE__, __FUNCTION__);
            }

            // LCD display on
            lcd_backlight_1();
    }

    void dss_init(void)
    {
            struct panel_config *panel = (struct panel_config *)&dvid_cfg;


            panel->frame_buffer = (void *)gd->fb_base;
            omap3_dss_panel_config(panel);
            omap3_dss_enable();
    }
    #endif

    #ifdef CONFIG_BOARD_LATE_INIT
    int board_late_init(void)
    {
    // added
    #if !defined(CONFIG_SPL_BUILD)
            splash_screen();
    #endif

    #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
            set_board_info_env(NULL);

    6. scripts/check-config.sh  : modify
     
    CONFIG_SPLASH error -> modify from Error to warning

    7. splash.bmp.gz copy to SD card