Subject: viafb suspend & resume

This little patch series tries to implement suspend and resume in a sane way
that should work on all IGPs supported. It's not yet error free but should be
a good start. It is based on the second version of Jon's first patch series.


Thanks,

Florian Tobias Schandinat


Deepak Saxena (1):
Minimal support for viafb suspend/resume

Florian Tobias Schandinat (3):
viafb: restore display on resume
viafb: make suspend and resume work (on all machines?)
viafb: fix hardware acceleration for suspend & resume


Subject: [PATCH 1/4] Minimal support for viafb suspend/resume

From: Deepak Saxena <[email protected]>

This patch adds minimal support for suspend/resume of the
VIA framebuffer device. It requires a version of OFW
that restores the video mode.

This patch is OLPC-specific as the proper upstream solution
is to move the VIA video path to using the kernel modesetting
infrastructure and doing a proper save/restore in the kernel.

[jc: extensive changes for 2.6.34 merge]
Signed-off-by: Deepak Saxena <[email protected]>
---
drivers/video/via/viafbdev.c | 51 ++++++++++++++++++++++++++++++++++++++++++
drivers/video/via/viafbdev.h | 3 ++
2 files changed, 54 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index d21bc89..8197096 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1732,6 +1732,53 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
return 0;
}

+
+#ifdef CONFIG_PM
+static int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ if (state.event == PM_EVENT_SUSPEND) {
+ acquire_console_sem();
+
+ memcpy_fromio(viaparinfo->shared->saved_regs,
+ viaparinfo->shared->engine_mmio + 0x100,
+ 0xff * sizeof(u32));
+
+ fb_set_suspend(viafbinfo, 1);
+
+ viafb_sync(viafbinfo);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ release_console_sem();
+ }
+
+ return 0;
+}
+
+static int viafb_resume(struct pci_dev *pdev)
+{
+ acquire_console_sem();
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev))
+ goto fail;
+ pci_set_master(pdev);
+
+ memcpy_toio(viaparinfo->shared->engine_mmio + 0x100,
+ viaparinfo->shared->saved_regs,
+ 0x100 * sizeof(u32));
+
+ fb_set_suspend(viafbinfo, 0);
+
+fail:
+ release_console_sem();
+ return 0;
+}
+
+#endif
+
+
static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -2095,6 +2142,10 @@ static struct pci_driver viafb_driver = {
.id_table = viafb_pci_table,
.probe = via_pci_probe,
.remove = __devexit_p(via_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = viafb_suspend,
+ .resume = viafb_resume,
+#endif
};

static int __init viafb_init(void)
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index 4bc00ec..d58a0ac 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -60,6 +60,9 @@ struct viafb_shared {
u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
u32 fg_color, u32 bg_color, u8 fill_rop);
+
+ /* For suspend/resume */
+ u32 saved_regs[0x100];
};

