From 2cac613be8d4d661edd359cdab3c474286c4f5f0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 30 Jan 2014 16:50:42 +0200 Subject: drm/i915: vlv: fix DP PHY lockup due to invalid PP sequencer setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atm we setup the HW panel power sequencer logic both for eDP and DP ports. On eDP we then go on and start the power on sequence and commence with link training when it's ready. On DP we don't do the power on sequencing but do the link training immediately. At this point the DP PHY block gets stuck, since - supposedly - it is waiting for the power on sequence to finish. The actual register write that seems to hold off the PHY is PIPEX_PP_ON_DELAYS[Panel Control Port Select]. Writing here a non-0 value eventually sets PIPEX_PP_STATUS[Require Asset Status] to 1 and blocks the PHY until the panel power on is ready. Fix this by not doing any PP sequencing setup for DP ports. Thanks to Ville Syrjälä, Jesse Barnes and Todd Previte for the help in tracking this down. Note that on older gmch platforms (where we have lvds instead of edp) we've hacked around this by writing the magic ABCD unlock key to PP registers, which disables the hw sanity checks. For edp all platforms thus far had the pch split, with the edp port in the north display complex and the PP registers on the pch the hw sanity checks (expressed through the "Require Asset Status" bit) was never functional, hence never a real issue. This regression has been introduce in commit bf13e81b904a37d94d83dd6c3b53a147719a3ead Author: Jani Nikula Date: Fri Sep 6 07:40:05 2013 +0300 drm/i915: add support for per-pipe power sequencing on vlv Signed-off-by: Imre Deak [danvet: Add note about the bigger story here.] Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ede4e8..c00b6e3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1869,10 +1869,12 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); - /* init power sequencer on this pipe and port */ - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + if (is_edp(intel_dp)) { + /* init power sequencer on this pipe and port */ + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, + &power_seq); + } intel_enable_dp(encoder); -- cgit v0.10.2 From 7288ca07b638db485abec5752bd6b1faed1c33ef Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:44 +0100 Subject: drm/i2c: tda998x: fix bad value in the AIF The AIF has an uninitialized byte. This patch clears the whole buffer before filling it. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 400b0c4..e620826 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -528,10 +528,10 @@ tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p) { uint8_t buf[PB(5) + 1]; + memset(buf, 0, sizeof(buf)); buf[HB(0)] = 0x84; buf[HB(1)] = 0x01; buf[HB(2)] = 10; - buf[PB(0)] = 0; buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */ buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */ buf[PB(4)] = p->audio_frame[4]; -- cgit v0.10.2 From 6ae668cc19e8b18df28cd67b3448d9abd79284a4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:43 +0100 Subject: drm/i2c: tda998x: check the CEC device creation This patch checks if the CEC device is well created at intialization time. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index e620826..c37180a 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1144,6 +1144,8 @@ tda998x_encoder_init(struct i2c_client *client, priv->current_page = 0; priv->cec = i2c_new_dummy(client->adapter, 0x34); + if (!priv->cec) + return -ENODEV; priv->dpms = DRM_MODE_DPMS_OFF; encoder_slave->slave_priv = priv; -- cgit v0.10.2 From fc275a74eb816c12d4fc226344e734872ed0b2f9 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:42 +0100 Subject: drm/i2c: tda998x: free the CEC device on encoder_destroy The cec i2c device is created in tda998x_encoder_init() when the DRM driver starts. This patch frees it when the DRM driver is unloaded. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index c37180a..de0572e 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1094,6 +1094,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder) { struct tda998x_priv *priv = to_tda998x_priv(encoder); drm_i2c_encoder_destroy(encoder); + if (priv->cec) + i2c_unregister_device(priv->cec); kfree(priv); } -- cgit v0.10.2 From 2eb4c7b1e7f275fe833aabe0a251b8e3f767fb08 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:45 +0100 Subject: drm/i2c: tda998x: force the page register at startup time This patch forces the page register to be set on the first I/O operation. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index de0572e..e871a42 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1144,7 +1144,7 @@ tda998x_encoder_init(struct i2c_client *client, priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); - priv->current_page = 0; + priv->current_page = 0xff; priv->cec = i2c_new_dummy(client->adapter, 0x34); if (!priv->cec) return -ENODEV; -- cgit v0.10.2 From 3ae471f73a1d581e078b5b06d08d7b82833a093f Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:36 +0100 Subject: drm/i2c: tda998x: set the PLL division factor in range 0..3 The predivider division factor of the register PLL_SERIAL_2 is in the range 0..3, the value 0 being used for a division by 1. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index e871a42..a65250b 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -208,7 +208,7 @@ struct tda998x_priv { # define PLL_SERIAL_1_SRL_IZ(x) (((x) & 3) << 1) # define PLL_SERIAL_1_SRL_MAN_IZ (1 << 6) #define REG_PLL_SERIAL_2 REG(0x02, 0x01) /* read/write */ -# define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 3) << 0) +# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0) # define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4) #define REG_PLL_SERIAL_3 REG(0x02, 0x02) /* read/write */ # define PLL_SERIAL_3_SRL_CCIR (1 << 0) @@ -824,6 +824,11 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, } div = 148500 / mode->clock; + if (div != 0) { + div--; + if (div > 3) + div = 3; + } /* mute the audio FIFO: */ reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); -- cgit v0.10.2 From 2e9a3fc3a360ac180f5b4c3c4416a0d0dec60dd8 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 25 Jan 2014 18:14:37 +0100 Subject: drm/i2c: tda998x: fix the ENABLE_SPACE register This patch fixes the ENABLE_SPACE register, the value of which was inverted. Tested-by: Russell King Acked-by: Russell King Signed-off-by: Jean-Francois Moine Signed-off-by: Russell King diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a65250b..fa18cf3 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -918,7 +918,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, if (priv->rev == TDA19988) { /* let incoming pixels fill the active space (if any) */ - reg_write(encoder, REG_ENABLE_SPACE, 0x01); + reg_write(encoder, REG_ENABLE_SPACE, 0x00); } /* must be last register set: */ -- cgit v0.10.2 From 89258a97531124cd1e212f7a8ed44fccf8f9a891 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 4 Feb 2014 19:57:38 +0100 Subject: MAINTAINERS: Update drm/i915 git repo Moved to a common location so that Jani also can push to it, to avoid moving it every time I go on vacation. Please update autobuilders and everything else pointing at the drm-intel.git repo, the old one won't be updated any more. Cc: Dave Airlie Cc: Jani Nikula Signed-off-by: Daniel Vetter diff --git a/MAINTAINERS b/MAINTAINERS index 31a0462..e3aaf27 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2832,7 +2832,7 @@ M: Jani Nikula L: intel-gfx@lists.freedesktop.org L: dri-devel@lists.freedesktop.org Q: http://patchwork.freedesktop.org/project/intel-gfx/ -T: git git://people.freedesktop.org/~danvet/drm-intel +T: git git://anongit.freedesktop.org/drm-intel S: Supported F: drivers/gpu/drm/i915/ F: include/drm/i915* -- cgit v0.10.2 From 48b8f6315a6a230f859fcae8ef4a0ccf4f48e802 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 31 Jan 2014 15:49:07 +0200 Subject: drm: add DRM_INFO_ONCE() to print a one-time DRM_INFO() message Just like DRM_INFO(), but only do it once. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Acked-by: Dave Airlie Signed-off-by: Daniel Vetter diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 04086c5..04a7f31 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -199,6 +199,9 @@ int drm_err(const char *func, const char *format, ...); #define DRM_INFO(fmt, ...) \ printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) +#define DRM_INFO_ONCE(fmt, ...) \ + printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) + /** * Debug output. * -- cgit v0.10.2 From bdde5c6a258a702bdfa7d1f4ae804a7bc405e788 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 31 Jan 2014 15:49:08 +0200 Subject: drm/i915: demote opregion excessive timeout WARN_ONCE to DRM_INFO_ONCE The WARN_ONCE is a bit too verbose, make it a DRM_INFO_ONCE. While at it, add a #define for MAX_DSLP and make the message a bit more informative. v2: use DRM_INFO_ONCE, add MAX_DSLP, pimp the message. Suggested-by: Chris Wilson Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 37e9a96..6845960 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -227,6 +227,8 @@ struct opregion_asle { #define ACPI_DIGITAL_OUTPUT (3<<8) #define ACPI_LVDS_OUTPUT (4<<8) +#define MAX_DSLP 1500 + #ifdef CONFIG_ACPI static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) { @@ -261,10 +263,11 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) /* The spec says 2ms should be the default, but it's too small * for some machines. */ dslp = 50; - } else if (dslp > 500) { + } else if (dslp > MAX_DSLP) { /* Hey bios, trust must be earned. */ - WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp); - dslp = 500; + DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, " + "using %u ms instead\n", dslp, MAX_DSLP); + dslp = MAX_DSLP; } /* The spec tells us to do this, but we are the only user... */ -- cgit v0.10.2 From 7896052d90d7de899fd3a34c0b34e91941e2f2ea Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 13 Dec 2013 09:11:01 -0500 Subject: drm/msm: fix inconsequential typo Small typo I noticed in the mdp4_plane code.. no consequence because PIPE_SRC_XY and PIPE_DST_XY have same register layout. Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 2406027..1e893dd 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -170,8 +170,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane, MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), - MDP4_PIPE_SRC_XY_X(crtc_x) | - MDP4_PIPE_SRC_XY_Y(crtc_y)); + MDP4_PIPE_DST_XY_X(crtc_x) | + MDP4_PIPE_DST_XY_Y(crtc_y)); mdp4_plane_set_scanout(plane, fb); -- cgit v0.10.2 From 37033a7689b01d0c46f9cc450bdf9f02d86b7e57 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 13 Dec 2013 10:38:54 -0500 Subject: drm/msm/mdp5: fix ref leaks in error paths Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 71a3b23..f279402 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -296,6 +296,7 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { + drm_framebuffer_unreference(crtc->fb); dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", mdp5_crtc->name, ret); return ret; @@ -343,11 +344,15 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + return ret; + } update_fb(crtc, crtc->fb); update_scanout(crtc, crtc->fb); - return ret; + return 0; } static void mdp5_crtc_load_lut(struct drm_crtc *crtc) -- cgit v0.10.2 From b69720c0f5d417310fbfd59c2d681bd90430a4f5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 13 Dec 2013 10:41:07 -0500 Subject: drm/msm/mdp4: pageflip fixes Backport a few fixes found in the course of getting mdp5 working. There is a window of time after pageflip is requested, before we start scanning out the new fb (ie. while we are waiting for gpu). During that time we need to continue holding a reference to the still-current scanout fb, to avoid the backing gem bo's from being destroyed. Possibly a common mdp_crtc parent class could be useful to share some of this logic between mdp4_crtc and mdp5_crtc. OTOH, this all can be removed from the driver once atomic is in place, as plane/crtc updates get deferred until all fb's are ready before calling in to .page_flip(), etc. Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 1964f4f..ed739e8 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -57,9 +57,16 @@ struct mdp4_crtc { #define PENDING_FLIP 0x2 atomic_t pending; - /* the fb that we currently hold a scanout ref to: */ + /* the fb that we logically (from PoV of KMS API) hold a ref + * to. Which we may not yet be scanning out (we may still + * be scanning out previous in case of page_flip while waiting + * for gpu rendering to complete: + */ struct drm_framebuffer *fb; + /* the fb that we currently hold a scanout ref to: */ + struct drm_framebuffer *scanout_fb; + /* for unref'ing framebuffers after scanout completes: */ struct drm_flip_work unref_fb_work; @@ -77,24 +84,73 @@ static struct mdp4_kms *get_kms(struct drm_crtc *crtc) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void update_fb(struct drm_crtc *crtc, bool async, - struct drm_framebuffer *new_fb) +static void request_pending(struct drm_crtc *crtc, uint32_t pending) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct drm_framebuffer *old_fb = mdp4_crtc->fb; - if (old_fb) - drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); + atomic_or(pending, &mdp4_crtc->pending); + mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); +} + +static void crtc_flush(struct drm_crtc *crtc) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); + uint32_t i, flush = 0; + + for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { + struct drm_plane *plane = mdp4_crtc->planes[i]; + if (plane) { + enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); + flush |= pipe2flush(pipe_id); + } + } + flush |= ovlp2flush(mdp4_crtc->ovlp); + + DBG("%s: flush=%08x", mdp4_crtc->name, flush); + + mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); +} + +static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct drm_framebuffer *old_fb = mdp4_crtc->fb; /* grab reference to incoming scanout fb: */ drm_framebuffer_reference(new_fb); mdp4_crtc->base.fb = new_fb; mdp4_crtc->fb = new_fb; - if (!async) { - /* enable vblank to pick up the old_fb */ - mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); - } + if (old_fb) + drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); +} + +/* unlike update_fb(), take a ref to the new scanout fb *before* updating + * plane, then call this. Needed to ensure we don't unref the buffer that + * is actually still being scanned out. + * + * Note that this whole thing goes away with atomic.. since we can defer + * calling into driver until rendering is done. + */ +static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + + /* flush updates, to make sure hw is updated to new scanout fb, + * so that we can safely queue unref to current fb (ie. next + * vblank we know hw is done w/ previous scanout_fb). + */ + crtc_flush(crtc); + + if (mdp4_crtc->scanout_fb) + drm_flip_work_queue(&mdp4_crtc->unref_fb_work, + mdp4_crtc->scanout_fb); + + mdp4_crtc->scanout_fb = fb; + + /* enable vblank to complete flip: */ + request_pending(crtc, PENDING_FLIP); } /* if file!=NULL, this is preclose potential cancel-flip path */ @@ -120,34 +176,6 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) spin_unlock_irqrestore(&dev->event_lock, flags); } -static void crtc_flush(struct drm_crtc *crtc) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct mdp4_kms *mdp4_kms = get_kms(crtc); - uint32_t i, flush = 0; - - for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { - struct drm_plane *plane = mdp4_crtc->planes[i]; - if (plane) { - enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); - flush |= pipe2flush(pipe_id); - } - } - flush |= ovlp2flush(mdp4_crtc->ovlp); - - DBG("%s: flush=%08x", mdp4_crtc->name, flush); - - mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); -} - -static void request_pending(struct drm_crtc *crtc, uint32_t pending) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - - atomic_or(pending, &mdp4_crtc->pending); - mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); -} - static void pageflip_cb(struct msm_fence_cb *cb) { struct mdp4_crtc *mdp4_crtc = @@ -158,11 +186,9 @@ static void pageflip_cb(struct msm_fence_cb *cb) if (!fb) return; + drm_framebuffer_reference(fb); mdp4_plane_set_scanout(mdp4_crtc->plane, fb); - crtc_flush(crtc); - - /* enable vblank to complete flip: */ - request_pending(crtc, PENDING_FLIP); + update_scanout(crtc, fb); } static void unref_fb_worker(struct drm_flip_work *work, void *val) @@ -320,6 +346,20 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mode->vsync_end, mode->vtotal, mode->type, mode->flags); + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); + + ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x << 16, y << 16, + mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", + mdp4_crtc->name, ret); + return ret; + } + mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); @@ -341,24 +381,15 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); - update_fb(crtc, false, crtc->fb); - - ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, - mode->hdisplay << 16, mode->vdisplay << 16); - if (ret) { - dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", - mdp4_crtc->name, ret); - return ret; - } - if (dma == DMA_E) { mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); } + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + return 0; } @@ -385,13 +416,24 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct drm_plane *plane = mdp4_crtc->plane; struct drm_display_mode *mode = &crtc->mode; + int ret; - update_fb(crtc, false, crtc->fb); + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); - return mdp4_plane_mode_set(plane, crtc, crtc->fb, + ret = mdp4_plane_mode_set(plane, crtc, crtc->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + return ret; + } + + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + + return 0; } static void mdp4_crtc_load_lut(struct drm_crtc *crtc) @@ -419,7 +461,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, mdp4_crtc->event = event; spin_unlock_irqrestore(&dev->event_lock, flags); - update_fb(crtc, true, new_fb); + update_fb(crtc, new_fb); return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); } @@ -713,6 +755,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, crtc = &mdp4_crtc->base; mdp4_crtc->plane = plane; + mdp4_crtc->id = id; mdp4_crtc->ovlp = ovlp_id; mdp4_crtc->dma = dma_id; -- cgit v0.10.2 From aa1b0e59d3096f4602afeb114a3b3be505889a26 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 13 Dec 2013 10:49:25 -0500 Subject: drm/msm/mdp4: cursor fixes It seems we need to update all cursor registers from vblank. This appears to be the cause of intermittent underflows when enabling/ disabling cursor. Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index ed739e8..84c5b13 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -39,6 +39,7 @@ struct mdp4_crtc { spinlock_t lock; bool stale; uint32_t width, height; + uint32_t x, y; /* next cursor to scan-out: */ uint32_t next_iova; @@ -484,12 +485,12 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc, static void update_cursor(struct drm_crtc *crtc) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); enum mdp4_dma dma = mdp4_crtc->dma; unsigned long flags; spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); if (mdp4_crtc->cursor.stale) { - struct mdp4_kms *mdp4_kms = get_kms(crtc); struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo; struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo; uint32_t iova = mdp4_crtc->cursor.next_iova; @@ -521,6 +522,11 @@ static void update_cursor(struct drm_crtc *crtc) mdp4_crtc->cursor.scanout_bo = next_bo; mdp4_crtc->cursor.stale = false; } + + mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma), + MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) | + MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y)); + spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); } @@ -572,6 +578,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, drm_gem_object_unreference_unlocked(old_bo); } + crtc_flush(crtc); request_pending(crtc, PENDING_CURSOR); return 0; @@ -584,12 +591,15 @@ fail: static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct mdp4_kms *mdp4_kms = get_kms(crtc); - enum mdp4_dma dma = mdp4_crtc->dma; + unsigned long flags; - mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma), - MDP4_DMA_CURSOR_POS_X(x) | - MDP4_DMA_CURSOR_POS_Y(y)); + spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); + mdp4_crtc->cursor.x = x; + mdp4_crtc->cursor.y = y; + spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); + + crtc_flush(crtc); + request_pending(crtc, PENDING_CURSOR); return 0; } -- cgit v0.10.2 From 9999f105e76977d97304d7cb2030a52d96800d69 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 4 Feb 2014 14:17:32 -0500 Subject: drm/msm: fix deadlock in bo create fail path We already hold struct_mutex here. Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index d8d60c9..3da8264 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -644,7 +644,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, fail: if (obj) - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_unreference(obj); return ERR_PTR(ret); } -- cgit v0.10.2 From b927e1c20462c1ad9caf4c4fa3a30e838a2d4037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 30 Jan 2014 19:01:16 +0100 Subject: drm/radeon: fix UVD IRQ support on SI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise decoding isn't really useable. bug: https://bugs.freedesktop.org/show_bug.cgi?id=71448 Signed-off-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 09ec4f6..8357832 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6338,6 +6338,10 @@ restart_ih: break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 146: case 147: addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); -- cgit v0.10.2 From 858a41c853cef2cb01de34dae334c19c1c15b237 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Jan 2014 14:35:04 -0500 Subject: drm/radeon: fix UVD IRQ support on 7xx Otherwise decoding isn't really useable. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 56140b4..cdbc417 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3991,6 +3991,10 @@ restart_ih: break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ -- cgit v0.10.2 From 9f3f63f24c901cad831e78bbb738df61a1c4ff02 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Jan 2014 11:19:22 -0500 Subject: drm/radeon/dpm: use the driver state for dpm debugfs For btc and newer, we may modify the power state depending on the circumstances. Use the modified state rather than the base state. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 0fbd36f..05ad469 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -2756,6 +2756,37 @@ void btc_dpm_fini(struct radeon_device *rdev) r600_free_extended_power_table(rdev); } +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + seq_printf(m, "invalid dpm profile %d\n", current_index); + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + if (rdev->family >= CHIP_CEDAR) { + seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", + current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); + } else { + seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", + current_index, pl->sclk, pl->mclk, pl->vddc); + } + } +} + u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low) { struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h index 29e32de..9c65be2 100644 --- a/drivers/gpu/drm/radeon/btcd.h +++ b/drivers/gpu/drm/radeon/btcd.h @@ -44,6 +44,10 @@ # define DYN_SPREAD_SPECTRUM_EN (1 << 23) # define AC_DC_SW (1 << 24) +#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c +# define CURRENT_PROFILE_INDEX_MASK (0xf << 4) +# define CURRENT_PROFILE_INDEX_SHIFT 4 + #define CG_BIF_REQ_AND_RSP 0x7f4 #define CG_CLIENT_REQ(x) ((x) << 0) #define CG_CLIENT_REQ_MASK (0xff << 0) diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index c351226..22c3391 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -4322,7 +4322,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev, void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; struct ni_ps *ps = ni_get_ps(rps); struct rv7xx_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f74db43..dda02bf 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1555,7 +1555,7 @@ static struct radeon_asic btc_asic = { .get_sclk = &btc_dpm_get_sclk, .get_mclk = &btc_dpm_get_mclk, .print_power_state = &rv770_dpm_print_power_state, - .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, + .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv770_dpm_force_performance_level, .vblank_too_short = &btc_dpm_vblank_too_short, }, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index b3bc433..ae637cf 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -551,6 +551,8 @@ void btc_dpm_fini(struct radeon_device *rdev); u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low); u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low); bool btc_dpm_vblank_too_short(struct radeon_device *rdev); +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m); int sumo_dpm_init(struct radeon_device *rdev); int sumo_dpm_enable(struct radeon_device *rdev); int sumo_dpm_late_enable(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 0471501..eafb0e6 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -6472,7 +6472,8 @@ void si_dpm_fini(struct radeon_device *rdev) void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; struct ni_ps *ps = ni_get_ps(rps); struct rv7xx_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index f121efe..8b47b3cd 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1807,7 +1807,7 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev struct seq_file *m) { struct sumo_power_info *pi = sumo_get_pi(rdev); - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct radeon_ps *rps = &pi->current_rps; struct sumo_ps *ps = sumo_get_ps(rps); struct sumo_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 2d44719..2da0e17 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1926,7 +1926,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev, void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct trinity_power_info *pi = trinity_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; struct trinity_ps *ps = trinity_get_ps(rps); struct trinity_pl *pl; u32 current_index = -- cgit v0.10.2 From 299302294e109aec5e7f54ea61a9816c555c2106 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Jan 2014 13:11:47 -0500 Subject: drm/radeon/dpm: use stored max_vddc rather than looking it up When we parse the power tables use the stored mac_vddc value rather than lookig it up manually each time. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 22c3391..1217fbc 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -3945,7 +3945,6 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev, struct rv7xx_power_info *pi = rv770_get_pi(rdev); struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); struct ni_ps *ps = ni_get_ps(rps); - u16 vddc; struct rv7xx_pl *pl = &ps->performance_levels[index]; ps->performance_level_count = index + 1; @@ -3961,8 +3960,8 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev, /* patch up vddc if necessary */ if (pl->vddc == 0xff01) { - if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) - pl->vddc = vddc; + if (pi->max_vddc) + pl->vddc = pi->max_vddc; } if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 80c595a..5b2ea8a 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2174,7 +2174,6 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); struct rv7xx_ps *ps = rv770_get_ps(rps); u32 sclk, mclk; - u16 vddc; struct rv7xx_pl *pl; switch (index) { @@ -2214,8 +2213,8 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, /* patch up vddc if necessary */ if (pl->vddc == 0xff01) { - if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) - pl->vddc = vddc; + if (pi->max_vddc) + pl->vddc = pi->max_vddc; } if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { -- cgit v0.10.2 From 4dbffb8f21999c2156ddac00186810f1dfd9eb1a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 30 Jan 2014 14:06:05 -0500 Subject: drm/radeon: remove useless return Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index 824550d..d177100 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -57,7 +57,6 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev, radeon_ring_write(ring, 0); radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); radeon_ring_write(ring, 2); - return; } /** -- cgit v0.10.2 From 7c7e867cf0f74c4c79649605b964510041f1a8bf Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 30 Jan 2014 21:17:30 -0500 Subject: drm/radeon/dpm: fix uninitialized read from stack in kv_dpm_late_enable If we take the false branch of the if quoted in the diff below, we end up doing a return ret, without ever having initialized it. Picked up by coverity. Signed-off-by: Dave Jones Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index b6e01d5..351db36 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -1223,7 +1223,7 @@ int kv_dpm_enable(struct radeon_device *rdev) int kv_dpm_late_enable(struct radeon_device *rdev) { - int ret; + int ret = 0; if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { -- cgit v0.10.2 From d02f8575f1a38b3180a76a8ae0857dfde67f5ead Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 6 Feb 2014 14:22:21 -0500 Subject: drm/radeon: add missing include in btc_dpm.c Fixes a compile error with debugfs disabled. Signed-off-by: Alex Deucher diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 05ad469..ea103cc 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -29,6 +29,7 @@ #include "cypress_dpm.h" #include "btc_dpm.h" #include "atom.h" +#include #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b -- cgit v0.10.2 From 6ca605f7c70895a35737435f17ae9cc5e36f1466 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 16 Jan 2014 11:31:26 +0530 Subject: drm/exynos: Fix freeing issues in exynos_drm_drv.c Fixes the following errors: drivers/gpu/drm/exynos/exynos_drm_drv.c:182 exynos_drm_open() error: double free of 'file_priv' drivers/gpu/drm/exynos/exynos_drm_drv.c:188 exynos_drm_open() error: dereferencing freed memory 'file_priv' Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 9d096a0..215131a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -171,22 +171,24 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; ret = exynos_drm_subdrv_open(dev, file); - if (ret) { - kfree(file_priv); - file->driver_priv = NULL; - } + if (ret) + goto out; anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops, NULL, 0); if (IS_ERR(anon_filp)) { - kfree(file_priv); - return PTR_ERR(anon_filp); + ret = PTR_ERR(anon_filp); + goto out; } anon_filp->f_mode = FMODE_READ | FMODE_WRITE; file_priv->anon_filp = anon_filp; return ret; +out: + kfree(file_priv); + file->driver_priv = NULL; + return ret; } static void exynos_drm_preclose(struct drm_device *dev, -- cgit v0.10.2 From 86ac5b84efa87c3ed741dd73597f8c29bba53da2 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 16 Jan 2014 11:57:57 +0530 Subject: drm/exynos: Fix multiplatform breakage for ipp/gsc There is no need to include "plat/map-base.h" in ipp driver. Remove this and enable this driver for multi-platform. However gsc driver is not multiplatform compliant yet, so make the compilation conditional upon !ARCH_MULTIPLATFORM. Signed-off-by: Tushar Behera Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index f227f54..6e1a1a2 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -51,7 +51,7 @@ config DRM_EXYNOS_G2D config DRM_EXYNOS_IPP bool "Exynos DRM IPP" - depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM + depends on DRM_EXYNOS help Choose this option if you want to use IPP feature for DRM. @@ -69,6 +69,6 @@ config DRM_EXYNOS_ROTATOR config DRM_EXYNOS_GSC bool "Exynos DRM GSC" - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 + depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM help Choose this option if you want to use Exynos GSC for DRM. diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index d519a4e..eefb429 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include -- cgit v0.10.2 From 5cdbc8d993074ffda3d3be68935b8afe3ff96b9e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 16 Jan 2014 10:00:22 +0530 Subject: drm/exynos: Remove unnecessary semicolon Semicolon after a switch statement is not needed. Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 380aec2..6c1885e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -607,7 +607,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) reg_type = REG_TYPE_NONE; DRM_ERROR("Unknown register offset![%d]\n", reg_offset); break; - }; + } return reg_type; } -- cgit v0.10.2 From 4fe25b822bca31aa9bf97c1a56747443f0d7d239 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 16 Jan 2014 10:00:23 +0530 Subject: drm/exynos: Fix trivial typo Changed quf -> qbuf. Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index eefb429..09312b8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -825,7 +825,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e); /* - * quf == NULL condition means all event deletion. + * qbuf == NULL condition means all event deletion. * stop operations want to delete all event list. * another case delete only same buf id. */ -- cgit v0.10.2 From d34d59bda242cf97b90161ea5fe339f0daf0cc33 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 4 Feb 2014 08:40:18 +0530 Subject: drm/exynos: Convert to use the standard hdmi.h header Remove local definitions and use the ones provided by hdmi.h. Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a0e10ae..c021ddc 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -59,19 +60,6 @@ #define HDMI_AUI_VERSION 0x01 #define HDMI_AUI_LENGTH 0x0A -/* HDMI infoframe to configure HDMI out packet header, AUI and AVI */ -enum HDMI_PACKET_TYPE { - /* refer to Table 5-8 Packet Type in HDMI specification v1.4a */ - /* InfoFrame packet type */ - HDMI_PACKET_TYPE_INFOFRAME = 0x80, - /* Vendor-Specific InfoFrame */ - HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1, - /* Auxiliary Video information InfoFrame */ - HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2, - /* Audio information InfoFrame */ - HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4 -}; - enum hdmi_type { HDMI_TYPE13, HDMI_TYPE14, @@ -379,12 +367,6 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, }; -struct hdmi_infoframe { - enum HDMI_PACKET_TYPE type; - u8 ver; - u8 len; -}; - static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) { return readl(hdata->regs + reg_id); @@ -682,7 +664,7 @@ static u8 hdmi_chksum(struct hdmi_context *hdata, } static void hdmi_reg_infoframe(struct hdmi_context *hdata, - struct hdmi_infoframe *infoframe) + union hdmi_infoframe *infoframe) { u32 hdr_sum; u8 chksum; @@ -700,13 +682,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, return; } - switch (infoframe->type) { - case HDMI_PACKET_TYPE_AVI: + switch (infoframe->any.type) { + case HDMI_INFOFRAME_TYPE_AVI: hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->type); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, infoframe->ver); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->len); - hdr_sum = infoframe->type + infoframe->ver + infoframe->len; + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type); + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, + infoframe->any.version); + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length); + hdr_sum = infoframe->any.type + infoframe->any.version + + infoframe->any.length; /* Output format zero hardcoded ,RGB YBCR selection */ hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 | @@ -722,18 +706,20 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), - infoframe->len, hdr_sum); + infoframe->any.length, hdr_sum); DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum); hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum); break; - case HDMI_PACKET_TYPE_AUI: + case HDMI_INFOFRAME_TYPE_AUDIO: hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->type); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, infoframe->ver); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->len); - hdr_sum = infoframe->type + infoframe->ver + infoframe->len; + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type); + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, + infoframe->any.version); + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length); + hdr_sum = infoframe->any.type + infoframe->any.version + + infoframe->any.length; chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1), - infoframe->len, hdr_sum); + infoframe->any.length, hdr_sum); DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum); hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum); break; @@ -985,7 +971,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) static void hdmi_conf_init(struct hdmi_context *hdata) { - struct hdmi_infoframe infoframe; + union hdmi_infoframe infoframe; /* disable HPD interrupts from HDMI IP block, use GPIO instead */ hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | @@ -1021,14 +1007,14 @@ static void hdmi_conf_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02); hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04); } else { - infoframe.type = HDMI_PACKET_TYPE_AVI; - infoframe.ver = HDMI_AVI_VERSION; - infoframe.len = HDMI_AVI_LENGTH; + infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI; + infoframe.any.version = HDMI_AVI_VERSION; + infoframe.any.length = HDMI_AVI_LENGTH; hdmi_reg_infoframe(hdata, &infoframe); - infoframe.type = HDMI_PACKET_TYPE_AUI; - infoframe.ver = HDMI_AUI_VERSION; - infoframe.len = HDMI_AUI_LENGTH; + infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO; + infoframe.any.version = HDMI_AUI_VERSION; + infoframe.any.length = HDMI_AUI_LENGTH; hdmi_reg_infoframe(hdata, &infoframe); /* enable AVI packet every vsync, fixes purple line problem */ -- cgit v0.10.2 From c2703b13a63da335053a2f3cb560bb806bdda0ae Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 6 Feb 2014 19:19:20 -0500 Subject: drm/msm: bigger synchronization hammer Because we use a list_head in the bo to track it's position in a submit, we need to serialize at a higher layer. Otherwise there are problems when multiple contexts are SUBMIT'ing in parallel cmdstreams referencing a shared bo. Signed-off-by: Rob Clark diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 5281d4b..5423e91 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -163,7 +163,7 @@ retry: /* if locking succeeded, pin bo: */ - ret = msm_gem_get_iova(&msm_obj->base, + ret = msm_gem_get_iova_locked(&msm_obj->base, submit->gpu->id, &iova); /* this would break the logic in the fail path.. there is no @@ -247,7 +247,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob /* For now, just map the entire thing. Eventually we probably * to do it page-by-page, w/ kmap() if not vmap()d.. */ - ptr = msm_gem_vaddr(&obj->base); + ptr = msm_gem_vaddr_locked(&obj->base); if (IS_ERR(ptr)) { ret = PTR_ERR(ptr); @@ -307,14 +307,12 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool fail) { unsigned i; - mutex_lock(&submit->dev->struct_mutex); for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; submit_unlock_unpin_bo(submit, i); list_del_init(&msm_obj->submit_entry); drm_gem_object_unreference(&msm_obj->base); } - mutex_unlock(&submit->dev->struct_mutex); ww_acquire_fini(&submit->ticket); kfree(submit); @@ -342,6 +340,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (args->nr_cmds > MAX_CMDS) return -EINVAL; + mutex_lock(&dev->struct_mutex); + submit = submit_create(dev, gpu, args->nr_bos); if (!submit) { ret = -ENOMEM; @@ -410,5 +410,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: if (submit) submit_cleanup(submit, !!ret); + mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4ebce8b..0cfe3f4 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -298,8 +298,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_drm_private *priv = dev->dev_private; int i, ret; - mutex_lock(&dev->struct_mutex); - submit->fence = ++priv->next_fence; gpu->submitted_fence = submit->fence; @@ -331,7 +329,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } hangcheck_timer_reset(gpu); - mutex_unlock(&dev->struct_mutex); return ret; } -- cgit v0.10.2 From 4e6b788c3f2388c519ab6ed7fe59f372c85d26e9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Feb 2014 16:33:20 +0100 Subject: drm/i915: Disable dp aux irq on g4x Apparently it's broken in the exact same way as the gmbus irq. For reference of the full story see commit c12aba5aa0e60b7947bc8b6ea25ef55c4acf81a4 Author: Jiri Kosina Date: Tue Mar 19 09:56:57 2013 +0100 drm/i915: stop using GMBUS IRQs on Gen4 chips The effect is that we have a storm of unclaimed interrupts on the legacy irq line. If that one is used by a different device then the kernel will complain and rather quickly kill the irq source. Which breaks any device trying to actually use the legacy irq line. This regression has been introduced commit 4aeebd7443e36b0a40032e518a9338f48bd27efc Author: Daniel Vetter Date: Thu Oct 31 09:53:36 2013 +0100 drm/i915: dp aux irq support for g4x/vlv Note that disabling MSI works around the issue, but we can't do that since apparently then the hw will miss interrupts. At least if relevant comments in i915_irq.c are accurate. v2: Cross-reference dp aux and gmbus gen4 comments. v3: Consolidate harder into i915_drv.h as suggested by Chris. Cc: Jani Nikula Cc: Jiri Kosina Cc: Chris Wilson Reported-and-tested-by: Jiri Kosina Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9832205..c0cba20 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1831,6 +1831,14 @@ struct drm_i915_file_private { /* Early gen2 have a totally busted CS tlb and require pinned batches. */ #define HAS_BROKEN_CS_TLB(dev) (IS_I830(dev) || IS_845G(dev)) +/* + * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts + * even when in MSI mode. This results in spurious interrupt warnings if the + * legacy irq no. is shared with another device. The kernel then disables that + * interrupt source and so prevents the other device from working properly. + */ +#define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) +#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c00b6e3..2f517b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, int i, ret, recv_bytes; uint32_t status; int try, precharge, clock = 0; - bool has_aux_irq = true; + bool has_aux_irq = HAS_AUX_IRQ(dev); uint32_t timeout; /* dp aux is extremely sensitive to irq latency, hence request the diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index b1dc33f..d33b61d 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -258,13 +258,6 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) algo->data = bus; } -/* - * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI - * mode. This results in spurious interrupt warnings if the legacy irq no. is - * shared with another device. The kernel then disables that interrupt source - * and so prevents the other device from working properly. - */ -#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) static int gmbus_wait_hw_status(struct drm_i915_private *dev_priv, u32 gmbus2_status, -- cgit v0.10.2 From a2d213dd77da4710bcb75f8efe85a32e3db8b39b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 7 Feb 2014 16:34:05 +0100 Subject: drm/i915: Fix intel_pipe_to_cpu_transcoder for UMS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't have all the drm_crtc&co hanging around in that case. This regression has been introduced in commit 391f75e2bf13f105d9e4a120736ccdd8e3bc638b Author: Ville Syrjälä Date: Wed Sep 25 19:55:26 2013 +0300 drm/i915: Fix pre-CTG vblank counter Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=69521 Cc: stable@vger.kernel.org (for 3.13 only) Cc: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 17d8fcb..9fec711 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -567,8 +567,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; } else { - enum transcoder cpu_transcoder = - intel_pipe_to_cpu_transcoder(dev_priv, pipe); + enum transcoder cpu_transcoder = (enum transcoder) pipe; u32 htotal; htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; -- cgit v0.10.2 From 1d2cb9a54abc6e1d239f28f07661366d5662a94a Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 7 Feb 2014 17:40:50 +0200 Subject: drm/i915: Pair va_copy with va_end in i915_error_vprintf Each invocation of va_copy() must be matched by a corresponding invocation of va_end() in the same function. This regression has been introduced in commit e29bb4ebbf000ff9ac081d29784a3331618f012e Author: Chris Wilson Date: Fri Sep 20 10:20:59 2013 +0100 drm/i915: Use a temporary va_list for two-pass string handling Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d7fd2fd..990cf8f 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -146,7 +146,10 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, va_list tmp; va_copy(tmp, args); - if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp))) + len = vsnprintf(NULL, 0, f, tmp); + va_end(tmp); + + if (!__i915_error_seek(e, len)) return; } -- cgit v0.10.2