From e3c74757c23cbbbb0c64b34c107732f3e2d67fa3 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:39 -0700 Subject: drm/i915: Support PCH no display GEN supports a fusing option which subtracts the PCH display (making the CPU display also useless). In this configuration MMIO which gets decoded to a certain range will hang the CPU. For us, this is sort of the equivalent of having no pipes, and we can easily modify some code to not do certain things with no pipes. v2: Moved the num pipes check up in the call chain, and removed extra checks noted by Daniel. For more details, see: http://lists.freedesktop.org/archives/intel-gfx/2013-March/025746.html v3: Drop the intel_setup_overlay check (Daniel) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 20 ++++++++++++++------ drivers/gpu/drm/i915/intel_display.c | 3 +++ drivers/gpu/drm/i915/intel_fb.c | 3 +++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4be58e3b8e4f..4a1a517b09e5 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1322,6 +1322,10 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; + if (INTEL_INFO(dev)->num_pipes == 0) { + dev_priv->mm.suspended = 0; + return 0; + } ret = intel_fbdev_init(dev); if (ret) @@ -1634,9 +1638,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_VALLEYVIEW(dev)) dev_priv->num_plane = 2; - ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); - if (ret) - goto out_gem_unload; + if (INTEL_INFO(dev)->num_pipes) { + ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes); + if (ret) + goto out_gem_unload; + } /* Start out suspended */ dev_priv->mm.suspended = 1; @@ -1651,9 +1657,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) i915_setup_sysfs(dev); - /* Must be done after probing outputs */ - intel_opregion_init(dev); - acpi_video_register(); + if (INTEL_INFO(dev)->num_pipes) { + /* Must be done after probing outputs */ + intel_opregion_init(dev); + acpi_video_register(); + } if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b7005640144c..945fa9f245af 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8991,6 +8991,9 @@ void intel_modeset_init(struct drm_device *dev) intel_init_pm(dev); + if (INTEL_INFO(dev)->num_pipes == 0) + return; + intel_init_display(dev); if (IS_GEN2(dev)) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8d81c929b7b5..0e19e575a1b4 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -283,6 +283,9 @@ void intel_fb_restore_mode(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; + if (INTEL_INFO(dev)->num_pipes == 0) + return; + drm_modeset_lock_all(dev); ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); -- cgit v1.2.2 From 40c7ead980945ac96eadbd6d99b050458d797e2b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:40 -0700 Subject: drm/i915: PCH_NOP Given certain fusing options discussed in the previous patch, it's possible to end up with platforms that normally have PCH but that PCH doesn't actually exist. In many cases, this is easily remedied with setting 0 pipes. This covers the other corners. Requiring this is a symptom of improper code splitting (using HAS_PCH_SPLIT instead of proper GEN checking, basically). I do not want to fix this. v2: Remove PCH reflck after change in previous patch (Daniel) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 44fca0b69473..69ddfd1c18f5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -479,6 +479,7 @@ enum intel_pch { PCH_IBX, /* Ibexpeak PCH */ PCH_CPT, /* Cougarpoint PCH */ PCH_LPT, /* Lynxpoint PCH */ + PCH_NOP, }; enum intel_sbi_destination { @@ -1373,6 +1374,7 @@ struct drm_i915_file_private { #define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT) #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT) #define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX) +#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP) #define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE) #define HAS_FORCE_WAKE(dev) (INTEL_INFO(dev)->has_force_wake) -- cgit v1.2.2 From ab5c608b2d96c8db80b9c7df072f18f3a4226b55 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:41 -0700 Subject: drm/i915: Don't touch South Display when PCH_NOP Interrupts, clock gating, LVDS, and GMBUS are all within the, "this will be bad for CPU" range when we have PCH_NOP. There is a bit of a hack in init clock gating. We want to do most of the clock gating, but the part we skip will hang the system. It could probably be abstracted a bit better, but I don't feel it's too unsightly. v2: Use inverse HAS_PCH_NOP check (Jani) v3: Actually do what I claimed in v2 (spotted by Daniel) Merge Ivybridge IRQ handler PCH check to decrease whitespace (Daniel) Move LVDS bail into this patch (Ben) v4: logical rebase conflict resolution with SDEIIR (Ben) Signed-off-by: Ben Widawsky Brush up patch a bit and resolve conflicts: - Adjust PCH_NOP checks due to Egbert's hpd handling rework. - Addd a PCH_NOP check in the irq uninstall code. - Resolve conflicts with Paulo's SDE irq handling race fix. v5: Drop the added hunks in the ilk irq handler again, they're bogus. OOps. Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 28 +++++++++++++++++++++------- drivers/gpu/drm/i915/intel_bios.c | 3 +++ drivers/gpu/drm/i915/intel_i2c.c | 4 +++- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4c5bdd037388..b4e237d9927d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -758,7 +758,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier = 0; irqreturn_t ret = IRQ_NONE; int i; @@ -773,9 +773,11 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) * able to process them after we restore SDEIER (as soon as we restore * it, we'll get an interrupt if SDEIIR still has something to process * due to its back queue). */ - sde_ier = I915_READ(SDEIER); - I915_WRITE(SDEIER, 0); - POSTING_READ(SDEIER); + if (!HAS_PCH_NOP(dev)) { + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + } gt_iir = I915_READ(GTIIR); if (gt_iir) { @@ -802,7 +804,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) } /* check event from PCH */ - if (de_iir & DE_PCH_EVENT_IVB) { + if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) { u32 pch_iir = I915_READ(SDEIIR); cpt_irq_handler(dev, pch_iir); @@ -825,8 +827,10 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); - I915_WRITE(SDEIER, sde_ier); - POSTING_READ(SDEIER); + if (!HAS_PCH_NOP(dev)) { + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); + } return ret; } @@ -2027,6 +2031,9 @@ static void ironlake_irq_preinstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); POSTING_READ(GTIER); + if (HAS_PCH_NOP(dev)) + return; + /* south display irq */ I915_WRITE(SDEIMR, 0xffffffff); /* @@ -2112,6 +2119,10 @@ static void ibx_irq_postinstall(struct drm_device *dev) mask = SDE_GMBUS | SDE_AUX_MASK; else mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT; + + if (HAS_PCH_NOP(dev)) + return; + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); I915_WRITE(SDEIMR, ~mask); } @@ -2306,6 +2317,9 @@ static void ironlake_irq_uninstall(struct drm_device *dev) I915_WRITE(GTIER, 0x0); I915_WRITE(GTIIR, I915_READ(GTIIR)); + if (HAS_PCH_NOP(dev)) + return; + I915_WRITE(SDEIMR, 0xffffffff); I915_WRITE(SDEIER, 0x0); I915_WRITE(SDEIIR, I915_READ(SDEIIR)); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 55ffba1f5818..194df27c89eb 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -692,6 +692,9 @@ intel_parse_bios(struct drm_device *dev) struct bdb_header *bdb = NULL; u8 __iomem *bios = NULL; + if (HAS_PCH_NOP(dev)) + return -ENODEV; + init_vbt_defaults(dev_priv); /* XXX Should this validation be moved to intel_opregion.c? */ diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index ef4744e1bf0b..5d245031e391 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -522,7 +522,9 @@ int intel_setup_gmbus(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_NOP(dev)) + return 0; + else if (HAS_PCH_SPLIT(dev)) dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; else if (IS_VALLEYVIEW(dev)) dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 13a0666a53b4..17f157a7b640 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3890,7 +3890,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) snpcr |= GEN6_MBC_SNPCR_MED; I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); - cpt_init_clock_gating(dev); + if (!HAS_PCH_NOP(dev)) + cpt_init_clock_gating(dev); gen6_check_mch_setup(dev); } -- cgit v1.2.2 From 88a2b2a32d71aad6d8dcd843294b00a204faa66b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:43 -0700 Subject: drm/i915: Don't wait for PCH on reset BIOS should be setting this, but in case it doesn't... v2: Define the bits we actually want to clear (Jesse) Make it an RMW op (Jesse) Signed-off-by: Ben Widawsky Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++++ drivers/gpu/drm/i915/i915_reg.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 911bd40ef513..74c560150293 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3992,6 +3992,12 @@ i915_gem_init_hw(struct drm_device *dev) if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + if (HAS_PCH_NOP(dev)) { + u32 temp = I915_READ(GEN7_MSG_CTL); + temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK); + I915_WRITE(GEN7_MSG_CTL, temp); + } + i915_gem_l3_remap(dev); i915_gem_init_swizzling(dev); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 058686c0dbbf..0e4b7fb7d691 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3568,6 +3568,9 @@ #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) +#define GEN7_MSG_CTL 0x45010 +#define WAIT_FOR_PCH_RESET_ACK (1<<1) +#define WAIT_FOR_PCH_FLR_ACK (1<<0) /* GEN7 chicken */ #define GEN7_COMMON_SLICE_CHICKEN1 0x7010 -- cgit v1.2.2 From ce1bb329795c3efc4bfd8846ee4ef1798536307a Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:44 -0700 Subject: drm/i915: Set PCH_NOP Set up PCH_NOP when we match a certain platform. v2: Just do a num_pipes check + comment instead of trying to check the platform (Daniel) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 3b4b9c09a20b..88d78e39bf6d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -397,6 +397,15 @@ void intel_detect_pch(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct pci_dev *pch; + /* In all current cases, num_pipes is equivalent to the PCH_NOP setting + * (which really amounts to a PCH but no South Display). + */ + if (INTEL_INFO(dev)->num_pipes == 0) { + dev_priv->pch_type = PCH_NOP; + dev_priv->num_pch_pll = 0; + return; + } + /* * The reason to probe ISA bridge instead of Dev31:Fun0 is to * make graphics device passthrough work easy for VMM, that only -- cgit v1.2.2 From 999bcdea3206ea8a402c010f78060cd3da4f812c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 13:12:45 -0700 Subject: drm/i915: Add a pipeless ivybridge configuration FIXME: This is based on some HW being used for a demo. We should probably wait until we have confirmation on the IDs before upstreaming this patch. v2: Use GEN7_FEATURES (Chris) Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 88d78e39bf6d..bd92e7d47653 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -140,6 +140,16 @@ extern int intel_agp_enabled; .subdevice = PCI_ANY_ID, \ .driver_data = (unsigned long) info } +#define INTEL_QUANTA_VGA_DEVICE(info) { \ + .class = PCI_BASE_CLASS_DISPLAY << 16, \ + .class_mask = 0xff0000, \ + .vendor = 0x8086, \ + .device = 0x16a, \ + .subvendor = 0x152d, \ + .subdevice = 0x8990, \ + .driver_data = (unsigned long) info } + + static const struct intel_device_info intel_i830_info = { .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2, .has_overlay = 1, .overlay_needs_physical = 1, @@ -272,6 +282,12 @@ static const struct intel_device_info intel_ivybridge_m_info = { .is_mobile = 1, }; +static const struct intel_device_info intel_ivybridge_q_info = { + GEN7_FEATURES, + .is_ivybridge = 1, + .num_pipes = 0, /* legal, last one wins */ +}; + static const struct intel_device_info intel_valleyview_m_info = { GEN7_FEATURES, .is_mobile = 1, @@ -342,6 +358,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */ INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */ + INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */ INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ -- cgit v1.2.2 From 7a7d1fb79fb581553f4830498045de774a9659f8 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Thu, 4 Apr 2013 16:04:02 -0400 Subject: drm/i915: Fix SDVO connector and encoder get_hw_state functions The connector associated with the encoder is considered active when the output associtated with this connector is active on the encoder. The encoder itself is considered active when either there is an active output on it or the respective SDVO channel is active. Having active outputs when the SDVO channel is inactive seems to be inconsistent: such states can be found when intel_modeset_setup_hw_state() collects the hardware state set by the BIOS. This inconsistency will be fixed in intel_sanitize_crtc() (when intel_crtc_update_dpms() is called), this however only happens when the encoder is associated with a crtc. This patch also reverts: commit bd6946e87a98fea11907b2a47368e13044458a35 Author: Daniel Vetter Date: Tue Apr 2 21:30:34 2013 +0200 drm/i915: Fix sdvo connector get_hw_state function Signed-off-by: Egbert Eich Suggested-by: Daniel Vetter Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=63031 Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 298dc85ec32c..f6a9f4a0d7f0 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1231,12 +1231,8 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector) struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(&connector->base); struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base); - struct drm_i915_private *dev_priv = intel_sdvo->base.base.dev->dev_private; u16 active_outputs; - if (!(I915_READ(intel_sdvo->sdvo_reg) & SDVO_ENABLE)) - return false; - intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); if (active_outputs & intel_sdvo_connector->output_flag) @@ -1251,11 +1247,13 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); + u16 active_outputs; u32 tmp; tmp = I915_READ(intel_sdvo->sdvo_reg); + intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs); - if (!(tmp & SDVO_ENABLE)) + if (!(tmp & SDVO_ENABLE) && (active_outputs == 0)) return false; if (HAS_PCH_CPT(dev)) @@ -2746,7 +2744,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) struct intel_sdvo *intel_sdvo; u32 hotplug_mask; int i; - intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL); if (!intel_sdvo) return false; -- cgit v1.2.2 From 7d0ac5b74ec091b0829fa9d17bc717c907dcd62d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Apr 2013 22:20:32 +0200 Subject: drm/i915: fix lost FP_CB_TUNE setting for pch plls commit de13a2e3f88a4da8e85063b6de37096795079e41 Author: Paulo Zanoni Date: Thu Sep 20 18:36:05 2012 -0300 drm/i915: extract compute_dpll from ironlake_crtc_mode_set missed the subtle adjustment of the FP1 register. Fix this up by passing a pointer around instead of the value. Cc: Paulo Zanoni Cc: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 945fa9f245af..baacfcbbbbe7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5469,7 +5469,7 @@ static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) } static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, - intel_clock_t *clock, u32 fp) + intel_clock_t *clock, u32 *fp) { struct drm_crtc *crtc = &intel_crtc->base; struct drm_device *dev = crtc->dev; @@ -5509,7 +5509,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 20; if (clock->m < factor * clock->n) - fp |= FP_CB_TUNE; + *fp |= FP_CB_TUNE; dpll = 0; @@ -5626,7 +5626,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | reduced_clock.m2; - dpll = ironlake_compute_dpll(intel_crtc, &clock, fp); + dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp); DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); -- cgit v1.2.2 From f0b4405687f8b35173575be8493bf2af84b85091 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Apr 2013 22:20:33 +0200 Subject: drm/i915: fix FP CB tuning limits for lvds Only on IBX should we set the limiting factor to 25 unconditionally for dual-channel mode, on CPT/PPT 25 only applies when the lvds refclock is 100MHz. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index baacfcbbbbe7..f235e8a48b38 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5503,7 +5503,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || - intel_is_dual_link_lvds(dev)) + (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (is_sdvo && is_tv) factor = 20; -- cgit v1.2.2 From 9a7c7890d2f05af63f98ac397597755a3c009485 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 4 Apr 2013 22:20:34 +0200 Subject: drm/i915: set CB tuning also for the reduce clock Since the ratio is different, we also need to pass in the parameters for the reduced clock. Might or might not reduce flicker for the auto-downclocking on lvds/eDP. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f235e8a48b38..b884932c2e00 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5469,7 +5469,8 @@ static void ironlake_fdi_set_m_n(struct drm_crtc *crtc) } static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, - intel_clock_t *clock, u32 *fp) + intel_clock_t *clock, u32 *fp, + intel_clock_t *reduced_clock, u32 *fp2) { struct drm_crtc *crtc = &intel_crtc->base; struct drm_device *dev = crtc->dev; @@ -5511,6 +5512,9 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (clock->m < factor * clock->n) *fp |= FP_CB_TUNE; + if (fp2 && (reduced_clock->m < factor * reduced_clock->n)) + *fp2 |= FP_CB_TUNE; + dpll = 0; if (is_lvds) @@ -5626,7 +5630,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | reduced_clock.m2; - dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp); + dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock, + has_reduced_clock ? &fp2 : NULL); DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); -- cgit v1.2.2 From 8bb6e9590b6a568c643d0e8e73e0689ceb489e01 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 6 Apr 2013 23:54:56 +0200 Subject: drm/i915: tune down Y tiling scanout warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Userspace can easily hit this and does since Ville added a new evil igt testcase in: commit 069e35e0fc3785faa562adcfd2dd7bbed4cb1dea Author: Ville Syrjälä Date: Mon Mar 4 15:34:06 2013 +0200 kms_flip: Add flip-vs-bad-tiling test v2: Fix the spelling in the added comment (Chris). Cc: Ville Syrjälä Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=63246 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b884932c2e00..04d91cc21381 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2002,8 +2002,10 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, alignment = 0; break; case I915_TILING_Y: - /* FIXME: Is this true? */ - DRM_ERROR("Y tiled not allowed for scan out buffers\n"); + /* Despite that we check this in framebuffer_init userspace can + * screw us over and change the tiling after the fact. Only + * pinned buffers can't change their tiling. */ + DRM_DEBUG_DRIVER("Y tiled not allowed for scan out buffers\n"); return -EINVAL; default: BUG(); -- cgit v1.2.2 From 25ff1195f8a0b3724541ae7bbe331b4296de9c06 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 4 Apr 2013 21:31:03 +0100 Subject: drm/i915: Workaround incoherence between fences and LLC across multiple CPUs In order to fully serialize access to the fenced region and the update to the fence register we need to take extreme measures on SNB+, and manually flush writes to memory prior to writing the fence register in conjunction with the memory barriers placed around the register write. Fixes i-g-t/gem_fence_thrash v2: Bring a bigger gun v3: Switch the bigger gun for heavier bullets (Arjan van de Ven) v4: Remove changes for working generations. v5: Reduce to a per-cpu wbinvd() call prior to updating the fences. v6: Rewrite comments to ellide forgotten history. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=62191 Signed-off-by: Chris Wilson Cc: Jon Bloomfield Tested-by: Jon Bloomfield (v2) Cc: stable@vger.kernel.org Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 74c560150293..63c05ddea612 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2683,17 +2683,35 @@ static inline int fence_number(struct drm_i915_private *dev_priv, return fence - dev_priv->fence_regs; } +static void i915_gem_write_fence__ipi(void *data) +{ + wbinvd(); +} + static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - int reg = fence_number(dev_priv, fence); - - i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int fence_reg = fence_number(dev_priv, fence); + + /* In order to fully serialize access to the fenced region and + * the update to the fence register we need to take extreme + * measures on SNB+. In theory, the write to the fence register + * flushes all memory transactions before, and coupled with the + * mb() placed around the register write we serialise all memory + * operations with respect to the changes in the tiler. Yet, on + * SNB+ we need to take a step further and emit an explicit wbinvd() + * on each processor in order to manually flush all memory + * transactions before updating the fence register. + */ + if (HAS_LLC(obj->base.dev)) + on_each_cpu(i915_gem_write_fence__ipi, NULL, 1); + i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL); if (enable) { - obj->fence_reg = reg; + obj->fence_reg = fence_reg; fence->obj = obj; list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); } else { -- cgit v1.2.2 From 57d277bbfcfbacaf1dc738bf23279cc60d5cda65 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 8 Apr 2013 11:52:20 +0200 Subject: drm/i915: update FDI mPHY setup code Bspec has been been updated and dropped these two changes for non-sdv LPT PCHs. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 04d91cc21381..880981360e09 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4958,13 +4958,6 @@ static void lpt_init_pch_refclk(struct drm_device *dev) tmp |= (0x12 << 24); intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY); - if (!is_sdv) { - tmp = intel_sbi_read(dev_priv, 0x808C, SBI_MPHY); - tmp &= ~(0x3 << 6); - tmp |= (1 << 6) | (1 << 0); - intel_sbi_write(dev_priv, 0x808C, tmp, SBI_MPHY); - } - if (is_sdv) { tmp = intel_sbi_read(dev_priv, 0x800C, SBI_MPHY); tmp |= 0x7FFF; -- cgit v1.2.2 From 4615d4c9e27eda42c3e965f208a4b4065841498c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 Apr 2013 14:28:40 +0100 Subject: drm/i915: Use MLC (l3$) for context objects Enabling context support increases SwapBuffers latency by about 20% (measured on an i7-3720qm). We can offset that loss slightly by enabling faster caching for the contexts. As they are not backed by any particular cache (such as the sampler or render caches) our only option is to select the generic mid-level cache. This reduces the latency of the swap by about 5%. Oddly this effect can be observed running smokin-guns on IVB at 1280x1024: Using BLT copies for swaps: 151.67 fps Using Render copies for swaps (unpatched): 141.70 fps With contexts disabled: 150.23 fps With contexts in L3$: 150.77 fps Signed-off-by: Chris Wilson Cc: Ben Widawsky Cc: Kenneth Graunke Reviewed-by: Kenneth Graunke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 94d873a6cffb..a1e8ecb6adf6 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -152,6 +152,13 @@ create_hw_context(struct drm_device *dev, return ERR_PTR(-ENOMEM); } + if (INTEL_INFO(dev)->gen >= 7) { + ret = i915_gem_object_set_cache_level(ctx->obj, + I915_CACHE_LLC_MLC); + if (ret) + goto err_out; + } + /* The ring associated with the context object is handled by the normal * object tracking code. We give an initial ring value simple to pass an * assertion in the context switch code. -- cgit v1.2.2 From a93e41618ecf69a2ced005a13377d7903da4dd62 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:47 -0700 Subject: drm/i915: generalize pte vs. register BAR allocation All gen6+ parts so far have 1 BAR which holds both the register space and the GTT PTEs. Up until now, that was a 4MB BAR with half allocated to each. I have a strong hunch (wink, nod, wink) that future gens will also keep a similar 50-50 split though the sizes may change. To help this along change the code to obey the rule of half the total size instead of a hard-coded 2MB. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 24a23b31b55f..215d72ce3f67 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -738,8 +738,10 @@ static int gen6_gmch_probe(struct drm_device *dev, *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; - /* For GEN6+ the PTEs for the ggtt live at 2MB + BAR0 */ - gtt_bus_addr = pci_resource_start(dev->pdev, 0) + (2<<20); + /* For Modern GENs the PTEs and register space are split in the BAR */ + gtt_bus_addr = pci_resource_start(dev->pdev, 0) + + (pci_resource_len(dev->pdev, 0) / 2); + dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); if (!dev_priv->gtt.gsm) { DRM_ERROR("Failed to map the gtt page table\n"); -- cgit v1.2.2 From e7c2b58b700f467eedcbd1c8d7a3d4bada403439 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:48 -0700 Subject: drm/i915: Call out GEN6 PTE specificity We can assume that the PTE layout, and size changes for future generations. To avoid confusion with the existing GEN6 PTE typedef, give it a GEN6_ prefix. v2: Fixup checkpatch warning and bikeshed commit message slightly. v3: Rebase on top of Imre's for_each_sg_pages rework. v4: Fixup conflicts in patch series reordering. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 215d72ce3f67..091b2709cdeb 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -28,7 +28,7 @@ #include "i915_trace.h" #include "intel_drv.h" -typedef uint32_t gtt_pte_t; +typedef uint32_t gen6_gtt_pte_t; /* PPGTT stuff */ #define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0)) @@ -44,11 +44,11 @@ typedef uint32_t gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, +static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, dma_addr_t addr, enum i915_cache_level level) { - gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); switch (level) { @@ -72,7 +72,6 @@ static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, BUG(); } - return pte; } @@ -81,8 +80,7 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { - gtt_pte_t *pt_vaddr; - gtt_pte_t scratch_pte; + gen6_gtt_pte_t *pt_vaddr, scratch_pte; unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; @@ -114,7 +112,7 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, enum i915_cache_level cache_level) { - gtt_pte_t *pt_vaddr; + gen6_gtt_pte_t *pt_vaddr; unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES; unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES; struct sg_page_iter sg_iter; @@ -208,7 +206,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->clear_range(ppgtt, 0, ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); - ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); + ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); return 0; @@ -284,7 +282,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev) uint32_t pd_offset; struct intel_ring_buffer *ring; struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - gtt_pte_t __iomem *pd_addr; + gen6_gtt_pte_t __iomem *pd_addr; uint32_t pd_entry; int i; @@ -292,7 +290,8 @@ void i915_gem_init_ppgtt(struct drm_device *dev) return; - pd_addr = (gtt_pte_t __iomem*)dev_priv->gtt.gsm + ppgtt->pd_offset/sizeof(gtt_pte_t); + pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { dma_addr_t pt_addr; @@ -416,8 +415,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev, enum i915_cache_level level) { struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t __iomem *gtt_entries = - (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; + gen6_gtt_pte_t __iomem *gtt_entries = + (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int i = 0; struct sg_page_iter sg_iter; dma_addr_t addr; @@ -451,8 +450,8 @@ static void gen6_ggtt_clear_range(struct drm_device *dev, unsigned int num_entries) { struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; + gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = + (gen6_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry; int i; @@ -736,7 +735,7 @@ static int gen6_gmch_probe(struct drm_device *dev, else *stolen = gen6_get_stolen_size(snb_gmch_ctl); - *gtt_total = (gtt_size / sizeof(gtt_pte_t)) << PAGE_SHIFT; + *gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT; /* For Modern GENs the PTEs and register space are split in the BAR */ gtt_bus_addr = pci_resource_start(dev->pdev, 0) + @@ -816,7 +815,7 @@ int i915_gem_gtt_init(struct drm_device *dev) if (ret) return ret; - gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gtt_pte_t); + gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gen6_gtt_pte_t); /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %zdM\n", -- cgit v1.2.2 From 1e1bd0fd4ef3f74f05e4c164eb57a3b29c5f6790 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:49 -0700 Subject: drm/i915: Map registers before GTT init This will allow us to read/write registers in GTT init. Signed-off-by: Ben Widawsky [danvet: Fix up error handling. We really should look into devres for this stuff ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 47 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 4a1a517b09e5..3b315ba85a3e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1518,6 +1518,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto free_priv; } + mmio_bar = IS_GEN2(dev) ? 1 : 0; + /* Before gen4, the registers and the GTT are behind different BARs. + * However, from gen4 onwards, the registers and the GTT are shared + * in the same BAR, so we want to restrict this ioremap from + * clobbering the GTT which we want ioremap_wc instead. Fortunately, + * the register BAR remains the same size for all the earlier + * generations up to Ironlake. + */ + if (info->gen < 5) + mmio_size = 512*1024; + else + mmio_size = 2*1024*1024; + + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); + if (!dev_priv->regs) { + DRM_ERROR("failed to map registers\n"); + ret = -EIO; + goto put_bridge; + } + + intel_early_sanitize_regs(dev); + ret = i915_gem_gtt_init(dev); if (ret) goto put_bridge; @@ -1542,28 +1564,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); - mmio_bar = IS_GEN2(dev) ? 1 : 0; - /* Before gen4, the registers and the GTT are behind different BARs. - * However, from gen4 onwards, the registers and the GTT are shared - * in the same BAR, so we want to restrict this ioremap from - * clobbering the GTT which we want ioremap_wc instead. Fortunately, - * the register BAR remains the same size for all the earlier - * generations up to Ironlake. - */ - if (info->gen < 5) - mmio_size = 512*1024; - else - mmio_size = 2*1024*1024; - - dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); - if (!dev_priv->regs) { - DRM_ERROR("failed to map registers\n"); - ret = -EIO; - goto put_gmch; - } - - intel_early_sanitize_regs(dev); - aperture_size = dev_priv->gtt.mappable_end; dev_priv->gtt.mappable = @@ -1686,10 +1686,9 @@ out_mtrrfree: dev_priv->mm.gtt_mtrr = -1; } io_mapping_free(dev_priv->gtt.mappable); + dev_priv->gtt.gtt_remove(dev); out_rmmap: pci_iounmap(dev->pdev, dev_priv->regs); -put_gmch: - dev_priv->gtt.gtt_remove(dev); put_bridge: pci_dev_put(dev_priv->bridge_dev); free_priv: -- cgit v1.2.2 From c81dbe056317659ddd7d17779933e5f09d33ffeb Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:50 -0700 Subject: drm/i915: random checkpatch fixes There used to be other fixes in this patch but they've slowly disappeared as other parts have been fixed. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 091b2709cdeb..923c70525f16 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -45,8 +45,8 @@ typedef uint32_t gen6_gtt_pte_t; #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) + dma_addr_t addr, + enum i915_cache_level level) { gen6_gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); @@ -289,7 +289,6 @@ void i915_gem_init_ppgtt(struct drm_device *dev) if (!dev_priv->mm.aliasing_ppgtt) return; - pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); for (i = 0; i < ppgtt->num_pd_entries; i++) { -- cgit v1.2.2 From 1e7d12d46733d5a6ddf3f07a1f9ab75ec12d5a19 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:51 -0700 Subject: drm/i915/ppgtt: Set scratch page "globally" The PPGTT scratch page is used for all gens, and doing it in the global part of our PPGTT setup makes the code a bit nicer. This was in a patch submitted earlier as part of the PPGTT cleanups. Grumpy maintainer must have missed it, and I didn't yell when appropriate. Apologies for everyone :-) v2: Update commit message Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 923c70525f16..0f214fb1a75f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -201,8 +201,6 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->pt_dma_addr[i] = pt_addr; } - ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; - ppgtt->clear_range(ppgtt, 0, ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); @@ -238,6 +236,7 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) return -ENOMEM; ppgtt->dev = dev; + ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; ret = gen6_ppgtt_init(ppgtt); if (ret) -- cgit v1.2.2 From 3eb1c005c616f110ccec25540712ce7232d5d4bf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:52 -0700 Subject: drm/i915: Conditionally carve out GGTT PDE It only works that way on GEN6 and GEN7. Let's not assume GENn will be the same. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0f214fb1a75f..b4ba488e5c83 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -623,9 +623,12 @@ void i915_gem_init_global_gtt(struct drm_device *dev) if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { int ret; - /* PPGTT pdes are stolen from global gtt ptes, so shrink the - * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + + if (INTEL_INFO(dev)->gen <= 7) { + /* PPGTT pdes are stolen from global gtt ptes, so shrink the + * aperture accordingly when using aliasing ppgtt. */ + gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + } i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); -- cgit v1.2.2 From 3ed124b21e6bf388c63b182d9c2d766a6ca0e8be Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:53 -0700 Subject: drm/i915: Rework PPGTT init code This rework will help if future platforms choose to be a bit different. Should have no functional impact. v2: Don't move around the vtable setup (Daniel) v3: Squash in the disable-by-default patch. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b4ba488e5c83..b13ba9d53b19 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -238,7 +238,11 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) ppgtt->dev = dev; ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; - ret = gen6_ppgtt_init(ppgtt); + if (INTEL_INFO(dev)->gen < 8) + ret = gen6_ppgtt_init(ppgtt); + else + BUG(); + if (ret) kfree(ppgtt); else -- cgit v1.2.2 From 6197349bdeb97ee6f533990617c51c67ac233f79 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:54 -0700 Subject: drm/i915: Abstract PPGTT enabling Since we've already set up a nice vtable to abstract other PPGTT functions, also abstract the actual register programming to enable things. This function will probably need to change a bit as we implement real processes. v2: Resolve conflicts due to patch series reordering. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 3 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 3 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 114 ++++++++++++++++++------------------ 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index bd92e7d47653..70d10de73bbd 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -927,7 +927,8 @@ int i915_reset(struct drm_device *dev) ring->init(ring); i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); + if (dev_priv->mm.aliasing_ppgtt) + dev_priv->mm.aliasing_ppgtt->enable(dev); /* * It would make sense to re-init all the other hw state, at diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 69ddfd1c18f5..c1213213e495 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -449,6 +449,7 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); + void (*enable)(struct drm_device *dev); void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; @@ -1642,7 +1643,6 @@ int __must_check i915_gem_init(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); void i915_gem_l3_remap(struct drm_device *dev); void i915_gem_init_swizzling(struct drm_device *dev); -void i915_gem_init_ppgtt(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 63c05ddea612..8a73a68a79ff 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4029,7 +4029,8 @@ i915_gem_init_hw(struct drm_device *dev) * contexts before PPGTT. */ i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); + if (dev_priv->mm.aliasing_ppgtt) + dev_priv->mm.aliasing_ppgtt->enable(dev); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b13ba9d53b19..c56de21af910 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -75,6 +75,61 @@ static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, return pte; } +static void gen6_ppgtt_enable(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t pd_offset; + struct intel_ring_buffer *ring; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + gen6_gtt_pte_t __iomem *pd_addr; + uint32_t pd_entry; + int i; + + pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm + + ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + + pt_addr = ppgtt->pt_dma_addr[i]; + pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); + pd_entry |= GEN6_PDE_VALID; + + writel(pd_entry, pd_addr + i); + } + readl(pd_addr); + + pd_offset = ppgtt->pd_offset; + pd_offset /= 64; /* in cachelines, */ + pd_offset <<= 16; + + if (INTEL_INFO(dev)->gen == 6) { + uint32_t ecochk, gab_ctl, ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + + gab_ctl = I915_READ(GAB_CTL); + I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + + ecochk = I915_READ(GAM_ECOCHK); + I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | + ECOCHK_PPGTT_CACHE64B); + I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + } else if (INTEL_INFO(dev)->gen >= 7) { + I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); + /* GFX_MODE is per-ring on gen7+ */ + } + + for_each_ring(ring, dev_priv, i) { + if (INTEL_INFO(dev)->gen >= 7) + I915_WRITE(RING_MODE_GEN7(ring), + _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); + + I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); + I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); + } +} + /* PPGTT support for Sandybdrige/Gen6 and later */ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, @@ -168,6 +223,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) gtt_total_entries(dev_priv->gtt) - I915_PPGTT_PD_ENTRIES; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->enable = gen6_ppgtt_enable; ppgtt->clear_range = gen6_ppgtt_clear_range; ppgtt->insert_entries = gen6_ppgtt_insert_entries; ppgtt->cleanup = gen6_ppgtt_cleanup; @@ -279,64 +335,6 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, obj->base.size >> PAGE_SHIFT); } -void i915_gem_init_ppgtt(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t pd_offset; - struct intel_ring_buffer *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - gen6_gtt_pte_t __iomem *pd_addr; - uint32_t pd_entry; - int i; - - if (!dev_priv->mm.aliasing_ppgtt) - return; - - pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + - ppgtt->pd_offset / sizeof(gen6_gtt_pte_t); - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; - - pt_addr = ppgtt->pt_dma_addr[i]; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); - pd_entry |= GEN6_PDE_VALID; - - writel(pd_entry, pd_addr + i); - } - readl(pd_addr); - - pd_offset = ppgtt->pd_offset; - pd_offset /= 64; /* in cachelines, */ - pd_offset <<= 16; - - if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk, gab_ctl, ecobits; - - ecobits = I915_READ(GAC_ECO_BITS); - I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); - - gab_ctl = I915_READ(GAB_CTL); - I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); - - ecochk = I915_READ(GAM_ECOCHK); - I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | - ECOCHK_PPGTT_CACHE64B); - I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - } else if (INTEL_INFO(dev)->gen >= 7) { - I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); - /* GFX_MODE is per-ring on gen7+ */ - } - - for_each_ring(ring, dev_priv, i) { - if (INTEL_INFO(dev)->gen >= 7) - I915_WRITE(RING_MODE_GEN7(ring), - _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); - - I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); - I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); - } -} - extern int intel_iommu_gfx_mapped; /* Certain Gen5 chipsets require require idling the GPU before * unmapping anything from the GTT when VT-d is enabled. -- cgit v1.2.2 From 5963cf049a044f41be7dc90c83756fb245f038b4 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:55 -0700 Subject: drm/i915: NULL aliasing_ppgtt on cleanup This will allow us to carry on if we've cleaned up the PPGTT. The usage for this is coming up - it simplifies handling a failed PPGTT init. Signed-off-by: Ben Widawsky [danvet: Spill the secrets about failing ppgtt init.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c56de21af910..d32912e07bad 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -316,6 +316,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) return; ppgtt->cleanup(ppgtt); + dev_priv->mm.aliasing_ppgtt = NULL; } void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, -- cgit v1.2.2 From b7c36d25461ae41e6562a2f70cb3423bcf8af2d2 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 8 Apr 2013 18:43:56 -0700 Subject: drm/i915: Allow PPGTT enable to fail I'm really not happy that we have to support this, but this will be the simplest way to handle cases where PPGTT init can fail, which I promise will be coming in the future. v2: Resolve conflicts due to patch series reordering. Signed-off-by: Ben Widawsky (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 7 +++++-- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 9 +++++++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 ++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 70d10de73bbd..bddb9a50ea76 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -927,8 +927,11 @@ int i915_reset(struct drm_device *dev) ring->init(ring); i915_gem_context_init(dev); - if (dev_priv->mm.aliasing_ppgtt) - dev_priv->mm.aliasing_ppgtt->enable(dev); + if (dev_priv->mm.aliasing_ppgtt) { + ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + if (ret) + i915_gem_cleanup_aliasing_ppgtt(dev); + } /* * It would make sense to re-init all the other hw state, at diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1213213e495..f59a388a9e8c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -449,7 +449,7 @@ struct i915_hw_ppgtt { struct sg_table *st, unsigned int pg_start, enum i915_cache_level cache_level); - void (*enable)(struct drm_device *dev); + int (*enable)(struct drm_device *dev); void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8a73a68a79ff..da6d6de0a8b9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4029,8 +4029,13 @@ i915_gem_init_hw(struct drm_device *dev) * contexts before PPGTT. */ i915_gem_context_init(dev); - if (dev_priv->mm.aliasing_ppgtt) - dev_priv->mm.aliasing_ppgtt->enable(dev); + if (dev_priv->mm.aliasing_ppgtt) { + ret = dev_priv->mm.aliasing_ppgtt->enable(dev); + if (ret) { + i915_gem_cleanup_aliasing_ppgtt(dev); + DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n"); + } + } return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d32912e07bad..11143b4982fc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -75,7 +75,7 @@ static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev, return pte; } -static void gen6_ppgtt_enable(struct drm_device *dev) +static int gen6_ppgtt_enable(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t pd_offset; @@ -128,6 +128,7 @@ static void gen6_ppgtt_enable(struct drm_device *dev) I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset); } + return 0; } /* PPGTT support for Sandybdrige/Gen6 and later */ -- cgit v1.2.2 From 2c55c336a71cb32ae837dc829d216dc86ed9d84f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 9 Apr 2013 08:11:00 +0300 Subject: drm/i915: use lower aux clock divider on non-ULT HSW Workaround to avoid intermittent aux channel failures, per spec change. v2: Don't mess with cpu dp aux divider (Paulo Zanoni) Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni [danvet: Kill spurious tab spotted by Paulo.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 482b5e570d84..173add1d819e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -353,10 +353,14 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ else aux_clock_divider = 225; /* eDP input clock at 450Mhz */ - } else if (HAS_PCH_SPLIT(dev)) + } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { + /* Workaround for non-ULT HSW */ + aux_clock_divider = 74; + } else if (HAS_PCH_SPLIT(dev)) { aux_clock_divider = DIV_ROUND_UP(intel_pch_rawclk(dev), 2); - else + } else { aux_clock_divider = intel_hrawclk(dev) / 2; + } if (IS_GEN6(dev)) precharge = 3; -- cgit v1.2.2 From 31c77388662de2efe1dd74a3b7e106e633e8a833 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 14:29:22 -0700 Subject: drm/i915: Better overclock support Most importantly this will allow users to set overclock frequencies in sysfs. Previously the max was limited by the RP0 max as opposed to the overclock max. This is useful if one wants to either limit the max overclock frequency, or set the minimum frequency to be in the overclock range. It also fixes an issue where if one sets the max frequency to be below the overclock max, they wouldn't be able to set back the proper overclock max. In addition I've added a couple of other bits: Show the overclock freq. as max in sysfs Print the overclock max in debugfs. Print a warning if the user sets the min frequency to be in the overclock range. In this patch I've decided to store the hw_max when we read it from the pcode at init. The reason I do this is the pcode reads can fail, and are slow. v2: Report when user requested overclocked max (Daniel) Remove when user sets min to overclock range (Daniel) Reported-by: freezer from #intel-gfx on irc Signed-off-by: Ben Widawsky Reviewed-by: Mika Kuoppala [danvet: Fixup the s/100MHz/50MHz/ confusion in an unrelated comment that Mika spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_sysfs.c | 13 +++++++++---- drivers/gpu/drm/i915/intel_pm.c | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index be88532b35cf..7da45aa2dbee 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1006,6 +1006,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) max_freq = rp_state_cap & 0xff; seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", max_freq * GT_FREQUENCY_MULTIPLIER); + + seq_printf(m, "Max overclocked frequency: %dMHz\n", + dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER); } else { seq_printf(m, "no P-state info available\n"); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f59a388a9e8c..a4a8e608649f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -668,6 +668,7 @@ struct intel_gen6_power_mgmt { u8 cur_delay; u8 min_delay; u8 max_delay; + u8 hw_max; struct delayed_work delayed_resume_work; diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index a3a3e22f1a84..fa4b4e881401 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -226,7 +226,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute int ret; mutex_lock(&dev_priv->rps.hw_lock); - ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; + ret = dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); @@ -239,7 +239,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev); struct drm_device *dev = minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 val, rp_state_cap, hw_max, hw_min; + u32 val, rp_state_cap, hw_max, hw_min, non_oc_max; ssize_t ret; ret = kstrtou32(buf, 0, &val); @@ -251,7 +251,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = (rp_state_cap & 0xff); + hw_max = dev_priv->rps.hw_max; + non_oc_max = (rp_state_cap & 0xff); hw_min = ((rp_state_cap & 0xff0000) >> 16); if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) { @@ -259,6 +260,10 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev, return -EINVAL; } + if (val > non_oc_max) + DRM_DEBUG("User requested overclocking to %d\n", + val * GT_FREQUENCY_MULTIPLIER); + if (dev_priv->rps.cur_delay > val) gen6_set_rps(dev_priv->dev, val); @@ -302,7 +307,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, mutex_lock(&dev_priv->rps.hw_lock); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - hw_max = (rp_state_cap & 0xff); + hw_max = dev_priv->rps.hw_max; hw_min = ((rp_state_cap & 0xff0000) >> 16); if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 17f157a7b640..059c77367701 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2558,8 +2558,8 @@ static void gen6_enable_rps(struct drm_device *dev) rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - /* In units of 100MHz */ - dev_priv->rps.max_delay = rp_state_cap & 0xff; + /* In units of 50MHz */ + dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff; dev_priv->rps.min_delay = (rp_state_cap & 0xff0000) >> 16; dev_priv->rps.cur_delay = 0; @@ -2646,6 +2646,7 @@ static void gen6_enable_rps(struct drm_device *dev) DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max from %dMHz to %dMHz\n", (dev_priv->rps.max_delay & 0xff) * 50, (pcu_mbox & 0xff) * 50); + dev_priv->rps.hw_max = pcu_mbox & 0xff; dev_priv->rps.max_delay = pcu_mbox & 0xff; } } else { -- cgit v1.2.2 From 10e084979411a2f066eac5500615ca617aeaf3c9 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 5 Apr 2013 14:29:23 -0700 Subject: drm/i915: Don't default to overclock max Requested-by: Daniel Vetter Signed-off-by: Ben Widawsky Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 059c77367701..baea4fce5a34 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2643,11 +2643,10 @@ static void gen6_enable_rps(struct drm_device *dev) pcu_mbox = 0; ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox); if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */ - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max from %dMHz to %dMHz\n", + DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n", (dev_priv->rps.max_delay & 0xff) * 50, (pcu_mbox & 0xff) * 50); dev_priv->rps.hw_max = pcu_mbox & 0xff; - dev_priv->rps.max_delay = pcu_mbox & 0xff; } } else { DRM_DEBUG_DRIVER("Failed to set the min frequency\n"); -- cgit v1.2.2 From 3b9d7888df1d1ee9928e2ab41b2ca2fca70a4a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Apr 2013 15:13:40 +0300 Subject: drm/i915: Add ECOBITS_SNB_BIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GAC_ECO_BITS has a bit similar to GAM_ECOCHK's ECOCHK_SNB_BIT. Add the define, and enable it on SNB. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 ++- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 11143b4982fc..a336c4d609a2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -106,7 +106,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev) uint32_t ecochk, gab_ctl, ecobits; ecobits = I915_READ(GAC_ECO_BITS); - I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT | + ECOBITS_PPGTT_CACHE64B); gab_ctl = I915_READ(GAB_CTL); I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0e4b7fb7d691..96b361f9a32d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -127,6 +127,7 @@ #define ECOCHK_PPGTT_CACHE4B (0x0<<3) #define GAC_ECO_BITS 0x14090 +#define ECOBITS_SNB_BIT (1<<13) #define ECOBITS_PPGTT_CACHE64B (3<<8) #define ECOBITS_PPGTT_CACHE4B (0<<8) -- cgit v1.2.2 From a65c2fcd00518b7339d72e08e6b2b4261fbcc22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Apr 2013 15:13:41 +0300 Subject: drm/i915: Set GAC_ECO_BITS register on Gen7+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to BSpec GAC_ECO_BITS register exists on Gen7 platforms as well. Configure it accordingly. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a336c4d609a2..fae638072d7d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -117,6 +117,11 @@ static int gen6_ppgtt_enable(struct drm_device *dev) ECOCHK_PPGTT_CACHE64B); I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); } else if (INTEL_INFO(dev)->gen >= 7) { + uint32_t ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); + I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); /* GFX_MODE is per-ring on gen7+ */ } -- cgit v1.2.2 From a6f429a5a2f6ae0e1e8df2493884f9a881486d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 4 Apr 2013 15:13:42 +0300 Subject: drm/i915: Configure GAM_ECOCHK appropriatly for Gen7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IVB and HSW use different encodings for the PPGTT cacheability bits in the GAM_ECOCHK register. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 11 +++++++++-- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index fae638072d7d..b77e98c0812c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -117,12 +117,19 @@ static int gen6_ppgtt_enable(struct drm_device *dev) ECOCHK_PPGTT_CACHE64B); I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE)); } else if (INTEL_INFO(dev)->gen >= 7) { - uint32_t ecobits; + uint32_t ecochk, ecobits; ecobits = I915_READ(GAC_ECO_BITS); I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); - I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B); + ecochk = I915_READ(GAM_ECOCHK); + if (IS_HASWELL(dev)) { + ecochk |= ECOCHK_PPGTT_WB_HSW; + } else { + ecochk |= ECOCHK_PPGTT_LLC_IVB; + ecochk &= ~ECOCHK_PPGTT_GFDT_IVB; + } + I915_WRITE(GAM_ECOCHK, ecochk); /* GFX_MODE is per-ring on gen7+ */ } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 96b361f9a32d..3b9ec9bcd383 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -125,6 +125,11 @@ #define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define ECOCHK_PPGTT_GFDT_IVB (0x1<<4) +#define ECOCHK_PPGTT_LLC_IVB (0x1<<3) +#define ECOCHK_PPGTT_UC_HSW (0x1<<3) +#define ECOCHK_PPGTT_WT_HSW (0x2<<3) +#define ECOCHK_PPGTT_WB_HSW (0x3<<3) #define GAC_ECO_BITS 0x14090 #define ECOBITS_SNB_BIT (1<<13) -- cgit v1.2.2 From fe48d8de34eeaefb2c71dab68ea7c236f06e5877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Apr 2013 20:09:13 +0300 Subject: drm/i915: Reject fence stride=0 on gen4+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our checks for an invalid fence stride forgot to guard against zero stride on gen4+. Fix it. v2: Avoid duplicated code (danvet) Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_tiling.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index c807eb93755b..b56185f4babb 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -235,6 +235,9 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) } } + if (stride < tile_width) + return false; + /* 965+ just needs multiples of tile width */ if (INTEL_INFO(dev)->gen >= 4) { if (stride & (tile_width - 1)) @@ -243,9 +246,6 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) } /* Pre-965 needs power of two tile widths */ - if (stride < tile_width) - return false; - if (stride & (stride - 1)) return false; -- cgit v1.2.2 From 3a062478308187d4b4d0ef546a16e66852d03489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Apr 2013 11:45:05 +0300 Subject: drm/i915: Increase max fence pitch limit to 256KB on IVB+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BSpec contains several scattered notes which state that the maximum fence stride was increased to 256KB on IVB. Testing on real hardware agrees. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_tiling.c | 9 ++++++--- drivers/gpu/drm/i915/i915_reg.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index b56185f4babb..537545be69db 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -217,9 +217,12 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) tile_width = 512; /* check maximum stride & object size */ - if (INTEL_INFO(dev)->gen >= 4) { - /* i965 stores the end address of the gtt mapping in the fence - * reg, so dont bother to check the size */ + /* i965+ stores the end address of the gtt mapping in the fence + * reg, so dont bother to check the size */ + if (INTEL_INFO(dev)->gen >= 7) { + if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL) + return false; + } else if (INTEL_INFO(dev)->gen >= 4) { if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) return false; } else { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3b9ec9bcd383..e0fc0706e034 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -430,6 +430,7 @@ #define FENCE_REG_SANDYBRIDGE_0 0x100000 #define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 +#define GEN7_FENCE_MAX_PITCH_VAL 0x0800 /* control register for cpu gtt access */ #define TILECTL 0x101000 -- cgit v1.2.2 From 6a994761806388ad99f581d2063e3308d8d77f01 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 9 Apr 2013 17:25:50 -0700 Subject: drm/i915: Remove stale code Looks like a some remnant from a rebase. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b77e98c0812c..50df194914a6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -815,7 +815,6 @@ int i915_gem_gtt_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct i915_gtt *gtt = &dev_priv->gtt; - unsigned long gtt_size; int ret; if (INTEL_INFO(dev)->gen <= 5) { @@ -833,8 +832,6 @@ int i915_gem_gtt_init(struct drm_device *dev) if (ret) return ret; - gtt_size = (dev_priv->gtt.total >> PAGE_SHIFT) * sizeof(gen6_gtt_pte_t); - /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %zdM\n", dev_priv->gtt.total >> 20); -- cgit v1.2.2 From 182642b09311c94898acbc01cc9bac8e02f63da6 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 11 Apr 2013 15:07:59 +0300 Subject: drm/i915: Return stored value from max freq sysfs entry commit 4f9b2fe0441d4bdf5666a306156b5d6755de2584 Author: Ben Widawsky Date: Fri Apr 5 14:29:22 2013 -0700 drm/i915: Better overclock support changed the sysfs read semantics for 'gt_max_freq_mhz'. By always returning overclock max instead of stored value. Fix this by returning the stored value. Separate sysfs entry should be considered for overclocking max freq. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=63415 Cc: Ben Widawsky Signed-off-by: Mika Kuoppala Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index fa4b4e881401..d5e1890678f9 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -226,7 +226,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute int ret; mutex_lock(&dev_priv->rps.hw_lock); - ret = dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER; + ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER; mutex_unlock(&dev_priv->rps.hw_lock); return snprintf(buf, PAGE_SIZE, "%d\n", ret); -- cgit v1.2.2 From 42b5aeabe9286cdaabfc9b0ce5fa869bbe04dcd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 9 Apr 2013 13:02:47 +0300 Subject: drm/i915: IVB/HSW have 32 fence register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the number of fence registers to 32 on IVB/HSW. VLV however only has 16 fence registers according to the docs. Increasing the number of fences was attempted before [1], but there was some uncertainty about the maximum CPU fence number for FBC. Since then BSpec has been updated to state that there are in fact 32 fence registers, and the CPU fence number field in the SNB_DPFC_CTL_SA register is 5 bits, and the CPU fence number field in the ILK_DPFC_CONTROL register must be zero. So now it all makes sense. [1] http://lists.freedesktop.org/archives/intel-gfx/2011-October/012865.html v2: Include some background information based on the previous attempt Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 +++--- drivers/gpu/drm/i915/i915_gem.c | 4 +++- drivers/gpu/drm/i915/i915_irq.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a4a8e608649f..b5a495a97ea7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -195,9 +195,9 @@ struct drm_i915_master_private { struct _drm_i915_sarea *sarea_priv; }; #define I915_FENCE_REG_NONE -1 -#define I915_MAX_NUM_FENCES 16 -/* 16 fences + sign bit for FENCE_REG_NONE */ -#define I915_MAX_NUM_FENCE_BITS 5 +#define I915_MAX_NUM_FENCES 32 +/* 32 fences + sign bit for FENCE_REG_NONE */ +#define I915_MAX_NUM_FENCE_BITS 6 struct drm_i915_fence_reg { struct list_head lru_list; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index da6d6de0a8b9..6be940effefd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4190,7 +4190,9 @@ i915_gem_load(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) dev_priv->fence_reg_start = 3; - if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) + if (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev)) + dev_priv->num_fence_regs = 32; + else if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) dev_priv->num_fence_regs = 16; else dev_priv->num_fence_regs = 8; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b4e237d9927d..e97bbb2abd59 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1213,7 +1213,7 @@ static void i915_gem_record_fences(struct drm_device *dev, switch (INTEL_INFO(dev)->gen) { case 7: case 6: - for (i = 0; i < 16; i++) + for (i = 0; i < dev_priv->num_fence_regs; i++) error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); break; case 5: -- cgit v1.2.2 From f30da187cdcd0939288038e11fb3bfbd1b655564 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 20:22:50 +0200 Subject: drm/i915: don't check inconsistent modeset state when force-restoring It will be only consistent once we've restored all the crtcs. Since a bunch of other callers also want to just restore a single crtc, add a boolean to disable checking only where it doesn't make sense. Note that intel_modeset_setup_hw_state already has a call to intel_modeset_check_state at the end, so we don't reduce the amount of checking. v2: Try harder not to create a big patch (Chris). v3: Even smaller (still Chris). Also fix a trailing space. References: https://lkml.org/lkml/2013/3/16/60 Cc: Tomas Melin Cc: Richard Cochran Cc: Chris Wilson Cc: stable@vger.kernel.org Reviewed-by: Chris Wilson Tested-by: Tomas Melin Tested-by: Richard Cochran Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 880981360e09..457a0a03c063 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7916,9 +7916,9 @@ intel_modeset_check_state(struct drm_device *dev) } } -int intel_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb) +static int __intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -8012,8 +8012,6 @@ done: if (ret && crtc->enabled) { crtc->hwmode = *saved_hwmode; crtc->mode = *saved_mode; - } else { - intel_modeset_check_state(dev); } out: @@ -8022,6 +8020,20 @@ out: return ret; } +int intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) +{ + int ret; + + ret = __intel_set_mode(crtc, mode, x, y, fb); + + if (ret == 0) + intel_modeset_check_state(crtc->dev); + + return ret; +} + void intel_crtc_restore_mode(struct drm_crtc *crtc) { intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); @@ -9333,10 +9345,16 @@ setup_pipes: } if (force_restore) { + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ for_each_pipe(pipe) { struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - intel_crtc_restore_mode(crtc); + + __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, + crtc->fb); } list_for_each_entry(plane, &dev->mode_config.plane_list, head) intel_plane_restore(plane); -- cgit v1.2.2 From 15d199ea1f3e2b960b0efccca2cdd0ba40a31f3c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 22 Mar 2013 14:14:13 -0300 Subject: drm/i915: add intel_using_power_well It returns true if we've requested to turn the power well on and it's really on. It also returns true for all the previous gens. For now there's just one caller, but I'm going to add more. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 457a0a03c063..236d268d809c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1227,8 +1227,8 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && - !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { + if (!intel_using_power_well(dev_priv->dev) && + cpu_transcoder != TRANSCODER_EDP) { cur_state = false; } else { reg = PIPECONF(cpu_transcoder); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d7bd031dd642..a124e05fb581 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -693,6 +693,7 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); +extern bool intel_using_power_well(struct drm_device *dev); extern void intel_init_power_well(struct drm_device *dev); extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index baea4fce5a34..4dc06a1bd43d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4085,6 +4085,22 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } +/** + * We should only use the power well if we explicitly asked the hardware to + * enable it, so check if it's enabled and also check if we've requested it to + * be enabled. + */ +bool intel_using_power_well(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_HASWELL(dev)) + return I915_READ(HSW_PWR_WELL_DRIVER) == + (HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE); + else + return true; +} + void intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.2.2 From f7708f78bd51a46abf00ae22ebb1b7deb594fc62 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 22 Mar 2013 14:16:38 -0300 Subject: drm/i915: don't touch the PF regs if the power well is down This solves some "unclaimed register" messages when booting the machine with eDP attached. V2: Rebase and add the comment requested by Daniel. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 236d268d809c..51871c248d6d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3599,9 +3599,13 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); - /* Disable PF */ - I915_WRITE(PF_CTL(pipe), 0); - I915_WRITE(PF_WIN_SZ(pipe), 0); + /* XXX: Once we have proper panel fitter state tracking implemented with + * hardware state read/check support we should switch to only disable + * the panel fitter when we know it's used. */ + if (intel_using_power_well(dev)) { + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); + } intel_ddi_disable_pipe_clock(intel_crtc); -- cgit v1.2.2 From dc652f90e088798bfa31f496ba994ddadd5d5680 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 12 Apr 2013 15:18:38 +0300 Subject: drm/i915: ensure single initialization and cleanup of backlight device Backlight cleanup in the eDP connector destroy callback caused the backlight device to be removed on some systems that first initialized LVDS and then attempted to initialize eDP. Prevent multiple backlight initializations, and ensure backlight cleanup is only done once by moving it to modeset cleanup. A small wrinkle is the introduced asymmetry in backlight setup/cleanup. This could be solved by adding refcounting, but it seems overkill considering that there should only ever be one backlight device. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=55701 Signed-off-by: Jani Nikula Tested-by: Peter Verthez Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 +++ drivers/gpu/drm/i915/intel_dp.c | 5 +---- drivers/gpu/drm/i915/intel_lvds.c | 1 - drivers/gpu/drm/i915/intel_panel.c | 7 ++++++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 51871c248d6d..7672f3e49df1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9423,6 +9423,9 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); + /* destroy backlight, if any, before the connectors */ + intel_panel_destroy_backlight(dev); + drm_mode_config_cleanup(dev); intel_cleanup_overlay(dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 173add1d819e..8845e82ec9ed 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2474,17 +2474,14 @@ done: static void intel_dp_destroy(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; struct intel_dp *intel_dp = intel_attached_dp(connector); struct intel_connector *intel_connector = to_intel_connector(connector); if (!IS_ERR_OR_NULL(intel_connector->edid)) kfree(intel_connector->edid); - if (is_edp(intel_dp)) { - intel_panel_destroy_backlight(dev); + if (is_edp(intel_dp)) intel_panel_fini(&intel_connector->panel); - } drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ca2d903c19bb..f36f1baabd5a 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -631,7 +631,6 @@ static void intel_lvds_destroy(struct drm_connector *connector) if (!IS_ERR_OR_NULL(lvds_connector->base.edid)) kfree(lvds_connector->base.edid); - intel_panel_destroy_backlight(connector->dev); intel_panel_fini(&lvds_connector->base.panel); drm_sysfs_connector_remove(connector); diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7874cecc2863..eb5e6e95f3c7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -428,6 +428,9 @@ int intel_panel_setup_backlight(struct drm_connector *connector) intel_panel_init_backlight(dev); + if (WARN_ON(dev_priv->backlight.device)) + return -ENODEV; + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.brightness = dev_priv->backlight.level; @@ -453,8 +456,10 @@ int intel_panel_setup_backlight(struct drm_connector *connector) void intel_panel_destroy_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight.device) + if (dev_priv->backlight.device) { backlight_device_unregister(dev_priv->backlight.device); + dev_priv->backlight.device = NULL; + } } #else int intel_panel_setup_backlight(struct drm_connector *connector) -- cgit v1.2.2 From b6c5164d7bf624f3e1b750787ddb983150c5117c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 12 Apr 2013 18:48:43 +0200 Subject: drm/i915: Fixup Oops in the pipe config computation Yet again our current confusion between doing the modeset globally, but only having the new parameters for one crtc at a time. So that intel_set_mode essentially already does a global modeset: intel_modeset_affected_pipes compares the current state with where we want to go to (which is carefully set up by intel_crtc_set_config) and then goes through the modeset sequence for any crtc which needs updating. Now the issue is that the actual interface with the remaining code still only works on one crtc, and so we only pass in one fb and one mode. In intel_set_mode we also only compute one intel_crtc_config (which should be the one for the crtc we're doing a modeset on). The reason for that mismatch is twofold: - We want to eventually do all modeset as global state changes, so it's just infrastructure prep. - But even the old semantics can change more than one crtc when you e.g. move a connector from crtc A to crtc B, then both crtc A and B need to be updated. Usually that means one pipe is disabled and the other enabled. This is also the reason why the hack doesn't touch the disable_pipes mask. Now hilarity ensued in our kms config restore paths when we actually try to do a modeset on all crtcs: If the first crtc should be off and the second should be on, then the call on the first crtc will notice that the 2nd one should be switched on and so tries to compute the pipe_config. But due to a lack of passed-in fb (crtc 1 should be off after all) it only results in tears. This case is ridiculously easy to hit on gen2/3 where the lvds output is restricted to pipe B. Note that before the pipe_config bpp rework gen2/3 didn't care really about the fb->depth, so this is a regression brought to light with commit 4e53c2e010e531b4a014692199e978482d471c7e Author: Daniel Vetter Date: Wed Mar 27 00:44:58 2013 +0100 drm/i915: precompute pipe bpp before touching the hw But apparently Ajax also managed to blow up pch platforms, probably with some randomized configs, and pch platforms trip up over the lack of an fb even in the old code. So this actually goes back to the first introduction of the new modeset restore code in commit 45e2b5f640b3766da3eda48f6c35f088155c06f3 Author: Daniel Vetter Date: Fri Nov 23 18:16:34 2012 +0100 drm/i915: force restore on lid open Fix this mess by now by justing shunting all the cool new global modeset logic in intel_modeset_affected_pipes. v2: Improve commit message and clean up all the comments in intel_modeset_affected_pipes - since the introduction of the modeset restore code they've been a bit outdated. Bugzill: https://bugzilla.redhat.com/show_bug.cgi?id=917725 Cc: stable@vger.kernel.org References: http://www.mail-archive.com/stable@vger.kernel.org/msg38084.html Tested-by: Richard Cochran Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7672f3e49df1..fd7fb6a6a9a0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7712,22 +7712,25 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, if (crtc->enabled) *prepare_pipes |= 1 << intel_crtc->pipe; - /* We only support modeset on one single crtc, hence we need to do that - * only for the passed in crtc iff we change anything else than just - * disable crtcs. - * - * This is actually not true, to be fully compatible with the old crtc - * helper we automatically disable _any_ output (i.e. doesn't need to be - * connected to the crtc we're modesetting on) if it's disconnected. - * Which is a rather nutty api (since changed the output configuration - * without userspace's explicit request can lead to confusion), but - * alas. Hence we currently need to modeset on all pipes we prepare. */ + /* + * For simplicity do a full modeset on any pipe where the output routing + * changed. We could be more clever, but that would require us to be + * more careful with calling the relevant encoder->mode_set functions. + */ if (*prepare_pipes) *modeset_pipes = *prepare_pipes; /* ... and mask these out. */ *modeset_pipes &= ~(*disable_pipes); *prepare_pipes &= ~(*disable_pipes); + + /* + * HACK: We don't (yet) fully support global modesets. intel_set_config + * obies this rule, but the modeset restore mode of + * intel_modeset_setup_hw_state does not. + */ + *modeset_pipes &= 1 << intel_crtc->pipe; + *prepare_pipes &= 1 << intel_crtc->pipe; } static bool intel_crtc_in_use(struct drm_crtc *crtc) -- cgit v1.2.2 From 87476d632c5041cfb962630e618d787243c81ed8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 11 Apr 2013 16:29:06 +0200 Subject: drm/i915: Fixup pfit disabling for gen2/3 The recent rework of the pfit handling didn't take into account that the panel fitter is fixed to pipe B: commit 24a1f16de97c4cf0029d9acd04be06db32208726 Author: Mika Kuoppala Date: Fri Feb 8 16:35:37 2013 +0200 drm/i915: disable shared panel fitter for pipe Fix this up by properly computing the pipe the pfit is on. Also extract the logic into its own function, add a debug assert to check that the pipe is off (mostly just documentation) and add some debug output. If pipe A was disabled after pipe B was set up, the panel fitter will be disabled. Now most userspace doesn't do modesets in this order, which is why I couldn't ever reproduce this and why it took me so long to figure out. We really need hw state readout and check support for the pannel fitter ... Reported-by: Hans de Bruin Cc: Mika Kuoppala Cc: Hans de Bruin References: http://permalink.gmane.org/gmane.comp.freedesktop.xorg.drivers.intel/19049 Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd7fb6a6a9a0..1bbf7071e0c4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3724,6 +3724,26 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) encoder->enable(encoder); } +static void i9xx_pfit_disable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + uint32_t pctl = I915_READ(PFIT_CONTROL); + + assert_pipe_disabled(dev_priv, crtc->pipe); + + if (INTEL_INFO(dev)->gen >= 4) + pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT; + else + pipe = PIPE_B; + + if (pipe == crtc->pipe) { + DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl); + I915_WRITE(PFIT_CONTROL, 0); + } +} + static void i9xx_crtc_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3732,8 +3752,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 pctl; - if (!intel_crtc->active) return; @@ -3753,11 +3771,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) intel_disable_plane(dev_priv, plane, pipe); intel_disable_pipe(dev_priv, pipe); - /* Disable pannel fitter if it is on this pipe. */ - pctl = I915_READ(PFIT_CONTROL); - if ((pctl & PFIT_ENABLE) && - ((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe) - I915_WRITE(PFIT_CONTROL, 0); + i9xx_pfit_disable(intel_crtc); intel_disable_pll(dev_priv, pipe); -- cgit v1.2.2 From 3a3b4f984b230d815d9f956f296a6145f1dfebb7 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 12 Apr 2013 12:10:05 +0300 Subject: drm/i915: shorten debugfs output simple attributes commit 647416f9eefe7699754b01b9fc82758fde83248c Author: Kees Cook Date: Sun Mar 10 14:10:06 2013 -0700 drm/i915: use simple attribute in debugfs routines made i915_next_seqno debugfs entry to crop it's output if returned value was large enough. Using simple_attr will limit the output to 24 bytes. Fix is to strip out preamples on all simple attributes that have one. v2: Fix all simple attributes (Daniel Vetter) Cc: Kees Cook Signed-off-by: Mika Kuoppala Acked-by: Kees Cook Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7da45aa2dbee..23187fc99ca6 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -901,7 +901,7 @@ i915_next_seqno_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(i915_next_seqno_fops, i915_next_seqno_get, i915_next_seqno_set, - "next_seqno : 0x%llx\n"); + "0x%llx\n"); static int i915_rstdby_delays(struct seq_file *m, void *unused) { @@ -1690,7 +1690,7 @@ i915_wedged_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(i915_wedged_fops, i915_wedged_get, i915_wedged_set, - "wedged : %llu\n"); + "%llu\n"); static int i915_ring_stop_get(void *data, u64 *val) @@ -1844,7 +1844,7 @@ i915_max_freq_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(i915_max_freq_fops, i915_max_freq_get, i915_max_freq_set, - "max freq: %llu\n"); + "%llu\n"); static int i915_min_freq_get(void *data, u64 *val) @@ -1895,7 +1895,7 @@ i915_min_freq_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops, i915_min_freq_get, i915_min_freq_set, - "min freq: %llu\n"); + "%llu\n"); static int i915_cache_sharing_get(void *data, u64 *val) -- cgit v1.2.2 From 3ebecd07d382c022e93c560c56114eec1d6d2cdd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 12 Apr 2013 19:10:13 +0100 Subject: drm/i915: Scale ring, rather than ia, frequency on Haswell Haswell introduces a separate frequency domain for the ring (uncore). So where we used to increase the CPU (IA) clock with GPU busyness, we now need to scale the ring frequency directly instead. As the ring limits our memory bandwidth, it is vital for performance that when the GPU is busy, we increase the frequency of the ring to increase the available memory bandwidth. v2: Fix the algorithm to actually use the scaled gpu frequency for the ring. v3: s/max_ring_freq/min_ring_freq/ as that is what it is Signed-off-by: Chris Wilson Cc: Jesse Barnes Reviewed-by: Jesse Barnes [danvet: Add space checkpatch complained about.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 7 ++++-- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_pm.c | 43 +++++++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 23187fc99ca6..e913d325d5b8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1357,7 +1357,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) return ret; - seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n"); + seq_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); for (gpu_freq = dev_priv->rps.min_delay; gpu_freq <= dev_priv->rps.max_delay; @@ -1366,7 +1366,10 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_MIN_FREQ_TABLE, &ia_freq); - seq_printf(m, "%d\t\t%d\n", gpu_freq * GT_FREQUENCY_MULTIPLIER, ia_freq * 100); + seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", + gpu_freq * GT_FREQUENCY_MULTIPLIER, + ((ia_freq >> 0) & 0xff) * 100, + ((ia_freq >> 8) & 0xff) * 100); } mutex_unlock(&dev_priv->rps.hw_lock); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e0fc0706e034..077d40f37b97 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1210,6 +1210,9 @@ #define MCHBAR_MIRROR_BASE_SNB 0x140000 +/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ +#define DCLK 0x5e04 + /** 915-945 and GM965 MCH register controlling DRAM channel access */ #define DCC 0x10200 #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) @@ -4390,6 +4393,7 @@ #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) #define GEN6_PCODE_DATA 0x138128 #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 +#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 #define VLV_IOSF_DOORBELL_REQ 0x182100 #define IOSF_DEVFN_SHIFT 24 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4dc06a1bd43d..5e1cdd54ba13 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2684,8 +2684,8 @@ static void gen6_update_ring_freq(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int min_freq = 15; - int gpu_freq; - unsigned int ia_freq, max_ia_freq; + unsigned int gpu_freq; + unsigned int max_ia_freq, min_ring_freq; int scaling_factor = 180; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -2701,6 +2701,10 @@ static void gen6_update_ring_freq(struct drm_device *dev) /* Convert from kHz to MHz */ max_ia_freq /= 1000; + min_ring_freq = I915_READ(MCHBAR_MIRROR_BASE_SNB + DCLK); + /* convert DDR frequency from units of 133.3MHz to bandwidth */ + min_ring_freq = (2 * 4 * min_ring_freq + 2) / 3; + /* * For each potential GPU frequency, load a ring frequency we'd like * to use for memory access. We do this by specifying the IA frequency @@ -2709,21 +2713,32 @@ static void gen6_update_ring_freq(struct drm_device *dev) for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay; gpu_freq--) { int diff = dev_priv->rps.max_delay - gpu_freq; - - /* - * For GPU frequencies less than 750MHz, just use the lowest - * ring freq. - */ - if (gpu_freq < min_freq) - ia_freq = 800; - else - ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); - ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); - ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT; + unsigned int ia_freq = 0, ring_freq = 0; + + if (IS_HASWELL(dev)) { + ring_freq = (gpu_freq * 5 + 3) / 4; + ring_freq = max(min_ring_freq, ring_freq); + /* leave ia_freq as the default, chosen by cpufreq */ + } else { + /* On older processors, there is no separate ring + * clock domain, so in order to boost the bandwidth + * of the ring, we need to upclock the CPU (ia_freq). + * + * For GPU frequencies less than 750MHz, + * just use the lowest ring freq. + */ + if (gpu_freq < min_freq) + ia_freq = 800; + else + ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); + ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); + } sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, - ia_freq | gpu_freq); + ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT | + ring_freq << GEN6_PCODE_FREQ_RING_RATIO_SHIFT | + gpu_freq); } } -- cgit v1.2.2 From 30ccd9644e021ae95e0f039d70b7d5ea8d9d8f3b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 15 Apr 2013 21:48:03 -0700 Subject: drm/i915: VLV doesn't have LLC Caused by me with v2 of commit 219f4fdbed5570f1d2e8da0af1c298dd3622060e Author: Ben Widawsky Date: Fri Mar 15 11:17:54 2013 -0700 drm/i915: Introduce GEN7_FEATURES for device info I don't have a VLV to test it with, Jesse, Ken, can one of you test? Cc: Jesse Barnes Cc: Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index bddb9a50ea76..c413aab6eb74 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -294,6 +294,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_llc = 0, /* legal, last one wins */ }; static const struct intel_device_info intel_valleyview_d_info = { @@ -301,6 +302,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .num_pipes = 2, .is_valleyview = 1, .display_mmio_offset = VLV_DISPLAY_BASE, + .has_llc = 0, /* legal, last one wins */ }; static const struct intel_device_info intel_haswell_d_info = { -- cgit v1.2.2 From 6af79ae2ae81efb2abd42d908041aa6ac0db9d43 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Apr 2013 18:16:52 -0300 Subject: drm/i915: remove comment about IVB link training from intel_pm.c We have the exact same comment inside intel_init_display. This is a leftover from when we moved a lot of code from intel_display.c to intel_pm.c. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5e1cdd54ba13..f747cb036d8c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4222,7 +4222,6 @@ void intel_init_pm(struct drm_device *dev) } dev_priv->display.init_clock_gating = gen6_init_clock_gating; } else if (IS_IVYBRIDGE(dev)) { - /* FIXME: detect B0+ stepping and use auto training */ if (SNB_READ_WM0_LATENCY()) { dev_priv->display.update_wm = ivybridge_update_wm; dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; -- cgit v1.2.2 From c40c0f5bd5b0f09e4386d2cf26c96c89c45ee539 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Apr 2013 18:16:53 -0300 Subject: drm/i915: don't intel_crt_init on any ULT machines We may have DDI_BUF_CTL(PORT_A) configured with 2 lanes and still not have CRT, so just check for !IS_ULT. This problem happened on a real machine and resulted in a very ugly dmesg. Cc: stable@vger.kernel.org Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1bbf7071e0c4..6a8262867b0b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8495,7 +8495,7 @@ static void intel_setup_outputs(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, 0); } - if (!(HAS_DDI(dev) && (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) + if (!IS_ULT(dev)) intel_crt_init(dev); if (HAS_DDI(dev)) { -- cgit v1.2.2 From 08e1413d95b50b19259fe2e425885030f93c7b85 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Apr 2013 18:16:54 -0300 Subject: drm/i915: WARN when LPT-LP is not paired with ULT CPU Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c413aab6eb74..9ebe895c17d6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -459,11 +459,13 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->num_pch_pll = 0; DRM_DEBUG_KMS("Found LynxPoint PCH\n"); WARN_ON(!IS_HASWELL(dev)); + WARN_ON(IS_ULT(dev)); } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_LPT; dev_priv->num_pch_pll = 0; DRM_DEBUG_KMS("Found LynxPoint LP PCH\n"); WARN_ON(!IS_HASWELL(dev)); + WARN_ON(!IS_ULT(dev)); } BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS); } -- cgit v1.2.2 From b543fb0464ddf30a5b554957fd212eb7a2acac65 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 16 Apr 2013 13:36:54 +0200 Subject: drm/i915: Add HPD IRQ storm detection (v5) Add a hotplug IRQ storm detection (triggered when a hotplug interrupt fires more than 5 times / sec). Rationale: Despite of the many attempts to fix the problem with noisy hotplug interrupt lines we are still seeing systems which have issues: Once cause of noise seems to be bad routing of the hotplug line on the board: cross talk from other signals seems to cause erronous hotplug interrupts. This has been documented as an erratum for the the i945GM chipset and thus hotplug support was disabled for this chipset model but others seem to have this problem, too. We have seen this issue on a G35 motherboard for example: Even different motherboards of the same model seem to behave differently: while some only see only around 10-100 interrupts/s others seem to see 5k or more. We've also observed a dependency on the selected video mode. Also on certain laptops interrupt noise seems to occur duing battery charging when the battery is at a certain charge levels. Thus we add a simple algorithm here that detects an 'interrupt storm' condition. v2: Fixed comment. v3: Reordered drm_i915_private: moved hpd state tracking to hotplug work stuff. v4: Followed by Jesse Barnes to use a time_..() macro. v5: Fixed coding style as suggested by Jani Nikula. Signed-off-by: Egbert Eich Acked-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 9 ++++++ drivers/gpu/drm/i915/i915_irq.c | 69 ++++++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b5a495a97ea7..7b613c2280f1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -932,6 +932,15 @@ typedef struct drm_i915_private { struct work_struct hotplug_work; bool enable_hotplug_processing; + struct { + unsigned long hpd_last_jiffies; + int hpd_cnt; + enum { + HPD_ENABLED = 0, + HPD_DISABLED = 1, + HPD_MARK_DISABLED = 2 + } hpd_mark; + } hpd_stats[HPD_NUM_PINS]; int num_pch_pll; int num_plane; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e97bbb2abd59..5ac1291c5853 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -582,6 +582,40 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, queue_work(dev_priv->wq, &dev_priv->rps.work); } +#define HPD_STORM_DETECT_PERIOD 1000 +#define HPD_STORM_THRESHOLD 5 + +static inline void hotplug_irq_storm_detect(struct drm_device *dev, + u32 hotplug_trigger, + const u32 *hpd) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long irqflags; + int i; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + + for (i = 1; i < HPD_NUM_PINS; i++) { + if (!(hpd[i] & hotplug_trigger) || + dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) + continue; + + if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, + dev_priv->hpd_stats[i].hpd_last_jiffies + + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { + dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; + dev_priv->hpd_stats[i].hpd_cnt = 0; + } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { + dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); + } else { + dev_priv->hpd_stats[i].hpd_cnt++; + } + } + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -650,13 +684,15 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) /* Consume port. Then clear IIR or we'll miss events */ if (iir & I915_DISPLAY_PORT_INTERRUPT) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & HOTPLUG_INT_STATUS_I915) + if (hotplug_trigger) { + hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } @@ -680,10 +716,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - if (pch_iir & SDE_HOTPLUG_MASK) + if (hotplug_trigger) { + hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } if (pch_iir & SDE_AUDIO_POWER_MASK) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -726,10 +764,12 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - if (pch_iir & SDE_HOTPLUG_MASK_CPT) + if (hotplug_trigger) { + hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) DRM_DEBUG_DRIVER("PCH audio power change on port %d\n", (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> @@ -2621,13 +2661,15 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) if ((I915_HAS_HOTPLUG(dev)) && (iir & I915_DISPLAY_PORT_INTERRUPT)) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & HOTPLUG_INT_STATUS_I915) + if (hotplug_trigger) { + hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); POSTING_READ(PORT_HOTPLUG_STAT); } @@ -2854,15 +2896,18 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) /* Consume port. Then clear IIR or we'll miss events */ if (iir & I915_DISPLAY_PORT_INTERRUPT) { u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ? + HOTPLUG_INT_STATUS_G4X : + HOTPLUG_INT_STATUS_I965); DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); - if (hotplug_status & (IS_G4X(dev) ? - HOTPLUG_INT_STATUS_G4X : - HOTPLUG_INT_STATUS_I965)) + if (hotplug_trigger) { + hotplug_irq_storm_detect(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965); queue_work(dev_priv->wq, &dev_priv->hotplug_work); - + } I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); I915_READ(PORT_HOTPLUG_STAT); } -- cgit v1.2.2 From 821450c6938d9228d8569d54d5c369985b1cc8dd Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 16 Apr 2013 13:36:55 +0200 Subject: drm/i915: (re)init HPD interrupt storm statistics When an encoder is shared on several connectors there is only one hotplug line, thus this line needs to be shared among these connectors. If HPD detect only works reliably on a subset of those connectors, we want to poll the others. Thus we need to make sure that storm detection doesn't mess up the settings for those connectors. Therefore we store the settings in the intel_connector struct and restore them from there. If nothing is set but the encoder has a hpd_pin set we assume this connector is hotplug capable. On init/reset we make sure the polled state of the connectors is (re)set to the default value, the HPD interrupts are marked enabled. Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++++++++++++++ drivers/gpu/drm/i915/intel_crt.c | 6 ++---- drivers/gpu/drm/i915/intel_dp.c | 1 - drivers/gpu/drm/i915/intel_drv.h | 4 ++++ drivers/gpu/drm/i915/intel_hdmi.c | 1 - drivers/gpu/drm/i915/intel_sdvo.c | 5 ++--- drivers/gpu/drm/i915/intel_tv.c | 2 +- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 5ac1291c5853..2b4967014dc6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -596,6 +596,7 @@ static inline void hotplug_irq_storm_detect(struct drm_device *dev, spin_lock_irqsave(&dev_priv->irq_lock, irqflags); for (i = 1; i < HPD_NUM_PINS; i++) { + if (!(hpd[i] & hotplug_trigger) || dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) continue; @@ -3062,7 +3063,20 @@ void intel_irq_init(struct drm_device *dev) void intel_hpd_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + int i; + for (i = 1; i < HPD_NUM_PINS; i++) { + dev_priv->hpd_stats[i].hpd_cnt = 0; + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + } + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + connector->polled = intel_connector->polled; + if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } if (dev_priv->display.hpd_irq_setup) dev_priv->display.hpd_irq_setup(dev); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 1ae2d7f39c6f..c063b9f0dd51 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -793,10 +793,8 @@ void intel_crt_init(struct drm_device *dev) drm_sysfs_connector_add(connector); - if (I915_HAS_HOTPLUG(dev)) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + if (!I915_HAS_HOTPLUG(dev)) + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; /* * Configure the automatic hotplug detection stuff diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8845e82ec9ed..89f89b727900 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2787,7 +2787,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); - connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = true; connector->doublescan_allowed = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a124e05fb581..7b97b9a1523e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -171,6 +171,10 @@ struct intel_connector { /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ struct edid *edid; + + /* since POLL and HPD connectors may use the same HPD line keep the native + state of connector->polled in case hotplug storm detection changes it */ + u8 polled; }; struct intel_crtc_config { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ee4a8da8311e..89122011720b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -998,7 +998,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs); - connector->polled = DRM_CONNECTOR_POLL_HPD; connector->interlace_allowed = 1; connector->doublescan_allowed = 0; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f6a9f4a0d7f0..a618a6a45a77 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2274,7 +2274,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector = &intel_connector->base; if (intel_sdvo_get_hotplug_support(intel_sdvo) & intel_sdvo_connector->output_flag) { - connector->polled = DRM_CONNECTOR_POLL_HPD; intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; /* Some SDVO devices have one-shot hotplug interrupts. * Ensure that they get re-enabled when an interrupt happens. @@ -2282,7 +2281,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_encoder->hot_plug = intel_sdvo_enable_hotplug; intel_sdvo_enable_hotplug(intel_encoder); } else { - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; } encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2351,7 +2350,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; encoder->encoder_type = DRM_MODE_ENCODER_DAC; connector->connector_type = DRM_MODE_CONNECTOR_VGA; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 66737265200f..b945bc54207a 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1613,7 +1613,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = DRM_CONNECTOR_POLL_CONNECT; + intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); -- cgit v1.2.2 From 995e6b3dcfa25e5837f103ae6e732fbca1790dd9 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 16 Apr 2013 13:36:56 +0200 Subject: drm/i915: Mask out the HPD irq bits before setting them individually. To disable previously enabled HPD IRQs we need to reset them and set the enabled ones individually. Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2b4967014dc6..b59df6e989cb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2128,9 +2128,11 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) u32 hotplug; if (HAS_PCH_IBX(dev)) { + mask &= ~SDE_HOTPLUG_MASK; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) mask |= hpd_ibx[intel_encoder->hpd_pin]; } else { + mask &= ~SDE_HOTPLUG_MASK_CPT; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) mask |= hpd_cpt[intel_encoder->hpd_pin]; } -- cgit v1.2.2 From cd569aed17b35b7be4567d0b277d23014ad34631 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 16 Apr 2013 13:36:57 +0200 Subject: drm/i915: Disable HPD interrupt on pin when irq storm is detected (v3) This patch disables hotplug interrupts if an 'interrupt storm' has been detected. Noise on the interrupt line renders the hotplug interrupt useless: each hotplug event causes the devices to be rescanned which will will only increase the system load. Thus disable the hotplug interrupts and fall back to periodic device polling. v2: Fixed cleanup typo. v3: Fixed format issues, clarified a variable name, changed pr_warn() to DRM_INFO() as suggested by Jani Nikula . Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 75 +++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b59df6e989cb..565ea96f772f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -88,7 +88,8 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */ [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS }; - +static void ibx_hpd_irq_setup(struct drm_device *dev); +static void i915_hpd_irq_setup(struct drm_device *dev); /* For display hotplug interrupt */ static void @@ -342,7 +343,11 @@ static void i915_hotplug_work_func(struct work_struct *work) hotplug_work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + unsigned long irqflags; + bool hpd_disabled = false; /* HPD irq before everything is fully set up. */ if (!dev_priv->enable_hotplug_processing) @@ -351,9 +356,33 @@ static void i915_hotplug_work_func(struct work_struct *work) mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) - if (encoder->hot_plug) - encoder->hot_plug(encoder); + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + list_for_each_entry(connector, &mode_config->connector_list, head) { + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (intel_encoder->hpd_pin > HPD_NONE && + dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && + connector->polled == DRM_CONNECTOR_POLL_HPD) { + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + drm_get_connector_name(connector)); + dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + } + /* if there were no outputs to poll, poll was disabled, + * therefore make sure it's enabled when disabling HPD on + * some connectors */ + if (hpd_disabled) + drm_kms_helper_poll_enable(dev); + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (intel_encoder->hot_plug) + intel_encoder->hot_plug(intel_encoder); mutex_unlock(&mode_config->mutex); @@ -585,13 +614,14 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static inline void hotplug_irq_storm_detect(struct drm_device *dev, +static inline bool hotplug_irq_storm_detect(struct drm_device *dev, u32 hotplug_trigger, const u32 *hpd) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned long irqflags; int i; + bool ret = false; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); @@ -609,12 +639,15 @@ static inline void hotplug_irq_storm_detect(struct drm_device *dev, } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); + ret = true; } else { dev_priv->hpd_stats[i].hpd_cnt++; } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + + return ret; } static void gmbus_irq_handler(struct drm_device *dev) @@ -690,7 +723,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915); + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -720,7 +754,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx); + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx)) + ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK) @@ -768,7 +803,8 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt); + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt)) + ibx_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) @@ -2130,11 +2166,13 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) if (HAS_PCH_IBX(dev)) { mask &= ~SDE_HOTPLUG_MASK; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) - mask |= hpd_ibx[intel_encoder->hpd_pin]; + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + mask |= hpd_ibx[intel_encoder->hpd_pin]; } else { mask &= ~SDE_HOTPLUG_MASK_CPT; list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) - mask |= hpd_cpt[intel_encoder->hpd_pin]; + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + mask |= hpd_cpt[intel_encoder->hpd_pin]; } I915_WRITE(SDEIMR, ~mask); @@ -2669,7 +2707,8 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915); + if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } @@ -2819,7 +2858,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; + struct intel_encoder *intel_encoder; u32 hotplug_en; if (I915_HAS_HOTPLUG(dev)) { @@ -2827,8 +2866,9 @@ static void i915_hpd_irq_setup(struct drm_device *dev) hotplug_en &= ~HOTPLUG_INT_EN_MASK; /* Note HDMI and DP share hotplug bits */ /* enable bits are the same for all generations */ - list_for_each_entry(encoder, &mode_config->encoder_list, base.head) - hotplug_en |= hpd_mask_i915[encoder->hpd_pin]; + list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head) + if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; /* Programming the CRT detection parameters tends to generate a spurious hotplug event about three seconds later. So just do it once. @@ -2906,8 +2946,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", hotplug_status); if (hotplug_trigger) { - hotplug_irq_storm_detect(dev, hotplug_trigger, - IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965); + if (hotplug_irq_storm_detect(dev, hotplug_trigger, + IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965)) + i915_hpd_irq_setup(dev); queue_work(dev_priv->wq, &dev_priv->hotplug_work); } -- cgit v1.2.2 From ac4c16c56cd41f320af064fc7bf28a1ec82c2278 Mon Sep 17 00:00:00 2001 From: Egbert Eich Date: Tue, 16 Apr 2013 13:36:58 +0200 Subject: drm/i915: Add Reenable Timer to turn Hotplug Detection back on (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We disable hoptplug detection when we encounter a hotplug event storm. Still hotplug detection is required on some outputs (like Display Port). The interrupt storm may be only temporary (on certain Dell Laptops for instance it happens at certain charging states of the system). Thus we enable it after a certain grace period (2 minutes). Should the interrupt storm persist it will be detected immediately and it will be disabled again. v2: Reordered drm_i915_private: moved hotplug_reenable_timer to hpd state tracker. v3: Clarified loop start value, Removed superfluous test for Ivybridge and Haswell, Restructured loop to avoid deep nesting (all suggested by Ville Syrjälä) v4: Fixed two bugs pointed out by Jani Nikula. Signed-off-by: Egbert Eich Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 52 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7b613c2280f1..9b85fcdb3918 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -941,6 +941,7 @@ typedef struct drm_i915_private { HPD_MARK_DISABLED = 2 } hpd_mark; } hpd_stats[HPD_NUM_PINS]; + struct timer_list hotplug_reenable_timer; int num_pch_pll; int num_plane; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 565ea96f772f..0aa2ef0d2ae0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -337,6 +337,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, /* * Handle hotplug events outside the interrupt handler proper. */ +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) + static void i915_hotplug_work_func(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, @@ -375,8 +377,11 @@ static void i915_hotplug_work_func(struct work_struct *work) /* if there were no outputs to poll, poll was disabled, * therefore make sure it's enabled when disabling HPD on * some connectors */ - if (hpd_disabled) + if (hpd_disabled) { drm_kms_helper_poll_enable(dev); + mod_timer(&dev_priv->hotplug_reenable_timer, + jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -2367,6 +2372,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + for_each_pipe(pipe) I915_WRITE(PIPESTAT(pipe), 0xffff); @@ -2388,6 +2395,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(DEIMR, 0xffffffff); @@ -2767,6 +2776,8 @@ static void i915_irq_uninstall(struct drm_device * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int pipe; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -3011,6 +3022,8 @@ static void i965_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; + del_timer_sync(&dev_priv->hotplug_reenable_timer); + I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -3026,6 +3039,41 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } +static void i915_reenable_hotplug_timer_func(unsigned long data) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *)data; + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + unsigned long irqflags; + int i; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { + struct drm_connector *connector; + + if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED) + continue; + + dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (intel_connector->encoder->hpd_pin == i) { + if (connector->polled != intel_connector->polled) + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", + drm_get_connector_name(connector)); + connector->polled = intel_connector->polled; + if (!connector->polled) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + } + } + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + void intel_irq_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3038,6 +3086,8 @@ void intel_irq_init(struct drm_device *dev) setup_timer(&dev_priv->gpu_error.hangcheck_timer, i915_hangcheck_elapsed, (unsigned long) dev); + setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func, + (unsigned long) dev_priv); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); -- cgit v1.2.2 From 3f704fa2778d3fe45e6529825a5c7a8bcbc686f4 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 8 Apr 2013 15:48:07 -0300 Subject: drm/i915: set CPT FDI RX polarity bits based on VBT Check the VBT to see if the machine has inverted FDI RX polarity on CPT. Based on this bit, set the appropriate bit on the TRANS_CHICKEN2 registers. This should fix some machines that were showing black screens on all outputs. Cc: stable@vger.kernel.org Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=60029 Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_bios.c | 6 ++++-- drivers/gpu/drm/i915/intel_bios.h | 4 +++- drivers/gpu/drm/i915/intel_pm.c | 9 +++++++-- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b85fcdb3918..d5dcf7fe1ee9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -976,6 +976,7 @@ typedef struct drm_i915_private { unsigned int int_crt_support:1; unsigned int lvds_use_ssc:1; unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ struct { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 077d40f37b97..fc8a4a940e92 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3960,7 +3960,7 @@ #define _TRANSB_CHICKEN2 0xf1064 #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) #define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) - +#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) #define SOUTH_CHICKEN1 0xc2000 #define FDIA_PHASE_SYNC_SHIFT_OVR 19 diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 194df27c89eb..95070b2124c6 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -351,12 +351,14 @@ parse_general_features(struct drm_i915_private *dev_priv, dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, general->ssc_freq); dev_priv->display_clock_mode = general->display_clock_mode; - DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n", + dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted; + DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n", dev_priv->int_tv_support, dev_priv->int_crt_support, dev_priv->lvds_use_ssc, dev_priv->lvds_ssc_freq, - dev_priv->display_clock_mode); + dev_priv->display_clock_mode, + dev_priv->fdi_rx_polarity_inverted); } } diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 36e57f934373..e088d6f0956a 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -127,7 +127,9 @@ struct bdb_general_features { /* bits 3 */ u8 disable_smooth_vision:1; u8 single_dvi:1; - u8 rsvd9:6; /* finish byte */ + u8 rsvd9:1; + u8 fdi_rx_polarity_inverted:1; + u8 rsvd10:4; /* finish byte */ /* bits 4 */ u8 legacy_monitor_detect; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f747cb036d8c..6f67fa122f81 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3590,6 +3590,7 @@ static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; + uint32_t val; /* * On Ibex Peak and Cougar Point, we need to disable clock @@ -3602,8 +3603,12 @@ static void cpt_init_clock_gating(struct drm_device *dev) /* The below fixes the weird display corruption, a few pixels shifted * downward, on (only) LVDS of some HP laptops with IVY. */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_CHICKEN2_TIMING_OVERRIDE); + for_each_pipe(pipe) { + val = TRANS_CHICKEN2_TIMING_OVERRIDE; + if (dev_priv->fdi_rx_polarity_inverted) + val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + I915_WRITE(TRANS_CHICKEN2(pipe), val); + } /* WADP0ClockGatingDisable */ for_each_pipe(pipe) { I915_WRITE(TRANS_CHICKEN1(pipe), -- cgit v1.2.2 From dc4bd2d1095d0a7b45dcd23cc8a423a2952cbf4d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Mon, 8 Apr 2013 15:48:08 -0300 Subject: drm/i915: preserve the PBC bits of TRANS_CHICKEN2 Bits 30 and 24:0 are PBC, so don't zero them. Some of the other bits are being zeroed, but I couldn't find a reason for this, so leave them as they are for now to avoid regressions. Signed-off-by: Paulo Zanoni Reviewed-by: Imre Deak [danvet: Delete the redudant #define that Imre spotted in his review.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 7 +++++-- drivers/gpu/drm/i915/intel_pm.c | 7 ++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fc8a4a940e92..31de7e4b1f3e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3959,8 +3959,11 @@ #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 #define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) -#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) -#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) +#define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) +#define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) +#define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) +#define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) #define SOUTH_CHICKEN1 0xc2000 #define FDIA_PHASE_SYNC_SHIFT_OVR 19 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6f67fa122f81..e34ad9642519 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3604,9 +3604,14 @@ static void cpt_init_clock_gating(struct drm_device *dev) * downward, on (only) LVDS of some HP laptops with IVY. */ for_each_pipe(pipe) { - val = TRANS_CHICKEN2_TIMING_OVERRIDE; + val = I915_READ(TRANS_CHICKEN2(pipe)); + val |= TRANS_CHICKEN2_TIMING_OVERRIDE; + val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED; if (dev_priv->fdi_rx_polarity_inverted) val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED; + val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER; + val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH; I915_WRITE(TRANS_CHICKEN2(pipe), val); } /* WADP0ClockGatingDisable */ -- cgit v1.2.2 From 3b117c8f2815bc4dd36b0b2c4b6490ad7d10b758 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 17 Apr 2013 20:15:07 +0200 Subject: drm/i915: move cpu_transcoder to the pipe configuration For a bunch of reason we need to more accurately track this: - hw pipe state readout for Haswell needs the cpu transcoder. - We need to know the right cpu transcoder in a bunch of places in ->disable and other modeset callbacks. In the future we need to add hw state readout&check support, too. But to avoid ugly merge conflicts do the rote sed job now without any functional changes. v2: Preserve the cpu_transcoder value when overwriting crtc->config. Reported by Paulo. Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Reviewed-by: Chris Wilson (v1) [danvet: Removed rough whitespace that Chris spotted.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++---- drivers/gpu/drm/i915/intel_display.c | 37 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 5 ++++- drivers/gpu/drm/i915/intel_hdmi.c | 6 +++--- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 22524cb6903b..26a0a570f92e 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -924,7 +924,7 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; int type = intel_encoder->type; uint32_t temp; @@ -958,7 +958,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) struct drm_encoder *encoder = &intel_encoder->base; struct drm_i915_private *dev_priv = crtc->dev->dev_private; enum pipe pipe = intel_crtc->pipe; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; uint32_t temp; @@ -1223,7 +1223,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); enum port port = intel_ddi_get_encoder_port(intel_encoder); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (cpu_transcoder != TRANSCODER_EDP) I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), @@ -1233,7 +1233,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) { struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (cpu_transcoder != TRANSCODER_EDP) I915_WRITE(TRANS_CLK_SEL(cpu_transcoder), diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6a8262867b0b..c5bf283c27b3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -892,7 +892,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - return intel_crtc->cpu_transcoder; + return intel_crtc->config.cpu_transcoder; } static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe) @@ -3203,7 +3203,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; assert_transcoder_disabled(dev_priv, TRANSCODER_A); @@ -3578,7 +3578,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; if (!intel_crtc->active) return; @@ -3638,7 +3638,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc) /* Stop saying we're using TRANSCODER_EDP because some other CRTC might * start using it. */ - intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe; + intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe; intel_ddi_put_crtc_pll(crtc); } @@ -4494,7 +4494,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc, struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = intel_crtc->pipe; - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; uint32_t vsyncshift; if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { @@ -5236,7 +5236,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc, { struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; uint32_t val; val = I915_READ(PIPECONF(cpu_transcoder)); @@ -5430,7 +5430,7 @@ void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int pipe = crtc->pipe; - enum transcoder transcoder = crtc->cpu_transcoder; + enum transcoder transcoder = crtc->config.cpu_transcoder; if (INTEL_INFO(dev)->gen >= 5) { I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m); @@ -5613,7 +5613,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)), "Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev)); - intel_crtc->cpu_transcoder = pipe; + intel_crtc->config.cpu_transcoder = pipe; ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, &has_reduced_clock, &reduced_clock); @@ -5797,9 +5797,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, } if (is_cpu_edp) - intel_crtc->cpu_transcoder = TRANSCODER_EDP; + intel_crtc->config.cpu_transcoder = TRANSCODER_EDP; else - intel_crtc->cpu_transcoder = pipe; + intel_crtc->config.cpu_transcoder = pipe; /* We are not sure yet this won't happen. */ WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n", @@ -5808,7 +5808,7 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, WARN(num_connectors != 1, "%d connectors attached to pipe %c\n", num_connectors, pipe_name(pipe)); - WARN_ON(I915_READ(PIPECONF(intel_crtc->cpu_transcoder)) & + WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) & (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE)); WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE); @@ -5859,7 +5859,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t tmp; - tmp = I915_READ(PIPECONF(crtc->cpu_transcoder)); + tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder)); if (!(tmp & PIPECONF_ENABLE)) return false; @@ -6827,7 +6827,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; + enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; struct drm_display_mode *mode; int htot = I915_READ(HTOTAL(cpu_transcoder)); int hsync = I915_READ(HSYNC(cpu_transcoder)); @@ -7990,10 +7990,12 @@ static int __intel_set_mode(struct drm_crtc *crtc, * to set it here already despite that we pass it down the callchain. */ if (modeset_pipes) { + enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder; crtc->mode = *mode; /* mode_set/enable/disable functions rely on a correct pipe * config. */ to_intel_crtc(crtc)->config = *pipe_config; + to_intel_crtc(crtc)->config.cpu_transcoder = tmp; } /* Only after disabling all output pipelines that will be changed can we @@ -8404,7 +8406,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) /* Swap pipes & planes for FBC on pre-965 */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - intel_crtc->cpu_transcoder = pipe; + intel_crtc->config.cpu_transcoder = pipe; if (IS_MOBILE(dev) && IS_GEN3(dev)) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; @@ -9129,7 +9131,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) u32 reg; /* Clear any frame start delays used for debugging left by the BIOS */ - reg = PIPECONF(crtc->cpu_transcoder); + reg = PIPECONF(crtc->config.cpu_transcoder); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* We need to sanitize the plane -> pipe mapping first because this will @@ -9295,7 +9297,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, } crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - crtc->cpu_transcoder = TRANSCODER_EDP; + crtc->config.cpu_transcoder = TRANSCODER_EDP; DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n", pipe_name(pipe)); @@ -9305,7 +9307,10 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, setup_pipes: list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + enum transcoder tmp = crtc->config.cpu_transcoder; memset(&crtc->config, 0, sizeof(crtc->config)); + crtc->config.cpu_transcoder = tmp; + crtc->active = dev_priv->display.get_pipe_config(crtc, &crtc->config); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7b97b9a1523e..b5b6d19e6dd3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -188,6 +188,10 @@ struct intel_crtc_config { * between pch encoders and cpu encoders. */ bool has_pch_encoder; + /* CPU Transcoder for the pipe. Currently this can only differ from the + * pipe on Haswell (where we have a special eDP transcoder). */ + enum transcoder cpu_transcoder; + /* * Use reduced/limited/broadcast rbg range, compressing from the full * range fed into the crtcs. @@ -226,7 +230,6 @@ struct intel_crtc { struct drm_crtc base; enum pipe pipe; enum plane plane; - enum transcoder cpu_transcoder; u8 lut_r[256], lut_g[256], lut_b[256]; /* * Whether the crtc and the connected output pipeline is active. Implies diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 89122011720b..3e6a3ef10d5c 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -294,8 +294,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); - u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->cpu_transcoder); + u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); + u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->config.cpu_transcoder); unsigned int i, len = DIP_HEADER_SIZE + frame->len; u32 val = I915_READ(ctl_reg); @@ -570,7 +570,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->cpu_transcoder); + u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder); u32 val = I915_READ(reg); assert_hdmi_port_disabled(intel_hdmi); -- cgit v1.2.2 From bd080ee57c2173cefdcadc39c7863a76c249d049 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 17 Apr 2013 20:01:39 +0200 Subject: drm/i915: fix bpc vs. bpp confusion in intel_crtc_compute_config Oops. This regression has been introduced in commit 5d2d38ddcac991f71c19d03d95bde8e14abc0352 Author: Daniel Vetter Date: Wed Mar 27 00:45:01 2013 +0100 drm/i915: clean up pipe bpp confusion Reported-by: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c5bf283c27b3..6e423e04c35e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4003,9 +4003,9 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc, adjusted_mode->hsync_start == adjusted_mode->hdisplay) return false; - if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10) { + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) { pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */ - } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8) { + } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) { /* only a 8bpc pipe, with 6bpc dither through the panel fitter * for lvds. */ pipe_config->pipe_bpp = 8*3; -- cgit v1.2.2