struct viafb_par {
--
1.6.3.2

Subject: [PATCH 4/4] viafb: fix hardware acceleration for suspend & resume

viafb: fix hardware acceleration for suspend & resume

This patch splits the acceleration initialization in two parts:
The first is only called during probe and is used to allocate
resources. The second part is also called on resume to reinitalize
the 2D engine. This should fix all acceleration issues after resume
most notable an "invisible" cursor and as we do nothing special it is
reasonable to assume that it works on all supported IGPs.

Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/accel.c | 41 +++++++++++++++++++++++++----------------
drivers/video/via/accel.h | 1 +
drivers/video/via/viafbdev.c | 1 +
3 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 0d90c85..726c153 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -317,9 +317,7 @@ int viafb_init_engine(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
void __iomem *engine;
- int highest_reg, i;
- u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
- vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
+ u32 chip_name = viapar->shared->chip_info.gfx_chip_name;

engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
viapar->shared->engine_mmio = engine;
@@ -329,18 +327,6 @@ int viafb_init_engine(struct fb_info *info)
return -ENOMEM;
}

- /* Initialize registers to reset the 2D engine */
- switch (viapar->shared->chip_info.twod_engine) {
- case VIA_2D_ENG_M1:
- highest_reg = 0x5c;
- break;
- default:
- highest_reg = 0x40;
- break;
- }
- for (i = 0; i <= highest_reg; i += 4)
- writel(0x0, engine + i);
-
switch (chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
@@ -370,6 +356,29 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;

+ viafb_start_engine(viapar);
+ return 0;
+}
+
+void viafb_start_engine(struct viafb_par *viapar)
+{
+ void __iomem *engine = viapar->shared->engine_mmio;
+ int highest_reg, i;
+ u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
+ vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
+
+ /* Initialize registers to reset the 2D engine */
+ switch (viapar->shared->chip_info.twod_engine) {
+ case VIA_2D_ENG_M1:
+ highest_reg = 0x5c;
+ break;
+ default:
+ highest_reg = 0x40;
+ break;
+ }
+ for (i = 0; i <= highest_reg; i += 4)
+ writel(0x0, engine + i);
+
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
@@ -457,7 +466,7 @@ int viafb_init_engine(struct fb_info *info)
writel(0x0, engine + VIA_REG_CURSOR_ORG);
writel(0x0, engine + VIA_REG_CURSOR_BG);
writel(0x0, engine + VIA_REG_CURSOR_FG);
- return 0;
+ return;
}

void viafb_show_hw_cursor(struct fb_info *info, int Status)
diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h
index 2c122d2..5352f87 100644
--- a/drivers/video/via/accel.h
+++ b/drivers/video/via/accel.h
@@ -204,6 +204,7 @@
#define VIA_BITBLT_FILL 3

int viafb_init_engine(struct fb_info *info);
+void viafb_start_engine(struct viafb_par *viapar);
void viafb_show_hw_cursor(struct fb_info *info, int Status);
void viafb_wait_engine_idle(struct fb_info *info);

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 86d3ded..bbf0f70 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1759,6 +1759,7 @@ static int viafb_resume(struct pci_dev *pdev)
if (pci_enable_device(pdev))
goto fail;
pci_set_master(pdev);
+ viafb_start_engine(viafbinfo->par);
viafb_set_par(viafbinfo);
if (viafb_dual_fb)
viafb_set_par(viafbinfo1);
--
1.6.3.2

Subject: [PATCH 2/4] viafb: restore display on resume

viafb: restore display on resume

This patch makes viafb restore the display on resume by calling
viafb_set_par. Resumeing has still its issues:
- will probably freeze most machines (for me on VX800 reliable on the
second resume)
- under some configurations the screen appears on the wrong output
device (reason unknown)

Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/viafbdev.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 8197096..4af5a43 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1769,6 +1769,9 @@ static int viafb_resume(struct pci_dev *pdev)
viaparinfo->shared->saved_regs,
0x100 * sizeof(u32));

+ viafb_set_par(viafbinfo);
+ if (viafb_dual_fb)
+ viafb_set_par(viafbinfo1);
fb_set_suspend(viafbinfo, 0);

fail:
--
1.6.3.2

Subject: [PATCH 3/4] viafb: make suspend and resume work (on all machines?)

viafb: make suspend and resume work (on all machines?)

This patch removes the dangerous suspend and resume code that was
developed for VX855 only. After this the framebuffer is expected to
cause no longer serious (freezing) issues on any machines.
However the hardware acceleration is broken now so only doing resume
with unaccelerated framebuffers is save. This did not work previously
as the 2D engine is not mapped if the framebuffer is not accelerated.
The acceleration issue will be addressed later.

Signed-off-by: Florian Tobias Schandinat <[email protected]>
---
drivers/video/via/viafbdev.c | 10 ----------
drivers/video/via/viafbdev.h | 3 ---
2 files changed, 0 insertions(+), 13 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 4af5a43..86d3ded 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1738,11 +1738,6 @@ static int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
{
if (state.event == PM_EVENT_SUSPEND) {
acquire_console_sem();
-
- memcpy_fromio(viaparinfo->shared->saved_regs,
- viaparinfo->shared->engine_mmio + 0x100,
- 0xff * sizeof(u32));
-
fb_set_suspend(viafbinfo, 1);

viafb_sync(viafbinfo);
@@ -1764,11 +1759,6 @@ static int viafb_resume(struct pci_dev *pdev)
if (pci_enable_device(pdev))
goto fail;
pci_set_master(pdev);
-
- memcpy_toio(viaparinfo->shared->engine_mmio + 0x100,
- viaparinfo->shared->saved_regs,
- 0x100 * sizeof(u32));
-
viafb_set_par(viafbinfo);
if (viafb_dual_fb)
viafb_set_par(viafbinfo1);
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index d58a0ac..4bc00ec 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -60,9 +60,6 @@ struct viafb_shared {
u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
u32 fg_color, u32 bg_color, u8 fill_rop);
-
- /* For suspend/resume */
- u32 saved_regs[0x100];
};

struct viafb_par {
--
1.6.3.2