[coreboot-gerrit] Patch set updated for coreboot: fb007bd ryu: display: Split dc functions from dsi display code

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Mon Apr 13 13:07:02 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/9583

-gerrit

commit fb007bdffae962b52ab80d752ef6b72b05c14eb6
Author: Jimmy Zhang <jimmzhang at nvidia.com>
Date:   Tue Dec 9 15:20:20 2014 -0800

    ryu: display: Split dc functions from dsi display code
    
    dc supporting functions can be used for other than dsi display
    interfaces. This change is preparing for supporting sor display
    interface.
    
    BUG=chrome-os-partner:34336
    BRANCH=none
    TEST=build ryu and test dev/rec mode, also build rush ok
    
    Change-Id: I8a310e188fae70d7726c4360894b392c4546e105
    Signed-off-by: Stefan Reinauer <reinauer at chromium.org>
    Original-Commit-Id: a7ab7225e3419a0fd93894dbb9a959390f29945b
    Original-Change-Id: Id14cbd89457cb91c23526927a432f4eb7cc6291b
    Original-Signed-off-by: Jimmy Zhang <jimmzhang at nvidia.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/234270
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
---
 src/mainboard/google/rush_ryu/devicetree.cb   |   2 +
 src/soc/nvidia/tegra/dc.h                     |   3 +
 src/soc/nvidia/tegra132/Makefile.inc          |   4 +-
 src/soc/nvidia/tegra132/chip.h                |   2 +
 src/soc/nvidia/tegra132/dc.c                  | 223 ++++++
 src/soc/nvidia/tegra132/display.c             | 329 ---------
 src/soc/nvidia/tegra132/dsi.c                 | 970 ++++++++++++++++++++++++++
 src/soc/nvidia/tegra132/include/soc/display.h |  12 +-
 src/soc/nvidia/tegra132/tegra_dsi.c           | 874 -----------------------
 9 files changed, 1210 insertions(+), 1209 deletions(-)

diff --git a/src/mainboard/google/rush_ryu/devicetree.cb b/src/mainboard/google/rush_ryu/devicetree.cb
index b5c9981..f621e00 100644
--- a/src/mainboard/google/rush_ryu/devicetree.cb
+++ b/src/mainboard/google/rush_ryu/devicetree.cb
@@ -50,4 +50,6 @@ chip soc/nvidia/tegra132
 
 	# kernel driver
 	register "pixel_clock" = "301620000"
+
+	register "win_opt" = "DSI_ENABLE"
 end
diff --git a/src/soc/nvidia/tegra/dc.h b/src/soc/nvidia/tegra/dc.h
index 71c3881..ffdc773 100644
--- a/src/soc/nvidia/tegra/dc.h
+++ b/src/soc/nvidia/tegra/dc.h
@@ -25,6 +25,7 @@
 #ifndef __SOC_NVIDIA_TEGRA_DC_H
 #define __SOC_NVIDIA_TEGRA_DC_H
 #include <stddef.h>
+#include <device/device.h>
 
 /* Register definitions for the Tegra display controller */
 
