* [PATCH] video: tegra: add tegra display controller and fb driver
@ 2010-08-11 23:11 Erik Gilling
2010-08-12 4:34 ` Ryan Mallon
2010-08-25 22:04 ` Erik Gilling
0 siblings, 2 replies; 6+ messages in thread
From: Erik Gilling @ 2010-08-11 23:11 UTC (permalink / raw)
To: linux-arm-kernel
This patch supersedes the previous framebuffer patch
Supports:
* panel setup
* overlays
* suspend / resume
Notable ommisions:
* support for anything but lvds panels
* inegration with nvhost driver to sync updates with 3D
* FB physical geometry is not set
* lacks interface to set overlay/window x,y offset
Signed-off-by: Erik Gilling <konkers@android.com>
Cc: Colin Cross <ccross@android.com>
Cc: Travis Geiselbrecht <travis@palm.com>
---
arch/arm/mach-tegra/include/mach/dc.h | 152 ++++++
arch/arm/mach-tegra/include/mach/fb.h | 44 ++
drivers/video/Kconfig | 1 +
drivers/video/Makefile | 1 +
drivers/video/tegra/Kconfig | 15 +
drivers/video/tegra/Makefile | 2 +
drivers/video/tegra/dc/Makefile | 2 +
drivers/video/tegra/dc/dc.c | 894 +++++++++++++++++++++++++++++++++
drivers/video/tegra/dc/dc_priv.h | 86 ++++
drivers/video/tegra/dc/dc_reg.h | 342 +++++++++++++
drivers/video/tegra/dc/rgb.c | 63 +++
drivers/video/tegra/fb.c | 311 ++++++++++++
12 files changed, 1913 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-tegra/include/mach/dc.h
create mode 100644 arch/arm/mach-tegra/include/mach/fb.h
create mode 100644 drivers/video/tegra/Kconfig
create mode 100644 drivers/video/tegra/Makefile
create mode 100644 drivers/video/tegra/dc/Makefile
create mode 100644 drivers/video/tegra/dc/dc.c
create mode 100644 drivers/video/tegra/dc/dc_priv.h
create mode 100644 drivers/video/tegra/dc/dc_reg.h
create mode 100644 drivers/video/tegra/dc/rgb.c
create mode 100644 drivers/video/tegra/fb.c
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
new file mode 100644
index 0000000..b8a0e7a
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -0,0 +1,152 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dc.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Erik Gilling <konkers@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_DC_H
+#define __MACH_TEGRA_DC_H
+
+
+#define TEGRA_MAX_DC 2
+#define DC_N_WINDOWS 3
+
+struct tegra_dc_blend {
+ u32 nokey;
+ u32 one_win;
+ u32 two_win_x;
+ u32 two_win_y;
+ u32 three_win_xy;
+};
+
+#define BLEND(key, control, weight0, weight1) \
+ (CKEY_ ## key | BLEND_CONTROL_ ## control | \
+ BLEND_WEIGHT0(weight0) | BLEND_WEIGHT0(weight1))
+
+struct tegra_dc_mode {
+ int pclk;
+ int h_ref_to_sync;
+ int v_ref_to_sync;
+ int h_sync_width;
+ int v_sync_width;
+ int h_back_porch;
+ int v_back_porch;
+ int h_active;
+ int v_active;
+ int h_front_porch;
+ int v_front_porch;
+};
+
+enum {
+ TEGRA_DC_OUT_RGB,
+};
+
+struct tegra_dc_out {
+ int type;
+
+ unsigned order;
+ unsigned align;
+
+ struct tegra_dc_mode *modes;
+ int n_modes;
+};
+
+#define TEGRA_DC_ALIGN_MSB 0
+#define TEGRA_DC_ALIGN_LSB 1
+
+#define TEGRA_DC_ORDER_RED_BLUE 0
+#define TEGRA_DC_ORDER_BLUE_RED 1
+
+struct tegra_dc;
+
+struct tegra_dc_win {
+ u8 idx;
+ u8 fmt;
+ u32 flags;
+
+ void *virt_addr;
+ dma_addr_t phys_addr;
+ unsigned x;
+ unsigned y;
+ unsigned w;
+ unsigned h;
+ unsigned out_w;
+ unsigned out_h;
+
+ int dirty;
+ struct tegra_dc *dc;
+};
+
+#define TEGRA_WIN_FLAG_ENABLED (1 << 0)
+#define TEGRA_WIN_FLAG_COLOR_EXPAND (1 << 1)
+
+/* Note: These are the actual values written to the DC_WIN_COLOR_DEPTH register
+ * and may change in new tegra architectures.
+ */
+#define TEGRA_WIN_FMT_P1 0
+#define TEGRA_WIN_FMT_P2 1
+#define TEGRA_WIN_FMT_P4 2
+#define TEGRA_WIN_FMT_P8 3
+#define TEGRA_WIN_FMT_B4G4R4A4 4
+#define TEGRA_WIN_FMT_B5G5R5A 5
+#define TEGRA_WIN_FMT_B5G6R5 6
+#define TEGRA_WIN_FMT_AB5G5R5 7
+#define TEGRA_WIN_FMT_B8G8R8A8 12
+#define TEGRA_WIN_FMT_R8G8B8A8 13
+#define TEGRA_WIN_FMT_B6x2G6x2R6x2A8 14
+#define TEGRA_WIN_FMT_R6x2G6x2B6x2A8 15
+#define TEGRA_WIN_FMT_YCbCr422 16
+#define TEGRA_WIN_FMT_YUV422 17
+#define TEGRA_WIN_FMT_YCbCr420P 18
+#define TEGRA_WIN_FMT_YUV420P 19
+#define TEGRA_WIN_FMT_YCbCr422P 20
+#define TEGRA_WIN_FMT_YUV422P 21
+#define TEGRA_WIN_FMT_YCbCr422R 22
+#define TEGRA_WIN_FMT_YUV422R 23
+#define TEGRA_WIN_FMT_YCbCr422RA 24
+#define TEGRA_WIN_FMT_YUV422RA 25
+
+struct tegra_fb_data {
+ int win;
+
+ int xres;
+ int yres;
+ int bits_per_pixel;
+};
+
+struct tegra_dc_platform_data {
+ unsigned long flags;
+ struct tegra_dc_out *default_out;
+ struct tegra_fb_data *fb;
+};
+
+#define TEGRA_DC_FLAG_ENABLED (1 << 0)
+
+struct tegra_dc *tegra_dc_get_dc(unsigned idx);
+struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win);
+
+/* tegra_dc_update_windows and tegra_dc_sync_windows do not support windows
+ * with differenct dcs in one call
+ */
+int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n);
+int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
+
+/* will probably be replaced with an interface describing the window order */
+void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend);
+
+int tegra_dc_set_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode);
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/fb.h b/arch/arm/mach-tegra/include/mach/fb.h
new file mode 100644
index 0000000..9e5f7f8
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/fb.h
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/mach-tegra/include/mach/fb.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Erik Gilling <konkers@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_FB_H
+#define __MACH_TEGRA_FB_H
+
+#ifdef CONFIG_FB_TEGRA
+struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
+ struct tegra_dc *dc,
+ struct tegra_fb_data *fb_data,
+ struct resource *fb_mem);
+void tegra_fb_unregister(struct tegra_fb_info *fb_info);
+#else
+static inline
+struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
+ struct tegra_dc *dc,
+ struct tegra_fb_data *fb_data,
+ struct resource *fb_mem)
+{
+ return NULL;
+}
+
+static inline void tegra_fb_unregister(struct tegra_fb_info *fb_info)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3d94a14..1eb0ac1 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2231,6 +2231,7 @@ config FB_BROADSHEET
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
+source "drivers/video/tegra/Kconfig"
source "drivers/video/backlight/Kconfig"
source "drivers/video/display/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ddc2af2..21b527d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -131,6 +131,7 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
+obj-y += tegra/
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
new file mode 100644
index 0000000..b01dc95
--- /dev/null
+++ b/drivers/video/tegra/Kconfig
@@ -0,0 +1,15 @@
+config TEGRA_DC
+ tristate "Tegra Display Contoller"
+ depends on ARCH_TEGRA
+ help
+ Tegra display controller support.
+
+config FB_TEGRA
+ tristate "Tegra Framebuffer driver"
+ depends on TEGRA_DC && FB = y
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ default FB
+ help
+ Framebuffer device support for the Tegra display controller.
diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile
new file mode 100644
index 0000000..8f9d0e2
--- /dev/null
+++ b/drivers/video/tegra/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TEGRA_DC) += dc/
+obj-$(CONFIG_FB_TEGRA) += fb.o
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
new file mode 100644
index 0000000..3ecb63c
--- /dev/null
+++ b/drivers/video/tegra/dc/Makefile
@@ -0,0 +1,2 @@
+obj-y += dc.o
+obj-y += rgb.o
\ No newline at end of file
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
new file mode 100644
index 0000000..261bced
--- /dev/null
+++ b/drivers/video/tegra/dc/dc.c
@@ -0,0 +1,894 @@
+/*
+ * drivers/video/tegra/dc/dc.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+#include <mach/fb.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+struct tegra_dc_blend tegra_dc_blend_modes[][DC_N_WINDOWS] = {
+ {{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .two_win_x = BLEND(NOKEY, FIX, 0x00, 0x00),
+ .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
+ .three_win_xy = BLEND(NOKEY, FIX, 0x00, 0x00)},
+ {.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .two_win_x = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
+ .three_win_xy = BLEND(NOKEY, DEPENDANT, 0x00, 0x00)},
+ {.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
+ .two_win_x = BLEND(NOKEY, ALPHA, 0xff, 0xff),
+ .two_win_y = BLEND(NOKEY, ALPHA, 0xff, 0xff),
+ .three_win_xy = BLEND(NOKEY, ALPHA, 0xff, 0xff)}
+ }
+};
+
+struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
+
+DEFINE_MUTEX(tegra_dc_lock);
+
+static inline int tegra_dc_fmt_bpp(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_P1:
+ return 1;
+
+ case TEGRA_WIN_FMT_P2:
+ return 2;
+
+ case TEGRA_WIN_FMT_P4:
+ return 4;
+
+ case TEGRA_WIN_FMT_P8:
+ return 8;
+
+ case TEGRA_WIN_FMT_B4G4R4A4:
+ case TEGRA_WIN_FMT_B5G5R5A:
+ case TEGRA_WIN_FMT_B5G6R5:
+ case TEGRA_WIN_FMT_AB5G5R5:
+ return 16;
+
+ case TEGRA_WIN_FMT_B8G8R8A8:
+ case TEGRA_WIN_FMT_R8G8B8A8:
+ case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
+ case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
+ return 32;
+
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ /* FIXME: need to know the bpp of these formats */
+ return 0;
+ }
+ return 0;
+}
+
+#define DUMP_REG(a) do { \
+ snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
+ #a, a, tegra_dc_readl(dc, a)); \
+ print(data, buff); \
+ } while (0)
+
+static void _dump_regs(struct tegra_dc *dc, void *data,
+ void (* print)(void *data, const char *str))
+{
+ int i;
+ char buff[256];
+
+ DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
+ DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
+ DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT);
+ DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR);
+ DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT);
+ DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR);
+ DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT);
+ DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL);
+ DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR);
+ DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC);
+ DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
+ DUMP_REG(DC_CMD_DISPLAY_COMMAND);
+ DUMP_REG(DC_CMD_SIGNAL_RAISE);
+ DUMP_REG(DC_CMD_INT_STATUS);
+ DUMP_REG(DC_CMD_INT_MASK);
+ DUMP_REG(DC_CMD_INT_ENABLE);
+ DUMP_REG(DC_CMD_INT_TYPE);
+ DUMP_REG(DC_CMD_INT_POLARITY);
+ DUMP_REG(DC_CMD_SIGNAL_RAISE1);
+ DUMP_REG(DC_CMD_SIGNAL_RAISE2);
+ DUMP_REG(DC_CMD_SIGNAL_RAISE3);
+ DUMP_REG(DC_CMD_STATE_ACCESS);
+ DUMP_REG(DC_CMD_STATE_CONTROL);
+ DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
+ DUMP_REG(DC_CMD_REG_ACT_CONTROL);
+
+ DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
+ DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
+ DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
+ DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY);
+ DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER);
+ DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
+ DUMP_REG(DC_DISP_REF_TO_SYNC);
+ DUMP_REG(DC_DISP_SYNC_WIDTH);
+ DUMP_REG(DC_DISP_BACK_PORCH);
+ DUMP_REG(DC_DISP_DISP_ACTIVE);
+ DUMP_REG(DC_DISP_FRONT_PORCH);
+ DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
+ DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
+ DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
+ DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
+ DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
+ DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
+ DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
+ DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
+ DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
+ DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
+ DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
+ DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
+ DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
+ DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
+ DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
+ DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
+ DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
+ DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
+ DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
+ DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
+ DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
+ DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
+ DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
+ DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
+ DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
+ DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
+ DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
+ DUMP_REG(DC_DISP_M0_CONTROL);
+ DUMP_REG(DC_DISP_M1_CONTROL);
+ DUMP_REG(DC_DISP_DI_CONTROL);
+ DUMP_REG(DC_DISP_PP_CONTROL);
+ DUMP_REG(DC_DISP_PP_SELECT_A);
+ DUMP_REG(DC_DISP_PP_SELECT_B);
+ DUMP_REG(DC_DISP_PP_SELECT_C);
+ DUMP_REG(DC_DISP_PP_SELECT_D);
+ DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
+ DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
+ DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
+ DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
+ DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
+ DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
+ DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
+ DUMP_REG(DC_DISP_BORDER_COLOR);
+ DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
+ DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
+ DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
+ DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
+ DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
+ DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
+ DUMP_REG(DC_DISP_CURSOR_START_ADDR);
+ DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
+ DUMP_REG(DC_DISP_CURSOR_POSITION);
+ DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
+ DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
+ DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
+ DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
+ DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
+ DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
+ DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
+ DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
+ DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
+ DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST);
+ DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
+ DUMP_REG(DC_DISP_DAC_CRT_CTRL);
+ DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
+
+
+ for (i = 0; i < 3; i++) {
+ print(data, "\n");
+ snprintf(buff, sizeof(buff), "WINDOW %c:\n", 'A' + i);
+ print(data, buff);
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << i,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+ DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
+ DUMP_REG(DC_WIN_WIN_OPTIONS);
+ DUMP_REG(DC_WIN_BYTE_SWAP);
+ DUMP_REG(DC_WIN_BUFFER_CONTROL);
+ DUMP_REG(DC_WIN_COLOR_DEPTH);
+ DUMP_REG(DC_WIN_POSITION);
+ DUMP_REG(DC_WIN_SIZE);
+ DUMP_REG(DC_WIN_PRESCALED_SIZE);
+ DUMP_REG(DC_WIN_H_INITIAL_DDA);
+ DUMP_REG(DC_WIN_V_INITIAL_DDA);
+ DUMP_REG(DC_WIN_DDA_INCREMENT);
+ DUMP_REG(DC_WIN_LINE_STRIDE);
+ DUMP_REG(DC_WIN_BUF_STRIDE);
+ DUMP_REG(DC_WIN_BLEND_NOKEY);
+ DUMP_REG(DC_WIN_BLEND_1WIN);
+ DUMP_REG(DC_WIN_BLEND_2WIN_X);
+ DUMP_REG(DC_WIN_BLEND_2WIN_Y);
+ DUMP_REG(DC_WIN_BLEND_3WIN_XY);
+ DUMP_REG(DC_WINBUF_START_ADDR);
+ DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
+ DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
+ }
+}
+
+#undef DUMP_REG
+
+#ifdef DEBUG
+static void dump_regs_print(void *data, const char *str)
+{
+ struct tegra_dc *dc = data;
+ dev_dbg(&dc->pdev->dev, "%s", str);
+}
+
+static void dump_regs(struct tegra_dc *dc)
+{
+ _dump_regs(dc, dc, dump_regs_print);
+}
+#else
+
+static void dump_regs(struct tegra_dc *dc) {}
+
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+
+static void dbg_regs_print(void *data, const char *str)
+{
+ struct seq_file *s = data;
+
+ seq_printf(s, "%s", str);
+}
+
+#undef DUMP_REG
+
+static int dbg_dc_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+
+ _dump_regs(dc, s, dbg_regs_print);
+
+ return 0;
+}
+
+
+static int dbg_dc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_dc_show, inode->i_private);
+}
+
+static const struct file_operations dbg_fops = {
+ .open = dbg_dc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void tegra_dc_dbg_add(struct tegra_dc *dc)
+{
+ char name[32];
+
+ snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->pdev->id);
+ (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops);
+}
+#else
+static void tegra_dc_dbg_add(struct tegra_dc *dc) {}
+
+#endif
+
+
+static int tegra_dc_add(struct tegra_dc *dc, int index)
+{
+ int ret = 0;
+
+ mutex_lock(&tegra_dc_lock);
+ if (index >= TEGRA_MAX_DC) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (tegra_dcs[index] != NULL) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ tegra_dcs[index] = dc;
+
+out:
+ mutex_unlock(&tegra_dc_lock);
+
+ return ret;
+}
+
+struct tegra_dc *tegra_dc_get_dc(unsigned idx)
+{
+ if (idx < TEGRA_MAX_DC)
+ return tegra_dcs[idx];
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(tegra_dc_get_dc);
+
+struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
+{
+ if (win >= dc->n_windows)
+ return NULL;
+
+ return &dc->windows[win];
+}
+EXPORT_SYMBOL(tegra_dc_get_window);
+
+/* does not support updating windows on multiple dcs in one call */
+int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
+{
+ struct tegra_dc *dc;
+ unsigned long update_mask = GENERAL_ACT_REQ;
+ unsigned long val;
+ unsigned long flags;
+ int i;
+
+ dc = windows[0]->dc;
+
+ spin_lock_irqsave(&dc->lock, flags);
+ for (i = 0; i < n; i++) {
+ struct tegra_dc_win *win = windows[i];
+ unsigned h_dda;
+ unsigned v_dda;
+ unsigned stride;
+
+ tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ update_mask |= WIN_A_ACT_REQ << win->idx;
+
+ if (!(win->flags & TEGRA_WIN_FLAG_ENABLED)) {
+ tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
+ continue;
+ }
+
+ tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
+ tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
+
+ stride = win->w * tegra_dc_fmt_bpp(win->fmt) / 8;
+
+ /* TODO: implement filter on settings */
+ h_dda = (win->w * 0x1000) / (win->out_w - 1);
+ v_dda = (win->h * 0x1000) / (win->out_h - 1);
+
+ tegra_dc_writel(dc,
+ V_POSITION(win->y) | H_POSITION(win->x),
+ DC_WIN_POSITION);
+ tegra_dc_writel(dc,
+ V_SIZE(win->out_h) | H_SIZE(win->out_w),
+ DC_WIN_SIZE);
+ tegra_dc_writel(dc,
+ V_PRESCALED_SIZE(win->out_h) |
+ H_PRESCALED_SIZE(stride),
+ DC_WIN_PRESCALED_SIZE);
+ tegra_dc_writel(dc, 0, DC_WIN_H_INITIAL_DDA);
+ tegra_dc_writel(dc, 0, DC_WIN_V_INITIAL_DDA);
+ tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
+ DC_WIN_DDA_INCREMENT);
+ tegra_dc_writel(dc, stride, DC_WIN_LINE_STRIDE);
+ tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
+
+ val = WIN_ENABLE;
+ if (win->flags & TEGRA_WIN_FLAG_COLOR_EXPAND)
+ val |= COLOR_EXPAND;
+ tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
+
+ tegra_dc_writel(dc, (unsigned long)win->phys_addr,
+ DC_WINBUF_START_ADDR);
+ tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_H_OFFSET);
+ tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_V_OFFSET);
+
+ win->dirty = 1;
+
+ }
+
+ tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
+
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ val |= FRAME_END_INT;
+ tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+
+ val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
+ val |= FRAME_END_INT;
+ tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
+
+ tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+ spin_unlock_irqrestore(&dc->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_update_windows);
+
+static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (windows[i]->dirty)
+ return false;
+ }
+
+ return true;
+}
+
+/* does not support syncing windows on multiple dcs in one call */
+int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
+{
+ if (n < 1 || n > DC_N_WINDOWS)
+ return -EINVAL;
+
+ return wait_event_interruptible_timeout(windows[0]->dc->wq,
+ tegra_dc_windows_are_clean(windows, n),
+ HZ);
+}
+EXPORT_SYMBOL(tegra_dc_sync_windows);
+
+void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
+{
+ int i;
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ tegra_dc_writel(dc, WINDOW_A_SELECT << i,
+ DC_CMD_DISPLAY_WINDOW_HEADER);
+ tegra_dc_writel(dc, blend[i].nokey, DC_WIN_BLEND_NOKEY);
+ tegra_dc_writel(dc, blend[i].one_win, DC_WIN_BLEND_1WIN);
+ tegra_dc_writel(dc, blend[i].two_win_x, DC_WIN_BLEND_2WIN_X);
+ tegra_dc_writel(dc, blend[i].two_win_y, DC_WIN_BLEND_2WIN_Y);
+ tegra_dc_writel(dc, blend[i].three_win_xy,
+ DC_WIN_BLEND_3WIN_XY);
+ }
+}
+EXPORT_SYMBOL(tegra_dc_set_blending);
+
+int tegra_dc_set_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
+{
+ unsigned long val;
+ unsigned long rate;
+ unsigned long div;
+
+ tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
+ tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
+ DC_DISP_REF_TO_SYNC);
+ tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
+ DC_DISP_SYNC_WIDTH);
+ tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
+ DC_DISP_BACK_PORCH);
+ tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
+ DC_DISP_DISP_ACTIVE);
+ tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
+ DC_DISP_FRONT_PORCH);
+
+ tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
+ DC_DISP_DATA_ENABLE_OPTIONS);
+
+ /* TODO: MIPI/CRT/HDMI clock cals */
+
+ val = DISP_DATA_FORMAT_DF1P1C;
+
+ if (dc->out->align == TEGRA_DC_ALIGN_MSB)
+ val |= DISP_DATA_ALIGNMENT_MSB;
+ else
+ val |= DISP_DATA_ALIGNMENT_LSB;
+
+ if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
+ val |= DISP_DATA_ORDER_RED_BLUE;
+ else
+ val |= DISP_DATA_ORDER_BLUE_RED;
+
+ tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
+
+ rate = clk_get_rate(dc->clk);
+
+ div = ((rate * 2 + mode->pclk / 2) / mode->pclk) - 2;
+
+ if (rate * 2 / (div + 2) < (mode->pclk / 100 * 99) ||
+ rate * 2 / (div + 2) > (mode->pclk / 100 * 109)) {
+ dev_err(&dc->pdev->dev,
+ "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
+ rate, mode->pclk,
+ rate / div, (mode->pclk / 100 * 99),
+ (mode->pclk / 100 * 109));
+ return -EINVAL;
+ }
+
+ tegra_dc_writel(dc, 0x00010001,
+ DC_DISP_SHIFT_CLOCK_OPTIONS);
+ tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
+ DC_DISP_DISP_CLOCK_CONTROL);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_set_mode);
+
+static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
+{
+ dc->out = out;
+
+ if (out->n_modes > 0)
+ dc->mode = &dc->out->modes[0];
+ else
+ dev_err(&dc->pdev->dev,
+ "No default modes specified. Leaving output disabled.\n");
+
+ switch (out->type) {
+ case TEGRA_DC_OUT_RGB:
+ dc->out_ops = &tegra_dc_rgb_ops;
+ break;
+
+ default:
+ dc->out_ops = NULL;
+ break;
+ }
+}
+
+
+static irqreturn_t tegra_dc_irq(int irq, void *ptr)
+{
+ struct tegra_dc *dc = ptr;
+ unsigned long status;
+ unsigned long flags;
+ unsigned long val;
+ int i;
+
+
+ status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
+ tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
+
+ if (status & FRAME_END_INT) {
+ int completed = 0;
+ int dirty = 0;
+
+ spin_lock_irqsave(&dc->lock, flags);
+ val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ if (!(val & (WIN_A_ACT_REQ << i))) {
+ dc->windows[i].dirty = 0;
+ completed = 1;
+ } else {
+ dirty = 1;
+ }
+ }
+
+ if (!dirty) {
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ val &= ~FRAME_END_INT;
+ tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+ }
+
+ spin_unlock_irqrestore(&dc->lock, flags);
+
+ if (completed)
+ wake_up(&dc->wq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void tegra_dc_init(struct tegra_dc *dc)
+{
+ tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+ if (dc->pdev->id == 0)
+ tegra_dc_writel(dc, 0x0000011a, DC_CMD_CONT_SYNCPT_VSYNC);
+ else if (dc->pdev->id == 1)
+ tegra_dc_writel(dc, 0x0000011b, DC_CMD_CONT_SYNCPT_VSYNC);
+ tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE);
+ tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY);
+ tegra_dc_writel(dc, 0x00000020, DC_DISP_MEM_HIGH_PRIORITY);
+ tegra_dc_writel(dc, 0x00000001, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
+
+ tegra_dc_writel(dc, 0x0001c702, DC_CMD_INT_MASK);
+ tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_ENABLE);
+
+ if (dc->mode)
+ tegra_dc_set_mode(dc, dc->mode);
+
+
+ if (dc->out_ops && dc->out_ops->init)
+ dc->out_ops->init(dc);
+}
+
+static int tegra_dc_probe(struct platform_device *pdev)
+{
+ struct tegra_dc *dc;
+ struct clk *clk;
+ struct clk *host1x_clk;
+ struct resource *res;
+ struct resource *base_res;
+ struct resource *fb_mem = NULL;
+ int ret = 0;
+ void __iomem *base;
+ int irq;
+ int i;
+
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENOENT;
+ }
+
+ dc = kzalloc(sizeof(struct tegra_dc), GFP_KERNEL);
+ if (!dc) {
+ dev_err(&pdev->dev, "can't allocate memory for tegra_dc\n");
+ return -ENOMEM;
+ }
+
+ irq = platform_get_irq_byname(pdev, "irq");
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "no irq\n");
+ ret = -ENOENT;
+ goto err_free;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ ret = -ENOENT;
+ goto err_free;
+ }
+
+ base_res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!base_res) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "registers can't be mapped\n");
+ ret = -EBUSY;
+ goto err_release_resource_reg;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fbmem");
+ if (res)
+ fb_mem = request_mem_region(res->start, resource_size(res), pdev->name);
+
+ host1x_clk = clk_get(&pdev->dev, "host1x");
+ if (IS_ERR_OR_NULL(host1x_clk)) {
+ dev_err(&pdev->dev, "can't get host1x clock\n");
+ ret = -ENOENT;
+ goto err_iounmap_reg;
+ }
+ clk_enable(host1x_clk);
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR_OR_NULL(clk)) {
+ dev_err(&pdev->dev, "can't get clock\n");
+ ret = -ENOENT;
+
+ goto err_put_host1x_clk;
+ }
+ clk_enable(clk);
+ tegra_periph_reset_deassert(clk);
+
+ dc->clk = clk;
+ dc->host1x_clk = host1x_clk;
+ dc->base_res = base_res;
+ dc->base = base;
+ dc->irq = irq;
+ dc->pdev = pdev;
+ dc->pdata = pdev->dev.platform_data;
+ spin_lock_init(&dc->lock);
+ init_waitqueue_head(&dc->wq);
+
+
+ dc->n_windows = DC_N_WINDOWS;
+ for (i = 0; i < dc->n_windows; i++) {
+ dc->windows[i].idx = i;
+ dc->windows[i].dc = dc;
+ }
+
+ if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
+ dev_name(&pdev->dev), dc)) {
+ dev_err(&pdev->dev, "request_irq %d failed\n", irq);
+ ret = -EBUSY;
+ goto err_put_clk;
+ }
+
+ ret = tegra_dc_add(dc, pdev->id);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't add dc\n");
+ goto err_free_irq;
+ }
+
+ if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) {
+ if (dc->pdata->default_out)
+ tegra_dc_set_out(dc, dc->pdata->default_out);
+ else
+ dev_err(&pdev->dev, "No default output specified. Leaving output disabled.\n");
+ }
+
+ tegra_dc_init(dc);
+
+ tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
+
+ platform_set_drvdata(pdev, dc);
+
+ tegra_dc_dbg_add(dc);
+
+ dev_info(&pdev->dev, "probed\n");
+
+ if (fb_mem && dc->pdata->fb) {
+ dc->fb = tegra_fb_register(pdev, dc, dc->pdata->fb, fb_mem);
+ if (IS_ERR_OR_NULL(dc->fb))
+ dc->fb = NULL;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(irq, dc);
+err_put_clk:
+ clk_disable(clk);
+ clk_put(clk);
+err_put_host1x_clk:
+ clk_disable(host1x_clk);
+ clk_put(host1x_clk);
+err_iounmap_reg:
+ iounmap(base);
+ if (fb_mem)
+ release_resource(fb_mem);
+err_release_resource_reg:
+ release_resource(base_res);
+err_free:
+ kfree(dc);
+
+ return ret;
+}
+
+static int tegra_dc_remove(struct platform_device *pdev)
+{
+ struct tegra_dc *dc = platform_get_drvdata(pdev);
+
+ if (dc->fb) {
+ tegra_fb_unregister(dc->fb);
+ release_resource(dc->fb_mem);
+ }
+
+ free_irq(dc->irq, dc);
+ tegra_periph_reset_assert(dc->clk);
+ clk_disable(dc->clk);
+ clk_put(dc->clk);
+ clk_disable(dc->host1x_clk);
+ clk_put(dc->host1x_clk);
+ iounmap(dc->base);
+ release_resource(dc->base_res);
+ kfree(dc);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_dc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tegra_dc *dc = platform_get_drvdata(pdev);
+
+ dev_info(&pdev->dev, "suspend\n");
+
+ disable_irq(dc->irq);
+ tegra_periph_reset_assert(dc->clk);
+ clk_disable(dc->clk);
+
+ return 0;
+}
+
+static int tegra_dc_resume(struct platform_device *pdev)
+{
+ struct tegra_dc *dc = platform_get_drvdata(pdev);
+ struct tegra_dc_win *wins[DC_N_WINDOWS];
+ int i;
+
+ dev_info(&pdev->dev, "resume\n");
+
+ clk_enable(dc->clk);
+ tegra_periph_reset_deassert(dc->clk);
+ enable_irq(dc->irq);
+
+ for (i = 0; i < dc->n_windows; i++)
+ wins[i] = &dc->windows[i];
+
+ tegra_dc_init(dc);
+
+ tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
+ tegra_dc_update_windows(wins, dc->n_windows);
+
+ return 0;
+}
+
+#endif
+
+extern int suspend_set(const char *val, struct kernel_param *kp)
+{
+ if (!strcmp(val, "dump"))
+ dump_regs(tegra_dcs[0]);
+#ifdef CONFIG_PM
+ else if (!strcmp(val, "suspend"))
+ tegra_dc_suspend(tegra_dcs[0]->pdev, PMSG_SUSPEND);
+ else if (!strcmp(val, "resume"))
+ tegra_dc_resume(tegra_dcs[0]->pdev);
+#endif
+
+ return 0;
+}
+
+extern int suspend_get(char *buffer, struct kernel_param *kp)
+{
+ return 0;
+}
+
+int suspend;
+
+module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644);
+
+struct platform_driver tegra_dc_driver = {
+ .driver = {
+ .name = "tegradc",
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_dc_probe,
+ .remove = tegra_dc_remove,
+#ifdef CONFIG_PM
+ .suspend = tegra_dc_suspend,
+ .resume = tegra_dc_resume,
+#endif
+};
+
+static int __init tegra_dc_module_init(void)
+{
+ return platform_driver_register(&tegra_dc_driver);
+}
+
+static void __exit tegra_dc_module_exit(void)
+{
+ platform_driver_unregister(&tegra_dc_driver);
+}
+
+module_exit(tegra_dc_module_exit);
+module_init(tegra_dc_module_init);
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
new file mode 100644
index 0000000..b2351b1
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -0,0 +1,86 @@
+/*
+ * drivers/video/tegra/dc/dc_priv.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
+
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/io.h>
+
+struct tegra_dc;
+
+struct tegra_dc_out_ops {
+ void (*init)(struct tegra_dc *dc);
+};
+
+struct tegra_dc {
+ struct list_head list;
+
+ struct platform_device *pdev;
+ struct tegra_dc_platform_data *pdata;
+
+ struct resource *base_res;
+ void __iomem *base;
+ int irq;
+
+ struct clk *clk;
+ struct clk *host1x_clk;
+
+ struct tegra_dc_out *out;
+ struct tegra_dc_out_ops *out_ops;
+
+ struct tegra_dc_mode *mode;
+
+ struct tegra_dc_win windows[DC_N_WINDOWS];
+ int n_windows;
+
+ wait_queue_head_t wq;
+
+ spinlock_t lock;
+
+ struct resource *fb_mem;
+ struct tegra_fb_info *fb;
+};
+
+static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
+ unsigned long reg)
+{
+ return readl(dc->base + reg * 4);
+}
+
+static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
+ unsigned long reg)
+{
+ writel(val, dc->base + reg * 4);
+}
+
+static inline void _tegra_dc_write_table(struct tegra_dc *dc, const u32 *table,
+ unsigned len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ tegra_dc_writel(dc, table[i * 2 + 1], table[i * 2]);
+}
+
+#define tegra_dc_write_table(dc, table) \
+ _tegra_dc_write_table(dc, table, ARRAY_SIZE(table) / 2)
+
+extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
+
+#endif
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
new file mode 100644
index 0000000..6d6b3ba
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -0,0 +1,342 @@
+/*
+ * drivers/video/tegra/dc/dc_reg.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
+
+#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
+#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
+#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002
+#define DC_CMD_WIN_A_INCR_SYNCPT 0x008
+#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009
+#define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a
+#define DC_CMD_WIN_B_INCR_SYNCPT 0x010
+#define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011
+#define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012
+#define DC_CMD_WIN_C_INCR_SYNCPT 0x018
+#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019
+#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a
+#define DC_CMD_CONT_SYNCPT_VSYNC 0x028
+#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
+#define DC_CMD_DISPLAY_COMMAND 0x032
+#define DISP_COMMAND_RAISE (1 << 0)
+#define DISP_CTRL_MODE_STOP (0 << 5)
+#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
+#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
+#define DISP_COMMAND_RAISE_VECTOR(x) (((x) & 0x1f) << 22)
+#define DISP_COMMAND_RAISE_CHANNEL_ID(x) (((x) & 0xf) << 27)
+
+#define DC_CMD_SIGNAL_RAISE 0x033
+#define DC_CMD_DISPLAY_POWER_CONTROL 0x036
+#define PW0_ENABLE (1 << 0)
+#define PW1_ENABLE (1 << 2)
+#define PW2_ENABLE (1 << 4)
+#define PW3_ENABLE (1 << 6)
+#define PW4_ENABLE (1 << 8)
+#define PM0_ENABLE (1 << 16)
+#define PM1_ENABLE (1 << 18)
+#define SPI_ENABLE (1 << 24)
+#define HSPI_ENABLE (1 << 25)
+
+#define DC_CMD_INT_STATUS 0x037
+#define DC_CMD_INT_MASK 0x038
+#define DC_CMD_INT_ENABLE 0x039
+#define DC_CMD_INT_TYPE 0x03a
+#define DC_CMD_INT_POLARITY 0x03b
+#define CTXSW_INT (1 << 0)
+#define FRAME_END_INT (1 << 1)
+#define V_BLANK_INT (1 << 2)
+#define H_BLANK_INT (1 << 3)
+#define V_PULSE3_INT (1 << 4)
+#define SPI_BUSY_INT (1 << 7)
+#define WIN_A_UF_INT (1 << 8)
+#define WIN_B_UF_INT (1 << 9)
+#define WIN_C_UF_INT (1 << 10)
+#define MSF_INT (1 << 12)
+#define SSF_INT (1 << 13)
+#define WIN_A_OF_INT (1 << 14)
+#define WIN_B_OF_INT (1 << 15)
+#define WIN_C_OF_INT (1 << 16)
+#define GPIO_0_INT (1 << 18)
+#define GPIO_1_INT (1 << 19)
+#define GPIO_2_INT (1 << 20)
+
+#define DC_CMD_SIGNAL_RAISE1 0x03c
+#define DC_CMD_SIGNAL_RAISE2 0x03d
+#define DC_CMD_SIGNAL_RAISE3 0x03e
+#define DC_CMD_STATE_ACCESS 0x040
+#define DC_CMD_STATE_CONTROL 0x041
+#define GENERAL_ACT_REQ (1 << 0)
+#define WIN_A_ACT_REQ (1 << 1)
+#define WIN_B_ACT_REQ (1 << 2)
+#define WIN_C_ACT_REQ (1 << 3)
+
+#define DC_CMD_DISPLAY_WINDOW_HEADER 0x042
+#define WINDOW_A_SELECT (1 << 4)
+#define WINDOW_B_SELECT (1 << 5)
+#define WINDOW_C_SELECT (1 << 6)
+
+#define DC_CMD_REG_ACT_CONTROL 0x043
+
+#define DC_COM_CRC_CONTROL 0x300
+#define DC_COM_CRC_CHECKSUM 0x301
+#define DC_COM_PIN_OUTPUT_ENABLE0 0x302
+#define DC_COM_PIN_OUTPUT_ENABLE1 0x303
+#define DC_COM_PIN_OUTPUT_ENABLE2 0x304
+#define DC_COM_PIN_OUTPUT_ENABLE3 0x305
+#define DC_COM_PIN_OUTPUT_POLARITY0 0x306
+#define DC_COM_PIN_OUTPUT_POLARITY1 0x307
+#define DC_COM_PIN_OUTPUT_POLARITY2 0x308
+#define DC_COM_PIN_OUTPUT_POLARITY3 0x309
+#define DC_COM_PIN_OUTPUT_DATA0 0x30a
+#define DC_COM_PIN_OUTPUT_DATA1 0x30b
+#define DC_COM_PIN_OUTPUT_DATA2 0x30c
+#define DC_COM_PIN_OUTPUT_DATA3 0x30d
+#define DC_COM_PIN_INPUT_ENABLE0 0x30e
+#define DC_COM_PIN_INPUT_ENABLE1 0x30f
+#define DC_COM_PIN_INPUT_ENABLE2 0x310
+#define DC_COM_PIN_INPUT_ENABLE3 0x311
+#define DC_COM_PIN_INPUT_DATA0 0x312
+#define DC_COM_PIN_INPUT_DATA1 0x313
+#define DC_COM_PIN_OUTPUT_SELECT0 0x314
+#define DC_COM_PIN_OUTPUT_SELECT1 0x315
+#define DC_COM_PIN_OUTPUT_SELECT2 0x316
+#define DC_COM_PIN_OUTPUT_SELECT3 0x317
+#define DC_COM_PIN_OUTPUT_SELECT4 0x318
+#define DC_COM_PIN_OUTPUT_SELECT5 0x319
+#define DC_COM_PIN_OUTPUT_SELECT6 0x31a
+#define DC_COM_PIN_MISC_CONTROL 0x31b
+#define DC_COM_PM0_CONTROL 0x31c
+#define DC_COM_PM0_DUTY_CYCLE 0x31d
+#define DC_COM_PM1_CONTROL 0x31e
+#define DC_COM_PM1_DUTY_CYCLE 0x31f
+#define DC_COM_SPI_CONTROL 0x320
+#define DC_COM_SPI_START_BYTE 0x321
+#define DC_COM_HSPI_WRITE_DATA_AB 0x322
+#define DC_COM_HSPI_WRITE_DATA_CD 0x323
+#define DC_COM_HSPI_CS_DC 0x324
+#define DC_COM_SCRATCH_REGISTER_A 0x325
+#define DC_COM_SCRATCH_REGISTER_B 0x326
+#define DC_COM_GPIO_CTRL 0x327
+#define DC_COM_GPIO_DEBOUNCE_COUNTER 0x328
+#define DC_COM_CRC_CHECKSUM_LATCHED 0x329
+
+#define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400
+#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
+#define DC_DISP_DISP_WIN_OPTIONS 0x402
+#define DC_DISP_MEM_HIGH_PRIORITY 0x403
+#define DC_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
+#define DC_DISP_DISP_TIMING_OPTIONS 0x405
+#define DC_DISP_REF_TO_SYNC 0x406
+#define DC_DISP_SYNC_WIDTH 0x407
+#define DC_DISP_BACK_PORCH 0x408
+#define DC_DISP_DISP_ACTIVE 0x409
+#define DC_DISP_FRONT_PORCH 0x40a
+#define DC_DISP_H_PULSE0_CONTROL 0x40b
+#define DC_DISP_H_PULSE0_POSITION_A 0x40c
+#define DC_DISP_H_PULSE0_POSITION_B 0x40d
+#define DC_DISP_H_PULSE0_POSITION_C 0x40e
+#define DC_DISP_H_PULSE0_POSITION_D 0x40f
+#define DC_DISP_H_PULSE1_CONTROL 0x410
+#define DC_DISP_H_PULSE1_POSITION_A 0x411
+#define DC_DISP_H_PULSE1_POSITION_B 0x412
+#define DC_DISP_H_PULSE1_POSITION_C 0x413
+#define DC_DISP_H_PULSE1_POSITION_D 0x414
+#define DC_DISP_H_PULSE2_CONTROL 0x415
+#define DC_DISP_H_PULSE2_POSITION_A 0x416
+#define DC_DISP_H_PULSE2_POSITION_B 0x417
+#define DC_DISP_H_PULSE2_POSITION_C 0x418
+#define DC_DISP_H_PULSE2_POSITION_D 0x419
+#define DC_DISP_V_PULSE0_CONTROL 0x41a
+#define DC_DISP_V_PULSE0_POSITION_A 0x41b
+#define DC_DISP_V_PULSE0_POSITION_B 0x41c
+#define DC_DISP_V_PULSE0_POSITION_C 0x41d
+#define DC_DISP_V_PULSE1_CONTROL 0x41e
+#define DC_DISP_V_PULSE1_POSITION_A 0x41f
+#define DC_DISP_V_PULSE1_POSITION_B 0x420
+#define DC_DISP_V_PULSE1_POSITION_C 0x421
+#define DC_DISP_V_PULSE2_CONTROL 0x422
+#define DC_DISP_V_PULSE2_POSITION_A 0x423
+#define DC_DISP_V_PULSE3_CONTROL 0x424
+#define DC_DISP_V_PULSE3_POSITION_A 0x425
+#define DC_DISP_M0_CONTROL 0x426
+#define DC_DISP_M1_CONTROL 0x427
+#define DC_DISP_DI_CONTROL 0x428
+#define DC_DISP_PP_CONTROL 0x429
+#define DC_DISP_PP_SELECT_A 0x42a
+#define DC_DISP_PP_SELECT_B 0x42b
+#define DC_DISP_PP_SELECT_C 0x42c
+#define DC_DISP_PP_SELECT_D 0x42d
+#define DC_DISP_DISP_CLOCK_CONTROL 0x42e
+#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
+#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
+#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
+#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
+#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
+#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
+#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
+#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
+#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
+#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
+#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
+#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
+#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
+#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
+
+#define DC_DISP_DISP_INTERFACE_CONTROL 0x42f
+#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
+#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
+#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
+#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
+#define DISP_DATA_FORMAT_DF2S (5 << 0)
+#define DISP_DATA_FORMAT_DF3S (6 << 0)
+#define DISP_DATA_FORMAT_DFSPI (7 << 0)
+#define DISP_DATA_FORMAT_DF1P3C24B (8 << 0)
+#define DISP_DATA_FORMAT_DF1P3C18B (9 << 0)
+#define DISP_DATA_ALIGNMENT_MSB (0 << 8)
+#define DISP_DATA_ALIGNMENT_LSB (1 << 8)
+#define DISP_DATA_ORDER_RED_BLUE (0 << 9)
+#define DISP_DATA_ORDER_BLUE_RED (1 << 9)
+
+#define DC_DISP_DISP_COLOR_CONTROL 0x430
+#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
+#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
+#define DE_SELECT_ACTIVE_BLANK 0x0
+#define DE_SELECT_ACTIVE 0x1
+#define DE_SELECT_ACTIVE_IS 0x2
+#define DE_CONTROL_ONECLK (0 << 2)
+#define DE_CONTROL_NORMAL (1 << 2)
+#define DE_CONTROL_EARLY_EXT (2 << 2)
+#define DE_CONTROL_EARLY (3 << 2)
+#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
+
+#define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433
+#define DC_DISP_LCD_SPI_OPTIONS 0x434
+#define DC_DISP_BORDER_COLOR 0x435
+#define DC_DISP_COLOR_KEY0_LOWER 0x436
+#define DC_DISP_COLOR_KEY0_UPPER 0x437
+#define DC_DISP_COLOR_KEY1_LOWER 0x438
+#define DC_DISP_COLOR_KEY1_UPPER 0x439
+#define DC_DISP_CURSOR_FOREGROUND 0x43c
+#define DC_DISP_CURSOR_BACKGROUND 0x43d
+#define DC_DISP_CURSOR_START_ADDR 0x43e
+#define DC_DISP_CURSOR_START_ADDR_NS 0x43f
+#define DC_DISP_CURSOR_POSITION 0x440
+#define DC_DISP_CURSOR_POSITION_NS 0x441
+#define DC_DISP_INIT_SEQ_CONTROL 0x442
+#define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443
+#define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444
+#define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445
+#define DC_DISP_SPI_INIT_SEQ_DATA_D 0x446
+#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
+#define DC_DISP_MCCIF_DISPLAY0A_HYST 0x481
+#define DC_DISP_MCCIF_DISPLAY0B_HYST 0x482
+#define DC_DISP_MCCIF_DISPLAY0C_HYST 0x483
+#define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484
+#define DC_DISP_DAC_CRT_CTRL 0x4c0
+#define DC_DISP_DISP_MISC_CONTROL 0x4c1
+
+#define DC_WINC_COLOR_PALETTE(x) (0x500 + (x))
+
+#define DC_WINC_PALETTE_COLOR_EXT 0x600
+#define DC_WINC_H_FILTER_P(x) (0x601 + (x))
+#define DC_WINC_CSC_YOF 0x611
+#define DC_WINC_CSC_KYRGB 0x612
+#define DC_WINC_CSC_KUR 0x613
+#define DC_WINC_CSC_KVR 0x614
+#define DC_WINC_CSC_KUG 0x615
+#define DC_WINC_CSC_KVG 0x616
+#define DC_WINC_CSC_KUB 0x617
+#define DC_WINC_CSC_KVB 0x618
+#define DC_WINC_V_FILTER_P(x) (0x619 + (x))
+#define DC_WIN_WIN_OPTIONS 0x700
+#define H_DIRECTION_INCREMENT (0 << 0)
+#define H_DIRECTION_DECREMENTT (1 << 0)
+#define V_DIRECTION_INCREMENT (0 << 2)
+#define V_DIRECTION_DECREMENTT (1 << 2)
+#define COLOR_EXPAND (1 << 6)
+#define CP_ENABLE (1 << 16)
+#define DV_ENABLE (1 << 20)
+#define WIN_ENABLE (1 << 30)
+
+#define DC_WIN_BYTE_SWAP 0x701
+#define BYTE_SWAP_NOSWAP 0
+#define BYTE_SWAP_SWAP2 1
+#define BYTE_SWAP_SWAP4 2
+#define BYTE_SWAP_SWAP4HW 3
+
+#define DC_WIN_BUFFER_CONTROL 0x702
+#define BUFFER_CONTROL_HOST 0
+#define BUFFER_CONTROL_VI 1
+#define BUFFER_CONTROL_EPP 2
+#define BUFFER_CONTROL_MPEGE 3
+#define BUFFER_CONTROL_SB2D 4
+
+#define DC_WIN_COLOR_DEPTH 0x703
+
+#define DC_WIN_POSITION 0x704
+#define H_POSITION(x) (((x) & 0xfff) << 0)
+#define V_POSITION(x) (((x) & 0xfff) << 16)
+
+#define DC_WIN_SIZE 0x705
+#define H_SIZE(x) (((x) & 0xfff) << 0)
+#define V_SIZE(x) (((x) & 0xfff) << 16)
+
+#define DC_WIN_PRESCALED_SIZE 0x706
+#define H_PRESCALED_SIZE(x) (((x) & 0x3fff) << 0)
+#define V_PRESCALED_SIZE(x) (((x) & 0xfff) << 16)
+
+#define DC_WIN_H_INITIAL_DDA 0x707
+#define DC_WIN_V_INITIAL_DDA 0x708
+#define DC_WIN_DDA_INCREMENT 0x709
+#define H_DDA_INC(x) (((x) & 0xffff) << 0)
+#define V_DDA_INC(x) (((x) & 0xffff) << 16)
+
+#define DC_WIN_LINE_STRIDE 0x70a
+#define DC_WIN_BUF_STRIDE 0x70b
+#define DC_WIN_UV_BUF_STRIDE 0x70c
+#define DC_WIN_BUFFER_ADDR_MODE 0x70d
+#define DC_WIN_DV_CONTROL 0x70e
+#define DC_WIN_BLEND_NOKEY 0x70f
+#define DC_WIN_BLEND_1WIN 0x710
+#define DC_WIN_BLEND_2WIN_X 0x711
+#define DC_WIN_BLEND_2WIN_Y 0x712
+#define DC_WIN_BLEND_3WIN_XY 0x713
+#define CKEY_NOKEY (0 << 0)
+#define CKEY_KEY0 (1 << 0)
+#define CKEY_KEY1 (2 << 0)
+#define CKEY_KEY01 (3 << 0)
+#define BLEND_CONTROL_FIX (0 << 2)
+#define BLEND_CONTROL_ALPHA (1 << 2)
+#define BLEND_CONTROL_DEPENDANT (2 << 2)
+#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
+#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
+
+#define DC_WIN_HP_FETCH_CONTROL 0x714
+#define DC_WINBUF_START_ADDR 0x800
+#define DC_WINBUF_START_ADDR_NS 0x801
+#define DC_WINBUF_START_ADDR_U 0x802
+#define DC_WINBUF_START_ADDR_U_NS 0x803
+#define DC_WINBUF_START_ADDR_V 0x804
+#define DC_WINBUF_START_ADDR_V_NS 0x805
+#define DC_WINBUF_ADDR_H_OFFSET 0x806
+#define DC_WINBUF_ADDR_H_OFFSET_NS 0x807
+#define DC_WINBUF_ADDR_V_OFFSET 0x808
+#define DC_WINBUF_ADDR_V_OFFSET_NS 0x809
+#define DC_WINBUF_UFLOW_STATUS 0x80a
+
+#endif
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
new file mode 100644
index 0000000..de1a8fa
--- /dev/null
+++ b/drivers/video/tegra/dc/rgb.c
@@ -0,0 +1,63 @@
+/*
+ * drivers/video/tegra/dc/rgb.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include <mach/dc.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+
+
+static const u32 tegra_dc_rgb_pintable[] = {
+ DC_COM_PIN_OUTPUT_ENABLE0, 0x00000000,
+ DC_COM_PIN_OUTPUT_ENABLE1, 0x00000000,
+ DC_COM_PIN_OUTPUT_ENABLE2, 0x00000000,
+ DC_COM_PIN_OUTPUT_ENABLE3, 0x00000000,
+ DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000,
+ DC_COM_PIN_OUTPUT_POLARITY1, 0x01000000,
+ DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000,
+ DC_COM_PIN_OUTPUT_POLARITY3, 0x00000000,
+ DC_COM_PIN_OUTPUT_DATA0, 0x00000000,
+ DC_COM_PIN_OUTPUT_DATA1, 0x00000000,
+ DC_COM_PIN_OUTPUT_DATA2, 0x00000000,
+ DC_COM_PIN_OUTPUT_DATA3, 0x00000000,
+ DC_COM_PIN_OUTPUT_SELECT0, 0x00000000,
+ DC_COM_PIN_OUTPUT_SELECT1, 0x00000000,
+ DC_COM_PIN_OUTPUT_SELECT2, 0x00000000,
+ DC_COM_PIN_OUTPUT_SELECT3, 0x00000000,
+ DC_COM_PIN_OUTPUT_SELECT4, 0x00210222,
+ DC_COM_PIN_OUTPUT_SELECT5, 0x00002200,
+ DC_COM_PIN_OUTPUT_SELECT6, 0x00020000,
+};
+
+
+void tegra_dc_rgb_init(struct tegra_dc *dc)
+{
+ tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+ PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
+ DC_CMD_DISPLAY_POWER_CONTROL);
+
+ tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
+
+ tegra_dc_write_table(dc, tegra_dc_rgb_pintable);
+}
+
+struct tegra_dc_out_ops tegra_dc_rgb_ops = {
+ .init = tegra_dc_rgb_init,
+};
+
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
new file mode 100644
index 0000000..4db3958
--- /dev/null
+++ b/drivers/video/tegra/fb.c
@@ -0,0 +1,311 @@
+/*
+ * drivers/video/tegra/fb.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <konkers@android.com>
+ * Colin Cross <ccross@android.com>
+ * Travis Geiselbrecht <travis@palm.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <asm/atomic.h>
+
+#include <mach/dc.h>
+#include <mach/fb.h>
+
+struct tegra_fb_info {
+ struct tegra_dc_win *win;
+ struct platform_device *pdev;
+ struct fb_info *info;
+
+ struct resource *fb_mem;
+
+ int xres;
+ int yres;
+
+ atomic_t in_use;
+};
+
+/* palette array used by the fbcon */
+static u32 pseudo_palette[16];
+
+static int tegra_fb_open(struct fb_info *info, int user)
+{
+ struct tegra_fb_info *tegra_fb = info->par;
+
+ if (atomic_xchg(&tegra_fb->in_use, 1))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int tegra_fb_release(struct fb_info *info, int user)
+{
+ struct tegra_fb_info *tegra_fb = info->par;
+
+ WARN_ON(!atomic_xchg(&tegra_fb->in_use, 0));
+
+ return 0;
+}
+
+static int tegra_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ if ((var->xres != info->var.xres) ||
+ (var->yres != info->var.yres) ||
+ (var->xres_virtual != info->var.xres_virtual) ||
+ (var->yres_virtual != info->var.yres_virtual) ||
+ (var->grayscale != info->var.grayscale))
+ return -EINVAL;
+ return 0;
+}
+
+static int tegra_fb_set_par(struct fb_info *info)
+{
+ struct tegra_fb_info *tegra_fb = info->par;
+ struct fb_var_screeninfo *var = &info->var;
+
+ /* we only support RGB ordering for now */
+ switch (var->bits_per_pixel) {
+ case 32:
+ case 24:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ info->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
+ tegra_dc_update_windows(&tegra_fb->win, 1);
+
+ return 0;
+}
+
+static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ v = (red << var->red.offset) |
+ (green << var->green.offset) |
+ (blue << var->blue.offset);
+
+ ((u32 *)info->pseudo_palette)[regno] = v;
+ }
+
+ return 0;
+}
+
+static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct tegra_fb_info *tegra_fb = info->par;
+ char __iomem *flush_start;
+ char __iomem *flush_end;
+ u32 addr;
+
+ flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
+ flush_end = flush_start + (var->yres * info->fix.line_length);
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+
+ addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (var->bits_per_pixel/8));
+
+ tegra_fb->win->phys_addr = addr;
+ /* TODO: update virt_addr */
+
+ tegra_dc_update_windows(&tegra_fb->win, 1);
+ tegra_dc_sync_windows(&tegra_fb->win, 1);
+
+ return 0;
+}
+
+static void tegra_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ cfb_fillrect(info, rect);
+}
+
+static void tegra_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region)
+{
+ cfb_copyarea(info, region);
+}
+
+static void tegra_fb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ cfb_imageblit(info, image);
+}
+
+static struct fb_ops tegra_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = tegra_fb_open,
+ .fb_release = tegra_fb_release,
+ .fb_check_var = tegra_fb_check_var,
+ .fb_set_par = tegra_fb_set_par,
+ .fb_setcolreg = tegra_fb_setcolreg,
+ .fb_pan_display = tegra_fb_pan_display,
+ .fb_fillrect = tegra_fb_fillrect,
+ .fb_copyarea = tegra_fb_copyarea,
+ .fb_imageblit = tegra_fb_imageblit,
+};
+
+struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
+ struct tegra_dc *dc,
+ struct tegra_fb_data *fb_data,
+ struct resource *fb_mem)
+{
+ struct tegra_dc_win *win;
+ struct fb_info *info;
+ struct tegra_fb_info *tegra_fb;
+ void __iomem *fb_base;
+ unsigned long fb_size;
+ unsigned long fb_phys;
+ int ret = 0;
+
+ win = tegra_dc_get_window(dc, fb_data->win);
+ if (!win) {
+ dev_err(&pdev->dev, "dc does not have a window at index %d\n",
+ fb_data->win);
+ return ERR_PTR(-ENOENT);
+ }
+
+ info = framebuffer_alloc(sizeof(struct tegra_fb_info), &pdev->dev);
+ if (!info) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ fb_size = resource_size(fb_mem);
+ fb_phys = fb_mem->start;
+ fb_base = ioremap_nocache(fb_phys, fb_size);
+ if (!fb_base) {
+ dev_err(&pdev->dev, "fb can't be mapped\n");
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ tegra_fb = info->par;
+ tegra_fb->win = win;
+ tegra_fb->pdev = pdev;
+ tegra_fb->fb_mem = fb_mem;
+ tegra_fb->xres = fb_data->xres;
+ tegra_fb->yres = fb_data->yres;
+ atomic_set(&tegra_fb->in_use, 0);
+
+ info->fbops = &tegra_fb_ops;
+ info->pseudo_palette = pseudo_palette;
+ info->screen_base = fb_base;
+ info->screen_size = fb_size;
+
+ strlcpy(info->fix.id, "tegra_fb", sizeof(info->fix.id));
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.xpanstep = 1;
+ info->fix.ypanstep = 1;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.smem_start = fb_phys;
+ info->fix.smem_len = fb_size;
+
+ info->var.xres = fb_data->xres;
+ info->var.yres = fb_data->yres;
+ info->var.xres_virtual = fb_data->xres;
+ info->var.yres_virtual = fb_data->yres*2;
+ info->var.bits_per_pixel = fb_data->bits_per_pixel;
+ info->var.activate = FB_ACTIVATE_VBL;
+ /* TODO: fill in the following by querying the DC */
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.pixclock = 24500;
+ info->var.left_margin = 0;
+ info->var.right_margin = 0;
+ info->var.upper_margin = 0;
+ info->var.lower_margin = 0;
+ info->var.hsync_len = 0;
+ info->var.vsync_len = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ win->x = 0;
+ win->y = 0;
+ win->w = fb_data->xres;
+ win->h = fb_data->yres;
+ /* TODO: set to output res dc */
+ win->out_w = fb_data->xres;
+ win->out_h = fb_data->yres;
+ win->phys_addr = fb_phys;
+ win->virt_addr = fb_base;
+ win->flags = TEGRA_WIN_FLAG_ENABLED | TEGRA_WIN_FLAG_COLOR_EXPAND;
+
+ tegra_fb_set_par(info);
+
+ if (register_framebuffer(info)) {
+ dev_err(&pdev->dev, "failed to register framebuffer\n");
+ ret = -ENODEV;
+ goto err_iounmap_fb;
+ }
+
+ tegra_fb->info = info;
+
+ dev_info(&pdev->dev, "probed\n");
+
+ return tegra_fb;
+
+err_iounmap_fb:
+ iounmap(fb_base);
+err_free:
+ framebuffer_release(info);
+err:
+ return ERR_PTR(ret);
+}
+
+void tegra_fb_unregister(struct tegra_fb_info *fb_info)
+{
+ struct fb_info *info = fb_info->info;
+
+ unregister_framebuffer(info);
+ iounmap(info->screen_base);
+ framebuffer_release(info);
+}
--
1.6.5.6
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH] video: tegra: add tegra display controller and fb driver
2010-08-11 23:11 [PATCH] video: tegra: add tegra display controller and fb driver Erik Gilling
@ 2010-08-12 4:34 ` Ryan Mallon
[not found] ` <AANLkTini+n1osaQHkomguzZi-DaHLX3i1G4gA82bK0=S@mail.gmail.com>
2010-08-25 22:04 ` Erik Gilling
1 sibling, 1 reply; 6+ messages in thread
From: Ryan Mallon @ 2010-08-12 4:34 UTC (permalink / raw)
To: linux-arm-kernel
On 08/12/2010 11:11 AM, Erik Gilling wrote:
> This patch supersedes the previous framebuffer patch
>
> Supports:
> * panel setup
> * overlays
> * suspend / resume
>
> Notable ommisions:
> * support for anything but lvds panels
> * inegration with nvhost driver to sync updates with 3D
> * FB physical geometry is not set
> * lacks interface to set overlay/window x,y offset
>
> Signed-off-by: Erik Gilling <konkers@android.com>
> Cc: Colin Cross <ccross@android.com>
> Cc: Travis Geiselbrecht <travis@palm.com>
Hi Erik,
Just a couple of notes, not really a full review.
> +++ b/drivers/video/tegra/Kconfig
> @@ -0,0 +1,15 @@
> +config TEGRA_DC
> + tristate "Tegra Display Contoller"
> + depends on ARCH_TEGRA
> + help
> + Tegra display controller support.
> +
> +config FB_TEGRA
> + tristate "Tegra Framebuffer driver"
> + depends on TEGRA_DC && FB = y
How come this depends on FB=y?
> +++ b/drivers/video/tegra/dc/Makefile
> @@ -0,0 +1,2 @@
> +obj-y += dc.o
> +obj-y += rgb.o
> \ No newline at end of file
Is that meant to be there?
> +struct tegra_dc_blend tegra_dc_blend_modes[][DC_N_WINDOWS] = {
> + {{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .two_win_x = BLEND(NOKEY, FIX, 0x00, 0x00),
> + .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
> + .three_win_xy = BLEND(NOKEY, FIX, 0x00, 0x00)},
> + {.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .two_win_x = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
> + .three_win_xy = BLEND(NOKEY, DEPENDANT, 0x00, 0x00)},
> + {.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + .two_win_x = BLEND(NOKEY, ALPHA, 0xff, 0xff),
> + .two_win_y = BLEND(NOKEY, ALPHA, 0xff, 0xff),
> + .three_win_xy = BLEND(NOKEY, ALPHA, 0xff, 0xff)}
> + }
> +};
Tab delimiting this would make it a bit more readable.
> +#define DUMP_REG(a) do { \
> + snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
> + #a, a, tegra_dc_readl(dc, a)); \
> + print(data, buff); \
> + } while (0)
> +
> +static void _dump_regs(struct tegra_dc *dc, void *data,
> + void (* print)(void *data, const char *str))
> +{
> + int i;
> + char buff[256];
> +
> + DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
> + DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
> + DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
<snip>
The dump_regs code is very long for a debugging feature. Can it just be
replaced by a for loop which prints the offsets and values of each register?
> +
> +#undef DUMP_REG
> +
> +#ifdef DEBUG
> +static void dump_regs_print(void *data, const char *str)
> +{
> + struct tegra_dc *dc = data;
> + dev_dbg(&dc->pdev->dev, "%s", str);
> +}
> +
> +static void dump_regs(struct tegra_dc *dc)
> +{
> + _dump_regs(dc, dc, dump_regs_print);
> +}
> +#else
> +
> +static void dump_regs(struct tegra_dc *dc) {}
> +
> +#endif
> +
> +#ifdef CONFIG_DEBUG_FS
> +
> +static void dbg_regs_print(void *data, const char *str)
> +{
> + struct seq_file *s = data;
> +
> + seq_printf(s, "%s", str);
> +}
> +
> +#undef DUMP_REG
> +
> +static int dbg_dc_show(struct seq_file *s, void *unused)
> +{
> + struct tegra_dc *dc = s->private;
> +
> + _dump_regs(dc, s, dbg_regs_print);
> +
> + return 0;
> +}
This all looks a bit confusing (especially the undef stuff). Why do you
have both a debugfs interface to the registers and one which prints them
using dev_dbg?
> +static void tegra_dc_dbg_add(struct tegra_dc *dc)
> +{
> + char name[32];
> +
> + snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->pdev->id);
> + (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops);
Don't cast the return value to void. Possibly print a warning if the
call fails?
> +/* does not support syncing windows on multiple dcs in one call */
> +int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
> +{
> + if (n < 1 || n > DC_N_WINDOWS)
> + return -EINVAL;
if (n < 1 || n >= DC_N_WINDOWS) ?
> + return wait_event_interruptible_timeout(windows[0]->dc->wq,
> + tegra_dc_windows_are_clean(windows, n),
> + HZ);
> +}
> +EXPORT_SYMBOL(tegra_dc_sync_windows);
<snip>
> +static irqreturn_t tegra_dc_irq(int irq, void *ptr)
> +{
> + struct tegra_dc *dc = ptr;
> + unsigned long status;
> + unsigned long flags;
> + unsigned long val;
> + int i;
> +
> +
There are a few places like this with excess blank lines.
> + tegra_dc_init(dc);
> +
> + tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
> +
> + platform_set_drvdata(pdev, dc);
> +
> + tegra_dc_dbg_add(dc);
> +
> + dev_info(&pdev->dev, "probed\n");
dev_dbg? Also, probably don't need all those blank lines.
> +#ifdef CONFIG_PM
> +static int tegra_dc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + struct tegra_dc *dc = platform_get_drvdata(pdev);
> +
> + dev_info(&pdev->dev, "suspend\n");
dev_dbg?
> + disable_irq(dc->irq);
> + tegra_periph_reset_assert(dc->clk);
> + clk_disable(dc->clk);
> +
> + return 0;
> +}
> +
> +static int tegra_dc_resume(struct platform_device *pdev)
> +{
> + struct tegra_dc *dc = platform_get_drvdata(pdev);
> + struct tegra_dc_win *wins[DC_N_WINDOWS];
> + int i;
> +
> + dev_info(&pdev->dev, "resume\n");
dev_dbg?
> +extern int suspend_get(char *buffer, struct kernel_param *kp)
> +{
> + return 0;
> +}
> +
> +int suspend;
Should be static? Have a global called suspend is likely to cause issues
somewhere.
> +module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644);
> +
> +struct platform_driver tegra_dc_driver = {
> + .driver = {
> + .name = "tegradc",
> + .owner = THIS_MODULE,
> + },
> + .probe = tegra_dc_probe,
> + .remove = tegra_dc_remove,
> +#ifdef CONFIG_PM
> + .suspend = tegra_dc_suspend,
> + .resume = tegra_dc_resume,
> +#endif
> +};
Also should be static?
> +static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
> + unsigned long reg)
> +{
> + return readl(dc->base + reg * 4);
> +}
Can these functions use __raw_readl/__raw_writel?
> +static void tegra_fb_fillrect(struct fb_info *info,
> + const struct fb_fillrect *rect)
> +{
> + cfb_fillrect(info, rect);
> +}
> +
> +static void tegra_fb_copyarea(struct fb_info *info,
> + const struct fb_copyarea *region)
> +{
> + cfb_copyarea(info, region);
> +}
> +
> +static void tegra_fb_imageblit(struct fb_info *info,
> + const struct fb_image *image)
> +{
> + cfb_imageblit(info, image);
> +}
You can just set the cfb_ functions directly in the fb_ops. See below:
> +static struct fb_ops tegra_fb_ops = {
> + .owner = THIS_MODULE,
> + .fb_open = tegra_fb_open,
> + .fb_release = tegra_fb_release,
> + .fb_check_var = tegra_fb_check_var,
> + .fb_set_par = tegra_fb_set_par,
> + .fb_setcolreg = tegra_fb_setcolreg,
> + .fb_pan_display = tegra_fb_pan_display,
> + .fb_fillrect = tegra_fb_fillrect,
> + .fb_copyarea = tegra_fb_copyarea,
> + .fb_imageblit = tegra_fb_imageblit,
Should be:
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_fillarea,
.fb_imageblit = cfb_imageblit,
Also (nitpicky) tab delimit to make it more readable.
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon 5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com New Zealand
Phone: +64 3 3779127 Freecall: Australia 1800 148 751
Fax: +64 3 3779135 USA 1800 261 2934
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH] video: tegra: add tegra display controller and fb driver
2010-08-11 23:11 [PATCH] video: tegra: add tegra display controller and fb driver Erik Gilling
2010-08-12 4:34 ` Ryan Mallon
@ 2010-08-25 22:04 ` Erik Gilling
1 sibling, 0 replies; 6+ messages in thread
From: Erik Gilling @ 2010-08-25 22:04 UTC (permalink / raw)
To: linux-arm-kernel
ping. any more comments. I'd like to have this ready for the next
merge window.
On Wed, Aug 11, 2010 at 4:11 PM, Erik Gilling <konkers@android.com> wrote:
> This patch supersedes the previous framebuffer patch
>
> Supports:
> ? ? ? ?* panel setup
> ? ? ? ?* overlays
> ? ? ? ?* suspend / resume
>
> Notable ommisions:
> ? ? ? ?* support for anything but lvds panels
> ? ? ? ?* inegration with nvhost driver to sync updates with 3D
> ? ? ? ?* FB physical geometry is not set
> ? ? ? ?* lacks interface to set overlay/window x,y offset
>
> Signed-off-by: Erik Gilling <konkers@android.com>
> Cc: Colin Cross <ccross@android.com>
> Cc: Travis Geiselbrecht <travis@palm.com>
> ---
> ?arch/arm/mach-tegra/include/mach/dc.h | ?152 ++++++
> ?arch/arm/mach-tegra/include/mach/fb.h | ? 44 ++
> ?drivers/video/Kconfig ? ? ? ? ? ? ? ? | ? ?1 +
> ?drivers/video/Makefile ? ? ? ? ? ? ? ?| ? ?1 +
> ?drivers/video/tegra/Kconfig ? ? ? ? ? | ? 15 +
> ?drivers/video/tegra/Makefile ? ? ? ? ?| ? ?2 +
> ?drivers/video/tegra/dc/Makefile ? ? ? | ? ?2 +
> ?drivers/video/tegra/dc/dc.c ? ? ? ? ? | ?894 +++++++++++++++++++++++++++++++++
> ?drivers/video/tegra/dc/dc_priv.h ? ? ?| ? 86 ++++
> ?drivers/video/tegra/dc/dc_reg.h ? ? ? | ?342 +++++++++++++
> ?drivers/video/tegra/dc/rgb.c ? ? ? ? ?| ? 63 +++
> ?drivers/video/tegra/fb.c ? ? ? ? ? ? ?| ?311 ++++++++++++
> ?12 files changed, 1913 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-tegra/include/mach/dc.h
> ?create mode 100644 arch/arm/mach-tegra/include/mach/fb.h
> ?create mode 100644 drivers/video/tegra/Kconfig
> ?create mode 100644 drivers/video/tegra/Makefile
> ?create mode 100644 drivers/video/tegra/dc/Makefile
> ?create mode 100644 drivers/video/tegra/dc/dc.c
> ?create mode 100644 drivers/video/tegra/dc/dc_priv.h
> ?create mode 100644 drivers/video/tegra/dc/dc_reg.h
> ?create mode 100644 drivers/video/tegra/dc/rgb.c
> ?create mode 100644 drivers/video/tegra/fb.c
>
> diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
> new file mode 100644
> index 0000000..b8a0e7a
> --- /dev/null
> +++ b/arch/arm/mach-tegra/include/mach/dc.h
> @@ -0,0 +1,152 @@
> +/*
> + * arch/arm/mach-tegra/include/mach/dc.h
> + *
> + * Copyright (C) 2010 Google, Inc.
> + *
> + * Author:
> + * ? ? Erik Gilling <konkers@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef __MACH_TEGRA_DC_H
> +#define __MACH_TEGRA_DC_H
> +
> +
> +#define TEGRA_MAX_DC ? ? ? ? ? 2
> +#define DC_N_WINDOWS ? ? ? ? ? 3
> +
> +struct tegra_dc_blend {
> + ? ? ? u32 ? ? nokey;
> + ? ? ? u32 ? ? one_win;
> + ? ? ? u32 ? ? two_win_x;
> + ? ? ? u32 ? ? two_win_y;
> + ? ? ? u32 ? ? three_win_xy;
> +};
> +
> +#define BLEND(key, control, weight0, weight1) ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ? (CKEY_ ## key | BLEND_CONTROL_ ## control | ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? ?BLEND_WEIGHT0(weight0) | BLEND_WEIGHT0(weight1))
> +
> +struct tegra_dc_mode {
> + ? ? ? int ? ? pclk;
> + ? ? ? int ? ? h_ref_to_sync;
> + ? ? ? int ? ? v_ref_to_sync;
> + ? ? ? int ? ? h_sync_width;
> + ? ? ? int ? ? v_sync_width;
> + ? ? ? int ? ? h_back_porch;
> + ? ? ? int ? ? v_back_porch;
> + ? ? ? int ? ? h_active;
> + ? ? ? int ? ? v_active;
> + ? ? ? int ? ? h_front_porch;
> + ? ? ? int ? ? v_front_porch;
> +};
> +
> +enum {
> + ? ? ? TEGRA_DC_OUT_RGB,
> +};
> +
> +struct tegra_dc_out {
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? type;
> +
> + ? ? ? unsigned ? ? ? ? ? ? ? ?order;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?align;
> +
> + ? ? ? struct tegra_dc_mode ? ?*modes;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? n_modes;
> +};
> +
> +#define TEGRA_DC_ALIGN_MSB ? ? ? ? ? ? 0
> +#define TEGRA_DC_ALIGN_LSB ? ? ? ? ? ? 1
> +
> +#define TEGRA_DC_ORDER_RED_BLUE ? ? ? ? ? ? ? ?0
> +#define TEGRA_DC_ORDER_BLUE_RED ? ? ? ? ? ? ? ?1
> +
> +struct tegra_dc;
> +
> +struct tegra_dc_win {
> + ? ? ? u8 ? ? ? ? ? ? ? ? ? ? ?idx;
> + ? ? ? u8 ? ? ? ? ? ? ? ? ? ? ?fmt;
> + ? ? ? u32 ? ? ? ? ? ? ? ? ? ? flags;
> +
> + ? ? ? void ? ? ? ? ? ? ? ? ? ?*virt_addr;
> + ? ? ? dma_addr_t ? ? ? ? ? ? ?phys_addr;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?x;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?y;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?w;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?h;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?out_w;
> + ? ? ? unsigned ? ? ? ? ? ? ? ?out_h;
> +
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? dirty;
> + ? ? ? struct tegra_dc ? ? ? ? *dc;
> +};
> +
> +#define TEGRA_WIN_FLAG_ENABLED ? ? ? ? (1 << 0)
> +#define TEGRA_WIN_FLAG_COLOR_EXPAND ? ?(1 << 1)
> +
> +/* Note: These are the actual values written to the DC_WIN_COLOR_DEPTH register
> + * and may change in new tegra architectures.
> + */
> +#define TEGRA_WIN_FMT_P1 ? ? ? ? ? ? ? 0
> +#define TEGRA_WIN_FMT_P2 ? ? ? ? ? ? ? 1
> +#define TEGRA_WIN_FMT_P4 ? ? ? ? ? ? ? 2
> +#define TEGRA_WIN_FMT_P8 ? ? ? ? ? ? ? 3
> +#define TEGRA_WIN_FMT_B4G4R4A4 ? ? ? ? 4
> +#define TEGRA_WIN_FMT_B5G5R5A ? ? ? ? ?5
> +#define TEGRA_WIN_FMT_B5G6R5 ? ? ? ? ? 6
> +#define TEGRA_WIN_FMT_AB5G5R5 ? ? ? ? ?7
> +#define TEGRA_WIN_FMT_B8G8R8A8 ? ? ? ? 12
> +#define TEGRA_WIN_FMT_R8G8B8A8 ? ? ? ? 13
> +#define TEGRA_WIN_FMT_B6x2G6x2R6x2A8 ? 14
> +#define TEGRA_WIN_FMT_R6x2G6x2B6x2A8 ? 15
> +#define TEGRA_WIN_FMT_YCbCr422 ? ? ? ? 16
> +#define TEGRA_WIN_FMT_YUV422 ? ? ? ? ? 17
> +#define TEGRA_WIN_FMT_YCbCr420P ? ? ? ? ? ? ? ?18
> +#define TEGRA_WIN_FMT_YUV420P ? ? ? ? ?19
> +#define TEGRA_WIN_FMT_YCbCr422P ? ? ? ? ? ? ? ?20
> +#define TEGRA_WIN_FMT_YUV422P ? ? ? ? ?21
> +#define TEGRA_WIN_FMT_YCbCr422R ? ? ? ? ? ? ? ?22
> +#define TEGRA_WIN_FMT_YUV422R ? ? ? ? ?23
> +#define TEGRA_WIN_FMT_YCbCr422RA ? ? ? 24
> +#define TEGRA_WIN_FMT_YUV422RA ? ? ? ? 25
> +
> +struct tegra_fb_data {
> + ? ? ? int ? ? ? ? ? ? win;
> +
> + ? ? ? int ? ? ? ? ? ? xres;
> + ? ? ? int ? ? ? ? ? ? yres;
> + ? ? ? int ? ? ? ? ? ? bits_per_pixel;
> +};
> +
> +struct tegra_dc_platform_data {
> + ? ? ? unsigned long ? ? ? ? ? flags;
> + ? ? ? struct tegra_dc_out ? ? *default_out;
> + ? ? ? struct tegra_fb_data ? ?*fb;
> +};
> +
> +#define TEGRA_DC_FLAG_ENABLED ? ? ? ? ?(1 << 0)
> +
> +struct tegra_dc *tegra_dc_get_dc(unsigned idx);
> +struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win);
> +
> +/* tegra_dc_update_windows and tegra_dc_sync_windows do not support windows
> + * with differenct dcs in one call
> + */
> +int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n);
> +int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
> +
> +/* will probably be replaced with an interface describing the window order */
> +void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend);
> +
> +int tegra_dc_set_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode);
> +
> +#endif
> diff --git a/arch/arm/mach-tegra/include/mach/fb.h b/arch/arm/mach-tegra/include/mach/fb.h
> new file mode 100644
> index 0000000..9e5f7f8
> --- /dev/null
> +++ b/arch/arm/mach-tegra/include/mach/fb.h
> @@ -0,0 +1,44 @@
> +/*
> + * arch/arm/mach-tegra/include/mach/fb.h
> + *
> + * Copyright (C) 2010 Google, Inc.
> + *
> + * Author:
> + * ? ? Erik Gilling <konkers@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef __MACH_TEGRA_FB_H
> +#define __MACH_TEGRA_FB_H
> +
> +#ifdef CONFIG_FB_TEGRA
> +struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_dc *dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_fb_data *fb_data,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct resource *fb_mem);
> +void tegra_fb_unregister(struct tegra_fb_info *fb_info);
> +#else
> +static inline
> +struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_dc *dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_fb_data *fb_data,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct resource *fb_mem)
> +{
> + ? ? ? return NULL;
> +}
> +
> +static inline void tegra_fb_unregister(struct tegra_fb_info *fb_info)
> +{
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 3d94a14..1eb0ac1 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2231,6 +2231,7 @@ config FB_BROADSHEET
>
> ?source "drivers/video/omap/Kconfig"
> ?source "drivers/video/omap2/Kconfig"
> +source "drivers/video/tegra/Kconfig"
>
> ?source "drivers/video/backlight/Kconfig"
> ?source "drivers/video/display/Kconfig"
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index ddc2af2..21b527d 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -131,6 +131,7 @@ obj-$(CONFIG_FB_CARMINE) ? ? ? ? ?+= carminefb.o
> ?obj-$(CONFIG_FB_MB862XX) ? ? ? ? += mb862xx/
> ?obj-$(CONFIG_FB_MSM) ? ? ? ? ? ? ?+= msm/
> ?obj-$(CONFIG_FB_NUC900) ? ? ? ? ? += nuc900fb.o
> +obj-y ? ? ? ? ? ? ? ? ? ? ? ? ? ? += tegra/
>
> ?# Platform or fallback drivers go here
> ?obj-$(CONFIG_FB_UVESA) ? ? ? ? ? ?+= uvesafb.o
> diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
> new file mode 100644
> index 0000000..b01dc95
> --- /dev/null
> +++ b/drivers/video/tegra/Kconfig
> @@ -0,0 +1,15 @@
> +config TEGRA_DC
> + ? ? ? tristate "Tegra Display Contoller"
> + ? ? ? depends on ARCH_TEGRA
> + ? ? ? help
> + ? ? ? ? Tegra display controller support.
> +
> +config FB_TEGRA
> + ? ? ? tristate "Tegra Framebuffer driver"
> + ? ? ? depends on TEGRA_DC && FB = y
> + ? ? ? select FB_CFB_FILLRECT
> + ? ? ? select FB_CFB_COPYAREA
> + ? ? ? select FB_CFB_IMAGEBLIT
> + ? ? ? default FB
> + ? ? ? help
> + ? ? ? ? Framebuffer device support for the Tegra display controller.
> diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile
> new file mode 100644
> index 0000000..8f9d0e2
> --- /dev/null
> +++ b/drivers/video/tegra/Makefile
> @@ -0,0 +1,2 @@
> +obj-$(CONFIG_TEGRA_DC) += dc/
> +obj-$(CONFIG_FB_TEGRA) += fb.o
> diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
> new file mode 100644
> index 0000000..3ecb63c
> --- /dev/null
> +++ b/drivers/video/tegra/dc/Makefile
> @@ -0,0 +1,2 @@
> +obj-y += dc.o
> +obj-y += rgb.o
> \ No newline at end of file
> diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
> new file mode 100644
> index 0000000..261bced
> --- /dev/null
> +++ b/drivers/video/tegra/dc/dc.c
> @@ -0,0 +1,894 @@
> +/*
> + * drivers/video/tegra/dc/dc.c
> + *
> + * Copyright (C) 2010 Google, Inc.
> + * Author: Erik Gilling <konkers@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/clk.h>
> +#include <linux/mutex.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/workqueue.h>
> +#include <linux/ktime.h>
> +#include <linux/debugfs.h>
> +#include <linux/seq_file.h>
> +
> +#include <mach/clk.h>
> +#include <mach/dc.h>
> +#include <mach/fb.h>
> +
> +#include "dc_reg.h"
> +#include "dc_priv.h"
> +
> +struct tegra_dc_blend tegra_dc_blend_modes[][DC_N_WINDOWS] = {
> + ? ? ? {{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .two_win_x = BLEND(NOKEY, FIX, 0x00, 0x00),
> + ? ? ? ? .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
> + ? ? ? ? .three_win_xy = BLEND(NOKEY, FIX, 0x00, 0x00)},
> + ? ? ? ?{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .two_win_x = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .two_win_y = BLEND(NOKEY, DEPENDANT, 0x00, 0x00),
> + ? ? ? ? .three_win_xy = BLEND(NOKEY, DEPENDANT, 0x00, 0x00)},
> + ? ? ? ?{.nokey = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .one_win = BLEND(NOKEY, FIX, 0xff, 0xff),
> + ? ? ? ? .two_win_x = BLEND(NOKEY, ALPHA, 0xff, 0xff),
> + ? ? ? ? .two_win_y = BLEND(NOKEY, ALPHA, 0xff, 0xff),
> + ? ? ? ? .three_win_xy = BLEND(NOKEY, ALPHA, 0xff, 0xff)}
> + ? ? ? }
> +};
> +
> +struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
> +
> +DEFINE_MUTEX(tegra_dc_lock);
> +
> +static inline int tegra_dc_fmt_bpp(int fmt)
> +{
> + ? ? ? switch (fmt) {
> + ? ? ? case TEGRA_WIN_FMT_P1:
> + ? ? ? ? ? ? ? return 1;
> +
> + ? ? ? case TEGRA_WIN_FMT_P2:
> + ? ? ? ? ? ? ? return 2;
> +
> + ? ? ? case TEGRA_WIN_FMT_P4:
> + ? ? ? ? ? ? ? return 4;
> +
> + ? ? ? case TEGRA_WIN_FMT_P8:
> + ? ? ? ? ? ? ? return 8;
> +
> + ? ? ? case TEGRA_WIN_FMT_B4G4R4A4:
> + ? ? ? case TEGRA_WIN_FMT_B5G5R5A:
> + ? ? ? case TEGRA_WIN_FMT_B5G6R5:
> + ? ? ? case TEGRA_WIN_FMT_AB5G5R5:
> + ? ? ? ? ? ? ? return 16;
> +
> + ? ? ? case TEGRA_WIN_FMT_B8G8R8A8:
> + ? ? ? case TEGRA_WIN_FMT_R8G8B8A8:
> + ? ? ? case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
> + ? ? ? case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
> + ? ? ? ? ? ? ? return 32;
> +
> + ? ? ? case TEGRA_WIN_FMT_YCbCr422:
> + ? ? ? case TEGRA_WIN_FMT_YUV422:
> + ? ? ? case TEGRA_WIN_FMT_YCbCr420P:
> + ? ? ? case TEGRA_WIN_FMT_YUV420P:
> + ? ? ? case TEGRA_WIN_FMT_YCbCr422P:
> + ? ? ? case TEGRA_WIN_FMT_YUV422P:
> + ? ? ? case TEGRA_WIN_FMT_YCbCr422R:
> + ? ? ? case TEGRA_WIN_FMT_YUV422R:
> + ? ? ? case TEGRA_WIN_FMT_YCbCr422RA:
> + ? ? ? case TEGRA_WIN_FMT_YUV422RA:
> + ? ? ? ? ? ? ? /* FIXME: need to know the bpp of these formats */
> + ? ? ? ? ? ? ? return 0;
> + ? ? ? }
> + ? ? ? return 0;
> +}
> +
> +#define DUMP_REG(a) do { ? ? ? ? ? ? ? ? ? ? ? \
> + ? ? ? snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
> + ? ? ? ? ? ? ? ?#a, a, tegra_dc_readl(dc, a)); ? ? ? ? ? ? ? \
> + ? ? ? print(data, buff); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?\
> + ? ? ? } while (0)
> +
> +static void _dump_regs(struct tegra_dc *dc, void *data,
> + ? ? ? ? ? ? ? ? ? ? ?void (* print)(void *data, const char *str))
> +{
> + ? ? ? int i;
> + ? ? ? char buff[256];
> +
> + ? ? ? DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT);
> + ? ? ? DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
> + ? ? ? DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR);
> + ? ? ? DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT);
> + ? ? ? DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL);
> + ? ? ? DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR);
> + ? ? ? DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT);
> + ? ? ? DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL);
> + ? ? ? DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR);
> + ? ? ? DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT);
> + ? ? ? DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL);
> + ? ? ? DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR);
> + ? ? ? DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC);
> + ? ? ? DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
> + ? ? ? DUMP_REG(DC_CMD_DISPLAY_COMMAND);
> + ? ? ? DUMP_REG(DC_CMD_SIGNAL_RAISE);
> + ? ? ? DUMP_REG(DC_CMD_INT_STATUS);
> + ? ? ? DUMP_REG(DC_CMD_INT_MASK);
> + ? ? ? DUMP_REG(DC_CMD_INT_ENABLE);
> + ? ? ? DUMP_REG(DC_CMD_INT_TYPE);
> + ? ? ? DUMP_REG(DC_CMD_INT_POLARITY);
> + ? ? ? DUMP_REG(DC_CMD_SIGNAL_RAISE1);
> + ? ? ? DUMP_REG(DC_CMD_SIGNAL_RAISE2);
> + ? ? ? DUMP_REG(DC_CMD_SIGNAL_RAISE3);
> + ? ? ? DUMP_REG(DC_CMD_STATE_ACCESS);
> + ? ? ? DUMP_REG(DC_CMD_STATE_CONTROL);
> + ? ? ? DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
> + ? ? ? DUMP_REG(DC_CMD_REG_ACT_CONTROL);
> +
> + ? ? ? DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
> + ? ? ? DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
> + ? ? ? DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY);
> + ? ? ? DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER);
> + ? ? ? DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_REF_TO_SYNC);
> + ? ? ? DUMP_REG(DC_DISP_SYNC_WIDTH);
> + ? ? ? DUMP_REG(DC_DISP_BACK_PORCH);
> + ? ? ? DUMP_REG(DC_DISP_DISP_ACTIVE);
> + ? ? ? DUMP_REG(DC_DISP_FRONT_PORCH);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
> + ? ? ? DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
> + ? ? ? DUMP_REG(DC_DISP_M0_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_M1_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_DI_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_PP_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_PP_SELECT_A);
> + ? ? ? DUMP_REG(DC_DISP_PP_SELECT_B);
> + ? ? ? DUMP_REG(DC_DISP_PP_SELECT_C);
> + ? ? ? DUMP_REG(DC_DISP_PP_SELECT_D);
> + ? ? ? DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
> + ? ? ? DUMP_REG(DC_DISP_BORDER_COLOR);
> + ? ? ? DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
> + ? ? ? DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
> + ? ? ? DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
> + ? ? ? DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_START_ADDR);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_POSITION);
> + ? ? ? DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
> + ? ? ? DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
> + ? ? ? DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
> + ? ? ? DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
> + ? ? ? DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
> + ? ? ? DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
> + ? ? ? DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
> + ? ? ? DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
> + ? ? ? DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
> + ? ? ? DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST);
> + ? ? ? DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
> + ? ? ? DUMP_REG(DC_DISP_DAC_CRT_CTRL);
> + ? ? ? DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
> +
> +
> + ? ? ? for (i = 0; i < 3; i++) {
> + ? ? ? ? ? ? ? print(data, "\n");
> + ? ? ? ? ? ? ? snprintf(buff, sizeof(buff), "WINDOW %c:\n", 'A' + i);
> + ? ? ? ? ? ? ? print(data, buff);
> +
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, WINDOW_A_SELECT << i,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_CMD_DISPLAY_WINDOW_HEADER);
> + ? ? ? ? ? ? ? DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_WIN_OPTIONS);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BYTE_SWAP);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BUFFER_CONTROL);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_COLOR_DEPTH);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_POSITION);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_SIZE);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_PRESCALED_SIZE);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_H_INITIAL_DDA);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_V_INITIAL_DDA);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_DDA_INCREMENT);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_LINE_STRIDE);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BUF_STRIDE);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BLEND_NOKEY);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BLEND_1WIN);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BLEND_2WIN_X);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BLEND_2WIN_Y);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WIN_BLEND_3WIN_XY);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WINBUF_START_ADDR);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
> + ? ? ? ? ? ? ? DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
> + ? ? ? }
> +}
> +
> +#undef DUMP_REG
> +
> +#ifdef DEBUG
> +static void dump_regs_print(void *data, const char *str)
> +{
> + ? ? ? struct tegra_dc *dc = data;
> + ? ? ? dev_dbg(&dc->pdev->dev, "%s", str);
> +}
> +
> +static void dump_regs(struct tegra_dc *dc)
> +{
> + ? ? ? _dump_regs(dc, dc, dump_regs_print);
> +}
> +#else
> +
> +static void dump_regs(struct tegra_dc *dc) {}
> +
> +#endif
> +
> +#ifdef CONFIG_DEBUG_FS
> +
> +static void dbg_regs_print(void *data, const char *str)
> +{
> + ? ? ? struct seq_file *s = data;
> +
> + ? ? ? seq_printf(s, "%s", str);
> +}
> +
> +#undef DUMP_REG
> +
> +static int dbg_dc_show(struct seq_file *s, void *unused)
> +{
> + ? ? ? struct tegra_dc *dc = s->private;
> +
> + ? ? ? _dump_regs(dc, s, dbg_regs_print);
> +
> + ? ? ? return 0;
> +}
> +
> +
> +static int dbg_dc_open(struct inode *inode, struct file *file)
> +{
> + ? ? ? return single_open(file, dbg_dc_show, inode->i_private);
> +}
> +
> +static const struct file_operations dbg_fops = {
> + ? ? ? .open ? ? ? ? ? = dbg_dc_open,
> + ? ? ? .read ? ? ? ? ? = seq_read,
> + ? ? ? .llseek ? ? ? ? = seq_lseek,
> + ? ? ? .release ? ? ? ?= single_release,
> +};
> +
> +static void tegra_dc_dbg_add(struct tegra_dc *dc)
> +{
> + ? ? ? char name[32];
> +
> + ? ? ? snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->pdev->id);
> + ? ? ? (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops);
> +}
> +#else
> +static void tegra_dc_dbg_add(struct tegra_dc *dc) {}
> +
> +#endif
> +
> +
> +static int tegra_dc_add(struct tegra_dc *dc, int index)
> +{
> + ? ? ? int ret = 0;
> +
> + ? ? ? mutex_lock(&tegra_dc_lock);
> + ? ? ? if (index >= TEGRA_MAX_DC) {
> + ? ? ? ? ? ? ? ret = -EINVAL;
> + ? ? ? ? ? ? ? goto out;
> + ? ? ? }
> +
> + ? ? ? if (tegra_dcs[index] != NULL) {
> + ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto out;
> + ? ? ? }
> +
> + ? ? ? tegra_dcs[index] = dc;
> +
> +out:
> + ? ? ? mutex_unlock(&tegra_dc_lock);
> +
> + ? ? ? return ret;
> +}
> +
> +struct tegra_dc *tegra_dc_get_dc(unsigned idx)
> +{
> + ? ? ? if (idx < TEGRA_MAX_DC)
> + ? ? ? ? ? ? ? return tegra_dcs[idx];
> + ? ? ? else
> + ? ? ? ? ? ? ? return NULL;
> +}
> +EXPORT_SYMBOL(tegra_dc_get_dc);
> +
> +struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
> +{
> + ? ? ? if (win >= dc->n_windows)
> + ? ? ? ? ? ? ? return NULL;
> +
> + ? ? ? return &dc->windows[win];
> +}
> +EXPORT_SYMBOL(tegra_dc_get_window);
> +
> +/* does not support updating windows on multiple dcs in one call */
> +int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
> +{
> + ? ? ? struct tegra_dc *dc;
> + ? ? ? unsigned long update_mask = GENERAL_ACT_REQ;
> + ? ? ? unsigned long val;
> + ? ? ? unsigned long flags;
> + ? ? ? int i;
> +
> + ? ? ? dc = windows[0]->dc;
> +
> + ? ? ? spin_lock_irqsave(&dc->lock, flags);
> + ? ? ? for (i = 0; i < n; i++) {
> + ? ? ? ? ? ? ? struct tegra_dc_win *win = windows[i];
> + ? ? ? ? ? ? ? unsigned h_dda;
> + ? ? ? ? ? ? ? unsigned v_dda;
> + ? ? ? ? ? ? ? unsigned stride;
> +
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_CMD_DISPLAY_WINDOW_HEADER);
> +
> + ? ? ? ? ? ? ? update_mask |= WIN_A_ACT_REQ << win->idx;
> +
> + ? ? ? ? ? ? ? if (!(win->flags & TEGRA_WIN_FLAG_ENABLED)) {
> + ? ? ? ? ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
> + ? ? ? ? ? ? ? ? ? ? ? continue;
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
> +
> + ? ? ? ? ? ? ? stride = win->w * tegra_dc_fmt_bpp(win->fmt) / 8;
> +
> + ? ? ? ? ? ? ? /* TODO: implement filter on settings */
> + ? ? ? ? ? ? ? h_dda = (win->w * 0x1000) / (win->out_w - 1);
> + ? ? ? ? ? ? ? v_dda = (win->h * 0x1000) / (win->out_h - 1);
> +
> + ? ? ? ? ? ? ? tegra_dc_writel(dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? V_POSITION(win->y) | H_POSITION(win->x),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WIN_POSITION);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? V_SIZE(win->out_h) | H_SIZE(win->out_w),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WIN_SIZE);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? V_PRESCALED_SIZE(win->out_h) |
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? H_PRESCALED_SIZE(stride),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WIN_PRESCALED_SIZE);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WIN_H_INITIAL_DDA);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WIN_V_INITIAL_DDA);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WIN_DDA_INCREMENT);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, stride, DC_WIN_LINE_STRIDE);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
> +
> + ? ? ? ? ? ? ? val = WIN_ENABLE;
> + ? ? ? ? ? ? ? if (win->flags & TEGRA_WIN_FLAG_COLOR_EXPAND)
> + ? ? ? ? ? ? ? ? ? ? ? val |= COLOR_EXPAND;
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
> +
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, (unsigned long)win->phys_addr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WINBUF_START_ADDR);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_H_OFFSET);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0, DC_WINBUF_ADDR_V_OFFSET);
> +
> + ? ? ? ? ? ? ? win->dirty = 1;
> +
> + ? ? ? }
> +
> + ? ? ? tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
> +
> + ? ? ? val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
> + ? ? ? val |= FRAME_END_INT;
> + ? ? ? tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
> +
> + ? ? ? val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
> + ? ? ? val |= FRAME_END_INT;
> + ? ? ? tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
> +
> + ? ? ? tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
> + ? ? ? spin_unlock_irqrestore(&dc->lock, flags);
> +
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL(tegra_dc_update_windows);
> +
> +static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int n)
> +{
> + ? ? ? int i;
> +
> + ? ? ? for (i = 0; i < n; i++) {
> + ? ? ? ? ? ? ? if (windows[i]->dirty)
> + ? ? ? ? ? ? ? ? ? ? ? return false;
> + ? ? ? }
> +
> + ? ? ? return true;
> +}
> +
> +/* does not support syncing windows on multiple dcs in one call */
> +int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
> +{
> + ? ? ? if (n < 1 || n > DC_N_WINDOWS)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? return wait_event_interruptible_timeout(windows[0]->dc->wq,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?tegra_dc_windows_are_clean(windows, n),
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?HZ);
> +}
> +EXPORT_SYMBOL(tegra_dc_sync_windows);
> +
> +void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
> +{
> + ? ? ? int i;
> +
> + ? ? ? for (i = 0; i < DC_N_WINDOWS; i++) {
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, WINDOW_A_SELECT << i,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_CMD_DISPLAY_WINDOW_HEADER);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, blend[i].nokey, DC_WIN_BLEND_NOKEY);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, blend[i].one_win, DC_WIN_BLEND_1WIN);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, blend[i].two_win_x, DC_WIN_BLEND_2WIN_X);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, blend[i].two_win_y, DC_WIN_BLEND_2WIN_Y);
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, blend[i].three_win_xy,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DC_WIN_BLEND_3WIN_XY);
> + ? ? ? }
> +}
> +EXPORT_SYMBOL(tegra_dc_set_blending);
> +
> +int tegra_dc_set_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
> +{
> + ? ? ? unsigned long val;
> + ? ? ? unsigned long rate;
> + ? ? ? unsigned long div;
> +
> + ? ? ? tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
> + ? ? ? tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_REF_TO_SYNC);
> + ? ? ? tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_SYNC_WIDTH);
> + ? ? ? tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_BACK_PORCH);
> + ? ? ? tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_DISP_ACTIVE);
> + ? ? ? tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_FRONT_PORCH);
> +
> + ? ? ? tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_DATA_ENABLE_OPTIONS);
> +
> + ? ? ? /* TODO: MIPI/CRT/HDMI clock cals */
> +
> + ? ? ? val = DISP_DATA_FORMAT_DF1P1C;
> +
> + ? ? ? if (dc->out->align == TEGRA_DC_ALIGN_MSB)
> + ? ? ? ? ? ? ? val |= DISP_DATA_ALIGNMENT_MSB;
> + ? ? ? else
> + ? ? ? ? ? ? ? val |= DISP_DATA_ALIGNMENT_LSB;
> +
> + ? ? ? if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
> + ? ? ? ? ? ? ? val |= DISP_DATA_ORDER_RED_BLUE;
> + ? ? ? else
> + ? ? ? ? ? ? ? val |= DISP_DATA_ORDER_BLUE_RED;
> +
> + ? ? ? tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
> +
> + ? ? ? rate = clk_get_rate(dc->clk);
> +
> + ? ? ? div = ((rate * 2 + mode->pclk / 2) / mode->pclk) - 2;
> +
> + ? ? ? if (rate * 2 / (div + 2) < (mode->pclk / 100 * 99) ||
> + ? ? ? ? ? rate * 2 / (div + 2) > (mode->pclk / 100 * 109)) {
> + ? ? ? ? ? ? ? dev_err(&dc->pdev->dev,
> + ? ? ? ? ? ? ? ? ? ? ? "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? rate, mode->pclk,
> + ? ? ? ? ? ? ? ? ? ? ? rate / div, (mode->pclk / 100 * 99),
> + ? ? ? ? ? ? ? ? ? ? ? (mode->pclk / 100 * 109));
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> +
> + ? ? ? tegra_dc_writel(dc, 0x00010001,
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_SHIFT_CLOCK_OPTIONS);
> + ? ? ? tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
> + ? ? ? ? ? ? ? ? ? ? ? DC_DISP_DISP_CLOCK_CONTROL);
> +
> + ? ? ? return 0;
> +}
> +EXPORT_SYMBOL(tegra_dc_set_mode);
> +
> +static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
> +{
> + ? ? ? dc->out = out;
> +
> + ? ? ? if (out->n_modes > 0)
> + ? ? ? ? ? ? ? dc->mode = &dc->out->modes[0];
> + ? ? ? else
> + ? ? ? ? ? ? ? dev_err(&dc->pdev->dev,
> + ? ? ? ? ? ? ? ? ? ? ? "No default modes specified. ?Leaving output disabled.\n");
> +
> + ? ? ? switch (out->type) {
> + ? ? ? case TEGRA_DC_OUT_RGB:
> + ? ? ? ? ? ? ? dc->out_ops = &tegra_dc_rgb_ops;
> + ? ? ? ? ? ? ? break;
> +
> + ? ? ? default:
> + ? ? ? ? ? ? ? dc->out_ops = NULL;
> + ? ? ? ? ? ? ? break;
> + ? ? ? }
> +}
> +
> +
> +static irqreturn_t tegra_dc_irq(int irq, void *ptr)
> +{
> + ? ? ? struct tegra_dc *dc = ptr;
> + ? ? ? unsigned long status;
> + ? ? ? unsigned long flags;
> + ? ? ? unsigned long val;
> + ? ? ? int i;
> +
> +
> + ? ? ? status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
> + ? ? ? tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
> +
> + ? ? ? if (status & FRAME_END_INT) {
> + ? ? ? ? ? ? ? int completed = 0;
> + ? ? ? ? ? ? ? int dirty = 0;
> +
> + ? ? ? ? ? ? ? spin_lock_irqsave(&dc->lock, flags);
> + ? ? ? ? ? ? ? val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
> + ? ? ? ? ? ? ? for (i = 0; i < DC_N_WINDOWS; i++) {
> + ? ? ? ? ? ? ? ? ? ? ? if (!(val & (WIN_A_ACT_REQ << i))) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dc->windows[i].dirty = 0;
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? completed = 1;
> + ? ? ? ? ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dirty = 1;
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? if (!dirty) {
> + ? ? ? ? ? ? ? ? ? ? ? val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
> + ? ? ? ? ? ? ? ? ? ? ? val &= ~FRAME_END_INT;
> + ? ? ? ? ? ? ? ? ? ? ? tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
> + ? ? ? ? ? ? ? }
> +
> + ? ? ? ? ? ? ? spin_unlock_irqrestore(&dc->lock, flags);
> +
> + ? ? ? ? ? ? ? if (completed)
> + ? ? ? ? ? ? ? ? ? ? ? wake_up(&dc->wq);
> + ? ? ? }
> +
> + ? ? ? return IRQ_HANDLED;
> +}
> +
> +static void tegra_dc_init(struct tegra_dc *dc)
> +{
> + ? ? ? tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
> + ? ? ? if (dc->pdev->id == 0)
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0x0000011a, DC_CMD_CONT_SYNCPT_VSYNC);
> + ? ? ? else if (dc->pdev->id == 1)
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, 0x0000011b, DC_CMD_CONT_SYNCPT_VSYNC);
> + ? ? ? tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE);
> + ? ? ? tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY);
> + ? ? ? tegra_dc_writel(dc, 0x00000020, DC_DISP_MEM_HIGH_PRIORITY);
> + ? ? ? tegra_dc_writel(dc, 0x00000001, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
> +
> + ? ? ? tegra_dc_writel(dc, 0x0001c702, DC_CMD_INT_MASK);
> + ? ? ? tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_ENABLE);
> +
> + ? ? ? if (dc->mode)
> + ? ? ? ? ? ? ? tegra_dc_set_mode(dc, dc->mode);
> +
> +
> + ? ? ? if (dc->out_ops && dc->out_ops->init)
> + ? ? ? ? ? ? ? dc->out_ops->init(dc);
> +}
> +
> +static int tegra_dc_probe(struct platform_device *pdev)
> +{
> + ? ? ? struct tegra_dc *dc;
> + ? ? ? struct clk *clk;
> + ? ? ? struct clk *host1x_clk;
> + ? ? ? struct resource *res;
> + ? ? ? struct resource *base_res;
> + ? ? ? struct resource *fb_mem = NULL;
> + ? ? ? int ret = 0;
> + ? ? ? void __iomem *base;
> + ? ? ? int irq;
> + ? ? ? int i;
> +
> + ? ? ? if (!pdev->dev.platform_data) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "no platform data\n");
> + ? ? ? ? ? ? ? return -ENOENT;
> + ? ? ? }
> +
> + ? ? ? dc = kzalloc(sizeof(struct tegra_dc), GFP_KERNEL);
> + ? ? ? if (!dc) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "can't allocate memory for tegra_dc\n");
> + ? ? ? ? ? ? ? return -ENOMEM;
> + ? ? ? }
> +
> + ? ? ? irq = platform_get_irq_byname(pdev, "irq");
> + ? ? ? if (irq <= 0) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "no irq\n");
> + ? ? ? ? ? ? ? ret = -ENOENT;
> + ? ? ? ? ? ? ? goto err_free;
> + ? ? ? }
> +
> + ? ? ? res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
> + ? ? ? if (!res) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "no mem resource\n");
> + ? ? ? ? ? ? ? ret = -ENOENT;
> + ? ? ? ? ? ? ? goto err_free;
> + ? ? ? }
> +
> + ? ? ? base_res = request_mem_region(res->start, resource_size(res), pdev->name);
> + ? ? ? if (!base_res) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "request_mem_region failed\n");
> + ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto err_free;
> + ? ? ? }
> +
> + ? ? ? base = ioremap(res->start, resource_size(res));
> + ? ? ? if (!base) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "registers can't be mapped\n");
> + ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto err_release_resource_reg;
> + ? ? ? }
> +
> + ? ? ? res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fbmem");
> + ? ? ? if (res)
> + ? ? ? ? ? ? ? fb_mem = request_mem_region(res->start, resource_size(res), pdev->name);
> +
> + ? ? ? host1x_clk = clk_get(&pdev->dev, "host1x");
> + ? ? ? if (IS_ERR_OR_NULL(host1x_clk)) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "can't get host1x clock\n");
> + ? ? ? ? ? ? ? ret = -ENOENT;
> + ? ? ? ? ? ? ? goto err_iounmap_reg;
> + ? ? ? }
> + ? ? ? clk_enable(host1x_clk);
> +
> + ? ? ? clk = clk_get(&pdev->dev, NULL);
> + ? ? ? if (IS_ERR_OR_NULL(clk)) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "can't get clock\n");
> + ? ? ? ? ? ? ? ret = -ENOENT;
> +
> + ? ? ? ? ? ? ? goto err_put_host1x_clk;
> + ? ? ? }
> + ? ? ? clk_enable(clk);
> + ? ? ? tegra_periph_reset_deassert(clk);
> +
> + ? ? ? dc->clk = clk;
> + ? ? ? dc->host1x_clk = host1x_clk;
> + ? ? ? dc->base_res = base_res;
> + ? ? ? dc->base = base;
> + ? ? ? dc->irq = irq;
> + ? ? ? dc->pdev = pdev;
> + ? ? ? dc->pdata = pdev->dev.platform_data;
> + ? ? ? spin_lock_init(&dc->lock);
> + ? ? ? init_waitqueue_head(&dc->wq);
> +
> +
> + ? ? ? dc->n_windows = DC_N_WINDOWS;
> + ? ? ? for (i = 0; i < dc->n_windows; i++) {
> + ? ? ? ? ? ? ? dc->windows[i].idx = i;
> + ? ? ? ? ? ? ? dc->windows[i].dc = dc;
> + ? ? ? }
> +
> + ? ? ? if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
> + ? ? ? ? ? ? ? ? ? ? ? dev_name(&pdev->dev), dc)) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "request_irq %d failed\n", irq);
> + ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto err_put_clk;
> + ? ? ? }
> +
> + ? ? ? ret = tegra_dc_add(dc, pdev->id);
> + ? ? ? if (ret < 0) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "can't add dc\n");
> + ? ? ? ? ? ? ? goto err_free_irq;
> + ? ? ? }
> +
> + ? ? ? if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) {
> + ? ? ? ? ? ? ? if (dc->pdata->default_out)
> + ? ? ? ? ? ? ? ? ? ? ? tegra_dc_set_out(dc, dc->pdata->default_out);
> + ? ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? ? ? ? ? dev_err(&pdev->dev, "No default output specified. ?Leaving output disabled.\n");
> + ? ? ? }
> +
> + ? ? ? tegra_dc_init(dc);
> +
> + ? ? ? tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
> +
> + ? ? ? platform_set_drvdata(pdev, dc);
> +
> + ? ? ? tegra_dc_dbg_add(dc);
> +
> + ? ? ? dev_info(&pdev->dev, "probed\n");
> +
> + ? ? ? if (fb_mem && dc->pdata->fb) {
> + ? ? ? ? ? ? ? dc->fb = tegra_fb_register(pdev, dc, dc->pdata->fb, fb_mem);
> + ? ? ? ? ? ? ? if (IS_ERR_OR_NULL(dc->fb))
> + ? ? ? ? ? ? ? ? ? ? ? dc->fb = NULL;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +
> +err_free_irq:
> + ? ? ? free_irq(irq, dc);
> +err_put_clk:
> + ? ? ? clk_disable(clk);
> + ? ? ? clk_put(clk);
> +err_put_host1x_clk:
> + ? ? ? clk_disable(host1x_clk);
> + ? ? ? clk_put(host1x_clk);
> +err_iounmap_reg:
> + ? ? ? iounmap(base);
> + ? ? ? if (fb_mem)
> + ? ? ? ? ? ? ? release_resource(fb_mem);
> +err_release_resource_reg:
> + ? ? ? release_resource(base_res);
> +err_free:
> + ? ? ? kfree(dc);
> +
> + ? ? ? return ret;
> +}
> +
> +static int tegra_dc_remove(struct platform_device *pdev)
> +{
> + ? ? ? struct tegra_dc *dc = platform_get_drvdata(pdev);
> +
> + ? ? ? if (dc->fb) {
> + ? ? ? ? ? ? ? tegra_fb_unregister(dc->fb);
> + ? ? ? ? ? ? ? release_resource(dc->fb_mem);
> + ? ? ? }
> +
> + ? ? ? free_irq(dc->irq, dc);
> + ? ? ? tegra_periph_reset_assert(dc->clk);
> + ? ? ? clk_disable(dc->clk);
> + ? ? ? clk_put(dc->clk);
> + ? ? ? clk_disable(dc->host1x_clk);
> + ? ? ? clk_put(dc->host1x_clk);
> + ? ? ? iounmap(dc->base);
> + ? ? ? release_resource(dc->base_res);
> + ? ? ? kfree(dc);
> + ? ? ? return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int tegra_dc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> + ? ? ? struct tegra_dc *dc = platform_get_drvdata(pdev);
> +
> + ? ? ? dev_info(&pdev->dev, "suspend\n");
> +
> + ? ? ? disable_irq(dc->irq);
> + ? ? ? tegra_periph_reset_assert(dc->clk);
> + ? ? ? clk_disable(dc->clk);
> +
> + ? ? ? return 0;
> +}
> +
> +static int tegra_dc_resume(struct platform_device *pdev)
> +{
> + ? ? ? struct tegra_dc *dc = platform_get_drvdata(pdev);
> + ? ? ? struct tegra_dc_win *wins[DC_N_WINDOWS];
> + ? ? ? int i;
> +
> + ? ? ? dev_info(&pdev->dev, "resume\n");
> +
> + ? ? ? clk_enable(dc->clk);
> + ? ? ? tegra_periph_reset_deassert(dc->clk);
> + ? ? ? enable_irq(dc->irq);
> +
> + ? ? ? for (i = 0; i < dc->n_windows; i++)
> + ? ? ? ? ? ? ? wins[i] = &dc->windows[i];
> +
> + ? ? ? tegra_dc_init(dc);
> +
> + ? ? ? tegra_dc_set_blending(dc, tegra_dc_blend_modes[0]);
> + ? ? ? tegra_dc_update_windows(wins, dc->n_windows);
> +
> + ? ? ? return 0;
> +}
> +
> +#endif
> +
> +extern int suspend_set(const char *val, struct kernel_param *kp)
> +{
> + ? ? ? if (!strcmp(val, "dump"))
> + ? ? ? ? ? ? ? dump_regs(tegra_dcs[0]);
> +#ifdef CONFIG_PM
> + ? ? ? else if (!strcmp(val, "suspend"))
> + ? ? ? ? ? ? ? tegra_dc_suspend(tegra_dcs[0]->pdev, PMSG_SUSPEND);
> + ? ? ? else if (!strcmp(val, "resume"))
> + ? ? ? ? ? ? ? tegra_dc_resume(tegra_dcs[0]->pdev);
> +#endif
> +
> + ? ? ? return 0;
> +}
> +
> +extern int suspend_get(char *buffer, struct kernel_param *kp)
> +{
> + ? ? ? return 0;
> +}
> +
> +int suspend;
> +
> +module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644);
> +
> +struct platform_driver tegra_dc_driver = {
> + ? ? ? .driver = {
> + ? ? ? ? ? ? ? .name = "tegradc",
> + ? ? ? ? ? ? ? .owner = THIS_MODULE,
> + ? ? ? },
> + ? ? ? .probe = tegra_dc_probe,
> + ? ? ? .remove = tegra_dc_remove,
> +#ifdef CONFIG_PM
> + ? ? ? .suspend = tegra_dc_suspend,
> + ? ? ? .resume = tegra_dc_resume,
> +#endif
> +};
> +
> +static int __init tegra_dc_module_init(void)
> +{
> + ? ? ? return platform_driver_register(&tegra_dc_driver);
> +}
> +
> +static void __exit tegra_dc_module_exit(void)
> +{
> + ? ? ? platform_driver_unregister(&tegra_dc_driver);
> +}
> +
> +module_exit(tegra_dc_module_exit);
> +module_init(tegra_dc_module_init);
> diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
> new file mode 100644
> index 0000000..b2351b1
> --- /dev/null
> +++ b/drivers/video/tegra/dc/dc_priv.h
> @@ -0,0 +1,86 @@
> +/*
> + * drivers/video/tegra/dc/dc_priv.h
> + *
> + * Copyright (C) 2010 Google, Inc.
> + * Author: Erik Gilling <konkers@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
> +#define __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
> +
> +#include <linux/wait.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +
> +struct tegra_dc;
> +
> +struct tegra_dc_out_ops {
> + ? ? ? void (*init)(struct tegra_dc *dc);
> +};
> +
> +struct tegra_dc {
> + ? ? ? struct list_head ? ? ? ? ? ? ? ?list;
> +
> + ? ? ? struct platform_device ? ? ? ? ?*pdev;
> + ? ? ? struct tegra_dc_platform_data ? *pdata;
> +
> + ? ? ? struct resource ? ? ? ? ? ? ? ? *base_res;
> + ? ? ? void __iomem ? ? ? ? ? ? ? ? ? ?*base;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? irq;
> +
> + ? ? ? struct clk ? ? ? ? ? ? ? ? ? ? ?*clk;
> + ? ? ? struct clk ? ? ? ? ? ? ? ? ? ? ?*host1x_clk;
> +
> + ? ? ? struct tegra_dc_out ? ? ? ? ? ? *out;
> + ? ? ? struct tegra_dc_out_ops ? ? ? ? *out_ops;
> +
> + ? ? ? struct tegra_dc_mode ? ? ? ? ? ?*mode;
> +
> + ? ? ? struct tegra_dc_win ? ? ? ? ? ? windows[DC_N_WINDOWS];
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? n_windows;
> +
> + ? ? ? wait_queue_head_t ? ? ? ? ? ? ? wq;
> +
> + ? ? ? spinlock_t ? ? ? ? ? ? ? ? ? ? ?lock;
> +
> + ? ? ? struct resource ? ? ? ? ? ? ? ? *fb_mem;
> + ? ? ? struct tegra_fb_info ? ? ? ? ? ?*fb;
> +};
> +
> +static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long reg)
> +{
> + ? ? ? return readl(dc->base + reg * 4);
> +}
> +
> +static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long reg)
> +{
> + ? ? ? writel(val, dc->base + reg * 4);
> +}
> +
> +static inline void _tegra_dc_write_table(struct tegra_dc *dc, const u32 *table,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned len)
> +{
> + ? ? ? int i;
> +
> + ? ? ? for (i = 0; i < len; i++)
> + ? ? ? ? ? ? ? tegra_dc_writel(dc, table[i * 2 + 1], table[i * 2]);
> +}
> +
> +#define tegra_dc_write_table(dc, table) ? ? ? ? ? ? ? ?\
> + ? ? ? _tegra_dc_write_table(dc, table, ARRAY_SIZE(table) / 2)
> +
> +extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
> +
> +#endif
> diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
> new file mode 100644
> index 0000000..6d6b3ba
> --- /dev/null
> +++ b/drivers/video/tegra/dc/dc_reg.h
> @@ -0,0 +1,342 @@
> +/*
> + * drivers/video/tegra/dc/dc_reg.h
> + *
> + * Copyright (C) 2010 Google, Inc.
> + * Author: Erik Gilling <konkers@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
> +#define __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
> +
> +#define DC_CMD_GENERAL_INCR_SYNCPT ? ? ? ? ? ? 0x000
> +#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL ? ? ? 0x001
> +#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR ? ? ? 0x002
> +#define DC_CMD_WIN_A_INCR_SYNCPT ? ? ? ? ? ? ? 0x008
> +#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL ? ? ? ? 0x009
> +#define DC_CMD_WIN_A_INCR_SYNCPT_ERROR ? ? ? ? 0x00a
> +#define DC_CMD_WIN_B_INCR_SYNCPT ? ? ? ? ? ? ? 0x010
> +#define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL ? ? ? ? 0x011
> +#define DC_CMD_WIN_B_INCR_SYNCPT_ERROR ? ? ? ? 0x012
> +#define DC_CMD_WIN_C_INCR_SYNCPT ? ? ? ? ? ? ? 0x018
> +#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL ? ? ? ? 0x019
> +#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR ? ? ? ? 0x01a
> +#define DC_CMD_CONT_SYNCPT_VSYNC ? ? ? ? ? ? ? 0x028
> +#define DC_CMD_DISPLAY_COMMAND_OPTION0 ? ? ? ? 0x031
> +#define DC_CMD_DISPLAY_COMMAND ? ? ? ? ? ? ? ? 0x032
> +#define ?DISP_COMMAND_RAISE ? ? ? ? ? ?(1 << 0)
> +#define ?DISP_CTRL_MODE_STOP ? ? ? ? ? (0 << 5)
> +#define ?DISP_CTRL_MODE_C_DISPLAY ? ? ?(1 << 5)
> +#define ?DISP_CTRL_MODE_NC_DISPLAY ? ? (2 << 5)
> +#define ?DISP_COMMAND_RAISE_VECTOR(x) ?(((x) & 0x1f) << 22)
> +#define ?DISP_COMMAND_RAISE_CHANNEL_ID(x) ? ? ?(((x) & 0xf) << 27)
> +
> +#define DC_CMD_SIGNAL_RAISE ? ? ? ? ? ? ? ? ? ?0x033
> +#define DC_CMD_DISPLAY_POWER_CONTROL ? ? ? ? ? 0x036
> +#define ?PW0_ENABLE ? ? ? ? ? ?(1 << 0)
> +#define ?PW1_ENABLE ? ? ? ? ? ?(1 << 2)
> +#define ?PW2_ENABLE ? ? ? ? ? ?(1 << 4)
> +#define ?PW3_ENABLE ? ? ? ? ? ?(1 << 6)
> +#define ?PW4_ENABLE ? ? ? ? ? ?(1 << 8)
> +#define ?PM0_ENABLE ? ? ? ? ? ?(1 << 16)
> +#define ?PM1_ENABLE ? ? ? ? ? ?(1 << 18)
> +#define ?SPI_ENABLE ? ? ? ? ? ?(1 << 24)
> +#define ?HSPI_ENABLE ? ? ? ? ? (1 << 25)
> +
> +#define DC_CMD_INT_STATUS ? ? ? ? ? ? ? ? ? ? ?0x037
> +#define DC_CMD_INT_MASK ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x038
> +#define DC_CMD_INT_ENABLE ? ? ? ? ? ? ? ? ? ? ?0x039
> +#define DC_CMD_INT_TYPE ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x03a
> +#define DC_CMD_INT_POLARITY ? ? ? ? ? ? ? ? ? ?0x03b
> +#define ?CTXSW_INT ? ? ? ? ? ? (1 << 0)
> +#define ?FRAME_END_INT ? ? ? ? (1 << 1)
> +#define ?V_BLANK_INT ? ? ? ? ? (1 << 2)
> +#define ?H_BLANK_INT ? ? ? ? ? (1 << 3)
> +#define ?V_PULSE3_INT ? ? ? ? ?(1 << 4)
> +#define ?SPI_BUSY_INT ? ? ? ? ?(1 << 7)
> +#define ?WIN_A_UF_INT ? ? ? ? ?(1 << 8)
> +#define ?WIN_B_UF_INT ? ? ? ? ?(1 << 9)
> +#define ?WIN_C_UF_INT ? ? ? ? ?(1 << 10)
> +#define ?MSF_INT ? ? ? ? ? ? ? (1 << 12)
> +#define ?SSF_INT ? ? ? ? ? ? ? (1 << 13)
> +#define ?WIN_A_OF_INT ? ? ? ? ?(1 << 14)
> +#define ?WIN_B_OF_INT ? ? ? ? ?(1 << 15)
> +#define ?WIN_C_OF_INT ? ? ? ? ?(1 << 16)
> +#define ?GPIO_0_INT ? ? ? ? ? ?(1 << 18)
> +#define ?GPIO_1_INT ? ? ? ? ? ?(1 << 19)
> +#define ?GPIO_2_INT ? ? ? ? ? ?(1 << 20)
> +
> +#define DC_CMD_SIGNAL_RAISE1 ? ? ? ? ? ? ? ? ? 0x03c
> +#define DC_CMD_SIGNAL_RAISE2 ? ? ? ? ? ? ? ? ? 0x03d
> +#define DC_CMD_SIGNAL_RAISE3 ? ? ? ? ? ? ? ? ? 0x03e
> +#define DC_CMD_STATE_ACCESS ? ? ? ? ? ? ? ? ? ?0x040
> +#define DC_CMD_STATE_CONTROL ? ? ? ? ? ? ? ? ? 0x041
> +#define ?GENERAL_ACT_REQ ? ? ? (1 << 0)
> +#define ?WIN_A_ACT_REQ ? ? ? ? (1 << 1)
> +#define ?WIN_B_ACT_REQ ? ? ? ? (1 << 2)
> +#define ?WIN_C_ACT_REQ ? ? ? ? (1 << 3)
> +
> +#define DC_CMD_DISPLAY_WINDOW_HEADER ? ? ? ? ? 0x042
> +#define ?WINDOW_A_SELECT ? ? ? ? ? ? ? (1 << 4)
> +#define ?WINDOW_B_SELECT ? ? ? ? ? ? ? (1 << 5)
> +#define ?WINDOW_C_SELECT ? ? ? ? ? ? ? (1 << 6)
> +
> +#define DC_CMD_REG_ACT_CONTROL ? ? ? ? ? ? ? ? 0x043
> +
> +#define DC_COM_CRC_CONTROL ? ? ? ? ? ? ? ? ? ? 0x300
> +#define DC_COM_CRC_CHECKSUM ? ? ? ? ? ? ? ? ? ?0x301
> +#define DC_COM_PIN_OUTPUT_ENABLE0 ? ? ? ? ? ? ?0x302
> +#define DC_COM_PIN_OUTPUT_ENABLE1 ? ? ? ? ? ? ?0x303
> +#define DC_COM_PIN_OUTPUT_ENABLE2 ? ? ? ? ? ? ?0x304
> +#define DC_COM_PIN_OUTPUT_ENABLE3 ? ? ? ? ? ? ?0x305
> +#define DC_COM_PIN_OUTPUT_POLARITY0 ? ? ? ? ? ?0x306
> +#define DC_COM_PIN_OUTPUT_POLARITY1 ? ? ? ? ? ?0x307
> +#define DC_COM_PIN_OUTPUT_POLARITY2 ? ? ? ? ? ?0x308
> +#define DC_COM_PIN_OUTPUT_POLARITY3 ? ? ? ? ? ?0x309
> +#define DC_COM_PIN_OUTPUT_DATA0 ? ? ? ? ? ? ? ? ? ? ? ?0x30a
> +#define DC_COM_PIN_OUTPUT_DATA1 ? ? ? ? ? ? ? ? ? ? ? ?0x30b
> +#define DC_COM_PIN_OUTPUT_DATA2 ? ? ? ? ? ? ? ? ? ? ? ?0x30c
> +#define DC_COM_PIN_OUTPUT_DATA3 ? ? ? ? ? ? ? ? ? ? ? ?0x30d
> +#define DC_COM_PIN_INPUT_ENABLE0 ? ? ? ? ? ? ? 0x30e
> +#define DC_COM_PIN_INPUT_ENABLE1 ? ? ? ? ? ? ? 0x30f
> +#define DC_COM_PIN_INPUT_ENABLE2 ? ? ? ? ? ? ? 0x310
> +#define DC_COM_PIN_INPUT_ENABLE3 ? ? ? ? ? ? ? 0x311
> +#define DC_COM_PIN_INPUT_DATA0 ? ? ? ? ? ? ? ? 0x312
> +#define DC_COM_PIN_INPUT_DATA1 ? ? ? ? ? ? ? ? 0x313
> +#define DC_COM_PIN_OUTPUT_SELECT0 ? ? ? ? ? ? ?0x314
> +#define DC_COM_PIN_OUTPUT_SELECT1 ? ? ? ? ? ? ?0x315
> +#define DC_COM_PIN_OUTPUT_SELECT2 ? ? ? ? ? ? ?0x316
> +#define DC_COM_PIN_OUTPUT_SELECT3 ? ? ? ? ? ? ?0x317
> +#define DC_COM_PIN_OUTPUT_SELECT4 ? ? ? ? ? ? ?0x318
> +#define DC_COM_PIN_OUTPUT_SELECT5 ? ? ? ? ? ? ?0x319
> +#define DC_COM_PIN_OUTPUT_SELECT6 ? ? ? ? ? ? ?0x31a
> +#define DC_COM_PIN_MISC_CONTROL ? ? ? ? ? ? ? ? ? ? ? ?0x31b
> +#define DC_COM_PM0_CONTROL ? ? ? ? ? ? ? ? ? ? 0x31c
> +#define DC_COM_PM0_DUTY_CYCLE ? ? ? ? ? ? ? ? ?0x31d
> +#define DC_COM_PM1_CONTROL ? ? ? ? ? ? ? ? ? ? 0x31e
> +#define DC_COM_PM1_DUTY_CYCLE ? ? ? ? ? ? ? ? ?0x31f
> +#define DC_COM_SPI_CONTROL ? ? ? ? ? ? ? ? ? ? 0x320
> +#define DC_COM_SPI_START_BYTE ? ? ? ? ? ? ? ? ?0x321
> +#define DC_COM_HSPI_WRITE_DATA_AB ? ? ? ? ? ? ?0x322
> +#define DC_COM_HSPI_WRITE_DATA_CD ? ? ? ? ? ? ?0x323
> +#define DC_COM_HSPI_CS_DC ? ? ? ? ? ? ? ? ? ? ?0x324
> +#define DC_COM_SCRATCH_REGISTER_A ? ? ? ? ? ? ?0x325
> +#define DC_COM_SCRATCH_REGISTER_B ? ? ? ? ? ? ?0x326
> +#define DC_COM_GPIO_CTRL ? ? ? ? ? ? ? ? ? ? ? 0x327
> +#define DC_COM_GPIO_DEBOUNCE_COUNTER ? ? ? ? ? 0x328
> +#define DC_COM_CRC_CHECKSUM_LATCHED ? ? ? ? ? ?0x329
> +
> +#define DC_DISP_DISP_SIGNAL_OPTIONS0 ? ? ? ? ? 0x400
> +#define DC_DISP_DISP_SIGNAL_OPTIONS1 ? ? ? ? ? 0x401
> +#define DC_DISP_DISP_WIN_OPTIONS ? ? ? ? ? ? ? 0x402
> +#define DC_DISP_MEM_HIGH_PRIORITY ? ? ? ? ? ? ?0x403
> +#define DC_DISP_MEM_HIGH_PRIORITY_TIMER ? ? ? ? ? ? ? ?0x404
> +#define DC_DISP_DISP_TIMING_OPTIONS ? ? ? ? ? ?0x405
> +#define DC_DISP_REF_TO_SYNC ? ? ? ? ? ? ? ? ? ?0x406
> +#define DC_DISP_SYNC_WIDTH ? ? ? ? ? ? ? ? ? ? 0x407
> +#define DC_DISP_BACK_PORCH ? ? ? ? ? ? ? ? ? ? 0x408
> +#define DC_DISP_DISP_ACTIVE ? ? ? ? ? ? ? ? ? ?0x409
> +#define DC_DISP_FRONT_PORCH ? ? ? ? ? ? ? ? ? ?0x40a
> +#define DC_DISP_H_PULSE0_CONTROL ? ? ? ? ? ? ? 0x40b
> +#define DC_DISP_H_PULSE0_POSITION_A ? ? ? ? ? ?0x40c
> +#define DC_DISP_H_PULSE0_POSITION_B ? ? ? ? ? ?0x40d
> +#define DC_DISP_H_PULSE0_POSITION_C ? ? ? ? ? ?0x40e
> +#define DC_DISP_H_PULSE0_POSITION_D ? ? ? ? ? ?0x40f
> +#define DC_DISP_H_PULSE1_CONTROL ? ? ? ? ? ? ? 0x410
> +#define DC_DISP_H_PULSE1_POSITION_A ? ? ? ? ? ?0x411
> +#define DC_DISP_H_PULSE1_POSITION_B ? ? ? ? ? ?0x412
> +#define DC_DISP_H_PULSE1_POSITION_C ? ? ? ? ? ?0x413
> +#define DC_DISP_H_PULSE1_POSITION_D ? ? ? ? ? ?0x414
> +#define DC_DISP_H_PULSE2_CONTROL ? ? ? ? ? ? ? 0x415
> +#define DC_DISP_H_PULSE2_POSITION_A ? ? ? ? ? ?0x416
> +#define DC_DISP_H_PULSE2_POSITION_B ? ? ? ? ? ?0x417
> +#define DC_DISP_H_PULSE2_POSITION_C ? ? ? ? ? ?0x418
> +#define DC_DISP_H_PULSE2_POSITION_D ? ? ? ? ? ?0x419
> +#define DC_DISP_V_PULSE0_CONTROL ? ? ? ? ? ? ? 0x41a
> +#define DC_DISP_V_PULSE0_POSITION_A ? ? ? ? ? ?0x41b
> +#define DC_DISP_V_PULSE0_POSITION_B ? ? ? ? ? ?0x41c
> +#define DC_DISP_V_PULSE0_POSITION_C ? ? ? ? ? ?0x41d
> +#define DC_DISP_V_PULSE1_CONTROL ? ? ? ? ? ? ? 0x41e
> +#define DC_DISP_V_PULSE1_POSITION_A ? ? ? ? ? ?0x41f
> +#define DC_DISP_V_PULSE1_POSITION_B ? ? ? ? ? ?0x420
> +#define DC_DISP_V_PULSE1_POSITION_C ? ? ? ? ? ?0x421
> +#define DC_DISP_V_PULSE2_CONTROL ? ? ? ? ? ? ? 0x422
> +#define DC_DISP_V_PULSE2_POSITION_A ? ? ? ? ? ?0x423
> +#define DC_DISP_V_PULSE3_CONTROL ? ? ? ? ? ? ? 0x424
> +#define DC_DISP_V_PULSE3_POSITION_A ? ? ? ? ? ?0x425
> +#define DC_DISP_M0_CONTROL ? ? ? ? ? ? ? ? ? ? 0x426
> +#define DC_DISP_M1_CONTROL ? ? ? ? ? ? ? ? ? ? 0x427
> +#define DC_DISP_DI_CONTROL ? ? ? ? ? ? ? ? ? ? 0x428
> +#define DC_DISP_PP_CONTROL ? ? ? ? ? ? ? ? ? ? 0x429
> +#define DC_DISP_PP_SELECT_A ? ? ? ? ? ? ? ? ? ?0x42a
> +#define DC_DISP_PP_SELECT_B ? ? ? ? ? ? ? ? ? ?0x42b
> +#define DC_DISP_PP_SELECT_C ? ? ? ? ? ? ? ? ? ?0x42c
> +#define DC_DISP_PP_SELECT_D ? ? ? ? ? ? ? ? ? ?0x42d
> +#define DC_DISP_DISP_CLOCK_CONTROL ? ? ? ? ? ? 0x42e
> +#define ?PIXEL_CLK_DIVIDER_PCD1 ? ? ? ? ? ? ? ?(0 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD1H ? ? ? (1 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD2 ? ? ? ? ? ? ? ?(2 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD3 ? ? ? ? ? ? ? ?(3 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD4 ? ? ? ? ? ? ? ?(4 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD6 ? ? ? ? ? ? ? ?(5 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD8 ? ? ? ? ? ? ? ?(6 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD9 ? ? ? ? ? ? ? ?(7 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD12 ? ? ? (8 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD16 ? ? ? (9 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD18 ? ? ? (10 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD24 ? ? ? (11 << 8)
> +#define ?PIXEL_CLK_DIVIDER_PCD13 ? ? ? (12 << 8)
> +#define ?SHIFT_CLK_DIVIDER(x) ? ? ? ? ?((x) & 0xff)
> +
> +#define DC_DISP_DISP_INTERFACE_CONTROL ? ? ? ? 0x42f
> +#define ?DISP_DATA_FORMAT_DF1P1C ? ? ? (0 << 0)
> +#define ?DISP_DATA_FORMAT_DF1P2C24B ? ?(1 << 0)
> +#define ?DISP_DATA_FORMAT_DF1P2C18B ? ?(2 << 0)
> +#define ?DISP_DATA_FORMAT_DF1P2C16B ? ?(3 << 0)
> +#define ?DISP_DATA_FORMAT_DF2S ? ? ? ? (5 << 0)
> +#define ?DISP_DATA_FORMAT_DF3S ? ? ? ? (6 << 0)
> +#define ?DISP_DATA_FORMAT_DFSPI ? ? ? ? ? ? ? ?(7 << 0)
> +#define ?DISP_DATA_FORMAT_DF1P3C24B ? ?(8 << 0)
> +#define ?DISP_DATA_FORMAT_DF1P3C18B ? ?(9 << 0)
> +#define ?DISP_DATA_ALIGNMENT_MSB ? ? ? (0 << 8)
> +#define ?DISP_DATA_ALIGNMENT_LSB ? ? ? (1 << 8)
> +#define ?DISP_DATA_ORDER_RED_BLUE ? ? ?(0 << 9)
> +#define ?DISP_DATA_ORDER_BLUE_RED ? ? ?(1 << 9)
> +
> +#define DC_DISP_DISP_COLOR_CONTROL ? ? ? ? ? ? 0x430
> +#define DC_DISP_SHIFT_CLOCK_OPTIONS ? ? ? ? ? ?0x431
> +#define DC_DISP_DATA_ENABLE_OPTIONS ? ? ? ? ? ?0x432
> +#define ? DE_SELECT_ACTIVE_BLANK ? ? ? 0x0
> +#define ? DE_SELECT_ACTIVE ? ? ? ? ? ? 0x1
> +#define ? DE_SELECT_ACTIVE_IS ? ? ? ? ?0x2
> +#define ? DE_CONTROL_ONECLK ? ? ? ? ? ?(0 << 2)
> +#define ? DE_CONTROL_NORMAL ? ? ? ? ? ?(1 << 2)
> +#define ? DE_CONTROL_EARLY_EXT ? ? ? ? (2 << 2)
> +#define ? DE_CONTROL_EARLY ? ? ? ? ? ? (3 << 2)
> +#define ? DE_CONTROL_ACTIVE_BLANK ? ? ?(4 << 2)
> +
> +#define DC_DISP_SERIAL_INTERFACE_OPTIONS ? ? ? 0x433
> +#define DC_DISP_LCD_SPI_OPTIONS ? ? ? ? ? ? ? ? ? ? ? ?0x434
> +#define DC_DISP_BORDER_COLOR ? ? ? ? ? ? ? ? ? 0x435
> +#define DC_DISP_COLOR_KEY0_LOWER ? ? ? ? ? ? ? 0x436
> +#define DC_DISP_COLOR_KEY0_UPPER ? ? ? ? ? ? ? 0x437
> +#define DC_DISP_COLOR_KEY1_LOWER ? ? ? ? ? ? ? 0x438
> +#define DC_DISP_COLOR_KEY1_UPPER ? ? ? ? ? ? ? 0x439
> +#define DC_DISP_CURSOR_FOREGROUND ? ? ? ? ? ? ?0x43c
> +#define DC_DISP_CURSOR_BACKGROUND ? ? ? ? ? ? ?0x43d
> +#define DC_DISP_CURSOR_START_ADDR ? ? ? ? ? ? ?0x43e
> +#define DC_DISP_CURSOR_START_ADDR_NS ? ? ? ? ? 0x43f
> +#define DC_DISP_CURSOR_POSITION ? ? ? ? ? ? ? ? ? ? ? ?0x440
> +#define DC_DISP_CURSOR_POSITION_NS ? ? ? ? ? ? 0x441
> +#define DC_DISP_INIT_SEQ_CONTROL ? ? ? ? ? ? ? 0x442
> +#define DC_DISP_SPI_INIT_SEQ_DATA_A ? ? ? ? ? ?0x443
> +#define DC_DISP_SPI_INIT_SEQ_DATA_B ? ? ? ? ? ?0x444
> +#define DC_DISP_SPI_INIT_SEQ_DATA_C ? ? ? ? ? ?0x445
> +#define DC_DISP_SPI_INIT_SEQ_DATA_D ? ? ? ? ? ?0x446
> +#define DC_DISP_DC_MCCIF_FIFOCTRL ? ? ? ? ? ? ?0x480
> +#define DC_DISP_MCCIF_DISPLAY0A_HYST ? ? ? ? ? 0x481
> +#define DC_DISP_MCCIF_DISPLAY0B_HYST ? ? ? ? ? 0x482
> +#define DC_DISP_MCCIF_DISPLAY0C_HYST ? ? ? ? ? 0x483
> +#define DC_DISP_MCCIF_DISPLAY1B_HYST ? ? ? ? ? 0x484
> +#define DC_DISP_DAC_CRT_CTRL ? ? ? ? ? ? ? ? ? 0x4c0
> +#define DC_DISP_DISP_MISC_CONTROL ? ? ? ? ? ? ?0x4c1
> +
> +#define DC_WINC_COLOR_PALETTE(x) ? ? ? ? ? ? ? (0x500 + (x))
> +
> +#define DC_WINC_PALETTE_COLOR_EXT ? ? ? ? ? ? ?0x600
> +#define DC_WINC_H_FILTER_P(x) ? ? ? ? ? ? ? ? ?(0x601 + (x))
> +#define DC_WINC_CSC_YOF ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x611
> +#define DC_WINC_CSC_KYRGB ? ? ? ? ? ? ? ? ? ? ?0x612
> +#define DC_WINC_CSC_KUR ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x613
> +#define DC_WINC_CSC_KVR ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x614
> +#define DC_WINC_CSC_KUG ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x615
> +#define DC_WINC_CSC_KVG ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x616
> +#define DC_WINC_CSC_KUB ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x617
> +#define DC_WINC_CSC_KVB ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x618
> +#define DC_WINC_V_FILTER_P(x) ? ? ? ? ? ? ? ? ?(0x619 + (x))
> +#define DC_WIN_WIN_OPTIONS ? ? ? ? ? ? ? ? ? ? 0x700
> +#define ?H_DIRECTION_INCREMENT ? ? ? ? (0 << 0)
> +#define ?H_DIRECTION_DECREMENTT ? ? ? ? ? ? ? ?(1 << 0)
> +#define ?V_DIRECTION_INCREMENT ? ? ? ? (0 << 2)
> +#define ?V_DIRECTION_DECREMENTT ? ? ? ? ? ? ? ?(1 << 2)
> +#define ?COLOR_EXPAND ? ? ? ? ? ? ? ? ?(1 << 6)
> +#define ?CP_ENABLE ? ? ? ? ? ? ? ? ? ? (1 << 16)
> +#define ?DV_ENABLE ? ? ? ? ? ? ? ? ? ? (1 << 20)
> +#define ?WIN_ENABLE ? ? ? ? ? ? ? ? ? ?(1 << 30)
> +
> +#define DC_WIN_BYTE_SWAP ? ? ? ? ? ? ? ? ? ? ? 0x701
> +#define ?BYTE_SWAP_NOSWAP ? ? ? ? ? ? ?0
> +#define ?BYTE_SWAP_SWAP2 ? ? ? ? ? ? ? 1
> +#define ?BYTE_SWAP_SWAP4 ? ? ? ? ? ? ? 2
> +#define ?BYTE_SWAP_SWAP4HW ? ? ? ? ? ? 3
> +
> +#define DC_WIN_BUFFER_CONTROL ? ? ? ? ? ? ? ? ?0x702
> +#define ?BUFFER_CONTROL_HOST ? ? ? ? ? 0
> +#define ?BUFFER_CONTROL_VI ? ? ? ? ? ? 1
> +#define ?BUFFER_CONTROL_EPP ? ? ? ? ? ?2
> +#define ?BUFFER_CONTROL_MPEGE ? ? ? ? ?3
> +#define ?BUFFER_CONTROL_SB2D ? ? ? ? ? 4
> +
> +#define DC_WIN_COLOR_DEPTH ? ? ? ? ? ? ? ? ? ? 0x703
> +
> +#define DC_WIN_POSITION ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x704
> +#define ?H_POSITION(x) ? ? ? ? (((x) & 0xfff) << 0)
> +#define ?V_POSITION(x) ? ? ? ? (((x) & 0xfff) << 16)
> +
> +#define DC_WIN_SIZE ? ? ? ? ? ? ? ? ? ? ? ? ? ?0x705
> +#define ?H_SIZE(x) ? ? ? ? ? ? (((x) & 0xfff) << 0)
> +#define ?V_SIZE(x) ? ? ? ? ? ? (((x) & 0xfff) << 16)
> +
> +#define DC_WIN_PRESCALED_SIZE ? ? ? ? ? ? ? ? ?0x706
> +#define ?H_PRESCALED_SIZE(x) ? (((x) & 0x3fff) << 0)
> +#define ?V_PRESCALED_SIZE(x) ? (((x) & 0xfff) << 16)
> +
> +#define DC_WIN_H_INITIAL_DDA ? ? ? ? ? ? ? ? ? 0x707
> +#define DC_WIN_V_INITIAL_DDA ? ? ? ? ? ? ? ? ? 0x708
> +#define DC_WIN_DDA_INCREMENT ? ? ? ? ? ? ? ? ? 0x709
> +#define ?H_DDA_INC(x) ? ? ? ? ?(((x) & 0xffff) << 0)
> +#define ?V_DDA_INC(x) ? ? ? ? ?(((x) & 0xffff) << 16)
> +
> +#define DC_WIN_LINE_STRIDE ? ? ? ? ? ? ? ? ? ? 0x70a
> +#define DC_WIN_BUF_STRIDE ? ? ? ? ? ? ? ? ? ? ?0x70b
> +#define DC_WIN_UV_BUF_STRIDE ? ? ? ? ? ? ? ? ? 0x70c
> +#define DC_WIN_BUFFER_ADDR_MODE ? ? ? ? ? ? ? ? ? ? ? ?0x70d
> +#define DC_WIN_DV_CONTROL ? ? ? ? ? ? ? ? ? ? ?0x70e
> +#define DC_WIN_BLEND_NOKEY ? ? ? ? ? ? ? ? ? ? 0x70f
> +#define DC_WIN_BLEND_1WIN ? ? ? ? ? ? ? ? ? ? ?0x710
> +#define DC_WIN_BLEND_2WIN_X ? ? ? ? ? ? ? ? ? ?0x711
> +#define DC_WIN_BLEND_2WIN_Y ? ? ? ? ? ? ? ? ? ?0x712
> +#define DC_WIN_BLEND_3WIN_XY ? ? ? ? ? ? ? ? ? 0x713
> +#define ?CKEY_NOKEY ? ? ? ? ? ? ? ? ? ?(0 << 0)
> +#define ?CKEY_KEY0 ? ? ? ? ? ? ? ? ? ? (1 << 0)
> +#define ?CKEY_KEY1 ? ? ? ? ? ? ? ? ? ? (2 << 0)
> +#define ?CKEY_KEY01 ? ? ? ? ? ? ? ? ? ?(3 << 0)
> +#define ?BLEND_CONTROL_FIX ? ? ? ? ? ? (0 << 2)
> +#define ?BLEND_CONTROL_ALPHA ? ? ? ? ? (1 << 2)
> +#define ?BLEND_CONTROL_DEPENDANT ? ? ? (2 << 2)
> +#define ?BLEND_WEIGHT0(x) ? ? ? ? ? ? ?(((x) & 0xff) << 8)
> +#define ?BLEND_WEIGHT1(x) ? ? ? ? ? ? ?(((x) & 0xff) << 16)
> +
> +#define DC_WIN_HP_FETCH_CONTROL ? ? ? ? ? ? ? ? ? ? ? ?0x714
> +#define DC_WINBUF_START_ADDR ? ? ? ? ? ? ? ? ? 0x800
> +#define DC_WINBUF_START_ADDR_NS ? ? ? ? ? ? ? ? ? ? ? ?0x801
> +#define DC_WINBUF_START_ADDR_U ? ? ? ? ? ? ? ? 0x802
> +#define DC_WINBUF_START_ADDR_U_NS ? ? ? ? ? ? ?0x803
> +#define DC_WINBUF_START_ADDR_V ? ? ? ? ? ? ? ? 0x804
> +#define DC_WINBUF_START_ADDR_V_NS ? ? ? ? ? ? ?0x805
> +#define DC_WINBUF_ADDR_H_OFFSET ? ? ? ? ? ? ? ? ? ? ? ?0x806
> +#define DC_WINBUF_ADDR_H_OFFSET_NS ? ? ? ? ? ? 0x807
> +#define DC_WINBUF_ADDR_V_OFFSET ? ? ? ? ? ? ? ? ? ? ? ?0x808
> +#define DC_WINBUF_ADDR_V_OFFSET_NS ? ? ? ? ? ? 0x809
> +#define DC_WINBUF_UFLOW_STATUS ? ? ? ? ? ? ? ? 0x80a
> +
> +#endif
> diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
> new file mode 100644
> index 0000000..de1a8fa
> --- /dev/null
> +++ b/drivers/video/tegra/dc/rgb.c
> @@ -0,0 +1,63 @@
> +/*
> + * drivers/video/tegra/dc/rgb.c
> + *
> + * Copyright (C) 2010 Google, Inc.
> + * Author: Erik Gilling <konkers@android.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +
> +#include <mach/dc.h>
> +
> +#include "dc_reg.h"
> +#include "dc_priv.h"
> +
> +
> +static const u32 tegra_dc_rgb_pintable[] = {
> + ? ? ? DC_COM_PIN_OUTPUT_ENABLE0, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_ENABLE1, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_ENABLE2, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_ENABLE3, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_POLARITY0, ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_POLARITY1, ? ?0x01000000,
> + ? ? ? DC_COM_PIN_OUTPUT_POLARITY2, ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_POLARITY3, ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_DATA0, ? ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_DATA1, ? ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_DATA2, ? ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_DATA3, ? ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT0, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT1, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT2, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT3, ? ? ?0x00000000,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT4, ? ? ?0x00210222,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT5, ? ? ?0x00002200,
> + ? ? ? DC_COM_PIN_OUTPUT_SELECT6, ? ? ?0x00020000,
> +};
> +
> +
> +void tegra_dc_rgb_init(struct tegra_dc *dc)
> +{
> + ? ? ? tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
> + ? ? ? ? ? ? ? ? ? ? ? PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
> + ? ? ? ? ? ? ? ? ? ? ? DC_CMD_DISPLAY_POWER_CONTROL);
> +
> + ? ? ? tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
> +
> + ? ? ? tegra_dc_write_table(dc, tegra_dc_rgb_pintable);
> +}
> +
> +struct tegra_dc_out_ops tegra_dc_rgb_ops = {
> + ? ? ? .init = tegra_dc_rgb_init,
> +};
> +
> diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
> new file mode 100644
> index 0000000..4db3958
> --- /dev/null
> +++ b/drivers/video/tegra/fb.c
> @@ -0,0 +1,311 @@
> +/*
> + * drivers/video/tegra/fb.c
> + *
> + * Copyright (C) 2010 Google, Inc.
> + * Author: Erik Gilling <konkers@android.com>
> + * ? ? ? ? Colin Cross <ccross@android.com>
> + * ? ? ? ? Travis Geiselbrecht <travis@palm.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/fb.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +
> +#include <asm/atomic.h>
> +
> +#include <mach/dc.h>
> +#include <mach/fb.h>
> +
> +struct tegra_fb_info {
> + ? ? ? struct tegra_dc_win ? ? *win;
> + ? ? ? struct platform_device ?*pdev;
> + ? ? ? struct fb_info ? ? ? ? ?*info;
> +
> + ? ? ? struct resource ? ? ? ? *fb_mem;
> +
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? xres;
> + ? ? ? int ? ? ? ? ? ? ? ? ? ? yres;
> +
> + ? ? ? atomic_t ? ? ? ? ? ? ? ?in_use;
> +};
> +
> +/* palette array used by the fbcon */
> +static u32 pseudo_palette[16];
> +
> +static int tegra_fb_open(struct fb_info *info, int user)
> +{
> + ? ? ? struct tegra_fb_info *tegra_fb = info->par;
> +
> + ? ? ? if (atomic_xchg(&tegra_fb->in_use, 1))
> + ? ? ? ? ? ? ? return -EBUSY;
> +
> + ? ? ? return 0;
> +}
> +
> +static int tegra_fb_release(struct fb_info *info, int user)
> +{
> + ? ? ? struct tegra_fb_info *tegra_fb = info->par;
> +
> + ? ? ? WARN_ON(!atomic_xchg(&tegra_fb->in_use, 0));
> +
> + ? ? ? return 0;
> +}
> +
> +static int tegra_fb_check_var(struct fb_var_screeninfo *var,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct fb_info *info)
> +{
> + ? ? ? if ((var->xres != info->var.xres) ||
> + ? ? ? ? ? (var->yres != info->var.yres) ||
> + ? ? ? ? ? (var->xres_virtual != info->var.xres_virtual) ||
> + ? ? ? ? ? (var->yres_virtual != info->var.yres_virtual) ||
> + ? ? ? ? ? (var->grayscale != info->var.grayscale))
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? return 0;
> +}
> +
> +static int tegra_fb_set_par(struct fb_info *info)
> +{
> + ? ? ? struct tegra_fb_info *tegra_fb = info->par;
> + ? ? ? struct fb_var_screeninfo *var = &info->var;
> +
> + ? ? ? /* we only support RGB ordering for now */
> + ? ? ? switch (var->bits_per_pixel) {
> + ? ? ? case 32:
> + ? ? ? case 24:
> + ? ? ? ? ? ? ? var->red.offset = 0;
> + ? ? ? ? ? ? ? var->red.length = 8;
> + ? ? ? ? ? ? ? var->green.offset = 8;
> + ? ? ? ? ? ? ? var->green.length = 8;
> + ? ? ? ? ? ? ? var->blue.offset = 16;
> + ? ? ? ? ? ? ? var->blue.length = 8;
> + ? ? ? ? ? ? ? tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
> + ? ? ? ? ? ? ? break;
> + ? ? ? case 16:
> + ? ? ? ? ? ? ? var->red.offset = 11;
> + ? ? ? ? ? ? ? var->red.length = 5;
> + ? ? ? ? ? ? ? var->green.offset = 5;
> + ? ? ? ? ? ? ? var->green.length = 6;
> + ? ? ? ? ? ? ? var->blue.offset = 0;
> + ? ? ? ? ? ? ? var->blue.length = 5;
> + ? ? ? ? ? ? ? tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
> + ? ? ? ? ? ? ? break;
> + ? ? ? default:
> + ? ? ? ? ? ? ? return -EINVAL;
> + ? ? ? }
> + ? ? ? info->fix.line_length = var->xres * var->bits_per_pixel / 8;
> +
> + ? ? ? tegra_dc_update_windows(&tegra_fb->win, 1);
> +
> + ? ? ? return 0;
> +}
> +
> +static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
> + ? ? ? unsigned blue, unsigned transp, struct fb_info *info)
> +{
> + ? ? ? struct fb_var_screeninfo *var = &info->var;
> +
> + ? ? ? if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
> + ? ? ? ? ? info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
> + ? ? ? ? ? ? ? u32 v;
> +
> + ? ? ? ? ? ? ? if (regno >= 16)
> + ? ? ? ? ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? ? ? ? ? v = (red << var->red.offset) |
> + ? ? ? ? ? ? ? ? ? ? ? (green << var->green.offset) |
> + ? ? ? ? ? ? ? ? ? ? ? (blue << var->blue.offset);
> +
> + ? ? ? ? ? ? ? ((u32 *)info->pseudo_palette)[regno] = v;
> + ? ? ? }
> +
> + ? ? ? return 0;
> +}
> +
> +static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct fb_info *info)
> +{
> + ? ? ? struct tegra_fb_info *tegra_fb = info->par;
> + ? ? ? char __iomem *flush_start;
> + ? ? ? char __iomem *flush_end;
> + ? ? ? u32 addr;
> +
> + ? ? ? flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
> + ? ? ? flush_end = flush_start + (var->yres * info->fix.line_length);
> +
> + ? ? ? info->var.xoffset = var->xoffset;
> + ? ? ? info->var.yoffset = var->yoffset;
> +
> + ? ? ? addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
> + ? ? ? ? ? ? ? (var->xoffset * (var->bits_per_pixel/8));
> +
> + ? ? ? tegra_fb->win->phys_addr = addr;
> + ? ? ? /* TODO: update virt_addr */
> +
> + ? ? ? tegra_dc_update_windows(&tegra_fb->win, 1);
> + ? ? ? tegra_dc_sync_windows(&tegra_fb->win, 1);
> +
> + ? ? ? return 0;
> +}
> +
> +static void tegra_fb_fillrect(struct fb_info *info,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct fb_fillrect *rect)
> +{
> + ? ? ? cfb_fillrect(info, rect);
> +}
> +
> +static void tegra_fb_copyarea(struct fb_info *info,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? const struct fb_copyarea *region)
> +{
> + ? ? ? cfb_copyarea(info, region);
> +}
> +
> +static void tegra_fb_imageblit(struct fb_info *info,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const struct fb_image *image)
> +{
> + ? ? ? cfb_imageblit(info, image);
> +}
> +
> +static struct fb_ops tegra_fb_ops = {
> + ? ? ? .owner = THIS_MODULE,
> + ? ? ? .fb_open = tegra_fb_open,
> + ? ? ? .fb_release = tegra_fb_release,
> + ? ? ? .fb_check_var = tegra_fb_check_var,
> + ? ? ? .fb_set_par = tegra_fb_set_par,
> + ? ? ? .fb_setcolreg = tegra_fb_setcolreg,
> + ? ? ? .fb_pan_display = tegra_fb_pan_display,
> + ? ? ? .fb_fillrect = tegra_fb_fillrect,
> + ? ? ? .fb_copyarea = tegra_fb_copyarea,
> + ? ? ? .fb_imageblit = tegra_fb_imageblit,
> +};
> +
> +struct tegra_fb_info *tegra_fb_register(struct platform_device *pdev,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_dc *dc,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct tegra_fb_data *fb_data,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct resource *fb_mem)
> +{
> + ? ? ? struct tegra_dc_win *win;
> + ? ? ? struct fb_info *info;
> + ? ? ? struct tegra_fb_info *tegra_fb;
> + ? ? ? void __iomem *fb_base;
> + ? ? ? unsigned long fb_size;
> + ? ? ? unsigned long fb_phys;
> + ? ? ? int ret = 0;
> +
> + ? ? ? win = tegra_dc_get_window(dc, fb_data->win);
> + ? ? ? if (!win) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "dc does not have a window at index %d\n",
> + ? ? ? ? ? ? ? ? ? ? ? fb_data->win);
> + ? ? ? ? ? ? ? return ERR_PTR(-ENOENT);
> + ? ? ? }
> +
> + ? ? ? info = framebuffer_alloc(sizeof(struct tegra_fb_info), &pdev->dev);
> + ? ? ? if (!info) {
> + ? ? ? ? ? ? ? ret = -ENOMEM;
> + ? ? ? ? ? ? ? goto err;
> + ? ? ? }
> +
> + ? ? ? fb_size = resource_size(fb_mem);
> + ? ? ? fb_phys = fb_mem->start;
> + ? ? ? fb_base = ioremap_nocache(fb_phys, fb_size);
> + ? ? ? if (!fb_base) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "fb can't be mapped\n");
> + ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto err_free;
> + ? ? ? }
> +
> + ? ? ? tegra_fb = info->par;
> + ? ? ? tegra_fb->win = win;
> + ? ? ? tegra_fb->pdev = pdev;
> + ? ? ? tegra_fb->fb_mem = fb_mem;
> + ? ? ? tegra_fb->xres = fb_data->xres;
> + ? ? ? tegra_fb->yres = fb_data->yres;
> + ? ? ? atomic_set(&tegra_fb->in_use, 0);
> +
> + ? ? ? info->fbops = &tegra_fb_ops;
> + ? ? ? info->pseudo_palette = pseudo_palette;
> + ? ? ? info->screen_base = fb_base;
> + ? ? ? info->screen_size = fb_size;
> +
> + ? ? ? strlcpy(info->fix.id, "tegra_fb", sizeof(info->fix.id));
> + ? ? ? info->fix.type ? ? ? ? ?= FB_TYPE_PACKED_PIXELS;
> + ? ? ? info->fix.visual ? ? ? ?= FB_VISUAL_TRUECOLOR;
> + ? ? ? info->fix.xpanstep ? ? ?= 1;
> + ? ? ? info->fix.ypanstep ? ? ?= 1;
> + ? ? ? info->fix.accel ? ? ? ? = FB_ACCEL_NONE;
> + ? ? ? info->fix.smem_start ? ?= fb_phys;
> + ? ? ? info->fix.smem_len ? ? ?= fb_size;
> +
> + ? ? ? info->var.xres ? ? ? ? ? ? ? ? ?= fb_data->xres;
> + ? ? ? info->var.yres ? ? ? ? ? ? ? ? ?= fb_data->yres;
> + ? ? ? info->var.xres_virtual ? ? ? ? ?= fb_data->xres;
> + ? ? ? info->var.yres_virtual ? ? ? ? ?= fb_data->yres*2;
> + ? ? ? info->var.bits_per_pixel ? ? ? ?= fb_data->bits_per_pixel;
> + ? ? ? info->var.activate ? ? ? ? ? ? ?= FB_ACTIVATE_VBL;
> + ? ? ? /* TODO: fill in the following by querying the DC */
> + ? ? ? info->var.height ? ? ? ? ? ? ? ?= -1;
> + ? ? ? info->var.width ? ? ? ? ? ? ? ? = -1;
> + ? ? ? info->var.pixclock ? ? ? ? ? ? ?= 24500;
> + ? ? ? info->var.left_margin ? ? ? ? ? = 0;
> + ? ? ? info->var.right_margin ? ? ? ? ?= 0;
> + ? ? ? info->var.upper_margin ? ? ? ? ?= 0;
> + ? ? ? info->var.lower_margin ? ? ? ? ?= 0;
> + ? ? ? info->var.hsync_len ? ? ? ? ? ? = 0;
> + ? ? ? info->var.vsync_len ? ? ? ? ? ? = 0;
> + ? ? ? info->var.vmode ? ? ? ? ? ? ? ? = FB_VMODE_NONINTERLACED;
> +
> + ? ? ? win->x = 0;
> + ? ? ? win->y = 0;
> + ? ? ? win->w = fb_data->xres;
> + ? ? ? win->h = fb_data->yres;
> + ? ? ? /* TODO: set to output res dc */
> + ? ? ? win->out_w = fb_data->xres;
> + ? ? ? win->out_h = fb_data->yres;
> + ? ? ? win->phys_addr = fb_phys;
> + ? ? ? win->virt_addr = fb_base;
> + ? ? ? win->flags = TEGRA_WIN_FLAG_ENABLED | TEGRA_WIN_FLAG_COLOR_EXPAND;
> +
> + ? ? ? tegra_fb_set_par(info);
> +
> + ? ? ? if (register_framebuffer(info)) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "failed to register framebuffer\n");
> + ? ? ? ? ? ? ? ret = -ENODEV;
> + ? ? ? ? ? ? ? goto err_iounmap_fb;
> + ? ? ? }
> +
> + ? ? ? tegra_fb->info = info;
> +
> + ? ? ? dev_info(&pdev->dev, "probed\n");
> +
> + ? ? ? return tegra_fb;
> +
> +err_iounmap_fb:
> + ? ? ? iounmap(fb_base);
> +err_free:
> + ? ? ? framebuffer_release(info);
> +err:
> + ? ? ? return ERR_PTR(ret);
> +}
> +
> +void tegra_fb_unregister(struct tegra_fb_info *fb_info)
> +{
> + ? ? ? struct fb_info *info = fb_info->info;
> +
> + ? ? ? unregister_framebuffer(info);
> + ? ? ? iounmap(info->screen_base);
> + ? ? ? framebuffer_release(info);
> +}
> --
> 1.6.5.6
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-08-26 0:02 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-11 23:11 [PATCH] video: tegra: add tegra display controller and fb driver Erik Gilling
2010-08-12 4:34 ` Ryan Mallon
[not found] ` <AANLkTini+n1osaQHkomguzZi-DaHLX3i1G4gA82bK0=S@mail.gmail.com>
[not found] ` <4C75A039.8060701@bluewatersys.com>
2010-08-25 23:56 ` Erik Gilling
2010-08-26 0:00 ` Ryan Mallon
2010-08-26 0:02 ` Erik Gilling
2010-08-25 22:04 ` Erik Gilling
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).