[msm7k] mddi support for msm7k and surf-msm7k wvga panel.
diff --git a/platform/msm7k/include/platform/mddi.h b/platform/msm7k/include/platform/mddi.h
new file mode 100644
index 0000000..d1d3a77
--- /dev/null
+++ b/platform/msm7k/include/platform/mddi.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_MDDI_H
+#define __PLATFORM_MDDI_H
+
+struct fbcon_config;
+
+struct __attribute__((packed)) mddi_client_caps 
+{
+    unsigned short length;
+    unsigned short type;
+    unsigned short client_id;
+
+    unsigned short protocol_ver;
+    unsigned short min_protocol_ver;
+    unsigned short data_rate_cap;
+    unsigned char interface_type_cap;
+    unsigned char num_alt_displays;
+    unsigned short postcal_data_rate;
+    unsigned short bitmap_width;
+    unsigned short bitmap_height;
+    unsigned short display_window_width;
+    unsigned short display_window_height;
+    unsigned cmap_size;
+    unsigned short cmap_rgb_width;
+    unsigned short rgb_cap;
+    unsigned char mono_cap;
+    unsigned char reserved1;
+    unsigned short ycbcr_cap;
+    unsigned short bayer_cap;
+    unsigned short alpha_cursor_planes;
+    unsigned client_feature_cap;
+    unsigned char max_video_frame_rate_cap;
+    unsigned char min_video_frame_rate_cap;
+    unsigned short min_sub_frame_rate;
+    unsigned short audio_buf_depth;
+    unsigned short audio_channel_cap;
+    unsigned short audio_sampe_rate_rap;
+    unsigned char audio_sample_res;
+    unsigned char mic_audio_sample_res;
+    unsigned short mic_sample_rate_cap;
+    unsigned char keyboard_data_fmt;
+    unsigned char pointing_device_data_fmt;
+    unsigned short content_protection_type;
+    unsigned short manufacturer_name;
+    unsigned short product_code;
+    unsigned short reserved3;
+    unsigned serial_no;
+    unsigned char week_of_manufacture;
+    unsigned char year_of_manufacture;
+
+    unsigned short crc;    
+};
+
+void mddi_remote_write(unsigned val, unsigned reg);
+struct fbcon_config *mddi_init(void);
+
+#endif /* __PLATFORM_MDDI_H */
diff --git a/platform/msm7k/mddi.c b/platform/msm7k/mddi.c
new file mode 100644
index 0000000..7472953
--- /dev/null
+++ b/platform/msm7k/mddi.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dev/fbcon.h>
+#include <kernel/thread.h>
+#include <platform/iomap.h>
+#include <platform/mddi.h>
+
+#include "mddi_hw.h"
+
+static mddi_llentry *mlist = NULL;
+static mddi_llentry *mlist_remote_write = NULL;
+
+#define MDDI_MAX_REV_PKT_SIZE 0x60
+#define MDDI_REV_PKT_BUF_SIZE (MDDI_MAX_REV_PKT_SIZE * 4)
+static void *rev_pkt_buf;
+
+/* functions provided by the target specific panel code */
+void panel_init(struct mddi_client_caps *client_caps);
+void panel_poweron(void);
+void panel_backlight(int on);
+
+/* forward decls */
+static void mddi_start_update(void);
+static int mddi_update_done(void);
+
+static struct fbcon_config fb_cfg = {
+	.format		= FB_FORMAT_RGB565,
+	.bpp		= 16,
+	.update_start	= mddi_start_update,
+	.update_done	= mddi_update_done,
+};
+
+static void printcaps(struct mddi_client_caps *c)
+{
+	if ((c->length != 0x4a) || (c->type != 0x42)) {
+		dprintf(INFO, "bad caps header\n");
+		memset(c, 0, sizeof(*c));
+		return;
+	}
+
+	dprintf(INFO, "mddi: bm: %d,%d win %d,%d rgb %x\n",
+		c->bitmap_width, c->bitmap_height,
+		c->display_window_width, c->display_window_height,
+		c->rgb_cap);
+	dprintf(INFO, "mddi: vend %x prod %x\n",
+		c->manufacturer_name, c->product_code);
+}
+
+/* TODO: add timeout */
+static int mddi_wait_status(unsigned statmask)
+{
+	while ((readl(MDDI_STAT) & statmask) == 0);
+	return 0;
+}
+
+/* TODO: add timeout */
+static int mddi_wait_interrupt(unsigned intmask)
+{
+	while ((readl(MDDI_INT) & intmask) == 0);
+	return 0;
+}
+
+void mddi_remote_write(unsigned val, unsigned reg)
+{
+	mddi_llentry *ll;
+	mddi_register_access *ra;
+
+	ll = mlist_remote_write;
+	
+	ra = &(ll->u.r);
+	ra->length = 14 + 4;
+	ra->type = TYPE_REGISTER_ACCESS;
+	ra->client_id = 0;
+	ra->rw_info = MDDI_WRITE | 1;
+	ra->crc = 0;
+
+	ra->reg_addr = reg;
+	ra->reg_data = val;
+
+	ll->flags = 1;
+	ll->header_count = 14;
+	ll->data_count = 4;
+	ll->data = &ra->reg_data;
+	ll->next = (void *) 0;
+	ll->reserved = 0;
+
+	writel((unsigned) ll, MDDI_PRI_PTR);
+
+	mddi_wait_status(MDDI_STAT_PRI_LINK_LIST_DONE);
+}
+
+static void mddi_start_update(void)
+{
+	writel((unsigned) mlist, MDDI_PRI_PTR);
+}
+
+static int mddi_update_done(void)
+{
+	return !!(readl(MDDI_STAT) & MDDI_STAT_PRI_LINK_LIST_DONE);
+}
+
+static void mddi_do_cmd(unsigned cmd)
+{
+	writel(cmd, MDDI_CMD);
+	mddi_wait_interrupt(MDDI_INT_NO_REQ_PKTS_PENDING);
+}
+
+static void mddi_init_rev_encap(void)
+{
+	memset(rev_pkt_buf, 0xee, MDDI_REV_PKT_BUF_SIZE);
+	writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
+	writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
+	mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
+}
+
+static void mddi_set_auto_hibernate(unsigned on)
+{
+	writel(CMD_POWER_DOWN, MDDI_CMD);
+	mddi_wait_interrupt(MDDI_INT_IN_HIBERNATION);
+	mddi_do_cmd(CMD_HIBERNATE | !!on);
+}
+
+static void mddi_get_caps(struct mddi_client_caps *caps)
+{
+	unsigned timeout = 100000;
+	unsigned n;
+
+	writel(0xffffffff, MDDI_INT);
+	mddi_do_cmd(CMD_LINK_ACTIVE);
+
+	/* sometimes this will fail -- do it three times for luck... */
+	mddi_do_cmd(CMD_RTD_MEASURE);
+	thread_sleep(1);//mdelay(1);
+
+	mddi_do_cmd(CMD_RTD_MEASURE);
+	thread_sleep(1);//mdelay(1);
+
+	mddi_do_cmd(CMD_RTD_MEASURE);
+	thread_sleep(1);//mdelay(1);
+
+	mddi_do_cmd(CMD_GET_CLIENT_CAP);
+
+	do {
+		n = readl(MDDI_INT);
+	} while (!(n & MDDI_INT_REV_DATA_AVAIL) && (--timeout));
+	
+	if (timeout == 0)
+		dprintf(INFO, "timeout\n");
+
+	memcpy(caps, rev_pkt_buf, sizeof(struct mddi_client_caps));
+}
+
+static unsigned mddi_init_regs(void)
+{
+	mddi_set_auto_hibernate(0);
+	mddi_do_cmd(CMD_RESET);
+
+	mddi_do_cmd(CMD_PERIODIC_REV_ENC);
+
+	writel(0x0001, MDDI_VERSION);
+	writel(0x3C00, MDDI_BPS);
+	writel(0x0003, MDDI_SPM);
+
+	writel(0x0005, MDDI_TA1_LEN);
+	writel(0x000C, MDDI_TA2_LEN);
+	writel(0x0096, MDDI_DRIVE_HI);
+	writel(0x0050, MDDI_DRIVE_LO);
+	writel(0x003C, MDDI_DISP_WAKE);
+	writel(0x0002, MDDI_REV_RATE_DIV);
+
+	writel(MDDI_REV_PKT_BUF_SIZE, MDDI_REV_SIZE);
+//	writel(MDDI_REV_PKT_BUF_SIZE, MDDI_REV_ENCAP_SZ);
+	writel(MDDI_MAX_REV_PKT_SIZE, MDDI_REV_ENCAP_SZ);
+
+	mddi_do_cmd(CMD_PERIODIC_REV_ENC);
+
+	/* needs to settle for 5uS */
+	if (readl(MDDI_PAD_CTL) == 0) {
+		writel(0x08000, MDDI_PAD_CTL);
+		thread_sleep(1);//udelay(5);
+	}
+
+	writel(0xA850F, MDDI_PAD_CTL);
+	writel(0x60006, MDDI_DRIVER_START_CNT);
+
+	/* disable hibernate */
+	mddi_set_auto_hibernate(0);
+	mddi_do_cmd(CMD_IGNORE);
+
+	mddi_init_rev_encap();
+	return readl(MDDI_CORE_VER) & 0xffff;
+}
+
+struct fbcon_config *mddi_init(void)
+{
+	unsigned n;
+	struct mddi_client_caps client_caps;
+
+	dprintf(INFO, "mddi_init()\n");
+
+	rev_pkt_buf = memalign(32, MDDI_REV_PKT_BUF_SIZE);
+	mlist_remote_write = memalign(32, sizeof(struct mddi_llentry));
+
+	n = mddi_init_regs();
+	dprintf(INFO, "mddi version: 0x%08x\n", n);
+
+	mddi_get_caps(&client_caps);
+	ASSERT(client_caps.length == 0x4a && client_caps.type == 0x42);
+
+	fb_cfg.width = client_caps.bitmap_width;
+	fb_cfg.stride = fb_cfg.width;
+	fb_cfg.height = client_caps.bitmap_height;
+
+	printcaps(&client_caps);
+
+	panel_init(&client_caps);
+
+	panel_backlight(0);
+	panel_poweron();
+
+	/* v > 8?  v > 8 && < 0x19 ? */
+	writel(2, MDDI_TEST);
+
+	dprintf(INFO, "panel is %d x %d\n", fb_cfg.width, fb_cfg.height);
+
+	fb_cfg.base =
+		memalign(4096, fb_cfg.width * fb_cfg.height * (fb_cfg.bpp / 8));
+
+	mlist = memalign(32, sizeof(mddi_llentry) * (fb_cfg.height / 8));
+	dprintf(INFO, "FB @ %p  mlist @ %x\n", fb_cfg.base, (unsigned) mlist);
+	
+	for(n = 0; n < (fb_cfg.height / 8); n++) {
+		unsigned y = n * 8;
+		unsigned pixels = fb_cfg.width * 8;
+		mddi_video_stream *vs = &(mlist[n].u.v);
+
+		vs->length = sizeof(mddi_video_stream) - 2 + (pixels * 2);
+		vs->type = TYPE_VIDEO_STREAM;
+		vs->client_id = 0;
+		vs->format = 0x5565; // FORMAT_16BPP;
+		vs->pixattr = PIXATTR_BOTH_EYES | PIXATTR_TO_ALL;
+		
+		vs->left = 0;
+		vs->right = fb_cfg.width - 1;
+		vs->top = y;
+		vs->bottom = y + 7;
+		
+		vs->start_x = 0;
+		vs->start_y = y;
+		
+		vs->pixels = pixels;
+		vs->crc = 0;
+		vs->reserved = 0;
+		
+		mlist[n].header_count = sizeof(mddi_video_stream) - 2;
+		mlist[n].data_count = pixels * 2;
+		mlist[n].reserved = 0;
+		mlist[n].data = fb_cfg.base + (y * fb_cfg.width * 2);
+		mlist[n].next = &mlist[n + 1];
+		mlist[n].flags = 0;
+	}
+
+	mlist[n-1].flags = 1;
+	mlist[n-1].next = 0;
+
+	mddi_set_auto_hibernate(1);
+	mddi_do_cmd(CMD_LINK_ACTIVE);
+
+	panel_backlight(1);
+
+	return &fb_cfg;
+}
diff --git a/platform/msm7k/mddi_hw.h b/platform/msm7k/mddi_hw.h
new file mode 100644
index 0000000..814ea0e
--- /dev/null
+++ b/platform/msm7k/mddi_hw.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_MSM7K_MDDI_HW_H
+#define __PLATFORM_MSM7K_MDDI_HW_H
+
+#define MSM_MDDI_BASE 0xAA600000
+
+/* see 80-VA736-2 C pp 776-787 */
+
+#define MDDI_REG(off) (MSM_MDDI_BASE + (off))
+
+#define MDDI_CMD               MDDI_REG(0x0000)
+#define MDDI_VERSION           MDDI_REG(0x0004)
+#define MDDI_PRI_PTR           MDDI_REG(0x0008)
+#define MDDI_SEC_PTR           MDDI_REG(0x000C)
+#define MDDI_BPS               MDDI_REG(0x0010)
+#define MDDI_SPM               MDDI_REG(0x0014)
+#define MDDI_INT               MDDI_REG(0x0018)
+
+#define MDDI_INT_PRI_PTR_READ          (1 << 0)
+#define MDDI_INT_SEC_PTR_READ          (1 << 1)
+#define MDDI_INT_REV_DATA_AVAIL        (1 << 2)
+#define MDDI_INT_DISP_REQ              (1 << 3)
+#define MDDI_INT_PRI_UNDERFLOW         (1 << 4)
+#define MDDI_INT_SEC_UNDERFLOW         (1 << 5)
+#define MDDI_INT_REV_OVERFLOW          (1 << 6)
+#define MDDI_INT_CRC_ERROR             (1 << 7)
+#define MDDI_INT_MDDI_IN               (1 << 8)
+#define MDDI_INT_PRI_OVERWRITE         (1 << 9)
+#define MDDI_INT_SEC_OVERWRITE         (1 << 10)
+#define MDDI_INT_REV_OVERWRITE         (1 << 11)
+#define MDDI_INT_DMA_FAILURE           (1 << 12)
+#define MDDI_INT_LINK_ACTIVE           (1 << 13)
+#define MDDI_INT_IN_HIBERNATION        (1 << 14)
+#define MDDI_INT_PRI_LINK_LIST_DONE    (1 << 15)
+#define MDDI_INT_SEC_LINK_LIST_DONE    (1 << 16)
+#define MDDI_INT_NO_REQ_PKTS_PENDING   (1 << 17)
+#define MDDI_INT_RTD_FAILURE           (1 << 18)
+#define MDDI_INT_REV_PKT_RECEIVED      (1 << 19)
+#define MDDI_INT_REV_PKTS_AVAIL        (1 << 20)
+
+#define MDDI_INTEN             MDDI_REG(0x001C)
+#define MDDI_REV_PTR           MDDI_REG(0x0020)
+#define MDDI_REV_SIZE          MDDI_REG(0x0024)
+#define MDDI_STAT              MDDI_REG(0x0028)
+
+#define MDDI_STAT_LINK_ACTIVE                (1 << 0)
+#define MDDI_STAT_NEW_REV_PTR                (1 << 1)
+#define MDDI_STAT_NEW_PRI_PTR                (1 << 2)
+#define MDDI_STAT_NEW_SEC_PTR                (1 << 3)
+#define MDDI_STAT_IN_HIBERNATION             (1 << 4)
+#define MDDI_STAT_PRI_LINK_LIST_DONE         (1 << 5)
+#define MDDI_STAT_SEC_LINK_LIST_DONE         (1 << 6)
+#define MDDI_STAT_SEND_TIMING_PKT            (1 << 7)
+#define MDDI_STAT_SEND_REV_ENCAP_WITH_FLAGS  (1 << 8)
+#define MDDI_STAT_SEND_POWER_DOWN            (1 << 9)
+#define MDDI_STAT_DO_HANDSHAKE               (1 << 10)
+#define MDDI_STAT_RTD_MEAS_FAIL              (1 << 11)
+#define MDDI_STAT_CLIENT_WAKEUP_REQ          (1 << 12)
+#define MDDI_STAT_DMA_ABORT                  (1 << 13)
+#define MDDI_STAT_REV_OVERFLOW_RESET         (1 << 14)
+#define MDDI_STAT_FORCE_NEW_REV_PTR          (1 << 15)
+#define MDDI_STAT_CRC_ERRORS                 (1 << 16)
+
+#define MDDI_REV_RATE_DIV      MDDI_REG(0x002C)
+#define MDDI_REV_CRC_ERR       MDDI_REG(0x0030)
+#define MDDI_TA1_LEN           MDDI_REG(0x0034)
+#define MDDI_TA2_LEN           MDDI_REG(0x0038)
+#define MDDI_TEST_BUS          MDDI_REG(0x003C)
+#define MDDI_TEST              MDDI_REG(0x0040)
+#define MDDI_REV_PKT_CNT       MDDI_REG(0x0044)
+#define MDDI_DRIVE_HI          MDDI_REG(0x0048)
+#define MDDI_DRIVE_LO          MDDI_REG(0x004C)
+#define MDDI_DISP_WAKE         MDDI_REG(0x0050)
+#define MDDI_REV_ENCAP_SZ      MDDI_REG(0x0054)
+#define MDDI_RTD_VAL           MDDI_REG(0x0058)
+#define MDDI_MDP_VID_FMT_DES   MDDI_REG(0x005C)
+#define MDDI_MDP_VID_PIX_ATTR  MDDI_REG(0x0060)
+#define MDDI_MDP_VID_CLIENTID  MDDI_REG(0x0064)
+#define MDDI_PAD_CTL           MDDI_REG(0x0068)
+#define MDDI_DRIVER_START_CNT  MDDI_REG(0x006C)
+#define MDDI_NEXT_PRI_PTR      MDDI_REG(0x0070)
+#define MDDI_NEXT_SEC_PTR      MDDI_REG(0x0074)
+#define MDDI_MISR_CTL          MDDI_REG(0x0078)
+#define MDDI_MISR_DATA         MDDI_REG(0x007C)
+#define MDDI_SF_CNT            MDDI_REG(0x0080)
+#define MDDI_MF_CNT            MDDI_REG(0x0084)
+#define MDDI_CURR_REV_PTR      MDDI_REG(0x0088)
+#define MDDI_CORE_VER          MDDI_REG(0x008C)
+
+#define CMD_POWER_DOWN         0x0100
+#define CMD_POWER_UP           0x0200
+#define CMD_HIBERNATE          0x0300
+#define CMD_RESET              0x0400
+#define CMD_IGNORE             0x0501
+#define CMD_LISTEN             0x0500
+#define CMD_REV_ENC_REQ        0x0600
+#define CMD_RTD_MEASURE        0x0700
+#define CMD_LINK_ACTIVE        0x0900
+#define CMD_PERIODIC_REV_ENC   0x0A00
+#define CMD_FORCE_NEW_REV_PTR  0x0C00
+
+#define CMD_GET_CLIENT_CAP     0x0601
+#define CMD_GET_CLIENT_STATUS  0x0602
+
+#if 1
+#define FORMAT_18BPP           0x5666
+#define FORMAT_24BPP           0x5888
+#define FORMAT_16BPP           0x5565
+#else
+#define FORMAT_MONOCHROME      (0 << 13)
+#define FORMAT_PALETTE         (1 << 13)
+#define FORMAT_RGB             (2 << 13)
+#define FORMAT_YCBCR422        (3 << 13)
+#define FORMAT_BAYER           (4 << 13)
+#endif
+
+#define PIXATTR_BOTH_EYES      3
+#define PIXATTR_LEFT_EYE       2
+#define PIXATTR_RIGHT_EYE      1
+#define PIXATTR_ALT_DISPLAY    0
+
+#define PIXATTR_PROGRESSIVE    0
+#define PIXATTR_INTERLACED     (1 << 2)
+#define PIXATTR_ALTERNATE      (1 << 3)
+
+#define PIXATTR_IGNORE_LRTB    (1 << 5)
+
+#define PIXATTR_TO_REFRESH     (0 << 6)
+#define PIXATTR_TO_OFFLINE     (1 << 6)
+#define PIXATTR_TO_ALL         (3 << 6)
+
+#define PIXATTR_LAST_ROW       (1 << 15)
+
+#define TYPE_VIDEO_STREAM      16
+#define TYPE_CLIENT_CAPS       66
+#define TYPE_REGISTER_ACCESS   146
+#define TYPE_CLIENT_STATUS     70
+
+typedef struct mddi_video_stream mddi_video_stream;
+typedef struct mddi_register_access mddi_register_access;
+typedef struct mddi_client_caps mddi_client_caps;
+
+typedef struct mddi_llentry mddi_llentry;
+
+struct __attribute__((packed)) mddi_video_stream 
+{
+    unsigned short length;      /* length in bytes excluding this field */
+    unsigned short type;        /* MDDI_TYPE_VIDEO_STREAM */
+    unsigned short client_id;   /* set to zero */
+    
+    unsigned short format;
+    unsigned short pixattr;
+
+    unsigned short left;
+    unsigned short top;
+    unsigned short right;
+    unsigned short bottom;
+
+    unsigned short start_x;
+    unsigned short start_y;
+
+    unsigned short pixels;
+
+    unsigned short crc;
+    unsigned short reserved;
+};
+
+struct __attribute__((packed)) mddi_register_access
+{
+    unsigned short length;
+    unsigned short type;
+    unsigned short client_id;
+
+    unsigned short rw_info;    /* flag below | count of reg_data */
+#define MDDI_WRITE     (0 << 14)
+#define MDDI_READ      (2 << 14)
+#define MDDI_READ_RESP (3 << 14)
+    
+    unsigned reg_addr;
+    unsigned short crc;        /* 16 bit crc of the above */
+
+    unsigned reg_data;         /* "list" of 3byte data values */
+};
+
+struct __attribute__((packed)) mddi_llentry {
+    unsigned short flags;
+    unsigned short header_count;
+    unsigned short data_count;
+    void *data;
+    mddi_llentry *next;
+    unsigned short reserved;
+    union {
+        mddi_video_stream v;
+        mddi_register_access r;
+        unsigned _[12];
+    } u;
+};
+
+#endif /* __PLATFORM_MSM7K_MDDI_HW_H */
diff --git a/platform/msm7k/platform.c b/platform/msm7k/platform.c
index 15ee2eb..c545262 100644
--- a/platform/msm7k/platform.c
+++ b/platform/msm7k/platform.c
@@ -30,9 +30,12 @@
  */
 
 #include <debug.h>