@@ -502,7 +503,9 @@ struct tegra_dc {
 unsigned long READL(void * p);
 void WRITEL(unsigned long value, void * p);
 
+#ifndef __PRE_RAM__
 void display_startup(device_t dev);
+#endif
 void dp_init(void * _config);
 void dp_enable(void * _dp);
 unsigned int fb_base_mb(void);
diff --git a/src/soc/nvidia/tegra132/Makefile.inc b/src/soc/nvidia/tegra132/Makefile.inc
index fc22b2a..9d4c33d 100644
--- a/src/soc/nvidia/tegra132/Makefile.inc
+++ b/src/soc/nvidia/tegra132/Makefile.inc
@@ -66,8 +66,8 @@ ramstage-y += cbmem.c
 ramstage-y += cpu.c
 ramstage-y += cpu_lib.S
 ramstage-y += clock.c
-ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display.c
-ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += tegra_dsi.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += dc.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += dsi.c
 ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += mipi_dsi.c
 ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += mipi.c
 ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += mipi-phy.c
diff --git a/src/soc/nvidia/tegra132/chip.h b/src/soc/nvidia/tegra132/chip.h
index 2468870..fbbef50 100644
--- a/src/soc/nvidia/tegra132/chip.h
+++ b/src/soc/nvidia/tegra132/chip.h
@@ -21,6 +21,7 @@
 #define __SOC_NVIDIA_TEGRA132_CHIP_H__
 #include <soc/addressmap.h>
 #include <stdint.h>
+#include <soc/nvidia/tegra/dc.h>
 
 struct soc_nvidia_tegra132_config {
 	/* Address to monitor if spintable employed. */
@@ -68,6 +69,7 @@ struct soc_nvidia_tegra132_config {
 	int refresh;		/* display refresh rate */
 
 	int pixel_clock;	/* dc pixel clock source rate */
+	int win_opt;
 };
 
 #endif /* __SOC_NVIDIA_TEGRA132_CHIP_H__ */
diff --git a/src/soc/nvidia/tegra132/dc.c b/src/soc/nvidia/tegra132/dc.c
new file mode 100644
index 0000000..e5ab23a
--- /dev/null
+++ b/src/soc/nvidia/tegra132/dc.c
@@ -0,0 +1,223 @@
+/*
+ * 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 <stdlib.h>
+#include <device/device.h>
+#include <soc/nvidia/tegra/dc.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,
+			"Panel Mode: %dx%d@%d.%03uHz pclk=%d\n",
+			config->xres, config->yres,
+			refresh / 1000, refresh % 1000,
+			config->pixel_clock);
+	}
+}
+
+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 win opt */
+	WRITEL(config->win_opt, &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_configure_plld(), 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.
+ */
+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->display_yres << 16) |
+		(config->display_xres *
+		config->framebuffer_bits_per_pixel / 8)),
+		&disp_ctrl->win.prescaled_size);
+
+	val = ALIGN_UP((config->display_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(((DDA_INC(config->display_yres, config->yres) << 16) |
+		DDA_INC(config->display_xres, config->xres)),
+		&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);
+}
+
+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;
+}
diff --git a/src/soc/nvidia/tegra132/display.c b/src/soc/nvidia/tegra132/display.c
deleted file mode 100644
index d616b73..0000000
--- a/src/soc/nvidia/tegra132/display.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * 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 <edid.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,
-			"Panel 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_configure_plld(), 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->display_yres << 16) |
-		(config->display_xres *
-		config->framebuffer_bits_per_pixel / 8)),
-		&disp_ctrl->win.prescaled_size);
-
-	val = ALIGN_UP((config->display_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(((DDA_INC(config->display_yres, config->yres) << 16) |
-		DDA_INC(config->display_xres, config->xres)),
-		&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->display_xres *
-			config->display_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_configure_plld(config->pixel_clock * 2);
-	if (plld_rate == 0) {
-		printk(BIOS_ERR, "dc: clock init failed\n");
-		return;
-	}
-
-	/* 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__);
-
-	/*
-	 * Pass panel information to cb tables
-	 */
-	struct edid edid;
-	/* Align bytes_per_line to 64 bytes as required by dc */
-	edid.bytes_per_line = ALIGN_UP((config->display_xres *
-				config->framebuffer_bits_per_pixel / 8), 64);
-	edid.x_resolution = edid.bytes_per_line /
-				(config->framebuffer_bits_per_pixel / 8);
-	edid.y_resolution = config->display_yres;
-	edid.framebuffer_bits_per_pixel = config->framebuffer_bits_per_pixel;
-
-	printk(BIOS_INFO, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
-			"               x_res x y_res: %d x %d, size: %d\n",
-			 __func__, edid.bytes_per_line,
-			edid.framebuffer_bits_per_pixel,
-			edid.x_resolution, edid.y_resolution,
-			(edid.bytes_per_line * edid.y_resolution));
-
-	set_vbe_mode_info_valid(&edid, 0);
-
-	/*
-	 * After this point, it is payload's responsibility to allocate
-	 * framebuffer and sets the base address to dc's
-	 * WINBUF_START_ADDR register and enables window by setting dc's
-	 * DISP_DISP_WIN_OPTIONS register.
-	 */
-}
-
diff --git a/src/soc/nvidia/tegra132/dsi.c b/src/soc/nvidia/tegra132/dsi.c
new file mode 100644
index 0000000..cfeb7fd
--- /dev/null
+++ b/src/soc/nvidia/tegra132/dsi.c
@@ -0,0 +1,970 @@
+/*
+ * 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 <edid.h>
+#include <soc/nvidia/tegra/types.h>
+#include <soc/nvidia/tegra/dc.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_configure_plld(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;
+}
+
+static 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;
+}
+
+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->display_xres *
+			config->display_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_configure_plld(config->pixel_clock * 2);
+	if (plld_rate == 0) {
+		printk(BIOS_ERR, "dc: clock init failed\n");
+		return;
+	}
+
+	/* 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__);
+
+	/*
+	 * Pass panel information to cb tables
+	 */
+	struct edid edid;
+	/* Align bytes_per_line to 64 bytes as required by dc */
+	edid.bytes_per_line = ALIGN_UP((config->display_xres *
+				config->framebuffer_bits_per_pixel / 8), 64);
+	edid.x_resolution = edid.bytes_per_line /
+				(config->framebuffer_bits_per_pixel / 8);
+	edid.y_resolution = config->display_yres;
+	edid.framebuffer_bits_per_pixel = config->framebuffer_bits_per_pixel;
+
+	printk(BIOS_INFO, "%s: bytes_per_line: %d, bits_per_pixel: %d\n "
+			"               x_res x y_res: %d x %d, size: %d\n",
+			 __func__, edid.bytes_per_line,
+			edid.framebuffer_bits_per_pixel,
+			edid.x_resolution, edid.y_resolution,
+			(edid.bytes_per_line * edid.y_resolution));
+
+	set_vbe_mode_info_valid(&edid, 0);
+
+	/*
+	 * After this point, it is payload's responsibility to allocate
+	 * framebuffer and sets the base address to dc's
+	 * WINBUF_START_ADDR register and enables window by setting dc's
+	 * DISP_DISP_WIN_OPTIONS register.
+	 */
+}
diff --git a/src/soc/nvidia/tegra132/include/soc/display.h b/src/soc/nvidia/tegra132/include/soc/display.h
index 3378a4f..b0f2573 100644
--- a/src/soc/nvidia/tegra132/include/soc/display.h
+++ b/src/soc/nvidia/tegra132/include/soc/display.h
@@ -34,8 +34,12 @@
 	(mode->yres + mode->vfront_porch + \
 	mode->vsync_width + mode->vback_porch)
 
-struct soc_nvidia_tegra132_config;	/* forward declaration */
-
-int dsi_enable(struct soc_nvidia_tegra132_config *config);
-
+/* forward declaration */
+struct soc_nvidia_tegra132_config;
+struct display_controller;
+
+int tegra_dc_init(struct display_controller *disp_ctrl);
+int update_display_mode(struct display_controller *disp_ctrl,
+			struct soc_nvidia_tegra132_config *config);
+void update_window(const struct soc_nvidia_tegra132_config *config);
 #endif /* __SOC_NVIDIA_TEGRA132_INCLUDE_SOC_DISPLAY_H__ */
diff --git a/src/soc/nvidia/tegra132/tegra_dsi.c b/src/soc/nvidia/tegra132/tegra_dsi.c
deleted file mode 100644
index f1e7c9f..0000000
--- a/src/soc/nvidia/tegra132/tegra_dsi.c
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * 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_configure_plld(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