[coreboot-gerrit] New patch to review for coreboot: 333b0b3 tegra132: Add dsi driver

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Apr 10 13:17:40 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9517

-gerrit

commit 333b0b31fcf9d2a345984fdbef792dff197ca841
Author: Jimmy Zhang <jimmzhang at nvidia.com>
Date:   Mon Sep 15 16:50:36 2014 -0700

    tegra132: Add dsi driver
    
    Add dsi and related dc, panel configuration functions.
    
    BRANCH=none
    BUG=chrome-os-partner:31936
    TEST=build and test on ryu
    
    Change-Id: I8440b6dfccc7ed7cd280a0df3a98cbc7b7d66070
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: fb08563f67daf9a616b60609c4523b823d34f8e3
    Original-Change-Id: I87b8047e23ebe114af353fcce5924a46621d16d2
    Original-Signed-off-by: Jimmy Zhang <jimmzhang at nvidia.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/227202
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
    Original-Commit-Queue: Aaron Durbin <adurbin at chromium.org>
---
 src/soc/nvidia/tegra/dc.h                          |   1 +
 src/soc/nvidia/tegra/types.h                       |  76 ++
 src/soc/nvidia/tegra132/Makefile.inc               |   7 +
 src/soc/nvidia/tegra132/chip.h                     |   4 -
 src/soc/nvidia/tegra132/display.c                  | 297 +++++++
 src/soc/nvidia/tegra132/include/soc/addressmap.h   |   3 +
 src/soc/nvidia/tegra132/include/soc/display.h      | 187 +----
 src/soc/nvidia/tegra132/include/soc/mipi-phy.h     |  46 ++
 src/soc/nvidia/tegra132/include/soc/mipi_display.h | 148 ++++
 src/soc/nvidia/tegra132/include/soc/mipi_dsi.h     | 283 +++++++
 src/soc/nvidia/tegra132/include/soc/tegra_dsi.h    | 219 ++++++
 .../jdi_25x18_display/panel-jdi-lpm102a188a.c      | 213 +++++
 .../jdi_25x18_display/panel-jdi-lpm102a188a.h      | 131 +++
 src/soc/nvidia/tegra132/mipi-phy.c                 |  92 +++
 src/soc/nvidia/tegra132/mipi.c                     | 151 ++++
 src/soc/nvidia/tegra132/mipi_dsi.c                 | 431 ++++++++++
 src/soc/nvidia/tegra132/soc.c                      |   5 -
 src/soc/nvidia/tegra132/tegra_dsi.c                | 874 +++++++++++++++++++++
 18 files changed, 2986 insertions(+), 182 deletions(-)

diff --git a/src/soc/nvidia/tegra/dc.h b/src/soc/nvidia/tegra/dc.h
index ff36a0b..0d2d761 100644
--- a/src/soc/nvidia/tegra/dc.h
+++ b/src/soc/nvidia/tegra/dc.h
@@ -24,6 +24,7 @@
 
 #ifndef __SOC_NVIDIA_TEGRA_DC_H
 #define __SOC_NVIDIA_TEGRA_DC_H
+#include <stddef.h>
 
 /* Register definitions for the Tegra display controller */
 
diff --git a/src/soc/nvidia/tegra/types.h b/src/soc/nvidia/tegra/types.h
new file mode 100644
index 0000000..ce0b6bb
--- /dev/null
+++ b/src/soc/nvidia/tegra/types.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TEGRA_MISC_TYPES_H__
+#define __TEGRA_MISC_TYPES_H__
+
+#define EFAULT		1
+#define EINVAL		2
+#define ETIMEDOUT 	3
+#define ENOSPC		4
+#define ENOSYS		5
+#define EPTR		6
+
+#define IS_ERR_PTR(ptr) \
+		(ptr == (void *)-EPTR)
+
+#ifndef bool
+#define bool int
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+#define DIV_ROUND_UP(x, y)  (((x) + (y) - 1) / (y))
+
+/*
+ * Divide positive or negative dividend by positive divisor and round
+ * to closest integer. Result is undefined for negative divisors and
+ * for negative dividends if the divisor variable type is unsigned.
+ */
+#define DIV_ROUND_CLOSEST(x, divisor)(			\
+{							\
+	typeof(x) __x = x;				\
+	typeof(divisor) __d = divisor;			\
+	(((typeof(x))-1) > 0 ||				\
+	 ((typeof(divisor))-1) > 0 || (__x) > 0) ?	\
+		(((__x) + ((__d) / 2)) / (__d)) :	\
+		(((__x) - ((__d) / 2)) / (__d));	\
+}							\
+)
+
+#endif /* __TEGRA_MISC_TYPES_H__ */
diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc
index 117f629..a7485fa 100644
--- a/src/soc/nvidia/tegra132/Makefile.inc
+++ b/src/soc/nvidia/tegra132/Makefile.inc
@@ -66,6 +66,13 @@ ramstage-y += cbmem.c
 ramstage-y += cpu.c
 ramstage-y += cpu_lib.S
 ramstage-y += clock.c
+ramstage-y += display.c
+ramstage-y += tegra_dsi.c
+ramstage-y += mipi_dsi.c
+ramstage-y += mipi.c
+ramstage-y += mipi-phy.c
+ramstage-y += ./jdi_25x18_display/panel-jdi-lpm102a188a.c
+
 ramstage-y += soc.c
 ramstage-y += spi.c
 ramstage-y += i2c.c
diff --git a/src/soc/nvidia/tegra132/chip.h b/src/soc/nvidia/tegra132/chip.h
index 23f2cd8..35e72d5 100644
--- a/src/soc/nvidia/tegra132/chip.h
+++ b/src/soc/nvidia/tegra132/chip.h
@@ -19,13 +19,9 @@
 
 #ifndef __SOC_NVIDIA_TEGRA132_CHIP_H__
 #define __SOC_NVIDIA_TEGRA132_CHIP_H__
-#include <arch/cache.h>
 #include <soc/addressmap.h>
 #include <stdint.h>
 
