Commit ee7b9f93 authored by Jesse Barnes's avatar Jesse Barnes Committed by Daniel Vetter

drm/i915: manage PCH PLLs separately from pipes

PCH PLLs aren't required for outputs on the CPU, so we shouldn't just
treat them as part of the pipe.

So split the code out and manage PCH PLLs separately, allocating them
when needed or trying to re-use existing PCH PLL setups when the timings
match.

v2: add num_pch_pll field to dev_priv (Daniel)
    don't NULL the pch_pll pointer in disable or DPMS will fail (Jesse)
    put register offsets in pll struct (Chris)

v3: Decouple enable/disable of PLLs from get/put.
v4: Track temporary PLL disabling during modeset
v5: Tidy PLL initialisation by only checking for num_pch_pll == 0 (Eugeni)
v6: Avoid mishandling allocation failure by embedding the small array of
    PLLs into the device struct

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44309
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> (up to v2)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> (v3+)
Reviewed-by: default avatarEugeni Dodonov <eugeni.dodonov@intel.com>
Tested-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Reviewed-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent c2798b19
...@@ -377,18 +377,23 @@ void intel_detect_pch(struct drm_device *dev) ...@@ -377,18 +377,23 @@ void intel_detect_pch(struct drm_device *dev)
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_IBX; dev_priv->pch_type = PCH_IBX;
dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_CPT; dev_priv->pch_type = PCH_CPT;
dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found CougarPoint PCH\n"); DRM_DEBUG_KMS("Found CougarPoint PCH\n");
} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
/* PantherPoint is CPT compatible */ /* PantherPoint is CPT compatible */
dev_priv->pch_type = PCH_CPT; dev_priv->pch_type = PCH_CPT;
dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found PatherPoint PCH\n"); DRM_DEBUG_KMS("Found PatherPoint PCH\n");
} else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT; dev_priv->pch_type = PCH_LPT;
dev_priv->num_pch_pll = 0;
DRM_DEBUG_KMS("Found LynxPoint PCH\n"); DRM_DEBUG_KMS("Found LynxPoint PCH\n");
} }
BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
} }
pci_dev_put(pch); pci_dev_put(pch);
} }
......
...@@ -78,6 +78,16 @@ enum port { ...@@ -78,6 +78,16 @@ enum port {
#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
struct intel_pch_pll {
int refcount; /* count of number of CRTCs sharing this PLL */
int active; /* count of number of active CRTCs (i.e. DPMS on) */
bool on; /* is the PLL actually active? Disabled during modeset */
int pll_reg;
int fp0_reg;
int fp1_reg;
};
#define I915_NUM_PLLS 2
/* Interface history: /* Interface history:
* *
* 1.1: Original. * 1.1: Original.
...@@ -233,6 +243,7 @@ struct drm_i915_display_funcs { ...@@ -233,6 +243,7 @@ struct drm_i915_display_funcs {
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
int x, int y, int x, int y,
struct drm_framebuffer *old_fb); struct drm_framebuffer *old_fb);
void (*off)(struct drm_crtc *crtc);
void (*write_eld)(struct drm_connector *connector, void (*write_eld)(struct drm_connector *connector,
struct drm_crtc *crtc); struct drm_crtc *crtc);
void (*fdi_link_train)(struct drm_crtc *crtc); void (*fdi_link_train)(struct drm_crtc *crtc);
...@@ -391,6 +402,7 @@ typedef struct drm_i915_private { ...@@ -391,6 +402,7 @@ typedef struct drm_i915_private {
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe; int vblank_pipe;
int num_pipe; int num_pipe;
int num_pch_pll;
/* For hangcheck timer */ /* For hangcheck timer */
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
...@@ -753,6 +765,8 @@ typedef struct drm_i915_private { ...@@ -753,6 +765,8 @@ typedef struct drm_i915_private {
wait_queue_head_t pending_flip_queue; wait_queue_head_t pending_flip_queue;
bool flip_pending_is_done; bool flip_pending_is_done;
struct intel_pch_pll pch_plls[I915_NUM_PLLS];
/* Reclocking support */ /* Reclocking support */
bool render_reclock_avail; bool render_reclock_avail;
bool lvds_downclock_avail; bool lvds_downclock_avail;
......
...@@ -3402,15 +3402,15 @@ ...@@ -3402,15 +3402,15 @@
#define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_A 0xc6014
#define _PCH_DPLL_B 0xc6018 #define _PCH_DPLL_B 0xc6018
#define PCH_DPLL(pipe) (pipe == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
#define _PCH_FPA0 0xc6040 #define _PCH_FPA0 0xc6040
#define FP_CB_TUNE (0x3<<22) #define FP_CB_TUNE (0x3<<22)
#define _PCH_FPA1 0xc6044 #define _PCH_FPA1 0xc6044
#define _PCH_FPB0 0xc6048 #define _PCH_FPB0 0xc6048
#define _PCH_FPB1 0xc604c #define _PCH_FPB1 0xc604c
#define PCH_FP0(pipe) (pipe == 0 ? _PCH_FPA0 : _PCH_FPB0) #define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
#define PCH_FP1(pipe) (pipe == 0 ? _PCH_FPA1 : _PCH_FPB1) #define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
#define PCH_DPLL_TEST 0xc606c #define PCH_DPLL_TEST 0xc606c
......
...@@ -40,7 +40,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) ...@@ -40,7 +40,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
return false; return false;
if (HAS_PCH_SPLIT(dev)) if (HAS_PCH_SPLIT(dev))
dpll_reg = PCH_DPLL(pipe); dpll_reg = _PCH_DPLL(pipe);
else else
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
......
This diff is collapsed.
...@@ -2445,6 +2445,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -2445,6 +2445,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
} }
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
connector->interlace_allowed = true; connector->interlace_allowed = true;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
......
...@@ -179,8 +179,8 @@ struct intel_crtc { ...@@ -179,8 +179,8 @@ struct intel_crtc {
bool cursor_visible; bool cursor_visible;
unsigned int bpp; unsigned int bpp;
bool no_pll; /* tertiary pipe for IVB */ /* We can share PLLs across outputs if the timings match */
bool use_pll_a; struct intel_pch_pll *pch_pll;
}; };
struct intel_plane { struct intel_plane {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment