Resuming video

Jordan Crouse jordan.crouse at amd.com
Tue Dec 4 17:31:25 EST 2007


If you have used suspend before while running record, then you know that
things don't come back very healthy - the video is basically hosed.  The
attached patch should fix that - I'm reliably getting video to come
back after resume over here.  This is a pretty fragile part of the code,
though, so I do need testers.

Thanks,
Jordan

-- 
Jordan Crouse
Systems Software Development Engineer 
Advanced Micro Devices, Inc.
-------------- next part --------------
[LXFB]:  _Really_ fix suspend/resume for LX video

From: Jordan Crouse <jordan.crouse at amd.com>

It turns out that the registers on resume are picky about when they are
restored.  This completely rearranges the resume sequence for the DC
and VP, especially concentrating on restoring the video properly.

Signed-off-by: Jordan Crouse <jordan.crouse at amd.com>
---

 drivers/video/geode/geode_regs.h |   11 +
 drivers/video/geode/lxfb_ops.c   |  284 +++++++++++++++++++++-----------------
 2 files changed, 167 insertions(+), 128 deletions(-)

Index: git/drivers/video/geode/geode_regs.h
===================================================================
--- git.orig/drivers/video/geode/geode_regs.h	2007-11-20 22:13:07.000000000 -0700
+++ git/drivers/video/geode/geode_regs.h	2007-12-04 14:05:01.000000000 -0700
@@ -40,6 +40,9 @@
 #endif
 
 #define DC_PAL_SIZE 0x105
+#define VP_COEFF_COUNT 512
+#define DC_HFILT_SIZE 256
+#define DC_VFILT_SIZE 256
 
 struct geoderegs {
 
@@ -239,6 +242,14 @@
 
 	u32 pal[DC_PAL_SIZE];
 	u32 gamma[256];
+
+#ifdef _GEODELX_
+
+	u32 hcoeff[DC_HFILT_SIZE * 2];
+	u32 vcoeff[DC_VFILT_SIZE];
+
+	u32 vp_coeff[VP_COEFF_COUNT];
+#endif
 };
 
 #endif
Index: git/drivers/video/geode/lxfb_ops.c
===================================================================
--- git.orig/drivers/video/geode/lxfb_ops.c	2007-11-20 22:13:07.000000000 -0700
+++ git/drivers/video/geode/lxfb_ops.c	2007-12-04 14:05:01.000000000 -0700
@@ -611,6 +611,7 @@
 {
 	struct lxfb_par *par = info->par;
 	int i;
+	u32 filt;
 
 	/* Wait for the command buffer to empty */
 	while(!(readl(par->gp_regs + 0x44) & (1 << 4)));
@@ -630,98 +631,71 @@
 	memcpy(regs->vp.b, par->df_regs, VP_REG_SIZE);
 	memcpy(regs->fp.b, par->df_regs + VP_FP_START, FP_REG_SIZE);
 
-	/* Save the palettes */
+	/* Save the palette */
 	writel(0, par->dc_regs + 0x70);
 
-	for(i = 0; i < DC_PAL_SIZE; i++) 
+	for(i = 0; i < DC_PAL_SIZE; i++)
 		regs->pal[i] = readl(par->dc_regs + 0x74);
-	
-	writel(0, par->df_regs + 0x38);
-
-	for(i = 0; i <= 0xFF; i++)
-		regs->gamma[i] = readl(par->df_regs + 0x40);
-}
-
-static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
-{
-	struct lxfb_par *par = info->par;
-	u32 val, i;
 
-	/* == DOTPLL == */
+	/* save the filter coefficients */
 
-	lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
-
-	/* MSRs */
-
-	wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
-
-	/* == GP == */
-
-	writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
-	writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
-	writel(regs->gp.r.stride, par->gp_regs + 0x08);
-	writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
-	writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
-	writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
-	writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
-	writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
-	writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
-	writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
-	writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
-	writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
-	writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
-	writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
+	filt = readl(par->dc_regs + 0x94);
+	filt |= DC_IRQFILT_H_FILT_SEL;
 
-	/* Writing to these registers would cause a blt to happen */
-	/* 0x38, 0x3c, 0x40 */
+	for(i = 0; i < DC_HFILT_SIZE; i++) {
+		writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
+		regs->hcoeff[i << 1] = readl(par->dc_regs + 0x98);
+		regs->hcoeff[(i << 1) + 1] = readl(par->dc_regs + 0x9c);
+	}
 
-	/* Status register (0x44) is read only */
+	filt &= ~DC_IRQFILT_H_FILT_SEL;
 
-	writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
-	writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
-	writel(regs->gp.r.cmd_top, par->gp_regs + 0x50);
-	writel(regs->gp.r.cmd_bot, par->gp_regs + 0x54);
-	writel(regs->gp.r.cmd_read, par->gp_regs + 0x58);
-	writel(regs->gp.r.cmd_write, par->gp_regs + 0x5C);
-	writel(regs->gp.r.ch3_offset, par->gp_regs + 0x60);
-	writel(regs->gp.r.ch3_mode_str, par->gp_regs + 0x64);
-	writel(regs->gp.r.ch3_width, par->gp_regs + 0x6C);
-	writel(regs->gp.r.ch3_hsrc, par->gp_regs + 0x70);
+	for(i = 0; i < DC_VFILT_SIZE; i++) {
+		writel((filt & 0xFFFFFF00) | i, par->dc_regs + 0x94);
+		regs->vcoeff[i] = readl(par->dc_regs + 0x98);
+	}
 
-	/* FIXME:  Restore the LUT data here */
+	/* Save the vg filter coefficients */
+	for(i = 0; i < VP_COEFF_COUNT; i++)
+		regs->vp_coeff[i] =
+			readl(par->df_regs + 0x1000 + (i << 2));
 
-	writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
+	/* Save the VP gamma */
 
-	/* == DC == */
-
-	/* Write the unlock value */
-	writel(0x4758, par->dc_regs + 0x00);
+	writel(0, par->df_regs + 0x38);
 
-	/* Write the palette data first */
+	for(i = 0; i <= 0xFF; i++)
+		regs->gamma[i] = readl(par->df_regs + 0x40);
+}
 