-
 #include <kernel/thread.h>
 #include <platform/debug.h>
+#include <platform/mddi.h>
+#include <dev/fbcon.h>
+
+static struct fbcon_config *fb_config;
 
 void platform_init_interrupts(void);
 void platform_init_timer();
@@ -40,6 +43,8 @@
 void uart3_clock_init(void);
 void uart_init(void);
 
+void mddi_clock_init(unsigned num, unsigned rate);
+
 void platform_early_init(void)
 {
 	uart3_clock_init();
@@ -52,4 +57,9 @@
 void platform_init(void)
 {
 	dprintf(INFO, "platform_init()\n");
+
+	mddi_clock_init(0, 122880000);
+	fb_config = mddi_init();
+	ASSERT(fb_config);
+	fbcon_setup(fb_config);
 }
diff --git a/platform/msm7k/rules.mk b/platform/msm7k/rules.mk
index 4a756fc..5c96a32 100644
--- a/platform/msm7k/rules.mk
+++ b/platform/msm7k/rules.mk
@@ -6,9 +6,12 @@
 
 INCLUDES += -I$(LOCAL_DIR)/include
 
+MODULES += dev/fbcon
+
 OBJS += \
 	$(LOCAL_DIR)/platform.o \
 	$(LOCAL_DIR)/interrupts.o \
+	$(LOCAL_DIR)/mddi.o \
 	$(LOCAL_DIR)/gpio.o \
 	$(LOCAL_DIR)/debug.o
 
diff --git a/platform/msm_shared/proc_comm.c b/platform/msm_shared/proc_comm.c
index 53c32a7..4315c28 100644
--- a/platform/msm_shared/proc_comm.c
+++ b/platform/msm_shared/proc_comm.c
@@ -220,3 +220,16 @@
 	clock_enable(USB_HS_CLK);
 	clock_enable(USB_HS_PCLK);
 }
