1 //==========================================================================
5 // TX25 Bootsplash Implementation
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
42 #include <pkgconf/hal.h>
43 #include <pkgconf/system.h>
47 #include <cyg/infra/cyg_type.h>
48 #include <cyg/io/flash.h>
49 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
50 #include <flash_config.h>
52 #ifdef CYGOPT_REDBOOT_FIS
55 #include CYGBLD_HAL_PLATFORM_H
56 #include <cyg/hal/plf_mmap.h>
57 #include CYGBLD_HAL_PLF_DEFS_H // Platform specific hardware definitions
59 #define LCDC_BASE 0x53fbc000
63 #define LCDC_SIZE 0x04
64 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
66 #define SIZE_YMAX(y) ((y) & 0x3ff)
69 #define VPW_VPW(x) ((x) & 0x3ff)
71 #define LCDC_CPOS 0x0C
72 #define CPOS_CC1 (1 << 31)
73 #define CPOS_CC0 (1 << 30)
74 #define CPOS_OP (1 << 28)
75 #define CPOS_CXP(x) (((x) & 3ff) << 16)
77 #define CPOS_CYP(y) ((y) & 0x3ff)
79 #define LCDC_LCWHB 0x10
80 #define LCWHB_BK_EN (1 << 31)
81 #define LCWHB_CW(w) (((w) & 0x1f) << 24)
82 #define LCWHB_CH(h) (((h) & 0x1f) << 16)
83 #define LCWHB_BD(x) ((x) & 0xff)
85 #define LCDC_LCHCC 0x14
87 #define LCHCC_CUR_COL_R(r) (((r) & 0x3f) << 12)
88 #define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 6)
89 #define LCHCC_CUR_COL_B(b) ((b) & 0x3f)
93 #define PCR_TFT (1 << 31)
94 #define PCR_COLOR (1 << 30)
95 #define PCR_PBSIZ_1 (0 << 28)
96 #define PCR_PBSIZ_2 (1 << 28)
97 #define PCR_PBSIZ_4 (2 << 28)
98 #define PCR_PBSIZ_8 (3 << 28)
99 #define PCR_BPIX_1 (0 << 25)
100 #define PCR_BPIX_2 (1 << 25)
101 #define PCR_BPIX_4 (2 << 25)
102 #define PCR_BPIX_8 (3 << 25)
103 #define PCR_BPIX_12 (4 << 25)
104 #define PCR_BPIX_16 (5 << 25)
105 #define PCR_BPIX_18 (6 << 25)
106 #define PCR_PIXPOL (1 << 24)
107 #define PCR_FLMPOL (1 << 23)
108 #define PCR_LPPOL (1 << 22)
109 #define PCR_CLKPOL (1 << 21)
110 #define PCR_OEPOL (1 << 20)
111 #define PCR_SCLKIDLE (1 << 19)
112 #define PCR_END_SEL (1 << 18)
113 #define PCR_END_BYTE_SWAP (1 << 17)
114 #define PCR_REV_VS (1 << 16)
115 #define PCR_ACD_SEL (1 << 15)
116 #define PCR_ACD(x) (((x) & 0x7f) << 8)
117 #define PCR_SCLK_SEL (1 << 7)
118 #define PCR_SHARP (1 << 6)
119 #define PCR_PCD(x) ((x) & 0x3f)
121 #define LCDC_HCR 0x1C
122 #define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
123 #define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
124 #define HCR_H_WAIT_2(x) ((x) & 0xff)
126 #define LCDC_VCR 0x20
127 #define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
128 #define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
129 #define VCR_V_WAIT_2(x) ((x) & 0xff)
131 #define LCDC_POS 0x24
132 #define POS_POS(x) ((x) & 1f)
134 #define LCDC_LSCR1 0x28
136 #define LCDC_PWMR 0x2C
138 #define LCDC_DMACR 0x30
140 #define LCDC_RMCR 0x34
142 #define RMCR_SELF_REF (1 << 0)
144 #define LCDC_LCDICR 0x38
145 #define LCDICR_INT_SYN (1 << 2)
146 #define LCDICR_INT_CON (1)
148 #define LCDC_LCDISR 0x40
149 #define LCDISR_UDR_ERR (1 << 3)
150 #define LCDISR_ERR_RES (1 << 2)
151 #define LCDISR_EOF (1 << 1)
152 #define LCDISR_BOF (1 << 0)
154 #define BMP_MAGIC 0x4D42
155 #define BMP_HEADER_V3_SIZE sizeof(V3BITMAPINFOHEADER)
157 typedef struct lcd_display_metrics {
158 cyg_uint16 *frame_buffer;
159 unsigned long pixclk;
161 unsigned long height;
165 /* margin settings */
167 unsigned long bottom;
170 /* control signal polarities */
182 cyg_uint16 bit_count;
183 cyg_uint32 compression;
184 cyg_uint32 size_image;
185 cyg_int32 x_pels_per_meter;
186 cyg_int32 y_pels_per_meter;
188 cyg_uint32 clr_important;
189 } V3BITMAPINFOHEADER;
192 cyg_uint16 type; // Signatur
193 cyg_uint32 size; // Groesse der datei
194 cyg_uint16 reserved[2];
195 cyg_uint32 offset; // Offset der Pixeldaten
196 } __attribute__((packed)) BITMAPFILEHEADER;
198 #define lcd_reg_write(val, reg) __lcd_reg_write(val, reg, #reg)
199 static inline void __lcd_reg_write(cyg_uint32 val, unsigned short reg,
202 writel(val, LCDC_BASE + reg);
205 static inline cyg_uint32 lcd_reg_read(unsigned short reg)
209 val = readl(LCDC_BASE + reg);
214 static bool get_var(const char *name, void *val, int type)
218 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
219 (char *)name, val, type);
221 diag_printf("fconfig variable %s not set; fconfig -i is needed!\n",
227 static inline void lcdc_enable(int on)
229 cyg_uint32 cgcr1 = readl(CCM_BASE_ADDR + CLKCTL_CGR1);
236 writel(cgcr1, CCM_BASE_ADDR + CLKCTL_CGR1);
239 static inline int bytes_per_pixel(unsigned long bpp)
253 static void lcd_pin_cfg(void)
256 writel(1, IOMUXC_BASE_ADDR + 0x088);
257 writel(1, IOMUXC_BASE_ADDR + 0x08c);
258 writel(0, IOMUXC_BASE_ADDR + 0x0c8);
259 writel(0, IOMUXC_BASE_ADDR + 0x0cc);
260 writel(0, IOMUXC_BASE_ADDR + 0x0d0);
261 writel(0, IOMUXC_BASE_ADDR + 0x0d4);
262 writel(0, IOMUXC_BASE_ADDR + 0x0d8);
263 writel(0, IOMUXC_BASE_ADDR + 0x0dc);
264 writel(0, IOMUXC_BASE_ADDR + 0x0e0);
265 writel(0, IOMUXC_BASE_ADDR + 0x0e4);
266 writel(0, IOMUXC_BASE_ADDR + 0x0e8);
267 writel(0, IOMUXC_BASE_ADDR + 0x0ec);
268 writel(0, IOMUXC_BASE_ADDR + 0x0f0);
269 writel(0, IOMUXC_BASE_ADDR + 0x0f4);
270 writel(0, IOMUXC_BASE_ADDR + 0x0f8);
271 writel(0, IOMUXC_BASE_ADDR + 0x0fc);
272 writel(0, IOMUXC_BASE_ADDR + 0x100);
273 writel(0, IOMUXC_BASE_ADDR + 0x104);
274 writel(0, IOMUXC_BASE_ADDR + 0x108);
275 writel(0, IOMUXC_BASE_ADDR + 0x10c);
276 writel(0, IOMUXC_BASE_ADDR + 0x110);
277 writel(0, IOMUXC_BASE_ADDR + 0x114);
281 /* evaluate the config parameters */
282 static bool bootsplash_setup(LCDDIM *ldim, unsigned long img_len)
286 ok = get_var("lcd_buffer_addr", &ldim->frame_buffer, CONFIG_INT);
287 ok &= get_var("lcd_clk_period", &ldim->pixclk, CONFIG_INT);
288 ok &= get_var("lcd_clk_polarity", &ldim->clk_pol, CONFIG_BOOL);
289 ok &= get_var("lcd_pix_polarity", &ldim->pix_pol, CONFIG_BOOL);
291 ok &= get_var("lcd_panel_width", &ldim->width, CONFIG_INT);
292 ok &= get_var("lcd_panel_height", &ldim->height, CONFIG_INT);
293 ok &= get_var("lcd_bpp", &ldim->bpp, CONFIG_INT);
295 ok &= get_var("lcd_hsync_width", &ldim->hsync, CONFIG_INT);
296 ok &= get_var("lcd_hsync_polarity", &ldim->hsync_pol, CONFIG_BOOL);
297 ok &= get_var("lcd_margin_left", &ldim->left, CONFIG_INT);
298 ok &= get_var("lcd_margin_right", &ldim->right, CONFIG_INT);
300 ok &= get_var("lcd_vsync_width", &ldim->vsync, CONFIG_INT);
301 ok &= get_var("lcd_vsync_polarity", &ldim->vsync_pol, CONFIG_BOOL);
302 ok &= get_var("lcd_margin_top", &ldim->top, CONFIG_INT);
303 ok &= get_var("lcd_margin_bottom", &ldim->bottom, CONFIG_INT);
308 if (ldim->width < 16 || ldim->width > 1024) {
309 diag_printf("Invalid LCD panel width: %lu\n", ldim->width);
313 if (ldim->height < 1 || ldim->height > 511) {
314 diag_printf("Invalid LCD panel height: %lu\n", ldim->height);
318 if (ldim->hsync < 1 || ldim->hsync > 64) {
319 diag_printf("Invalid HSYNC width: %lu\n", ldim->hsync);
323 if (ldim->vsync > 63) {
324 diag_printf("Invalid VSYNC width: %lu\n", ldim->vsync);
328 if (ldim->left < 3 || ldim->left > 258) {
329 diag_printf("Invalid left margin: %lu\n", ldim->left);
333 if (ldim->right < 1 || ldim->right > 256) {
334 diag_printf("Invalid right margin: %lu\n", ldim->right);
338 if (ldim->top > 255) {
339 diag_printf("Invalid top margin: %lu\n", ldim->top);
343 if (ldim->bottom > 255) {
344 diag_printf("Invalid bottom margin: %lu\n", ldim->bottom);
350 diag_printf("Invalid color depth: %lu\n", ldim->bpp);
358 if (ldim->width * ldim->height * bytes_per_pixel(ldim->bpp) > img_len) {
359 diag_printf("LCD panel size %lux%lux%u = %lu does not match image size %lu\n",
360 ldim->width, ldim->height, bytes_per_pixel(ldim->bpp),
361 ldim->width * ldim->height * bytes_per_pixel(ldim->bpp),
369 /* initialize the LCD controller */
370 static bool bootsplash_display(LCDDIM *ldim)
372 unsigned long lcdc_clk = get_peri_clock(LCDC_CLK);
374 CYG_ADDRESS disp_addr_phys;
376 HAL_VIRT_TO_PHYS_ADDRESS(ldim->frame_buffer, disp_addr_phys);
378 diag_printf("LCD %lux%lu-%lu %lu.%03luMHz\n",
379 ldim->width, ldim->height, ldim->bpp,
380 1000000 / ldim->pixclk,
381 1000000000 / ldim->pixclk % 1000);
383 ldim->pixclk = 1000000000 / ldim->pixclk * 1000;
384 if (ldim->pixclk > lcdc_clk / 2) {
385 diag_printf("LCD pixel clock %lu too high; max.: %lu\n",
386 ldim->pixclk, lcdc_clk / 2);
390 pcr = lcdc_clk / ldim->pixclk;
392 diag_printf("LCD pixel clock %lu too low; min.: %lu\n",
393 ldim->pixclk, lcdc_clk / 128);
397 pcr |= PCR_TFT | PCR_COLOR | PCR_SCLK_SEL |
398 (ldim->vsync_pol * PCR_FLMPOL) |
399 (ldim->hsync_pol * PCR_LPPOL) |
400 (ldim->pix_pol * PCR_PIXPOL) |
401 (ldim->clk_pol * PCR_CLKPOL);
405 pcr |= PCR_PBSIZ_8 | PCR_BPIX_18;
409 pcr |= PCR_PBSIZ_8 | PCR_BPIX_16;
413 pcr |= PCR_BPIX_8 | PCR_END_BYTE_SWAP;
420 lcd_reg_write(VPW_VPW(ldim->width * ldim->bpp / 8 / 4), LCDC_VPW);
421 lcd_reg_write(HCR_H_WIDTH(ldim->hsync - 1) | HCR_H_WAIT_2(ldim->left - 3) |
422 HCR_H_WAIT_1(ldim->right - 1), LCDC_HCR);
423 lcd_reg_write(VCR_V_WIDTH(ldim->vsync) | VCR_V_WAIT_2(ldim->top) |
424 VCR_V_WAIT_1(ldim->bottom), LCDC_VCR);
425 lcd_reg_write(SIZE_XMAX(ldim->width) | SIZE_YMAX(ldim->height), LCDC_SIZE);
426 lcd_reg_write(pcr, LCDC_PCR);
427 lcd_reg_write(0, LCDC_PWMR);
428 lcd_reg_write(0, LCDC_LSCR1);
429 lcd_reg_write(0x80040060, LCDC_DMACR);
431 lcd_reg_write(disp_addr_phys, LCDC_SSA);
432 lcd_reg_write(0, LCDC_POS);
433 lcd_reg_write(0, LCDC_CPOS);
434 lcd_reg_write(0, LCDC_RMCR);
438 while (!(lcd_reg_read(LCDC_LCDISR) & LCDISR_EOF));
440 gpio_set_bit(LCD_POWER_GPIO / 32 + 1, LCD_POWER_GPIO % 32);
441 gpio_set_bit(LCD_RESET_GPIO / 32 + 1, LCD_RESET_GPIO % 32);
443 HAL_DELAY_US(300000);
444 gpio_clr_bit(LCD_BACKLIGHT_GPIO / 32 + 1, LCD_BACKLIGHT_GPIO % 32);
449 static void set_pixel(LCDDIM *ldim, unsigned short x, unsigned short y,
450 unsigned char red, unsigned char green, unsigned char blue)
452 unsigned int offset = y * ldim->width + x;
453 unsigned short *fb = (unsigned short *)(ldim->frame_buffer + offset);
455 *fb = ((red & 0x1f) << 11) |
456 ((green & 0x3f) << 5) |
457 ((blue & 0x1f) << 0);
460 static unsigned long paint_test_picture(LCDDIM *ldim)
462 const int stripes = 8;
463 const unsigned int fill_size = ldim->width * ldim->height / stripes;
464 cyg_uint16 *frame_pointer = ldim->frame_buffer;
467 memset(frame_pointer, 0, fill_size * bytes_per_pixel(ldim->bpp));
468 frame_pointer += fill_size;
470 for (x = 0; x < fill_size; x++) {
471 *frame_pointer++ = 0xf800; // red screen
474 for (x = 0; x < fill_size; x++) {
475 *frame_pointer++ = 0x07e0; // green screen
478 for (x = 0; x < fill_size; x++) {
479 *frame_pointer++ = 0x001f; // blue screen
482 for (x = 0; x < fill_size; x++) {
483 *frame_pointer++ = 0x07ff; // yellow screen
486 for (x = 0; x < fill_size; x++) {
487 *frame_pointer++ = 0xf81f; // magenta screen
490 for (x = 0; x < fill_size; x++) {
491 *frame_pointer++ = 0xffe0; // cyan screen
494 memset(frame_pointer, 0xff, fill_size * bytes_per_pixel(ldim->bpp));
495 frame_pointer += fill_size;
497 // draw a white frame
498 for (x = 0; x < ldim->width; x++)
499 set_pixel(ldim, x, 0,
502 for (x = 0; x < ldim->height; x++)
503 set_pixel(ldim, ldim->width - 1, x,
506 for (x = 0; x < ldim->width; x++)
507 set_pixel(ldim, x, ldim->height - 1,
510 for (x = 0; x < ldim->height; x++)
511 set_pixel(ldim, 0, x,
515 for (x = 0; x < ldim->width; x++)
516 set_pixel(ldim, x, x * ldim->height / ldim->width,
517 (x & 1) * 0xff, (x & 1) * 0xff, (x & 1) * 0xff);
519 for (x = 0; x < ldim->width; x++)
520 set_pixel(ldim, ldim->width - x - 1, x * ldim->height / ldim->width,
521 (x & 1) * 0xff, (x & 1) * 0xff, (x & 1) * 0xff);
522 return (frame_pointer - ldim->frame_buffer) * bytes_per_pixel(ldim->bpp);
525 static void load_bitmap(LCDDIM *ldim, void *ram_addr,
526 unsigned long img_len)
529 cyg_uint8 red, green, blue;
532 BITMAPFILEHEADER bmfh;
533 V3BITMAPINFOHEADER bmih;
536 /* copy bitmap file header */
537 memcpy(&bmfh, ram_addr, sizeof(bmfh));
539 /* copy bitmap info header */
540 memcpy(&bmih, (cyg_uint8 *)ram_addr + sizeof(bmfh), sizeof(bmih));
542 if (bmfh.type != 0x4d42) {
543 if (ldim->width * ldim->height * bytes_per_pixel(ldim->bpp) > img_len) {
544 diag_printf("LCD panel size %lux%lux%u = %lu does not match image size %lu\n",
545 ldim->width, ldim->height, bytes_per_pixel(ldim->bpp),
546 ldim->width * ldim->height * bytes_per_pixel(ldim->bpp),
550 memcpy(ldim->frame_buffer, ram_addr, img_len);
554 if (bmfh.offset >= bmfh.size) {
555 diag_printf("Corrupted BMP header\n");
559 if (bmih.size != BMP_HEADER_V3_SIZE ) {
560 diag_printf("** ERROR: unsupported bitmap header version, structure size must be %u\n",
565 if (bmih.bit_count != 24) {
566 diag_printf("** ERROR: only 24 bit BMP files are supported\n");
570 if ((bmih.width != ldim->width) || (bmih.height != ldim->height)) {
571 diag_printf("** ERROR: BMP image size %ux%u does not match configured size: %lux%lu\n",
572 bmih.width, bmih.height, ldim->width, ldim->height);
576 /* pointer to picture data */
577 sp = (cyg_uint8 *)ram_addr + bmfh.offset;
579 if (bmih.bit_count == 16) {
580 for (line = ldim->height; line > 0; line--) {
581 memcpy(ldim->frame_buffer + (line - 1) * ldim->width,
582 sp, ldim->width * 2);
583 sp += ldim->width * 2;
588 for (line = ldim->height; line > 0; line--) {
589 ppixel = ldim->frame_buffer + (line - 1) * ldim->width;
590 for (col = 0; col < ldim->width; col ++) {
591 blue = *sp++ >> 3; // 5 bits
592 green = *sp++ >> 2; // 6 bits
593 red = *sp++ >> 3; // 5 bits
594 *ppixel++ = ((red << 11) | (green << 5) | (blue << 0));
600 paint_test_picture(ldim);
604 * load the logo from nand flash to memory.
606 static bool do_logo_load(LCDDIM *ldim)
611 unsigned int logo_size;
612 struct fis_image_desc *img;
615 /* Read the logo from storage media */
616 if ((img = fis_lookup("logo", NULL)) == NULL) {
617 diag_printf("No logo partition found in the fis table, logo not loaded\n");
621 fis_addr = (void *)img->flash_base;
622 ram_addr = (void *)img->mem_base;
624 logo_size = img->data_length;
625 ret = FLASH_READ(fis_addr, ram_addr, logo_size, &err_addr);
627 diag_printf("Loading logo from FLASH to MEMORY failed. error code: %d", ret);
630 if (!bootsplash_setup(ldim, logo_size)) {
631 diag_printf("Cannot init splash screen; Invalid display parameters\n");
634 load_bitmap(ldim, ram_addr, logo_size);
635 bootsplash_display(ldim);
639 static void redboot_bootsplash_display(void)
641 bool bootsplash_feature_enable;
645 gpio_set_bit(LCD_RESET_GPIO / 32, LCD_RESET_GPIO % 32);
646 gpio_set_bit(LCD_POWER_GPIO / 32, LCD_POWER_GPIO % 32);
647 gpio_set_bit(LCD_BACKLIGHT_GPIO / 32, LCD_BACKLIGHT_GPIO % 32);
649 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
651 &bootsplash_feature_enable, CONFIG_BOOL);
653 diag_printf("fconfig variable bootsplash_enable not found\n");
655 if (ok && bootsplash_feature_enable) {
660 #ifdef CYGPKG_REDBOOT
661 RedBoot_init(redboot_bootsplash_display, RedBoot_INIT_SECOND);
663 RedBoot_config_option("Enable splash display at boot",
665 ALWAYS_ENABLED, true,
670 RedBoot_config_option("LCD frame buffer address",
672 "bootsplash_enable", true,
674 RAM_BANK0_BASE + RAM_BANK0_SIZE
677 RedBoot_config_option("Pixel clock period (in ps)",
679 "bootsplash_enable", true,
684 RedBoot_config_option("Pixel polarity active low",
686 "bootsplash_enable", true,
691 RedBoot_config_option("Pixel clock polarity active low",
693 "bootsplash_enable", true,
698 RedBoot_config_option("LCD panel width (in pixels)",
700 "bootsplash_enable", true,
705 RedBoot_config_option("LCD panel height (in pixels)",
707 "bootsplash_enable", true,
712 RedBoot_config_option("LCD color depth (BPP)",
714 "bootsplash_enable", true,
719 RedBoot_config_option("HSYNC pulse width (in pixels)",
721 "bootsplash_enable", true,
726 RedBoot_config_option("HSYNC polarity active low",
728 "bootsplash_enable", true,
733 RedBoot_config_option("Left margin (in pixels)",
735 "bootsplash_enable", true,
740 RedBoot_config_option("Right margin (in pixels)",
742 "bootsplash_enable", true,
747 RedBoot_config_option("VSYNC pulse width (in scan lines)",
749 "bootsplash_enable", true,
754 RedBoot_config_option("VSYNC polarity active low",
756 "bootsplash_enable", true,
761 RedBoot_config_option("Top margin (in scan lines)",
763 "bootsplash_enable", true,
768 RedBoot_config_option("Bottom margin (in scan lines)",
770 "bootsplash_enable", true,