From patchwork Thu Dec 9 23:00:46 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Barnes X-Patchwork-Id: 396772 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oB9N1FJ4032012 for ; Thu, 9 Dec 2010 23:01:36 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BFC239EAEE for ; Thu, 9 Dec 2010 15:01:13 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from cpoproxy2-pub.bluehost.com (cpoproxy2-pub.bluehost.com [67.222.39.38]) by gabe.freedesktop.org (Postfix) with SMTP id 98BEC9E807 for ; Thu, 9 Dec 2010 15:00:49 -0800 (PST) Received: (qmail 807 invoked by uid 0); 9 Dec 2010 23:00:48 -0000 Received: from unknown (HELO box514.bluehost.com) (74.220.219.114) by cpoproxy2.bluehost.com with SMTP; 9 Dec 2010 23:00:48 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=virtuousgeek.org; h=Received:Date:From:To:Subject:Message-ID:X-Mailer:Mime-Version:Content-Type:Content-Transfer-Encoding:X-Identified-User; b=oRFTSH4XnydDoP/5xC2vedNXrZvL6JkC8X/OACa3wgYN+i2vpUDVBXhUjWS7Zoz6INOKlG25t4aWJ3NRKXD+Z0zi99t5c2G12DRZzKswCivsSf8pbJKGJU0HXHBkOFOC; Received: from c-67-174-193-198.hsd1.ca.comcast.net ([67.174.193.198] helo=jbarnes-desktop) by box514.bluehost.com with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.69) (envelope-from ) id 1PQpTk-00025h-Gb for intel-gfx@lists.freedesktop.org; Thu, 09 Dec 2010 16:00:48 -0700 Date: Thu, 9 Dec 2010 15:00:46 -0800 From: Jesse Barnes To: intel-gfx@lists.freedesktop.org Message-ID: <20101209150046.23bef984@jbarnes-desktop> X-Mailer: Claws Mail 3.7.6 (GTK+ 2.18.9; x86_64-redhat-linux-gnu) Mime-Version: 1.0 X-Identified-User: {10642:box514.bluehost.com:virtuous:virtuousgeek.org} {sentby:smtp auth 67.174.193.198 authed with jbarnes@virtuousgeek.org} Subject: [Intel-gfx] [PATCH] drm/i915: render p-state support for Sandybridge X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 09 Dec 2010 23:01:36 +0000 (UTC) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1f4f3ce..f25e960 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -658,15 +658,42 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u16 rgvswctl = I915_READ16(MEMSWCTL); - u16 rgvstat = I915_READ16(MEMSTAT_ILK); - - seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); - seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); - seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> - MEMSTAT_VID_SHIFT); - seq_printf(m, "Current P-state: %d\n", - (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); + + if (IS_GEN5(dev)) { + u16 rgvswctl = I915_READ16(MEMSWCTL); + u16 rgvstat = I915_READ16(MEMSTAT_ILK); + + seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); + seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f); + seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> + MEMSTAT_VID_SHIFT); + seq_printf(m, "Current P-state: %d\n", + (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); + } else if (IS_GEN6(dev)) { + u32 gt_perf_status = I915_READ(0x145948); + u32 rp_state_limits = I915_READ(0x145994); + u32 rp_state_cap = I915_READ(0x145998); + int max_freq; + + seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); + seq_printf(m, "Render p-state ratio: %d\n", + (gt_perf_status & 0xff00) >> 8); + seq_printf(m, "Render p-state VID: %d\n", + gt_perf_status & 0xff); + seq_printf(m, "Render p-state limit: %d\n", + rp_state_limits & 0xff); + + max_freq = (rp_state_cap & 0xff0000) >> 16; + seq_printf(m, "Max RPN frequency: %dMHz\n", max_freq * 100); + + max_freq = (rp_state_cap & 0xff00) >> 8; + seq_printf(m, "Max RP1 frequency: %dMHz\n", max_freq * 100); + + max_freq = rp_state_cap & 0xff; + seq_printf(m, "Max RP0 frequency: %dMHz\n", max_freq * 100); + } else { + seq_printf(m, "no P-state info available\n"); + } return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 80745f8..d0eeaae 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -509,6 +509,7 @@ i915_pci_remove(struct pci_dev *pdev) struct drm_device *dev = pci_get_drvdata(pdev); drm_put_dev(dev); + pci_disable_device(pdev); } static int i915_pm_suspend(struct device *dev) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 90414ae..6c5a1c4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -186,6 +186,7 @@ struct drm_i915_display_funcs { void (*update_wm)(struct drm_device *dev, int planea_clock, int planeb_clock, int sr_hdisplay, int sr_htotal, int pixel_size); + void (*handle_rps_change)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -1161,6 +1162,7 @@ extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); +extern void sandybridge_set_drps(struct drm_device *dev, u8 val); extern void intel_detect_pch (struct drm_device *dev); extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 62aa93a..9d828ef 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -306,6 +306,38 @@ static void notify_ring(struct drm_device *dev, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); } +static void sandybridge_pm_irq_handler(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u8 new_delay = dev_priv->cur_delay; + u32 pm_iir; + + pm_iir = I915_READ(PMIIR); + if (!pm_iir) + return; + + DRM_ERROR("received PM interrupt: 0x%08x\n", pm_iir); + DRM_ERROR(" ISR: 0x%08x, IMR: 0x%08x, IER: 0x%08x\n", + I915_READ(PMISR), I915_READ(PMIMR), I915_READ(PMIER)); + + if (pm_iir & PM_RP_UP) { + if (dev_priv->cur_delay != dev_priv->max_delay) + new_delay = dev_priv->cur_delay + 1; + if (new_delay > dev_priv->max_delay) + new_delay = dev_priv->max_delay; + } else if (pm_iir & PM_RP_DOWN) { + if (dev_priv->cur_delay != dev_priv->min_delay) + new_delay = dev_priv->cur_delay - 1; + if (new_delay < dev_priv->min_delay) + new_delay = dev_priv->min_delay; + } + + sandybridge_set_drps(dev, new_delay); + dev_priv->cur_delay = new_delay; + + I915_WRITE(PMIIR, pm_iir); +} + static irqreturn_t ironlake_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -379,6 +411,9 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) i915_handle_rps_change(dev); } + if (IS_GEN6(dev)) + sandybridge_pm_irq_handler(dev); + /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8415950..6bc0c21 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -888,6 +888,48 @@ #define PALETTE_A 0x0a000 #define PALETTE_B 0x0a800 +/* + * Sandybridge PM regs + */ +#define RPNSWREQ 0x0a008 +#define RPVSWREQ 0x0a00c +#define RPDNTIMOUT 0x0a010 /* in usec */ +#define RPINTLIM 0x0a014 +#define RPSTAT1 0x0a01c +#define RPMODECTL1 0x0a024 +#define RPINCLIMIT 0x0a02c +#define RPDECLIMIT 0x0a030 +#define RPCURUPEI 0x0a050 +#define RPCURUP 0x0a054 +#define RPPREVUP 0x0a058 +#define RPCURDNEI 0x0a05c +#define RPCURDN 0x0a060 +#define RPPREVDN 0x0a064 +#define RPUPEI 0x0a068 +#define RPDNEI 0x0a06c +#define GPMPIHYST 0x0a070 +#define RPDEUCSW 0x0a088 +#define RCCTL1 0x0a090 +#define RCCTL2 0x0a094 +#define RC1WRL 0x0a098 +#define RCxWRL 0x0a09c +#define RCDPSTRC6WRL 0x0a0a0 +#define RCWC 0x0a0a4 +#define RCI 0x0a0a8 +#define RCIHYST 0x0a0ac +#define RCUBMABDTMR 0x0a0b0 +#define RC1TIMER 0x0a0b4 +#define RC6TIMER 0x0a0b8 +#define RCDEEPRC6TIMER 0x0a0bc +#define RCDEEPESTRC6TIMER 0x0a0c0 +#define PMINTRMSK 0x0a168 +#define PMINTR_TOINTRMSK (1<<6) +#define PMINTR_UPINTRMSK (1<<5) +#define PMINTR_DOWNINTRMSK (1<<4) +#define PMINTR_TEMPMSK (1<<3) +#define PMINTR_EIUPINTRMSK (1<<2) +#define PMINTR_EIDNINTRMSK (1<<1) + /* MCH MMIO space */ /* @@ -2433,6 +2475,14 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +/* Sandybridge PM */ +#define PMISR 0x44020 +#define PMIMR 0x44024 +#define PM_RP_UP (1<<5) +#define PM_RP_DOWN (1<<4) +#define PMIIR 0x44028 +#define PMIER 0x4402c + /* Ironlake */ #define CPU_VGACNTRL 0x41000 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 454c064..39641fd 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -771,8 +771,10 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveIMR = I915_READ(IMR); } - if (HAS_PCH_SPLIT(dev)) + if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); + if (IS_GEN6(dev)) + sandybridge_disable_drps(dev); /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); @@ -862,11 +864,14 @@ int i915_restore_state(struct drm_device *dev) /* Clock gating state */ intel_init_clock_gating(dev); - if (HAS_PCH_SPLIT(dev)) { + if (IS_IRONLAKE_M(dev)) { ironlake_enable_drps(dev); intel_init_emon(dev); } + if (IS_GEN6(dev)) + sandybridge_enable_drps(dev); + /* Cache mode state */ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 48d8fd6..0a6750a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5654,6 +5654,92 @@ void ironlake_disable_drps(struct drm_device *dev) } +void sandybridge_set_drps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 swreq; + + DRM_ERROR("setting render p-state to %d\n", val); + + swreq = (val & 0x3ff) << 25; + I915_WRITE(0xa18c, 1); /* force wake */ + wait_for_atomic((I915_READ(0x130090) & 1) == 1, 100); /* wait for wake */ + I915_WRITE(0xa008, swreq); + I915_WRITE(0xa18c, 0); /* clear force wake */ + wait_for_atomic((I915_READ(0x130090) & 1) == 0, 100); /* wait for sleep */ + + DRM_ERROR("RPNSWREQ: 0x%08x\n", I915_READ(0xa008)); +} + +void sandybridge_enable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 gt_perf_status = I915_READ(0x145948); + u32 rp_state_cap = I915_READ(0x145998); + u64 perf_ctl; + + rdmsrl(0x199, perf_ctl); + DRM_ERROR("IA32_PERF_CTL: 0x%016llx\n", (unsigned long long)perf_ctl); + DRM_ERROR("RPNSWREQ: 0x%08x\n", I915_READ(0xa008)); + + I915_WRITE(0xa094, 0); /* set rc0 */ + I915_WRITE(0xa18c, 1); /* force wake */ + wait_for((I915_READ(0x130090) & 1) == 1, 100); /* wait for wake */ + I915_WRITE(0xa090, 0); /* disable hw rc */ + I915_WRITE(0xa098, 0x3e80000); /* rc1e wake rate limit */ + I915_WRITE(0xa09c, 0x28001e); /* rc6/6p wake rate limit */ + I915_WRITE(0xa0a0, 0x1e); /* rc6pp wake rate limit */ + I915_WRITE(0xa0ac, 0x64); /* idle hysteresis */ + I915_WRITE(0x2054, 0xa); /* render idle max count */ + I915_WRITE(0x12054, 0xa); /* video idle max count */ + I915_WRITE(0x22054, 0xa); /* blitter idle max count */ + I915_WRITE(0xa0b0, 0); /* unblock ack to busy */ + I915_WRITE(0xa0b4, 0x3e8); /* rc1e threshold 1ms/EI */ + I915_WRITE(0xa0b8, 0xc350); /* rc6 threshold 40% */ + I915_WRITE(0xa0bc, 0x186a0); /* rc6p threshold */ + I915_WRITE(0xa0c0, 0xfa00); /* rc6pp threshold */ + I915_WRITE(0xa090, 0x88040000); /* enable rc etc */ + I915_WRITE(0xa008, 0x14000000); /* enable turbo, request 1GHz .. */ + I915_WRITE(0xa00c, 0x18000000); /* 1.2GHz video freq */ + I915_WRITE(0xa010, 0xf4240); /* rp down timeout 1s */ + I915_WRITE(0xa014, 0x12060000); /* interrupt limits */ + I915_WRITE(0xa02c, 0x15f90); /* rp up threshold */ + I915_WRITE(0xa030, 0x186a0); /* rp down threshold */ + I915_WRITE(0xa068, 0x186a0); /* rp up ei 100ms */ + I915_WRITE(0xa06c, 0x493e0); /* rp down ei 300ms */ + I915_WRITE(0xa070, 0xa); /* idle hysteresis 0us */ + I915_WRITE(0xa024, 0xb92); /* rp control */ + wait_for((I915_READ(0x138124) & 0x80000000) == 0, 100); + I915_WRITE(0x138128, 0); + I915_WRITE(0x138124, 0x80000004); + wait_for((I915_READ(0x138124) & 0x80000000) == 0, 100); + I915_WRITE(0x4402c, 0x3000076); /* enable PM interrupts */ + I915_WRITE(0xa18c, 0); /* clear force wake */ + wait_for((I915_READ(0x130090) & 1) == 0, 100); /* wait for sleep */ + + dev_priv->max_delay = rp_state_cap & 0xff; + dev_priv->min_delay = 0; + dev_priv->cur_delay = (gt_perf_status & 0xff00) >> 8; + + DRM_ERROR("DRPS initialized, max freq %dMHz, current %dMHz\n", + dev_priv->max_delay * 100, dev_priv->cur_delay * 100); + + /* Enable the interrupts */ + I915_WRITE(PMIER, ~0); + I915_WRITE(PMIMR, 0); + I915_WRITE(PMINTRMSK, 0); +// I915_WRITE(PMINTRMSK, PMINTR_TOINTRMSK | PMINTR_UPINTRMSK | +// PMINTR_DOWNINTRMSK | PMINTR_TEMPMSK | PMINTR_EIUPINTRMSK | +// PMINTR_EIDNINTRMSK); +} + +void sandybridge_disable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(0xa008, 1 << 31); +} + static unsigned long intel_pxfreq(u32 vidfreq) { unsigned long freq; @@ -6137,6 +6223,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_emon(dev); } + if (IS_GEN6(dev)) + sandybridge_enable_drps(dev); + INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); @@ -6190,6 +6279,8 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); + if (IS_GEN6(dev)) + sandybridge_disable_drps(dev); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 21551fe..c7d86cb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -296,6 +296,8 @@ extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, extern void intel_init_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); +extern void sandybridge_enable_drps(struct drm_device *dev); +extern void sandybridge_disable_drps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,