+
+void mddi_clock_init(unsigned num, unsigned rate)
+{
+	unsigned clock_id;
+
+	if (num == 0)
+		clock_id = PMDH_CLK;
+	else
+		clock_id = EMDH_CLK;
+
+	clock_enable(clock_id);
+	clock_set_rate(clock_id, rate);
+}
diff --git a/target/surf-msm7k/panel.c b/target/surf-msm7k/panel.c
new file mode 100644
index 0000000..c2b56a1
--- /dev/null
+++ b/target/surf-msm7k/panel.c
@@ -0,0 +1,471 @@
+/* Copyright 2007, Google Inc. */
+
+#include <debug.h>
+#include <dev/gpio.h>
+#include <kernel/thread.h>
+#include <platform/mddi.h>
+
+#define MDDI_CLIENT_CORE_BASE  0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE         0x120000
+#define I2C_BLOCK_BASE         0x130000
+#define PWM_BLOCK_BASE         0x140000
+#define GPIO_BLOCK_BASE        0x150000
+#define SYSTEM_BLOCK1_BASE     0x160000
+#define SYSTEM_BLOCK2_BASE     0x170000
+
+
+#define	MDDICAP0    (MDDI_CLIENT_CORE_BASE|0x00)
+#define	MDDICAP1    (MDDI_CLIENT_CORE_BASE|0x04)
+#define	MDDICAP2    (MDDI_CLIENT_CORE_BASE|0x08)
+#define	MDDICAP3    (MDDI_CLIENT_CORE_BASE|0x0C)
+#define	MDCAPCHG    (MDDI_CLIENT_CORE_BASE|0x10)
+#define	MDCRCERC    (MDDI_CLIENT_CORE_BASE|0x14)
+#define	TTBUSSEL    (MDDI_CLIENT_CORE_BASE|0x18)
+#define	DPSET0      (MDDI_CLIENT_CORE_BASE|0x1C)
+#define	DPSET1      (MDDI_CLIENT_CORE_BASE|0x20)
+#define	DPSUS       (MDDI_CLIENT_CORE_BASE|0x24)
+#define	DPRUN       (MDDI_CLIENT_CORE_BASE|0x28)
+#define	SYSCKENA    (MDDI_CLIENT_CORE_BASE|0x2C)
+#define	TESTMODE    (MDDI_CLIENT_CORE_BASE|0x30)
+#define	FIFOMONI    (MDDI_CLIENT_CORE_BASE|0x34)
+#define	INTMONI     (MDDI_CLIENT_CORE_BASE|0x38)
+#define	MDIOBIST    (MDDI_CLIENT_CORE_BASE|0x3C)
+#define	MDIOPSET    (MDDI_CLIENT_CORE_BASE|0x40)
+#define	BITMAP0     (MDDI_CLIENT_CORE_BASE|0x44)
+#define	BITMAP1     (MDDI_CLIENT_CORE_BASE|0x48)
+#define	BITMAP2     (MDDI_CLIENT_CORE_BASE|0x4C)
+#define	BITMAP3     (MDDI_CLIENT_CORE_BASE|0x50)
+#define	BITMAP4     (MDDI_CLIENT_CORE_BASE|0x54)
+
+
+#define	SRST        (LCD_CONTROL_BLOCK_BASE|0x00)
+#define	PORT_ENB    (LCD_CONTROL_BLOCK_BASE|0x04)
+#define	START       (LCD_CONTROL_BLOCK_BASE|0x08)
+#define	PORT        (LCD_CONTROL_BLOCK_BASE|0x0C)
+#define	CMN         (LCD_CONTROL_BLOCK_BASE|0x10)
+#define	GAMMA       (LCD_CONTROL_BLOCK_BASE|0x14)
+#define	INTFLG      (LCD_CONTROL_BLOCK_BASE|0x18)
+#define	INTMSK      (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define	MPLFBUF     (LCD_CONTROL_BLOCK_BASE|0x20)
+#define	HDE_LEFT    (LCD_CONTROL_BLOCK_BASE|0x24)
+#define	VDE_TOP     (LCD_CONTROL_BLOCK_BASE|0x28)
+
+#define	PXL         (LCD_CONTROL_BLOCK_BASE|0x30)
+#define	HCYCLE      (LCD_CONTROL_BLOCK_BASE|0x34)
+#define	HSW         (LCD_CONTROL_BLOCK_BASE|0x38)
+#define	HDE_START   (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define	HDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x40)
+#define	VCYCLE      (LCD_CONTROL_BLOCK_BASE|0x44)
+#define	VSW         (LCD_CONTROL_BLOCK_BASE|0x48)
+#define	VDE_START   (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define	VDE_SIZE    (LCD_CONTROL_BLOCK_BASE|0x50)
+#define	WAKEUP      (LCD_CONTROL_BLOCK_BASE|0x54)
+#define	WSYN_DLY    (LCD_CONTROL_BLOCK_BASE|0x58)
+#define	REGENB      (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define	VSYNIF      (LCD_CONTROL_BLOCK_BASE|0x60)
+#define	WRSTB       (LCD_CONTROL_BLOCK_BASE|0x64)
+#define	RDSTB       (LCD_CONTROL_BLOCK_BASE|0x68)
+#define	ASY_DATA    (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define	ASY_DATB    (LCD_CONTROL_BLOCK_BASE|0x70)
+#define	ASY_DATC    (LCD_CONTROL_BLOCK_BASE|0x74)
+#define	ASY_DATD    (LCD_CONTROL_BLOCK_BASE|0x78)
+#define	ASY_DATE    (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define	ASY_DATF    (LCD_CONTROL_BLOCK_BASE|0x80)
+#define	ASY_DATG    (LCD_CONTROL_BLOCK_BASE|0x84)
+#define	ASY_DATH    (LCD_CONTROL_BLOCK_BASE|0x88)
+#define	ASY_CMDSET  (LCD_CONTROL_BLOCK_BASE|0x8C)
+
+#define	MONI        (LCD_CONTROL_BLOCK_BASE|0xB0)
+
+#define	Current     (LCD_CONTROL_BLOCK_BASE|0xC0)
+#define	LCD         (LCD_CONTROL_BLOCK_BASE|0xC4)
+#define	COMMAND     (LCD_CONTROL_BLOCK_BASE|0xC8)
+
+
+#define	SSICTL      (SPI_BLOCK_BASE|0x00)
+#define	SSITIME     (SPI_BLOCK_BASE|0x04)
+#define	SSITX       (SPI_BLOCK_BASE|0x08)
+#define	SSIRX       (SPI_BLOCK_BASE|0x0C)
+#define	SSIINTC     (SPI_BLOCK_BASE|0x10)
+#define	SSIINTS     (SPI_BLOCK_BASE|0x14)
+#define	SSIDBG1     (SPI_BLOCK_BASE|0x18)
+#define	SSIDBG2     (SPI_BLOCK_BASE|0x1C)
+#define	SSIID       (SPI_BLOCK_BASE|0x20)
+
+
+#define	I2CSETUP	(I2C_BLOCK_BASE|0x00)
+#define	I2CCTRL	    (I2C_BLOCK_BASE|0x04)
+
+
+#define	TIMER0LOAD	  (PWM_BLOCK_BASE|0x00)
+#define	TIMER0VALUE	  (PWM_BLOCK_BASE|0x04)
+#define	TIMER0CONTROL (PWM_BLOCK_BASE|0x08)
+#define	TIMER0INTCLR  (PWM_BLOCK_BASE|0x0C)
+#define	TIMER0RIS	  (PWM_BLOCK_BASE|0x10)
+#define	TIMER0MIS	  (PWM_BLOCK_BASE|0x14)
+#define	TIMER0BGLOAD  (PWM_BLOCK_BASE|0x18)
+#define	PWM0OFF	      (PWM_BLOCK_BASE|0x1C)
+#define	TIMER1LOAD	  (PWM_BLOCK_BASE|0x20)
+#define	TIMER1VALUE	  (PWM_BLOCK_BASE|0x24)
+#define	TIMER1CONTROL (PWM_BLOCK_BASE|0x28)
+#define	TIMER1INTCLR  (PWM_BLOCK_BASE|0x2C)
+#define	TIMER1RIS	  (PWM_BLOCK_BASE|0x30)
+#define	TIMER1MIS	  (PWM_BLOCK_BASE|0x34)
+#define	TIMER1BGLOAD  (PWM_BLOCK_BASE|0x38)
+#define	PWM1OFF	      (PWM_BLOCK_BASE|0x3C)
+#define	TIMERITCR	  (PWM_BLOCK_BASE|0x60)
+#define	TIMERITOP	  (PWM_BLOCK_BASE|0x64)
+#define	PWMCR	      (PWM_BLOCK_BASE|0x68)
+#define	PWMID	      (PWM_BLOCK_BASE|0x6C)
+#define	PWMMON	      (PWM_BLOCK_BASE|0x70)
+
+
+#define	GPIODATA    (GPIO_BLOCK_BASE|0x00)
+#define	GPIODIR     (GPIO_BLOCK_BASE|0x04)
+#define	GPIOIS      (GPIO_BLOCK_BASE|0x08)
+#define	GPIOIBE     (GPIO_BLOCK_BASE|0x0C)
+#define	GPIOIEV     (GPIO_BLOCK_BASE|0x10)
+#define	GPIOIE      (GPIO_BLOCK_BASE|0x14)
+#define	GPIORIS     (GPIO_BLOCK_BASE|0x18)
+#define	GPIOMIS     (GPIO_BLOCK_BASE|0x1C)
+#define	GPIOIC      (GPIO_BLOCK_BASE|0x20)
+#define	GPIOOMS     (GPIO_BLOCK_BASE|0x24)
+#define	GPIOPC      (GPIO_BLOCK_BASE|0x28)
+
+#define	GPIOID      (GPIO_BLOCK_BASE|0x30)
+
+
+#define	WKREQ       (SYSTEM_BLOCK1_BASE|0x00)
+#define	CLKENB      (SYSTEM_BLOCK1_BASE|0x04)
+#define	DRAMPWR     (SYSTEM_BLOCK1_BASE|0x08)
+#define	INTMASK     (SYSTEM_BLOCK1_BASE|0x0C)
+#define	GPIOSEL     (SYSTEM_BLOCK2_BASE|0x00)
+
+struct init_table {
+    unsigned int reg;
+    unsigned int val;
+};
+
+static struct init_table toshiba_480x640_init_table[] = {
+	{ DPSET0,               0x4BEC0066 },  // # MDC.DPSET0  # Setup DPLL parameters
+	{ DPSET1,               0x00000113 },  //   # MDC.DPSET1  
+	{ DPSUS,                0x00000000 },  //   # MDC.DPSUS  # Set DPLL oscillation enable
+	{ DPRUN,                0x00000001 },  //   # MDC.DPRUN  # Release reset signal for DPLL
+	{ 0,                    14         },  // wait_ms(14);
+	{ SYSCKENA,             0x00000001 },  //   # MDC.SYSCKENA  # Enable system clock output
+	{ CLKENB,               0x000000EF },  //   # SYS.CLKENB  # Enable clocks for each module (without DCLK , i2cCLK)
+	{ GPIO_BLOCK_BASE,      0x03FF0000 },  //   # GPI .GPIODATA  # GPIO2(RESET_LCD_N) set to 0 , GPIO3(eDRAM_Power) set to 0
+	{ GPIODIR,              0x0000024D },  //   # GPI .GPIODIR  # Select direction of GPIO port (0,2,3,6,9 output)
+	{ SYSTEM_BLOCK2_BASE,   0x00000173 },  //   # SYS.GPIOSEL  # GPIO port multiplexing control
+	{ GPIOPC,               0x03C300C0 },  //   # GPI .GPIOPC  # GPIO2,3 PD cut
+	{ SYSTEM_BLOCK1_BASE,   0x00000000 },  //   # SYS.WKREQ  # Wake-up request event is VSYNC alignment
+	{ GPIOIS,               0x00000000 },  //   # GPI .GPIOIS  # Set interrupt sense of GPIO
+	{ GPIOIEV,              0x00000001 },  //   # GPI .GPIOIEV  # Set interrupt event of GPIO
+	{ GPIOIC,               0x000003FF },  //   # GPI .GPIOIC  # GPIO interrupt clear
+	{ GPIO_BLOCK_BASE,      0x00060006 },  //   # GPI .GPIODATA  # Release LCDD reset
+	{ GPIO_BLOCK_BASE,      0x00080008 },  //   # GPI .GPIODATA  # eDRAM VD supply
+	{ GPIO_BLOCK_BASE,      0x02000200 },  //   # GPI .GPIODATA  # TEST LED ON
+	{ DRAMPWR,              0x00000001 },  //   # SYS.DRAMPWR  # eDRAM power up
+	{ TIMER0CONTROL,        0x00000060 },  //   # PWM.Timer0Control  # PWM0 output stop
+	{ PWM_BLOCK_BASE,       0x00001388 },  //   # PWM.Timer0Load  # PWM0 10kHz , Duty 99 (BackLight OFF)
+	//{PWM0OFF,               0x00000001 },  //   # PWM.PWM0OFF  
+#if 0
+	{ PWM0OFF,              0x00001387 }, // SURF 100% backlight
+	{ PWM0OFF,              0x00000000 }, // FFA 100% backlight
+#endif
+	{ PWM0OFF,              0x000009C3 }, // 50% BL
+	{ TIMER1CONTROL,        0x00000060 },  //   # PWM.Timer1Control  # PWM1 output stop
+	{ TIMER1LOAD,           0x00001388 },  //   # PWM.Timer1Load  # PWM1 10kHz , Duty 99 (BackLight OFF)
+	//{PWM1OFF,               0x00000001 },  //   # PWM.PWM1OFF  
+	{ PWM1OFF,              0x00001387 },
+	{ TIMER0CONTROL,        0x000000E0 },  //   # PWM.Timer0Control  # PWM0 output start
+	{ TIMER1CONTROL,        0x000000E0 },  //   # PWM.Timer1Control  # PWM1 output start
+	{ PWMCR,                0x00000003 },  //   # PWM.PWMCR  # PWM output enable
+	{ 0,                    1          },  //  wait_ms(1);        
+	{ SPI_BLOCK_BASE,       0x00000799 },  //   # SPI .SSICTL  # SPI operation mode setting
+	{ SSITIME,              0x00000100 },  //   # SPI .SSITIME  # SPI serial interface timing setting
+	{ SPI_BLOCK_BASE,       0x0000079b },  //   # SPI .SSICTL  # Set SPI active mode
+
+	{ SSITX,                0x00000000 },  //   # SPI.SSITX  # Release from Deep Stanby mode
+	{ 0,                    1          },  //  wait_ms(1);
+	{ SSITX,                0x00000000 },  //   # SPI.SSITX  
+	{ 0,                    1          },  //  wait_ms(1);
+	{ SSITX,                0x00000000 },  //   # SPI.SSITX  
+	{ 0,                    1          },  //  wait_ms(1);
+	{ SSITX,                0x000800BA },  //   # SPI.SSITX          *NOTE 1  # Command setting of SPI block
+	{ SSITX,                0x00000111 },  //     # Display mode setup(1) : Normaly Black
+	{ SSITX,                0x00080036 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000100 },  //     # Memory access control
+	{ 0,                    2          },  //  wait_ms(2);    //      #  Wait SPI fifo empty
+	{ SSITX,                0x000800BB },  //   # Command setting of SPI block
+	{ SSITX,                0x00000100 },  //   # Display mode setup(2)
+	{ SSITX,                0x0008003A },  //   # Command setting of SPI block
+	{ SSITX,                0x00000160 },  //   # RGB Interface data format
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800BF },  //   # Command setting of SPI block
+	{ SSITX,                0x00000100 },  //   # Drivnig method
+	{ SSITX,                0x000800B1 },  //   # Command setting of SPI block
+	{ SSITX,                0x0000015D },  //   # Booster operation setup
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800B2 },  //   # Command setting of SPI block
+	{ SSITX,                0x00000133 },  //   # Booster mode setup
+	{ SSITX,                0x000800B3 },  //   # Command setting of SPI block
+	{ SSITX,                0x00000122 },  //     # Booster frequencies setup
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800B4 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000102 },  //     # OP-amp capability/System clock freq. division setup
+	{ SSITX,                0x000800B5 },  //     # Command setting of SPI block
+	{ SSITX,                0x0000011F },  //     # VCS Voltage adjustment  (1C->1F for Rev 2)
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800B6 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000128 },  //     # VCOM Voltage adjustment
+	{ SSITX,                0x000800B7 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000103 },  //     # Configure an external display signal
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800B9 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000120 },  //     # DCCK/DCEV timing setup
+	{ SSITX,                0x000800BD },  //     # Command setting of SPI block
+	{ SSITX,                0x00000102 },  //     # ASW signal control
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800BE },  //     # Command setting of SPI block
+	{ SSITX,                0x00000100 },  //     # Dummy display (white/black) count setup for QUAD Data operation
+	{ SSITX,                0x000800C0 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000111 },  //     # wait_ms(-out FR count setup (A)
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C1 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000111 },  //     # wait_ms(-out FR count setup (B)
+	{ SSITX,                0x000800C2 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000111 },  //     # wait_ms(-out FR count setup (C)
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C3 },  //     # Command setting of SPI block
+	{ SSITX,                0x0008010A },  //     # wait_ms(-in line clock count setup (D)
+	{ SSITX,                0x0000010A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C4 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080160 },  //     # Seep-in line clock count setup (E)
+	{ SSITX,                0x00000160 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C5 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080160 },  //     # wait_ms(-in line clock count setup (F)
+	{ SSITX,                0x00000160 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C6 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080160 },  //     # wait_ms(-in line clock setup (G)
+	{ SSITX,                0x00000160 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C7 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080133 },  //     # Gamma 1 fine tuning (1)
+	{ SSITX,                0x00000143 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800C8 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000144 },  //     # Gamma 1 fine tuning (2)
+	{ SSITX,                0x000800C9 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000133 },  //     # Gamma 1 inclination adjustment
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800CA },  //     # Command setting of SPI block
+	{ SSITX,                0x00000100 },  //     # Gamma 1 blue offset adjustment
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800EC },  //     # Command setting of SPI block
+	{ SSITX,                0x00080102 },  //     # Total number of horizontal clock cycles (1) [PCLK Sync. VGA setting]
+	{ SSITX,                0x00000118 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800CF },  //     # Command setting of SPI block
+	{ SSITX,                0x00000101 },  //     # Blanking period control (1) [PCLK Sync. Table1 for VGA]
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D0 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080110 },  //     # Blanking period control (2) [PCLK Sync. Table1 for VGA]
+	{ SSITX,                0x00000104 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D1 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000101 },  //     # CKV timing control on/off [PCLK Sync. Table1 for VGA]
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D2 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080100 },  //     # CKV1,2 timing control [PCLK Sync. Table1 for VGA]
+	{ SSITX,                0x0000013A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D3 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080100 },  //     # OEV timing control [PCLK Sync. Table1 for VGA]
+	{ SSITX,                0x0000013A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D4 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080124 },  //     # ASW timing control (1) [PCLK Sync. Table1 for VGA]
+	{ SSITX,                0x0000016E },  //     
+	{ 0,                    1          },  //  wait_ms(1);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D5 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000124 },  //     # ASW timing control (2) [PCLK Sync. Table1 for VGA]
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800ED },  //     # Command setting of SPI block
+	{ SSITX,                0x00080101 },  //     # Total number of horizontal clock cycles (2) [PCLK Sync. Table1 for QVGA ]
+	{ SSITX,                0x0000010A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D6 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000101 },  //     # Blanking period control (1) [PCLK Sync. Table2 for QVGA]
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D7 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080110 },  //     # Blanking period control (2) [PCLK Sync. Table2 for QVGA]
+	{ SSITX,                0x0000010A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D8 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000101 },  //     # CKV timing control on/off [PCLK Sync. Table2 for QVGA]
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800D9 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080100 },  //     # CKV1,2 timing control [PCLK Sync. Table2 for QVGA]
+	{ SSITX,                0x00000114 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800DE },  //     # Command setting of SPI block
+	{ SSITX,                0x00080100 },  //     # OEV timing control [PCLK Sync. Table2 for QVGA]
+	{ SSITX,                0x00000114 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800DF },  //     # Command setting of SPI block
+	{ SSITX,                0x00080112 },  //     # ASW timing control (1) [PCLK Sync. Table2 for QVGA]
+	{ SSITX,                0x0000013F },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E0 },  //     # Command setting of SPI block
+	{ SSITX,                0x0000010B },  //     # ASW timing control (2) [PCLK Sync. Table2 for QVGA]
+	{ SSITX,                0x000800E2 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000101 },  //     # Built-in oscillator frequency division setup [Frequency division ratio : 2 (60Hq)
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E3 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000136 },  //     # Built-in oscillator clock count setup
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E4 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080100 },  //     # CKV timing control for using build-in osc
+	{ SSITX,                0x00000103 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E5 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080102 },  //     # OEV timing control for using build-in osc
+	{ SSITX,                0x00000104 },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E6 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000103 },  //     # DCEV timing control for using build-in osc
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E7 },  //     # Command setting of SPI block
+	{ SSITX,                0x00080104 },  //     # ASW timing setup for using build-in osc(1)
+	{ SSITX,                0x0000010A },  //     
+	{ 0,                    2          },  //  wait_ms(2);      //    #  Wait SPI fifo empty
+	{ SSITX,                0x000800E8 },  //     # Command setting of SPI block
+	{ SSITX,                0x00000104 },  //     # ASW timing setup for using build-in osc(2)
+            
+            
+	{ CLKENB,               0x000001EF },  //   # SYS.CLKENB  # DCLK enable
+	{ START,                0x00000000 },  //   # LCD.START  # LCDC wait_ms( mode
+	{ WRSTB,                0x0000003F },  //   # LCD.WRSTB  # write_client_reg( strobe
+	{ RDSTB,                0x00000432 },  //   # LCD.RDSTB  # Read strobe
+	{ PORT_ENB,             0x00000002 },  //   # LCD.PORT_ENB  # Asynchronous port enable
+	{ VSYNIF,               0x00000000 },  //   # LCD.VSYNCIF  # VSYNC I/F mode set
+	{ ASY_DATA,             0x80000000 },  //   # LCD.ASY_DATx  # Index setting of SUB LCDD
+	{ ASY_DATB,             0x00000001 },  //     # Oscillator start
+	{ ASY_CMDSET,           0x00000005 },  //   # LCD.ASY_CMDSET  # Direct command transfer enable
+	{ ASY_CMDSET,           0x00000004 },  //   # LCD.ASY_CMDSET  # Direct command transfer disable
+	{ 0,                    10         },  //  wait_ms(10);
+	{ ASY_DATA,             0x80000000 },  //   # LCD.ASY_DATx  # DUMMY write_client_reg(@*NOTE2
+	{ ASY_DATB,             0x80000000 },  //     
+	{ ASY_DATC,             0x80000000 },  //     
+	{ ASY_DATD,             0x80000000 },  //     
+	{ ASY_CMDSET,           0x00000009 },  //   # LCD.ASY_CMDSET  
+	{ ASY_CMDSET,           0x00000008 },  //   # LCD.ASY_CMDSET  
+	{ ASY_DATA,             0x80000007 },  //   # LCD.ASY_DATx  # Index setting of SUB LCDD
+	{ ASY_DATB,             0x00004005 },  //     # LCD driver control
+	{ ASY_CMDSET,           0x00000005 },  //   # LCD.ASY_CMDSET  # Direct command transfer enable
+	{ ASY_CMDSET,           0x00000004 },  //   # LCD.ASY_CMDSET  # Direct command transfer disable
+	{ 0,                    20         },  //  wait_ms(20);
+	{ ASY_DATA,             0x80000059 },  //   # LCD.ASY_DATx  # Index setting of SUB LCDD
+	{ ASY_DATB,             0x00000000 },  //     # LTPS I/F control
+	{ ASY_CMDSET,           0x00000005 },  //   # LCD.ASY_CMDSET  # Direct command transfer enable
+	{ ASY_CMDSET,           0x00000004 },  //   # LCD.ASY_CMDSET  # Direct command transfer disable
+
+	{ VSYNIF,               0x00000001 },  //   # LCD.VSYNCIF  # VSYNC I/F mode OFF
+	{ PORT_ENB,             0x00000001 },  //   # LCD.PORT_ENB  # SYNC I/F  output select
+
+	/******************************/
+
+	{ VSYNIF,               0x00000001 },  // VSYNC I/F mode OFF
+	{ PORT_ENB,             0x00000001 },  // SYNC I/F mode ON
+
+	{ BITMAP1,              0x01E000F0 },  // MDC.BITMAP2  ); // Setup of PITCH size to Frame buffer1
+	{ BITMAP2,              0x01E000F0 },  // MDC.BITMAP3  ); // Setup of PITCH size to Frame buffer2
+	{ BITMAP3,              0x01E000F0 },  // MDC.BITMAP4  ); // Setup of PITCH size to Frame buffer3
+	{ BITMAP4,              0x00DC00B0 },  // MDC.BITMAP5  ); // Setup of PITCH size to Frame buffer4
+	{ CLKENB,               0x000001EF },  // SYS.CLKENB  ); // DCLK supply
+	{ PORT_ENB,             0x00000001 },  // LCD.PORT_ENB  ); // Synchronous port enable
+	{ PORT,                 0x00000004 },  // LCD.PORT  ); // Polarity of DE is set to high active
+	{ PXL,                  0x00000002 },  // LCD.PXL  ); // ACTMODE 2 set (1st frame black data output)
+	{ MPLFBUF,              0x00000000 },  // LCD.MPLFBUF  ); // Select the reading buffer
+	{ HCYCLE,               0x0000010b },  // LCD.HCYCLE  ); // Setup to VGA size
+	{ HSW,                  0x00000003 },  // LCD.HSW  
+	{ HDE_START,            0x00000007 },  // LCD.HDE_START  
+	{ HDE_SIZE,             0x000000EF },  // LCD.HDE_SIZE  
+	{ VCYCLE,               0x00000285 },  // LCD.VCYCLE  
+	{ VSW,                  0x00000001 },  // LCD.VSW  
+	{ VDE_START,            0x00000003 },  // LCD.VDE_START  
+	{ VDE_SIZE,             0x0000027F },  // LCD.VDE_SIZE  
+
+	{ START,                0x00000001 },  // LCD.START  ); // LCDC - Pixel data transfer start
+
+	{ 0,                    10         },  //  wait_ms( 10  );
+	{ SSITX,                0x000800BC },  // SPI.SSITX  ); // Command setting of SPI block
+	{ SSITX,                0x00000180 },  // Display data setup
+	{ SSITX,                0x0008003B },  // Command setting of SPI block
+	{ SSITX,                0x00000100 },  // Quad Data configuration - VGA
+	{ 0,                    1          },  //  wait_ms( 1          ); //  Wait SPI fifo empty
+	{ SSITX,                0x000800B0 },  // Command setting of SPI block
+	{ SSITX,                0x00000116 },  // Power supply ON/OFF control
+	{ 0,                    1          },  //  wait_ms( 1          ); //  Wait SPI fifo empty
+	{ SSITX,                0x000800B8 },  // Command setting of SPI block
+	{ SSITX,                0x000801FF },  // Output control
+	{ SSITX,                0x000001F5 },   
+	{ 0,                    1          },  //  wait_ms( 1);         //  Wait SPI fifo empty
+	{ SSITX,                0x00000011 },  // wait_ms(-out (Command only)
+	{ SSITX,                0x00000029 },  // Display on (Command only)
+
+	{ SYSTEM_BLOCK1_BASE,   0x00000002 },  //    # wakeREQ -> GPIO
+
+	{ 0, 0 }
+};
+
+static void _panel_init(struct init_table *init_table)
+{
+	unsigned n;
+
+	dprintf(INFO, "panel_init()\n");
+
+	n = 0;
+	while (init_table[n].reg != 0 || init_table[n].val != 0) {
+		if (init_table[n].reg != 0)
+			mddi_remote_write(init_table[n].val, init_table[n].reg);
+		else
+			thread_sleep(init_table[n].val);//mdelay(init_table[n].val);
+		n++;
+	}
+
+	dprintf(INFO, "panel_init() done\n");
+}
+
+void panel_init(struct mddi_client_caps *client_caps)
+{
+	switch(client_caps->manufacturer_name) {
+	case 0xd263: // Toshiba
+		dprintf(INFO, "Found Toshiba panel\n");
+		_panel_init(toshiba_480x640_init_table);
+		break;
+	case 0x4474: //??
+		if (client_caps->product_code == 0xc065)
+			dprintf(INFO, "Found WVGA panel\n");
+		break;
+	}
+}
+
+void panel_poweron(void)
+{
+	gpio_set(88, 0);
+	gpio_config(88, GPIO_OUTPUT);
+	thread_sleep(1); //udelay(10);
+	gpio_set(88, 1);
+	thread_sleep(10); //mdelay(10);
+
+	//mdelay(1000); // uncomment for second stage boot
+}
+
+void panel_backlight(int on)
+{}
diff --git a/target/surf-msm7k/rules.mk b/target/surf-msm7k/rules.mk
index 4593475..597628e 100644
--- a/target/surf-msm7k/rules.mk
+++ b/target/surf-msm7k/rules.mk
@@ -7,14 +7,15 @@
 MEMBASE := 0x00000000 # SMI
 MEMSIZE := 0x00800000 # 8MB
 
-DEFINES += SDRAM_SIZE=$(MEMSIZE) MEMBASE=$(MEMBASE)
-
 KEYS_USE_GPIO_KEYPAD := 1
 
 MODULES += \
 	dev/keys \
 	lib/ptable
 
+DEFINES += SDRAM_SIZE=$(MEMSIZE) MEMBASE=$(MEMBASE)
+
 OBJS += \
 	$(LOCAL_DIR)/init.o \
-	$(LOCAL_DIR)/keypad.o
+	$(LOCAL_DIR)/keypad.o \
+	$(LOCAL_DIR)/panel.o