From 2a6dad31d84252d505f392f91dffd90689bb947c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:05:59 +1000 Subject: radeon: add initial suspend/resume support plus a bunch of fixes --- linux-core/radeon_pm.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 linux-core/radeon_pm.c (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c new file mode 100644 index 00000000..c7a57b97 --- /dev/null +++ b/linux-core/radeon_pm.c @@ -0,0 +1,180 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "atom.h" + +#include "drm_crtc_helper.h" + +int radeon_suspend(struct drm_device *dev, pm_message_t state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb; + int i; + + if (!dev || !dev_priv) { + return -ENODEV; + } + + if (state.event == PM_EVENT_PRETHAW) + return 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + /* unpin the front buffers */ + list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + if (!radeon_fb) + continue; + + if (!radeon_fb->obj) + continue; + + radeon_gem_object_unpin(radeon_fb->obj); + } + + if (!(dev_priv->flags & RADEON_IS_IGP)) + drm_bo_evict_mm(dev, DRM_BO_MEM_VRAM, 0); + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); + } + + dev_priv->pmregs.crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + for (i = 0; i < 8; i++) + dev_priv->pmregs.bios_scratch[i] = RADEON_READ(RADEON_BIOS_0_SCRATCH + (i * 4)); + + radeon_modeset_cp_suspend(dev); + + pci_save_state(dev->pdev); + + if (state.event == PM_EVENT_SUSPEND) { + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + } + return 0; +} + +int radeon_resume(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb; + int i; + u32 tmp; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) + return -1; + pci_set_master(dev->pdev); + + /* Turn on bus mastering */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + + /* on atom cards re init the whole card + and set the modes again */ + + if (dev_priv->is_atom_bios) { + struct atom_context *ctx = dev_priv->mode_info.atom_context; + atom_asic_init(ctx); + } else { + radeon_combios_asic_init(dev); + } + + for (i = 0; i < 8; i++) + RADEON_WRITE(RADEON_BIOS_0_SCRATCH + (i * 4), dev_priv->pmregs.bios_scratch[i]); + + /* VGA render mayhaps */ + if (dev_priv->chip_family >= CHIP_RS600) { + uint32_t tmp; + + RADEON_WRITE(AVIVO_D1VGA_CONTROL, 0); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, 0); + tmp = RADEON_READ(0x300); + tmp &= ~(3 << 16); + RADEON_WRITE(0x300, tmp); + RADEON_WRITE(0x308, (1 << 8)); + RADEON_WRITE(0x310, dev_priv->fb_location); + RADEON_WRITE(0x594, 0); + } + + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, dev_priv->pmregs.crtc_ext_cntl); + + radeon_static_clocks_init(dev); + + radeon_init_memory_map(dev); + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_toio(dev_priv->mm.pcie_table.kmap.virtual, dev_priv->mm.pcie_table_backup, RADEON_PCIGART_TABLE_SIZE); + } + + if (dev_priv->mm.ring.kmap.virtual) + memset(dev_priv->mm.ring.kmap.virtual, 0, RADEON_DEFAULT_RING_SIZE); + + if (dev_priv->mm.ring_read.kmap.virtual) + memset(dev_priv->mm.ring_read.kmap.virtual, 0, PAGE_SIZE); + + radeon_modeset_cp_resume(dev); + + /* reset swi reg */ + RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); + + radeon_enable_interrupt(dev); + + /* reset the context for userspace */ + if (dev->primary->master) { + struct drm_radeon_master_private *master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->ctx_owner = 0; + } + + /* unpin the front buffers */ + list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { + + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + if (!radeon_fb) + continue; + + if (!radeon_fb->obj) + continue; + + radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); + } + /* blat the mode back in */ + drm_helper_resume_force_mode(dev); + + return 0; +} -- cgit v1.2.3 From 6a0248cbf2197d64f51d557f85bf2fdbaa505870 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:28:42 +1000 Subject: fixup radeon stuff - need to checkout irqs --- linux-core/radeon_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index c7a57b97..e9a6130a 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -151,7 +151,7 @@ int radeon_resume(struct drm_device *dev) /* reset swi reg */ RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); - radeon_enable_interrupt(dev); +// radeon_enable_interrupt(dev); /* reset the context for userspace */ if (dev->primary->master) { -- cgit v1.2.3 From 34af71c42a66e5ef6a9a08250ca541030ca3cc4f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 16:07:41 -0400 Subject: radeon: add function to configure PCIE lanes --- linux-core/radeon_pm.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index e9a6130a..5d14384c 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -178,3 +178,63 @@ int radeon_resume(struct drm_device *dev) return 0; } + +bool radeon_set_pcie_lanes(struct drm_device *dev, int lanes) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t link_width_cntl, mask; + + /* FIXME wait for idle */ + + + switch (lanes) { + case 0: + mask = RADEON_PCIE_LC_LINK_WIDTH_X0; + break; + case 1: + mask = RADEON_PCIE_LC_LINK_WIDTH_X1; + break; + case 2: + mask = RADEON_PCIE_LC_LINK_WIDTH_X2; + break; + case 4: + mask = RADEON_PCIE_LC_LINK_WIDTH_X4; + break; + case 8: + mask = RADEON_PCIE_LC_LINK_WIDTH_X8; + break; + case 12: + mask = RADEON_PCIE_LC_LINK_WIDTH_X12; + break; + case 16: + default: + mask = RADEON_PCIE_LC_LINK_WIDTH_X16; + break; + } + + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return true; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + RADEON_PCIE_LC_RECONFIG_LATER | + RADEON_PCIE_LC_SHORT_RECONFIG_EN); + link_width_cntl |= mask; + RADEON_WRITE_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + RADEON_WRITE_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW); + + /* wait for lane set to complete */ + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return true; + else + return false; +} + -- cgit v1.2.3 From 5fdfbee22acb8eaaa834457c30e6f68883ab1353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:47:34 +1000 Subject: Store the buffer object backing the fb as a void pointer, not a handle. This lets us defer handle creation until userspace acutally asks for one, at which point we also have a drm_file to associate it with. --- linux-core/radeon_pm.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 5d14384c..de107797 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -54,10 +54,10 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!radeon_fb) continue; - if (!radeon_fb->obj) + if (!radeon_fb->base.mm_private) continue; - radeon_gem_object_unpin(radeon_fb->obj); + radeon_gem_object_unpin(radeon_fb->base.mm_private); } if (!(dev_priv->flags & RADEON_IS_IGP)) @@ -168,10 +168,11 @@ int radeon_resume(struct drm_device *dev) if (!radeon_fb) continue; - if (!radeon_fb->obj) + if (!radeon_fb->base.mm_private) continue; - radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); + radeon_gem_object_pin(radeon_fb->base.mm_private, + PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); } /* blat the mode back in */ drm_helper_resume_force_mode(dev); -- cgit v1.2.3 From 3e3280eccc38cd080cbab7b471aad1b9cd12fd1b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:52:28 +1000 Subject: radeon: move memcpy until after CP is stopped --- linux-core/radeon_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index de107797..1a814d91 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -63,16 +63,16 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!(dev_priv->flags & RADEON_IS_IGP)) drm_bo_evict_mm(dev, DRM_BO_MEM_VRAM, 0); - if (dev_priv->flags & RADEON_IS_PCIE) { - memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); - } - dev_priv->pmregs.crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); for (i = 0; i < 8; i++) dev_priv->pmregs.bios_scratch[i] = RADEON_READ(RADEON_BIOS_0_SCRATCH + (i * 4)); radeon_modeset_cp_suspend(dev); + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); + } + pci_save_state(dev->pdev); if (state.event == PM_EVENT_SUSPEND) { -- cgit v1.2.3 From 318770a78dc563a9a2780614fa3bf6c813584889 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:53:55 +1000 Subject: radeon: fixup suspend/resume bus master enable --- linux-core/radeon_pm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 1a814d91..0a068cb8 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -97,12 +97,14 @@ int radeon_resume(struct drm_device *dev) pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) return -1; - pci_set_master(dev->pdev); - /* Turn on bus mastering */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); + /* Turn on bus mastering -todo fix properly */ + if (dev_priv->chip_family < CHIP_RV380) { + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + } + DRM_ERROR("\n"); /* on atom cards re init the whole card and set the modes again */ @@ -113,6 +115,8 @@ int radeon_resume(struct drm_device *dev) radeon_combios_asic_init(dev); } + pci_set_master(dev->pdev); + for (i = 0; i < 8; i++) RADEON_WRITE(RADEON_BIOS_0_SCRATCH + (i * 4), dev_priv->pmregs.bios_scratch[i]); @@ -160,7 +164,7 @@ int radeon_resume(struct drm_device *dev) master_priv->sarea_priv->ctx_owner = 0; } - /* unpin the front buffers */ + /* pin the front buffers */ list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); -- cgit v1.2.3 From 66740cbd5411a870dc6cc282c19a72809dd992be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:55:24 +1000 Subject: radeon: fixup interrupt suspend/resume --- linux-core/radeon_pm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 0a068cb8..6b1e6f84 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -69,6 +69,11 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) radeon_modeset_cp_suspend(dev); + /* Disable *all* interrupts */ + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, 0); + RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); + if (dev_priv->flags & RADEON_IS_PCIE) { memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); } @@ -155,7 +160,9 @@ int radeon_resume(struct drm_device *dev) /* reset swi reg */ RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); -// radeon_enable_interrupt(dev); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); + RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); /* reset the context for userspace */ if (dev->primary->master) { -- cgit v1.2.3 From 1c817cc3fc09abe93539413130de3875e4c7eafe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:32:39 +1000 Subject: radeon: pull bus master enable into its own function --- linux-core/radeon_pm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 6b1e6f84..db8f44c4 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -93,7 +93,6 @@ int radeon_resume(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb; int i; - u32 tmp; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return 0; @@ -104,10 +103,7 @@ int radeon_resume(struct drm_device *dev) return -1; /* Turn on bus mastering -todo fix properly */ - if (dev_priv->chip_family < CHIP_RV380) { - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); - } + radeon_enable_bm(dev_priv); DRM_ERROR("\n"); /* on atom cards re init the whole card -- cgit v1.2.3 From 563e7e5930a8d628b33cb1f7a9aaea251f2fc50b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:36:03 +1000 Subject: radeon/drm: fixup ref counting in on fb objs --- linux-core/radeon_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux-core/radeon_pm.c') diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index db8f44c4..259d42da 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -54,10 +54,10 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!radeon_fb) continue; - if (!radeon_fb->base.mm_private) + if (!radeon_fb->obj) continue; - radeon_gem_object_unpin(radeon_fb->base.mm_private); + radeon_gem_object_unpin(radeon_fb->obj); } if (!(dev_priv->flags & RADEON_IS_IGP)) @@ -175,10 +175,10 @@ int radeon_resume(struct drm_device *dev) if (!radeon_fb) continue; - if (!radeon_fb->base.mm_private) + if (!radeon_fb->obj) continue; - radeon_gem_object_pin(radeon_fb->base.mm_private, + radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); } /* blat the mode back in */ -- cgit v1.2.3