diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index d0060db7..4e489883 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -254,7 +254,7 @@ CONFIG_MSM_QDSP6=y CONFIG_WIFI_CONTROL_FUNC=y # CONFIG_WIFI_MEM_PREALLOC is not set # CONFIG_VIRTUAL_KPANIC_PARTITION is not set -# CONFIG_HTC_FB_CONSOLE is not set +CONFIG_HTC_FB_CONSOLE=y CONFIG_VERY_EARLY_CONSOLE=y CONFIG_HTCLEO_ENABLE_MULTI_TOUCH=y CONFIG_ENABLE_BRAVO_UART_DRV=y @@ -1459,7 +1459,7 @@ CONFIG_ANDROID_LOGGER=y CONFIG_ANDROID_RAM_CONSOLE=y CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT=y -CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR=0xF9100000 +CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR=0x2FFC0000 CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE=0x00040000 CONFIG_ANDROID_TIMED_OUTPUT=y CONFIG_ANDROID_TIMED_GPIO=y diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 8fed8f6e..6671770e 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1048,3 +1048,27 @@ config PHYS_OFFSET hex depends on MACH_HTCLEO default "0x11800000" if MACH_HTCLEO + +config HTC_FB_CONSOLE + bool "Boot console for HTC phones (needs a font which has width <= 8)" + default n + +config HTC_FB_CONSOLE_DELAY + bool "Wait some time after each message is printed" + default n + depends on HTC_FB_CONSOLE + +config HTC_FB_CONSOLE_BOOT + bool "Use console only during boot" + default n + depends on HTC_FB_CONSOLE + +config VERY_EARLY_CONSOLE + bool "Support for very early consoles" + default n + help + Add support to initialize consoles very early. For this to have + effect, the driver must support this and the consoles should + be initialized in the board file as soon as possible. + + diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index d2f7c751..05e5822d 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-rfkill.o board-bravoc-audio.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-wifi.o htc_awb_cal.o obj-$(CONFIG_MACH_BRAVOC) += board-bravoc-microp.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo.o # MSM7x30 boards obj-$(CONFIG_ARCH_MSM7X30) += panel-samsungwvga-tl2796a.o panel-samsungwvga-s6e63m0.o panel-sonywvga-s6d16a0x21-7x30.o @@ -219,3 +219,7 @@ obj-$(CONFIG_HTC_HEADSET_PMIC) += htc_headset_pmic.o obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-tpa2018d1.o obj-$(CONFIG_MACH_MAHIMAHI) += board-mahimahi-smb329.o obj-$(CONFIG_MSM_SSBI) += ssbi.o + +obj-$(CONFIG_HTC_FB_CONSOLE) += htc_fb_console.o + + diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index ebd1c99c..54c8fabe 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -133,10 +133,30 @@ static void __init htcleo_fixup(struct machine_desc *desc, struct tag *tags, mi->bank[0].size = MSM_EBI1_BANK0_SIZE; } +#if defined(CONFIG_VERY_EARLY_CONSOLE) +#if defined(CONFIG_HTC_FB_CONSOLE) +int __init htc_fb_console_init(void); +#endif +#if defined(CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT) +int __init ram_console_early_init(void); +#endif +#endif + static void __init htcleo_map_io(void) { msm_map_common_io(); msm_clock_init(); + +#if defined(CONFIG_VERY_EARLY_CONSOLE) +// Init our consoles _really_ early +#if defined(CONFIG_HTC_FB_CONSOLE) + htc_fb_console_init(); +#endif +#if defined(CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT) + ram_console_early_init(); +#endif +#endif + } extern struct sys_timer msm_timer; diff --git a/arch/arm/mach-msm/htc_fb_console.c b/arch/arm/mach-msm/htc_fb_console.c new file mode 100644 index 00000000..da77cd72 --- /dev/null +++ b/arch/arm/mach-msm/htc_fb_console.c @@ -0,0 +1,386 @@ +/* arch/arm/mach-msm/htc_fb_console.c + * + * By Octavian Voicu + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + + +/* + * Ugly hack to get some basic console working for HTC Diamond but should + * also work for Raphael and other similar phones. Will register itself + * as an early console to show boot messages. This won't work unless + * the LCD is already powered up and functional (from wince, boot + * using Haret). We just DMA pixels to the LCD, all configuration + * must already be done. + * + * Not exactly very clean nor optimized, but it's a one night hack + * and it works :) + * + * If anyone makes any progress on HTC Diamond drop me a line + * (see email at the top), I do wanna see Android on my HTC Diamond! + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../drivers/video/msm/mdp_hw.h" + + +/* Defined in /arch/arm/mm/mmu.c, helps us map physical memory to virtual memory. + * It should work pretty early in the boot process, that why we use it */ +extern void create_mapping(struct map_desc *md); + +/* Defined in include/linux/fb.h. When, on write, a registered framebuffer device is detected, + * we immediately unregister ourselves. */ +#ifndef CONFIG_HTC_FB_CONSOLE_BOOT +extern int num_registered_fb; +#endif + +/* Green message (color = 2), the reset color to white (color = 6) */ +#define HTC_FB_MSG ("\n\n" "\x1b" "2" "HTC Linux framebuffer console by druidu" "\x1b" "7" "\n\n") + +/* LCD resolution, can differ per device (below is based on HTCLEO) */ +#define HTC_FB_LCD_WIDTH 480 +#define HTC_FB_LCD_HEIGHT 800 + +/* Set max console size for a 4x4 font */ +#define HTC_FB_CON_MAX_ROWS (HTC_FB_LCD_WIDTH / 4) +#define HTC_FB_CON_MAX_COLS (HTC_FB_LCD_HEIGHT / 4) + +/* Device dependent settings, currently configured for HTCLEO */ +#define HTC_FB_BASE 0xe2000000 /* virtual page for our fb */ +#define HTC_FB_PHYS 0x03800000 +#define HTC_FB_OFF 0x00039000 +#define HTC_FB_SIZE 0x00400000 + +#define HTC_MDP_BASE 0xe3000000 +#define HTC_MDP_PHYS 0xAA200000 +#define HTC_MDP_SIZE 0x000F0000 + +/* Pack color data in 565 RGB format; r and b are 5 bits, g is 6 bits */ +#define HTC_FB_RGB(r, g, b) ((((r) & 0x1f) << 11) | (((g) & 0x3f) << 5) | (((b) & 0x1f) << 0)) + +/* Some standard colors */ +unsigned short htc_fb_colors[8] = { + HTC_FB_RGB(0x00, 0x00, 0x00), /* Black */ + HTC_FB_RGB(0x1f, 0x00, 0x00), /* Red */ + HTC_FB_RGB(0x00, 0x15, 0x00), /* Green */ + HTC_FB_RGB(0x0f, 0x15, 0x00), /* Brown */ + HTC_FB_RGB(0x00, 0x00, 0x1f), /* Blue */ + HTC_FB_RGB(0x1f, 0x00, 0x1f), /* Magenta */ + HTC_FB_RGB(0x00, 0x3f, 0x1f), /* Cyan */ + HTC_FB_RGB(0x1f, 0x3f, 0x1f) /* White */ +}; + +/* We can use any font which has width <= 8 pixels */ +const struct font_desc *htc_fb_default_font; + +/* Pointer to font data (255 * font_rows bytes of data) */ +const unsigned char *htc_fb_font_data; + +/* Size of font in pixels */ +unsigned int htc_fb_font_cols, htc_fb_font_rows; + +/* Size of console in chars */ +unsigned int htc_fb_console_cols, htc_fb_console_rows; + +/* Current position of cursor (where next character will be written) */ +unsigned int htc_fb_cur_x, htc_fb_cur_y; + +/* Current fg / bg colors */ +unsigned char htc_fb_cur_fg, htc_fb_cur_bg; + +/* Buffer to hold characters and attributes */ +unsigned char htc_fb_chars[HTC_FB_CON_MAX_ROWS][HTC_FB_CON_MAX_COLS]; +unsigned char htc_fb_fg[HTC_FB_CON_MAX_ROWS][HTC_FB_CON_MAX_COLS]; +unsigned char htc_fb_bg[HTC_FB_CON_MAX_ROWS][HTC_FB_CON_MAX_COLS]; + +static void htc_fb_console_write(struct console *console, const char *s, unsigned int count); + +/* Console data */ +static struct console htc_fb_console = { + .name = "htc_fb", + .write = htc_fb_console_write, + .flags = +#ifdef CONFIG_HTC_FB_CONSOLE_BOOT + CON_BOOT | +#endif + CON_PRINTBUFFER | CON_ENABLED, + .index = -1, +}; + +// Redefine these defines so that we can easily borrow the code, first parameter is ignored +#undef mdp_writel +#define mdp_writel(mdp, value, offset) writel(value, HTC_MDP_BASE + offset) +#undef mdp_readl +#define mdp_readl(mdp, offset) readl(HTC_MDP_BASE + offset) + +/* Update the framebuffer from the character buffer then start DMA */ +static void htc_fb_console_update(void) +{ + unsigned int memaddr, fbram, stride, width, height, x, y, i, j, r1, c1, r2, c2; +#if 0 + unsigned int dma2_cfg; +#endif + unsigned short ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ + unsigned short *ptr; + unsigned char ch; + + fbram = HTC_FB_PHYS + HTC_FB_OFF; + memaddr = HTC_FB_BASE + HTC_FB_OFF; + + ptr = (unsigned short*) memaddr; + for (i = 0; i < htc_fb_console_rows * htc_fb_font_rows; i++) { + r1 = i / htc_fb_font_rows; + r2 = i % htc_fb_font_rows; + for (j = 0; j < htc_fb_console_cols * htc_fb_font_cols; j++) { + c1 = j / htc_fb_font_cols; + c2 = j % htc_fb_font_cols; + ch = htc_fb_chars[r1][c1]; + *ptr++ = htc_fb_font_data[(((int) ch) * htc_fb_font_rows) + r2] & ((1 << (htc_fb_font_cols - 1)) >> c2) + ? htc_fb_colors[htc_fb_fg[r1][c1]] + : htc_fb_colors[htc_fb_bg[r1][c1]]; + } + ptr += HTC_FB_LCD_WIDTH - htc_fb_console_cols * htc_fb_font_cols; + } + + stride = HTC_FB_LCD_WIDTH * 2; + width = HTC_FB_LCD_WIDTH; + height = HTC_FB_LCD_HEIGHT; + x = 0; + y = 0; + + /* In previous versions of htc_fb_console we configured the dma_config. + However, the settings for HTCLEO are still unknown. Currently leaving + the dma unconfigured, which means we just assume bootloader or + Windows Mobile has configured it correctly for us. */ +#if 0 + dma2_cfg = DMA_PACK_TIGHT | + DMA_PACK_ALIGN_LSB | + DMA_PACK_PATTERN_RGB | + DMA_OUT_SEL_AHB | + DMA_IBUF_NONCONTIGUOUS; + + dma2_cfg |= DMA_IBUF_FORMAT_RGB565; + dma2_cfg |= DMA_OUT_SEL_MDDI; + dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; + dma2_cfg |= DMA_DITHER_EN; + + /* 565 16BPP */ + dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + + /* 666 18BPP */ + //dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; +#endif + + /* setup size, address, and stride */ + mdp_writel(NULL, (height << 16) | (width), MDP_DMA_P_SIZE); + mdp_writel(NULL, fbram, MDP_DMA_P_IBUF_ADDR); + mdp_writel(NULL, stride, MDP_DMA_P_IBUF_Y_STRIDE); + + /* set y & x offset and MDDI transaction parameters */ + mdp_writel(NULL, (y << 16) | (x), MDP_DMA_P_OUT_XY); + mdp_writel(NULL, ld_param, MDP_MDDI_PARAM_WR_SEL); + mdp_writel(NULL, (MDDI_VDO_PACKET_DESC_RGB565 << 16) | MDDI_VDO_PACKET_PRIM, + MDP_MDDI_PARAM); +#if 0 + //mdp_writel(NULL, dma2_cfg, MDP_DMA_P_CONFIG); +#endif + mdp_writel(NULL, 0, MDP_DMA_P_START); + + /* Wait a bit to let the transfer finish */ + mdelay(16); +} + +/* Clear screen and buffers */ +static void htc_fb_console_clear(void) +{ + /* Default white on black, clear everything */ + memset((void*) (HTC_FB_BASE + HTC_FB_OFF), 0, HTC_FB_LCD_WIDTH * HTC_FB_LCD_HEIGHT * 2); + memset(htc_fb_chars, 0, htc_fb_console_cols * htc_fb_console_rows); + memset(htc_fb_fg, 7, htc_fb_console_cols * htc_fb_console_rows); + memset(htc_fb_bg, 0, htc_fb_console_cols * htc_fb_console_rows); + htc_fb_cur_x = htc_fb_cur_y = 0; + htc_fb_cur_fg = 7; + htc_fb_cur_bg = 0; + htc_fb_console_update(); +} + +static struct console htc_fb_console; + +/* Write a string to character buffer; handles word wrapping, auto-scrolling, etc + * After that, calls htc_fb_console_update to send data to the LCD */ +static void htc_fb_console_write(struct console *console, const char *s, unsigned int count) +{ + unsigned int i, j, k, scroll; + const char *p; + +#ifndef CONFIG_HTC_FB_CONSOLE_BOOT + // See if a framebuffer has been registered. If so, we disable this console to prevent conflict with + // other FB devices (i.e. msm_fb). + if (num_registered_fb > 0) { + printk(KERN_INFO "htc_fb_console: framebuffer device detected, disabling boot console\n"); + console->flags = 0; + return; + } +#endif + + scroll = 0; + for (k = 0, p = s; k < count; k++, p++) { + if (*p == '\n') { + /* Jump to next line */ + scroll = 1; + } else if (*p == '\t') { + /* Tab size 8 chars */ + htc_fb_cur_x = (htc_fb_cur_x + 7) % 8; + if (htc_fb_cur_x >= htc_fb_console_cols) { + scroll = 1; + } + } else if (*p == '\x1b') { + /* Escape char (ascii 27) + * Some primitive way to change color: + * \x1b followed by one digit to represent color (0 black ... 7 white) */ + if (k < count - 1) { + p++; + htc_fb_cur_fg = *p - '0'; + if (htc_fb_cur_fg >= 8) { + htc_fb_cur_fg = 7; + } + } + } else if (*p != '\r') { + /* Ignore \r, other cars get written here */ + htc_fb_chars[htc_fb_cur_y][htc_fb_cur_x] = *p; + htc_fb_fg[htc_fb_cur_y][htc_fb_cur_x] = htc_fb_cur_fg; + htc_fb_bg[htc_fb_cur_y][htc_fb_cur_x] = htc_fb_cur_bg; + htc_fb_cur_x++; + if (htc_fb_cur_x >= htc_fb_console_cols) { + scroll = 1; + } + } + if (scroll) { + scroll = 0; + htc_fb_cur_x = 0; + htc_fb_cur_y++; + if (htc_fb_cur_y == htc_fb_console_rows) { + /* Scroll below last line, shift all rows up + * Should have used a bigger buffer so no shift, + * would actually be needed -- but hey, it's a one night hack */ + htc_fb_cur_y--; + for (i = 1; i < htc_fb_console_rows; i++) { + for (j = 0; j < htc_fb_console_cols; j++) { + htc_fb_chars[i - 1][j] = htc_fb_chars[i][j]; + htc_fb_fg[i - 1][j] = htc_fb_fg[i][j]; + htc_fb_bg[i - 1][j] = htc_fb_bg[i][j]; + } + } + for (j = 0; j < htc_fb_console_cols; j++) { + htc_fb_chars[htc_fb_console_rows - 1][j] = 0; + htc_fb_fg[htc_fb_console_rows - 1][j] = htc_fb_cur_fg; + htc_fb_bg[htc_fb_console_rows - 1][j] = htc_fb_cur_bg; + } + } + } + } + + htc_fb_console_update(); + +#ifdef CONFIG_HTC_FB_CONSOLE_DELAY + /* Delay so we can see what's there, we have no keys to scroll */ + mdelay(500); +#endif +} + +#if defined(CONFIG_VERY_EARLY_CONSOLE) +// Make sure we don't init twice +static bool htc_fb_console_init_done = false; +#endif + +/* Init console on LCD using MDDI/MDP interface to transfer pixel data. + * We can DMA to the board, as long as we give a physical address to the LCD + * controller and use the coresponding virtual address to write pixels to. + * The physical address I used is the one wince had for the framebuffer */ +#if !defined(CONFIG_VERY_EARLY_CONSOLE) +static +#endif +int __init htc_fb_console_init(void) +{ + struct map_desc map, map_mdp; + +#if defined(CONFIG_VERY_EARLY_CONSOLE) + if (htc_fb_console_init_done) + { + printk(KERN_INFO "htc_fb_console_init: already initialized, bailing out\n"); + return 0; + } + htc_fb_console_init_done = true; +#endif + + /* Map the framebuffer Windows was using, as we know the physical address */ + map.pfn = __phys_to_pfn(HTC_FB_PHYS & SECTION_MASK); + map.virtual = HTC_FB_BASE; + map.length = ((unsigned long) HTC_FB_SIZE + ~SECTION_MASK) & SECTION_MASK; + map.type = MT_MEMORY; + /* Ugly hack, but we're not sure what works and what doesn't, + * so better use the lowest level we have for setting the mapping */ + create_mapping(&map); + + /* Map the MDP */ + map_mdp.pfn = __phys_to_pfn(HTC_MDP_PHYS & SECTION_MASK); + map_mdp.virtual = HTC_MDP_BASE; + map_mdp.length = ((unsigned long) HTC_MDP_SIZE + ~SECTION_MASK) & SECTION_MASK; + map_mdp.type = MT_MEMORY; + create_mapping(&map_mdp); + + /* Init font (we support any font that has width <= 8; height doesn't matter) */ + htc_fb_default_font = get_default_font(HTC_FB_LCD_WIDTH, HTC_FB_LCD_HEIGHT, 0xFF, 0xFFFFFFFF); + if (!htc_fb_default_font) { + printk(KERN_WARNING "Can't find a suitable font for htc_fb\n"); + return -1; + } + + htc_fb_font_data = htc_fb_default_font->data; + htc_fb_font_cols = htc_fb_default_font->width; + htc_fb_font_rows = htc_fb_default_font->height; + htc_fb_console_cols = HTC_FB_LCD_WIDTH / htc_fb_font_cols; + if (htc_fb_console_cols > HTC_FB_CON_MAX_COLS) + htc_fb_console_cols = HTC_FB_CON_MAX_COLS; + htc_fb_console_rows = HTC_FB_LCD_HEIGHT / htc_fb_font_rows; + if (htc_fb_console_rows > HTC_FB_CON_MAX_ROWS) + htc_fb_console_rows = HTC_FB_CON_MAX_ROWS; + + /* Clear the buffer; we could probably see the Haret output if we didn't clear + * the buffer (if it used same physical address) */ + htc_fb_console_clear(); + + /* Welcome message */ + htc_fb_console_write(&htc_fb_console, HTC_FB_MSG, strlen(HTC_FB_MSG)); + + /* Register console */ + register_console(&htc_fb_console); + console_verbose(); + + return 0; +} + +console_initcall(htc_fb_console_init); + diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h index 08436dbe..80d6f416 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h @@ -163,3 +163,12 @@ #define MSM_TCSR_PHYS 0xA8700000 #define MSM_TCSR_SIZE SZ_4K #endif + +// Originally this does not need to be defined, +// but is required to make early_ramconsole work. +// These values must match the values used in +// the defconfig. +#define MSM_RAM_CONSOLE_BASE IOMEM(0xF9100000) +#define MSM_RAM_CONSOLE_PHYS 0x2FFC0000 +#define MSM_RAM_CONSOLE_SIZE 0x00040000 + diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index 53f736b0..7adbdc68 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -22,6 +22,14 @@ #include #include +#if defined(CONFIG_VERY_EARLY_CONSOLE) +#include + +/* Defined in /arch/arm/mm/mmu.c, helps us map physical memory to virtual memory. + * It should work pretty early in the boot process, that why we use it */ +extern void create_mapping(struct map_desc *md); +#endif + #ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION #include #endif @@ -308,8 +316,21 @@ static int __init ram_console_init(struct ram_console_buffer *buffer, } #ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT + +#if defined(CONFIG_VERY_EARLY_CONSOLE) +static bool ram_console_early_init_done = false; +int __init ram_console_early_init(void) +{ + if (ram_console_early_init_done) + { + printk(KERN_INFO "ram_console_early_init: already initialized, bailing out\n"); + return 0; + } + ram_console_early_init_done = true; +#else static int __init ram_console_early_init(void) { +#endif return ram_console_init((struct ram_console_buffer *) CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR, CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,