-#define EFAULT  1
-#define EINVAL  2
-
 struct soc_nvidia_tegra132_config {
 	/* Address to monitor if spintable employed. */
 	uintptr_t spintable_addr;
diff --git a/src/soc/nvidia/tegra132/display.c b/src/soc/nvidia/tegra132/display.c
new file mode 100644
index 0000000..62cea02
--- /dev/null
+++ b/src/soc/nvidia/tegra132/display.c
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <string.h>
+#include <cpu/cpu.h>
+#include <boot/tables.h>
+#include <cbmem.h>
+#include <soc/clock.h>
+#include <soc/nvidia/tegra/dc.h>
+#include <soc/funitcfg.h>
+#include "chip.h"
+#include <soc/display.h>
+
+int dump = 0;
+unsigned long READL(void * p)
+{
+        unsigned long value;
+
+	/*
+	 * In case of hard hung on readl(p), we can set dump > 1 to print out
+	 * the address accessed.
+	 */
+        if (dump > 1)
+		printk(BIOS_SPEW, "readl %p\n", p);
+
+        value = readl(p);
+        if (dump)
+		printk(BIOS_SPEW, "readl %p %08lx\n", p, value);
+        return value;
+}
+
+void WRITEL(unsigned long value, void * p)
+{
+        if (dump)
+		printk(BIOS_SPEW, "writel %p %08lx\n", p, value);
+        writel(value, p);
+}
+
+/* return in 1000ths of a Hertz */
+static int tegra_calc_refresh(const struct soc_nvidia_tegra132_config *config)
+{
+	int refresh;
+	int h_total = htotal(config);
+	int v_total = vtotal(config);
+	int pclk = config->pixel_clock;
+
+	if (!pclk || !h_total || !v_total)
+		return 0;
+	refresh = pclk / h_total;
+	refresh *= 1000;
+	refresh /= v_total;
+	return refresh;
+}
+
+static void print_mode(const struct soc_nvidia_tegra132_config *config)
+{
+	if (config) {
+		int refresh = tegra_calc_refresh(config);
+		printk(BIOS_ERR,
+			"MODE:%dx%d@%d.%03uHz pclk=%d\n",
+			config->xres, config->yres,
+			refresh / 1000, refresh % 1000,
+			config->pixel_clock);
+	}
+}
+
+static int update_display_mode(struct display_controller *disp_ctrl,
+			       struct soc_nvidia_tegra132_config *config)
+{
+	print_mode(config);
+
+	printk(BIOS_ERR, "config:      xres:yres: %d x %d\n ",
+			config->xres, config->yres);
+	printk(BIOS_ERR, "   href_sync:vref_sync: %d x %d\n ",
+			config->href_to_sync, config->vref_to_sync);
+	printk(BIOS_ERR, " hsyn_width:vsyn_width: %d x %d\n ",
+			config->hsync_width, config->vsync_width);
+	printk(BIOS_ERR, " hfnt_porch:vfnt_porch: %d x %d\n ",
+			config->hfront_porch, config->vfront_porch);
+	printk(BIOS_ERR, "   hbk_porch:vbk_porch: %d x %d\n ",
+			config->hback_porch, config->vback_porch);
+
+	WRITEL(0x0, &disp_ctrl->disp.disp_timing_opt);
+	WRITEL(0x0, &disp_ctrl->disp.disp_color_ctrl);
+
+	// select DSI
+	WRITEL(DSI_ENABLE, &disp_ctrl->disp.disp_win_opt);
+
+	WRITEL(config->vref_to_sync << 16 | config->href_to_sync,
+		&disp_ctrl->disp.ref_to_sync);
+
+	WRITEL(config->vsync_width << 16 | config->hsync_width,
+		&disp_ctrl->disp.sync_width);
+
+
+	WRITEL((config->vback_porch << 16) | config->hback_porch,
+		&disp_ctrl->disp.back_porch);
+
+	WRITEL((config->vfront_porch << 16) | config->hfront_porch,
+		&disp_ctrl->disp.front_porch);
+
+	WRITEL(config->xres | (config->yres << 16),
+		&disp_ctrl->disp.disp_active);
+
+	/**
+	 * We want to use PLLD_out0, which is PLLD / 2:
+	 *   PixelClock = (PLLD / 2) / ShiftClockDiv / PixelClockDiv.
+	 *
+	 * Currently most panels work inside clock range 50MHz~100MHz, and PLLD
+	 * has some requirements to have VCO in range 500MHz~1000MHz (see
+	 * clock.c for more detail). To simplify calculation, we set
+	 * PixelClockDiv to 1 and ShiftClockDiv to 1. In future these values
+	 * may be calculated by clock_display, to allow wider frequency range.
+	 *
+	 * Note ShiftClockDiv is a 7.1 format value.
+	 */
+	const u32 shift_clock_div = 1;
+	WRITEL((PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT) |
+	       ((shift_clock_div - 1) * 2 + 1) << SHIFT_CLK_DIVIDER_SHIFT,
+	       &disp_ctrl->disp.disp_clk_ctrl);
+	printk(BIOS_DEBUG, "%s: PixelClock=%u, ShiftClockDiv=%u\n",
+	       __func__, config->pixel_clock, shift_clock_div);
+	return 0;
+}
+
+/*
+ * update_window:
+ *   set up window registers and activate window except two:
+ *   frame buffer base address register (WINBUF_START_ADDR) and
+ *   display enable register (_DISP_DISP_WIN_OPTIONS). This is
+ *   becasue framebuffer is not available until payload stage.
+ */
+static void update_window(const struct soc_nvidia_tegra132_config *config)
+{
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+	u32 val;
+
+	WRITEL(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header);
+
+	WRITEL(((config->yres << 16) | config->xres), &disp_ctrl->win.size);
+	WRITEL(((config->yres << 16) |
+		(config->xres * config->framebuffer_bits_per_pixel / 8)),
+		&disp_ctrl->win.prescaled_size);
+
+	val = ALIGN_UP((config->xres * config->framebuffer_bits_per_pixel / 8),
+			64);
+	WRITEL(val, &disp_ctrl->win.line_stride);
+
+	WRITEL(config->color_depth, &disp_ctrl->win.color_depth);
+	WRITEL(COLOR_BLACK, &disp_ctrl->disp.blend_background_color);
+	WRITEL((V_DDA_INC(0x1000) | H_DDA_INC(0x1000)),
+		&disp_ctrl->win.dda_increment);
+
+	WRITEL(DISP_CTRL_MODE_C_DISPLAY, &disp_ctrl->cmd.disp_cmd);
+
+	WRITEL(WRITE_MUX_ACTIVE, &disp_ctrl->cmd.state_access);
+
+	WRITEL(0, &disp_ctrl->win.buffer_addr_mode);
+
+	val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+		PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+	WRITEL(val, &disp_ctrl->cmd.disp_pow_ctrl);
+
+	val = GENERAL_UPDATE | WIN_A_UPDATE;
+	val |= GENERAL_ACT_REQ | WIN_A_ACT_REQ;
+	WRITEL(val, &disp_ctrl->cmd.state_ctrl);
+}
+
+static int tegra_dc_init(struct display_controller *disp_ctrl)
+{
+	/* do not accept interrupts during initialization */
+	WRITEL(0x00000000, &disp_ctrl->cmd.int_mask);
+	WRITEL(WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY,
+		&disp_ctrl->cmd.state_access);
+	WRITEL(WINDOW_A_SELECT, &disp_ctrl->cmd.disp_win_header);
+	WRITEL(0x00000000, &disp_ctrl->win.win_opt);
+	WRITEL(0x00000000, &disp_ctrl->win.byte_swap);
+	WRITEL(0x00000000, &disp_ctrl->win.buffer_ctrl);
+
+	WRITEL(0x00000000, &disp_ctrl->win.pos);
+	WRITEL(0x00000000, &disp_ctrl->win.h_initial_dda);
+	WRITEL(0x00000000, &disp_ctrl->win.v_initial_dda);
+	WRITEL(0x00000000, &disp_ctrl->win.dda_increment);
+	WRITEL(0x00000000, &disp_ctrl->win.dv_ctrl);
+
+	WRITEL(0x01000000, &disp_ctrl->win.blend_layer_ctrl);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_match_select);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_nomatch_select);
+	WRITEL(0x00000000, &disp_ctrl->win.blend_alpha_1bit);
+
+	WRITEL(0x00000000, &disp_ctrl->winbuf.start_addr_hi);
+	WRITEL(0x00000000, &disp_ctrl->winbuf.addr_h_offset);
+	WRITEL(0x00000000, &disp_ctrl->winbuf.addr_v_offset);
+
+	WRITEL(0x00000000, &disp_ctrl->com.crc_checksum);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[0]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[1]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[2]);
+	WRITEL(0x00000000, &disp_ctrl->com.pin_output_enb[3]);
+	WRITEL(0x00000000, &disp_ctrl->disp.disp_signal_opt0);
+
+	return 0;
+}
+
+void display_startup(device_t dev)
+{
+	struct soc_nvidia_tegra132_config *config = dev->chip_info;
+	struct display_controller *disp_ctrl =
+			(void *)config->display_controller;
+	u32 plld_rate;
+
+	u32 framebuffer_size_mb = config->framebuffer_size / MiB;
+	u32 framebuffer_base_mb= config->framebuffer_base / MiB;
+
+	printk(BIOS_INFO, "%s: entry: disp_ctrl: %p.\n",
+		 __func__, disp_ctrl);
+
+	if (disp_ctrl == NULL) {
+		printk(BIOS_ERR, "Error: No dc is assigned by dt.\n");
+		return;
+	}
+
+	if (framebuffer_size_mb == 0){
+		framebuffer_size_mb = ALIGN_UP(config->xres * config->yres *
+			(config->framebuffer_bits_per_pixel / 8), MiB)/MiB;
+	}
+
+	config->framebuffer_size = framebuffer_size_mb * MiB;
+	config->framebuffer_base = framebuffer_base_mb * MiB;
+
+	/*
+	 * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER
+	 * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the
+	 * update_display_mode() for detail.
+	 */
+	/* set default plld */
+	plld_rate = clock_display(config->pixel_clock * 2);
+	if (plld_rate == 0) {
+		printk(BIOS_ERR, "dc: clock init failed\n");
+		return;
+	} else if (plld_rate != config->pixel_clock * 2) {
+		printk(BIOS_WARNING, "dc: plld rounded to %u\n", plld_rate);
+	}
+
+	/* set disp1's clock source to PLLD_OUT0 */
+	clock_configure_source(disp1, PLLD, (plld_rate/KHz)/2);
+
+	/* Init dc */
+	if (tegra_dc_init(disp_ctrl)) {
+		printk(BIOS_ERR, "dc: init failed\n");
+		return;
+	}
+
+	/* Configure dc mode */
+	if (update_display_mode(disp_ctrl, config)) {
+		printk(BIOS_ERR, "dc: failed to configure display mode.\n");
+		return;
+	}
+
+	/* Configure and enable dsi controller and panel */
+	if (dsi_enable(config)) {
+		printk(BIOS_ERR, "%s: failed to enable dsi controllers.\n",
+			__func__);
+		return;
+	}
+
+	/* set up window */
+	update_window(config);
+
+	printk(BIOS_INFO, "%s: display init done.\n", __func__);
+}
+
diff --git a/src/soc/nvidia/tegra132/include/soc/addressmap.h b/src/soc/nvidia/tegra132/include/soc/addressmap.h
index 7913521..36b0233 100644
--- a/src/soc/nvidia/tegra132/include/soc/addressmap.h
+++ b/src/soc/nvidia/tegra132/include/soc/addressmap.h
@@ -35,6 +35,8 @@ enum {
 	TEGRA_GICC_BASE =		0x50042000,
 	TEGRA_ARM_DISPLAYA =            0x54200000,
 	TEGRA_ARM_DISPLAYB =            0x54240000,
+	TEGRA_DSIA_BASE =               0x54300000,
+	TEGRA_DSIB_BASE =               0x54400000,
 	TEGRA_ARM_SOR =                 0x54540000,
 	TEGRA_ARM_DPAUX =               0x545c0000,
 	TEGRA_PG_UP_BASE =		0x60000000,
@@ -85,6 +87,7 @@ enum {
 	TEGRA_SDMMC2_BASE =		TEGRA_SDMMC_BASE + 0x0200,
 	TEGRA_SDMMC3_BASE =		TEGRA_SDMMC_BASE + 0x0400,
 	TEGRA_SDMMC4_BASE =		TEGRA_SDMMC_BASE + 0x0600,
+	TEGRA_MIPI_CAL_BASE =		0x700E3000,
 	TEGRA_SYSCTR0_BASE =		0x700F0000,
 	TEGRA_USBD_BASE =		0x7D000000,
 	TEGRA_USB2_BASE =		0x7D004000,
diff --git a/src/soc/nvidia/tegra132/include/soc/display.h b/src/soc/nvidia/tegra132/include/soc/display.h
index a6cd1a4..3378a4f 100644
--- a/src/soc/nvidia/tegra132/include/soc/display.h
+++ b/src/soc/nvidia/tegra132/include/soc/display.h
@@ -17,184 +17,25 @@
 #ifndef __SOC_NVIDIA_TEGRA132_INCLUDE_SOC_DISPLAY_H__
 #define __SOC_NVIDIA_TEGRA132_INCLUDE_SOC_DISPLAY_H__
 
-/* ardisplay.h */
-#define DC_CMD_DISPLAY_WINDOW_HEADER_0		0x42
-#define DC_COM_CRC_CONTROL_0			0x300
-#define DC_COM_CRC_CHECKSUM_0			0x301
-#define DC_COM_PIN_OUTPUT_ENABLE0_0		0x302
-#define DC_COM_PIN_OUTPUT_ENABLE1_0		0x303
-#define DC_COM_PIN_OUTPUT_ENABLE2_0		0x304
-#define DC_COM_PIN_OUTPUT_ENABLE3_0		0x305
-#define DC_CMD_STATE_ACCESS_0			0x40
-#define DC_DISP_DISP_CLOCK_CONTROL_0		0x42e
-#define DC_DISP_DISP_TIMING_OPTIONS_0		0x405
-#define DC_DISP_REF_TO_SYNC_0			0x406
-#define DC_DISP_SYNC_WIDTH_0			0x407
-#define DC_DISP_BACK_PORCH_0			0x408
-#define DC_DISP_DISP_ACTIVE_0			0x409
-#define DC_DISP_FRONT_PORCH_0			0x40a
-#define DC_DISP_DISP_WIN_OPTIONS_0		0x402
-#define DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT	25
-#define DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_FIELD	(0x1 << DC_DISP_DISP_WIN_OPTIONS_0_SOR_ENABLE_SHIFT)
-#define DC_DISP_DISP_SIGNAL_OPTIONS0_0		0x400
-#define DC_DISP_BLEND_BACKGROUND_COLOR_0	0x4e4
-#define DC_CMD_DISPLAY_COMMAND_0		0x32
-#define DC_CMD_STATE_CONTROL_0			0x41
-#define DC_CMD_DISPLAY_POWER_CONTROL_0		0x36
-
-/* ardisplay_a.h */
-#define DC_WIN_A_WIN_OPTIONS_0			0x700
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_SHIFT	30
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_FIELD	(0x1 << DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_SHIFT)
-#define DC_WIN_A_WIN_OPTIONS_0_A_WIN_ENABLE_ENABLE	(1)
-#define DC_WIN_A_BYTE_SWAP_0			0x701
-#define DC_WIN_A_BUFFER_CONTROL_0		0x702
-#define DC_WIN_A_COLOR_DEPTH_0			0x703
-#define DC_WIN_A_POSITION_0			0x704
-#define DC_WIN_A_SIZE_0				0x705
-#define DC_WIN_A_PRESCALED_SIZE_0		0x706
-#define DC_WIN_A_H_INITIAL_DDA_0		0x707
-#define DC_WIN_A_V_INITIAL_DDA_0		0x708
-#define DC_WIN_A_DDA_INCREMENT_0		0x709
-#define DC_WIN_A_LINE_STRIDE_0			0x70a
-#define DC_WIN_A_DV_CONTROL_0			0x70e
-#define DC_WIN_A_BLEND_LAYER_CONTROL_0		0x716
-#define DC_WIN_A_BLEND_MATCH_SELECT_0		0x717
-#define DC_WIN_A_BLEND_NOMATCH_SELECT_0		0x718
-#define DC_WIN_A_BLEND_ALPHA_1BIT_0		0x719
-#define DC_WINBUF_A_START_ADDR_LO_0		0x800
-#define DC_WINBUF_A_START_ADDR_HI_0		0x80d
-#define DC_WINBUF_A_ADDR_H_OFFSET_0		0x806
-#define DC_WINBUF_A_ADDR_V_OFFSET_0		0x808
-
-/* ardisplay_bd.h */
-#define DC_B_WIN_BD_SIZE_0			0xd85
-#define DC_B_WIN_BD_PRESCALED_SIZE_0		0xd86
-#define DC_B_WIN_BD_LINE_STRIDE_0		0xd8a
-#define DC_B_WIN_BD_COLOR_DEPTH_0		0xd83
-#define DC_B_WINBUF_BD_START_ADDR_0		0xdc0
-#define DC_B_WIN_BD_DDA_INCREMENT_0		0xd89
-#define DC_B_WIN_BD_WIN_OPTIONS_0		0xd80
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_SHIFT	30
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_FIELD	(0x1 << DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_SHIFT)
-#define DC_B_WIN_BD_WIN_OPTIONS_0_BD_WIN_ENABLE_ENABLE	(1)
-
-/* arsor.h */
-#define SOR_NV_PDISP_SOR_CLK_CNTRL_0		0x13
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0		0x5c
-#define SOR_NV_PDISP_SOR_PLL0_0			0x17
-#define SOR_NV_PDISP_SOR_PLL1_0			0x18
-#define SOR_NV_PDISP_SOR_PLL2_0			0x19
-#define SOR_NV_PDISP_SOR_PLL3_0			0x1a
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT	22
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX6_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX6_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT	0
-#define SOR_NV_PDISP_SOR_PLL0_0_PWR_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL0_0_PWR_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT	2
-#define SOR_NV_PDISP_SOR_PLL0_0_VCOPD_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL0_0_VCOPD_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT	24
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX8_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX8_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT	23
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX7_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX7_SHIFT)
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT	25
-#define SOR_NV_PDISP_SOR_PLL2_0_AUX9_FIELD	(0x1 << SOR_NV_PDISP_SOR_PLL2_0_AUX9_SHIFT)
-#define SOR_NV_PDISP_SOR_LANE_DRIVE_CURRENT0_0	0x4e
-#define SOR_NV_PDISP_SOR_LANE_PREEMPHASIS0_0	0x52
-#define SOR_NV_PDISP_SOR_POSTCURSOR0_0		0x56
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0		0x5c
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT	8
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_FIELD	(0xff << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_VALUE_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT	22
-#define SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_FIELD	(0x1 << SOR_NV_PDISP_SOR_DP_PADCTL0_0_TX_PU_SHIFT)
-#define SOR_NV_PDISP_SOR_LVDS_0			0x1c
-#define SOR_NV_PDISP_SOR_CLK_CNTRL_0		0x13
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0		0x4c
-#define SOR_NV_PDISP_SOR_LANE_SEQ_CTL_0		0x21
-#define SOR_NV_PDISP_SOR_DP_TPG_0		0x6d
-#define SOR_NV_PDISP_HEAD_STATE1_0		0x7
-#define SOR_NV_PDISP_HEAD_STATE2_0		0x9
-#define SOR_NV_PDISP_HEAD_STATE3_0		0xb
-#define SOR_NV_PDISP_HEAD_STATE4_0		0xd
-#define SOR_NV_PDISP_SOR_STATE1_0		0x4
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT	12
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_FIELD	(0x1 << SOR_NV_PDISP_SOR_STATE1_0_ASY_HSYNCPOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT	13
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_FIELD	(0x1 << SOR_NV_PDISP_SOR_STATE1_0_ASY_VSYNCPOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT	8
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_FIELD	(0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_LVDS_CUSTOM	(0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_A		(8)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_DP_B		(9)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PROTOCOL_CUSTOM		(15)
-
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_ACTIVE_RASTER	(0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_COMPLETE_RASTER	(1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_NON_ACTIVE_RASTER	(2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT		6
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_FIELD		(0x3 << SOR_NV_PDISP_SOR_STATE1_0_ASY_CRCMODE_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT		4
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_FIELD		(0x3 << SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_NONE		(0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SUBHEAD0		(1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_SUBHEAD1		(2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_SUBOWNER_BOTH		(3)
-
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT		0
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_FIELD		(0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_NONE		(0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD0		(1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_OWNER_HEAD1		(2)
-
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0				0x58
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT	24
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_FIELD	(0x1 << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_POLARITY_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT	16
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_FIELD	(0xf << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_FRAC_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT	8
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_FIELD	(0x7f << SOR_NV_PDISP_SOR_DP_CONFIG0_0_ACTIVESYM_COUNT_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT		0
-#define SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_FIELD		(0x3f << SOR_NV_PDISP_SOR_DP_CONFIG0_0_WATERMARK_SHIFT)
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT		2
-#define SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_FIELD		(0x7f << SOR_NV_PDISP_SOR_DP_LINKCTL0_0_TUSIZE_SHIFT)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT		17
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_FIELD		(0xf << SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_SHIFT)
+#define COLOR_WHITE	0xFFFFFF
+#define COLOR_BLACK	0x000000
 
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_DEFAULTVAL	(0)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_16_422	(1)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_18_444	(2)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_20_422	(3)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_422	(4)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_24_444	(5)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_30_444	(6)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_32_422	(7)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_36_444	(8)
-#define SOR_NV_PDISP_SOR_STATE1_0_ASY_PIXELDEPTH_BPP_48_444	(9)
+#define hsync_start(mode)	\
+	(mode->xres + mode->hfront_porch)
 
-#define SOR_NV_PDISP_SOR_CRC_CNTRL_0				0x11
-#define SOR_NV_PDISP_SOR_DP_AUDIO_VBLANK_SYMBOLS_0		0x64
-#define SOR_NV_PDISP_SOR_DP_SPARE0_0				0x60
-#define SOR_NV_PDISP_SOR_PWR_0					0x15
-#define SOR_NV_PDISP_SOR_STATE0_0				0x3
-#define SOR_NV_PDISP_SOR_SUPER_STATE1_0				0x2
-#define SOR_NV_PDISP_SOR_SUPER_STATE0_0				0x1
+#define hsync_end(mode)	\
+	(mode->xres + mode->hfront_porch + mode->hsync_width)
 
-/* ardpaux.h */
-#define DPAUX_DP_AUXDATA_READ_W0				0x19
+#define htotal(mode)	\
+	(mode->xres + mode->hfront_porch + \
+	mode->hsync_width + mode->hback_porch)
 
-#define DP_LVDS_SHIFT	25
-#define DP_LVDS		(1 << DP_LVDS_SHIFT)
-
-#define SRC_BPP		16
-#define COLORDEPTH	0x6
-#define COLOR_WHITE	0xFFFFFF
+#define vtotal(mode)	\
+	(mode->yres + mode->vfront_porch + \
+	mode->vsync_width + mode->vback_porch)
 
 struct soc_nvidia_tegra132_config;	/* forward declaration */
-void setup_display(struct soc_nvidia_tegra132_config *config);
-void init_dca_regs(void);
-void dp_io_powerup(void);
-u32 dp_setup_timing(u32 width, u32 height);
-void dp_misc_setting(u32 panel_bpp, u32 width, u32 height, u32 winb_addr,
-		     u32 lane_count, u32 enhanced_framing, u32 panel_edp,
-		     u32 pclkfreq, u32 linkfreq);
+
+int dsi_enable(struct soc_nvidia_tegra132_config *config);
 
 #endif /* __SOC_NVIDIA_TEGRA132_INCLUDE_SOC_DISPLAY_H__ */
diff --git a/src/soc/nvidia/tegra132/include/soc/mipi-phy.h b/src/soc/nvidia/tegra132/include/soc/mipi-phy.h
new file mode 100644
index 0000000..2ec3fce
--- /dev/null
+++ b/src/soc/nvidia/tegra132/include/soc/mipi-phy.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _TEGRA_MIPI_PHY_H
+#define _TEGRA_MIPI_PHY_H
+
+#include <stdlib.h>
+
+/*
+ * Macros for calculating the phy timings
+ */
+/* Period of one bit time in nano seconds */
+#define DSI_TBIT_Factorized(Freq)    (((1000) * (1000))/(Freq))
+#define DSI_TBIT(Freq)       (DSI_TBIT_Factorized(Freq)/(1000))
+
+//#define NV_MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Period of one byte time in nano seconds */
+#define DSI_TBYTE(Freq)    ((DSI_TBIT_Factorized(Freq)) * (8))
+#define DSI_PHY_TIMING_DIV(X, Freq) ((X*1000) / (DSI_TBYTE(Freq)))
+
+/*
+ * As per Mipi spec (minimum):
+ * (3 + MAX(8 * DSI_TBIT, 60 + 4 * DSI_TBIT) / DSI_TBYTE)
+ */
+#define DSI_THSTRAIL_VAL(Freq) \
+     (MAX(((8) * (DSI_TBIT(Freq))), ((60) + ((4) * (DSI_TBIT(Freq))))))
+
+int mipi_dphy_set_timing(struct tegra_dsi *dsi);
+
+#endif
diff --git a/src/soc/nvidia/tegra132/include/soc/mipi_display.h b/src/soc/nvidia/tegra132/include/soc/mipi_display.h
new file mode 100644
index 0000000..99bfa93
--- /dev/null
+++ b/src/soc/nvidia/tegra132/include/soc/mipi_display.h
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * Defines for Mobile Industry Processor Interface (MIPI(R))
+ * Display Working Group standards: DSI, DCS, DBI, DPI
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski at gmx.de>
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak at nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef MIPI_DISPLAY_H
+#define MIPI_DISPLAY_H
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+	MIPI_DSI_V_SYNC_START				= 0x01,
+	MIPI_DSI_V_SYNC_END				= 0x11,
+	MIPI_DSI_H_SYNC_START				= 0x21,
+	MIPI_DSI_H_SYNC_END				= 0x31,
+
+	MIPI_DSI_COLOR_MODE_OFF				= 0x02,
+	MIPI_DSI_COLOR_MODE_ON				= 0x12,
+	MIPI_DSI_SHUTDOWN_PERIPHERAL			= 0x22,
+	MIPI_DSI_TURN_ON_PERIPHERAL			= 0x32,
+
+	MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM		= 0x03,
+	MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM		= 0x13,
+	MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM		= 0x23,
+
+	MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM		= 0x04,
+	MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM		= 0x14,
+	MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM		= 0x24,
+
+	MIPI_DSI_DCS_SHORT_WRITE			= 0x05,
+	MIPI_DSI_DCS_SHORT_WRITE_PARAM			= 0x15,
+
+	MIPI_DSI_DCS_READ				= 0x06,
+
+	MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE		= 0x37,
+
+	MIPI_DSI_END_OF_TRANSMISSION			= 0x08,
+
+	MIPI_DSI_NULL_PACKET				= 0x09,
+	MIPI_DSI_BLANKING_PACKET			= 0x19,
+	MIPI_DSI_GENERIC_LONG_WRITE			= 0x29,
+	MIPI_DSI_DCS_LONG_WRITE				= 0x39,
+
+	MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20	= 0x0c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24		= 0x1c,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16		= 0x2c,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_30			= 0x0d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_36			= 0x1d,
+	MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12		= 0x3d,
+
+	MIPI_DSI_PACKED_PIXEL_STREAM_16			= 0x0e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_18			= 0x1e,
+	MIPI_DSI_PIXEL_STREAM_3BYTE_18			= 0x2e,
+	MIPI_DSI_PACKED_PIXEL_STREAM_24			= 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+	MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT	= 0x02,
+	MIPI_DSI_RX_END_OF_TRANSMISSION			= 0x08,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE	= 0x11,
+	MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE	= 0x12,
+	MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE		= 0x1a,
+	MIPI_DSI_RX_DCS_LONG_READ_RESPONSE		= 0x1c,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE	= 0x21,
+	MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE	= 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+	MIPI_DCS_NOP			= 0x00,
+	MIPI_DCS_SOFT_RESET		= 0x01,
+	MIPI_DCS_GET_DISPLAY_ID		= 0x04,
+	MIPI_DCS_GET_RED_CHANNEL	= 0x06,
+	MIPI_DCS_GET_GREEN_CHANNEL	= 0x07,
+	MIPI_DCS_GET_BLUE_CHANNEL	= 0x08,
+	MIPI_DCS_GET_DISPLAY_STATUS	= 0x09,
+	MIPI_DCS_GET_POWER_MODE		= 0x0A,
+	MIPI_DCS_GET_ADDRESS_MODE	= 0x0B,
+	MIPI_DCS_GET_PIXEL_FORMAT	= 0x0C,
+	MIPI_DCS_GET_DISPLAY_MODE	= 0x0D,
+	MIPI_DCS_GET_SIGNAL_MODE	= 0x0E,
+	MIPI_DCS_GET_DIAGNOSTIC_RESULT	= 0x0F,
+	MIPI_DCS_ENTER_SLEEP_MODE	= 0x10,
+	MIPI_DCS_EXIT_SLEEP_MODE	= 0x11,
+	MIPI_DCS_ENTER_PARTIAL_MODE	= 0x12,
+	MIPI_DCS_ENTER_NORMAL_MODE	= 0x13,
+	MIPI_DCS_EXIT_INVERT_MODE	= 0x20,
+	MIPI_DCS_ENTER_INVERT_MODE	= 0x21,
+	MIPI_DCS_SET_GAMMA_CURVE	= 0x26,
+	MIPI_DCS_SET_DISPLAY_OFF	= 0x28,
+	MIPI_DCS_SET_DISPLAY_ON		= 0x29,
+	MIPI_DCS_SET_COLUMN_ADDRESS	= 0x2A,
+	MIPI_DCS_SET_PAGE_ADDRESS	= 0x2B,
+	MIPI_DCS_WRITE_MEMORY_START	= 0x2C,
+	MIPI_DCS_WRITE_LUT		= 0x2D,
+	MIPI_DCS_READ_MEMORY_START	= 0x2E,
+	MIPI_DCS_SET_PARTIAL_AREA	= 0x30,
+	MIPI_DCS_SET_SCROLL_AREA	= 0x33,
+	MIPI_DCS_SET_TEAR_OFF		= 0x34,
+	MIPI_DCS_SET_TEAR_ON		= 0x35,
+	MIPI_DCS_SET_ADDRESS_MODE	= 0x36,
+	MIPI_DCS_SET_SCROLL_START	= 0x37,
+	MIPI_DCS_EXIT_IDLE_MODE		= 0x38,
+	MIPI_DCS_ENTER_IDLE_MODE	= 0x39,
+	MIPI_DCS_SET_PIXEL_FORMAT	= 0x3A,
+	MIPI_DCS_WRITE_MEMORY_CONTINUE	= 0x3C,
+	MIPI_DCS_READ_MEMORY_CONTINUE	= 0x3E,
+	MIPI_DCS_SET_TEAR_SCANLINE	= 0x44,
+	MIPI_DCS_GET_SCANLINE		= 0x45,
+	MIPI_DCS_READ_DDB_START		= 0xA1,
+	MIPI_DCS_READ_DDB_CONTINUE	= 0xA8,
+};
+
+/* MIPI DCS pixel formats */
+#define MIPI_DCS_PIXEL_FMT_24BIT	7
+#define MIPI_DCS_PIXEL_FMT_18BIT	6
+#define MIPI_DCS_PIXEL_FMT_16BIT	5
+#define MIPI_DCS_PIXEL_FMT_12BIT	3
+#define MIPI_DCS_PIXEL_FMT_8BIT		2
+#define MIPI_DCS_PIXEL_FMT_3BIT		1
+
+#endif
diff --git a/src/soc/nvidia/tegra132/include/soc/mipi_dsi.h b/src/soc/nvidia/tegra132/include/soc/mipi_dsi.h
new file mode 100644
index 0000000..1bca657
--- /dev/null
+++ b/src/soc/nvidia/tegra132/include/soc/mipi_dsi.h
@@ -0,0 +1,283 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda at samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MIPI_DSI_H__
+#define __MIPI_DSI_H__
+
+struct mipi_dsi_host;
+struct mipi_dsi_device;
+
+/* request ACK from peripheral */
+#define MIPI_DSI_MSG_REQ_ACK	BIT(0)
+/* use Low Power Mode to transmit message */
+#define MIPI_DSI_MSG_USE_LPM	BIT(1)
+
+/**
+ * struct mipi_dsi_msg - read/write DSI buffer
+ * @channel: virtual channel id
+ * @type: payload data type
+ * @flags: flags controlling this message transmission
+ * @tx_len: length of @tx_buf
+ * @tx_buf: data to be written
+ * @rx_len: length of @rx_buf
+ * @rx_buf: data to be read, or NULL
+ */
+struct mipi_dsi_msg {
+	u8 channel;
+	u8 type;
+	u16 flags;
+
+	size_t tx_len;
+	const void *tx_buf;
+
+	size_t rx_len;
+	void *rx_buf;
+};
+
+/**
+ * struct mipi_dsi_host_ops - DSI bus operations
+ * @attach: attach DSI device to DSI host
+ * @detach: detach DSI device from DSI host
+ * @transfer: transmit a DSI packet
+ *
+ * DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
+ * structures. This structure contains information about the type of packet
+ * being transmitted as well as the transmit and receive buffers. When an
+ * error is encountered during transmission, this function will return a
+ * negative error code. On success it shall return the number of bytes
+ * transmitted for write packets or the number of bytes received for read
+ * packets.
+ *
+ * Note that typically DSI packet transmission is atomic, so the .transfer()
+ * function will seldomly return anything other than the number of bytes
+ * contained in the transmit buffer on success.
+ */
+struct mipi_dsi_host_ops {
+	int (*attach)(struct mipi_dsi_host *host,
+		      struct mipi_dsi_device *dsi);
+	int (*detach)(struct mipi_dsi_host *host,
+		      struct mipi_dsi_device *dsi);
+	ssize_t (*transfer)(struct mipi_dsi_host *host,
+			    const struct mipi_dsi_msg *msg);
+};
+
+/**
+ * struct mipi_dsi_host - DSI host device
+ * @dev: driver model device node for this DSI host
+ * @ops: DSI host operations
+ */
+struct mipi_dsi_host {
+	//struct device *dev;
+	void *dev;
+	const struct mipi_dsi_host_ops *ops;
+};
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host);
+
+/* DSI mode flags */
+
+/* video mode */
+#define MIPI_DSI_MODE_VIDEO		BIT(0)
+/* video burst mode */
+#define MIPI_DSI_MODE_VIDEO_BURST	BIT(1)
+/* video pulse mode */
+#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE	BIT(2)
+/* enable auto vertical count mode */
+#define MIPI_DSI_MODE_VIDEO_AUTO_VERT	BIT(3)
+/* enable hsync-end packets in vsync-pulse and v-porch area */
+#define MIPI_DSI_MODE_VIDEO_HSE		BIT(4)
+/* disable hfront-porch area */
+#define MIPI_DSI_MODE_VIDEO_HFP		BIT(5)
+/* disable hback-porch area */
+#define MIPI_DSI_MODE_VIDEO_HBP		BIT(6)
+/* disable hsync-active area */
+#define MIPI_DSI_MODE_VIDEO_HSA		BIT(7)
+/* flush display FIFO on vsync pulse */
+#define MIPI_DSI_MODE_VSYNC_FLUSH	BIT(8)
+/* disable EoT packets in HS mode */
+#define MIPI_DSI_MODE_EOT_PACKET	BIT(9)
+/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
+#define MIPI_DSI_CLOCK_NON_CONTINUOUS	BIT(10)
+
+enum mipi_dsi_pixel_format {
+	MIPI_DSI_FMT_RGB888,
+	MIPI_DSI_FMT_RGB666,
+	MIPI_DSI_FMT_RGB666_PACKED,
+	MIPI_DSI_FMT_RGB565,
+};
+
+struct mipi_dsi_master_ops {
+	int (*enslave)(struct mipi_dsi_device *master,
+		       struct mipi_dsi_device *slave);
+	int (*liberate)(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave);
+};
+
+/**
+ * struct mipi_dsi_device - DSI peripheral device
+ * @host: DSI host for this peripheral
+ * @dev: driver model device node for this peripheral
+ * @channel: virtual channel assigned to the peripheral
+ * @format: pixel format for video mode
+ * @lanes: number of active data lanes
+ * @mode_flags: DSI operation mode related flags
+ * @ops: callbacks for master/slave setup
+ * @master: master interface for dual-channel peripherals
+ * @slave: slave interface for dual-channel peripherals
+ *
+ * For dual-channel interfaces, the master interface can be identified by the
+ * fact that it's .slave field is set to non-NULL. The slave interface will
+ * have the .master field set to non-NULL.
+ */
+struct mipi_dsi_device {
+	struct mipi_dsi_host *host;
+
+	unsigned int channel;
+	unsigned int lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+
+	const struct mipi_dsi_master_ops *ops;
+	struct mipi_dsi_device *master;
+	struct mipi_dsi_device *slave;
+};
+
+int mipi_dsi_attach(struct mipi_dsi_device *dsi);
+int mipi_dsi_detach(struct mipi_dsi_device *dsi);
+int mipi_dsi_enslave(struct mipi_dsi_device *master,
+		     struct mipi_dsi_device *slave);
+int mipi_dsi_liberate(struct mipi_dsi_device *master,
+		      struct mipi_dsi_device *slave);
+
+/**
+ * enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
+ * @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
+ *    information only
+ * @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
+ *    V-Blanking and H-Blanking information
+ */
+enum mipi_dsi_dcs_tear_mode {
+	MIPI_DSI_DCS_TEAR_MODE_VBLANK,
+	MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
+};
+
+#define MIPI_DSI_DCS_POWER_MODE_DISPLAY (1 << 2)
+#define MIPI_DSI_DCS_POWER_MODE_NORMAL  (1 << 3)
+#define MIPI_DSI_DCS_POWER_MODE_SLEEP   (1 << 4)
+#define MIPI_DSI_DCS_POWER_MODE_PARTIAL (1 << 5)
+#define MIPI_DSI_DCS_POWER_MODE_IDLE    (1 << 6)
+
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+			   const void *data, size_t len);
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+				    u16 end);
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+				  u16 end);
+int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device *dsi,
+				  bool reverse_page_address,
+				  bool reverse_col_address,
+				  bool reverse_page_col_address,
+				  bool refresh_from_bottom,
+				  bool reverse_rgb,
+				  bool latch_right_to_left,
+				  bool flip_horizontal,
+				  bool flip_vertical);
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+			     enum mipi_dsi_dcs_tear_mode mode);
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
+
+#define MIPI_CAL_CTRL			0x00
+#define MIPI_CAL_CTRL_START		(1 << 0)
+
+#define MIPI_CAL_AUTOCAL_CTRL		0x01
+
+#define MIPI_CAL_STATUS			0x02
+#define MIPI_CAL_STATUS_DONE		(1 << 16)
+#define MIPI_CAL_STATUS_ACTIVE		(1 <<  0)
+
+#define MIPI_CAL_CONFIG_CSIA		0x05
+#define MIPI_CAL_CONFIG_CSIB		0x06
+#define MIPI_CAL_CONFIG_CSIC		0x07
+#define MIPI_CAL_CONFIG_CSID		0x08
+#define MIPI_CAL_CONFIG_CSIE		0x09
+#define MIPI_CAL_CONFIG_DSIA		0x0e
+#define MIPI_CAL_CONFIG_DSIB		0x0f
+#define MIPI_CAL_CONFIG_DSIC		0x10
+#define MIPI_CAL_CONFIG_DSID		0x11
+
+#define MIPI_CAL_CONFIG_DSIAB_CLK	0x19
+#define MIPI_CAL_CONFIG_DSICD_CLK	0x1a
+#define MIPI_CAL_CONFIG_CSIAB_CLK	0x1b
+#define MIPI_CAL_CONFIG_CSICD_CLK	0x1c
+#define MIPI_CAL_CONFIG_CSIE_CLK	0x1d
+
+#define MIPI_CAL_CONFIG_SELECT		(1 << 21)
+#define MIPI_CAL_CONFIG_HSPDOS(x)	(((x) & 0x1f) << 16)
+#define MIPI_CAL_CONFIG_HSPUOS(x)	(((x) & 0x1f) <<  8)
+#define MIPI_CAL_CONFIG_TERMOS(x)	(((x) & 0x1f) <<  0)
+#define MIPI_CAL_CONFIG_HSCLKPDOSD(x)	(((x) & 0x1f) << 8)
+#define MIPI_CAL_CONFIG_HSCLKPUOSD(x)	(((x) & 0x1f) <<  0)
+
+#define MIPI_CAL_BIAS_PAD_CFG0		0x16
+#define MIPI_CAL_BIAS_PAD_PDVCLAMP	(1 << 1)
+#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF	(1 << 0)
+
+#define MIPI_CAL_BIAS_PAD_CFG1		0x17
+#define MIPI_CAL_BIAS_PAD_CFG1_DEFAULT	(0x20000)
+
+#define MIPI_CAL_BIAS_PAD_CFG2		0x18
+#define MIPI_CAL_BIAS_PAD_PDVREG	(1 << 1)
+
+struct calibration_regs {
+	unsigned long data;
+	unsigned long clk;
+};
+
+struct tegra_mipi_config {
+	int calibrate_clk_lane;
+	int num_pads;
+	const struct calibration_regs *regs;
+};
+
+struct tegra_mipi {
+	void *regs;
+};
+
+struct tegra_mipi_device {
+	struct tegra_mipi *mipi;
+	const struct tegra_mipi_config *config;
+	unsigned long pads;
+};
+
+struct tegra_mipi_device *tegra_mipi_request(struct tegra_mipi_device *device,
+						int device_index);
+int tegra_mipi_calibrate(struct tegra_mipi_device *device);
+#endif /* __MIPI_DSI_H__ */
diff --git a/src/soc/nvidia/tegra132/include/soc/tegra_dsi.h b/src/soc/nvidia/tegra132/include/soc/tegra_dsi.h
new file mode 100644
index 0000000..830257d
--- /dev/null
+++ b/src/soc/nvidia/tegra132/include/soc/tegra_dsi.h
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __TEGRA_DSI_H__
+#define __TEGRA_DSI_H__
+
+#define DSI_INCR_SYNCPT			0x00
+#define DSI_INCR_SYNCPT_CONTROL		0x01
+#define DSI_INCR_SYNCPT_ERROR		0x02
+#define DSI_CTXSW			0x08
+#define DSI_RD_DATA			0x09
+#define DSI_WR_DATA			0x0a
+#define DSI_POWER_CONTROL		0x0b
+#define DSI_POWER_CONTROL_ENABLE	(1 << 0)
+#define DSI_INT_ENABLE			0x0c
+#define DSI_INT_STATUS			0x0d
+#define DSI_INT_MASK			0x0e
+#define DSI_HOST_CONTROL		0x0f
+#define DSI_HOST_CONTROL_FIFO_RESET	(1 << 21)
+#define DSI_HOST_CONTROL_CRC_RESET	(1 << 20)
+#define DSI_HOST_CONTROL_TX_TRIG_SOL	(0 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_FIFO	(1 << 12)
+#define DSI_HOST_CONTROL_TX_TRIG_HOST	(2 << 12)
+#define DSI_HOST_CONTROL_RAW		(1 << 6)
+#define DSI_HOST_CONTROL_HS		(1 << 5)
+#define DSI_HOST_CONTROL_FIFO_SEL	(1 << 4)
+#define DSI_HOST_CONTROL_IMM_BTA	(1 << 3)
+#define DSI_HOST_CONTROL_PKT_BTA	(1 << 2)
+#define DSI_HOST_CONTROL_CS		(1 << 1)
+#define DSI_HOST_CONTROL_ECC		(1 << 0)
+#define DSI_CONTROL			0x10
+#define DSI_CONTROL_HS_CLK_CTRL		(1 << 20)
+#define DSI_CONTROL_CHANNEL(c)		(((c) & 0x3) << 16)
+#define DSI_CONTROL_FORMAT(f)		(((f) & 0x3) << 12)
+#define DSI_CONTROL_TX_TRIG(x)		(((x) & 0x3) <<  8)
+#define DSI_CONTROL_LANES(n)		(((n) & 0x3) <<  4)
+#define DSI_CONTROL_DCS_ENABLE		(1 << 3)
+#define DSI_CONTROL_SOURCE(s)		(((s) & 0x1) <<  2)
+#define DSI_CONTROL_VIDEO_ENABLE	(1 << 1)
+#define DSI_CONTROL_HOST_ENABLE		(1 << 0)
+#define DSI_SOL_DELAY			0x11
+#define DSI_MAX_THRESHOLD		0x12
+#define DSI_TRIGGER			0x13
+#define DSI_TRIGGER_HOST		(1 << 1)
+#define DSI_TRIGGER_VIDEO		(1 << 0)
+#define DSI_TX_CRC			0x14
+#define DSI_STATUS			0x15
+#define DSI_STATUS_IDLE			(1 << 10)
+#define DSI_STATUS_UNDERFLOW		(1 <<  9)
+#define DSI_STATUS_OVERFLOW		(1 <<  8)
+#define DSI_INIT_SEQ_CONTROL		0x1a
+#define DSI_INIT_SEQ_DATA_0		0x1b
+#define DSI_INIT_SEQ_DATA_1		0x1c
+#define DSI_INIT_SEQ_DATA_2		0x1d
+#define DSI_INIT_SEQ_DATA_3		0x1e
+#define DSI_INIT_SEQ_DATA_4		0x1f
+#define DSI_INIT_SEQ_DATA_5		0x20
+#define DSI_INIT_SEQ_DATA_6		0x21
+#define DSI_INIT_SEQ_DATA_7		0x22
+#define DSI_PKT_SEQ_0_LO		0x23
+#define DSI_PKT_SEQ_0_HI		0x24
+#define DSI_PKT_SEQ_1_LO		0x25
+#define DSI_PKT_SEQ_1_HI		0x26
+#define DSI_PKT_SEQ_2_LO		0x27
+#define DSI_PKT_SEQ_2_HI		0x28
+#define DSI_PKT_SEQ_3_LO		0x29
+#define DSI_PKT_SEQ_3_HI		0x2a
+#define DSI_PKT_SEQ_4_LO		0x2b
+#define DSI_PKT_SEQ_4_HI		0x2c
+#define DSI_PKT_SEQ_5_LO		0x2d
+#define DSI_PKT_SEQ_5_HI		0x2e
+#define DSI_DCS_CMDS			0x33
+#define DSI_PKT_LEN_0_1			0x34
+#define DSI_PKT_LEN_2_3			0x35
+#define DSI_PKT_LEN_4_5			0x36
+#define DSI_PKT_LEN_6_7			0x37
+#define DSI_PHY_TIMING_0		0x3c
+#define DSI_PHY_TIMING_1		0x3d
+#define DSI_PHY_TIMING_2		0x3e
+#define DSI_BTA_TIMING			0x3f
+
+#define DSI_TIMING_FIELD(value, period, hwinc) \
+	((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff)
+
+#define DSI_TIMEOUT_0			0x44
+#define DSI_TIMEOUT_LRX(x)		(((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_HTX(x)		(((x) & 0xffff) <<  0)
+#define DSI_TIMEOUT_1			0x45
+#define DSI_TIMEOUT_PR(x)		(((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_TA(x)		(((x) & 0xffff) <<  0)
+#define DSI_TO_TALLY			0x46
+#define DSI_TALLY_TA(x)			(((x) & 0xff) << 16)
+#define DSI_TALLY_LRX(x)		(((x) & 0xff) <<  8)
+#define DSI_TALLY_HTX(x)		(((x) & 0xff) <<  0)
+#define DSI_PAD_CONTROL_0		0x4b
+#define DSI_PAD_CONTROL_VS1_PDIO(x)	(((x) & 0xf) <<  0)
+#define DSI_PAD_CONTROL_VS1_PDIO_CLK	(1 <<  8)
+#define DSI_PAD_CONTROL_VS1_PULLDN(x)	(((x) & 0xf) << 16)
+#define DSI_PAD_CONTROL_VS1_PULLDN_CLK	(1 << 24)
+#define DSI_PAD_CONTROL_CD		0x4c
+#define DSI_PAD_CD_STATUS		0x4d
+#define DSI_VIDEO_MODE_CONTROL		0x4e
+#define DSI_PAD_CONTROL_1		0x4f
+#define DSI_PAD_CONTROL_2		0x50
+#define DSI_PAD_OUT_CLK(x)		(((x) & 0x7) <<  0)
+#define DSI_PAD_LP_DN(x)		(((x) & 0x7) <<  4)
+#define DSI_PAD_LP_UP(x)		(((x) & 0x7) <<  8)
+#define DSI_PAD_SLEW_DN(x)		(((x) & 0x7) << 12)
+#define DSI_PAD_SLEW_UP(x)		(((x) & 0x7) << 16)
+#define DSI_PAD_CONTROL_3		0x51
+#define DSI_PAD_CONTROL_4		0x52
+#define DSI_GANGED_MODE_CONTROL		0x53
+#define DSI_GANGED_MODE_CONTROL_ENABLE	(1 << 0)
+#define DSI_GANGED_MODE_START		0x54
+#define DSI_GANGED_MODE_SIZE		0x55
+#define DSI_RAW_DATA_BYTE_COUNT		0x56
+#define DSI_ULTRA_LOW_POWER_CONTROL	0x57
+#define DSI_INIT_SEQ_DATA_8		0x58
+#define DSI_INIT_SEQ_DATA_9		0x59
+#define DSI_INIT_SEQ_DATA_10		0x5a
+#define DSI_INIT_SEQ_DATA_11		0x5b
+#define DSI_INIT_SEQ_DATA_12		0x5c
+#define DSI_INIT_SEQ_DATA_13		0x5d
+#define DSI_INIT_SEQ_DATA_14		0x5e
+#define DSI_INIT_SEQ_DATA_15		0x5f
+
+#define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
+#define PKT_LEN0(len)	(((len) & 0x07) <<  0)
+#define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
+#define PKT_LEN1(len)	(((len) & 0x07) << 10)
+#define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
+#define PKT_LEN2(len)	(((len) & 0x07) << 20)
+
+#define PKT_LP		(1 << 30)
+#define NUM_PKT_SEQ	12
+
+#define APB_MISC_GP_MIPI_PAD_CTRL_0 	(TEGRA_APB_MISC_GP_BASE + 0x20)
+#define DSIB_MODE_SHIFT			1
+#define DSIB_MODE_CSI			(0 << DSIB_MODE_SHIFT)
+#define DSIB_MODE_DSI			(1 << DSIB_MODE_SHIFT)
+
+/*
+ * pixel format as used in the DSI_CONTROL_FORMAT field
+ */
+enum tegra_dsi_format {
+	TEGRA_DSI_FORMAT_16P,
+	TEGRA_DSI_FORMAT_18NP,
+	TEGRA_DSI_FORMAT_18P,
+	TEGRA_DSI_FORMAT_24P,
+};
+
+enum dsi_dev {
+        DSI_A = 0,
+        DSI_B,
+        NUM_DSI,
+};
+
+struct panel_jdi;
+struct tegra_mipi_device;
+struct mipi_dsi_host;
+struct mipi_dsi_msg;
+
+#define MAX_DSI_VIDEO_FIFO_DEPTH	96
+#define MAX_DSI_HOST_FIFO_DEPTH		64
+
+struct tegra_dsi {
+	struct panel_jdi *panel;
+	//struct tegra_output output;
+	void   *regs;
+	u8     channel;
+	unsigned long clk_rate;
+
+	unsigned long flags;
+	enum mipi_dsi_pixel_format format;
+	unsigned int lanes;
+
+	struct tegra_mipi_device *mipi;
+	struct mipi_dsi_host host;
+	bool enabled;
+
+	unsigned int video_fifo_depth;
+	unsigned int host_fifo_depth;
+
+	/* for ganged-mode support */
+	unsigned int ganged_lanes;
+	struct tegra_dsi *slave;
+	int ganged_mode;
+
+	struct tegra_dsi *master;
+};
+
+static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
+			unsigned long reg)
+{
+	return readl(dsi->regs + (reg << 2));
+}
+
+static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
+			unsigned long reg)
+{
+	writel(value, dsi->regs + (reg << 2));
+}
+
+#endif /* __TEGRA_DSI_H__ */
diff --git a/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.c b/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.c
new file mode 100644
index 0000000..45797b1
--- /dev/null
+++ b/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include "../chip.h"
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/tegra_dsi.h>
+#include "panel-jdi-lpm102a188a.h"
+
+struct panel_jdi jdi_data[NUM_DSI];
+
+int panel_jdi_prepare(struct panel_jdi *jdi)
+{
+	int ret;
+	u8 data;
+
+	if (jdi->enabled)
+		return 0;
+
+	ret = mipi_dsi_dcs_set_column_address(jdi->dsi, 0,
+				jdi->mode->xres / 2 - 1); // 2560/2
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set column address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_column_address(jdi->dsi->slave, 0,
+				jdi->mode->xres / 2 - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set column address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_page_address(jdi->dsi, 0,
+				jdi->mode->yres - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set page address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_page_address(jdi->dsi->slave, 0,
+				jdi->mode->yres - 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set page address: %d\n", ret);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(jdi->dsi);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to exit sleep mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(jdi->dsi->slave);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to exit sleep mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_tear_on(jdi->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set tear on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_tear_on(jdi->dsi->slave,
+			MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set tear on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_address_mode(jdi->dsi, false, false, false,
+			false, false, false, false, false);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set address mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_address_mode(jdi->dsi->slave, false, false,
+			false, false, false, false, false, false);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set address mode: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_pixel_format(jdi->dsi, 0x77);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set pixel format: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_pixel_format(jdi->dsi->slave, 0x77);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set pixel format: %d\n", ret);
+
+	data = 0xFF;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x51, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x51: %d\n", ret);
+
+	data = 0xFF;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x51, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x51: %d\n", ret);
+
+	data = 0x24;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x53, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x53: %d\n", ret);
+
+	data = 0x24;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x53, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x53: %d\n", ret);
+
+	data = 0x00;
+	ret = mipi_dsi_dcs_write(jdi->dsi, 0x55, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x55: %d\n", ret);
+
+	data = 0x00;
+	ret = mipi_dsi_dcs_write(jdi->dsi->slave, 0x55, &data, 1);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set 0x55: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_display_on(jdi->dsi);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set display on: %d\n", ret);
+
+	ret = mipi_dsi_dcs_set_display_on(jdi->dsi->slave);
+	if (ret < 0)
+		printk(BIOS_ERR, "failed to set display on: %d\n", ret);
+
+	jdi->enabled = true;
+
+	return 0;
+}
+
+static int panel_jdi_enslave(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave)
+{
+	int ret;
+
+	ret = mipi_dsi_attach(master);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static int panel_jdi_liberate(struct mipi_dsi_device *master,
+			struct mipi_dsi_device *slave)
+{
+	int ret;
+
+	ret = mipi_dsi_detach(master);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct mipi_dsi_master_ops panel_jdi_master_ops = {
+	.enslave = panel_jdi_enslave,
+	.liberate = panel_jdi_liberate,
+};
+
+struct panel_jdi *panel_jdi_dsi_probe(struct mipi_dsi_device *dsi)
+{
+	static int index = 0;
+	struct panel_jdi *jdi;
+	int ret;
+
+	if (index >= NUM_DSI)
+		return (void *)-EPTR;
+
+	jdi = &jdi_data[index++];
+
+	jdi->dsi = dsi;
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = 0;
+
+	if (dsi->master) {
+		ret = mipi_dsi_attach(dsi);
+		if (ret < 0) {
+			printk(BIOS_ERR, "mipi_dsi_attach() failed: %d\n", ret);
+			return (void *)-EPTR;
+		}
+
+		ret = mipi_dsi_enslave(dsi->master, dsi);
+		if (ret < 0) {
+			printk(BIOS_ERR, "mipi_dsi_enslave() failed: %d\n",
+				ret);
+			return (void *)-EPTR;
+		}
+
+		return jdi;
+	}
+
+	dsi->ops = &panel_jdi_master_ops;
+
+	jdi->enabled = 0;
+	jdi->width_mm = 211;
+	jdi->height_mm = 148;
+
+	return jdi;
+}
diff --git a/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.h b/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.h
new file mode 100644
index 0000000..a44882d
--- /dev/null
+++ b/src/soc/nvidia/tegra132/jdi_25x18_display/panel-jdi-lpm102a188a.h
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _PANEL_JDI_LPM102A188A_H_
+#define _PANEL_JDI_LPM102A188A_H_
+
+#define LP8557_MAX_BRIGHTNESS				0xFFF;
+
+#define LP8557_COMMAND					0x00
+#define LP8557_COMMAND_ON				(1 << 0)
+
+#define LP8557_BRIGHTNESS_LOW				0x03
+#define LP8557_BRIGHTNESS_LOW_MASK(x)			(((x) & 0xF) << 4)
+
+#define LP8557_BRIGHTNESS_HIGH				0x04
+#define LP8557_BRIGHTNESS_HIGH_MASK(x)			(((x) & 0xFF0) >> 4)
+
+enum lp8557_config_brightness_mode {
+	LP8557_CONFIG_BRTMODE_PWM			= 0x0,
+	LP8557_CONFIG_BRTMODE_REG,
+	LP8557_CONFIG_BRTMODE_PWM_REG_SHAPE_PWM,
+	LP8557_CONFIG_BRTMODE_PWM_REG_SHAPE_BRIGHTNESS,
+	LP8557_CONFIG_BRTMODE_MAX,
+};
+#define LP8557_CONFIG					0x10
+#define LP8557_CONFIG_BRTMODE(x)			(((x) & 0x3) << 0)
+#define LP8557_CONFIG_AUTO_DETECT_LED			(1 << 2)
+#define LP8557_CONFIG_PWM_STANDBY			(1 << 7)
+
+enum lp8557_current {
+	LP8557_CURRENT_5_MA				= 0x0,
+	LP8557_CURRENT_10_MA,
+	LP8557_CURRENT_13_MA,
+	LP8557_CURRENT_15_MA,
+	LP8557_CURRENT_18_MA,
+	LP8557_CURRENT_20_MA,
+	LP8557_CURRENT_23_MA,
+	LP8557_CURRENT_25_MA,
+	LP8557_CURRENT_MAX,
+};
+#define LP8557_CURRENT					0x11
+#define LP8557_CURRENT_MAXCURR(x)			(((x) & 0x7) << 0)
+#define LP8557_CURRENT_ISET				(1 << 7)
+
+enum lp8557_pgen_frequency {
+	LP8557_PGEN_FREQ_4_9_KHZ			= 0x0,
+	LP8557_PGEN_FREQ_9_8_KHZ,
+	LP8557_PGEN_FREQ_14_6_KHZ,
+	LP8557_PGEN_FREQ_19_5_KHZ,
+	LP8557_PGEN_FREQ_24_4_KHZ,
+	LP8557_PGEN_FREQ_29_3_KHZ,
+	LP8557_PGEN_FREQ_34_2_KHZ,
+	LP8557_PGEN_FREQ_39_1_KHZ,
+	LP8557_PGEN_FREQ_MAX,
+};
+#define LP8557_PGEN					0x12
+#define LP8557_PGEN_FREQ(x)				(((x) & 0x7) << 0)
+#define LP8557_PGEN_MAGIC				(5 << 3)
+#define LP8557_PGEN_FSET				(1 << 7)
+
+enum lp8557_boost_freq {
+	LP8557_BOOST_FREQ_500_KHZ			= 0x0,
+	LP8557_BOOST_FREQ_1_MHZ,
+	LP8557_BOOST_FREQ_MAX,
+};
+enum lp8557_boost_bcomp {
+	LP8557_BOOST_BCOMP_OPTION_0			= 0x0,
+	LP8557_BOOST_BCOMP_OPTION_1,
+	LP8557_BOOST_BCOMP_MAX,
+};
+#define LP8557_BOOST					0x13
+#define LP8557_BOOST_FREQ(x)				(((x) & 0x1) << 0)
+#define LP8557_BOOST_BCOMP(x)				(((x) & 0x1) << 1)
+#define LP8557_BOOST_BCSET				(1 << 6)
+#define LP8557_BOOST_BFSET				(1 << 7)
+
+#define LP8557_LED_ENABLE				0x14
+#define LP8557_LED_ENABLE_SINKS(x)			(((x) & 0x3F) << 0)
+#define LP8557_LED_ENABLE_MAGIC				(2 << 6)
+
+enum lp8557_step_ramp {
+	LP8557_STEP_RAMP_0_MS				= 0x0,
+	LP8557_STEP_RAMP_50_MS,
+	LP8557_STEP_RAMP_100_MS,
+	LP8557_STEP_RAMP_200_MS,
+	LP8557_STEP_RAMP_MAX,
+};
+enum lp8557_step_smoothing {
+	LP8557_STEP_SMOOTHING_NONE			= 0x0,
+	LP8557_STEP_SMOOTHING_LIGHT,
+	LP8557_STEP_SMOOTHING_MEDIUM,
+	LP8557_STEP_SMOOTHING_HEAVY,
+	LP8557_STEP_SMOOTHING_MAX,
+};
+#define LP8557_STEP					0x15
+#define LP8557_STEP_RAMP(x)				(((x) & 0x3) << 0)
+#define LP8557_STEP_SMOOTHING(x)			(((x) & 0x3) << 6)
+
+struct mipi_dsi_device;
+struct soc_nvidia_tegra132_config;
+
+struct panel_jdi {
+	struct mipi_dsi_device *dsi;
+	const struct soc_nvidia_tegra132_config *mode;
+
+	/* Physical size */
+	unsigned int width_mm;
+	unsigned int height_mm;
+
+	int enabled;
+};
+
+struct panel_jdi *panel_jdi_dsi_probe(struct mipi_dsi_device *dsi);
+int panel_jdi_prepare(struct panel_jdi *jdi);
+
+#endif
diff --git a/src/soc/nvidia/tegra132/mipi-phy.c b/src/soc/nvidia/tegra132/mipi-phy.c
new file mode 100644
index 0000000..35adf6e
--- /dev/null
+++ b/src/soc/nvidia/tegra132/mipi-phy.c
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+#include <soc/mipi-phy.h>
+
+int mipi_dphy_set_timing(struct tegra_dsi *dsi)
+{
+
+	u32 freq = (dsi->clk_rate * 2) / 1000000;
+
+	u32 thsdexit = (DSI_PHY_TIMING_DIV(120, (freq)));
+	u32 thstrial = (((3) + (DSI_PHY_TIMING_DIV((DSI_THSTRAIL_VAL(freq)),
+			freq))));
+	u32 tdatzero = DSI_PHY_TIMING_DIV(((145) + (5 * (DSI_TBIT(freq)))),
+			(freq));
+	u32 thsprepare = DSI_PHY_TIMING_DIV((65 + (5*(DSI_TBIT(freq)))), freq);
+	u32 tclktrial = (DSI_PHY_TIMING_DIV(80, freq));
+	u32 tclkpost = ((DSI_PHY_TIMING_DIV(((70) + ((52) * (DSI_TBIT(freq)))),
+			freq)));
+	u32 tclkzero = (DSI_PHY_TIMING_DIV(260, freq));
+	u32 ttlpx = (DSI_PHY_TIMING_DIV(60, freq)) ;
+	u32 tclkprepare = (DSI_PHY_TIMING_DIV(60, freq));
+	u32 tclkpre = 1; //min = 8*UI per mipi spec, tclk_pre=0 should be ok, but using 1 value
+	u32 twakeup = 0x7F; //min = 1ms
+
+	u32 ttaget;
+	u32 ttassure;
+	u32 ttago;
+	u32 value;
+
+	if (!ttlpx) {
+		ttaget = 5;
+		ttassure = 2;
+		ttago = 4;
+	} else {
+		ttaget = 5 * ttlpx;
+		ttassure = 2 * ttlpx;
+		ttago = 4 * ttlpx;
+	}
+
+	value = (thsdexit << 24) |
+		(thstrial << 16) |
+		(tdatzero << 8) |
+		(thsprepare << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
+
+	value = (tclktrial << 24) |
+		(tclkpost << 16)  |
+		(tclkzero << 8) |
+		(ttlpx << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
+
+	value = (tclkprepare << 16) |
+		(tclkpre << 8) |
+		(twakeup << 0);
+	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
+
+	value = (ttaget << 16) |
+		(ttassure << 8) |
+		(ttago << 0),
+	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
+	return 0;
+}
diff --git a/src/soc/nvidia/tegra132/mipi.c b/src/soc/nvidia/tegra132/mipi.c
new file mode 100644
index 0000000..abd2230
--- /dev/null
+++ b/src/soc/nvidia/tegra132/mipi.c
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/tegra_dsi.h>
+#include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
+
+static unsigned long dsi_pads[] = {
+	0x060, /* DSIA & DSIB pads */
+	0x180, /* DSIC & DSID pads */
+};
+
+static struct tegra_mipi mipi_data = {
+	.regs = (void *)TEGRA_MIPI_CAL_BASE,
+};
+
+static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
+					     unsigned long reg)
+{
+	return readl(mipi->regs + (reg << 2));
+}
+
+static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
+				     unsigned long value, unsigned long reg)
+{
+	writel(value, mipi->regs + (reg << 2));
+}
+
+static const struct calibration_regs tegra124_mipi_calibration_regs[] = {
+	{ .data = MIPI_CAL_CONFIG_CSIA, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
+	{ .data = MIPI_CAL_CONFIG_CSIB, .clk = MIPI_CAL_CONFIG_CSIAB_CLK },
+	{ .data = MIPI_CAL_CONFIG_CSIC, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
+	{ .data = MIPI_CAL_CONFIG_CSID, .clk = MIPI_CAL_CONFIG_CSICD_CLK },
+	{ .data = MIPI_CAL_CONFIG_CSIE, .clk = MIPI_CAL_CONFIG_CSIE_CLK },
+	{ .data = MIPI_CAL_CONFIG_DSIA, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
+	{ .data = MIPI_CAL_CONFIG_DSIB, .clk = MIPI_CAL_CONFIG_DSIAB_CLK },
+};
+static const struct tegra_mipi_config tegra124_mipi_config = {
+	.calibrate_clk_lane = 1,
+	.regs = tegra124_mipi_calibration_regs,
+	.num_pads = ARRAY_SIZE(tegra124_mipi_calibration_regs),
+};
+
+struct tegra_mipi_device *tegra_mipi_request(struct tegra_mipi_device *device,
+						int device_index)
+{
+	device->mipi = &mipi_data;
+	device->config = &tegra124_mipi_config;
+	device->pads = dsi_pads[device_index];
+
+	return device;
+}
+
+static int tegra_mipi_wait(struct tegra_mipi *mipi)
+{
+	u32 poll_interval_us = 1000;
+	u32 timeout_us = 250 * 1000;
+	unsigned long value;
+
+	do {
+		value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
+		if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
+		    (value & MIPI_CAL_STATUS_DONE) != 0)
+			return 0;
+
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
+	return -ETIMEDOUT;
+}
+
+int tegra_mipi_calibrate(struct tegra_mipi_device *device)
+{
+	const struct tegra_mipi_config *cfg = device->config;
+	unsigned long value, clk_value;
+	unsigned int i;
+	int err;
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
+	value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
+	value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+	tegra_mipi_writel(device->mipi, MIPI_CAL_BIAS_PAD_CFG1_DEFAULT,
+			 MIPI_CAL_BIAS_PAD_CFG1);
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
+	value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+	for (i = 0; i < cfg->num_pads; i++) {
+		if (device->pads & BIT(i)) {
+			value = MIPI_CAL_CONFIG_SELECT |
+				MIPI_CAL_CONFIG_HSPDOS(0) |
+				MIPI_CAL_CONFIG_HSPUOS(4) |
+				MIPI_CAL_CONFIG_TERMOS(5);
+			clk_value = MIPI_CAL_CONFIG_SELECT |
+				    MIPI_CAL_CONFIG_HSCLKPDOSD(0) |
+				    MIPI_CAL_CONFIG_HSCLKPUOSD(4);
+		} else {
+			value = 0;
+			clk_value = 0;
+		}
+
+		tegra_mipi_writel(device->mipi, value, cfg->regs[i].data);
+
+		if (cfg->calibrate_clk_lane)
+			tegra_mipi_writel(device->mipi, clk_value,
+					cfg->regs[i].clk);
+	}
+
+	value = tegra_mipi_readl(device->mipi, MIPI_CAL_CTRL);
+	value |= MIPI_CAL_CTRL_START;
+	tegra_mipi_writel(device->mipi, value, MIPI_CAL_CTRL);
+
+	err = tegra_mipi_wait(device->mipi);
+
+	return err;
+}
diff --git a/src/soc/nvidia/tegra132/mipi_dsi.c b/src/soc/nvidia/tegra132/mipi_dsi.c
new file mode 100644
index 0000000..440bb23
--- /dev/null
+++ b/src/soc/nvidia/tegra132/mipi_dsi.c
@@ -0,0 +1,431 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda at samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <string.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+
+struct mipi_dsi_device mipi_dsi_device_data[NUM_DSI] = {
+	{
+		.master = NULL,
+		.slave = &mipi_dsi_device_data[DSI_B],
+	},
+	{
+		.master = &mipi_dsi_device_data[DSI_A],
+		.slave = NULL,
+	},
+};
+
+static struct mipi_dsi_device *
+mipi_dsi_device_alloc(struct mipi_dsi_host *host)
+{
+	static int index = 0;
+	struct mipi_dsi_device *dsi;
+
+	if (index >= NUM_DSI)
+		return (void *)-EPTR;
+
+	dsi = &mipi_dsi_device_data[index++];
+	dsi->host = host;
+	return dsi;
+}
+
+static struct mipi_dsi_device *
+of_mipi_dsi_device_add(struct mipi_dsi_host *host)
+{
+	struct mipi_dsi_device *dsi;
+	u32 reg = 0;
+
+	dsi = mipi_dsi_device_alloc(host);
+	if (IS_ERR_PTR(dsi)) {
+		printk(BIOS_ERR, "failed to allocate DSI device\n");
+		return dsi;
+	}
+
+	dsi->channel = reg;
+	host->dev = (void *)dsi;
+
+	return dsi;
+}
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host)
+{
+	of_mipi_dsi_device_add(host);
+	return 0;
+}
+
+/**
+ * mipi_dsi_attach - attach a DSI device to its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_attach(struct mipi_dsi_device *dsi)
+{
+	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+	if (!ops || !ops->attach)
+		return -ENOSYS;
+
+	return ops->attach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_detach - detach a DSI device from its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_detach(struct mipi_dsi_device *dsi)
+{
+	const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+	if (!ops || !ops->detach)
+		return -ENOSYS;
+
+	return ops->detach(dsi->host, dsi);
+}
+
+/**
+ * mipi_dsi_enslave() - use a MIPI DSI peripheral as slave for dual-channel
+ *    operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_enslave(struct mipi_dsi_device *master,
+		     struct mipi_dsi_device *slave)
+{
+	int err = 0;
+
+	slave->master = master;
+	master->slave = slave;
+
+	if (master->ops && master->ops->enslave)
+		err = master->ops->enslave(master, slave);
+
+	return err;
+}
+
+/**
+ * mipi_dsi_liberate() - stop using a MIPI DSI peripheral as slave for dual-
+ *    channel operation
+ * @master: master DSI peripheral device
+ * @slave: slave DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_liberate(struct mipi_dsi_device *master,
+		      struct mipi_dsi_device *slave)
+{
+	int err = 0;
+
+	if (master->ops && master->ops->liberate)
+		err = master->ops->liberate(master, slave);
+
+	master->slave = NULL;
+	slave->master = NULL;
+
+	return err;
+}
+
+/**
+ * mipi_dsi_dcs_write() - send DCS write command
+ * @dsi: DSI peripheral device
+ * @cmd: DCS command
+ * @data: buffer containing the command payload
+ * @len: command payload length
+ *
+ * This function will automatically choose the right data type depending on
+ * the command payload length.
+ *
+ * Return: The number of bytes successfully transmitted or a negative error
+ * code on failure.
+ */
+ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
+			   const void *data, size_t len)
+{
+	struct mipi_dsi_msg msg;
+	ssize_t err;
+	size_t size;
+
+	u8 buffer[MAX_DSI_HOST_FIFO_DEPTH + 4];
+	u8 *tx = buffer;
+
+	if (len > MAX_DSI_HOST_FIFO_DEPTH) {
+		printk(BIOS_ERR, "%s: Error: too large payload length: %zu\n",
+			__func__, len);
+
+		return -EINVAL;
+	}
+
+	if (len > 0) {
+		unsigned int offset = 0;
+
+		/*
+		 * DCS long write packets contain the word count in the header
+		 * bytes 1 and 2 and have a payload containing the DCS command
+		 * byte folowed by word count minus one bytes.
+		 *
+		 * DCS short write packets encode the DCS command and up to
+		 * one parameter in header bytes 1 and 2.
+		 */
+		if (len > 1)
+			size = 3 + len;
+		else
+			size = 1 + len;
+
+		/* write word count to header for DCS long write packets */
+		if (len > 1) {
+			tx[offset++] = ((1 + len) >> 0) & 0xff;
+			tx[offset++] = ((1 + len) >> 8) & 0xff;
+		}
+
+		/* write the DCS command byte followed by the payload */
+		tx[offset++] = cmd;
+		memcpy(tx + offset, data, len);
+	} else {
+		tx = &cmd;
+		size = 1;
+	}
+
+	memset(&msg, 0, sizeof(msg));
+	msg.flags = MIPI_DSI_MSG_USE_LPM;
+	msg.channel = dsi->channel;
+	msg.tx_len = size;
+	msg.tx_buf = tx;
+
+	switch (len) {
+	case 0:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE;
+		break;
+	case 1:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+		break;
+	default:
+		msg.type = MIPI_DSI_DCS_LONG_WRITE;
+		break;
+	}
+
+	err = dsi->host->ops->transfer(dsi->host, &msg);
+
+	return err;
+}
+
+/**
+ * mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
+ *    module
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_display_on() - start displaying the image data on the
+ *    display device
+ * @dsi: DSI peripheral device
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_column_address() - define the column extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first column of frame memory
+ * @end: last column of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
+				    u16 end)
+{
+	u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
+				 sizeof(payload));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_page_address() - define the page extent of the frame
+ *    memory accessed by the host processor
+ * @dsi: DSI peripheral device
+ * @start: first page of frame memory
+ * @end: last page of frame memory
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
+				  u16 end)
+{
+	u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
+				 sizeof(payload));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
+ *    output signal on the TE signal line.
+ * @dsi: DSI peripheral device
+ * @mode: the Tearing Effect Output Line mode
+ *
+ * Return: 0 on success or a negative error code on failure
+ */
+int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
+			     enum mipi_dsi_dcs_tear_mode mode)
+{
+	u8 value = mode;
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
+				 sizeof(value));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
+ *    data used by the interface
+ * @dsi: DSI peripheral device
+ * @format: pixel format
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
+{
+	ssize_t err;
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
+				 sizeof(format));
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/**
+ * mipi_dsi_dcs_set_address_mode() - sets the data order for forward transfers
+ *    from the host to the peripheral
+ * @dsi: DSI peripheral device
+ * @reverse_page_address: reverses the page addressing to bottom->top
+ * @reverse_col_address: reverses the column addressing to right->left
+ * @reverse_page_col_address: reverses the page/column addressing order
+ * @refresh_from_bottom: refresh the display bottom to top
+ * @reverse_rgb: send pixel data bgr instead of rgb
+ * @latch_right_to_left: latch the incoming display data right to left
+ * @flip_horizontal: flip the image horizontally, left to right
+ * @flip_vertical: flip the image vertically, top to bottom
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_dcs_set_address_mode(struct mipi_dsi_device *dsi,
+			bool reverse_page_address,
+			bool reverse_col_address,
+			bool reverse_page_col_address,
+			bool refresh_from_bottom,
+			bool reverse_rgb,
+			bool latch_right_to_left,
+			bool flip_horizontal,
+			bool flip_vertical)
+{
+	ssize_t err;
+	u8 data;
+
+	data = ((flip_vertical ? 1 : 0) << 0) |
+		((flip_horizontal ? 1 : 0) << 1) |
+		((latch_right_to_left ? 1 : 0) << 2) |
+		((reverse_rgb ? 1 : 0) << 3) |
+		((refresh_from_bottom ? 1 : 0) << 4) |
+		((reverse_page_col_address ? 1 : 0) << 5) |
+		((reverse_col_address ? 1 : 0) << 6) |
+		((reverse_page_address ? 1 : 0) << 7);
+
+	err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_ADDRESS_MODE, &data, 1);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
diff --git a/src/soc/nvidia/tegra132/soc.c b/src/soc/nvidia/tegra132/soc.c
index 0014f84..d80a388 100644
--- a/src/soc/nvidia/tegra132/soc.c
+++ b/src/soc/nvidia/tegra132/soc.c
@@ -76,11 +76,6 @@ static struct cpu_control_ops cntrl_ops = {
 	.start_cpu = cntrl_start_cpu,
 };
 
-void display_startup(device_t dev)
-{
-	printk(BIOS_INFO, "Entering %s()\n", __func__);
-}
-
 static void soc_init(device_t dev)
 {
 	struct soc_nvidia_tegra132_config *cfg;
diff --git a/src/soc/nvidia/tegra132/tegra_dsi.c b/src/soc/nvidia/tegra132/tegra_dsi.c
new file mode 100644
index 0000000..3a7949d
--- /dev/null
+++ b/src/soc/nvidia/tegra132/tegra_dsi.c
@@ -0,0 +1,874 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2014 Google 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; version 2 of the License.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <lib.h>
+#include <stdlib.h>
+#include <delay.h>
+#include <timer.h>
+#include <soc/addressmap.h>
+#include <soc/clock.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/types.h>
+#include "chip.h"
+#include <soc/display.h>
+#include <soc/mipi_dsi.h>
+#include <soc/mipi_display.h>
+#include <soc/tegra_dsi.h>
+#include <soc/mipi-phy.h>
+#include "jdi_25x18_display/panel-jdi-lpm102a188a.h"
+
+struct tegra_mipi_device mipi_device_data[NUM_DSI];
+
+struct tegra_dsi dsi_data[NUM_DSI] = {
+	{
+		.regs = (void *)TEGRA_DSIA_BASE,
+		.channel = 0,
+		.slave = &dsi_data[DSI_B],
+		.master = NULL,
+		.video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
+		.host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
+	},
+	{
+		.regs = (void *)TEGRA_DSIB_BASE,
+		.channel = 0,
+		.slave = NULL,
+		.master = &dsi_data[DSI_A],
+		.video_fifo_depth = MAX_DSI_VIDEO_FIFO_DEPTH,
+		.host_fifo_depth = MAX_DSI_HOST_FIFO_DEPTH,
+	},
+};
+
+static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
+{
+	return container_of(host, struct tegra_dsi, host);
+}
+
+/*
+ * non-burst mode with sync pulses
+ */
+static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
+	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 1] = 0,
+	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 3] = 0,
+	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 5] = 0,
+	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+	       PKT_LP,
+	[ 9] = 0,
+	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+};
+
+/*
+ * non-burst mode with sync events
+ */
+static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
+	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 1] = 0,
+	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 3] = 0,
+	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 5] = 0,
+
+	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+
+	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
+	       PKT_LP,
+	[ 9] = 0,
+
+	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
+	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
+
+	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
+};
+
+static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
+	[ 0] = 0,
+	[ 1] = 0,
+	[ 2] = 0,
+	[ 3] = 0,
+	[ 4] = 0,
+	[ 5] = 0,
+	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
+	[ 7] = 0,
+	[ 8] = 0,
+	[ 9] = 0,
+	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
+	[11] = 0,
+};
+
+static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+{
+	int err;
+
+	err = mipi_dphy_set_timing(dsi);
+	if (err < 0) {
+		printk(BIOS_ERR, "failed to set D-PHY timing: %d\n", err);
+		return err;
+	}
+
+	if (dsi->slave)
+		tegra_dsi_set_phy_timing(dsi->slave);
+	return 0;
+}
+
+static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
+				unsigned int *mulp, unsigned int *divp)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB666_PACKED:
+	case MIPI_DSI_FMT_RGB888:
+		*mulp = 3;
+		*divp = 1;
+		break;
+
+	case MIPI_DSI_FMT_RGB565:
+		*mulp = 2;
+		*divp = 1;
+		break;
+
+	case MIPI_DSI_FMT_RGB666:
+		*mulp = 9;
+		*divp = 4;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
+				enum tegra_dsi_format *fmt)
+{
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		*fmt = TEGRA_DSI_FORMAT_24P;
+		break;
+
+	case MIPI_DSI_FMT_RGB666:
+		*fmt = TEGRA_DSI_FORMAT_18NP;
+		break;
+
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		*fmt = TEGRA_DSI_FORMAT_18P;
+		break;
+
+	case MIPI_DSI_FMT_RGB565:
+		*fmt = TEGRA_DSI_FORMAT_16P;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
+				    unsigned int size)
+{
+	u32 value;
+
+	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
+	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
+
+	value = DSI_GANGED_MODE_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
+}
+
+static void tegra_dsi_enable(struct tegra_dsi *dsi)
+{
+	u32 value;
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value |= DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	if (dsi->slave)
+		tegra_dsi_enable(dsi->slave);
+}
+
+static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+			const struct soc_nvidia_tegra132_config *mode)
+{
+	unsigned int hact, hsw, hbp, hfp, i, mul, div;
+	enum tegra_dsi_format format;
+	const u32 *pkt_seq;
+	u32 value;
+	int err;
+
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+		printk(BIOS_SPEW, "Non-burst video mode with sync pulses\n");
+		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
+	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
+		printk(BIOS_SPEW, "Non-burst video mode with sync events\n");
+		pkt_seq = pkt_seq_video_non_burst_sync_events;
+	} else {
+		printk(BIOS_SPEW, "Command mode\n");
+		pkt_seq = pkt_seq_command_mode;
+	}
+
+	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+	if (err < 0)
+		return err;
+
+	err = tegra_dsi_get_format(dsi->format, &format);
+	if (err < 0)
+		return err;
+
+	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
+		DSI_CONTROL_LANES(dsi->lanes - 1) |
+		DSI_CONTROL_SOURCE(pipe);
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
+
+	value = DSI_HOST_CONTROL_HS;
+	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+	value = tegra_dsi_readl(dsi, DSI_CONTROL);
+
+	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+		value |= DSI_CONTROL_HS_CLK_CTRL;
+
+	value &= ~DSI_CONTROL_TX_TRIG(3);
+
+	/* enable DCS commands for command mode */
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
+		value &= ~DSI_CONTROL_DCS_ENABLE;
+	else
+		value |= DSI_CONTROL_DCS_ENABLE;
+
+	value |= DSI_CONTROL_VIDEO_ENABLE;
+	value &= ~DSI_CONTROL_HOST_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	for (i = 0; i < NUM_PKT_SEQ; i++)
+		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
+
+	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
+		/* horizontal active pixels */
+		hact = mode->xres * mul / div;
+
+		/* horizontal sync width */
+		hsw = (hsync_end(mode) - hsync_start(mode)) * mul / div;
+		hsw -= 10;
+
+		/* horizontal back porch */
+		hbp = (htotal(mode) - hsync_end(mode)) * mul / div;
+		hbp -= 14;
+
+		/* horizontal front porch */
+		hfp = (hsync_start(mode) - mode->xres) * mul / div;
+		hfp -= 8;
+
+		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
+		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
+		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
+		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
+
+		/* set SOL delay (for non-burst mode only) */
+		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
+
+		/* TODO: implement ganged mode */
+	} else {
+		u16 bytes;
+		if (dsi->ganged_mode) {
+			/*
+			 * For ganged mode, assume symmetric left-right mode.
+			 */
+			bytes = 1 + (mode->xres / 2) * mul / div;
+		} else {
+			/* 1 byte (DCS command) + pixel data */
+			bytes = 1 + mode->xres * mul / div;
+		}
+
+		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
+		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
+		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
+		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
+
+		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
+			MIPI_DCS_WRITE_MEMORY_CONTINUE;
+		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
+
+		/* set SOL delay */
+		if (dsi->ganged_mode) {
+			unsigned long delay, bclk, bclk_ganged;
+			unsigned int lanes = dsi->ganged_lanes;
+
+			/* SOL to valid, valid to FIFO and FIFO write delay */
+			delay = 4 + 4 + 2;
+			delay = DIV_ROUND_UP(delay * mul, div * lanes);
+			/* FIFO read delay */
+			delay = delay + 6;
+
+			bclk = DIV_ROUND_UP(htotal(mode) * mul, div * lanes);
+			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
+			value = bclk - bclk_ganged + delay + 20;
+		} else {
+			/* TODO: revisit for non-ganged mode */
+			value = 8 * mul / div;
+		}
+
+		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
+	}
+
+	if (dsi->slave) {
+		err = tegra_dsi_configure(dsi->slave, pipe, mode);
+		if (err < 0)
+			return err;
+
+		/*
+		 * enable ganged mode
+		 */
+		if (dsi->ganged_mode) {
+			tegra_dsi_ganged_enable(dsi, mode->xres / 2,
+					mode->xres / 2);
+			tegra_dsi_ganged_enable(dsi->slave, 0, mode->xres / 2);
+		}
+	}
+	return 0;
+}
+
+static int tegra_output_dsi_enable(struct tegra_dsi *dsi,
+			const struct soc_nvidia_tegra132_config *config)
+{
+	int err;
+
+	if (dsi->enabled)
+		return 0;
+
+	err = tegra_dsi_configure(dsi, 0, config);
+	if (err < 0)
+		return err;
+
+	/* enable DSI controller */
+	tegra_dsi_enable(dsi);
+
+	dsi->enabled = true;
+	return 0;
+}
+
+
+static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
+				  unsigned int vrefresh)
+{
+	unsigned int timeout;
+	u32 value;
+
+	/* one frame high-speed transmission timeout */
+	timeout = (bclk / vrefresh) / 512;
+	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
+	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
+
+	/* 2 ms peripheral timeout for panel */
+	timeout = 2 * bclk / 512 * 1000;
+	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
+	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
+
+	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
+	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+
+	if (dsi->slave)
+		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
+}
+
+static int tegra_output_dsi_setup_clock(struct tegra_dsi *dsi,
+			const struct soc_nvidia_tegra132_config *config)
+{
+	unsigned int mul, div, num_lanes; // , vrefresh, num_lanes;
+	unsigned long bclk;
+	unsigned long pclk = config->pixel_clock;
+	int plld;
+	int err;
+
+	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+	if (err < 0)
+		return err;
+
+	/*
+	 * In ganged mode, account for the total number of lanes across both
+	 * DSI channels so that the bit clock is properly computed.
+	 */
+	if (dsi->ganged_mode)
+		num_lanes = dsi->ganged_lanes;
+	else
+		num_lanes = dsi->lanes;
+
+	/* compute byte clock */
+	bclk = (pclk * mul) / (div * num_lanes);
+
+	/*
+	 * Compute bit clock and round up to the next MHz.
+	 */
+	plld = DIV_ROUND_UP(bclk * 8, USECS_PER_SEC) * USECS_PER_SEC;
+
+	/*
+	 * the actual rate on PLLD_OUT0 is 1/2 plld
+	 */
+	dsi->clk_rate = plld / 2;
+	if (dsi->slave)
+		dsi->slave->clk_rate = dsi->clk_rate;
+
+	/* set up plld */
+	plld = clock_display(plld);
+	if (plld == 0) {
+                printk(BIOS_ERR, "%s: clock init failed\n", __func__);
+                return -1;
+        }
+
+	tegra_dsi_set_timeout(dsi, bclk, config->refresh);
+	return plld/1000000;
+}
+
+
+
+static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
+{
+	unsigned long value;
+
+	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
+	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+	return 0;
+}
+
+static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
+{
+	u32 value;
+
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
+	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
+
+	/* start calibration */
+	tegra_dsi_pad_enable(dsi);
+
+	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
+		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
+		DSI_PAD_OUT_CLK(0x0);
+	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
+
+	return tegra_mipi_calibrate(dsi->mipi);
+}
+
+static const char * const error_report[16] = {
+	"SoT Error",
+	"SoT Sync Error",
+	"EoT Sync Error",
+	"Escape Mode Entry Command Error",
+	"Low-Power Transmit Sync Error",
+	"Peripheral Timeout Error",
+	"False Control Error",
+	"Contention Detected",
+	"ECC Error, single-bit",
+	"ECC Error, multi-bit",
+	"Checksum Error",
+	"DSI Data Type Not Recognized",
+	"DSI VC ID Invalid",
+	"Invalid Transmission Length",
+	"Reserved",
+	"DSI Protocol Violation",
+};
+
+static int tegra_dsi_read_response(struct tegra_dsi *dsi,
+				   const struct mipi_dsi_msg *msg,
+				   unsigned int count)
+{
+	u8 *rx = msg->rx_buf;
+	unsigned int i, j, k;
+	size_t size = 0;
+	u16 errors;
+	u32 value;
+
+	/* read and parse packet header */
+	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+	switch (value & 0x3f) {
+	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+		errors = (value >> 8) & 0xffff;
+		printk(BIOS_ERR, "Acknowledge and error report: %04x\n",
+			errors);
+		for (i = 0; i < ARRAY_SIZE(error_report); i++)
+			if (errors & BIT(i))
+				printk(BIOS_INFO, "  %2u: %s\n", i,
+					error_report[i]);
+		break;
+
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+		rx[0] = (value >> 8) & 0xff;
+		break;
+
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+		rx[0] = (value >>  8) & 0xff;
+		rx[1] = (value >> 16) & 0xff;
+		break;
+
+	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+		break;
+
+	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
+		break;
+
+	default:
+		printk(BIOS_ERR, "unhandled response type: %02x\n",
+			value & 0x3f);
+		break;
+	}
+
+	size = MIN(size, msg->rx_len);
+
+	if (msg->rx_buf && size > 0) {
+		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
+			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+
+			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
+				rx[j + k] = (value >> (k << 3)) & 0xff;
+		}
+	}
+	return 0;
+}
+
+static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout_ms)
+{
+	u32 poll_interval_us = 2000;
+	u32 timeout_us = timeout_ms * 1000;
+
+	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
+	udelay(poll_interval_us);
+
+	do {
+		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
+		if ((value & DSI_TRIGGER_HOST) == 0)
+			return 0;
+
+		//usleep_range(1000, 2000);
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout waiting for transmission"
+			" to complete\n", __func__);
+	return -ETIMEDOUT;
+}
+
+static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
+				       unsigned long timeout_ms)
+{
+	u32 poll_interval_us = 2000;
+	u32 timeout_us = timeout_ms * 1000;
+
+	do {
+		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
+		u8 count = value & 0x1f;
+
+		if (count > 0)
+			return count;
+
+		if (timeout_us > poll_interval_us)
+			timeout_us -= poll_interval_us;
+		else
+			break;
+
+		udelay(poll_interval_us);
+	} while (1);
+
+	printk(BIOS_ERR, "%s: ERROR: timeout\n", __func__);
+
+	return -ETIMEDOUT;
+}
+
+static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
+				const struct mipi_dsi_msg *msg)
+{
+	struct tegra_dsi *dsi = host_to_tegra(host);
+	const u8 *tx = msg->tx_buf;
+	unsigned int count, i, j;
+	u32 value;
+	int err;
+
+	if (msg->tx_len > dsi->video_fifo_depth * 4)
+		return -ENOSPC;
+
+	/* reset underflow/overflow flags */
+	value = tegra_dsi_readl(dsi, DSI_STATUS);
+	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
+		value = DSI_HOST_CONTROL_FIFO_RESET;
+		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+		udelay(20);	// usleep_range(10, 20);
+	}
+
+	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+	value |= DSI_POWER_CONTROL_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+	udelay(7000);	//usleep_range(5000, 10000);
+
+	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
+		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
+
+	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
+		value |= DSI_HOST_CONTROL_HS;
+
+	/*
+	 * The host FIFO has a maximum of 64 words, so larger transmissions
+	 * need to use the video FIFO.
+	 */
+	if (msg->tx_len > dsi->host_fifo_depth * 4)
+		value |= DSI_HOST_CONTROL_FIFO_SEL;
+
+	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+	/*
+	 * For reads and messages with explicitly requested ACK, generate a
+	 * BTA sequence after the transmission of the packet.
+	 */
+	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+	    (msg->rx_buf && msg->rx_len > 0)) {
+		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
+		value |= DSI_HOST_CONTROL_PKT_BTA;
+		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+	}
+
+	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
+	tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+	/* write packet header */
+	value = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
+
+	if (tx && msg->tx_len > 0)
+		value |= tx[0] <<  8;
+
+	if (tx && msg->tx_len > 1)
+		value |= tx[1] << 16;
+
+	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+
+	/* write payload (if any) */
+	if (msg->tx_len > 2) {
+		for (j = 2; j < msg->tx_len; j += 4) {
+			value = 0;
+
+			for (i = 0; i < 4 && j + i < msg->tx_len; i++)
+				value |= tx[j + i] << (i << 3);
+
+			tegra_dsi_writel(dsi, value, DSI_WR_DATA);
+		}
+	}
+
+	err = tegra_dsi_transmit(dsi, 250);
+	if (err < 0)
+		return err;
+
+	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
+	    (msg->rx_buf && msg->rx_len > 0)) {
+		err = tegra_dsi_wait_for_response(dsi, 250);
+		if (err < 0)
+			return err;
+
+		count = err;
+
+		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
+		switch (value) {
+		case 0x84:
+			/*
+			dev_dbg(dsi->dev, "ACK\n");
+			*/
+			break;
+
+		case 0x87:
+			/*
+			dev_dbg(dsi->dev, "ESCAPE\n");
+			*/
+			break;
+
+		default:
+			printk(BIOS_INFO, "unknown status: %08x\n", value);
+			break;
+		}
+
+		if (count > 1) {
+			err = tegra_dsi_read_response(dsi, msg, count);
+			if (err < 0)
+				printk(BIOS_INFO,
+					"failed to parse response: %d\n",
+					err);
+		}
+	}
+	return 0;
+}
+
+static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi,
+			  struct tegra_dsi *slave)
+{
+	/*
+	 * The number of ganged lanes is the sum of lanes of all peripherals
+	 * in the gang.
+	 */
+	dsi->slave->ganged_lanes = dsi->lanes + dsi->slave->lanes;
+	dsi->slave->ganged_mode = 1;
+
+	dsi->ganged_lanes = dsi->lanes + dsi->slave->lanes;
+	dsi->ganged_mode = 1;
+	return 0;
+}
+
+static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
+				struct mipi_dsi_device *device)
+{
+	struct tegra_dsi *dsi = host_to_tegra(host);
+	int err;
+
+	dsi->flags = device->mode_flags;
+	dsi->format = device->format;
+	dsi->lanes = device->lanes;
+
+	if (dsi->master) {
+		err = tegra_dsi_ganged_setup(dsi->master, dsi);
+		if (err < 0) {
+			printk(BIOS_ERR, "failed to set up ganged mode: %d\n",
+				err);
+			return err;
+		}
+	}
+	return 0;
+}
+
+static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
+	.attach = tegra_dsi_host_attach,
+	.transfer = tegra_dsi_host_transfer,
+};
+
+static int dsi_probe_if(int dsi_index,
+			struct soc_nvidia_tegra132_config *config)
+{
+	struct tegra_dsi *dsi = &dsi_data[dsi_index];
+	int err;
+
+	/*
+	 * Set default value. Will be taken from attached device once detected
+	 */
+        dsi->flags = 0;
+        dsi->format = MIPI_DSI_FMT_RGB888;
+        dsi->lanes = 4;
+
+	/* get tegra_mipi_device */
+        dsi->mipi = tegra_mipi_request(&mipi_device_data[dsi_index], dsi_index);
+
+	/* calibrate */
+	err = tegra_dsi_pad_calibrate(dsi);
+	if (err < 0) {
+		printk(BIOS_ERR, "MIPI calibration failed: %d\n", err);
+		return err;
+	}
+
+	dsi->host.ops = &tegra_dsi_host_ops;
+	err = mipi_dsi_host_register(&dsi->host);
+	if (err < 0) {
+		printk(BIOS_ERR, "failed to register DSI host: %d\n", err);
+		return err;
+	}
+
+	/* get panel */
+	dsi->panel = panel_jdi_dsi_probe((struct mipi_dsi_device *)dsi->host.dev);
+	if (IS_ERR_PTR(dsi->panel)) {
+		printk(BIOS_ERR, "failed to get dsi panel\n");
+		return -EPTR;
+	}
+	dsi->panel->mode = config;
+	return 0;
+}
+
+static int dsi_probe(struct soc_nvidia_tegra132_config *config)
+{
+	dsi_probe_if(DSI_A, config);
+	dsi_probe_if(DSI_B, config);
+	return 0;
+}
+
+int dsi_enable(struct soc_nvidia_tegra132_config *config)
+{
+	struct tegra_dsi *dsi_a = &dsi_data[DSI_A];
+
+	dsi_probe(config);
+
+	/* set up clock and TimeOutRegisters */
+	tegra_output_dsi_setup_clock(dsi_a, config);
+
+	/* configure APB_MISC_GP_MIPI_PAD_CTRL_0 */
+	write32(DSIB_MODE_DSI, (unsigned int *)APB_MISC_GP_MIPI_PAD_CTRL_0);
+
+	/* configure phy interface timing registers */
+	tegra_dsi_set_phy_timing(dsi_a);
+
+	/* prepare panel */
+	panel_jdi_prepare(dsi_a->panel);
+
+	/* enable dsi */
+	if (tegra_output_dsi_enable(dsi_a, config)) {
+		printk(BIOS_ERR,"%s: Error: failed to enable dsi output.\n",
+			__func__);
+		return -1;
+	}
+
+	return 0;
+}



More information about the coreboot-gerrit mailing list