Skip to contentSkip to conversation

video: tegra: add tegra display controller and fb driver

PATCH New Erik Gilling 2 participants 6 messages Aug 11, 2010 – Aug 26, 2010 2 messages not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

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

Cc Colin Cross <[email protected]>
Cc Travis Geiselbrecht <[email protected]>
---
 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
arch/arm/mach-tegra/include/mach/dc.h new file +152 -0
new file mode 100644
index 0000000..b8a0e7a
@@ -0,0 +1,152 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dc.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Erik Gilling <[email protected]>
+ *
+ * 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
arch/arm/mach-tegra/include/mach/fb.h new file +44 -0

44 lines not on this page · raw message

drivers/video/Kconfig +1 -0
index 3d94a14..1eb0ac1 100644
@@ -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"
drivers/video/Makefile +1 -0
index ddc2af2..21b527d 100644
@@ -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
drivers/video/tegra/Kconfig new file +15 -0
new file mode 100644
index 0000000..b01dc95
@@ -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.
drivers/video/tegra/Makefile new file +2 -0
new file mode 100644
index 0000000..8f9d0e2
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TEGRA_DC) += dc/
+obj-$(CONFIG_FB_TEGRA) += fb.o
drivers/video/tegra/dc/Makefile new file +2 -0
new file mode 100644
index 0000000..3ecb63c
@@ -0,0 +1,2 @@
+obj-y += dc.o
+obj-y += rgb.o
\ No newline at end of file
drivers/video/tegra/dc/dc.c new file +894 -0

894 lines not on this page · raw message

drivers/video/tegra/dc/dc_priv.h new file +86 -0

86 lines not on this page · raw message

drivers/video/tegra/dc/dc_reg.h new file +342 -0

342 lines not on this page · raw message

drivers/video/tegra/dc/rgb.c new file +63 -0

63 lines not on this page · raw message

drivers/video/tegra/fb.c new file +311 -0

311 lines not on this page · raw message

Signature · 1 line
1.6.5.6
#1 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

Quoted 13 lines · Erik Gilling

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

Quoted 3 lines
Cc Colin Cross <[email protected]>
Cc Travis Geiselbrecht <[email protected]>

Hi Erik,

Just a couple of notes, not really a full review.

drivers/video/tegra/Kconfig line 9

Quoted 11 lines

+++ b/drivers/video/tegra/Kconfig

drivers/video/tegra/Kconfig new file +9 -0
@@ -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?

drivers/video/tegra/dc/Makefile line 2

Quoted 5 lines
drivers/video/tegra/dc/Makefile new file +3 -0
+++ 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?

Quoted 8 lines
drivers/video/tegra/dc/dc.c new file +8 -0
+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),

drivers/video/tegra/dc/dc.c line 59

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -0
+	  .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.

Quoted 5 lines
drivers/video/tegra/dc/dc.c new file +5 -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)

drivers/video/tegra/dc/dc.c line 122

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -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?

Quoted 29 lines
drivers/video/tegra/dc/dc.c new file +29 -0
+
+#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);
+}
+

drivers/video/tegra/dc/dc.c line 295

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -0
+#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?

drivers/video/tegra/dc/dc.c line 315

Quoted 6 lines
drivers/video/tegra/dc/dc.c new file +6 -0
+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?

drivers/video/tegra/dc/dc.c line 466