-	writel(0, par->dc_regs + 0x70);
+static void lx_restore_dc(struct lxfb_par *par, struct geoderegs *regs)
+{
+	u32 filt;
+	int i;
 
-	for(i = 0; i < DC_PAL_SIZE; i++)
-		writel(regs->pal[i], par->dc_regs + 0x74);
+	/* Unlock the registers */
+	writel(DC_UNLOCK_CODE, par->dc_regs + 0x00);
 
-	/* MSRs */
-	wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
+	/* Restore the framebuffer offset */
+	writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
 
-	/* Write the gcfg register without the enables */
-	writel(regs->dc.r.gcfg & ~0x0F, par->dc_regs + 0x04);
+	/* Blank the configuration registers while we restore */
+	writel(0, par->dc_regs + 0x04);
+	writel(0, par->dc_regs + 0x08);
 
-	/* Write the vcfg register without the enables */
-	writel(regs->dc.r.dcfg & ~0x19, par->dc_regs + 0x08);
+	/* Restore the bulk of the registers */
 
-	/* Write the rest of the active registers */
 	writel(regs->dc.r.arb, par->dc_regs + 0x0C);
 	writel(regs->dc.r.fb_st_offset, par->dc_regs + 0x10);
 	writel(regs->dc.r.cb_st_offset, par->dc_regs + 0x14);
 	writel(regs->dc.r.curs_st_offset, par->dc_regs + 0x18);
-	writel(regs->dc.r.icon_st_offset, par->dc_regs + 0x1C);
+
+	/* skip 0x1c */
+
 	writel(regs->dc.r.vid_y_st_offset, par->dc_regs + 0x20);
 	writel(regs->dc.r.vid_u_st_offset, par->dc_regs + 0x24);
 	writel(regs->dc.r.vid_v_st_offset, par->dc_regs + 0x28);
+
 	writel(regs->dc.r.dctop, par->dc_regs + 0x2c);
 	writel(regs->dc.r.line_size, par->dc_regs + 0x30);
 	writel(regs->dc.r.gfx_pitch, par->dc_regs + 0x34);
@@ -735,23 +709,20 @@
 	writel(regs->dc.r.fbactive, par->dc_regs + 0x5c);
 	writel(regs->dc.r.dc_cursor_x, par->dc_regs + 0x60);
 	writel(regs->dc.r.dc_cursor_y, par->dc_regs + 0x64);
-	writel(regs->dc.r.dc_icon_x, par->dc_regs + 0x68);
 
-	/* Skip register 0x6C (line_cnt), 0x70/0x74 (palette),
-	   0x78 (diagnostic), and 0x7c (diagnostic)
-	*/
+	/* skip 0x68, 0x6c, 0x70, 0x74, 0x78, 0x7c */
 
 	writel(regs->dc.r.dc_vid_ds_delta, par->dc_regs + 0x80);
-	writel(regs->dc.r.gliu0_mem_offset, par->dc_regs + 0x84);
-	writel(regs->dc.r.dv_ctl, par->dc_regs + 0x88);
-	writel(regs->dc.r.dv_acc, par->dc_regs + 0x8C);
 
+	/* 0x84 was written above */
+
+	writel(regs->dc.r.dv_ctl | 0x01, par->dc_regs + 0x88);
 	writel(regs->dc.r.gfx_scale, par->dc_regs + 0x90);
 	writel(regs->dc.r.irq_filt_ctl, par->dc_regs + 0x94);
-	writel(regs->dc.r.filt_coeff1, par->dc_regs + 0x98);
-	writel(regs->dc.r.filt_coeff2, par->dc_regs + 0x9C);
-	writel(regs->dc.r.vbi_event_ctl, par->dc_regs + 0xA0);
 
+	/* skip 0x98, 0x9c */
+
+	writel(regs->dc.r.vbi_event_ctl, par->dc_regs + 0xA0);
 	writel(regs->dc.r.vbi_odd_ctl, par->dc_regs + 0xA4);
 	writel(regs->dc.r.vbi_hor, par->dc_regs + 0xA8);
 	writel(regs->dc.r.vbi_ln_odd, par->dc_regs + 0xAC);
@@ -759,53 +730,78 @@
 	writel(regs->dc.r.vbi_pitch, par->dc_regs + 0xB4);
 	writel(regs->dc.r.clr_key, par->dc_regs + 0xB8);
 	writel(regs->dc.r.clr_key_mask, par->dc_regs + 0xBC);
-
 	writel(regs->dc.r.clr_key_x, par->dc_regs + 0xC0);
 	writel(regs->dc.r.clr_key_y, par->dc_regs + 0xC4);
 	writel(regs->dc.r.irq, par->dc_regs + 0xC8);
 	writel(regs->dc.r.genlk_ctrl, par->dc_regs + 0xD4);
-
 	writel(regs->dc.r.vid_even_y_st_offset, par->dc_regs + 0xD8);
 	writel(regs->dc.r.vid_even_u_st_offset, par->dc_regs + 0xDC);
 	writel(regs->dc.r.vid_even_v_st_offset, par->dc_regs + 0xE0);
-
 	writel(regs->dc.r.v_active_even_timing, par->dc_regs + 0xE4);
 	writel(regs->dc.r.v_blank_even_timing, par->dc_regs + 0xE8);
 	writel(regs->dc.r.v_sync_even_timing, par->dc_regs + 0xEC);
 
-	/* == VP == */
+	/* Restore the palette */
+	writel(0, par->dc_regs + 0x70);
 
-	/* MSR */
-	wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
+	for(i = 0; i < DC_PAL_SIZE; i++)
+		writel(regs->pal[i], par->dc_regs + 0x74);
 
-	/* Write gamma information first */
+	/* Restore the horizontal filter coefficients */
+	filt = readl(par->dc_regs + 0x94);
+	filt |= DC_IRQFILT_H_FILT_SEL;
+
+	for(i = 0; i < DC_HFILT_SIZE; i++) {
+		writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
+		writel(regs->hcoeff[i << 1], par->dc_regs + 0x98);
+		writel(regs->hcoeff[(i << 1) + 1], par->dc_regs + 0x9c);
+	}
 
-	writel(0, par->df_regs + 0x38);
+	filt &= ~DC_IRQFILT_H_FILT_SEL;
 
-	for(i = 0; i <= 0xFF; i++)
-		writel((u32) regs->gamma[i], par->df_regs + 0x40);
+	for(i = 0; i < DC_VFILT_SIZE; i++) {
+		writel(((filt & 0xFFFFFF00) | i), par->dc_regs + 0x94);
+		writel(regs->vcoeff[i], par->dc_regs + 0x98);
+	}
+
+	/* Turn on the dotpll */
+	lx_set_dotpll((u32) (regs->msr.dotpll >> 32));
+
+	/* Restore MSRs */
+	wrmsrl(MSR_LX_DC_SPARE, regs->msr.dcspare);
 
-	/* Don't enable video yet */
-	writel((u32) regs->vp.r.vcfg & ~0x01, par->df_regs + 0x00);
+	/* Restore the configuration registers */
 
-	/* Don't enable the CRT yet */
-	writel((u32) regs->vp.r.dcfg & ~0x0F, par->df_regs + 0x08);
+	writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
+	writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
+
+	/* Lock the DC again */
+	writel(0, par->dc_regs + 0x00);
+}
+
+static void lx_restore_vp(struct lxfb_par *par, struct geoderegs *regs)
+{
+	u32 val;
+	int i;
+
+	/* Restore MSRs */
+
+	wrmsrl(MSR_LX_DF_GLCONFIG, regs->msr.dfglcfg);
+	wrmsrl(MSR_LX_DF_PADSEL, regs->msr.padsel);
 
-	/* Write the rest of the VP registers */
+	/* Restore the registers */
 
 	writel((u32) regs->vp.r.vx, par->df_regs + 0x10);
 	writel((u32) regs->vp.r.vy, par->df_regs + 0x18);
 	writel((u32) regs->vp.r.vs, par->df_regs + 0x20);
 	writel((u32) regs->vp.r.vck, par->df_regs + 0x28);
 	writel((u32) regs->vp.r.vcm, par->df_regs + 0x30);
+	/* skip 0x38 and 0x40 */
 	writel((u32) regs->vp.r.slr, par->df_regs + 0x48);
 	writel((u32) regs->vp.r.misc, par->df_regs + 0x50);
-	writel((u32) regs->vp.r.ccs, par->df_regs + 0x58);
+	/* skip 0x58 */
 	writel((u32) regs->vp.r.vys, par->df_regs + 0x60);
 	writel((u32) regs->vp.r.vxs, par->df_regs + 0x68);
-	writel((u32) regs->vp.r.vdc, par->df_regs + 0x78);
-	writel((u32) regs->vp.r.vco, par->df_regs + 0x80);
-	writel((u32) regs->vp.r.crc, par->df_regs + 0x88);
 	writel((u32) regs->vp.r.vde, par->df_regs + 0x98);
 	writel((u32) regs->vp.r.cck, par->df_regs + 0xA0);
 	writel((u32) regs->vp.r.ccm, par->df_regs + 0xA8);
@@ -824,45 +820,92 @@
 	writel((u32) regs->vp.r.a3c, par->df_regs + 0x110);
 	writel((u32) regs->vp.r.a3t, par->df_regs + 0x118);
 	writel((u32) regs->vp.r.vrr, par->df_regs + 0x120);
-
 	writel((u32) regs->vp.r.vye, par->df_regs + 0x138);
 	writel((u32) regs->vp.r.a1ye, par->df_regs + 0x140);
 	writel((u32) regs->vp.r.a2ye, par->df_regs + 0x148);
 	writel((u32) regs->vp.r.a3ye, par->df_regs + 0x150);
 
-	/* == FP == */
+	/* Panel */
 
 	writel((u32) regs->fp.r.pt1, par->df_regs + 0x400);
 	writel((u32) regs->fp.r.pt2, par->df_regs + 0x408);
 	writel((u32) regs->fp.r.dfc, par->df_regs + 0x418);
-	writel(regs->fp.r.dca, par->df_regs + 0x448);
-	writel(regs->fp.r.dmd, par->df_regs + 0x450);
-	writel(regs->fp.r.crc, par->df_regs + 0x458);
 
-	/* Final enables */
+	/* Restore panel power */
 
 	val = readl(par->df_regs + 0x410);
 
-	/* Control the panel */
 	if (regs->fp.r.pm & (1 << 24)) {
-
 		if (!(val & 0x09))
-			writel(regs->fp.r.pm, par->df_regs + 0x410);
+                       writel(regs->fp.r.pm, par->df_regs + 0x410);
 	}
 	else {
 		if (!(val & 0x05))
 			writel(regs->fp.r.pm, par->df_regs + 0x410);
 	}
 
-	/* Turn everything on */
+	/* Restore the vp palette */
+
+	writel(0, par->df_regs + 0x38);
+
+	for(i = 0; i <= 0xFF; i++)
+		writel((u32) regs->gamma[i], par->df_regs + 0x40);
+
+	/* Restore filter coefficients */
+
+	for(i = 0; i < VP_COEFF_COUNT; i++)
+		writel(regs->vp_coeff[i],
+		       par->df_regs + 0x1000 + (i << 2));
+
+	/* Restore the configuration registers */
 
-	writel(regs->dc.r.gcfg, par->dc_regs + 0x04);
-	writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
 	writel((u32) regs->vp.r.dcfg, par->df_regs + 0x08);
-	writel(regs->dc.r.dcfg, par->dc_regs + 0x08);
+	writel((u32) regs->vp.r.vcfg, par->df_regs + 0x00);
+}
+
+static void lx_restore_gp(struct lxfb_par *par, struct geoderegs *regs)
+{
+	writel(regs->gp.r.dst_offset, par->gp_regs + 0x00);
+	writel(regs->gp.r.src_offset, par->gp_regs + 0x04);
+	writel(regs->gp.r.stride, par->gp_regs + 0x08);
+	writel(regs->gp.r.wid_height, par->gp_regs + 0x0C);
+	writel(regs->gp.r.src_color_fg, par->gp_regs + 0x10);
+	writel(regs->gp.r.src_color_bg, par->gp_regs + 0x14);
+	writel(regs->gp.r.pat_color_0, par->gp_regs + 0x18);
+	writel(regs->gp.r.pat_color_1, par->gp_regs + 0x1C);
+	writel(regs->gp.r.pat_color_2, par->gp_regs + 0x20);
+	writel(regs->gp.r.pat_color_3, par->gp_regs + 0x24);
+	writel(regs->gp.r.pat_color_4, par->gp_regs + 0x28);
+	writel(regs->gp.r.pat_color_5, par->gp_regs + 0x2C);
+	writel(regs->gp.r.pat_data_0, par->gp_regs + 0x30);
+	writel(regs->gp.r.pat_data_1, par->gp_regs + 0x34);
+
+	/* Writing to these registers would cause a blt to happen */
+	/* 0x38, 0x3c, 0x40 */
+
+	/* Status register (0x44) is read only */
+
+	writel(regs->gp.r.hst_src, par->gp_regs + 0x48);
+	writel(regs->gp.r.base_offset, par->gp_regs + 0x4c);
+	writel(regs->gp.r.cmd_top, par->gp_regs + 0x50);
+	writel(regs->gp.r.cmd_bot, par->gp_regs + 0x54);
+	writel(regs->gp.r.cmd_read, par->gp_regs + 0x58);
+	writel(regs->gp.r.cmd_write, par->gp_regs + 0x5C);
+	writel(regs->gp.r.ch3_offset, par->gp_regs + 0x60);
+	writel(regs->gp.r.ch3_mode_str, par->gp_regs + 0x64);
+	writel(regs->gp.r.ch3_width, par->gp_regs + 0x6C);
+	writel(regs->gp.r.ch3_hsrc, par->gp_regs + 0x70);
+
+	writel(regs->gp.r.int_cntrl, par->gp_regs + 0x70);
+}
+
+static void lx_restore_regs(struct fb_info *info, struct geoderegs *regs)
+{
+	struct lxfb_par *par = info->par;
 
-	/* Lock the DC */
-	writel(0, par->dc_regs + DC_UNLOCK);
+	lx_restore_gp(par, regs);
+	lx_restore_vp(par, regs);
+	lx_restore_dc(par, regs);
 }
 
 static int lx_power_on = 1;
Index: git/drivers/video/geode/lxfb.h
===================================================================
--- git.orig/drivers/video/geode/lxfb.h	2007-11-20 22:13:07.000000000 -0700
+++ git/drivers/video/geode/lxfb.h	2007-12-04 14:05:01.000000000 -0700
@@ -140,7 +140,7 @@
 
 #define DC_GFX_SCALE       0x90
 #define DC_IRQ_FILT_CTL    0x94
-
+#define   DC_IRQFILT_H_FILT_SEL   0x00000400
 
 #define DC_IRQ               0xC8
 #define  DC_IRQ_MASK         (1 << 0)


More information about the Devel mailing list