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 <cyg/hal/karo_tx25.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 */
181 cyg_uint16 bit_count;
182 cyg_uint32 compression;
183 cyg_uint32 size_image;
184 cyg_int32 x_pels_per_meter;
185 cyg_int32 y_pels_per_meter;
187 cyg_uint32 clr_important;
188 } V3BITMAPINFOHEADER;
191 cyg_uint16 type; // Signatur
192 cyg_uint32 size; // Groesse der datei
193 cyg_uint16 reserved[2];
194 cyg_uint32 offset; // Offset der Pixeldaten
195 } __attribute__((packed)) BITMAPFILEHEADER;
197 #define lcd_reg_write(val, reg) __lcd_reg_write(val, reg, #reg)
198 static inline void __lcd_reg_write(cyg_uint32 val, unsigned short reg,
201 writel(val, LCDC_BASE + reg);
204 static inline cyg_uint32 lcd_reg_read(unsigned short reg)
208 val = readl(LCDC_BASE + reg);
213 static bool get_var(const char *name, void *val, int type)
217 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
218 (char *)name, val, type);
220 diag_printf("fconfig variable %s not set; fconfig -i is needed!\n",
226 static inline void lcdc_enable(int on)
228 cyg_uint32 cgcr1 = readl(CCM_BASE_ADDR + CLKCTL_CGR1);
235 writel(cgcr1, CCM_BASE_ADDR + CLKCTL_CGR1);
238 static inline int bytes_per_pixel(unsigned long bpp)
252 static void lcd_pin_cfg(void)
255 writel(1, IOMUXC_BASE_ADDR + 0x088);
256 writel(1, IOMUXC_BASE_ADDR + 0x08c);
257 writel(0, IOMUXC_BASE_ADDR + 0x0c8);
258 writel(0, IOMUXC_BASE_ADDR + 0x0cc);
259 writel(0, IOMUXC_BASE_ADDR + 0x0d0);
260 writel(0, IOMUXC_BASE_ADDR + 0x0d4);
261 writel(0, IOMUXC_BASE_ADDR + 0x0d8);
262 writel(0, IOMUXC_BASE_ADDR + 0x0dc);
263 writel(0, IOMUXC_BASE_ADDR + 0x0e0);
264 writel(0, IOMUXC_BASE_ADDR + 0x0e4);
265 writel(0, IOMUXC_BASE_ADDR + 0x0e8);
266 writel(0, IOMUXC_BASE_ADDR + 0x0ec);
267 writel(0, IOMUXC_BASE_ADDR + 0x0f0);
268 writel(0, IOMUXC_BASE_ADDR + 0x0f4);
269 writel(0, IOMUXC_BASE_ADDR + 0x0f8);
270 writel(0, IOMUXC_BASE_ADDR + 0x0fc);
271 writel(0, IOMUXC_BASE_ADDR + 0x100);
272 writel(0, IOMUXC_BASE_ADDR + 0x104);
273 writel(0, IOMUXC_BASE_ADDR + 0x108);
274 writel(0, IOMUXC_BASE_ADDR + 0x10c);
275 writel(0, IOMUXC_BASE_ADDR + 0x110);
276 writel(0, IOMUXC_BASE_ADDR + 0x114);
280 /* evaluate the config parameters */
281 static bool bootsplash_setup(LCDDIM *ldim, unsigned long img_len)
285 ok = get_var("lcd_buffer_addr", &ldim->frame_buffer, CONFIG_INT);
286 ok &= get_var("lcd_clk_period", &ldim->pixclk, CONFIG_INT);
287 ok &= get_var("lcd_clk_polarity", &ldim->pixclk_pol, CONFIG_BOOL);
289 ok &= get_var("lcd_panel_width", &ldim->width, CONFIG_INT);
290 ok &= get_var("lcd_panel_height", &ldim->height, CONFIG_INT);
291 ok &= get_var("lcd_bpp", &ldim->bpp, CONFIG_INT);
293 ok &= get_var("lcd_hsync_width", &ldim->hsync, CONFIG_INT);
294 ok &= get_var("lcd_hsync_polarity", &ldim->hsync_pol, CONFIG_BOOL);
295 ok &= get_var("lcd_margin_left", &ldim->left, CONFIG_INT);
296 ok &= get_var("lcd_margin_right", &ldim->right, CONFIG_INT);
298 ok &= get_var("lcd_vsync_width", &ldim->vsync, CONFIG_INT);
299 ok &= get_var("lcd_vsync_polarity", &ldim->vsync_pol, CONFIG_BOOL);
300 ok &= get_var("lcd_margin_top", &ldim->top, CONFIG_INT);
301 ok &= get_var("lcd_margin_bottom", &ldim->bottom, CONFIG_INT);
306 if (ldim->width < 16 || ldim->width > 1024) {
307 diag_printf("Invalid LCD panel width: %lu\n", ldim->width);
311 if (ldim->height < 1 || ldim->height > 511) {
312 diag_printf("Invalid LCD panel height: %lu\n", ldim->height);
316 if (ldim->hsync < 1 || ldim->hsync > 64) {
317 diag_printf("Invalid HSYNC width: %lu\n", ldim->hsync);
321 if (ldim->vsync > 63) {
322 diag_printf("Invalid VSYNC width: %lu\n", ldim->vsync);
326 if (ldim->left < 3 || ldim->left > 258) {
327 diag_printf("Invalid left margin: %lu\n", ldim->left);
331 if (ldim->right < 1 || ldim->right > 256) {
332 diag_printf("Invalid right margin: %lu\n", ldim->right);
336 if (ldim->top > 255) {
337 diag_printf("Invalid top margin: %lu\n", ldim->top);
341 if (ldim->bottom > 255) {
342 diag_printf("Invalid bottom margin: %lu\n", ldim->bottom);
348 diag_printf("Invalid color depth: %lu\n", ldim->bpp);
356 if (ldim->width * ldim->height * bytes_per_pixel(ldim->bpp) > img_len) {
357 diag_printf("LCD panel size %lux%lux%u = %lu does not match image size %lu\n",
358 ldim->width, ldim->height, bytes_per_pixel(ldim->bpp),
359 ldim->width * ldim->height * bytes_per_pixel(ldim->bpp),
367 /* initialize the LCD controller */
368 static bool bootsplash_display(LCDDIM *ldim)
370 unsigned long lcdc_clk = get_peri_clock(LCDC_CLK);
372 CYG_ADDRESS disp_addr_phys;
374 HAL_VIRT_TO_PHYS_ADDRESS(ldim->frame_buffer, disp_addr_phys);
376 diag_printf("LCD %lux%lu-%lu %lu.%03luMHz\n",
377 ldim->width, ldim->height, ldim->bpp,
378 1000000 / ldim->pixclk,
379 1000000000 / ldim->pixclk % 1000);
381 ldim->pixclk = 1000000000 / ldim->pixclk * 1000;
382 if (ldim->pixclk > lcdc_clk / 2) {
383 diag_printf("LCD pixel clock %lu too high; max.: %lu\n",
384 ldim->pixclk, lcdc_clk / 2);
388 pcr = lcdc_clk / ldim->pixclk;
390 diag_printf("LCD pixel clock %lu too low; min.: %lu\n",
391 ldim->pixclk, lcdc_clk / 128);
395 pcr |= PCR_TFT | PCR_COLOR | PCR_SCLK_SEL |
396 (ldim->vsync_pol * PCR_FLMPOL) |
397 (ldim->hsync_pol * PCR_LPPOL) |
398 (ldim->pixclk_pol * PCR_PIXPOL);
402 pcr |= PCR_PBSIZ_8 | PCR_BPIX_18;
406 pcr |= PCR_PBSIZ_8 | PCR_BPIX_16;
410 pcr |= PCR_BPIX_8 | PCR_END_BYTE_SWAP;
417 lcd_reg_write(VPW_VPW(ldim->width * ldim->bpp / 8 / 4), LCDC_VPW);
418 lcd_reg_write(HCR_H_WIDTH(ldim->hsync - 1) | HCR_H_WAIT_2(ldim->left - 3) |
419 HCR_H_WAIT_1(ldim->right - 1), LCDC_HCR);
420 lcd_reg_write(VCR_V_WIDTH(ldim->vsync) | VCR_V_WAIT_2(ldim->top) |
421 VCR_V_WAIT_1(ldim->bottom), LCDC_VCR);
422 lcd_reg_write(SIZE_XMAX(ldim->width) | SIZE_YMAX(ldim->height), LCDC_SIZE);
423 lcd_reg_write(pcr, LCDC_PCR);
424 lcd_reg_write(0, LCDC_PWMR);
425 lcd_reg_write(0, LCDC_LSCR1);
426 lcd_reg_write(0x80040060, LCDC_DMACR);
428 lcd_reg_write(disp_addr_phys, LCDC_SSA);
429 lcd_reg_write(0, LCDC_POS);
430 lcd_reg_write(0, LCDC_CPOS);
431 lcd_reg_write(0, LCDC_RMCR);
435 while (!(lcd_reg_read(LCDC_LCDISR) & LCDISR_EOF));
437 gpio_set_bit(LCD_POWER_GPIO / 32 + 1, LCD_POWER_GPIO % 32);
438 gpio_set_bit(LCD_RESET_GPIO / 32 + 1, LCD_RESET_GPIO % 32);
440 HAL_DELAY_US(300000);
441 gpio_clr_bit(LCD_BACKLIGHT_GPIO / 32 + 1, LCD_BACKLIGHT_GPIO % 32);
446 static void set_pixel(LCDDIM *ldim, unsigned short x, unsigned short y,
447 unsigned char red, unsigned char green, unsigned char blue)
449 unsigned int offset = y * ldim->width + x;
450 unsigned short *fb = (unsigned short *)(ldim->frame_buffer + offset);
452 *fb = ((red & 0x1f) << 11) |
453 ((green & 0x3f) << 5) |
454 ((blue & 0x1f) << 0);
457 static unsigned long paint_test_picture(LCDDIM *ldim)
459 const int stripes = 8;
460 const unsigned int fill_size = ldim->width * ldim->height / stripes;
461 cyg_uint16 *frame_pointer = ldim->frame_buffer;
464 memset(frame_pointer, 0, fill_size * bytes_per_pixel(ldim->bpp));
465 frame_pointer += fill_size;
467 for (x = 0; x < fill_size; x++) {
468 *frame_pointer++ = 0xf800; // red screen
471 for (x = 0; x < fill_size; x++) {
472 *frame_pointer++ = 0x07e0; // green screen
475 for (x = 0; x < fill_size; x++) {
476 *frame_pointer++ = 0x001f; // blue screen
479 for (x = 0; x < fill_size; x++) {
480 *frame_pointer++ = 0x07ff; // yellow screen
483 for (x = 0; x < fill_size; x++) {
484 *frame_pointer++ = 0xf81f; // magenta screen
487 for (x = 0; x < fill_size; x++) {
488 *frame_pointer++ = 0xffe0; // cyan screen
491 memset(frame_pointer, 0xff, fill_size * bytes_per_pixel(ldim->bpp));
492 frame_pointer += fill_size;
494 // draw a white frame
495 for (x = 0; x < ldim->width; x++)
496 set_pixel(ldim, x, 0,
499 for (x = 0; x < ldim->height; x++)
500 set_pixel(ldim, ldim->width - 1, x,
503 for (x = 0; x < ldim->width; x++)
504 set_pixel(ldim, x, ldim->height - 1,
507 for (x = 0; x < ldim->height; x++)
508 set_pixel(ldim, 0, x,
512 for (x = 0; x < ldim->width; x++)
513 set_pixel(ldim, x, x * ldim->height / ldim->width,
514 (x & 1) * 0xff, (x & 1) * 0xff, (x & 1) * 0xff);
516 for (x = 0; x < ldim->width; x++)
517 set_pixel(ldim, ldim->width - x - 1, x * ldim->height / ldim->width,
518 (x & 1) * 0xff, (x & 1) * 0xff, (x & 1) * 0xff);
519 return (frame_pointer - ldim->frame_buffer) * bytes_per_pixel(ldim->bpp);
522 static void load_bitmap(LCDDIM *ldim, void *ram_addr,
523 unsigned long img_len)
526 cyg_uint8 red, green, blue;
529 BITMAPFILEHEADER bmfh;
530 V3BITMAPINFOHEADER bmih;
533 /* copy bitmap file header */
534 memcpy(&bmfh, ram_addr, sizeof(bmfh));
536 /* copy bitmap info header */
537 memcpy(&bmih, (cyg_uint8 *)ram_addr + sizeof(bmfh), sizeof(bmih));
539 if (bmfh.type != 0x4d42) {
540 if (ldim->width * ldim->height * bytes_per_pixel(ldim->bpp) > img_len) {
541 diag_printf("LCD panel size %lux%lux%u = %lu does not match image size %lu\n",
542 ldim->width, ldim->height, bytes_per_pixel(ldim->bpp),
543 ldim->width * ldim->height * bytes_per_pixel(ldim->bpp),
547 memcpy(ldim->frame_buffer, ram_addr, img_len);
551 if (bmfh.offset >= bmfh.size) {
552 diag_printf("Corrupted BMP header\n");
556 if (bmih.size != BMP_HEADER_V3_SIZE ) {
557 diag_printf("** ERROR: unsupported bitmap header version, structure size must be %u\n",
562 if (bmih.bit_count != 24) {
563 diag_printf("** ERROR: only 24 bit BMP files are supported\n");
567 if ((bmih.width != ldim->width) || (bmih.height != ldim->height)) {
568 diag_printf("** ERROR: BMP image size %ux%u does not match configured size: %lux%lu\n",
569 bmih.width, bmih.height, ldim->width, ldim->height);
573 /* pointer to picture data */
574 sp = (cyg_uint8 *)ram_addr + bmfh.offset;
576 if (bmih.bit_count == 16) {
577 for (line = ldim->height; line > 0; line--) {
578 memcpy(ldim->frame_buffer + (line - 1) * ldim->width,
579 sp, ldim->width * 2);
580 sp += ldim->width * 2;
585 for (line = ldim->height; line > 0; line--) {
586 ppixel = ldim->frame_buffer + (line - 1) * ldim->width;
587 for (col = 0; col < ldim->width; col ++) {
588 blue = *sp++ >> 3; // 5 bits
589 green = *sp++ >> 2; // 6 bits
590 red = *sp++ >> 3; // 5 bits
591 *ppixel++ = ((red << 11) | (green << 5) | (blue << 0));
597 paint_test_picture(ldim);
601 * load the logo from nand flash to memory.
603 static bool do_logo_load(LCDDIM *ldim)
608 unsigned int logo_size;
609 struct fis_image_desc *img;
612 /* Read the logo from storage media */
613 if ((img = fis_lookup("logo", NULL)) == NULL) {
614 diag_printf("No logo partition found in the fis table, logo not loaded\n");
618 fis_addr = (void *)img->flash_base;
619 ram_addr = (void *)img->mem_base;
621 logo_size = img->data_length;
622 ret = FLASH_READ(fis_addr, ram_addr, logo_size, &err_addr);
624 diag_printf("Loading logo from FLASH to MEMORY failed. error code: %d", ret);
627 if (!bootsplash_setup(ldim, logo_size)) {
628 diag_printf("Cannot init splash screen; Invalid display parameters\n");
631 load_bitmap(ldim, ram_addr, logo_size);
632 bootsplash_display(ldim);
636 static void redboot_bootsplash_display(void)
638 bool bootsplash_feature_enable;
642 gpio_set_bit(LCD_RESET_GPIO / 32, LCD_RESET_GPIO % 32);
643 gpio_set_bit(LCD_POWER_GPIO / 32, LCD_POWER_GPIO % 32);
644 gpio_set_bit(LCD_BACKLIGHT_GPIO / 32, LCD_BACKLIGHT_GPIO % 32);
646 ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
648 &bootsplash_feature_enable, CONFIG_BOOL);
650 diag_printf("fconfig variable bootsplash_enable not found\n");
652 if (ok && bootsplash_feature_enable) {
657 #ifdef CYGPKG_REDBOOT
658 RedBoot_init(redboot_bootsplash_display, RedBoot_INIT_SECOND);
660 RedBoot_config_option("Enable splash display at boot",
662 ALWAYS_ENABLED, true,
667 RedBoot_config_option("LCD frame buffer address",
669 "bootsplash_enable", true,
671 RAM_BANK0_BASE + RAM_BANK0_SIZE
674 RedBoot_config_option("Pixel clock period (in ps)",
676 "bootsplash_enable", true,
681 RedBoot_config_option("Pixel clock polarity active low",
683 "bootsplash_enable", true,
688 RedBoot_config_option("LCD panel width (in pixels)",
690 "bootsplash_enable", true,
695 RedBoot_config_option("LCD panel height (in pixels)",
697 "bootsplash_enable", true,
702 RedBoot_config_option("LCD color depth (BPP)",
704 "bootsplash_enable", true,
709 RedBoot_config_option("HSYNC pulse width (in pixels)",
711 "bootsplash_enable", true,
716 RedBoot_config_option("HSYNC polarity active low",
718 "bootsplash_enable", true,
723 RedBoot_config_option("Left margin (in pixels)",
725 "bootsplash_enable", true,
730 RedBoot_config_option("Right margin (in pixels)",
732 "bootsplash_enable", true,
737 RedBoot_config_option("VSYNC pulse width (in scan lines)",
739 "bootsplash_enable", true,
744 RedBoot_config_option("VSYNC polarity active low",
746 "bootsplash_enable", true,
751 RedBoot_config_option("Top margin (in scan lines)",
753 "bootsplash_enable", true,
758 RedBoot_config_option("Bottom margin (in scan lines)",
760 "bootsplash_enable", true,