Quoted 5 lines
drivers/video/tegra/dc/dc.c new file +5 -0
+/* 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) ?

Quoted 5 lines
drivers/video/tegra/dc/dc.c new file +5 -0
+	return wait_event_interruptible_timeout(windows[0]->dc->wq,
+					 tegra_dc_windows_are_clean(windows, n),
+					 HZ);
+}
+EXPORT_SYMBOL(tegra_dc_sync_windows);

<snip>

drivers/video/tegra/dc/dc.c line 581

Quoted 9 lines
drivers/video/tegra/dc/dc.c new file +9 -0
+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.

drivers/video/tegra/dc/dc.c line 757

Quoted 9 lines
drivers/video/tegra/dc/dc.c new file +9 -0
+	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.

drivers/video/tegra/dc/dc.c line 813

Quoted 6 lines
drivers/video/tegra/dc/dc.c new file +6 -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");

dev_dbg?

Quoted 4 lines
drivers/video/tegra/dc/dc.c new file +4 -0
+	disable_irq(dc->irq);
+	tegra_periph_reset_assert(dc->clk);
+	clk_disable(dc->clk);
+

drivers/video/tegra/dc/dc.c line 828

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -0
+	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?

drivers/video/tegra/dc/dc.c line 866

Quoted 6 lines
drivers/video/tegra/dc/dc.c new file +6 -0
+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.

Quoted 4 lines
drivers/video/tegra/dc/dc.c new file +4 -0
+module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644);
+
+struct platform_driver tegra_dc_driver = {
+	.driver = {

drivers/video/tegra/dc/dc.c line 881

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -0
+		.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?

drivers/video/tegra/dc/dc_priv.h line 64

Quoted 5 lines
drivers/video/tegra/dc/dc_priv.h new file +5 -0
+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?

Quoted 7 lines
drivers/video/tegra/fb.c new file +7 -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,

drivers/video/tegra/fb.c line 181

Quoted 10 lines
drivers/video/tegra/fb.c new file +10 -0
+			      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:

drivers/video/tegra/fb.c line 193

Quoted 11 lines
drivers/video/tegra/fb.c new file +11 -0
+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

Signature · 7 lines
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

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

Quoted 3 lines · Ryan Mallon

On 08/26/2010 10:03 AM, Erik Gilling wrote:

You sent this just to me, did you mean to post to the list also?

oops

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines
Quoted 3 lines

+config FB_TEGRA
+ ? ? tristate "Tegra Framebuffer driver"
+ ? ? depends on TEGRA_DC && FB = y

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?

Quoted 6 lines
Quoted 2 lines

Printing the names of the registers has been invaluable so far. ?I could move this to a separate file.

Its useful for debugging while developing the driver, but it adds a lot of code. Do you expect the register dumping features to be required once the driver hits mainline?

I expect the driver will hit mainline is several phases. This first one. One where HDMI works. One where DSI works. One which has rotation. This code is useful for all those phases.

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines

drivers/video/tegra/dc/dc.c line 295

Quoted 10 lines
drivers/video/tegra/dc/dc.c new file +10 -0
+#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?

Quoted 8 lines
Quoted 4 lines

The extra #undef was a type-o. ?The debugfs file is useful when someone brings me a misbehaving unit and I need to dump the register set. ?The dump_regs funciton is usefull when I want to look at the state at different points in a code-path.

If you really want to keep the debug feature then I would at least pick one interface or the other. The debugfs one feels a bit more standard, and is probably more useful to end users once the driver is in mainline.

They still fill different uses. You can't cat a debugfs file from an interrupt handler. You can't call dump_regs() from userspace. I'm still actively using both. I could see taking one out once development on the driver calms down.

Quoted 12 lines
Quoted 12 lines
Quoted 11 lines

arch/arm/mach-tegra/include/mach/dc.h

Quoted 9 lines

+ ? ? tegra_dc_init(dc);

arch/arm/mach-tegra/include/mach/dc.h new file +8 -0
+
+ ? ? 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?

Quoted 7 lines
Quoted 2 lines

I find it very useful when drivers announce when new devices are added.

It adds more noise to the bootlog. There are other ways to determine that a driver has successfully probed. If you do want to keep the message at least make it a bit more informative so that it prints the configuration out or something.

I'll add some more info to the line.

-Erik

#5 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

Quoted 26 lines · Erik Gilling
Quoted 3 lines · Ryan Mallon

On 08/26/2010 10:03 AM, Erik Gilling wrote:

You sent this just to me, did you mean to post to the list also?

oops

Quoted 9 lines
Quoted 9 lines
Quoted 8 lines

drivers/video/tegra/Kconfig line 9

Quoted 3 lines
drivers/video/tegra/Kconfig new file +3 -0
+config FB_TEGRA
+     tristate "Tegra Framebuffer driver"
+     depends on TEGRA_DC && FB = y

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?

Quoted 6 lines
Quoted 2 lines

Printing the names of the registers has been invaluable so far. I could move this to a separate file.

Its useful for debugging while developing the driver, but it adds a lot of code. Do you expect the register dumping features to be required once the driver hits mainline?

I expect the driver will hit mainline is several phases. This first one. One where HDMI works. One where DSI works. One which has rotation. This code is useful for all those phases.

...

Quoted 4 lines

They still fill different uses. You can't cat a debugfs file from an interrupt handler. You can't call dump_regs() from userspace. I'm still actively using both. I could see taking one out once development on the driver calms down.

Okay, maybe keep both with a comment stating why the debug is still there, and that it is scheduled to be removed once the driver is complete in mainline?

~Ryan

Signature · 7 lines
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
#6 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

Quoted 8 lines · Ryan Mallon
Quoted 7 lines
Quoted 3 lines

Its useful for debugging while developing the driver, but it adds a lot of code. Do you expect the register dumping features to be required once the driver hits mainline?

I expect the driver will hit mainline is several phases. ?This first one. ?One where HDMI works. ?One where DSI works. ?One which has rotation. ?This code is useful for all those phases.

...

Quoted 8 lines
Quoted 4 lines

They still fill different uses. ?You can't cat a debugfs file from an interrupt handler. ?You can't call dump_regs() from userspace. ?I'm still actively using both. ?I could see taking one out once development on the driver calms down.

Okay, maybe keep both with a comment stating why the debug is still there, and that it is scheduled to be removed once the driver is complete in mainline?

OK will do.

#7 lore raw

PATCH 1/1 video: tegra: add tegra display controller and fb driver

In reply to Erik Gilling

ping. any more comments. I'd like to have this ready for the next merge window.

Quoted 2,041 lines · Erik Gilling

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

Cc Colin Cross <[email protected]>
Cc Travis Geiselbrecht <[email protected]>

---

?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

arch/arm/mach-tegra/include/mach/dc.h new file +152 -0
new file mode 100644
index 0000000..b8a0e7a
@@ -0,0 +1,152 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dc.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * ? ? Erik Gilling <[email protected]>
+ *
+ * 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
arch/arm/mach-tegra/include/mach/fb.h new file +44 -0
new file mode 100644
index 0000000..9e5f7f8
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/mach-tegra/include/mach/fb.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * ? ? Erik Gilling <[email protected]>
+ *
+ * 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
drivers/video/Kconfig +0 -0
index 3d94a14..1eb0ac1 100644
@@ -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"

drivers/video/Makefile +0 -0
index ddc2af2..21b527d 100644
@@ -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

drivers/video/tegra/Kconfig new file +15 -0
new file mode 100644
index 0000000..b01dc95
@@ -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.
drivers/video/tegra/Makefile new file +2 -0
new file mode 100644
index 0000000..8f9d0e2
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TEGRA_DC) += dc/
+obj-$(CONFIG_FB_TEGRA) += fb.o
drivers/video/tegra/dc/Makefile new file +2 -0
new file mode 100644
index 0000000..3ecb63c
@@ -0,0 +1,2 @@
+obj-y += dc.o
+obj-y += rgb.o
\ No newline at end of file
drivers/video/tegra/dc/dc.c new file +894 -0
new file mode 100644
index 0000000..261bced
@@ -0,0 +1,894 @@
+/*
+ * drivers/video/tegra/dc/dc.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <[email protected]>
+ *
+ * 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);
drivers/video/tegra/dc/dc_priv.h new file +86 -0
new file mode 100644
index 0000000..b2351b1
@@ -0,0 +1,86 @@
+/*
+ * drivers/video/tegra/dc/dc_priv.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <[email protected]>
+ *
+ * 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
drivers/video/tegra/dc/dc_reg.h new file +342 -0
new file mode 100644
index 0000000..6d6b3ba
@@ -0,0 +1,342 @@
+/*
+ * drivers/video/tegra/dc/dc_reg.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <[email protected]>
+ *
+ * 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
drivers/video/tegra/dc/rgb.c new file +63 -0
new file mode 100644
index 0000000..de1a8fa
@@ -0,0 +1,63 @@
+/*
+ * drivers/video/tegra/dc/rgb.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <[email protected]>
+ *
+ * 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,
+};
+
drivers/video/tegra/fb.c new file +311 -1
new file mode 100644
index 0000000..4db3958
@@ -0,0 +1,311 @@
+/*
+ * drivers/video/tegra/fb.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Erik Gilling <[email protected]>
+ * ? ? ? ? Colin Cross <[email protected]>
+ * ? ? ? ? Travis Geiselbrecht <[email protected]>
+ *
+ * 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