/*++ WMT Dual Boot Driver Copyright (c) 2014 WonderMedia Technologies, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . WonderMedia Technologies, Inc. 2014-2-25, HowayHuo, ShenZhen --*/ /*--- History ------------------------------------------------------------------- * DATE | AUTHORS | DESCRIPTION * 2014/2/25 Howay Huo v1.0, First Release * * *------------------------------------------------------------------------------*/ /*----------------------------------------- Logo Layout in Nand Flash ---------------------------------------- logo layout: android-logo <-> charging-logo <-> dualboot-android-logo <-> dualboot-ubuntu-logo <-> ubuntu-logo 1. android logo 2. charging logo 3. dualboot android logo 4. dualboot ubuntu logo 5. ubuntu logo Merge logo: cat u-boot-logo.bmp charge-logo.bmp dualboot-android-logo.bmp dualboot-ubuntu-logo.bmp ubuntu-logo.bmp > logo.out Burn logo.out to Nand Flash --------------------------------------------------------------------------------------------------------------*/ #include #include #include #include "../wmt_display/minivgui.h" #include "../../board/wmt/include/wmt_iomux.h" #include "wmt_dual_boot.h" /*********************************** Constant Macro **********************************/ #define DUAL_BOOT "Dual Boot" #define TEXT_NO_KEY "No key to choose system" #define TEXT_PRESS_POWER_KEY "Press power key to choose system" #define TEXT_PRESS_VOLUME_KEY "Press volume key to choose system" #define TEXT_PRESS_POWER_VOLUME_KEY "Press power or volume key to choose system" #define TEXT_DETAIL_COUNT_DOWN "The chose system will startup in seconds: " #define TEXT_BRIEF_COUNT_DOWN "System will startup in seconds: " /*********************************** External Variable ***************************/ extern int g_tf_boot; /**************************** Data Type and Local Variable ***************************/ static int dualboot_logo_init_ok; static int dualboot_key_init_ok; static int mmc_init_ok; static int text_is_display; static int text_need_always_display; static int text_display_level = 3; static UBOOT_LOGO uboot_logo[LOGO_MAX_NUM]; static LOGO_TYPE current_logo_type = LOGO_MAX_NUM; static KEY_SELECT key_select = { .use_power_key = 1, .use_volume_key = 1, .use_usb_kpad = 0, .countdown_seconds = 3, .volume_plus_gpiono = WMT_PIN_GP1_GPIO15, .volume_minus_gpiono = WMT_PIN_GP62_WAKEUP2, .volume_key_active = 0, }; static TEXT_COORDINATE countdown_seconds_pos; /* * For example: setenv wmt.dualboot.key 1:1:0:3:8:10:0 */ #define ENV_DUALBOOT_KEY "wmt.dualboot.key" /* * For example: setenv wmt.dualboot.os android * setenv wmt.dualboot.os ubuntu */ #define ENV_DUALBOOT_OS "wmt.dualboot.os" /* * For example: setenv wmt.dualboot.infolevel 3 * * 0: don't display any text information to screen * 1: display which key is pressed to choose system in the screen * 2: display count down seconds to the screen * 3: display all info to the screen */ #define ENV_DUALBOOT_INFOLEVEL "wmt.dualboot.infolevel" /*********************************** External Function ***************************/ extern void *arm_memset(void *s, int c, size_t count); extern int display_show(int clearFB); extern int WMTAccessNandEarier(unsigned long long naddr, unsigned int maddr, unsigned int size, int write); extern int mv_le_to_cpu(char *buf, int size); /********************************** Function declare *********************************/ #undef DEBUG //#define DEBUG //if you need see the debug info, please define it. #undef DBG #ifdef DEBUG #define DBG(fmt, args...) printf("[" DUAL_BOOT "] " fmt , ## args) #else #define DBG(fmt, args...) #endif #define INFO(fmt, args...) printf("[" DUAL_BOOT "] " fmt , ## args) #define ERROR(fmt,args...) printf("[" DUAL_BOOT "]Error: " fmt , ## args) #define WARNING(fmt,args...) printf("[" DUAL_BOOT "]Warning: " fmt , ## args) static int init_dualboot_logo(int force, LOGO_TYPE logo_type) { char *p_android_logosize, *p_ubuntu_logosize, *p_charging_logosize; char *p_dualboot_android_logosize, *p_dualboot_ubuntu_logosize; char *p_naddr_env, *p_maddr_env; unsigned char *p_maddr; int android_logosize = 0, ubuntu_logosize= 0, charging_logosize= 0; int dualboot_android_logosize = 0, dualboot_ubuntu_logosize = 0, totalsize = 0x800000; unsigned int naddr, maddr = 0x500000; bmp_header_t *header; int ret; if(!g_tf_boot) { /* Load All logo to Memory from Nand Flash Only Load All logo to memory once unless 'force' is set */ if(force) { dualboot_logo_init_ok = 0; arm_memset(uboot_logo, 0, sizeof(uboot_logo)); } if(dualboot_logo_init_ok) return 0; if ((p_naddr_env = getenv("wmt.nfc.mtd.u-boot-logo"))) naddr = simple_strtoul(p_naddr_env, NULL, 16); else { ERROR("wmt.nfc.mtd.u-boot-logo is not set\n"); //show_text_to_screen("wmt.nfc.mtd.u-boot-logo is not set", 0xFF00); return -1; } if ((p_maddr_env = getenv("wmt.display.logoaddr"))) maddr = simple_strtoul(p_maddr_env, NULL, 16); else { maddr = 0x500000; WARNING("wmt.display.logoaddr is not set\n"); INFO("logoaddr default set to 0x500000"); } if( (p_android_logosize = getenv("wmt.logosize.uboot")) && (p_ubuntu_logosize = getenv("wmt.logosize.ubuntu")) && (p_charging_logosize = getenv("wmt.logosize.charge")) && (p_dualboot_android_logosize = getenv("wmt.logosize.dualboot.android")) && (p_dualboot_ubuntu_logosize = getenv("wmt.logosize.dualboot.ubuntu")) ) { /* use the logosize which the u-boot parameter appointed */ android_logosize = simple_strtoul(p_android_logosize, NULL, 0); ubuntu_logosize = simple_strtoul(p_ubuntu_logosize, NULL, 0); charging_logosize = simple_strtoul(p_charging_logosize, NULL, 0); dualboot_android_logosize = simple_strtoul(p_dualboot_android_logosize, NULL, 0); dualboot_ubuntu_logosize = simple_strtoul(p_dualboot_ubuntu_logosize, NULL, 0); if(android_logosize != 0 && ubuntu_logosize != 0 && charging_logosize != 0 && dualboot_android_logosize != 0 && dualboot_ubuntu_logosize != 0) { totalsize = android_logosize + ubuntu_logosize + charging_logosize + dualboot_android_logosize + dualboot_ubuntu_logosize; } else { if(android_logosize == 0) { ERROR("'wmt.logosize.uboot' is wrong\n"); //show_text_to_screen("Can Not show logo. 'wmt.logosize.uboot' is wrong", 0xFF00); return -1; } if(ubuntu_logosize == 0) { ERROR("'wmt.logosize.ubuntu' is wrong\n"); //show_text_to_screen("Can Not show logo. 'wmt.logosize.ubuntu' is wrong", 0xFF00); return -1; } if(charging_logosize == 0) { ERROR("'wmt.logosize.charge' is wrong\n"); //show_text_to_screen("Can Not show logo. 'wmt.logosize.charge' is wrong", 0xFF00); return -1; } if(dualboot_android_logosize == 0) { ERROR("'wmt.logosize.dualboot.android' is wrong\n"); //show_text_to_screen("Can Not show logo. 'wmt.logosize.dualboot.android' is wrong", 0xFF00); return -1; } if(dualboot_ubuntu_logosize == 0) { ERROR("'wmt.logosize.dualboot.ubuntu' is wrong\n"); //show_text_to_screen("Can Not show logo. 'wmt.logosize.dualboot.android' is wrong", 0xFF00); return -1; } } } else { /* auto caculate the logo size */ INFO("Caculate logo size\n"); android_logosize = 0; ubuntu_logosize = 0; charging_logosize = 0; dualboot_android_logosize= 0; dualboot_ubuntu_logosize = 0; totalsize = 0x800000; } /* Read all logo to memory from Nand Flash */ REG32_VAL(GPIO_BASE_ADDR + 0x200) &= ~(1 << 11); //PIN_SHARE_SDMMC1_NAND ret = WMTAccessNandEarier(naddr, maddr, totalsize, 0); if(ret) { ERROR("load logo from NAND Flash fail\n"); //show_text_to_screen("Load logo fail from NAND Flash", 0xFF00); return -1; } p_maddr = (unsigned char *)maddr; /* Check android logo. The 1st logo. */ if(*p_maddr != 'B') { ERROR("android logo is Not BMP picture\n"); //show_text_to_screen("android logo is Not BMP picture", 0xFF00); return -1; } if(android_logosize == 0) { android_logosize = (*(unsigned short *)(p_maddr + 4) << 16) + (*(unsigned short *)(p_maddr + 2)); if(android_logosize == 0) { ERROR("android logo size is 0\n"); //show_text_to_screen("Can Not show logo. android logo size is 0", 0xFF00); return -1; } } uboot_logo[LOGO_ANDROID].valid = 1; uboot_logo[LOGO_ANDROID].type = LOGO_ANDROID; uboot_logo[LOGO_ANDROID].maddr = (unsigned int)p_maddr; uboot_logo[LOGO_ANDROID].size = android_logosize; /* Check charging logo. The 2nd logo. */ p_maddr += android_logosize; if(*p_maddr != 'B') { ERROR("charging logo is Not BMP picture\n"); //show_text_to_screen("charging logo is Not BMP picture", 0xFF00); return -1; } if(charging_logosize == 0) { charging_logosize = (*(unsigned short *)(p_maddr + 4) << 16) + (*(unsigned short *)(p_maddr + 2)); if(charging_logosize == 0) { ERROR("charging logo size is 0\n"); //show_text_to_screen("Can Not show logo. charging logo size is 0", 0xFF00); return -1; } } uboot_logo[LOGO_CHARGING].valid = 1; uboot_logo[LOGO_CHARGING].type = LOGO_CHARGING; uboot_logo[LOGO_CHARGING].maddr = (unsigned int)p_maddr; uboot_logo[LOGO_CHARGING].size = charging_logosize; /* Check dualboot android logo. The 3rd logo */ p_maddr += charging_logosize; if(*p_maddr != 'B') { ERROR("dualboot android logo is Not BMP picture\n"); //show_text_to_screen("dualboot android logo is Not BMP picture", 0xFF00); return -1; } if(dualboot_android_logosize == 0) { dualboot_android_logosize = (*(unsigned short *)(p_maddr + 4) << 16) + (*(unsigned short *)(p_maddr + 2)); if(dualboot_android_logosize == 0) { ERROR("dualboot android logo size is 0\n"); //show_text_to_screen("Can Not show logo. dualboot android logo size is 0", 0xFF00); return -1; } } uboot_logo[LOGO_DUALBOOT_ANDROID].valid = 1; uboot_logo[LOGO_DUALBOOT_ANDROID].type = LOGO_DUALBOOT_ANDROID; uboot_logo[LOGO_DUALBOOT_ANDROID].maddr = (unsigned int)p_maddr; uboot_logo[LOGO_DUALBOOT_ANDROID].size = dualboot_android_logosize; header = (bmp_header_t *)p_maddr; uboot_logo[LOGO_DUALBOOT_ANDROID].height = mv_le_to_cpu((char *)&header->height, 4); /* Check dualboot ubuntu logo. the 4th logo */ p_maddr += dualboot_android_logosize; if(*p_maddr != 'B') { ERROR("dualboot ubuntu logo is Not BMP picture\n"); //show_text_to_screen("dualboot ubuntu logo is Not BMP picture", 0xFF00); return -1; } if(dualboot_ubuntu_logosize == 0) { dualboot_ubuntu_logosize = (*(unsigned short *)(p_maddr + 4) << 16) + (*(unsigned short *)(p_maddr + 2)); if(dualboot_ubuntu_logosize == 0) { ERROR("dualboot ubuntu logo size is 0\n"); //show_text_to_screen("Can Not show logo. dualboot ubuntu logo size is 0", 0xFF00); return -1; } } uboot_logo[LOGO_DUALBOOT_UBUNTU].valid = 1; uboot_logo[LOGO_DUALBOOT_UBUNTU].type = LOGO_DUALBOOT_UBUNTU; uboot_logo[LOGO_DUALBOOT_UBUNTU].maddr = (unsigned int)p_maddr; uboot_logo[LOGO_DUALBOOT_UBUNTU].size = dualboot_ubuntu_logosize; header = (bmp_header_t *)p_maddr; uboot_logo[LOGO_DUALBOOT_UBUNTU].height = mv_le_to_cpu((char *)&header->height, 4); /* Check ubuntu logo. the 5th logo */ p_maddr += dualboot_ubuntu_logosize; if(*p_maddr != 'B') { ERROR("ubuntu logo is Not BMP picture\n"); //show_text_to_screen("ubuntu logo is Not BMP picture", 0xFF00); return -1; } if(ubuntu_logosize == 0) { ubuntu_logosize = (*(unsigned short *)(p_maddr + 4) << 16) + (*(unsigned short *)(p_maddr + 2)); if(ubuntu_logosize == 0) { ERROR("ubuntu logo size is 0\n"); //show_text_to_screen("Can Not show logo. ubuntu logo size is 0", 0xFF00); return -1; } } uboot_logo[LOGO_UBUNTU].valid = 1; uboot_logo[LOGO_UBUNTU].type = LOGO_UBUNTU; uboot_logo[LOGO_UBUNTU].maddr = (unsigned int)p_maddr; uboot_logo[LOGO_UBUNTU].size = ubuntu_logosize; dualboot_logo_init_ok = 1; } else { /* Load every logo to Memory from SD Card Only load every logo to Memory Once unless 'force' is set */ char tmp[100] = {0}; if(force) { uboot_logo[logo_type].valid = 0; mmc_init_ok = 0; } if(uboot_logo[logo_type].valid) return 0; if ((p_maddr_env = getenv("wmt.display.logoaddr"))) maddr = simple_strtoul(p_maddr_env, NULL, 16); else { maddr = 0x500000; WARNING("wmt.display.logoaddr is not set\n"); INFO("logoaddr default set to 0x500000"); } if(mmc_init_ok == 0) { ret = run_command("mmcinit 0", 0); if(ret == -1) { ERROR("\"mmcinit 0\" failed\n"); //show_text_to_screen("Can Not show logo. 'mmcinit 0' failed", 0xFF00); return -1; } mmc_init_ok = 1; } switch (logo_type) { case LOGO_ANDROID: uboot_logo[logo_type].maddr = maddr + 0xC00000; sprintf(tmp, "fatload mmc 0 0x%x u-boot-logo.bmp", uboot_logo[logo_type].maddr); break; case LOGO_UBUNTU: uboot_logo[logo_type].maddr = maddr + 0x1800000; sprintf(tmp, "fatload mmc 0 0x%x ubuntu-logo.bmp", uboot_logo[logo_type].maddr); break; case LOGO_CHARGING: uboot_logo[logo_type].maddr = maddr + 0x1E00000; sprintf(tmp, "fatload mmc 0 0x%x charge-logo.bmp", uboot_logo[logo_type].maddr); break; case LOGO_DUALBOOT_ANDROID: uboot_logo[logo_type].maddr = maddr; sprintf(tmp, "fatload mmc 0 0x%x dualboot-android-logo.bmp", maddr); break; case LOGO_DUALBOOT_UBUNTU: uboot_logo[logo_type].maddr = maddr + 0x600000; sprintf(tmp, "fatload mmc 0 0x%x dualboot-ubuntu-logo.bmp", uboot_logo[logo_type].maddr); break; default: ERROR("Not Supported Logo Type: %d\n", logo_type); //sprintf(tmp, "Not Supported Logo Type: %d", logo_type); //show_text_to_screen(tmp, 0xFF00); return -1; } ret = run_command(tmp, 0); if(ret != -1) { p_maddr = (unsigned char *)uboot_logo[logo_type].maddr; if(*p_maddr == 'B') { uboot_logo[logo_type].valid = 1; uboot_logo[logo_type].type = logo_type; if(logo_type == LOGO_DUALBOOT_ANDROID || logo_type == LOGO_DUALBOOT_UBUNTU) { header = (bmp_header_t *)p_maddr; uboot_logo[logo_type].height = mv_le_to_cpu((char *)&header->height, 4); } } else ERROR("logo is Not BMP picture\n"); } else { ERROR("fatload logo failed. logo_type = %d\n", logo_type); //show_text_to_screen("Can Not show logo. fatload logo failed", 0xFF00); mmc_init_ok = 0; } } return 0; } static int init_dualboot_text(void) { char *p; char * endp; unsigned long value; p = getenv(ENV_DUALBOOT_INFOLEVEL); if (!p) return -1; value = simple_strtoul(p, &endp, 0); if(value <= 2) text_display_level = value; else text_display_level = 3; return 0; } static void display_dualboot_text(int show_text, LOGO_TYPE logo_type) { int no; mv_surface *s; mv_Rect rect; char r, g, b; unsigned int rgb = 0xFF00; //green int text_width, text_height, logo_height = 0; int text_pos_x, text_pos_y, logo_pos_y; if(text_display_level == 0) return; if(key_select.use_power_key == 0 && key_select.use_volume_key == 0 && key_select.use_usb_kpad == 0) return; /* * show count down text only when dualboot_andorid and dualboot_ubuntu display */ if(logo_type == LOGO_DUALBOOT_ANDROID || logo_type == LOGO_DUALBOOT_UBUNTU) logo_height = uboot_logo[logo_type].height; else if(logo_type < LOGO_MAX_NUM){ text_is_display = 0; return; } else return; if(text_need_always_display) text_is_display = 0; if(show_text) { if(text_is_display) return; } else { if(!text_is_display) return; } switch (text_display_level) { case 0: return; case 1: if(key_select.use_power_key && key_select.use_volume_key) text_width = strlen(TEXT_PRESS_POWER_VOLUME_KEY) * CHAR_WIDTH; else if(key_select.use_power_key) text_width = strlen(TEXT_PRESS_POWER_KEY) * CHAR_WIDTH; else if(key_select.use_volume_key) text_width = strlen(TEXT_PRESS_VOLUME_KEY) * CHAR_WIDTH; else text_width = strlen(TEXT_NO_KEY) * CHAR_WIDTH; text_height = CHAR_HEIGHT; // 1 line text break; case 2: text_width = strlen(TEXT_BRIEF_COUNT_DOWN) * CHAR_WIDTH; text_height = CHAR_HEIGHT; // 1 line text break; default: text_width = strlen(TEXT_DETAIL_COUNT_DOWN) * CHAR_WIDTH; text_height = 2 * CHAR_HEIGHT; // 2 line text break; } text_pos_x = CHAR_WIDTH; text_pos_y = CHAR_HEIGHT; r = (rgb >> 16) & 0xFF; g = (rgb >> 8) & 0xFF; b = rgb & 0xFF; for(no = 0; no < 2; no++) { if(no == 1 && g_vpp.virtual_display == 0) break; s = mv_getSurface(no); if(s->startAddr) { if(logo_height > 0) { if(g_display_direction == 0 || g_display_direction == 2) { if (text_width > s->height) WARNING("no = %d, text_width(%d) > LCD(%d)\n", no, text_width, s->height); else text_pos_x = (s->height - text_width) / 2; if (logo_height > s->width) WARNING("no = %d, logo_height(%d) > LCD(%d)\n", no, logo_height, s->width); else { logo_pos_y = (s->width - logo_height) / 2; text_pos_y = (logo_pos_y - text_height) / 2; if(text_pos_y < 0) { //WARNING("text_pos_y = %d, countdown alway show\n", text_pos_y); text_pos_y = CHAR_HEIGHT; text_need_always_display = 1; } } } else { if (text_width > s->width) WARNING("no = %d, text_width(%d) > LCD(%d)\n", no, text_width, s->width); else text_pos_x = (s->width - text_width) / 2; if (logo_height > s->height) WARNING("no = %d, logo_height(%d) > LCD(%d)\n", no, logo_height, s->height); else { logo_pos_y = (s->height - logo_height) / 2; text_pos_y = (logo_pos_y - text_height) / 2; if(text_pos_y < 0) { //WARNING("text_pos_y = %d, logo_height = %d, lcd_height = %d, text_height = %d, logo_pos_y = %d, countdown alway show\n", // text_pos_y, logo_height, s->height, text_height, logo_pos_y); text_pos_y = CHAR_HEIGHT; text_need_always_display = 1; } } } } else { text_pos_x = CHAR_WIDTH; text_pos_y = CHAR_HEIGHT; text_need_always_display = 1; } //printf("text_pos_x = %d, text_pos_y = %d\n", text_pos_x, text_pos_y); if(show_text) { switch (text_display_level) { case 0: return; case 1: if(key_select.use_power_key && key_select.use_volume_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_POWER_VOLUME_KEY, r, g, b); else if(key_select.use_power_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_POWER_KEY, r, g, b); else if(key_select.use_volume_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_VOLUME_KEY, r, g, b); else mv_textOut(no, text_pos_x, text_pos_y, TEXT_NO_KEY, r, g, b); break; case 2: mv_textOut(no, text_pos_x, text_pos_y, TEXT_BRIEF_COUNT_DOWN, r, g, b); /* * The TEXT_COUNT_DOWN reverse a char at last for calculating the TEXT_COUNT_DOWN's x coordinate */ countdown_seconds_pos.x = text_pos_x + text_width - CHAR_WIDTH; countdown_seconds_pos.y = text_pos_y; break; default: if(key_select.use_power_key && key_select.use_volume_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_POWER_VOLUME_KEY, r, g, b); else if(key_select.use_power_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_POWER_KEY, r, g, b); else if(key_select.use_volume_key) mv_textOut(no, text_pos_x, text_pos_y, TEXT_PRESS_VOLUME_KEY, r, g, b); else mv_textOut(no, text_pos_x, text_pos_y, TEXT_NO_KEY, r, g, b); mv_textOut(no, text_pos_x, text_pos_y + CHAR_HEIGHT, TEXT_DETAIL_COUNT_DOWN, r, g, b); /* * The TEXT_COUNT_DOWN reverse a char at last for calculating the TEXT_COUNT_DOWN's x coordinate */ countdown_seconds_pos.x = text_pos_x + text_width - CHAR_WIDTH; countdown_seconds_pos.y = text_pos_y + CHAR_HEIGHT; // seconds in the second line break; } text_is_display = 1; } else { rect.left = 0; rect.top = text_pos_y; rect.right = s->width; rect.bottom = text_pos_y + text_height; if(g_display_direction == 0 || g_display_direction == 2) //the screen is portrait rect.right = s->height; mv_fillRect(no, &rect, 0, 0, 0); text_is_display = 0; } } } } static void display_countdown_seconds(int seconds, int force_update) { int no, len; mv_surface *s; int max_seconds_char_num = 3; // 0 - 999 int screen_width; mv_Rect rect; char r, g, b; unsigned int rgb = 0xFF00; //green char tmpbuf[20]; static int last_seconds = -1; if(text_is_display == 0 || text_display_level < 2) { INFO("CountDown: %d\n", seconds); return; } if(force_update) last_seconds = -1; if(seconds == last_seconds) return; for(no = 0; no < 2; no++) { if(no == 1 && g_vpp.virtual_display == 0) break; s = mv_getSurface(no); if(s->startAddr) { if(g_display_direction == 0 || g_display_direction == 2) screen_width = s->height; else screen_width = s->width; if((countdown_seconds_pos.x + max_seconds_char_num) > (screen_width - 1)) { ERROR("No = %d, the seconds diaplay range ( %d ~ %d ) is larger than in screen display width (0 ~ %d)\n", no, countdown_seconds_pos.x, countdown_seconds_pos.x + max_seconds_char_num, screen_width - 1); return; } rect.left = countdown_seconds_pos.x; rect.top = countdown_seconds_pos.y; rect.right = s->width; switch(text_display_level) { case 0: case 1: return; default: rect.bottom = countdown_seconds_pos.y + CHAR_HEIGHT; break; } if(g_display_direction == 0 || g_display_direction == 2) rect.right = s->height; mv_fillRect(no, &rect, 0, 0, 0); r = (rgb >> 16) & 0xFF; g = (rgb >> 8) & 0xFF; b = rgb & 0xFF; len = sprintf(tmpbuf, "%2d", seconds); tmpbuf[len] = 0; mv_textOut(no, countdown_seconds_pos.x, countdown_seconds_pos.y, tmpbuf, r, g, b); INFO("CountDown: %d\n", seconds); last_seconds = seconds; } } } static int display_dualboot_logo(LOGO_TYPE logo_type, int display_text) { unsigned int backup_img_phy; if(logo_type == current_logo_type) return 0; init_dualboot_logo(0, logo_type); if(uboot_logo[logo_type].valid) { g_logo_x = -1; g_logo_y = -1; backup_img_phy = g_img_phy; g_img_phy = uboot_logo[logo_type].maddr; /* if logo switch between dualboot_android_logo and dualboot_ubuntu_logo, don't clear framebuffer */ if((logo_type == LOGO_DUALBOOT_ANDROID && current_logo_type == LOGO_DUALBOOT_UBUNTU) || (logo_type == LOGO_DUALBOOT_UBUNTU&& current_logo_type == LOGO_DUALBOOT_ANDROID)) display_show(0); else display_show(1); g_img_phy = backup_img_phy; current_logo_type = logo_type; if(display_text) display_dualboot_text(1, logo_type); } else { switch (logo_type) { case LOGO_DUALBOOT_ANDROID: show_text_to_screen("DualBoot-Android-Logo.bmp", 0xFF00); break; case LOGO_DUALBOOT_UBUNTU: show_text_to_screen("DualBoot-Ubuntu-Logo.bmp", 0xFF00); break; case LOGO_ANDROID: show_text_to_screen("Android-Logo.bmp", 0xFF00); break; case LOGO_CHARGING: show_text_to_screen("Charging-Logo.bmp", 0xFF00); break; case LOGO_UBUNTU: show_text_to_screen("Ubuntu-Logo.bmp", 0xFF00); break; case LOGO_MAX_NUM: default: break; } current_logo_type = logo_type; if(display_text) display_dualboot_text(1, logo_type); } return 0; } static int parse_key_param(char *name, KEY_SELECT *p_key_select, int *p_param_num) { enum { idx_use_power_key, idx_use_volume_key, idx_use_usb_kpad, idx_countdown_seconds, idx_volume_plus_gpiono, idx_volume_minus_gpiono, idx_volume_key_active, idx_max }; char *p; long ps[idx_max] = {0}; char * endp; int i = 0; p = getenv(name); if (!p) { return -1; } while (i < idx_max) { ps[i++] = simple_strtoul(p, &endp, 0); if (*endp == '\0') break; p = endp + 1; if (*p == '\0') break; } p_key_select->use_power_key = ps[0]; p_key_select->use_volume_key = ps[1]; p_key_select->use_usb_kpad = ps[2]; p_key_select->countdown_seconds = ps[3]; p_key_select->volume_plus_gpiono = ps[4]; p_key_select->volume_minus_gpiono = ps[5]; p_key_select->volume_key_active = ps[6]; *p_param_num = i; return 0; } static int init_dualboot_key(void) { KEY_SELECT key; int ret, num = 0; if(dualboot_key_init_ok) return 0; dualboot_key_init_ok = 1; ret = parse_key_param(ENV_DUALBOOT_KEY, &key, &num); if(ret) return -1; if(num == 7) { if(key.use_volume_key) { /* * Check whether the volume key's gpio is valid when use volume key */ if(key.volume_plus_gpiono >= WMT_PIN_GP0_GPIO0 && key.volume_plus_gpiono <= WMT_PIN_GP63_SD2CD && key.volume_minus_gpiono >= WMT_PIN_GP0_GPIO0 && key.volume_minus_gpiono >= WMT_PIN_GP63_SD2CD) { memcpy(&key_select, &key, sizeof(KEY_SELECT)); } else WARNING("wrong %s. volume+ = %d. volume- = %d. gpio_no range should be in %d ~ %d\n", ENV_DUALBOOT_KEY, key.volume_plus_gpiono, key.volume_minus_gpiono, WMT_PIN_GP0_GPIO0, WMT_PIN_GP63_SD2CD); } else memcpy(&key_select, &key, sizeof(KEY_SELECT)); } else WARNING("wrong %s. The param's num = %d. It should be equal to 7\n", ENV_DUALBOOT_KEY, num); if(key_select.use_volume_key) { gpio_direction_input(key_select.volume_plus_gpiono); gpio_direction_input(key_select.volume_minus_gpiono); if(key_select.volume_key_active) { gpio_setpull(key_select.volume_plus_gpiono, GPIO_PULL_DOWN); gpio_setpull(key_select.volume_minus_gpiono, GPIO_PULL_DOWN); } else { gpio_setpull(key_select.volume_plus_gpiono, GPIO_PULL_UP); gpio_setpull(key_select.volume_minus_gpiono, GPIO_PULL_UP); } } if(key_select.use_power_key) { if(REG32_VAL(0xD8130014) & BIT14) REG32_VAL(0xD8130014) |= BIT14; } return 0; } /* * return 1: key pressed. 0: key is Not pressed */ static KEY_STATUS volume_key_pressed(int key_gpiono) { int key_val; if(key_select.use_volume_key) { key_val = gpio_get_value(key_gpiono); if(key_select.volume_key_active) return key_val ? KEY_PRESSED : KEY_RELEASED; else return key_val ? KEY_RELEASED : KEY_PRESSED; } return KEY_STATUS_MAX; } static KEY_STATUS power_key_pressed(void) { if(key_select.use_power_key) { if(REG32_VAL(0xD8130054) & BIT24) return KEY_PRESSED; if(REG32_VAL(0xD8130014) & BIT14) { REG32_VAL(0xD8130014) |= BIT14; return KEY_PRESSED; } return KEY_RELEASED; } return KEY_STATUS_MAX; } static int save_os_param(LOGO_TYPE logo_type) { char *p; int ret; int need_save_env = 0; p = getenv(ENV_DUALBOOT_OS); if(!p) return -1; if(strnicmp(p, "android", 7) == 0) { if(logo_type == LOGO_UBUNTU || logo_type == LOGO_DUALBOOT_UBUNTU) { ret = setenv(ENV_DUALBOOT_OS, "ubuntu"); if(ret == 0) { INFO("set wmt.dualboot.os to ubuntu\n"); need_save_env = 1; } else { ERROR("fail to set wmt.dualboot.os to ubuntu\n"); return -1; } } } else if(strnicmp(p, "ubuntu", 6) == 0) { if(logo_type == LOGO_ANDROID || logo_type == LOGO_DUALBOOT_ANDROID) { ret = setenv(ENV_DUALBOOT_OS, "android"); if(ret == 0) { INFO("set wmt.dualboot.os to android\n"); need_save_env = 1; } else { ERROR("fail to set wmt.dualboot.os to android\n"); return -1; } } } else { ERROR("Wrong %s = %s\n", ENV_DUALBOOT_OS, p); return -1; } if(need_save_env) { ret = saveenv(); if(ret == 0) INFO("save env success\n"); else { ERROR("save env fail\n"); return -1; } } return 0; } #define ANDROID_BOOT_NAND_OTA_NORMAL "nandrw boot ${boot-NAND_ofs} ${load-addr-kernel} ${load-addr-initrd} filesize" #define ANDROID_SET_RFS_RAM_OTA "setenv bootargs mem=${memtotal} root=/dev/ram0 rw initrd=${load-addr-initrd},0x${filesize} console=ttyS0,115200n8 ${ubi-addon} init=/init androidboot.serialno=${androidboot.serialno}" #define UBUNTU_BOOT_NAND_OTA_NORMAL "nandrw boot ${boot-NAND_ofs_ubuntu} ${load-addr-kernel} ${load-addr-initrd} filesize" #define UBUNTU_SET_RFS_RAM_OTA "setenv bootargs elevator=noop mem=${memtotal} initrd=${load-addr-initrd},0x${filesize} ubi.mtd=14 root=ubi0_0 rw rootfstype=ubifs console=ttyS0,115200n8" static int set_android_bootargs(void) { char *p; int ret; p = getenv("boot-nand-ota-normal"); if(!p || strcmp(p, ANDROID_BOOT_NAND_OTA_NORMAL)) { ret = setenv("boot-nand-ota-normal", ANDROID_BOOT_NAND_OTA_NORMAL); if(ret == 0) INFO("set android's boot-nand-ota-normal success\n"); else { ERROR("fail to set android's boot-nand-ota-normal\n"); return -1; } } p = getenv("set-rfs-ram-ota"); if(!p || strcmp(p, ANDROID_SET_RFS_RAM_OTA)) { ret = setenv("set-rfs-ram-ota", ANDROID_SET_RFS_RAM_OTA); if(ret == 0) INFO("set android's set-rfs-ram-ota success\n"); else { ERROR("fail to set android's set-rfs-ram-ota\n"); return -1; } } return 0; } static int set_ubuntu_bootargs(void) { char *p; int ret; p = getenv("boot-nand-ota-normal"); if(!p || strcmp(p, UBUNTU_BOOT_NAND_OTA_NORMAL)) { ret = setenv("boot-nand-ota-normal", UBUNTU_BOOT_NAND_OTA_NORMAL); if(ret == 0) INFO("set ubuntu's boot-nand-ota-normal success\n"); else { ERROR("fail to set ubuntu's boot-nand-ota-normal\n"); return -1; } } p = getenv("set-rfs-ram-ota"); if(!p || strcmp(p, UBUNTU_SET_RFS_RAM_OTA)) { ret = setenv("set-rfs-ram-ota", UBUNTU_SET_RFS_RAM_OTA); if(ret == 0) INFO("set ubuntu's set-rfs-ram-ota success\n"); else { ERROR("fail to set ubuntu's set-rfs-ram-ota\n"); return -1; } } } #define PERIOD_CHECK 10 // 10 ms //how long time to check #define PERIOD_SHOW_SECONDS 1000 // 1s //how long time to show seconds int show_dualboot_logo(int show_text) { char *p; p = getenv(ENV_DUALBOOT_OS); if (!p) return -1; init_dualboot_key(); init_dualboot_text(); if(strnicmp(p, "android", 7) == 0) display_dualboot_logo(LOGO_DUALBOOT_ANDROID, show_text); else if(strnicmp(p, "ubuntu", 6) == 0) display_dualboot_logo(LOGO_DUALBOOT_UBUNTU, show_text); else { ERROR("Wrong %s = %s\n", ENV_DUALBOOT_OS, p); return -1; } INFO("show_dualboot_logo OK\n"); return 0; } int choose_dualboot_system(void) { char *p; int loop = 0; const int period_show_seconds = (PERIOD_SHOW_SECONDS) / (PERIOD_CHECK); int rising_edge_detected; int except_seconds, remain_seconds; int cancel = 0; LOGO_TYPE logo_type = LOGO_MAX_NUM; KEY_TRACE power_key_trace = { .old_status = KEY_STATUS_MAX, .new_status = KEY_STATUS_MAX }; KEY_TRACE volume_plus_key_trace = { .old_status = KEY_STATUS_MAX, .new_status = KEY_STATUS_MAX }; KEY_TRACE volume_minus_key_trace = { .old_status = KEY_STATUS_MAX, .new_status = KEY_STATUS_MAX }; p = getenv(ENV_DUALBOOT_OS); if (!p) return -1; init_dualboot_key(); init_dualboot_text(); if(strnicmp(p, "android", 7) == 0) { display_dualboot_logo(LOGO_DUALBOOT_ANDROID, 1); logo_type = LOGO_DUALBOOT_ANDROID; } else if(strnicmp(p, "ubuntu", 6) == 0) { display_dualboot_logo(LOGO_DUALBOOT_UBUNTU, 1); logo_type = LOGO_DUALBOOT_UBUNTU; } else { ERROR("Wrong %s = %s\n", ENV_DUALBOOT_OS, p); return -1; } display_dualboot_text(1, logo_type); except_seconds = key_select.countdown_seconds; if(except_seconds <= 0) { display_countdown_seconds(0, 1); mdelay(100); return 0; } remain_seconds = except_seconds; display_countdown_seconds(remain_seconds, 1); if(key_select.use_power_key) power_key_trace.old_status = power_key_pressed(); if(key_select.use_volume_key) { volume_plus_key_trace.old_status = volume_key_pressed(key_select.volume_plus_gpiono); volume_minus_key_trace.old_status = volume_key_pressed(key_select.volume_minus_gpiono); } while(1) { if (tstc()) {//we got a key press printf("we got a key press. Exit test.\n"); //Check if the key is 'Enter' which ascii code is 13 // If the key is 'Enter', exit if (getc() == 13) { cancel = 1; break; } } rising_edge_detected = 0; if(loop % period_show_seconds == 0) { display_countdown_seconds(remain_seconds, 0); if(remain_seconds == 0) { mdelay(100); break; } remain_seconds--; } udelay(PERIOD_CHECK * 1000); if(key_select.use_power_key) { power_key_trace.new_status = power_key_pressed(); /* * detected a rising edge */ if(power_key_trace.old_status == KEY_RELEASED && power_key_trace.new_status == KEY_PRESSED) rising_edge_detected = 1; power_key_trace.old_status = power_key_trace.new_status; } if(key_select.use_volume_key) { volume_plus_key_trace.new_status = volume_key_pressed(key_select.volume_plus_gpiono); if(volume_plus_key_trace.old_status == KEY_RELEASED && volume_plus_key_trace.new_status == KEY_PRESSED) rising_edge_detected = 1; volume_plus_key_trace.old_status = volume_plus_key_trace.new_status; volume_minus_key_trace.new_status = volume_key_pressed(key_select.volume_minus_gpiono); if(volume_minus_key_trace.old_status == KEY_RELEASED && volume_minus_key_trace.new_status == KEY_PRESSED) rising_edge_detected = 1; volume_minus_key_trace.old_status = volume_minus_key_trace.new_status; } if(rising_edge_detected) { if(logo_type == LOGO_DUALBOOT_UBUNTU) { display_dualboot_logo(LOGO_DUALBOOT_ANDROID, 1); logo_type = LOGO_DUALBOOT_ANDROID; } else if(logo_type == LOGO_DUALBOOT_ANDROID) { display_dualboot_logo(LOGO_DUALBOOT_UBUNTU, 1); logo_type = LOGO_DUALBOOT_UBUNTU; } remain_seconds = except_seconds; display_countdown_seconds(remain_seconds, 0); remain_seconds--; loop = 0; } loop++; } if(logo_type == LOGO_DUALBOOT_UBUNTU) { display_dualboot_logo(LOGO_UBUNTU, 1); logo_type = LOGO_UBUNTU; } else if(logo_type == LOGO_DUALBOOT_ANDROID) { display_dualboot_logo(LOGO_ANDROID, 1); logo_type = LOGO_ANDROID; } if(cancel == 0) save_os_param(logo_type); if(logo_type == LOGO_UBUNTU || logo_type == LOGO_DUALBOOT_UBUNTU) set_ubuntu_bootargs(); else if(logo_type == LOGO_ANDROID || logo_type == LOGO_DUALBOOT_ANDROID) set_android_bootargs(); return 0; } static void dualboot(void) { show_dualboot_logo(0); choose_dualboot_system(); } static int dualboot_main (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { LOGO_TYPE logo_type; unsigned long value; char *endp; switch (argc) { case 0: break; case 1: dualboot(); return 0; break; case 2: break; default: /* at least 3 args */ if (strncmp(argv[1], "logo", 1) == 0) { value = simple_strtoul(argv[2], &endp, 0); if (value >= LOGO_ANDROID && value < LOGO_MAX_NUM) { logo_type = (LOGO_TYPE)value; display_dualboot_logo(logo_type, 1); return 0; } } break; } printf ("Usage:\n%s\n", cmdtp->usage); return 1; } U_BOOT_CMD( dualboot, 5, 1, dualboot_main, "dualboot - WMT Dual Boot sub-system\n", NULL );