* [PATCH] drm/i915: Prevent timeline updates whilst performing reset
From: Chris Wilson @ 2016-12-19 14:56 UTC (permalink / raw)
To: intel-gfx; +Cc: drm-intel-fixes
As the fence may be signaled concurrently from an interrupt on another
device, it is possible for the list of requests on the timeline to be
modified as we walk it. Take both (the context's timeline and the global
timeline) locks to prevent such modifications.
Fixes: 80b204bce8f2 ("drm/i915: Enable multiple timelines")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: <drm-intel-fixes@lists.freedesktop.org>
---
drivers/gpu/drm/i915/i915_gem.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2d736442c6ab..d94df127d9f6 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2725,6 +2725,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
struct drm_i915_gem_request *request;
struct i915_gem_context *incomplete_ctx;
struct intel_timeline *timeline;
+ unsigned long flags;
bool ring_hung;
if (engine->irq_seqno_barrier)
@@ -2768,13 +2769,20 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
if (i915_gem_context_is_default(incomplete_ctx))
return;
+ timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine);
+
+ spin_lock_irqsave(&engine->timeline->lock, flags);
+ spin_lock(&timeline->lock);
+
list_for_each_entry_continue(request, &engine->timeline->requests, link)
if (request->ctx == incomplete_ctx)
reset_request(request);
- timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine);
list_for_each_entry(request, &timeline->requests, link)
reset_request(request);
+
+ spin_unlock(&timeline->lock);
+ spin_unlock_irqrestore(&engine->timeline->lock, flags);
}
void i915_gem_reset(struct drm_i915_private *dev_priv)
--
2.11.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* ✓ Fi.CI.BAT: success for series starting with [1/2] drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping
From: Patchwork @ 2016-12-19 14:45 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx
In-Reply-To: <20161219124346.550-1-chris@chris-wilson.co.uk>
== Series Details ==
Series: series starting with [1/2] drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping
URL : https://patchwork.freedesktop.org/series/16996/
State : success
== Summary ==
Series 16996v1 Series without cover letter
https://patchwork.freedesktop.org/api/1.0/series/16996/revisions/1/mbox/
fi-bdw-5557u total:247 pass:233 dwarn:0 dfail:0 fail:0 skip:14
fi-bsw-n3050 total:247 pass:208 dwarn:0 dfail:0 fail:0 skip:39
fi-bxt-j4205 total:247 pass:225 dwarn:1 dfail:0 fail:0 skip:21
fi-byt-j1900 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-n2820 total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-hsw-4770 total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-hsw-4770r total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-ilk-650 total:247 pass:195 dwarn:0 dfail:0 fail:0 skip:52
fi-ivb-3520m total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-ivb-3770 total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-kbl-7500u total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-skl-6260u total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-skl-6700hq total:247 pass:227 dwarn:0 dfail:0 fail:0 skip:20
fi-skl-6700k total:247 pass:224 dwarn:3 dfail:0 fail:0 skip:20
fi-skl-6770hq total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-snb-2520m total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-snb-2600 total:247 pass:215 dwarn:0 dfail:0 fail:0 skip:32
cda2d70a4395323bcf064c81ee0f89d2de015544 drm-tip: 2016y-12m-19d-13h-00m-10s UTC integration manifest
441ca15 drm/i915: Add a test that we terminate the trimmed sgtable as expected
db8fb5f drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping
== Logs ==
For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3329/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH] drm/i915/debugfs: use rb_entry()
From: Geliang Tang @ 2016-12-19 14:43 UTC (permalink / raw)
To: Daniel Vetter, Jani Nikula, David Airlie
Cc: Geliang Tang, intel-gfx, dri-devel, linux-kernel
To make the code clearer, use rb_entry() instead of container_of() to
deal with rbtree.
Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
drivers/gpu/drm/i915/i915_debugfs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index b77b53b..e04d9a1 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -686,7 +686,7 @@ static void i915_ring_seqno_info(struct seq_file *m,
spin_lock_irq(&b->lock);
for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
- struct intel_wait *w = container_of(rb, typeof(*w), node);
+ struct intel_wait *w = rb_entry(rb, typeof(*w), node);
seq_printf(m, "Waiting (%s): %s [%d] on %x\n",
engine->name, w->tsk->comm, w->tsk->pid, w->seqno);
@@ -1336,7 +1336,7 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
&dev_priv->gpu_error.missed_irq_rings)));
spin_lock_irq(&b->lock);
for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
- struct intel_wait *w = container_of(rb, typeof(*w), node);
+ struct intel_wait *w = rb_entry(rb, typeof(*w), node);
seq_printf(m, "\t%s [%d] waiting for %x\n",
w->tsk->comm, w->tsk->pid, w->seqno);
@@ -3252,7 +3252,7 @@ static int i915_engine_info(struct seq_file *m, void *unused)
spin_lock_irq(&b->lock);
for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
- struct intel_wait *w = container_of(rb, typeof(*w), node);
+ struct intel_wait *w = rb_entry(rb, typeof(*w), node);
seq_printf(m, "\t%s [%d] waiting for %x\n",
w->tsk->comm, w->tsk->pid, w->seqno);
--
2.9.3
^ permalink raw reply related
* Re: [PATCH 4/9] drm/i915/tdr: Add support for per engine reset recovery
From: Chris Wilson @ 2016-12-19 14:42 UTC (permalink / raw)
To: Mika Kuoppala; +Cc: intel-gfx
In-Reply-To: <87pokot2st.fsf@gaia.fi.intel.com>
On Mon, Dec 19, 2016 at 04:24:18PM +0200, Mika Kuoppala wrote:
> Chris Wilson <chris@chris-wilson.co.uk> writes:
>
> > On Fri, Dec 16, 2016 at 12:20:05PM -0800, Michel Thierry wrote:
> >> From: Arun Siluvery <arun.siluvery@linux.intel.com>
> >>
> >> This change implements support for per-engine reset as an initial, less
> >> intrusive hang recovery option to be attempted before falling back to the
> >> legacy full GPU reset recovery mode if necessary. This is only supported
> >> from Gen8 onwards.
> >>
> >> Hangchecker determines which engines are hung and invokes error handler to
> >> recover from it. Error handler schedules recovery for each of those engines
> >> that are hung. The recovery procedure is as follows,
> >> - identifies the request that caused the hang and it is dropped
> >> - force engine to idle: this is done by issuing a reset request
> >> - reset and re-init engine
> >> - restart submissions to the engine
> >>
> >> If engine reset fails then we fall back to heavy weight full gpu reset
> >> which resets all engines and reinitiazes complete state of HW and SW.
> >>
> >> v2: Rebase.
> >>
> >> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> >> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
> >> Signed-off-by: Tomas Elf <tomas.elf@intel.com>
> >> Signed-off-by: Arun Siluvery <arun.siluvery@linux.intel.com>
> >> Signed-off-by: Michel Thierry <michel.thierry@intel.com>
> >> ---
> >> drivers/gpu/drm/i915/i915_drv.c | 56 +++++++++++++++++++++++++++++++++++--
> >> drivers/gpu/drm/i915/i915_drv.h | 3 ++
> >> drivers/gpu/drm/i915/i915_gem.c | 2 +-
> >> drivers/gpu/drm/i915/intel_lrc.c | 12 ++++++++
> >> drivers/gpu/drm/i915/intel_lrc.h | 1 +
> >> drivers/gpu/drm/i915/intel_uncore.c | 41 ++++++++++++++++++++++++---
> >> 6 files changed, 108 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> >> index e5688edd62cd..a034793bc246 100644
> >> --- a/drivers/gpu/drm/i915/i915_drv.c
> >> +++ b/drivers/gpu/drm/i915/i915_drv.c
> >> @@ -1830,18 +1830,70 @@ void i915_reset(struct drm_i915_private *dev_priv)
> >> *
> >> * Reset a specific GPU engine. Useful if a hang is detected.
> >> * Returns zero on successful reset or otherwise an error code.
> >> + *
> >> + * Procedure is fairly simple:
> >> + * - identifies the request that caused the hang and it is dropped
> >> + * - force engine to idle: this is done by issuing a reset request
> >> + * - reset engine
> >> + * - restart submissions to the engine
> >> */
> >> int i915_reset_engine(struct intel_engine_cs *engine)
> >
> > What's the serialisation between potential callers of
> > i915_reset_engine()?
> >
>
> I feel that making 'reset_in_progress' per engine feature
> would clarify this and would be more fitting as now it is
> the one engine that can be in reset at particular point in time,
> decoupled with others.
That is not what "reset_in_progress" means. It principally means
MUTEX_BACKOFF.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH 4/9] drm/i915/tdr: Add support for per engine reset recovery
From: Mika Kuoppala @ 2016-12-19 14:24 UTC (permalink / raw)
To: Chris Wilson, Michel Thierry; +Cc: intel-gfx
In-Reply-To: <20161216204521.GG29871@nuc-i3427.alporthouse.com>
Chris Wilson <chris@chris-wilson.co.uk> writes:
> On Fri, Dec 16, 2016 at 12:20:05PM -0800, Michel Thierry wrote:
>> From: Arun Siluvery <arun.siluvery@linux.intel.com>
>>
>> This change implements support for per-engine reset as an initial, less
>> intrusive hang recovery option to be attempted before falling back to the
>> legacy full GPU reset recovery mode if necessary. This is only supported
>> from Gen8 onwards.
>>
>> Hangchecker determines which engines are hung and invokes error handler to
>> recover from it. Error handler schedules recovery for each of those engines
>> that are hung. The recovery procedure is as follows,
>> - identifies the request that caused the hang and it is dropped
>> - force engine to idle: this is done by issuing a reset request
>> - reset and re-init engine
>> - restart submissions to the engine
>>
>> If engine reset fails then we fall back to heavy weight full gpu reset
>> which resets all engines and reinitiazes complete state of HW and SW.
>>
>> v2: Rebase.
>>
>> Cc: Chris Wilson <chris@chris-wilson.co.uk>
>> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
>> Signed-off-by: Tomas Elf <tomas.elf@intel.com>
>> Signed-off-by: Arun Siluvery <arun.siluvery@linux.intel.com>
>> Signed-off-by: Michel Thierry <michel.thierry@intel.com>
>> ---
>> drivers/gpu/drm/i915/i915_drv.c | 56 +++++++++++++++++++++++++++++++++++--
>> drivers/gpu/drm/i915/i915_drv.h | 3 ++
>> drivers/gpu/drm/i915/i915_gem.c | 2 +-
>> drivers/gpu/drm/i915/intel_lrc.c | 12 ++++++++
>> drivers/gpu/drm/i915/intel_lrc.h | 1 +
>> drivers/gpu/drm/i915/intel_uncore.c | 41 ++++++++++++++++++++++++---
>> 6 files changed, 108 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
>> index e5688edd62cd..a034793bc246 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.c
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -1830,18 +1830,70 @@ void i915_reset(struct drm_i915_private *dev_priv)
>> *
>> * Reset a specific GPU engine. Useful if a hang is detected.
>> * Returns zero on successful reset or otherwise an error code.
>> + *
>> + * Procedure is fairly simple:
>> + * - identifies the request that caused the hang and it is dropped
>> + * - force engine to idle: this is done by issuing a reset request
>> + * - reset engine
>> + * - restart submissions to the engine
>> */
>> int i915_reset_engine(struct intel_engine_cs *engine)
>
> What's the serialisation between potential callers of
> i915_reset_engine()?
>
I feel that making 'reset_in_progress' per engine feature
would clarify this and would be more fitting as now it is
the one engine that can be in reset at particular point in time,
decoupled with others.
Having global 'reset_in_progress' and then a per engine
resets just doesn't feel right.
-Mika
>> {
>> int ret;
>> struct drm_i915_private *dev_priv = engine->i915;
>>
>> - /* FIXME: replace me with engine reset sequence */
>> - ret = -ENODEV;
>> + /*
>> + * We need to first idle the engine by issuing a reset request,
>> + * then perform soft reset and re-initialize hw state, for all of
>> + * this GT power need to be awake so ensure it does throughout the
>> + * process
>> + */
>> + intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
>> +
>> + /*
>> + * the request that caused the hang is stuck on elsp, identify the
>> + * active request and drop it, adjust head to skip the offending
>> + * request to resume executing remaining requests in the queue.
>> + */
>> + i915_gem_reset_engine(engine);
>
> Must freeze the engine and irqs first, before calling
> i915_gem_reset_engine() (i.e. something like disable_engines_irq,
> cancelling tasklet)
>
> Eeek note that the current i915_gem_reset_engine() is lacking a
> spinlock.
>
>> +
>> + ret = intel_engine_reset_begin(engine);
>> + if (ret) {
>> + DRM_ERROR("Failed to disable %s\n", engine->name);
>> + goto error;
>> + }
>> +
>> + ret = intel_gpu_reset(dev_priv, intel_engine_flag(engine));
>> + if (ret) {
>> + DRM_ERROR("Failed to reset %s, ret=%d\n", engine->name, ret);
>> + intel_engine_reset_cancel(engine);
>> + goto error;
>> + }
>> +
>> + ret = engine->init_hw(engine);
>> + if (ret)
>> + goto error;
>>
>> + intel_engine_reset_cancel(engine);
>> + intel_execlists_restart_submission(engine);
>
> engine->init_hw(engine) *is* intel_execlists_restart_submission.
>
>> +
>> + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
>> + return 0;
>> +
>> +error:
>> /* use full gpu reset to recover on error */
>> set_bit(I915_RESET_IN_PROGRESS, &dev_priv->gpu_error.flags);
>>
>> + /* Engine reset is performed without taking struct_mutex, since it
>> + * failed we now fallback to full gpu reset. Wakeup any waiters
>> + * which should now see the reset_in_progress and release
>> + * struct_mutex for us to continue recovery.
>> + */
>> + rcu_read_lock();
>> + intel_engine_wakeup(engine);
>> + rcu_read_unlock();
>> +
>> + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
>> return ret;
>> }
>
> --
> Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* ✗ Fi.CI.BAT: failure for drm/i915: Introduce intel_cdclk_state
From: Patchwork @ 2016-12-19 14:23 UTC (permalink / raw)
To: ville.syrjala; +Cc: intel-gfx
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
== Series Details ==
Series: drm/i915: Introduce intel_cdclk_state
URL : https://patchwork.freedesktop.org/series/16994/
State : failure
== Summary ==
Series 16994v1 drm/i915: Introduce intel_cdclk_state
https://patchwork.freedesktop.org/api/1.0/series/16994/revisions/1/mbox/
Test gem_exec_suspend:
Subgroup basic-s3:
pass -> DMESG-WARN (fi-bxt-j4205)
pass -> DMESG-WARN (fi-skl-6770hq)
Subgroup basic-s4-devices:
pass -> DMESG-WARN (fi-bxt-j4205)
pass -> DMESG-WARN (fi-skl-6770hq)
Test kms_busy:
Subgroup basic-flip-default-a:
pass -> DMESG-WARN (fi-bxt-j4205)
pass -> INCOMPLETE (fi-skl-6770hq)
Subgroup basic-flip-default-b:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-default-c:
pass -> DMESG-WARN (fi-bxt-j4205)
Test kms_cursor_legacy:
Subgroup basic-busy-flip-before-cursor-legacy:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-busy-flip-before-cursor-varying-size:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-after-cursor-legacy:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-after-cursor-varying-size:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-before-cursor-legacy:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-before-cursor-varying-size:
pass -> DMESG-WARN (fi-bxt-j4205)
Test kms_flip:
Subgroup basic-flip-vs-dpms:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-vs-modeset:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-flip-vs-wf_vblank:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-plain-flip:
pass -> DMESG-WARN (fi-bxt-j4205)
Test kms_frontbuffer_tracking:
Subgroup basic:
dmesg-warn -> DMESG-FAIL (fi-bxt-j4205)
Test kms_pipe_crc_basic:
Subgroup hang-read-crc-pipe-a:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup hang-read-crc-pipe-b:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup hang-read-crc-pipe-c:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-a:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-a-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-b:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-b-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-c:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup nonblocking-crc-pipe-c-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-a:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-a-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-b:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-b-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-c:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup read-crc-pipe-c-frame-sequence:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup suspend-read-crc-pipe-a:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup suspend-read-crc-pipe-b:
pass -> DMESG-FAIL (fi-bxt-j4205)
Subgroup suspend-read-crc-pipe-c:
pass -> DMESG-FAIL (fi-bxt-j4205)
Test pm_rpm:
Subgroup basic-pci-d3-state:
pass -> DMESG-WARN (fi-bxt-j4205)
Subgroup basic-rte:
pass -> DMESG-WARN (fi-bxt-j4205)
Test prime_vgem:
Subgroup basic-fence-flip:
pass -> DMESG-WARN (fi-bxt-j4205)
fi-bdw-5557u total:247 pass:233 dwarn:0 dfail:0 fail:0 skip:14
fi-bsw-n3050 total:247 pass:208 dwarn:0 dfail:0 fail:0 skip:39
fi-bxt-j4205 total:247 pass:189 dwarn:19 dfail:18 fail:0 skip:21
fi-bxt-t5700 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-j1900 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-n2820 total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-hsw-4770 total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-hsw-4770r total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-ilk-650 total:247 pass:195 dwarn:0 dfail:0 fail:0 skip:52
fi-ivb-3520m total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-ivb-3770 total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
WARNING: Long output truncated
cda2d70a4395323bcf064c81ee0f89d2de015544 drm-tip: 2016y-12m-19d-13h-00m-10s UTC integration manifest
7078934 drm/i915: Move ilk_pipe_pixel_rate() to intel_display.c
78d3a9e drm/i915: Replace the .modeset_commit_cdclk() hook with a more direct .set_cdclk() hook
53c86d0 drm/i915: Nuke the VLV/CHV PFI programming power domain workaround
654a8f2 drm/i915: Move PFI credit reprogramming into vlv/chv_set_cdclk()
fce72c3 drm/i915: Pass the cdclk state to the set_cdclk() functions
0664936a drm/i915: Pass dev_priv to remainder of the cdclk functions
ad20208 drm/i915: Track full cdclk state for the logical and actual cdclk frequencies
d671a54 drm/i915: Start moving the cdclk stuff into a distinct state structure
84f279e drm/i915: Pass computed vco to bxt_set_cdclk()
63fc02f drm/i915: Move most cdclk/rawclk related code to intel_cdclk.c
599e892 drm/i915: Clean up the .get_cdclk() assignment if ladder
9b9a25f drm/i915: s/get_display_clock_speed/get_cdclk/
75f08f7 drm/i915: Nuke intel_mode_max_pixclk()
6bbce65 drm/i915: Store the pipe pixel rate in the crtc state
== Logs ==
For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3328/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH] drm: parse hf-vsdb
From: Sharma, Shashank @ 2016-12-19 14:19 UTC (permalink / raw)
To: Thierry Reding; +Cc: airlied, intel-gfx, dri-devel, daniel.vetter
In-Reply-To: <20161205165936.GC21732@ulmo.ba.sec>
[-- Attachment #1.1: Type: text/plain, Size: 7608 bytes --]
Thanks for the review, Thierry. My comments inline.
Regards
Shashank
On 12/5/2016 10:29 PM, Thierry Reding wrote:
> On Tue, Nov 29, 2016 at 08:24:39PM +0530, Shashank Sharma wrote:
>> HDMI 2.0 / CEA-861-F specs define a new CEA extension data block,
>> called hdmi-forum vendor specific data block (HF-VSDB). This block
>> contains information about sink's support for HDMI 2.0 compliant
>> features. These features are:
>> - Deep color YUV 420 support and BPC
>> - 3D flags for
>> - OSD Displarity
>> - Dual view signaling
>> - independent view signaling
>> - SCDC support
>> - Max TMDS char rate
>> - Scrambling support
>>
>> This patch adds a parser function for this block, and add flags to
>> indicate support for new features, in drm_display_info structure.
>>
>> Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
>> ---
>> drivers/gpu/drm/drm_edid.c | 73 +++++++++++++++++++++++++++++++++++++++++++++
>> include/drm/drm_connector.h | 48 +++++++++++++++++++++++++++++
>> include/drm/drm_edid.h | 5 ++++
>> include/linux/hdmi.h | 1 +
>> 4 files changed, 127 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
>> index 336be31..b18bfe0 100644
>> --- a/drivers/gpu/drm/drm_edid.c
>> +++ b/drivers/gpu/drm/drm_edid.c
>> @@ -3223,6 +3223,27 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
>> return 0;
>> }
>>
>> +static bool cea_db_is_hf_vsdb(const u8 *db)
>> +{
>> + u8 len;
>> + int hfvsdb_id;
>> +
>> + if (cea_db_tag(db) != VENDOR_BLOCK)
>> + return false;
>> +
>> + len = cea_db_payload_len(db);
>> + if (len < 7 || len > 31)
> The second part of the check is unnecessary because there is no way that
> cea_db_payload_len() will return a number larger than 31.
Agree. Will remove this check.
>> + return false;
>> +
>> + /* version should be 1 */
>> + if (db[4] != 1)
> There's an extra space before !=.
Oh, I am surprised that checkpatch dint complaint. Will check this out.
> Also I'm not sure this is something
> that we need to worry about. Future versions of the HF VSDB are likely
> to be backwards compatible, so this seems like an unnecessary
> restriction.
Agree.
>
>> + return false;
>> +
>> + hfvsdb_id = db[1] | (db[2] << 8) | (db[3] << 16);
>> +
>> + return hfvsdb_id == HDMI_IEEE_OUI_HFVSDB;
>> +}
>> +
>> static bool cea_db_is_hdmi_vsdb(const u8 *db)
>> {
>> int hdmi_id;
>> @@ -3767,6 +3788,56 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
>> }
>> EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
>>
>> +static void drm_parse_yuv420_deep_color_info(struct drm_connector *connector,
>> + const u8 *db)
>> +{
>> + struct drm_display_info *info = &connector->display_info;
>> +
>> + if (db[7] & DRM_EDID_YUV420_DC_48)
>> + info->edid_yuv420_dc_modes |= DRM_EDID_YUV420_DC_48;
>> + if (db[7] & DRM_EDID_YUV420_DC_36)
>> + info->edid_yuv420_dc_modes |= DRM_EDID_YUV420_DC_36;
>> + if (db[7] & DRM_EDID_YUV420_DC_30)
>> + info->edid_yuv420_dc_modes |= DRM_EDID_YUV420_DC_30;
>> +
>> + if (!info->edid_yuv420_dc_modes) {
>> + DRM_DEBUG("%s: No YUV 420 deep color support in sink.\n",
>> + connector->name);
>> + return;
>> + }
>> +}
>> +
>> +static void
>> +drm_parse_hf_vsdb(struct drm_connector *connector, const u8 *db)
>> +{
>> + struct drm_display_info *info = &connector->display_info;
>> +
>> + if (db[5]) {
>> + /*
>> + * If the sink supplies max tmds char rate in db,
>> + * the actual max tmds rate = db[5] * 5Mhz.
>> + */
>> + info->max_tmds_clock = db[5] * 5000;
>> + DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
>> + info->max_tmds_clock);
>> + }
>> +
>> + if (db[6] & DRM_HFVSDB_SCDC_SUPPORT)
>> + info->scdc_supported = true;
>> + if (db[6] & DRM_HFVSDB_SCDC_RR_CAP)
>> + info->scdc_rr_cap = true;
>> + if (db[6] & DRM_HFVSDB_SCRAMBLING)
>> + info->scrambling = true;
>> + if (db[6] & DRM_HFVSDB_INDEPENDENT_VIEW)
>> + info->independent_view_3d = true;
>> + if (db[6] & DRM_HFVSDB_DUAL_VIEW)
>> + info->dual_view_3d = true;
>> + if (db[6] & DRM_HFVSDB_3D_OSD)
>> + info->osd_disparity_3d = true;
>> +
>> + drm_parse_yuv420_deep_color_info(connector, db);
>> +}
>> +
>> static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
>> const u8 *hdmi)
>> {
>> @@ -3881,6 +3952,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
>>
>> if (cea_db_is_hdmi_vsdb(db))
>> drm_parse_hdmi_vsdb_video(connector, db);
>> + if (cea_db_is_hf_vsdb(db))
>> + drm_parse_hf_vsdb(connector, db);
>> }
>> }
>>
>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> index 34f9741..d011dd5 100644
>> --- a/include/drm/drm_connector.h
>> +++ b/include/drm/drm_connector.h
>> @@ -167,6 +167,46 @@ struct drm_display_info {
>> */
>> u32 bus_flags;
>>
>> +#define DRM_HFVSDB_SCDC_SUPPORT (1<<7)
>> +#define DRM_HFVSDB_SCDC_RR_CAP (1<<6)
>> +#define DRM_HFVSDB_SCRAMBLING (1<<3)
>> +#define DRM_HFVSDB_INDEPENDENT_VIEW (1<<2)
>> +#define DRM_HFVSDB_DUAL_VIEW (1<<1)
>> +#define DRM_HFVSDB_3D_OSD (1<<0)
> This looks to me like the wrong place for these defines. They should
> probably go into include/drm/drm_edid.h instead.
I saw few other defines in this same structure, like
DRM_COLOR_FORMAT_RGB444 etc, so thought this would
be the right place.
>
>> +
>> + /**
>> + * @scdc_supported: Sink supports SCDC functionality.
>> + */
>> + bool scdc_supported;
>> +
>> + /**
>> + * @scdc_rr_cap: Sink has SCDC read request capability.
>> + */
>> + bool scdc_rr_cap;
>> +
>> + /**
>> + * @scrambling: Sync supports scrambling for <=340 Mcsc TMDS
>> + * char rates. Above 340 Mcsc rates, scrambling is always reqd.
>> + */
>> + bool scrambling;
>> +
>> + /**
>> + * @independent_view_3d: Sink supports 3d independent view signaling
>> + * in HF-VSIF.
>> + */
>> + bool independent_view_3d;
>> +
>> + /**
>> + * @dual_view_3d: Sink supports 3d dual view signaling in HF-VSIF.
>> + */
>> + bool dual_view_3d;
>> +
>> + /**
>> + * @osd_disparity_3d: Sink supports 3d osd disparity indication
>> + * in HF-VSIF.
>> + */
>> + bool osd_disparity_3d;
>> +
>> /**
>> * @max_tmds_clock: Maximum TMDS clock rate supported by the
>> * sink in kHz. 0 means undefined.
>> @@ -185,6 +225,14 @@ struct drm_display_info {
>> u8 edid_hdmi_dc_modes;
>>
>> /**
>> + * @edid_yuv420_dc_modes: bpc for deep color yuv420 encoding.
>> + * various sinks can support 10/12/16 bit per channel deep
>> + * color encoding. edid_yuv420_dc_modes = 0 means sink doesn't
>> + * support deep color yuv420 encoding.
>> + */
>> + u8 edid_yuv420_dc_modes;
> Why not store the additional formats in the edid_hdmi_dc_modes field?
Now, as per our discussion in mail thread, I will create nested
drm_hdmi_info within drm_display_info and add it there.
>
>> +
>> + /**
>> * @cea_rev: CEA revision of the HDMI sink.
>> */
>> u8 cea_rev;
>> diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
>> index 38eabf6..5df8b9c 100644
>> --- a/include/drm/drm_edid.h
>> +++ b/include/drm/drm_edid.h
>> @@ -212,6 +212,11 @@ struct detailed_timing {
>> #define DRM_EDID_HDMI_DC_30 (1 << 4)
>> #define DRM_EDID_HDMI_DC_Y444 (1 << 3)
>>
>> +/* YUV 420 deep color modes */
>> +#define DRM_EDID_YUV420_DC_48 (1 << 6)
>> +#define DRM_EDID_YUV420_DC_36 (1 << 5)
>> +#define DRM_EDID_YUV420_DC_30 (1 << 5)
> 36- and 30-bit depths have the same value. That probably wasn't
> intended.
Oops, thanks for pointing this out.
> Thierry
[-- Attachment #1.2: Type: text/html, Size: 46542 bytes --]
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: i915 regression in kernel 4.10
From: Juergen Gross @ 2016-12-19 14:16 UTC (permalink / raw)
To: Chris Wilson, Linux Kernel Mailing List, dri-devel, intel-gfx,
airlied, jani.nikula, daniel.vetter, Konrad Rzeszutek Wilk,
Boris Ostrovsky
In-Reply-To: <20161219122934.GM29871@nuc-i3427.alporthouse.com>
On 19/12/16 13:29, Chris Wilson wrote:
> On Mon, Dec 19, 2016 at 12:39:16PM +0100, Juergen Gross wrote:
>> With recent 4.10 kernel the graphics isn't coming up under Xen. First
>> failure message is:
>>
>> [ 46.656649] i915 0000:00:02.0: swiotlb buffer is full (sz: 1630208 bytes)
>
> Do we get a silent failure? i915_gem_gtt_prepare_pages() is where we
> call dma_map_sg() and pass the sg to swiotlb (in this case) for
> remapping, and we do check for an error value of 0. After that error,
> SWIOTLB_MAP_ERROR is propagated back and converted to 0 for
> dma_map_sg(). That looks valid, and we should report ENOMEM back to the
> caller.
>
>> Later I see splats like:
>>
>> [ 49.393583] general protection fault: 0000 [#1] SMP
>
> What was the faulting address? RAX is particularly non-pointer-like so I
> wonder if we walked onto an uninitialised portion of the sgtable. We may
> have tripped over a bug in our sg_page iterator.
During the bisect process there have been either GP or NULL pointer
dereferences or other page faults. Typical addresses where:
xen_swiotlb_unmap_sg_attrs+0x1f/0x50: access to 0000000000000018
xen_swiotlb_unmap_sg_attrs+0x1f/0x50: access to 0000000003020118
>
> The attached patch should prevent an early ENOMEM following the swiotlb
> allocation failure. But I suspect that we will still be tripping up the
> failure in the sg walker when binding to the GPU.
> -Chris
>
The patch is working not too bad. :-)
Still several "swiotlb buffer is full" messages (some with sz:, most
without), but no faults any more (neither GP nor NULL pointer
dereference). Graphical login is working now.
What I do see, however, is (no idea whether this is related):
[ 735.826492] INFO: task systemd-udevd:484 blocked for more than 120
seconds.
[ 735.826497] Tainted: G W 4.9.0-pv+ #767
[ 735.826499] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs"
disables this message.
[ 735.826501] systemd-udevd D 0 484 443 0x00000000
[ 735.826507] Call Trace:
[ 735.826522] ? __schedule+0x192/0x640
[ 735.826530] ? kmem_cache_free+0x45/0x150
[ 735.826535] ? schedule+0x2d/0x80
[ 735.826539] ? schedule_timeout+0x1f3/0x380
[ 735.826545] ? error_exit+0x9/0x20
[ 735.826555] ? sg_pool_index.part.0+0x2/0x2
[ 735.826561] ? wait_for_completion+0xa4/0x110
[ 735.826569] ? wake_up_q+0x70/0x70
[ 735.826577] ? cpufreq_boost_online+0x10/0x10 [acpi_cpufreq]
[ 735.826585] ? cpuhp_issue_call+0x9c/0xe0
[ 735.826590] ? __cpuhp_setup_state+0xd5/0x1d0
[ 735.826599] ? acpi_cpufreq_init+0x1cd/0x1000 [acpi_cpufreq]
[ 735.826601] ? 0xffffffffa00b1000
[ 735.826607] ? do_one_initcall+0x38/0x180
[ 735.826611] ? kmem_cache_alloc_trace+0x98/0x1e0
[ 735.826620] ? do_init_module+0x55/0x1e5
[ 735.826629] ? load_module+0x2088/0x26b0
[ 735.826633] ? __symbol_put+0x30/0x30
[ 735.826639] ? SYSC_finit_module+0x80/0xb0
[ 735.826644] ? entry_SYSCALL_64_fastpath+0x1e/0xad
I guess it is _not_ related, OTOH there is sg_pool_index() involved...
Juergen
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH 3/3] drm/i915/glk: Convert a few more IS_BROXTON() to IS_GEN9_LP()
From: Tomasz Lis @ 2016-12-19 13:17 UTC (permalink / raw)
To: Ander Conselvan de Oliveira, intel-gfx; +Cc: Daniel Vetter, Rodrigo Vivi
In-Reply-To: <1481902946-18593-3-git-send-email-ander.conselvan.de.oliveira@intel.com>
W dniu 2016-12-16 o 16:42, Ander Conselvan de Oliveira pisze:
> From: Michel Thierry <michel.thierry@intel.com>
>
> Commit 89b3c3c7ee9d ("drm/i915/glk: Reuse broxton's cdclk code for GLK")
> missed a few of occurences of IS_BROXTON() that should have been
> coverted to IS_GEN9_LP().
>
> Fixes: 89b3c3c7ee9d ("drm/i915/glk: Reuse broxton's cdclk code for GLK")
> Cc: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: intel-gfx@lists.freedesktop.org
Checked each change, everything OK.
Reviewed-by: Tomasz Lis <tomasz.lis@intel.com>
> Signed-off-by: Michel Thierry <michel.thierry@intel.com>
> Signed-off-by: Tomasz Lis <tomasz.lis@intel.com>
> Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
> ---
> drivers/gpu/drm/i915/i915_sysfs.c | 2 +-
> drivers/gpu/drm/i915/intel_device_info.c | 2 +-
> drivers/gpu/drm/i915/intel_dp.c | 2 +-
> drivers/gpu/drm/i915/intel_guc_loader.c | 4 ++--
> 4 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
> index 40c0ac7..376ac95 100644
> --- a/drivers/gpu/drm/i915/i915_sysfs.c
> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
> @@ -58,7 +58,7 @@ static u32 calc_residency(struct drm_i915_private *dev_priv,
>
> if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
> units <<= 8;
> - } else if (IS_BROXTON(dev_priv)) {
> + } else if (IS_GEN9_LP(dev_priv)) {
> units = 1;
> div = 1200; /* 833.33ns */
> }
> diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
> index c46415b..6aeb1ed 100644
> --- a/drivers/gpu/drm/i915/intel_device_info.c
> +++ b/drivers/gpu/drm/i915/intel_device_info.c
> @@ -192,7 +192,7 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
> (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
> hweight8(sseu->slice_mask) > 1;
> sseu->has_subslice_pg =
> - IS_BROXTON(dev_priv) && sseu_subslice_total(sseu) > 1;
> + IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1;
> sseu->has_eu_pg = sseu->eu_per_subslice > 2;
>
> if (IS_BROXTON(dev_priv)) {
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 45ebc96..ae08c19 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -3375,7 +3375,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp)
> if (HAS_DDI(dev_priv)) {
> signal_levels = ddi_signal_levels(intel_dp);
>
> - if (IS_BROXTON(dev_priv))
> + if (IS_GEN9_LP(dev_priv))
> signal_levels = 0;
> else
> mask = DDI_BUF_EMP_MASK;
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index 21db697..8b74525 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -339,7 +339,7 @@ static u32 guc_wopcm_size(struct drm_i915_private *dev_priv)
> u32 wopcm_size = GUC_WOPCM_TOP;
>
> /* On BXT, the top of WOPCM is reserved for RC6 context */
> - if (IS_BROXTON(dev_priv))
> + if (IS_GEN9_LP(dev_priv))
> wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED;
>
> return wopcm_size;
> @@ -388,7 +388,7 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
> if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
> I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
>
> - if (IS_BROXTON(dev_priv))
> + if (IS_GEN9_LP(dev_priv))
> I915_WRITE(GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
> else
> I915_WRITE(GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* ✓ Fi.CI.BAT: success for i915 regression in kernel 4.10 (rev2)
From: Patchwork @ 2016-12-19 13:16 UTC (permalink / raw)
To: Chris Wilson; +Cc: intel-gfx
In-Reply-To: <7abf8559-3aa7-af3a-8dc1-1dee42019fcd@suse.com>
== Series Details ==
Series: i915 regression in kernel 4.10 (rev2)
URL : https://patchwork.freedesktop.org/series/16990/
State : success
== Summary ==
Series 16990v2 i915 regression in kernel 4.10
https://patchwork.freedesktop.org/api/1.0/series/16990/revisions/2/mbox/
Test gem_sync:
Subgroup basic-store-all:
fail -> PASS (fi-ivb-3520m)
fi-bdw-5557u total:247 pass:233 dwarn:0 dfail:0 fail:0 skip:14
fi-bsw-n3050 total:247 pass:208 dwarn:0 dfail:0 fail:0 skip:39
fi-bxt-j4205 total:247 pass:225 dwarn:1 dfail:0 fail:0 skip:21
fi-bxt-t5700 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-j1900 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-n2820 total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-hsw-4770 total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-hsw-4770r total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-ilk-650 total:247 pass:195 dwarn:0 dfail:0 fail:0 skip:52
fi-ivb-3520m total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-ivb-3770 total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-kbl-7500u total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-skl-6260u total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-skl-6700hq total:247 pass:227 dwarn:0 dfail:0 fail:0 skip:20
fi-skl-6700k total:247 pass:224 dwarn:3 dfail:0 fail:0 skip:20
fi-skl-6770hq total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-snb-2520m total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-snb-2600 total:247 pass:215 dwarn:0 dfail:0 fail:0 skip:32
0f918489ce78af8bc606c24b62d12dc869fb8844 drm-tip: 2016y-12m-19d-11h-45m-08s UTC integration manifest
e4b1b56 i915 regression in kernel 4.10
== Logs ==
For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3327/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v2] drm/i915: Prevent PPS stealing from a normal DP port on VLV/CHV
From: Ville Syrjälä @ 2016-12-19 13:01 UTC (permalink / raw)
To: intel-gfx; +Cc: stable
In-Reply-To: <1481738423-29738-1-git-send-email-ville.syrjala@linux.intel.com>
On Wed, Dec 14, 2016 at 08:00:23PM +0200, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> VLV apparently gets upset if the PPS for a pipe currently driving an
> external DP port gets used for VDD stuff on another eDP port. The DP
> port falls over and fails to retrain when this happens, leaving the
> user staring at a black screen.
>
> Let's fix it by also tracking which pipe is driving which DP/eDP port.
> We'll track this under intel_dp so that we'll share the protection
> of the pps_mutex alongside the pps_pipe tracking, since the two
> things are intimately related.
>
> I had plans to reduce the protection of pps_mutex to cover only eDP
> ports, but with this we can't do that. Well, for for VLV/CHV at least.
> For other platforms it should still be possible, which would allow
> AUX communication to occur in parallel for multiple DP ports.
>
> v2: Drop stray crap from a comment (Imre)
> Grab pps_mutex when clearing active_pipe
> Fix a typo in the commit message
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Reviewed-by: Imre Deak <imre.deak@intel.com>
Pushed to dinq. Thanks for the review.
I did notice that I had neglected to make vlv_active_pipe() static,
but I just fixed that up while applying the patch.
> ---
> drivers/gpu/drm/i915/intel_dp.c | 152 +++++++++++++++++++++++++++------------
> drivers/gpu/drm/i915/intel_drv.h | 6 ++
> 2 files changed, 111 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index db75bb924e48..fe830e3736cf 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -454,14 +454,50 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
> }
> }
>
> +static enum pipe vlv_find_free_pps(struct drm_i915_private *dev_priv)
> +{
> + struct intel_encoder *encoder;
> + unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
> +
> + /*
> + * We don't have power sequencer currently.
> + * Pick one that's not used by other ports.
> + */
> + for_each_intel_encoder(&dev_priv->drm, encoder) {
> + struct intel_dp *intel_dp;
> +
> + if (encoder->type != INTEL_OUTPUT_DP &&
> + encoder->type != INTEL_OUTPUT_EDP)
> + continue;
> +
> + intel_dp = enc_to_intel_dp(&encoder->base);
> +
> + if (encoder->type == INTEL_OUTPUT_EDP) {
> + WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
> + intel_dp->active_pipe != intel_dp->pps_pipe);
> +
> + if (intel_dp->pps_pipe != INVALID_PIPE)
> + pipes &= ~(1 << intel_dp->pps_pipe);
> + } else {
> + WARN_ON(intel_dp->pps_pipe != INVALID_PIPE);
> +
> + if (intel_dp->active_pipe != INVALID_PIPE)
> + pipes &= ~(1 << intel_dp->active_pipe);
> + }
> + }
> +
> + if (pipes == 0)
> + return INVALID_PIPE;
> +
> + return ffs(pipes) - 1;
> +}
> +
> static enum pipe
> vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
> {
> struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> struct drm_device *dev = intel_dig_port->base.base.dev;
> struct drm_i915_private *dev_priv = to_i915(dev);
> - struct intel_encoder *encoder;
> - unsigned int pipes = (1 << PIPE_A) | (1 << PIPE_B);
> enum pipe pipe;
>
> lockdep_assert_held(&dev_priv->pps_mutex);
> @@ -469,33 +505,20 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp)
> /* We should never land here with regular DP ports */
> WARN_ON(!is_edp(intel_dp));
>
> + WARN_ON(intel_dp->active_pipe != INVALID_PIPE &&
> + intel_dp->active_pipe != intel_dp->pps_pipe);
> +
> if (intel_dp->pps_pipe != INVALID_PIPE)
> return intel_dp->pps_pipe;
>
> - /*
> - * We don't have power sequencer currently.
> - * Pick one that's not used by other ports.
> - */
> - for_each_intel_encoder(dev, encoder) {
> - struct intel_dp *tmp;
> -
> - if (encoder->type != INTEL_OUTPUT_EDP)
> - continue;
> -
> - tmp = enc_to_intel_dp(&encoder->base);
> -
> - if (tmp->pps_pipe != INVALID_PIPE)
> - pipes &= ~(1 << tmp->pps_pipe);
> - }
> + pipe = vlv_find_free_pps(dev_priv);
>
> /*
> * Didn't find one. This should not happen since there
> * are two power sequencers and up to two eDP ports.
> */
> - if (WARN_ON(pipes == 0))
> + if (WARN_ON(pipe == INVALID_PIPE))
> pipe = PIPE_A;
> - else
> - pipe = ffs(pipes) - 1;
>
> vlv_steal_power_sequencer(dev, pipe);
> intel_dp->pps_pipe = pipe;
> @@ -651,10 +674,17 @@ void intel_power_sequencer_reset(struct drm_i915_private *dev_priv)
> for_each_intel_encoder(dev, encoder) {
> struct intel_dp *intel_dp;
>
> - if (encoder->type != INTEL_OUTPUT_EDP)
> + if (encoder->type != INTEL_OUTPUT_DP &&
> + encoder->type != INTEL_OUTPUT_EDP)
> continue;
>
> intel_dp = enc_to_intel_dp(&encoder->base);
> +
> + WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
> +
> + if (encoder->type != INTEL_OUTPUT_EDP)
> + continue;
> +
> if (IS_GEN9_LP(dev_priv))
> intel_dp->pps_reset = true;
> else
> @@ -2814,6 +2844,8 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
> enum pipe pipe = intel_dp->pps_pipe;
> i915_reg_t pp_on_reg = PP_ON_DELAYS(pipe);
>
> + WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
> +
> edp_panel_vdd_off_sync(intel_dp);
>
> /*
> @@ -2848,22 +2880,23 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
> struct intel_dp *intel_dp;
> enum port port;
>
> - if (encoder->type != INTEL_OUTPUT_EDP)
> + if (encoder->type != INTEL_OUTPUT_DP &&
> + encoder->type != INTEL_OUTPUT_EDP)
> continue;
>
> intel_dp = enc_to_intel_dp(&encoder->base);
> port = dp_to_dig_port(intel_dp)->port;
>
> + WARN(intel_dp->active_pipe == pipe,
> + "stealing pipe %c power sequencer from active (e)DP port %c\n",
> + pipe_name(pipe), port_name(port));
> +
> if (intel_dp->pps_pipe != pipe)
> continue;
>
> DRM_DEBUG_KMS("stealing pipe %c power sequencer from port %c\n",
> pipe_name(pipe), port_name(port));
>
> - WARN(encoder->base.crtc,
> - "stealing pipe %c power sequencer from active eDP port %c\n",
> - pipe_name(pipe), port_name(port));
> -
> /* make sure vdd is off before we steal it */
> vlv_detach_power_sequencer(intel_dp);
> }
> @@ -2879,19 +2912,17 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
>
> lockdep_assert_held(&dev_priv->pps_mutex);
>
> - if (!is_edp(intel_dp))
> - return;
> + WARN_ON(intel_dp->active_pipe != INVALID_PIPE);
>
> - if (intel_dp->pps_pipe == crtc->pipe)
> - return;
> -
> - /*
> - * If another power sequencer was being used on this
> - * port previously make sure to turn off vdd there while
> - * we still have control of it.
> - */
> - if (intel_dp->pps_pipe != INVALID_PIPE)
> + if (intel_dp->pps_pipe != INVALID_PIPE &&
> + intel_dp->pps_pipe != crtc->pipe) {
> + /*
> + * If another power sequencer was being used on this
> + * port previously make sure to turn off vdd there while
> + * we still have control of it.
> + */
> vlv_detach_power_sequencer(intel_dp);
> + }
>
> /*
> * We may be stealing the power
> @@ -2899,6 +2930,11 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
> */
> vlv_steal_power_sequencer(dev, crtc->pipe);
>
> + intel_dp->active_pipe = crtc->pipe;
> +
> + if (!is_edp(intel_dp))
> + return;
> +
> /* now it's all ours */
> intel_dp->pps_pipe = crtc->pipe;
>
> @@ -3485,6 +3521,12 @@ intel_dp_link_down(struct intel_dp *intel_dp)
> msleep(intel_dp->panel_power_down_delay);
>
> intel_dp->DP = DP;
> +
> + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> + pps_lock(intel_dp);
> + intel_dp->active_pipe = INVALID_PIPE;
> + pps_unlock(intel_dp);
> + }
> }
>
> bool
> @@ -4750,6 +4792,19 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
> edp_panel_vdd_schedule_off(intel_dp);
> }
>
> +enum pipe vlv_active_pipe(struct intel_dp *intel_dp)
> +{
> + struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
> +
> + if ((intel_dp->DP & DP_PORT_EN) == 0)
> + return INVALID_PIPE;
> +
> + if (IS_CHERRYVIEW(dev_priv))
> + return DP_PORT_TO_PIPE_CHV(intel_dp->DP);
> + else
> + return PORT_TO_PIPE(intel_dp->DP);
> +}
> +
> void intel_dp_encoder_reset(struct drm_encoder *encoder)
> {
> struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> @@ -4762,14 +4817,16 @@ void intel_dp_encoder_reset(struct drm_encoder *encoder)
> if (lspcon->active)
> lspcon_resume(lspcon);
>
> - if (to_intel_encoder(encoder)->type != INTEL_OUTPUT_EDP)
> - return;
> -
> pps_lock(intel_dp);
>
> - /* Reinit the power sequencer, in case BIOS did something with it. */
> - intel_dp_pps_init(encoder->dev, intel_dp);
> - intel_edp_panel_vdd_sanitize(intel_dp);
> + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> + intel_dp->active_pipe = vlv_active_pipe(intel_dp);
> +
> + if (is_edp(intel_dp)) {
> + /* Reinit the power sequencer, in case BIOS did something with it. */
> + intel_dp_pps_init(encoder->dev, intel_dp);
> + intel_edp_panel_vdd_sanitize(intel_dp);
> + }
>
> pps_unlock(intel_dp);
> }
> @@ -5596,10 +5653,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
> * If the current pipe isn't valid, try the PPS pipe, and if that
> * fails just assume pipe A.
> */
> - if (IS_CHERRYVIEW(dev_priv))
> - pipe = DP_PORT_TO_PIPE_CHV(intel_dp->DP);
> - else
> - pipe = PORT_TO_PIPE(intel_dp->DP);
> + pipe = vlv_active_pipe(intel_dp);
>
> if (pipe != PIPE_A && pipe != PIPE_B)
> pipe = intel_dp->pps_pipe;
> @@ -5648,6 +5702,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> return false;
>
> intel_dp->pps_pipe = INVALID_PIPE;
> + intel_dp->active_pipe = INVALID_PIPE;
>
> /* intel_dp vfuncs */
> if (INTEL_GEN(dev_priv) >= 9)
> @@ -5676,6 +5731,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> else
> type = DRM_MODE_CONNECTOR_DisplayPort;
>
> + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> + intel_dp->active_pipe = vlv_active_pipe(intel_dp);
> +
> /*
> * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
> * for DP the encoder type can be set by the caller to
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 8f4ddca0f521..85b39d3a6dff 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -929,6 +929,12 @@ struct intel_dp {
> */
> enum pipe pps_pipe;
> /*
> + * Pipe currently driving the port. Used for preventing
> + * the use of the PPS for any pipe currentrly driving
> + * external DP as that will mess things up on VLV.
> + */
> + enum pipe active_pipe;
> + /*
> * Set if the sequencer may be reset due to a power transition,
> * requiring a reinitialization. Only relevant on BXT.
> */
> --
> 2.7.4
--
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH v3 01/38] drm/i915: Use the MRU stack search after evicting
From: Chris Wilson @ 2016-12-19 12:55 UTC (permalink / raw)
To: dri-devel; +Cc: intel-gfx
In-Reply-To: <20161216192550.8352-2-chris@chris-wilson.co.uk>
On Fri, Dec 16, 2016 at 07:25:13PM +0000, Chris Wilson wrote:
> When we evict from the GTT to make room for an object, the hole we
> create is put onto the MRU stack inside the drm_mm range manager. On the
> next search pass, we can speed up a PIN_HIGH allocation by referencing
> that stack for the new hole.
>
> v2: Pull together the 3 identical implements (ahem, a couple were
> outdated) into a common routine for allocating a node and evicting as
> necessary.
On noes, I realized that I have used the correct spelling of colour.
Needs a s/colour/color/ for consistency.
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* ✗ Fi.CI.BAT: warning for Introduce drmfs pseudo filesystem for drm subsystem (rev4)
From: Patchwork @ 2016-12-19 12:53 UTC (permalink / raw)
To: swati.dhingra; +Cc: intel-gfx
In-Reply-To: <1482144146-31605-1-git-send-email-swati.dhingra@intel.com>
== Series Details ==
Series: Introduce drmfs pseudo filesystem for drm subsystem (rev4)
URL : https://patchwork.freedesktop.org/series/16203/
State : warning
== Summary ==
Series 16203v4 Introduce drmfs pseudo filesystem for drm subsystem
https://patchwork.freedesktop.org/api/1.0/series/16203/revisions/4/mbox/
Test gem_sync:
Subgroup basic-store-all:
fail -> PASS (fi-ivb-3520m)
Test kms_force_connector_basic:
Subgroup force-load-detect:
pass -> DMESG-WARN (fi-snb-2520m)
fi-bdw-5557u total:247 pass:233 dwarn:0 dfail:0 fail:0 skip:14
fi-bsw-n3050 total:247 pass:208 dwarn:0 dfail:0 fail:0 skip:39
fi-bxt-j4205 total:247 pass:225 dwarn:1 dfail:0 fail:0 skip:21
fi-bxt-t5700 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-j1900 total:247 pass:220 dwarn:0 dfail:0 fail:0 skip:27
fi-byt-n2820 total:247 pass:216 dwarn:0 dfail:0 fail:0 skip:31
fi-hsw-4770 total:247 pass:228 dwarn:0 dfail:0 fail:0 skip:19
fi-ilk-650 total:247 pass:195 dwarn:0 dfail:0 fail:0 skip:52
fi-ivb-3520m total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-ivb-3770 total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-kbl-7500u total:247 pass:226 dwarn:0 dfail:0 fail:0 skip:21
fi-skl-6260u total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-skl-6700hq total:247 pass:227 dwarn:0 dfail:0 fail:0 skip:20
fi-skl-6700k total:247 pass:224 dwarn:3 dfail:0 fail:0 skip:20
fi-skl-6770hq total:247 pass:234 dwarn:0 dfail:0 fail:0 skip:13
fi-snb-2520m total:247 pass:215 dwarn:1 dfail:0 fail:0 skip:31
fi-snb-2600 total:247 pass:215 dwarn:0 dfail:0 fail:0 skip:32
0f918489ce78af8bc606c24b62d12dc869fb8844 drm-tip: 2016y-12m-19d-11h-45m-08s UTC integration manifest
1a09aad drm/i915: Creating guc log file in drmfs instead of debugfs
dd3f5ba drm: Create driver specific root directory inside drmfs
bb8d42c drm: Register drmfs filesystem from drm init
c468cc0 drm: Introduce drmfs pseudo filesystem interfaces
== Logs ==
For more details see: https://intel-gfx-ci.01.org/CI/Patchwork_3326/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH 2/2] drm/i915: Add a test that we terminate the trimmed sgtable as expected
From: Chris Wilson @ 2016-12-19 12:43 UTC (permalink / raw)
To: intel-gfx
In-Reply-To: <20161219124346.550-1-chris@chris-wilson.co.uk>
In commit 0c40ce130e38 ("drm/i915: Trim the object sg table"), we expect
to copy exactly orig_st->nents across and allocate the table thusly.
The copy loop should therefore end with the new_sg being NULL.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
drivers/gpu/drm/i915/i915_gem.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4e263df2afc3..0a82cce5f731 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2316,6 +2316,7 @@ static void i915_sg_trim(struct sg_table *orig_st)
/* called before being DMA mapped, no need to copy sg->dma_* */
new_sg = sg_next(new_sg);
}
+ GEM_BUG_ON(new_sg); /* Should walk exactly nents and hit the end */
sg_free_table(orig_st);
--
2.11.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 1/2] drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping
From: Chris Wilson @ 2016-12-19 12:43 UTC (permalink / raw)
To: intel-gfx; +Cc: drm-intel-fixes
If we at first do not succeed with attempting to remap our physical
pages using a coalesced scattergather list, try again with one
scattergather entry per page. This should help with swiotlb as it uses a
limited buffer size and only searches for contiguous chunks within its
buffer aligned up to the next boundary - i.e. we may prematurely cause a
failure as we are unable to utilize the unused space between large
chunks and trigger an error such as:
i915 0000:00:02.0: swiotlb buffer is full (sz: 1630208 bytes)
Reported-by: Juergen Gross <jgross@suse.com>
Fixes: 871dfbd67d4e ("drm/i915: Allow compaction upto SWIOTLB max segment size")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Cc: <drm-intel-fixes@lists.freedesktop.org>
---
drivers/gpu/drm/i915/i915_gem.c | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 412f3513f269..4e263df2afc3 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2326,7 +2326,8 @@ static struct sg_table *
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
- int page_count, i;
+ const unsigned long page_count = obj->base.size / PAGE_SIZE;
+ unsigned long i;
struct address_space *mapping;
struct sg_table *st;
struct scatterlist *sg;
@@ -2352,7 +2353,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
if (st == NULL)
return ERR_PTR(-ENOMEM);
- page_count = obj->base.size / PAGE_SIZE;
+rebuild_st:
if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
kfree(st);
return ERR_PTR(-ENOMEM);
@@ -2411,8 +2412,25 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
i915_sg_trim(st);
ret = i915_gem_gtt_prepare_pages(obj, st);
- if (ret)
- goto err_pages;
+ if (ret) {
+ /* DMA remapping failed? One possible cause is that
+ * it could not reserve enough large entries, asking
+ * for PAGE_SIZE chunks instead may be helpful.
+ */
+ if (max_segment > PAGE_SIZE) {
+ for_each_sgt_page(page, sgt_iter, st)
+ put_page(page);
+ sg_free_table(st);
+
+ max_segment = PAGE_SIZE;
+ goto rebuild_st;
+ } else {
+ dev_warn(&dev_priv->drm.pdev->dev,
+ "Failed to DMA remap %lu pages\n",
+ page_count);
+ goto err_pages;
+ }
+ }
if (i915_gem_object_needs_bit17_swizzle(obj))
i915_gem_object_do_bit_17_swizzle(obj, st);
--
2.11.0
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 13/14] drm/i915: Replace the .modeset_commit_cdclk() hook with a more direct .set_cdclk() hook
From: ville.syrjala @ 2016-12-19 12:35 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
With the cdclk state, all the .modeset_commit_cdclk() hooks are
now pointless wrappers. Get rid of the extra indirection and just
use set_cdclk function directly.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 3 +-
drivers/gpu/drm/i915/intel_cdclk.c | 57 ++++++------------------------------
drivers/gpu/drm/i915/intel_display.c | 5 ++--
3 files changed, 14 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b5a8d0f4cfbd..faf753570a9a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -614,6 +614,8 @@ struct intel_cdclk_state;
struct drm_i915_display_funcs {
void (*get_cdclk)(struct drm_i915_private *dev_priv,
struct intel_cdclk_state *cdclk_state);
+ void (*set_cdclk)(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_state *cdclk_state);
int (*get_fifo_size)(struct drm_i915_private *dev_priv, int plane);
int (*compute_pipe_wm)(struct intel_crtc_state *cstate);
int (*compute_intermediate_wm)(struct drm_device *dev,
@@ -628,7 +630,6 @@ struct drm_i915_display_funcs {
int (*compute_global_watermarks)(struct drm_atomic_state *state);
void (*update_wm)(struct intel_crtc *crtc);
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
- void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
/* Returns the active state of the crtc, and if the crtc is active,
* fills out the pipe-config with the hw state. */
bool (*get_pipe_config)(struct intel_crtc *,
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 0a9175eb7718..ed4bfee11a08 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -1417,18 +1417,6 @@ static int vlv_modeset_calc_cdclk(struct drm_atomic_state *state)
return 0;
}
-static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_i915_private *dev_priv = to_i915(old_state->dev);
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
-
- if (IS_CHERRYVIEW(dev_priv))
- chv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
- else
- vlv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
-}
-
static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->dev);
@@ -1462,15 +1450,6 @@ static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
return 0;
}
-static void bdw_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_i915_private *dev_priv = to_i915(old_state->dev);
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
-
- bdw_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
-}
-
static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
@@ -1510,15 +1489,6 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
return 0;
}
-static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_i915_private *dev_priv = to_i915(old_state->dev);
- struct intel_atomic_state *intel_state =
- to_intel_atomic_state(old_state);
-
- skl_set_cdclk(dev_priv, &intel_state->cdclk.actual);
-}
-
static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->dev);
@@ -1563,15 +1533,6 @@ static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
return 0;
}
-static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_i915_private *dev_priv = to_i915(old_state->dev);
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
-
- bxt_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
-}
-
static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
{
int max_cdclk_freq = dev_priv->max_cdclk_freq;
@@ -1726,24 +1687,24 @@ void intel_update_rawclk(struct drm_i915_private *dev_priv)
void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
{
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- vlv_modeset_commit_cdclk;
+ if (IS_CHERRYVIEW(dev_priv)) {
+ dev_priv->display.set_cdclk = chv_set_cdclk;
+ dev_priv->display.modeset_calc_cdclk =
+ vlv_modeset_calc_cdclk;
+ } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ dev_priv->display.set_cdclk = vlv_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
vlv_modeset_calc_cdclk;
} else if (IS_BROADWELL(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- bdw_modeset_commit_cdclk;
+ dev_priv->display.set_cdclk = bdw_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
bdw_modeset_calc_cdclk;
} else if (IS_GEN9_LP(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- bxt_modeset_commit_cdclk;
+ dev_priv->display.set_cdclk = bxt_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
bxt_modeset_calc_cdclk;
} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- skl_modeset_commit_cdclk;
+ dev_priv->display.set_cdclk = skl_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
skl_modeset_calc_cdclk;
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 00f047324a4f..22a6bb76e85b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12872,10 +12872,11 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
if (intel_state->modeset) {
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
- if (dev_priv->display.modeset_commit_cdclk &&
+ if (dev_priv->display.set_cdclk &&
!intel_cdclk_state_compare(&dev_priv->cdclk.actual,
&intel_state->cdclk.actual))
- dev_priv->display.modeset_commit_cdclk(state);
+ dev_priv->display.set_cdclk(dev_priv,
+ &intel_state->cdclk.actual);
/*
* SKL workaround: bspec recommends we disable the SAGV when we
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 14/14] drm/i915: Move ilk_pipe_pixel_rate() to intel_display.c
From: ville.syrjala @ 2016-12-19 12:35 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Move ilk_pipe_pixel_rate() next to its only caller
(intel_crtc_compute_pixel_rate()).
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 35 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 1 -
drivers/gpu/drm/i915/intel_pm.c | 33 ---------------------------------
3 files changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 22a6bb76e85b..0aab5b400569 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6229,6 +6229,41 @@ static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc)
(crtc->pipe == PIPE_A || IS_I915G(dev_priv));
}
+static uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config)
+{
+ uint32_t pixel_rate;
+
+ pixel_rate = pipe_config->base.adjusted_mode.crtc_clock;
+
+ /*
+ * We only use IF-ID interlacing. If we ever use
+ * PF-ID we'll need to adjust the pixel_rate here.
+ */
+
+ if (pipe_config->pch_pfit.enabled) {
+ uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+ uint32_t pfit_size = pipe_config->pch_pfit.size;
+
+ pipe_w = pipe_config->pipe_src_w;
+ pipe_h = pipe_config->pipe_src_h;
+
+ pfit_w = (pfit_size >> 16) & 0xFFFF;
+ pfit_h = pfit_size & 0xFFFF;
+ if (pipe_w < pfit_w)
+ pipe_w = pfit_w;
+ if (pipe_h < pfit_h)
+ pipe_h = pfit_h;
+
+ if (WARN_ON(!pfit_w || !pfit_h))
+ return pixel_rate;
+
+ pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
+ pfit_w * pfit_h);
+ }
+
+ return pixel_rate;
+}
+
static void intel_crtc_compute_pixel_rate(struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 605a47fd4a85..6059689f5b6f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1789,7 +1789,6 @@ bool skl_wm_level_equals(const struct skl_wm_level *l1,
bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry **entries,
const struct skl_ddb_entry *ddb,
int ignore);
-uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
bool ilk_disable_lp_wm(struct drm_device *dev);
int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
static inline int intel_enable_rc6(void)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index fe522ec21502..cd81b51291d6 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1701,39 +1701,6 @@ static void i845_update_wm(struct intel_crtc *unused_crtc)
I915_WRITE(FW_BLC, fwater_lo);
}
-uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config)
-{
- uint32_t pixel_rate;
-
- pixel_rate = pipe_config->base.adjusted_mode.crtc_clock;
-
- /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
- * adjust the pixel_rate here. */
-
- if (pipe_config->pch_pfit.enabled) {
- uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
- uint32_t pfit_size = pipe_config->pch_pfit.size;
-
- pipe_w = pipe_config->pipe_src_w;
- pipe_h = pipe_config->pipe_src_h;
-
- pfit_w = (pfit_size >> 16) & 0xFFFF;
- pfit_h = pfit_size & 0xFFFF;
- if (pipe_w < pfit_w)
- pipe_w = pfit_w;
- if (pipe_h < pfit_h)
- pipe_h = pfit_h;
-
- if (WARN_ON(!pfit_w || !pfit_h))
- return pixel_rate;
-
- pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
- pfit_w * pfit_h);
- }
-
- return pixel_rate;
-}
-
/* latency must be in 0.1us units. */
static uint32_t ilk_wm_method1(uint32_t pixel_rate, uint8_t cpp, uint32_t latency)
{
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 12/14] drm/i915: Nuke the VLV/CHV PFI programming power domain workaround
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
The hack to grab the pipe A power domain around VLV/CHV cdclk
programming has surely outlived its usefulness. We should be
hold sufficient power domains during any modeset, so let's just
nuke this hack.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_cdclk.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 4fe844c2cc24..0a9175eb7718 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -1423,24 +1423,10 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- /*
- * FIXME: We can end up here with all power domains off, yet
- * with a CDCLK frequency other than the minimum. To account
- * for this take the PIPE-A power domain, which covers the HW
- * blocks needed for the following programming. This can be
- * removed once it's guaranteed that we get here either with
- * the minimum CDCLK set, or the required power domains
- * enabled.
- */
- intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
-
if (IS_CHERRYVIEW(dev_priv))
chv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
else
vlv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
-
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
}
static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 11/14] drm/i915: Move PFI credit reprogramming into vlv/chv_set_cdclk()
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Move the vlv_program_pfi_credits() into vlv_set_cdclk() and
chv_set_cdclk() so that we can neuter vlv_modeset_commit_cdclk().
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_cdclk.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index f92a570adf1b..4fe844c2cc24 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -494,6 +494,8 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
mutex_unlock(&dev_priv->sb_lock);
+ vlv_program_pfi_credits(dev_priv);
+
intel_update_cdclk(dev_priv);
}
@@ -533,6 +535,8 @@ static void chv_set_cdclk(struct drm_i915_private *dev_priv,
}
mutex_unlock(&dev_priv->rps.hw_lock);
+ vlv_program_pfi_credits(dev_priv);
+
intel_update_cdclk(dev_priv);
}
@@ -1435,7 +1439,6 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
else
vlv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
- vlv_program_pfi_credits(dev_priv);
intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
}
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 10/14] drm/i915: Pass the cdclk state to the set_cdclk() functions
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Rather than passing all the different parameters (cdclk,vco so
far) sparately to the set_cdclk() functions, just pass the
entire cdclk state.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_cdclk.c | 79 +++++++++++++++++++++++---------------
1 file changed, 49 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 95dfd2629062..f92a570adf1b 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -433,8 +433,10 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
}
-static void vlv_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
+static void vlv_set_cdclk(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_state *cdclk_state)
{
+ int cdclk = cdclk_state->cdclk;
u32 val, cmd;
if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
@@ -495,8 +497,10 @@ static void vlv_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
intel_update_cdclk(dev_priv);
}
-static void chv_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
+static void chv_set_cdclk(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_state *cdclk_state)
{
+ int cdclk = cdclk_state->cdclk;
u32 val, cmd;
switch (cdclk) {
@@ -564,8 +568,10 @@ static void bdw_get_cdclk(struct drm_i915_private *dev_priv,
cdclk_state->cdclk = 675000;
}
-static void bdw_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
+static void bdw_set_cdclk(struct drm_i915_private *dev_priv,
+ const struct intel_cdclk_state *cdclk_state)
{
+ int cdclk = cdclk_state->cdclk;
uint32_t val, data;
int ret;
@@ -836,8 +842,10 @@ static void skl_dpll0_disable(struct drm_i915_private *dev_priv)
}
static void skl_set_cdclk(struct drm_i915_private *dev_priv,
- int cdclk, int vco)
+ const struct intel_cdclk_state *cdclk_state)
{
+ int cdclk = cdclk_state->cdclk;
+ int vco = cdclk_state->vco;
u32 freq_select, pcu_ack;
int ret;
@@ -942,12 +950,17 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
{
- skl_set_cdclk(dev_priv, dev_priv->cdclk.hw.ref, 0);
+ struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
+
+ cdclk_state.cdclk = cdclk_state.ref;
+ cdclk_state.vco = 0;
+
+ skl_set_cdclk(dev_priv, &cdclk_state);
}
void skl_init_cdclk(struct drm_i915_private *dev_priv)
{
- int cdclk, vco;
+ struct intel_cdclk_state cdclk_state;
skl_sanitize_cdclk(dev_priv);
@@ -963,12 +976,14 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv)
return;
}
- vco = dev_priv->skl_preferred_vco_freq;
- if (vco == 0)
- vco = 8100000;
- cdclk = skl_calc_cdclk(0, vco);
+ cdclk_state = dev_priv->cdclk.hw;
- skl_set_cdclk(dev_priv, cdclk, vco);
+ cdclk_state.vco = dev_priv->skl_preferred_vco_freq;
+ if (cdclk_state.vco == 0)
+ cdclk_state.vco = 8100000;
+ cdclk_state.cdclk = skl_calc_cdclk(0, cdclk_state.vco);
+
+ skl_set_cdclk(dev_priv, &cdclk_state);
}
static int bxt_calc_cdclk(int max_pixclk)
@@ -1132,8 +1147,10 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
}
static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
- int cdclk, int vco)
+ const struct intel_cdclk_state *cdclk_state)
{
+ int cdclk = cdclk_state->cdclk;
+ int vco = cdclk_state->vco;
u32 val, divider;
int ret;
@@ -1259,7 +1276,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
void bxt_init_cdclk(struct drm_i915_private *dev_priv)
{
- int cdclk, vco;
+ struct intel_cdclk_state cdclk_state;
bxt_sanitize_cdclk(dev_priv);
@@ -1267,25 +1284,33 @@ void bxt_init_cdclk(struct drm_i915_private *dev_priv)
dev_priv->cdclk.hw.vco != 0)
return;
+ cdclk_state = dev_priv->cdclk.hw;
+
/*
* FIXME:
* - The initial CDCLK needs to be read from VBT.
* Need to make this change after VBT has changes for BXT.
*/
if (IS_GEMINILAKE(dev_priv)) {
- cdclk = glk_calc_cdclk(0);
- vco = glk_de_pll_vco(dev_priv, cdclk);
+ cdclk_state.cdclk = glk_calc_cdclk(0);
+ cdclk_state.vco = glk_de_pll_vco(dev_priv, cdclk_state.cdclk);
} else {
- cdclk = bxt_calc_cdclk(0);
- vco = bxt_de_pll_vco(dev_priv, cdclk);
+ cdclk_state.ref = dev_priv->cdclk.hw.ref;
+ cdclk_state.cdclk = bxt_calc_cdclk(0);
+ cdclk_state.vco = bxt_de_pll_vco(dev_priv, cdclk_state.cdclk);
}
- bxt_set_cdclk(dev_priv, cdclk, vco);
+ bxt_set_cdclk(dev_priv, &cdclk_state);
}
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
{
- bxt_set_cdclk(dev_priv, dev_priv->cdclk.hw.ref, 0);
+ struct intel_cdclk_state cdclk_state = dev_priv->cdclk.hw;
+
+ cdclk_state.cdclk = cdclk_state.ref;
+ cdclk_state.vco = 0;
+
+ bxt_set_cdclk(dev_priv, &cdclk_state);
}
bool intel_cdclk_state_compare(struct intel_cdclk_state *a,
@@ -1393,7 +1418,6 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
/*
* FIXME: We can end up here with all power domains off, yet
@@ -1407,9 +1431,9 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
if (IS_CHERRYVIEW(dev_priv))
- chv_set_cdclk(dev_priv, req_cdclk);
+ chv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
else
- vlv_set_cdclk(dev_priv, req_cdclk);
+ vlv_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
vlv_program_pfi_credits(dev_priv);
@@ -1454,9 +1478,8 @@ static void bdw_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
- bdw_set_cdclk(dev_priv, req_cdclk);
+ bdw_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
}
static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
@@ -1503,10 +1526,8 @@ static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = intel_state->cdclk.actual.cdclk;
- unsigned int req_vco = intel_state->cdclk.actual.vco;
- skl_set_cdclk(dev_priv, req_cdclk, req_vco);
+ skl_set_cdclk(dev_priv, &intel_state->cdclk.actual);
}
static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
@@ -1558,10 +1579,8 @@ static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
- unsigned int req_vco = old_intel_state->cdclk.actual.vco;
- bxt_set_cdclk(dev_priv, req_cdclk, req_vco);
+ bxt_set_cdclk(dev_priv, &old_intel_state->cdclk.actual);
}
static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 09/14] drm/i915: Pass dev_priv to remainder of the cdclk functions
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Clean up the dev vs. dev_priv straggles that are making things
look inconsistentt.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_cdclk.c | 23 +++++++++--------------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index bd7ad9abcee5..95dfd2629062 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -433,9 +433,8 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
}
-static void vlv_set_cdclk(struct drm_device *dev, int cdclk)
+static void vlv_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
{
- struct drm_i915_private *dev_priv = to_i915(dev);
u32 val, cmd;
if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
@@ -496,9 +495,8 @@ static void vlv_set_cdclk(struct drm_device *dev, int cdclk)
intel_update_cdclk(dev_priv);
}
-static void chv_set_cdclk(struct drm_device *dev, int cdclk)
+static void chv_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
{
- struct drm_i915_private *dev_priv = to_i915(dev);
u32 val, cmd;
switch (cdclk) {
@@ -566,9 +564,8 @@ static void bdw_get_cdclk(struct drm_i915_private *dev_priv,
cdclk_state->cdclk = 675000;
}
-static void bdw_set_cdclk(struct drm_device *dev, int cdclk)
+static void bdw_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
{
- struct drm_i915_private *dev_priv = to_i915(dev);
uint32_t val, data;
int ret;
@@ -1363,8 +1360,7 @@ static int intel_max_pixel_rate(struct drm_atomic_state *state)
static int vlv_modeset_calc_cdclk(struct drm_atomic_state *state)
{
- struct drm_device *dev = state->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
int max_pixclk = intel_max_pixel_rate(state);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);
@@ -1394,8 +1390,7 @@ static int vlv_modeset_calc_cdclk(struct drm_atomic_state *state)
static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
- struct drm_device *dev = old_state->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
@@ -1412,9 +1407,9 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
if (IS_CHERRYVIEW(dev_priv))
- chv_set_cdclk(dev, req_cdclk);
+ chv_set_cdclk(dev_priv, req_cdclk);
else
- vlv_set_cdclk(dev, req_cdclk);
+ vlv_set_cdclk(dev_priv, req_cdclk);
vlv_program_pfi_credits(dev_priv);
@@ -1456,12 +1451,12 @@ static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
static void bdw_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
- struct drm_device *dev = old_state->dev;
+ struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
- bdw_set_cdclk(dev, req_cdclk);
+ bdw_set_cdclk(dev_priv, req_cdclk);
}
static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 08/14] drm/i915: Track full cdclk state for the logical and actual cdclk frequencies
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
The current dev_cdclk vs. cdclk vs. atomic_cdclk_freq is quite a mess.
So here I'm introducing the "actual" and "logical" naming for our
cdclk state. "actual" is what we'll bash into the hardware and "logical"
is what everyone should use for state computaion/checking and whatnot.
We'll track both using the intel_cdclk_state as both will need other
differing parameters than just the actual cdclk frequency.
While doing that we can at the same time unify the appearance of the
.modeset_calc_cdclk() implementations a little bit.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 13 ++--
drivers/gpu/drm/i915/intel_cdclk.c | 115 ++++++++++++++++++++++++-----------
drivers/gpu/drm/i915/intel_display.c | 39 ++++++------
drivers/gpu/drm/i915/intel_dp.c | 2 +-
drivers/gpu/drm/i915/intel_drv.h | 22 ++++---
drivers/gpu/drm/i915/intel_pm.c | 4 +-
6 files changed, 120 insertions(+), 75 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a4f1231ff8ca..b5a8d0f4cfbd 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2237,18 +2237,19 @@ struct drm_i915_private {
unsigned int skl_preferred_vco_freq;
unsigned int max_cdclk_freq;
- /*
- * For reading holding any crtc lock is sufficient,
- * for writing must hold all of them.
- */
- unsigned int atomic_cdclk_freq;
-
unsigned int max_dotclk_freq;
unsigned int rawclk_freq;
unsigned int hpll_freq;
unsigned int czclk_freq;
struct {
+ /*
+ * The current logical cdclk state.
+ * For reading holding any crtc lock is sufficient,
+ * for writing must hold all of them.
+ */
+ struct intel_cdclk_state logical;
+ struct intel_cdclk_state actual;
struct intel_cdclk_state hw;
} cdclk;
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 7c128d2138a1..bd7ad9abcee5 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -1368,12 +1368,26 @@ static int vlv_modeset_calc_cdclk(struct drm_atomic_state *state)
int max_pixclk = intel_max_pixel_rate(state);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);
+ int cdclk;
- intel_state->cdclk = intel_state->dev_cdclk =
- vlv_calc_cdclk(dev_priv, max_pixclk);
+ cdclk = vlv_calc_cdclk(dev_priv, max_pixclk);
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = vlv_calc_cdclk(dev_priv, 0);
+ if (cdclk > dev_priv->max_cdclk_freq) {
+ DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ return -EINVAL;
+ }
+
+ intel_state->cdclk.logical.cdclk = cdclk;
+
+ if (!intel_state->active_crtcs) {
+ cdclk = vlv_calc_cdclk(dev_priv, 0);
+
+ intel_state->cdclk.actual.cdclk = cdclk;
+ } else {
+ intel_state->cdclk.actual =
+ intel_state->cdclk.logical;
+ }
return 0;
}
@@ -1384,7 +1398,7 @@ static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->dev_cdclk;
+ unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
/*
* FIXME: We can end up here with all power domains off, yet
@@ -1426,9 +1440,16 @@ static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
return -EINVAL;
}
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = bdw_calc_cdclk(0);
+ intel_state->cdclk.logical.cdclk = cdclk;
+
+ if (!intel_state->active_crtcs) {
+ cdclk = bdw_calc_cdclk(0);
+
+ intel_state->cdclk.actual.cdclk = cdclk;
+ } else {
+ intel_state->cdclk.actual =
+ intel_state->cdclk.logical;
+ }
return 0;
}
@@ -1438,7 +1459,7 @@ static void bdw_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_device *dev = old_state->dev;
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->dev_cdclk;
+ unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
bdw_set_cdclk(dev, req_cdclk);
}
@@ -1448,8 +1469,11 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_i915_private *dev_priv = to_i915(state->dev);
const int max_pixclk = intel_max_pixel_rate(state);
- int vco = intel_state->cdclk_pll_vco;
- int cdclk;
+ int cdclk, vco;
+
+ vco = intel_state->cdclk.logical.vco;
+ if (!vco)
+ vco = dev_priv->skl_preferred_vco_freq;
/*
* FIXME should also account for plane ratio
@@ -1457,19 +1481,24 @@ static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
*/
cdclk = skl_calc_cdclk(max_pixclk, vco);
- /*
- * FIXME move the cdclk caclulation to
- * compute_config() so we can fail gracegully.
- */
if (cdclk > dev_priv->max_cdclk_freq) {
- DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
- cdclk, dev_priv->max_cdclk_freq);
- cdclk = dev_priv->max_cdclk_freq;
+ DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ return -EINVAL;
}
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = skl_calc_cdclk(0, vco);
+ intel_state->cdclk.logical.vco = vco;
+ intel_state->cdclk.logical.cdclk = cdclk;
+
+ if (!intel_state->active_crtcs) {
+ cdclk = skl_calc_cdclk(0, vco);
+
+ intel_state->cdclk.actual.vco = vco;
+ intel_state->cdclk.actual.cdclk = cdclk;
+ } else {
+ intel_state->cdclk.actual =
+ intel_state->cdclk.logical;
+ }
return 0;
}
@@ -1479,8 +1508,8 @@ static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = intel_state->dev_cdclk;
- unsigned int req_vco = intel_state->cdclk_pll_vco;
+ unsigned int req_cdclk = intel_state->cdclk.actual.cdclk;
+ unsigned int req_vco = intel_state->cdclk.actual.vco;
skl_set_cdclk(dev_priv, req_cdclk, req_vco);
}
@@ -1491,22 +1520,39 @@ static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
int max_pixclk = intel_max_pixel_rate(state);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);
- int cdclk;
+ int cdclk, vco;
- if (IS_GEMINILAKE(dev_priv))
+ if (IS_GEMINILAKE(dev_priv)) {
cdclk = glk_calc_cdclk(max_pixclk);
- else
+ vco = glk_de_pll_vco(dev_priv, cdclk);
+ } else {
cdclk = bxt_calc_cdclk(max_pixclk);
+ vco = bxt_de_pll_vco(dev_priv, cdclk);
+ }
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
+ if (cdclk > dev_priv->max_cdclk_freq) {
+ DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ return -EINVAL;
+ }
+
+ intel_state->cdclk.logical.vco = vco;
+ intel_state->cdclk.logical.cdclk = cdclk;
if (!intel_state->active_crtcs) {
- if (IS_GEMINILAKE(dev_priv))
+ if (IS_GEMINILAKE(dev_priv)) {
cdclk = glk_calc_cdclk(0);
- else
+ vco = glk_de_pll_vco(dev_priv, cdclk);
+ } else {
cdclk = bxt_calc_cdclk(0);
+ vco = bxt_de_pll_vco(dev_priv, cdclk);
+ }
- intel_state->dev_cdclk = cdclk;
+ intel_state->cdclk.actual.vco = vco;
+ intel_state->cdclk.actual.cdclk = cdclk;
+ } else {
+ intel_state->cdclk.actual =
+ intel_state->cdclk.logical;
}
return 0;
@@ -1517,13 +1563,8 @@ static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->dev_cdclk;
- unsigned int req_vco;
-
- if (IS_GEMINILAKE(dev_priv))
- req_vco = glk_de_pll_vco(dev_priv, req_cdclk);
- else
- req_vco = bxt_de_pll_vco(dev_priv, req_cdclk);
+ unsigned int req_cdclk = old_intel_state->cdclk.actual.cdclk;
+ unsigned int req_vco = old_intel_state->cdclk.actual.vco;
bxt_set_cdclk(dev_priv, req_cdclk, req_vco);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 6c38ab299506..00f047324a4f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -12416,6 +12416,8 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
intel_state->modeset = true;
intel_state->active_crtcs = dev_priv->active_crtcs;
+ intel_state->cdclk.logical = dev_priv->cdclk.logical;
+ intel_state->cdclk.actual = dev_priv->cdclk.actual;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (crtc_state->active)
@@ -12435,38 +12437,35 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
* adjusted_mode bits in the crtc directly.
*/
if (dev_priv->display.modeset_calc_cdclk) {
- if (!intel_state->cdclk_pll_vco)
- intel_state->cdclk_pll_vco = dev_priv->cdclk.hw.vco;
- if (!intel_state->cdclk_pll_vco)
- intel_state->cdclk_pll_vco = dev_priv->skl_preferred_vco_freq;
-
ret = dev_priv->display.modeset_calc_cdclk(state);
if (ret < 0)
return ret;
/*
- * Writes to dev_priv->atomic_cdclk_freq must protected by
+ * Writes to dev_priv->cdclk_locical must protected by
* holding all the crtc locks, even if we don't end up
* touching the hardware
*/
- if (intel_state->cdclk != dev_priv->atomic_cdclk_freq) {
+ if (!intel_cdclk_state_compare(&dev_priv->cdclk.logical,
+ &intel_state->cdclk.logical)) {
ret = intel_lock_all_pipes(state);
if (ret < 0)
return ret;
}
/* All pipes must be switched off while we change the cdclk. */
- if (intel_state->dev_cdclk != dev_priv->cdclk.hw.cdclk ||
- intel_state->cdclk_pll_vco != dev_priv->cdclk.hw.vco) {
+ if (!intel_cdclk_state_compare(&dev_priv->cdclk.actual,
+ &intel_state->cdclk.actual)) {
ret = intel_modeset_all_pipes(state);
if (ret < 0)
return ret;
}
- DRM_DEBUG_KMS("New cdclk calculated to be atomic %u, actual %u\n",
- intel_state->cdclk, intel_state->dev_cdclk);
+ DRM_DEBUG_KMS("New cdclk calculated to be logical %u kHz, actual %u kHz\n",
+ intel_state->cdclk.logical.cdclk,
+ intel_state->cdclk.actual.cdclk);
} else {
- to_intel_atomic_state(state)->cdclk = dev_priv->atomic_cdclk_freq;
+ to_intel_atomic_state(state)->cdclk.logical = dev_priv->cdclk.logical;
}
intel_modeset_clear_plls(state);
@@ -12569,7 +12568,7 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
} else {
- intel_state->cdclk = dev_priv->atomic_cdclk_freq;
+ intel_state->cdclk.logical = dev_priv->cdclk.logical;
}
ret = drm_atomic_helper_check_planes(dev, state);
@@ -12874,8 +12873,8 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
if (dev_priv->display.modeset_commit_cdclk &&
- (intel_state->dev_cdclk != dev_priv->cdclk.hw.cdclk ||
- intel_state->cdclk_pll_vco != dev_priv->cdclk.hw.vco))
+ !intel_cdclk_state_compare(&dev_priv->cdclk.actual,
+ &intel_state->cdclk.actual))
dev_priv->display.modeset_commit_cdclk(state);
/*
@@ -13056,7 +13055,8 @@ static int intel_atomic_commit(struct drm_device *dev,
memcpy(dev_priv->min_pixclk, intel_state->min_pixclk,
sizeof(intel_state->min_pixclk));
dev_priv->active_crtcs = intel_state->active_crtcs;
- dev_priv->atomic_cdclk_freq = intel_state->cdclk;
+ dev_priv->cdclk.logical = intel_state->cdclk.logical;
+ dev_priv->cdclk.actual = intel_state->cdclk.actual;
}
drm_atomic_state_get(state);
@@ -13298,7 +13298,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
return DRM_PLANE_HELPER_NO_SCALING;
crtc_clock = crtc_state->base.adjusted_mode.crtc_clock;
- cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk;
+ cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk;
if (WARN_ON_ONCE(!crtc_clock || cdclk < crtc_clock))
return DRM_PLANE_HELPER_NO_SCALING;
@@ -14723,8 +14723,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
struct drm_i915_private *dev_priv = to_i915(dev);
intel_update_cdclk(dev_priv);
-
- dev_priv->atomic_cdclk_freq = dev_priv->cdclk.hw.cdclk;
+ dev_priv->cdclk.logical = dev_priv->cdclk.actual = dev_priv->cdclk.hw;
intel_init_clock_gating(dev_priv);
}
@@ -14897,7 +14896,7 @@ int intel_modeset_init(struct drm_device *dev)
intel_update_czclk(dev_priv);
intel_update_cdclk(dev_priv);
- dev_priv->atomic_cdclk_freq = dev_priv->cdclk.hw.cdclk;
+ dev_priv->cdclk.logical = dev_priv->cdclk.actual = dev_priv->cdclk.hw;
intel_shared_dpll_init(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 73a708b8d887..4309509e8a34 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1734,7 +1734,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
break;
}
- to_intel_atomic_state(pipe_config->base.state)->cdclk_pll_vco = vco;
+ to_intel_atomic_state(pipe_config->base.state)->cdclk.logical.vco = vco;
}
if (!HAS_DDI(dev_priv))
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c062f063bfbc..605a47fd4a85 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -333,13 +333,20 @@ struct dpll {
struct intel_atomic_state {
struct drm_atomic_state base;
- unsigned int cdclk;
+ struct {
+ /*
+ * Logical state of cdclk (used for all scaling, watermark,
+ * etc. calculations and checks). This is computed as if all
+ * enabled crtcs were active.
+ */
+ struct intel_cdclk_state logical;
- /*
- * Calculated device cdclk, can be different from cdclk
- * only when all crtc's are DPMS off.
- */
- unsigned int dev_cdclk;
+ /*
+ * Actual state of cdclk, can be different from the logical
+ * state only when all crtc's are DPMS off.
+ */
+ struct intel_cdclk_state actual;
+ } cdclk;
bool dpll_set, modeset;
@@ -356,9 +363,6 @@ struct intel_atomic_state {
unsigned int active_crtcs;
unsigned int min_pixclk[I915_MAX_PIPES];
- /* SKL/KBL Only */
- unsigned int cdclk_pll_vco;
-
struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
/*
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 79e2be4216e4..fe522ec21502 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2095,7 +2095,7 @@ hsw_compute_linetime_wm(const struct intel_crtc_state *cstate)
return 0;
if (WARN_ON(adjusted_mode->crtc_clock == 0))
return 0;
- if (WARN_ON(intel_state->cdclk == 0))
+ if (WARN_ON(intel_state->cdclk.logical.cdclk == 0))
return 0;
/* The WM are computed with base on how long it takes to fill a single
@@ -2104,7 +2104,7 @@ hsw_compute_linetime_wm(const struct intel_crtc_state *cstate)
linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
adjusted_mode->crtc_clock);
ips_linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
- intel_state->cdclk);
+ intel_state->cdclk.logical.cdclk);
return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
PIPE_WM_LINETIME_TIME(linetime);
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 07/14] drm/i915: Start moving the cdclk stuff into a distinct state structure
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Introduce intel_cdclk state which for now will track the cdclk
frequency, the vco frequency and the reference frequency (not sure we
want the last one, but I put it there anyway). We'll also make the
.get_cdclk() function fill out this state structure rather than
just returning the current cdclk frequency.
One immediate benefit is that calling .get_cdclk() will no longer
clobber state stored under dev_priv unless ex[plicitly told to do
so. Previously it clobbered the vco and reference clocks stored
there on some platforms.
We'll expand the use of this structure to actually precomputing the
state and whatnot later.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/i915_debugfs.c | 2 +-
drivers/gpu/drm/i915/i915_drv.h | 14 +-
drivers/gpu/drm/i915/intel_audio.c | 2 +-
drivers/gpu/drm/i915/intel_cdclk.c | 359 ++++++++++++++++++--------------
drivers/gpu/drm/i915/intel_display.c | 18 +-
drivers/gpu/drm/i915/intel_dp.c | 2 +-
drivers/gpu/drm/i915/intel_drv.h | 3 +
drivers/gpu/drm/i915/intel_fbc.c | 2 +-
drivers/gpu/drm/i915/intel_panel.c | 4 +-
drivers/gpu/drm/i915/intel_runtime_pm.c | 5 +-
10 files changed, 240 insertions(+), 171 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 15deb2bc568b..c0171eef8f96 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1235,7 +1235,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_puts(m, "no P-state info available\n");
}
- seq_printf(m, "Current CD clock frequency: %d kHz\n", dev_priv->cdclk_freq);
+ seq_printf(m, "Current CD clock frequency: %d kHz\n", dev_priv->cdclk.hw.cdclk);
seq_printf(m, "Max CD clock frequency: %d kHz\n", dev_priv->max_cdclk_freq);
seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 393b34fb2d1a..a4f1231ff8ca 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -609,9 +609,11 @@ struct intel_initial_plane_config;
struct intel_crtc;
struct intel_limit;
struct dpll;
+struct intel_cdclk_state;
struct drm_i915_display_funcs {
- int (*get_cdclk)(struct drm_i915_private *dev_priv);
+ void (*get_cdclk)(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state);
int (*get_fifo_size)(struct drm_i915_private *dev_priv, int plane);
int (*compute_pipe_wm)(struct intel_crtc_state *cstate);
int (*compute_intermediate_wm)(struct drm_device *dev,
@@ -2126,6 +2128,10 @@ struct i915_oa_ops {
bool (*oa_buffer_is_empty)(struct drm_i915_private *dev_priv);
};
+struct intel_cdclk_state {
+ unsigned int cdclk, vco, ref;
+};
+
struct drm_i915_private {
struct drm_device drm;
@@ -2229,7 +2235,7 @@ struct drm_i915_private {
unsigned int fsb_freq, mem_freq, is_ddr3;
unsigned int skl_preferred_vco_freq;
- unsigned int cdclk_freq, max_cdclk_freq;
+ unsigned int max_cdclk_freq;
/*
* For reading holding any crtc lock is sufficient,
@@ -2243,8 +2249,8 @@ struct drm_i915_private {
unsigned int czclk_freq;
struct {
- unsigned int vco, ref;
- } cdclk_pll;
+ struct intel_cdclk_state hw;
+ } cdclk;
/**
* wq - Driver workqueue for GEM.
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 3bbc96c1767f..a292246995ef 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -734,7 +734,7 @@ static int i915_audio_component_get_cdclk_freq(struct device *kdev)
if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
return -ENODEV;
- return dev_priv->cdclk_freq;
+ return dev_priv->cdclk.hw.cdclk;
}
/*
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 89be610d0879..7c128d2138a1 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -23,37 +23,44 @@
#include "intel_drv.h"
-static int fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 133333;
+ cdclk_state->cdclk = 133333;
}
-static int fixed_200mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_200mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 200000;
+ cdclk_state->cdclk = 200000;
}
-static int fixed_266mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_266mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 266667;
+ cdclk_state->cdclk = 266667;
}
-static int fixed_333mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_333mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 333333;
+ cdclk_state->cdclk = 333333;
}
-static int fixed_400mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_400mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 400000;
+ cdclk_state->cdclk = 400000;
}
-static int fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv)
+static void fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return 450000;
+ cdclk_state->cdclk = 450000;
}
-static int i85x_get_cdclk(struct drm_i915_private *dev_priv)
+static void i85x_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
u16 hpllcc = 0;
@@ -63,8 +70,10 @@ static int i85x_get_cdclk(struct drm_i915_private *dev_priv)
* encoding is different :(
* FIXME is this the right way to detect 852GM/852GMV?
*/
- if (pdev->revision == 0x1)
- return 133333;
+ if (pdev->revision == 0x1) {
+ cdclk_state->cdclk = 133333;
+ return;
+ }
pci_bus_read_config_word(pdev->bus,
PCI_DEVFN(0, 3), HPLLCC, &hpllcc);
@@ -76,37 +85,43 @@ static int i85x_get_cdclk(struct drm_i915_private *dev_priv)
case GC_CLOCK_133_200:
case GC_CLOCK_133_200_2:
case GC_CLOCK_100_200:
- return 200000;
+ cdclk_state->cdclk = 200000;
+ break;
case GC_CLOCK_166_250:
- return 250000;
+ cdclk_state->cdclk = 250000;
+ break;
case GC_CLOCK_100_133:
- return 133333;
+ cdclk_state->cdclk = 133333;
+ break;
case GC_CLOCK_133_266:
case GC_CLOCK_133_266_2:
case GC_CLOCK_166_266:
- return 266667;
+ cdclk_state->cdclk = 266667;
+ break;
}
-
- /* Shouldn't happen */
- return 0;
}
-static int i915gm_get_cdclk(struct drm_i915_private *dev_priv)
+static void i915gm_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
u16 gcfgc = 0;
pci_read_config_word(pdev, GCFGC, &gcfgc);
- if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
- return 133333;
+ if (gcfgc & GC_LOW_FREQUENCY_ENABLE) {
+ cdclk_state->cdclk = 133333;
+ return;
+ }
switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
case GC_DISPLAY_CLOCK_333_MHZ:
- return 333333;
+ cdclk_state->cdclk = 333333;
+ break;
default:
case GC_DISPLAY_CLOCK_190_200_MHZ:
- return 190000;
+ cdclk_state->cdclk = 190000;
+ break;
}
}
@@ -178,7 +193,8 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv)
return vco;
}
-static int g33_get_cdclk(struct drm_i915_private *dev_priv)
+static void g33_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 };
@@ -186,9 +202,11 @@ static int g33_get_cdclk(struct drm_i915_private *dev_priv)
static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 };
static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 };
const uint8_t *div_table;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ unsigned int cdclk_sel;
uint16_t tmp = 0;
+ cdclk_state->vco = intel_hpll_vco(dev_priv);
+
pci_read_config_word(pdev, GCFGC, &tmp);
cdclk_sel = (tmp >> 4) & 0x7;
@@ -196,7 +214,7 @@ static int g33_get_cdclk(struct drm_i915_private *dev_priv)
if (cdclk_sel >= ARRAY_SIZE(div_3200))
goto fail;
- switch (vco) {
+ switch (cdclk_state->vco) {
case 3200000:
div_table = div_3200;
break;
@@ -213,15 +231,18 @@ static int g33_get_cdclk(struct drm_i915_private *dev_priv)
goto fail;
}
- return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
+ cdclk_state->cdclk = DIV_ROUND_CLOSEST(cdclk_state->vco,
+ div_table[cdclk_sel]);
+ return;
fail:
DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n",
- vco, tmp);
- return 190476;
+ cdclk_state->vco, tmp);
+ cdclk_state->cdclk = 190476;
}
-static int pnv_get_cdclk(struct drm_i915_private *dev_priv)
+static void pnv_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
u16 gcfgc = 0;
@@ -230,32 +251,41 @@ static int pnv_get_cdclk(struct drm_i915_private *dev_priv)
switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
case GC_DISPLAY_CLOCK_267_MHZ_PNV:
- return 266667;
+ cdclk_state->cdclk = 266667;
+ break;
case GC_DISPLAY_CLOCK_333_MHZ_PNV:
- return 333333;
+ cdclk_state->cdclk = 333333;
+ break;
case GC_DISPLAY_CLOCK_444_MHZ_PNV:
- return 444444;
+ cdclk_state->cdclk = 444444;
+ break;
case GC_DISPLAY_CLOCK_200_MHZ_PNV:
- return 200000;
+ cdclk_state->cdclk = 200000;
+ break;
default:
DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
case GC_DISPLAY_CLOCK_133_MHZ_PNV:
- return 133333;
+ cdclk_state->cdclk = 133333;
+ break;
case GC_DISPLAY_CLOCK_167_MHZ_PNV:
- return 166667;
+ cdclk_state->cdclk = 166667;
+ break;
}
}
-static int i965gm_get_cdclk(struct drm_i915_private *dev_priv)
+static void i965gm_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
static const uint8_t div_3200[] = { 16, 10, 8 };
static const uint8_t div_4000[] = { 20, 12, 10 };
static const uint8_t div_5333[] = { 24, 16, 14 };
const uint8_t *div_table;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ unsigned int cdclk_sel;
uint16_t tmp = 0;
+ cdclk_state->vco = intel_hpll_vco(dev_priv);
+
pci_read_config_word(pdev, GCFGC, &tmp);
cdclk_sel = ((tmp >> 8) & 0x1f) - 1;
@@ -263,7 +293,7 @@ static int i965gm_get_cdclk(struct drm_i915_private *dev_priv)
if (cdclk_sel >= ARRAY_SIZE(div_3200))
goto fail;
- switch (vco) {
+ switch (cdclk_state->vco) {
case 3200000:
div_table = div_3200;
break;
@@ -277,53 +307,62 @@ static int i965gm_get_cdclk(struct drm_i915_private *dev_priv)
goto fail;
}
- return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
+ cdclk_state->cdclk = DIV_ROUND_CLOSEST(cdclk_state->vco,
+ div_table[cdclk_sel]);
+ return;
fail:
DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n",
- vco, tmp);
- return 200000;
+ cdclk_state->vco, tmp);
+ cdclk_state->cdclk = 200000;
}
-static int gm45_get_cdclk(struct drm_i915_private *dev_priv)
+static void gm45_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
struct pci_dev *pdev = dev_priv->drm.pdev;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ unsigned int cdclk_sel;
uint16_t tmp = 0;
+ cdclk_state->vco = intel_hpll_vco(dev_priv);
+
pci_read_config_word(pdev, GCFGC, &tmp);
cdclk_sel = (tmp >> 12) & 0x1;
- switch (vco) {
+ switch (cdclk_state->vco) {
case 2666667:
case 4000000:
case 5333333:
- return cdclk_sel ? 333333 : 222222;
+ cdclk_state->cdclk = cdclk_sel ? 333333 : 222222;
+ break;
case 3200000:
- return cdclk_sel ? 320000 : 228571;
+ cdclk_state->cdclk = cdclk_sel ? 320000 : 228571;
+ break;
default:
DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n",
- vco, tmp);
- return 222222;
+ cdclk_state->vco, tmp);
+ cdclk_state->cdclk = 222222;
+ break;
}
}
-static int hsw_get_cdclk(struct drm_i915_private *dev_priv)
+static void hsw_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
uint32_t lcpll = I915_READ(LCPLL_CTL);
uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
if (lcpll & LCPLL_CD_SOURCE_FCLK)
- return 800000;
+ cdclk_state->cdclk = 800000;
else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
- return 450000;
+ cdclk_state->cdclk = 450000;
else if (freq == LCPLL_CLK_FREQ_450)
- return 450000;
+ cdclk_state->cdclk = 450000;
else if (IS_HSW_ULT(dev_priv))
- return 337500;
+ cdclk_state->cdclk = 337500;
else
- return 540000;
+ cdclk_state->cdclk = 540000;
}
static int vlv_calc_cdclk(struct drm_i915_private *dev_priv,
@@ -349,10 +388,13 @@ static int vlv_calc_cdclk(struct drm_i915_private *dev_priv,
return 200000;
}
-static int vlv_get_cdclk(struct drm_i915_private *dev_priv)
+static void vlv_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
- return vlv_get_cck_clock_hpll(dev_priv, "cdclk",
- CCK_DISPLAY_CLOCK_CONTROL);
+ cdclk_state->vco = vlv_get_hpll_vco(dev_priv);
+ cdclk_state->cdclk = vlv_get_cck_clock(dev_priv, "cdclk",
+ CCK_DISPLAY_CLOCK_CONTROL,
+ cdclk_state->vco);
}
static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
@@ -364,7 +406,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
else
default_credits = PFI_CREDIT(8);
- if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) {
+ if (dev_priv->cdclk.hw.cdclk >= dev_priv->czclk_freq) {
/* CHV suggested value is 31 or 63 */
if (IS_CHERRYVIEW(dev_priv))
credits = PFI_CREDIT_63;
@@ -396,8 +438,6 @@ static void vlv_set_cdclk(struct drm_device *dev, int cdclk)
struct drm_i915_private *dev_priv = to_i915(dev);
u32 val, cmd;
- WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
-
if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
cmd = 2;
else if (cdclk == 266667)
@@ -461,8 +501,6 @@ static void chv_set_cdclk(struct drm_device *dev, int cdclk)
struct drm_i915_private *dev_priv = to_i915(dev);
u32 val, cmd;
- WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
-
switch (cdclk) {
case 333333:
case 320000:
@@ -508,23 +546,24 @@ static int bdw_calc_cdclk(int max_pixclk)
return 337500;
}
-static int bdw_get_cdclk(struct drm_i915_private *dev_priv)
+static void bdw_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
uint32_t lcpll = I915_READ(LCPLL_CTL);
uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
if (lcpll & LCPLL_CD_SOURCE_FCLK)
- return 800000;
+ cdclk_state->cdclk = 800000;
else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
- return 450000;
+ cdclk_state->cdclk = 450000;
else if (freq == LCPLL_CLK_FREQ_450)
- return 450000;
+ cdclk_state->cdclk = 450000;
else if (freq == LCPLL_CLK_FREQ_54O_BDW)
- return 540000;
+ cdclk_state->cdclk = 540000;
else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
- return 337500;
+ cdclk_state->cdclk = 337500;
else
- return 675000;
+ cdclk_state->cdclk = 675000;
}
static void bdw_set_cdclk(struct drm_device *dev, int cdclk)
@@ -601,9 +640,9 @@ static void bdw_set_cdclk(struct drm_device *dev, int cdclk)
intel_update_cdclk(dev_priv);
- WARN(cdclk != dev_priv->cdclk_freq,
+ WARN(cdclk != dev_priv->cdclk.hw.cdclk,
"cdclk requested %d kHz but got %d kHz\n",
- cdclk, dev_priv->cdclk_freq);
+ cdclk, dev_priv->cdclk.hw.cdclk);
}
static int skl_calc_cdclk(int max_pixclk, int vco)
@@ -629,12 +668,13 @@ static int skl_calc_cdclk(int max_pixclk, int vco)
}
}
-static void skl_dpll0_update(struct drm_i915_private *dev_priv)
+static void skl_dpll0_update(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
u32 val;
- dev_priv->cdclk_pll.ref = 24000;
- dev_priv->cdclk_pll.vco = 0;
+ cdclk_state->ref = 24000;
+ cdclk_state->vco = 0;
val = I915_READ(LCPLL1_CTL);
if ((val & LCPLL_PLL_ENABLE) == 0)
@@ -656,11 +696,11 @@ static void skl_dpll0_update(struct drm_i915_private *dev_priv)
case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0):
case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0):
case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0):
- dev_priv->cdclk_pll.vco = 8100000;
+ cdclk_state->vco = 8100000;
break;
case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0):
case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0):
- dev_priv->cdclk_pll.vco = 8640000;
+ cdclk_state->vco = 8640000;
break;
default:
MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
@@ -668,46 +708,57 @@ static void skl_dpll0_update(struct drm_i915_private *dev_priv)
}
}
-static int skl_get_cdclk(struct drm_i915_private *dev_priv)
+static void skl_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
u32 cdctl;
- skl_dpll0_update(dev_priv);
+ skl_dpll0_update(dev_priv, cdclk_state);
- if (dev_priv->cdclk_pll.vco == 0)
- return dev_priv->cdclk_pll.ref;
+ cdclk_state->cdclk = cdclk_state->ref;
+
+ if (cdclk_state->vco == 0)
+ return;
cdctl = I915_READ(CDCLK_CTL);
- if (dev_priv->cdclk_pll.vco == 8640000) {
+ if (cdclk_state->vco == 8640000) {
switch (cdctl & CDCLK_FREQ_SEL_MASK) {
case CDCLK_FREQ_450_432:
- return 432000;
+ cdclk_state->cdclk = 432000;
+ break;
case CDCLK_FREQ_337_308:
- return 308571;
+ cdclk_state->cdclk = 308571;
+ break;
case CDCLK_FREQ_540:
- return 540000;
+ cdclk_state->cdclk = 540000;
+ break;
case CDCLK_FREQ_675_617:
- return 617143;
+ cdclk_state->cdclk = 617143;
+ break;
default:
MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
+ break;
}
} else {
switch (cdctl & CDCLK_FREQ_SEL_MASK) {
case CDCLK_FREQ_450_432:
- return 450000;
+ cdclk_state->cdclk = 450000;
+ break;
case CDCLK_FREQ_337_308:
- return 337500;
+ cdclk_state->cdclk = 337500;
+ break;
case CDCLK_FREQ_540:
- return 540000;
+ cdclk_state->cdclk = 540000;
+ break;
case CDCLK_FREQ_675_617:
- return 675000;
+ cdclk_state->cdclk = 675000;
+ break;
default:
MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
+ break;
}
}
-
- return dev_priv->cdclk_pll.ref;
}
/* convert from kHz to .1 fixpoint MHz with -1MHz offset */
@@ -770,7 +821,7 @@ static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)
5))
DRM_ERROR("DPLL0 not locked\n");
- dev_priv->cdclk_pll.vco = vco;
+ dev_priv->cdclk.hw.vco = vco;
/* We'll want to keep using the current vco from now on. */
skl_set_preferred_cdclk_vco(dev_priv, vco);
@@ -784,7 +835,7 @@ static void skl_dpll0_disable(struct drm_i915_private *dev_priv)
1))
DRM_ERROR("Couldn't disable DPLL0\n");
- dev_priv->cdclk_pll.vco = 0;
+ dev_priv->cdclk.hw.vco = 0;
}
static void skl_set_cdclk(struct drm_i915_private *dev_priv,
@@ -834,11 +885,11 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv,
break;
}
- if (dev_priv->cdclk_pll.vco != 0 &&
- dev_priv->cdclk_pll.vco != vco)
+ if (dev_priv->cdclk.hw.vco != 0 &&
+ dev_priv->cdclk.hw.vco != vco)
skl_dpll0_disable(dev_priv);
- if (dev_priv->cdclk_pll.vco != vco)
+ if (dev_priv->cdclk.hw.vco != vco)
skl_dpll0_enable(dev_priv, vco);
I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk));
@@ -866,8 +917,8 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
intel_update_cdclk(dev_priv);
/* Is PLL enabled and locked ? */
- if (dev_priv->cdclk_pll.vco == 0 ||
- dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
+ if (dev_priv->cdclk.hw.vco == 0 ||
+ dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref)
goto sanitize;
/* DPLL okay; verify the cdclock
@@ -878,7 +929,7 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
*/
cdctl = I915_READ(CDCLK_CTL);
expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
- skl_cdclk_decimal(dev_priv->cdclk_freq);
+ skl_cdclk_decimal(dev_priv->cdclk.hw.cdclk);
if (cdctl == expected)
/* All well; nothing to sanitize */
return;
@@ -887,14 +938,14 @@ static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
/* force cdclk programming */
- dev_priv->cdclk_freq = 0;
+ dev_priv->cdclk.hw.cdclk = 0;
/* force full PLL disable + enable */
- dev_priv->cdclk_pll.vco = -1;
+ dev_priv->cdclk.hw.vco = -1;
}
void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
{
- skl_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0);
+ skl_set_cdclk(dev_priv, dev_priv->cdclk.hw.ref, 0);
}
void skl_init_cdclk(struct drm_i915_private *dev_priv)
@@ -903,14 +954,15 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv)
skl_sanitize_cdclk(dev_priv);
- if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0) {
+ if (dev_priv->cdclk.hw.cdclk != 0 &&
+ dev_priv->cdclk.hw.vco != 0) {
/*
* Use the current vco as our initial
* guess as to what the preferred vco is.
*/
if (dev_priv->skl_preferred_vco_freq == 0)
skl_set_preferred_cdclk_vco(dev_priv,
- dev_priv->cdclk_pll.vco);
+ dev_priv->cdclk.hw.vco);
return;
}
@@ -950,7 +1002,7 @@ static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
{
int ratio;
- if (cdclk == dev_priv->cdclk_pll.ref)
+ if (cdclk == dev_priv->cdclk.hw.ref)
return 0;
switch (cdclk) {
@@ -967,14 +1019,14 @@ static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
break;
}
- return dev_priv->cdclk_pll.ref * ratio;
+ return dev_priv->cdclk.hw.ref * ratio;
}
static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
{
int ratio;
- if (cdclk == dev_priv->cdclk_pll.ref)
+ if (cdclk == dev_priv->cdclk.hw.ref)
return 0;
switch (cdclk) {
@@ -987,15 +1039,16 @@ static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
break;
}
- return dev_priv->cdclk_pll.ref * ratio;
+ return dev_priv->cdclk.hw.ref * ratio;
}
-static void bxt_de_pll_update(struct drm_i915_private *dev_priv)
+static void bxt_de_pll_update(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
u32 val;
- dev_priv->cdclk_pll.ref = 19200;
- dev_priv->cdclk_pll.vco = 0;
+ cdclk_state->ref = 19200;
+ cdclk_state->vco = 0;
val = I915_READ(BXT_DE_PLL_ENABLE);
if ((val & BXT_DE_PLL_PLL_ENABLE) == 0)
@@ -1005,20 +1058,21 @@ static void bxt_de_pll_update(struct drm_i915_private *dev_priv)
return;
val = I915_READ(BXT_DE_PLL_CTL);
- dev_priv->cdclk_pll.vco = (val & BXT_DE_PLL_RATIO_MASK) *
- dev_priv->cdclk_pll.ref;
+ cdclk_state->vco = (val & BXT_DE_PLL_RATIO_MASK) * cdclk_state->ref;
}
-static int bxt_get_cdclk(struct drm_i915_private *dev_priv)
+static void bxt_get_cdclk(struct drm_i915_private *dev_priv,
+ struct intel_cdclk_state *cdclk_state)
{
u32 divider;
- int div, vco;
+ int div;
- bxt_de_pll_update(dev_priv);
+ bxt_de_pll_update(dev_priv, cdclk_state);
- vco = dev_priv->cdclk_pll.vco;
- if (vco == 0)
- return dev_priv->cdclk_pll.ref;
+ cdclk_state->cdclk = cdclk_state->ref;
+
+ if (cdclk_state->vco == 0)
+ return;
divider = I915_READ(CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK;
@@ -1038,10 +1092,10 @@ static int bxt_get_cdclk(struct drm_i915_private *dev_priv)
break;
default:
MISSING_CASE(divider);
- return dev_priv->cdclk_pll.ref;
+ return;
}
- return DIV_ROUND_CLOSEST(vco, div);
+ cdclk_state->cdclk = DIV_ROUND_CLOSEST(cdclk_state->vco, div);
}
static void bxt_de_pll_disable(struct drm_i915_private *dev_priv)
@@ -1054,12 +1108,12 @@ static void bxt_de_pll_disable(struct drm_i915_private *dev_priv)
1))
DRM_ERROR("timeout waiting for DE PLL unlock\n");
- dev_priv->cdclk_pll.vco = 0;
+ dev_priv->cdclk.hw.vco = 0;
}
static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
{
- int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk_pll.ref);
+ int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk.hw.ref);
u32 val;
val = I915_READ(BXT_DE_PLL_CTL);
@@ -1077,7 +1131,7 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
1))
DRM_ERROR("timeout waiting for DE PLL lock\n");
- dev_priv->cdclk_pll.vco = vco;
+ dev_priv->cdclk.hw.vco = vco;
}
static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
@@ -1105,7 +1159,7 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
divider = BXT_CDCLK_CD2X_DIV_SEL_1;
break;
default:
- WARN_ON(cdclk != dev_priv->cdclk_pll.ref);
+ WARN_ON(cdclk != dev_priv->cdclk.hw.ref);
WARN_ON(vco != 0);
divider = BXT_CDCLK_CD2X_DIV_SEL_1;
@@ -1124,11 +1178,11 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
return;
}
- if (dev_priv->cdclk_pll.vco != 0 &&
- dev_priv->cdclk_pll.vco != vco)
+ if (dev_priv->cdclk.hw.vco != 0 &&
+ dev_priv->cdclk.hw.vco != vco)
bxt_de_pll_disable(dev_priv);
- if (dev_priv->cdclk_pll.vco != vco)
+ if (dev_priv->cdclk.hw.vco != vco)
bxt_de_pll_enable(dev_priv, vco);
val = divider | skl_cdclk_decimal(cdclk);
@@ -1165,8 +1219,8 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
intel_update_cdclk(dev_priv);
- if (dev_priv->cdclk_pll.vco == 0 ||
- dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
+ if (dev_priv->cdclk.hw.vco == 0 ||
+ dev_priv->cdclk.hw.cdclk == dev_priv->cdclk.hw.ref)
goto sanitize;
/* DPLL okay; verify the cdclock
@@ -1184,12 +1238,12 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE;
expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) |
- skl_cdclk_decimal(dev_priv->cdclk_freq);
+ skl_cdclk_decimal(dev_priv->cdclk.hw.cdclk);
/*
* Disable SSA Precharge when CD clock frequency < 500 MHz,
* enable otherwise.
*/
- if (dev_priv->cdclk_freq >= 500000)
+ if (dev_priv->cdclk.hw.cdclk >= 500000)
expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
if (cdctl == expected)
@@ -1200,10 +1254,10 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
/* force cdclk programming */
- dev_priv->cdclk_freq = 0;
+ dev_priv->cdclk.hw.cdclk = 0;
/* force full PLL disable + enable */
- dev_priv->cdclk_pll.vco = -1;
+ dev_priv->cdclk.hw.vco = -1;
}
void bxt_init_cdclk(struct drm_i915_private *dev_priv)
@@ -1212,7 +1266,8 @@ void bxt_init_cdclk(struct drm_i915_private *dev_priv)
bxt_sanitize_cdclk(dev_priv);
- if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0)
+ if (dev_priv->cdclk.hw.cdclk != 0 &&
+ dev_priv->cdclk.hw.vco != 0)
return;
/*
@@ -1233,7 +1288,13 @@ void bxt_init_cdclk(struct drm_i915_private *dev_priv)
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
{
- bxt_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0);
+ bxt_set_cdclk(dev_priv, dev_priv->cdclk.hw.ref, 0);
+}
+
+bool intel_cdclk_state_compare(struct intel_cdclk_state *a,
+ struct intel_cdclk_state *b)
+{
+ return memcmp(a, b, sizeof(*a)) == 0;
}
static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
@@ -1533,7 +1594,7 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
dev_priv->max_cdclk_freq = 400000;
} else {
/* otherwise assume cdclk is fixed */
- dev_priv->max_cdclk_freq = dev_priv->cdclk_freq;
+ dev_priv->max_cdclk_freq = dev_priv->cdclk.hw.cdclk;
}
dev_priv->max_dotclk_freq = intel_compute_max_dotclk(dev_priv);
@@ -1547,15 +1608,11 @@ void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
void intel_update_cdclk(struct drm_i915_private *dev_priv)
{
- dev_priv->cdclk_freq = dev_priv->display.get_cdclk(dev_priv);
+ dev_priv->display.get_cdclk(dev_priv, &dev_priv->cdclk.hw);
- if (INTEL_GEN(dev_priv) >= 9)
- DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n",
- dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco,
- dev_priv->cdclk_pll.ref);
- else
- DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n",
- dev_priv->cdclk_freq);
+ DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n",
+ dev_priv->cdclk.hw.cdclk, dev_priv->cdclk.hw.vco,
+ dev_priv->cdclk.hw.ref);
/*
* 9:0 CMBUS [sic] CDCLK frequency (cdfreq):
@@ -1565,7 +1622,7 @@ void intel_update_cdclk(struct drm_i915_private *dev_priv)
*/
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
I915_WRITE(GMBUSFREQ_VLV,
- DIV_ROUND_UP(dev_priv->cdclk_freq, 1000));
+ DIV_ROUND_UP(dev_priv->cdclk.hw.cdclk, 1000));
}
static int pch_rawclk(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 519e5d663c5f..6c38ab299506 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -136,7 +136,7 @@ struct intel_limit {
};
/* returns HPLL frequency in kHz */
-static int valleyview_get_vco(struct drm_i915_private *dev_priv)
+int vlv_get_hpll_vco(struct drm_i915_private *dev_priv)
{
int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
@@ -172,7 +172,7 @@ int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
const char *name, u32 reg)
{
if (dev_priv->hpll_freq == 0)
- dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
+ dev_priv->hpll_freq = vlv_get_hpll_vco(dev_priv);
return vlv_get_cck_clock(dev_priv, name, reg,
dev_priv->hpll_freq);
@@ -12436,7 +12436,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
*/
if (dev_priv->display.modeset_calc_cdclk) {
if (!intel_state->cdclk_pll_vco)
- intel_state->cdclk_pll_vco = dev_priv->cdclk_pll.vco;
+ intel_state->cdclk_pll_vco = dev_priv->cdclk.hw.vco;
if (!intel_state->cdclk_pll_vco)
intel_state->cdclk_pll_vco = dev_priv->skl_preferred_vco_freq;
@@ -12456,8 +12456,8 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
}
/* All pipes must be switched off while we change the cdclk. */
- if (intel_state->dev_cdclk != dev_priv->cdclk_freq ||
- intel_state->cdclk_pll_vco != dev_priv->cdclk_pll.vco) {
+ if (intel_state->dev_cdclk != dev_priv->cdclk.hw.cdclk ||
+ intel_state->cdclk_pll_vco != dev_priv->cdclk.hw.vco) {
ret = intel_modeset_all_pipes(state);
if (ret < 0)
return ret;
@@ -12874,8 +12874,8 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_update_legacy_modeset_state(state->dev, state);
if (dev_priv->display.modeset_commit_cdclk &&
- (intel_state->dev_cdclk != dev_priv->cdclk_freq ||
- intel_state->cdclk_pll_vco != dev_priv->cdclk_pll.vco))
+ (intel_state->dev_cdclk != dev_priv->cdclk.hw.cdclk ||
+ intel_state->cdclk_pll_vco != dev_priv->cdclk.hw.vco))
dev_priv->display.modeset_commit_cdclk(state);
/*
@@ -14724,7 +14724,7 @@ void intel_modeset_init_hw(struct drm_device *dev)
intel_update_cdclk(dev_priv);
- dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
+ dev_priv->atomic_cdclk_freq = dev_priv->cdclk.hw.cdclk;
intel_init_clock_gating(dev_priv);
}
@@ -14897,7 +14897,7 @@ int intel_modeset_init(struct drm_device *dev)
intel_update_czclk(dev_priv);
intel_update_cdclk(dev_priv);
- dev_priv->atomic_cdclk_freq = dev_priv->cdclk_freq;
+ dev_priv->atomic_cdclk_freq = dev_priv->cdclk.hw.cdclk;
intel_shared_dpll_init(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 45ebc9632633..73a708b8d887 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -885,7 +885,7 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
* divide by 2000 and use that
*/
if (intel_dig_port->port == PORT_A)
- return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
+ return DIV_ROUND_CLOSEST(dev_priv->cdclk.hw.cdclk, 2000);
else
return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8d93b7bda3ff..c062f063bfbc 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1225,10 +1225,13 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv);
void intel_update_max_cdclk(struct drm_i915_private *dev_priv);
void intel_update_cdclk(struct drm_i915_private *dev_priv);
void intel_update_rawclk(struct drm_i915_private *dev_priv);
+bool intel_cdclk_state_compare(struct intel_cdclk_state *a,
+ struct intel_cdclk_state *b);
/* intel_display.c */
enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc);
void intel_update_rawclk(struct drm_i915_private *dev_priv);
+int vlv_get_hpll_vco(struct drm_i915_private *dev_priv);
int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
const char *name, u32 reg, int ref_freq);
int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index 463056d80f9b..385251e48c74 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -829,7 +829,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
/* WaFbcExceedCdClockThreshold:hsw,bdw */
if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
- cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk_freq * 95 / 100) {
+ cache->crtc.hsw_bdw_pixel_rate >= dev_priv->cdclk.hw.cdclk * 95 / 100) {
fbc->no_fbc_reason = "pixel rate is too big";
return false;
}
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 1a6ff26dea20..cb50c527401f 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -1315,7 +1315,7 @@ static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
if (IS_PINEVIEW(dev_priv))
clock = KHz(dev_priv->rawclk_freq);
else
- clock = KHz(dev_priv->cdclk_freq);
+ clock = KHz(dev_priv->cdclk.hw.cdclk);
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
}
@@ -1333,7 +1333,7 @@ static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
if (IS_G4X(dev_priv))
clock = KHz(dev_priv->rawclk_freq);
else
- clock = KHz(dev_priv->cdclk_freq);
+ clock = KHz(dev_priv->cdclk.hw.cdclk);
return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
}
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 6d5efeb35823..14bbecc8f2ed 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -964,9 +964,12 @@ static void gen9_assert_dbuf_enabled(struct drm_i915_private *dev_priv)
static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
+ struct intel_cdclk_state cdclk_state = {};
+
gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
- WARN_ON(dev_priv->cdclk_freq != dev_priv->display.get_cdclk(dev_priv));
+ dev_priv->display.get_cdclk(dev_priv, &cdclk_state);
+ WARN_ON(!intel_cdclk_state_compare(&dev_priv->cdclk.hw, &cdclk_state));
gen9_assert_dbuf_enabled(dev_priv);
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 06/14] drm/i915: Pass computed vco to bxt_set_cdclk()
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Rather than compute the vco inside bxt_set_cdclk() let's precompute it
outside and pass it in. A small step towards a fully precomputed cdclk
state.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_cdclk.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 1804c43553b7..89be610d0879 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -1080,15 +1080,11 @@ static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
dev_priv->cdclk_pll.vco = vco;
}
-static void bxt_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
+static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
+ int cdclk, int vco)
{
u32 val, divider;
- int vco, ret;
-
- if (IS_GEMINILAKE(dev_priv))
- vco = glk_de_pll_vco(dev_priv, cdclk);
- else
- vco = bxt_de_pll_vco(dev_priv, cdclk);
+ int ret;
DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n",
cdclk, vco);
@@ -1212,7 +1208,7 @@ static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
void bxt_init_cdclk(struct drm_i915_private *dev_priv)
{
- int cdclk;
+ int cdclk, vco;
bxt_sanitize_cdclk(dev_priv);
@@ -1224,17 +1220,20 @@ void bxt_init_cdclk(struct drm_i915_private *dev_priv)
* - The initial CDCLK needs to be read from VBT.
* Need to make this change after VBT has changes for BXT.
*/
- if (IS_GEMINILAKE(dev_priv))
+ if (IS_GEMINILAKE(dev_priv)) {
cdclk = glk_calc_cdclk(0);
- else
+ vco = glk_de_pll_vco(dev_priv, cdclk);
+ } else {
cdclk = bxt_calc_cdclk(0);
+ vco = bxt_de_pll_vco(dev_priv, cdclk);
+ }
- bxt_set_cdclk(dev_priv, cdclk);
+ bxt_set_cdclk(dev_priv, cdclk, vco);
}
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
{
- bxt_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref);
+ bxt_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0);
}
static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
@@ -1454,12 +1453,18 @@ static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
{
- struct drm_device *dev = old_state->dev;
+ struct drm_i915_private *dev_priv = to_i915(old_state->dev);
struct intel_atomic_state *old_intel_state =
to_intel_atomic_state(old_state);
unsigned int req_cdclk = old_intel_state->dev_cdclk;
+ unsigned int req_vco;
- bxt_set_cdclk(to_i915(dev), req_cdclk);
+ if (IS_GEMINILAKE(dev_priv))
+ req_vco = glk_de_pll_vco(dev_priv, req_cdclk);
+ else
+ req_vco = bxt_de_pll_vco(dev_priv, req_cdclk);
+
+ bxt_set_cdclk(dev_priv, req_cdclk, req_vco);
}
static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
* [PATCH 05/14] drm/i915: Move most cdclk/rawclk related code to intel_cdclk.c
From: ville.syrjala @ 2016-12-19 12:34 UTC (permalink / raw)
To: intel-gfx; +Cc: Rodrigo Vivi
In-Reply-To: <20161219123501.3750-1-ville.syrjala@linux.intel.com>
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Let's try to shrink intel_display.c a bit by moving the cdclk/rawclk
stuff to a new file. It's all reasonably self contained so we don't
even have to add that many non-static symbols.
We'll also take the opportunity to shuffle around the functions a bit
to get things in a more consistent order based on the platform.
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/intel_cdclk.c | 1690 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_display.c | 1677 +--------------------------------
drivers/gpu/drm/i915/intel_drv.h | 9 +-
4 files changed, 1703 insertions(+), 1674 deletions(-)
create mode 100644 drivers/gpu/drm/i915/intel_cdclk.c
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5196509e71cf..3f5c21b76e85 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -70,6 +70,7 @@ i915-y += intel_audio.o \
intel_atomic.o \
intel_atomic_plane.o \
intel_bios.o \
+ intel_cdclk.o \
intel_color.o \
intel_display.o \
intel_dpio_phy.o \
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
new file mode 100644
index 000000000000..1804c43553b7
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright © 2006-2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "intel_drv.h"
+
+static int fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 133333;
+}
+
+static int fixed_200mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 200000;
+}
+
+static int fixed_266mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 266667;
+}
+
+static int fixed_333mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 333333;
+}
+
+static int fixed_400mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 400000;
+}
+
+static int fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return 450000;
+}
+
+static int i85x_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ u16 hpllcc = 0;
+
+ /*
+ * 852GM/852GMV only supports 133 MHz and the HPLLCC
+ * encoding is different :(
+ * FIXME is this the right way to detect 852GM/852GMV?
+ */
+ if (pdev->revision == 0x1)
+ return 133333;
+
+ pci_bus_read_config_word(pdev->bus,
+ PCI_DEVFN(0, 3), HPLLCC, &hpllcc);
+
+ /* Assume that the hardware is in the high speed state. This
+ * should be the default.
+ */
+ switch (hpllcc & GC_CLOCK_CONTROL_MASK) {
+ case GC_CLOCK_133_200:
+ case GC_CLOCK_133_200_2:
+ case GC_CLOCK_100_200:
+ return 200000;
+ case GC_CLOCK_166_250:
+ return 250000;
+ case GC_CLOCK_100_133:
+ return 133333;
+ case GC_CLOCK_133_266:
+ case GC_CLOCK_133_266_2:
+ case GC_CLOCK_166_266:
+ return 266667;
+ }
+
+ /* Shouldn't happen */
+ return 0;
+}
+
+static int i915gm_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ u16 gcfgc = 0;
+
+ pci_read_config_word(pdev, GCFGC, &gcfgc);
+
+ if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
+ return 133333;
+
+ switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
+ case GC_DISPLAY_CLOCK_333_MHZ:
+ return 333333;
+ default:
+ case GC_DISPLAY_CLOCK_190_200_MHZ:
+ return 190000;
+ }
+}
+
+static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv)
+{
+ static const unsigned int blb_vco[8] = {
+ [0] = 3200000,
+ [1] = 4000000,
+ [2] = 5333333,
+ [3] = 4800000,
+ [4] = 6400000,
+ };
+ static const unsigned int pnv_vco[8] = {
+ [0] = 3200000,
+ [1] = 4000000,
+ [2] = 5333333,
+ [3] = 4800000,
+ [4] = 2666667,
+ };
+ static const unsigned int cl_vco[8] = {
+ [0] = 3200000,
+ [1] = 4000000,
+ [2] = 5333333,
+ [3] = 6400000,
+ [4] = 3333333,
+ [5] = 3566667,
+ [6] = 4266667,
+ };
+ static const unsigned int elk_vco[8] = {
+ [0] = 3200000,
+ [1] = 4000000,
+ [2] = 5333333,
+ [3] = 4800000,
+ };
+ static const unsigned int ctg_vco[8] = {
+ [0] = 3200000,
+ [1] = 4000000,
+ [2] = 5333333,
+ [3] = 6400000,
+ [4] = 2666667,
+ [5] = 4266667,
+ };
+ const unsigned int *vco_table;
+ unsigned int vco;
+ uint8_t tmp = 0;
+
+ /* FIXME other chipsets? */
+ if (IS_GM45(dev_priv))
+ vco_table = ctg_vco;
+ else if (IS_G4X(dev_priv))
+ vco_table = elk_vco;
+ else if (IS_I965GM(dev_priv))
+ vco_table = cl_vco;
+ else if (IS_PINEVIEW(dev_priv))
+ vco_table = pnv_vco;
+ else if (IS_G33(dev_priv))
+ vco_table = blb_vco;
+ else
+ return 0;
+
+ tmp = I915_READ(IS_MOBILE(dev_priv) ? HPLLVCO_MOBILE : HPLLVCO);
+
+ vco = vco_table[tmp & 0x7];
+ if (vco == 0)
+ DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp);
+ else
+ DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco);
+
+ return vco;
+}
+
+static int g33_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 };
+ static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 };
+ static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 };
+ static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 };
+ const uint8_t *div_table;
+ unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ uint16_t tmp = 0;
+
+ pci_read_config_word(pdev, GCFGC, &tmp);
+
+ cdclk_sel = (tmp >> 4) & 0x7;
+
+ if (cdclk_sel >= ARRAY_SIZE(div_3200))
+ goto fail;
+
+ switch (vco) {
+ case 3200000:
+ div_table = div_3200;
+ break;
+ case 4000000:
+ div_table = div_4000;
+ break;
+ case 4800000:
+ div_table = div_4800;
+ break;
+ case 5333333:
+ div_table = div_5333;
+ break;
+ default:
+ goto fail;
+ }
+
+ return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
+
+fail:
+ DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n",
+ vco, tmp);
+ return 190476;
+}
+
+static int pnv_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ u16 gcfgc = 0;
+
+ pci_read_config_word(pdev, GCFGC, &gcfgc);
+
+ switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
+ case GC_DISPLAY_CLOCK_267_MHZ_PNV:
+ return 266667;
+ case GC_DISPLAY_CLOCK_333_MHZ_PNV:
+ return 333333;
+ case GC_DISPLAY_CLOCK_444_MHZ_PNV:
+ return 444444;
+ case GC_DISPLAY_CLOCK_200_MHZ_PNV:
+ return 200000;
+ default:
+ DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
+ case GC_DISPLAY_CLOCK_133_MHZ_PNV:
+ return 133333;
+ case GC_DISPLAY_CLOCK_167_MHZ_PNV:
+ return 166667;
+ }
+}
+
+static int i965gm_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ static const uint8_t div_3200[] = { 16, 10, 8 };
+ static const uint8_t div_4000[] = { 20, 12, 10 };
+ static const uint8_t div_5333[] = { 24, 16, 14 };
+ const uint8_t *div_table;
+ unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ uint16_t tmp = 0;
+
+ pci_read_config_word(pdev, GCFGC, &tmp);
+
+ cdclk_sel = ((tmp >> 8) & 0x1f) - 1;
+
+ if (cdclk_sel >= ARRAY_SIZE(div_3200))
+ goto fail;
+
+ switch (vco) {
+ case 3200000:
+ div_table = div_3200;
+ break;
+ case 4000000:
+ div_table = div_4000;
+ break;
+ case 5333333:
+ div_table = div_5333;
+ break;
+ default:
+ goto fail;
+ }
+
+ return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
+
+fail:
+ DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n",
+ vco, tmp);
+ return 200000;
+}
+
+static int gm45_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ struct pci_dev *pdev = dev_priv->drm.pdev;
+ unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
+ uint16_t tmp = 0;
+
+ pci_read_config_word(pdev, GCFGC, &tmp);
+
+ cdclk_sel = (tmp >> 12) & 0x1;
+
+ switch (vco) {
+ case 2666667:
+ case 4000000:
+ case 5333333:
+ return cdclk_sel ? 333333 : 222222;
+ case 3200000:
+ return cdclk_sel ? 320000 : 228571;
+ default:
+ DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n",
+ vco, tmp);
+ return 222222;
+ }
+}
+
+static int hsw_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ uint32_t lcpll = I915_READ(LCPLL_CTL);
+ uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+
+ if (lcpll & LCPLL_CD_SOURCE_FCLK)
+ return 800000;
+ else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_450)
+ return 450000;
+ else if (IS_HSW_ULT(dev_priv))
+ return 337500;
+ else
+ return 540000;
+}
+
+static int vlv_calc_cdclk(struct drm_i915_private *dev_priv,
+ int max_pixclk)
+{
+ int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ?
+ 333333 : 320000;
+ int limit = IS_CHERRYVIEW(dev_priv) ? 95 : 90;
+
+ /*
+ * We seem to get an unstable or solid color picture at 200MHz.
+ * Not sure what's wrong. For now use 200MHz only when all pipes
+ * are off.
+ */
+ if (!IS_CHERRYVIEW(dev_priv) &&
+ max_pixclk > freq_320*limit/100)
+ return 400000;
+ else if (max_pixclk > 266667*limit/100)
+ return freq_320;
+ else if (max_pixclk > 0)
+ return 266667;
+ else
+ return 200000;
+}
+
+static int vlv_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ return vlv_get_cck_clock_hpll(dev_priv, "cdclk",
+ CCK_DISPLAY_CLOCK_CONTROL);
+}
+
+static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
+{
+ unsigned int credits, default_credits;
+
+ if (IS_CHERRYVIEW(dev_priv))
+ default_credits = PFI_CREDIT(12);
+ else
+ default_credits = PFI_CREDIT(8);
+
+ if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) {
+ /* CHV suggested value is 31 or 63 */
+ if (IS_CHERRYVIEW(dev_priv))
+ credits = PFI_CREDIT_63;
+ else
+ credits = PFI_CREDIT(15);
+ } else {
+ credits = default_credits;
+ }
+
+ /*
+ * WA - write default credits before re-programming
+ * FIXME: should we also set the resend bit here?
+ */
+ I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
+ default_credits);
+
+ I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
+ credits | PFI_CREDIT_RESEND);
+
+ /*
+ * FIXME is this guaranteed to clear
+ * immediately or should we poll for it?
+ */
+ WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
+}
+
+static void vlv_set_cdclk(struct drm_device *dev, int cdclk)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ u32 val, cmd;
+
+ WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
+
+ if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
+ cmd = 2;
+ else if (cdclk == 266667)
+ cmd = 1;
+ else
+ cmd = 0;
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+ val &= ~DSPFREQGUAR_MASK;
+ val |= (cmd << DSPFREQGUAR_SHIFT);
+ vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
+ if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
+ DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT),
+ 50)) {
+ DRM_ERROR("timed out waiting for CDclk change\n");
+ }
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ if (cdclk == 400000) {
+ u32 divider;
+
+ divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1,
+ cdclk) - 1;
+
+ /* adjust cdclk divider */
+ val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
+ val &= ~CCK_FREQUENCY_VALUES;
+ val |= divider;
+ vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val);
+
+ if (wait_for((vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL) &
+ CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT),
+ 50))
+ DRM_ERROR("timed out waiting for CDclk change\n");
+ }
+
+ /* adjust self-refresh exit latency value */
+ val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC);
+ val &= ~0x7f;
+
+ /*
+ * For high bandwidth configs, we set a higher latency in the bunit
+ * so that the core display fetch happens in time to avoid underruns.
+ */
+ if (cdclk == 400000)
+ val |= 4500 / 250; /* 4.5 usec */
+ else
+ val |= 3000 / 250; /* 3.0 usec */
+ vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val);
+
+ mutex_unlock(&dev_priv->sb_lock);
+
+ intel_update_cdclk(dev_priv);
+}
+
+static void chv_set_cdclk(struct drm_device *dev, int cdclk)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ u32 val, cmd;
+
+ WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
+
+ switch (cdclk) {
+ case 333333:
+ case 320000:
+ case 266667:
+ case 200000:
+ break;
+ default:
+ MISSING_CASE(cdclk);
+ return;
+ }
+
+ /*
+ * Specs are full of misinformation, but testing on actual
+ * hardware has shown that we just need to write the desired
+ * CCK divider into the Punit register.
+ */
+ cmd = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+ val &= ~DSPFREQGUAR_MASK_CHV;
+ val |= (cmd << DSPFREQGUAR_SHIFT_CHV);
+ vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
+ if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
+ DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV),
+ 50)) {
+ DRM_ERROR("timed out waiting for CDclk change\n");
+ }
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ intel_update_cdclk(dev_priv);
+}
+
+static int bdw_calc_cdclk(int max_pixclk)
+{
+ if (max_pixclk > 540000)
+ return 675000;
+ else if (max_pixclk > 450000)
+ return 540000;
+ else if (max_pixclk > 337500)
+ return 450000;
+ else
+ return 337500;
+}
+
+static int bdw_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ uint32_t lcpll = I915_READ(LCPLL_CTL);
+ uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+
+ if (lcpll & LCPLL_CD_SOURCE_FCLK)
+ return 800000;
+ else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_450)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_54O_BDW)
+ return 540000;
+ else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
+ return 337500;
+ else
+ return 675000;
+}
+
+static void bdw_set_cdclk(struct drm_device *dev, int cdclk)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ uint32_t val, data;
+ int ret;
+
+ if (WARN((I915_READ(LCPLL_CTL) &
+ (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK |
+ LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE |
+ LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW |
+ LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK,
+ "trying to change cdclk frequency with cdclk not enabled\n"))
+ return;
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = sandybridge_pcode_write(dev_priv,
+ BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+ if (ret) {
+ DRM_ERROR("failed to inform pcode about cdclk change\n");
+ return;
+ }
+
+ val = I915_READ(LCPLL_CTL);
+ val |= LCPLL_CD_SOURCE_FCLK;
+ I915_WRITE(LCPLL_CTL, val);
+
+ if (wait_for_us(I915_READ(LCPLL_CTL) &
+ LCPLL_CD_SOURCE_FCLK_DONE, 1))
+ DRM_ERROR("Switching to FCLK failed\n");
+
+ val = I915_READ(LCPLL_CTL);
+ val &= ~LCPLL_CLK_FREQ_MASK;
+
+ switch (cdclk) {
+ case 450000:
+ val |= LCPLL_CLK_FREQ_450;
+ data = 0;
+ break;
+ case 540000:
+ val |= LCPLL_CLK_FREQ_54O_BDW;
+ data = 1;
+ break;
+ case 337500:
+ val |= LCPLL_CLK_FREQ_337_5_BDW;
+ data = 2;
+ break;
+ case 675000:
+ val |= LCPLL_CLK_FREQ_675_BDW;
+ data = 3;
+ break;
+ default:
+ WARN(1, "invalid cdclk frequency\n");
+ return;
+ }
+
+ I915_WRITE(LCPLL_CTL, val);
+
+ val = I915_READ(LCPLL_CTL);
+ val &= ~LCPLL_CD_SOURCE_FCLK;
+ I915_WRITE(LCPLL_CTL, val);
+
+ if (wait_for_us((I915_READ(LCPLL_CTL) &
+ LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
+ DRM_ERROR("Switching back to LCPLL failed\n");
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, data);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ I915_WRITE(CDCLK_FREQ, DIV_ROUND_CLOSEST(cdclk, 1000) - 1);
+
+ intel_update_cdclk(dev_priv);
+
+ WARN(cdclk != dev_priv->cdclk_freq,
+ "cdclk requested %d kHz but got %d kHz\n",
+ cdclk, dev_priv->cdclk_freq);
+}
+
+static int skl_calc_cdclk(int max_pixclk, int vco)
+{
+ if (vco == 8640000) {
+ if (max_pixclk > 540000)
+ return 617143;
+ else if (max_pixclk > 432000)
+ return 540000;
+ else if (max_pixclk > 308571)
+ return 432000;
+ else
+ return 308571;
+ } else {
+ if (max_pixclk > 540000)
+ return 675000;
+ else if (max_pixclk > 450000)
+ return 540000;
+ else if (max_pixclk > 337500)
+ return 450000;
+ else
+ return 337500;
+ }
+}
+
+static void skl_dpll0_update(struct drm_i915_private *dev_priv)
+{
+ u32 val;
+
+ dev_priv->cdclk_pll.ref = 24000;
+ dev_priv->cdclk_pll.vco = 0;
+
+ val = I915_READ(LCPLL1_CTL);
+ if ((val & LCPLL_PLL_ENABLE) == 0)
+ return;
+
+ if (WARN_ON((val & LCPLL_PLL_LOCK) == 0))
+ return;
+
+ val = I915_READ(DPLL_CTRL1);
+
+ if (WARN_ON((val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) |
+ DPLL_CTRL1_SSC(SKL_DPLL0) |
+ DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) !=
+ DPLL_CTRL1_OVERRIDE(SKL_DPLL0)))
+ return;
+
+ switch (val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) {
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0):
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0):
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0):
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0):
+ dev_priv->cdclk_pll.vco = 8100000;
+ break;
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0):
+ case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0):
+ dev_priv->cdclk_pll.vco = 8640000;
+ break;
+ default:
+ MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
+ break;
+ }
+}
+
+static int skl_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ u32 cdctl;
+
+ skl_dpll0_update(dev_priv);
+
+ if (dev_priv->cdclk_pll.vco == 0)
+ return dev_priv->cdclk_pll.ref;
+
+ cdctl = I915_READ(CDCLK_CTL);
+
+ if (dev_priv->cdclk_pll.vco == 8640000) {
+ switch (cdctl & CDCLK_FREQ_SEL_MASK) {
+ case CDCLK_FREQ_450_432:
+ return 432000;
+ case CDCLK_FREQ_337_308:
+ return 308571;
+ case CDCLK_FREQ_540:
+ return 540000;
+ case CDCLK_FREQ_675_617:
+ return 617143;
+ default:
+ MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
+ }
+ } else {
+ switch (cdctl & CDCLK_FREQ_SEL_MASK) {
+ case CDCLK_FREQ_450_432:
+ return 450000;
+ case CDCLK_FREQ_337_308:
+ return 337500;
+ case CDCLK_FREQ_540:
+ return 540000;
+ case CDCLK_FREQ_675_617:
+ return 675000;
+ default:
+ MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
+ }
+ }
+
+ return dev_priv->cdclk_pll.ref;
+}
+
+/* convert from kHz to .1 fixpoint MHz with -1MHz offset */
+static int skl_cdclk_decimal(int cdclk)
+{
+ return DIV_ROUND_CLOSEST(cdclk - 1000, 500);
+}
+
+static void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv,
+ int vco)
+{
+ bool changed = dev_priv->skl_preferred_vco_freq != vco;
+
+ dev_priv->skl_preferred_vco_freq = vco;
+
+ if (changed)
+ intel_update_max_cdclk(dev_priv);
+}
+
+static void skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)
+{
+ int min_cdclk = skl_calc_cdclk(0, vco);
+ u32 val;
+
+ WARN_ON(vco != 8100000 && vco != 8640000);
+
+ /* select the minimum CDCLK before enabling DPLL 0 */
+ val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk);
+ I915_WRITE(CDCLK_CTL, val);
+ POSTING_READ(CDCLK_CTL);
+
+ /*
+ * We always enable DPLL0 with the lowest link rate possible, but still
+ * taking into account the VCO required to operate the eDP panel at the
+ * desired frequency. The usual DP link rates operate with a VCO of
+ * 8100 while the eDP 1.4 alternate link rates need a VCO of 8640.
+ * The modeset code is responsible for the selection of the exact link
+ * rate later on, with the constraint of choosing a frequency that
+ * works with vco.
+ */
+ val = I915_READ(DPLL_CTRL1);
+
+ val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) |
+ DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
+ val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
+ if (vco == 8640000)
+ val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
+ SKL_DPLL0);
+ else
+ val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
+ SKL_DPLL0);
+
+ I915_WRITE(DPLL_CTRL1, val);
+ POSTING_READ(DPLL_CTRL1);
+
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) | LCPLL_PLL_ENABLE);
+
+ if (intel_wait_for_register(dev_priv,
+ LCPLL1_CTL, LCPLL_PLL_LOCK, LCPLL_PLL_LOCK,
+ 5))
+ DRM_ERROR("DPLL0 not locked\n");
+
+ dev_priv->cdclk_pll.vco = vco;
+
+ /* We'll want to keep using the current vco from now on. */
+ skl_set_preferred_cdclk_vco(dev_priv, vco);
+}
+
+static void skl_dpll0_disable(struct drm_i915_private *dev_priv)
+{
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
+ if (intel_wait_for_register(dev_priv,
+ LCPLL1_CTL, LCPLL_PLL_LOCK, 0,
+ 1))
+ DRM_ERROR("Couldn't disable DPLL0\n");
+
+ dev_priv->cdclk_pll.vco = 0;
+}
+
+static void skl_set_cdclk(struct drm_i915_private *dev_priv,
+ int cdclk, int vco)
+{
+ u32 freq_select, pcu_ack;
+ int ret;
+
+ WARN_ON((cdclk == 24000) != (vco == 0));
+
+ DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n",
+ cdclk, vco);
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL,
+ SKL_CDCLK_PREPARE_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE,
+ SKL_CDCLK_READY_FOR_CHANGE, 3);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+ if (ret) {
+ DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n",
+ ret);
+ return;
+ }
+
+ /* set CDCLK_CTL */
+ switch (cdclk) {
+ case 450000:
+ case 432000:
+ freq_select = CDCLK_FREQ_450_432;
+ pcu_ack = 1;
+ break;
+ case 540000:
+ freq_select = CDCLK_FREQ_540;
+ pcu_ack = 2;
+ break;
+ case 308571:
+ case 337500:
+ default:
+ freq_select = CDCLK_FREQ_337_308;
+ pcu_ack = 0;
+ break;
+ case 617143:
+ case 675000:
+ freq_select = CDCLK_FREQ_675_617;
+ pcu_ack = 3;
+ break;
+ }
+
+ if (dev_priv->cdclk_pll.vco != 0 &&
+ dev_priv->cdclk_pll.vco != vco)
+ skl_dpll0_disable(dev_priv);
+
+ if (dev_priv->cdclk_pll.vco != vco)
+ skl_dpll0_enable(dev_priv, vco);
+
+ I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk));
+ POSTING_READ(CDCLK_CTL);
+
+ /* inform PCU of the change */
+ mutex_lock(&dev_priv->rps.hw_lock);
+ sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ intel_update_cdclk(dev_priv);
+}
+
+static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
+{
+ uint32_t cdctl, expected;
+
+ /*
+ * check if the pre-os initialized the display
+ * There is SWF18 scratchpad register defined which is set by the
+ * pre-os which can be used by the OS drivers to check the status
+ */
+ if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0)
+ goto sanitize;
+
+ intel_update_cdclk(dev_priv);
+ /* Is PLL enabled and locked ? */
+ if (dev_priv->cdclk_pll.vco == 0 ||
+ dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
+ goto sanitize;
+
+ /* DPLL okay; verify the cdclock
+ *
+ * Noticed in some instances that the freq selection is correct but
+ * decimal part is programmed wrong from BIOS where pre-os does not
+ * enable display. Verify the same as well.
+ */
+ cdctl = I915_READ(CDCLK_CTL);
+ expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
+ skl_cdclk_decimal(dev_priv->cdclk_freq);
+ if (cdctl == expected)
+ /* All well; nothing to sanitize */
+ return;
+
+sanitize:
+ DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
+
+ /* force cdclk programming */
+ dev_priv->cdclk_freq = 0;
+ /* force full PLL disable + enable */
+ dev_priv->cdclk_pll.vco = -1;
+}
+
+void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
+{
+ skl_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0);
+}
+
+void skl_init_cdclk(struct drm_i915_private *dev_priv)
+{
+ int cdclk, vco;
+
+ skl_sanitize_cdclk(dev_priv);
+
+ if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0) {
+ /*
+ * Use the current vco as our initial
+ * guess as to what the preferred vco is.
+ */
+ if (dev_priv->skl_preferred_vco_freq == 0)
+ skl_set_preferred_cdclk_vco(dev_priv,
+ dev_priv->cdclk_pll.vco);
+ return;
+ }
+
+ vco = dev_priv->skl_preferred_vco_freq;
+ if (vco == 0)
+ vco = 8100000;
+ cdclk = skl_calc_cdclk(0, vco);
+
+ skl_set_cdclk(dev_priv, cdclk, vco);
+}
+
+static int bxt_calc_cdclk(int max_pixclk)
+{
+ if (max_pixclk > 576000)
+ return 624000;
+ else if (max_pixclk > 384000)
+ return 576000;
+ else if (max_pixclk > 288000)
+ return 384000;
+ else if (max_pixclk > 144000)
+ return 288000;
+ else
+ return 144000;
+}
+
+static int glk_calc_cdclk(int max_pixclk)
+{
+ if (max_pixclk > 2 * 158400)
+ return 316800;
+ else if (max_pixclk > 2 * 79200)
+ return 158400;
+ else
+ return 79200;
+}
+
+static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
+{
+ int ratio;
+
+ if (cdclk == dev_priv->cdclk_pll.ref)
+ return 0;
+
+ switch (cdclk) {
+ default:
+ MISSING_CASE(cdclk);
+ case 144000:
+ case 288000:
+ case 384000:
+ case 576000:
+ ratio = 60;
+ break;
+ case 624000:
+ ratio = 65;
+ break;
+ }
+
+ return dev_priv->cdclk_pll.ref * ratio;
+}
+
+static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
+{
+ int ratio;
+
+ if (cdclk == dev_priv->cdclk_pll.ref)
+ return 0;
+
+ switch (cdclk) {
+ default:
+ MISSING_CASE(cdclk);
+ case 79200:
+ case 158400:
+ case 316800:
+ ratio = 33;
+ break;
+ }
+
+ return dev_priv->cdclk_pll.ref * ratio;
+}
+
+static void bxt_de_pll_update(struct drm_i915_private *dev_priv)
+{
+ u32 val;
+
+ dev_priv->cdclk_pll.ref = 19200;
+ dev_priv->cdclk_pll.vco = 0;
+
+ val = I915_READ(BXT_DE_PLL_ENABLE);
+ if ((val & BXT_DE_PLL_PLL_ENABLE) == 0)
+ return;
+
+ if (WARN_ON((val & BXT_DE_PLL_LOCK) == 0))
+ return;
+
+ val = I915_READ(BXT_DE_PLL_CTL);
+ dev_priv->cdclk_pll.vco = (val & BXT_DE_PLL_RATIO_MASK) *
+ dev_priv->cdclk_pll.ref;
+}
+
+static int bxt_get_cdclk(struct drm_i915_private *dev_priv)
+{
+ u32 divider;
+ int div, vco;
+
+ bxt_de_pll_update(dev_priv);
+
+ vco = dev_priv->cdclk_pll.vco;
+ if (vco == 0)
+ return dev_priv->cdclk_pll.ref;
+
+ divider = I915_READ(CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK;
+
+ switch (divider) {
+ case BXT_CDCLK_CD2X_DIV_SEL_1:
+ div = 2;
+ break;
+ case BXT_CDCLK_CD2X_DIV_SEL_1_5:
+ WARN(IS_GEMINILAKE(dev_priv), "Unsupported divider\n");
+ div = 3;
+ break;
+ case BXT_CDCLK_CD2X_DIV_SEL_2:
+ div = 4;
+ break;
+ case BXT_CDCLK_CD2X_DIV_SEL_4:
+ div = 8;
+ break;
+ default:
+ MISSING_CASE(divider);
+ return dev_priv->cdclk_pll.ref;
+ }
+
+ return DIV_ROUND_CLOSEST(vco, div);
+}
+
+static void bxt_de_pll_disable(struct drm_i915_private *dev_priv)
+{
+ I915_WRITE(BXT_DE_PLL_ENABLE, 0);
+
+ /* Timeout 200us */
+ if (intel_wait_for_register(dev_priv,
+ BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 0,
+ 1))
+ DRM_ERROR("timeout waiting for DE PLL unlock\n");
+
+ dev_priv->cdclk_pll.vco = 0;
+}
+
+static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
+{
+ int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk_pll.ref);
+ u32 val;
+
+ val = I915_READ(BXT_DE_PLL_CTL);
+ val &= ~BXT_DE_PLL_RATIO_MASK;
+ val |= BXT_DE_PLL_RATIO(ratio);
+ I915_WRITE(BXT_DE_PLL_CTL, val);
+
+ I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE);
+
+ /* Timeout 200us */
+ if (intel_wait_for_register(dev_priv,
+ BXT_DE_PLL_ENABLE,
+ BXT_DE_PLL_LOCK,
+ BXT_DE_PLL_LOCK,
+ 1))
+ DRM_ERROR("timeout waiting for DE PLL lock\n");
+
+ dev_priv->cdclk_pll.vco = vco;
+}
+
+static void bxt_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
+{
+ u32 val, divider;
+ int vco, ret;
+
+ if (IS_GEMINILAKE(dev_priv))
+ vco = glk_de_pll_vco(dev_priv, cdclk);
+ else
+ vco = bxt_de_pll_vco(dev_priv, cdclk);
+
+ DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n",
+ cdclk, vco);
+
+ /* cdclk = vco / 2 / div{1,1.5,2,4} */
+ switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
+ case 8:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_4;
+ break;
+ case 4:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_2;
+ break;
+ case 3:
+ WARN(IS_GEMINILAKE(dev_priv), "Unsupported divider\n");
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1_5;
+ break;
+ case 2:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1;
+ break;
+ default:
+ WARN_ON(cdclk != dev_priv->cdclk_pll.ref);
+ WARN_ON(vco != 0);
+
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1;
+ break;
+ }
+
+ /* Inform power controller of upcoming frequency change */
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ 0x80000000);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ if (ret) {
+ DRM_ERROR("PCode CDCLK freq change notify failed (err %d, freq %d)\n",
+ ret, cdclk);
+ return;
+ }
+
+ if (dev_priv->cdclk_pll.vco != 0 &&
+ dev_priv->cdclk_pll.vco != vco)
+ bxt_de_pll_disable(dev_priv);
+
+ if (dev_priv->cdclk_pll.vco != vco)
+ bxt_de_pll_enable(dev_priv, vco);
+
+ val = divider | skl_cdclk_decimal(cdclk);
+ /*
+ * FIXME if only the cd2x divider needs changing, it could be done
+ * without shutting off the pipe (if only one pipe is active).
+ */
+ val |= BXT_CDCLK_CD2X_PIPE_NONE;
+ /*
+ * Disable SSA Precharge when CD clock frequency < 500 MHz,
+ * enable otherwise.
+ */
+ if (cdclk >= 500000)
+ val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+ I915_WRITE(CDCLK_CTL, val);
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ DIV_ROUND_UP(cdclk, 25000));
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ if (ret) {
+ DRM_ERROR("PCode CDCLK freq set failed, (err %d, freq %d)\n",
+ ret, cdclk);
+ return;
+ }
+
+ intel_update_cdclk(dev_priv);
+}
+
+static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
+{
+ u32 cdctl, expected;
+
+ intel_update_cdclk(dev_priv);
+
+ if (dev_priv->cdclk_pll.vco == 0 ||
+ dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
+ goto sanitize;
+
+ /* DPLL okay; verify the cdclock
+ *
+ * Some BIOS versions leave an incorrect decimal frequency value and
+ * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
+ * so sanitize this register.
+ */
+ cdctl = I915_READ(CDCLK_CTL);
+ /*
+ * Let's ignore the pipe field, since BIOS could have configured the
+ * dividers both synching to an active pipe, or asynchronously
+ * (PIPE_NONE).
+ */
+ cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE;
+
+ expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) |
+ skl_cdclk_decimal(dev_priv->cdclk_freq);
+ /*
+ * Disable SSA Precharge when CD clock frequency < 500 MHz,
+ * enable otherwise.
+ */
+ if (dev_priv->cdclk_freq >= 500000)
+ expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+
+ if (cdctl == expected)
+ /* All well; nothing to sanitize */
+ return;
+
+sanitize:
+ DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
+
+ /* force cdclk programming */
+ dev_priv->cdclk_freq = 0;
+
+ /* force full PLL disable + enable */
+ dev_priv->cdclk_pll.vco = -1;
+}
+
+void bxt_init_cdclk(struct drm_i915_private *dev_priv)
+{
+ int cdclk;
+
+ bxt_sanitize_cdclk(dev_priv);
+
+ if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0)
+ return;
+
+ /*
+ * FIXME:
+ * - The initial CDCLK needs to be read from VBT.
+ * Need to make this change after VBT has changes for BXT.
+ */
+ if (IS_GEMINILAKE(dev_priv))
+ cdclk = glk_calc_cdclk(0);
+ else
+ cdclk = bxt_calc_cdclk(0);
+
+ bxt_set_cdclk(dev_priv, cdclk);
+}
+
+void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
+{
+ bxt_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref);
+}
+
+static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
+ int pixel_rate)
+{
+ struct drm_i915_private *dev_priv =
+ to_i915(crtc_state->base.crtc->dev);
+
+ /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
+ if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
+ pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95);
+
+ /* BSpec says "Do not use DisplayPort with CDCLK less than
+ * 432 MHz, audio enabled, port width x4, and link rate
+ * HBR2 (5.4 GHz), or else there may be audio corruption or
+ * screen corruption."
+ */
+ if (intel_crtc_has_dp_encoder(crtc_state) &&
+ crtc_state->has_audio &&
+ crtc_state->port_clock >= 540000 &&
+ crtc_state->lane_count == 4)
+ pixel_rate = max(432000, pixel_rate);
+
+ return pixel_rate;
+}
+
+/* compute the max rate for new configuration */
+static int intel_max_pixel_rate(struct drm_atomic_state *state)
+{
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *cstate;
+ struct intel_crtc_state *crtc_state;
+ unsigned int max_pixel_rate = 0, i;
+ enum pipe pipe;
+
+ memcpy(intel_state->min_pixclk, dev_priv->min_pixclk,
+ sizeof(intel_state->min_pixclk));
+
+ for_each_crtc_in_state(state, crtc, cstate, i) {
+ int pixel_rate;
+
+ crtc_state = to_intel_crtc_state(cstate);
+ if (!crtc_state->base.enable) {
+ intel_state->min_pixclk[i] = 0;
+ continue;
+ }
+
+ pixel_rate = crtc_state->pixel_rate;
+
+ if (IS_BROADWELL(dev_priv) || IS_GEN9(dev_priv))
+ pixel_rate =
+ bdw_adjust_min_pipe_pixel_rate(crtc_state,
+ pixel_rate);
+
+ intel_state->min_pixclk[i] = pixel_rate;
+ }
+
+ for_each_pipe(dev_priv, pipe)
+ max_pixel_rate = max(intel_state->min_pixclk[pipe],
+ max_pixel_rate);
+
+ return max_pixel_rate;
+}
+
+static int vlv_modeset_calc_cdclk(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ int max_pixclk = intel_max_pixel_rate(state);
+ struct intel_atomic_state *intel_state =
+ to_intel_atomic_state(state);
+
+ intel_state->cdclk = intel_state->dev_cdclk =
+ vlv_calc_cdclk(dev_priv, max_pixclk);
+
+ if (!intel_state->active_crtcs)
+ intel_state->dev_cdclk = vlv_calc_cdclk(dev_priv, 0);
+
+ return 0;
+}
+
+static void vlv_modeset_commit_cdclk(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_atomic_state *old_intel_state =
+ to_intel_atomic_state(old_state);
+ unsigned int req_cdclk = old_intel_state->dev_cdclk;
+
+ /*
+ * FIXME: We can end up here with all power domains off, yet
+ * with a CDCLK frequency other than the minimum. To account
+ * for this take the PIPE-A power domain, which covers the HW
+ * blocks needed for the following programming. This can be
+ * removed once it's guaranteed that we get here either with
+ * the minimum CDCLK set, or the required power domains
+ * enabled.
+ */
+ intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
+
+ if (IS_CHERRYVIEW(dev_priv))
+ chv_set_cdclk(dev, req_cdclk);
+ else
+ vlv_set_cdclk(dev, req_cdclk);
+
+ vlv_program_pfi_credits(dev_priv);
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
+}
+
+static int bdw_modeset_calc_cdclk(struct drm_atomic_state *state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ int max_pixclk = intel_max_pixel_rate(state);
+ int cdclk;
+
+ /*
+ * FIXME should also account for plane ratio
+ * once 64bpp pixel formats are supported.
+ */
+ cdclk = bdw_calc_cdclk(max_pixclk);
+
+ if (cdclk > dev_priv->max_cdclk_freq) {
+ DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ return -EINVAL;
+ }
+
+ intel_state->cdclk = intel_state->dev_cdclk = cdclk;
+ if (!intel_state->active_crtcs)
+ intel_state->dev_cdclk = bdw_calc_cdclk(0);
+
+ return 0;
+}
+
+static void bdw_modeset_commit_cdclk(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+ struct intel_atomic_state *old_intel_state =
+ to_intel_atomic_state(old_state);
+ unsigned int req_cdclk = old_intel_state->dev_cdclk;
+
+ bdw_set_cdclk(dev, req_cdclk);
+}
+
+static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
+{
+ struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
+ const int max_pixclk = intel_max_pixel_rate(state);
+ int vco = intel_state->cdclk_pll_vco;
+ int cdclk;
+
+ /*
+ * FIXME should also account for plane ratio
+ * once 64bpp pixel formats are supported.
+ */
+ cdclk = skl_calc_cdclk(max_pixclk, vco);
+
+ /*
+ * FIXME move the cdclk caclulation to
+ * compute_config() so we can fail gracegully.
+ */
+ if (cdclk > dev_priv->max_cdclk_freq) {
+ DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
+ cdclk, dev_priv->max_cdclk_freq);
+ cdclk = dev_priv->max_cdclk_freq;
+ }
+
+ intel_state->cdclk = intel_state->dev_cdclk = cdclk;
+ if (!intel_state->active_crtcs)
+ intel_state->dev_cdclk = skl_calc_cdclk(0, vco);
+
+ return 0;
+}
+
+static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state)
+{
+ struct drm_i915_private *dev_priv = to_i915(old_state->dev);
+ struct intel_atomic_state *intel_state =
+ to_intel_atomic_state(old_state);
+ unsigned int req_cdclk = intel_state->dev_cdclk;
+ unsigned int req_vco = intel_state->cdclk_pll_vco;
+
+ skl_set_cdclk(dev_priv, req_cdclk, req_vco);
+}
+
+static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
+ int max_pixclk = intel_max_pixel_rate(state);
+ struct intel_atomic_state *intel_state =
+ to_intel_atomic_state(state);
+ int cdclk;
+
+ if (IS_GEMINILAKE(dev_priv))
+ cdclk = glk_calc_cdclk(max_pixclk);
+ else
+ cdclk = bxt_calc_cdclk(max_pixclk);
+
+ intel_state->cdclk = intel_state->dev_cdclk = cdclk;
+
+ if (!intel_state->active_crtcs) {
+ if (IS_GEMINILAKE(dev_priv))
+ cdclk = glk_calc_cdclk(0);
+ else
+ cdclk = bxt_calc_cdclk(0);
+
+ intel_state->dev_cdclk = cdclk;
+ }
+
+ return 0;
+}
+
+static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+ struct intel_atomic_state *old_intel_state =
+ to_intel_atomic_state(old_state);
+ unsigned int req_cdclk = old_intel_state->dev_cdclk;
+
+ bxt_set_cdclk(to_i915(dev), req_cdclk);
+}
+
+static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
+{
+ int max_cdclk_freq = dev_priv->max_cdclk_freq;
+
+ if (IS_GEMINILAKE(dev_priv))
+ return 2 * max_cdclk_freq;
+ else if (INTEL_INFO(dev_priv)->gen >= 9 ||
+ IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+ return max_cdclk_freq;
+ else if (IS_CHERRYVIEW(dev_priv))
+ return max_cdclk_freq*95/100;
+ else if (INTEL_INFO(dev_priv)->gen < 4)
+ return 2*max_cdclk_freq*90/100;
+ else
+ return max_cdclk_freq*90/100;
+}
+
+void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
+{
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+ u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
+ int max_cdclk, vco;
+
+ vco = dev_priv->skl_preferred_vco_freq;
+ WARN_ON(vco != 8100000 && vco != 8640000);
+
+ /*
+ * Use the lower (vco 8640) cdclk values as a
+ * first guess. skl_calc_cdclk() will correct it
+ * if the preferred vco is 8100 instead.
+ */
+ if (limit == SKL_DFSM_CDCLK_LIMIT_675)
+ max_cdclk = 617143;
+ else if (limit == SKL_DFSM_CDCLK_LIMIT_540)
+ max_cdclk = 540000;
+ else if (limit == SKL_DFSM_CDCLK_LIMIT_450)
+ max_cdclk = 432000;
+ else
+ max_cdclk = 308571;
+
+ dev_priv->max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco);
+ } else if (IS_GEMINILAKE(dev_priv)) {
+ dev_priv->max_cdclk_freq = 316800;
+ } else if (IS_BROXTON(dev_priv)) {
+ dev_priv->max_cdclk_freq = 624000;
+ } else if (IS_BROADWELL(dev_priv)) {
+ /*
+ * FIXME with extra cooling we can allow
+ * 540 MHz for ULX and 675 Mhz for ULT.
+ * How can we know if extra cooling is
+ * available? PCI ID, VTB, something else?
+ */
+ if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+ dev_priv->max_cdclk_freq = 450000;
+ else if (IS_BDW_ULX(dev_priv))
+ dev_priv->max_cdclk_freq = 450000;
+ else if (IS_BDW_ULT(dev_priv))
+ dev_priv->max_cdclk_freq = 540000;
+ else
+ dev_priv->max_cdclk_freq = 675000;
+ } else if (IS_CHERRYVIEW(dev_priv)) {
+ dev_priv->max_cdclk_freq = 320000;
+ } else if (IS_VALLEYVIEW(dev_priv)) {
+ dev_priv->max_cdclk_freq = 400000;
+ } else {
+ /* otherwise assume cdclk is fixed */
+ dev_priv->max_cdclk_freq = dev_priv->cdclk_freq;
+ }
+
+ dev_priv->max_dotclk_freq = intel_compute_max_dotclk(dev_priv);
+
+ DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n",
+ dev_priv->max_cdclk_freq);
+
+ DRM_DEBUG_DRIVER("Max dotclock rate: %d kHz\n",
+ dev_priv->max_dotclk_freq);
+}
+
+void intel_update_cdclk(struct drm_i915_private *dev_priv)
+{
+ dev_priv->cdclk_freq = dev_priv->display.get_cdclk(dev_priv);
+
+ if (INTEL_GEN(dev_priv) >= 9)
+ DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n",
+ dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco,
+ dev_priv->cdclk_pll.ref);
+ else
+ DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n",
+ dev_priv->cdclk_freq);
+
+ /*
+ * 9:0 CMBUS [sic] CDCLK frequency (cdfreq):
+ * Programmng [sic] note: bit[9:2] should be programmed to the number
+ * of cdclk that generates 4MHz reference clock freq which is used to
+ * generate GMBus clock. This will vary with the cdclk freq.
+ */
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ I915_WRITE(GMBUSFREQ_VLV,
+ DIV_ROUND_UP(dev_priv->cdclk_freq, 1000));
+}
+
+static int pch_rawclk(struct drm_i915_private *dev_priv)
+{
+ return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000;
+}
+
+static int vlv_hrawclk(struct drm_i915_private *dev_priv)
+{
+ /* RAWCLK_FREQ_VLV register updated from power well code */
+ return vlv_get_cck_clock_hpll(dev_priv, "hrawclk",
+ CCK_DISPLAY_REF_CLOCK_CONTROL);
+}
+
+static int g4x_hrawclk(struct drm_i915_private *dev_priv)
+{
+ uint32_t clkcfg;
+
+ /* hrawclock is 1/4 the FSB frequency */
+ clkcfg = I915_READ(CLKCFG);
+ switch (clkcfg & CLKCFG_FSB_MASK) {
+ case CLKCFG_FSB_400:
+ return 100000;
+ case CLKCFG_FSB_533:
+ return 133333;
+ case CLKCFG_FSB_667:
+ return 166667;
+ case CLKCFG_FSB_800:
+ return 200000;
+ case CLKCFG_FSB_1067:
+ return 266667;
+ case CLKCFG_FSB_1333:
+ return 333333;
+ /* these two are just a guess; one of them might be right */
+ case CLKCFG_FSB_1600:
+ case CLKCFG_FSB_1600_ALT:
+ return 400000;
+ default:
+ return 133333;
+ }
+}
+
+void intel_update_rawclk(struct drm_i915_private *dev_priv)
+{
+ if (HAS_PCH_SPLIT(dev_priv))
+ dev_priv->rawclk_freq = pch_rawclk(dev_priv);
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ dev_priv->rawclk_freq = vlv_hrawclk(dev_priv);
+ else if (IS_G4X(dev_priv) || IS_PINEVIEW(dev_priv))
+ dev_priv->rawclk_freq = g4x_hrawclk(dev_priv);
+ else
+ /* no rawclk on other platforms, or no need to know it */
+ return;
+
+ DRM_DEBUG_DRIVER("rawclk rate: %d kHz\n", dev_priv->rawclk_freq);
+}
+
+void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
+{
+ if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+ dev_priv->display.modeset_commit_cdclk =
+ vlv_modeset_commit_cdclk;
+ dev_priv->display.modeset_calc_cdclk =
+ vlv_modeset_calc_cdclk;
+ } else if (IS_BROADWELL(dev_priv)) {
+ dev_priv->display.modeset_commit_cdclk =
+ bdw_modeset_commit_cdclk;
+ dev_priv->display.modeset_calc_cdclk =
+ bdw_modeset_calc_cdclk;
+ } else if (IS_GEN9_LP(dev_priv)) {
+ dev_priv->display.modeset_commit_cdclk =
+ bxt_modeset_commit_cdclk;
+ dev_priv->display.modeset_calc_cdclk =
+ bxt_modeset_calc_cdclk;
+ } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+ dev_priv->display.modeset_commit_cdclk =
+ skl_modeset_commit_cdclk;
+ dev_priv->display.modeset_calc_cdclk =
+ skl_modeset_calc_cdclk;
+ }
+
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+ dev_priv->display.get_cdclk = skl_get_cdclk;
+ else if (IS_GEN9_LP(dev_priv))
+ dev_priv->display.get_cdclk = bxt_get_cdclk;
+ else if (IS_BROADWELL(dev_priv))
+ dev_priv->display.get_cdclk = bdw_get_cdclk;
+ else if (IS_HASWELL(dev_priv))
+ dev_priv->display.get_cdclk = hsw_get_cdclk;
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ dev_priv->display.get_cdclk = vlv_get_cdclk;
+ else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv))
+ dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
+ else if (IS_GEN5(dev_priv))
+ dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk;
+ else if (IS_GM45(dev_priv))
+ dev_priv->display.get_cdclk = gm45_get_cdclk;
+ else if (IS_G4X(dev_priv))
+ dev_priv->display.get_cdclk = g33_get_cdclk;
+ else if (IS_I965GM(dev_priv))
+ dev_priv->display.get_cdclk = i965gm_get_cdclk;
+ else if (IS_I965G(dev_priv))
+ dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
+ else if (IS_PINEVIEW(dev_priv))
+ dev_priv->display.get_cdclk = pnv_get_cdclk;
+ else if (IS_G33(dev_priv))
+ dev_priv->display.get_cdclk = g33_get_cdclk;
+ else if (IS_I945GM(dev_priv))
+ dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk;
+ else if (IS_I945G(dev_priv))
+ dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
+ else if (IS_I915GM(dev_priv))
+ dev_priv->display.get_cdclk = i915gm_get_cdclk;
+ else if (IS_I915G(dev_priv))
+ dev_priv->display.get_cdclk = fixed_333mhz_get_cdclk;
+ else if (IS_I865G(dev_priv))
+ dev_priv->display.get_cdclk = fixed_266mhz_get_cdclk;
+ else if (IS_I85X(dev_priv))
+ dev_priv->display.get_cdclk = i85x_get_cdclk;
+ else if (IS_I845G(dev_priv))
+ dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk;
+ else { /* 830 */
+ WARN(!IS_I830(dev_priv),
+ "Unknown platform. Assuming 133 MHz CDCLK\n");
+ dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk;
+ }
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 29f91e799272..519e5d663c5f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -123,9 +123,6 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
static void ironlake_pfit_enable(struct intel_crtc *crtc);
static void intel_modeset_setup_hw_state(struct drm_device *dev);
static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
-static int intel_max_pixel_rate(struct drm_atomic_state *state);
-static int glk_calc_cdclk(int max_pixclk);
-static int bxt_calc_cdclk(int max_pixclk);
struct intel_limit {
struct {
@@ -171,8 +168,8 @@ int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
return DIV_ROUND_CLOSEST(ref_freq << 1, divider + 1);
}
-static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
- const char *name, u32 reg)
+int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
+ const char *name, u32 reg)
{
if (dev_priv->hpll_freq == 0)
dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
@@ -181,63 +178,6 @@ static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
dev_priv->hpll_freq);
}
-static int
-intel_pch_rawclk(struct drm_i915_private *dev_priv)
-{
- return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000;
-}
-
-static int
-intel_vlv_hrawclk(struct drm_i915_private *dev_priv)
-{
- /* RAWCLK_FREQ_VLV register updated from power well code */
- return vlv_get_cck_clock_hpll(dev_priv, "hrawclk",
- CCK_DISPLAY_REF_CLOCK_CONTROL);
-}
-
-static int
-intel_g4x_hrawclk(struct drm_i915_private *dev_priv)
-{
- uint32_t clkcfg;
-
- /* hrawclock is 1/4 the FSB frequency */
- clkcfg = I915_READ(CLKCFG);
- switch (clkcfg & CLKCFG_FSB_MASK) {
- case CLKCFG_FSB_400:
- return 100000;
- case CLKCFG_FSB_533:
- return 133333;
- case CLKCFG_FSB_667:
- return 166667;
- case CLKCFG_FSB_800:
- return 200000;
- case CLKCFG_FSB_1067:
- return 266667;
- case CLKCFG_FSB_1333:
- return 333333;
- /* these two are just a guess; one of them might be right */
- case CLKCFG_FSB_1600:
- case CLKCFG_FSB_1600_ALT:
- return 400000;
- default:
- return 133333;
- }
-}
-
-void intel_update_rawclk(struct drm_i915_private *dev_priv)
-{
- if (HAS_PCH_SPLIT(dev_priv))
- dev_priv->rawclk_freq = intel_pch_rawclk(dev_priv);
- else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- dev_priv->rawclk_freq = intel_vlv_hrawclk(dev_priv);
- else if (IS_G4X(dev_priv) || IS_PINEVIEW(dev_priv))
- dev_priv->rawclk_freq = intel_g4x_hrawclk(dev_priv);
- else
- return; /* no rawclk on other platforms, or no need to know it */
-
- DRM_DEBUG_DRIVER("rawclk rate: %d kHz\n", dev_priv->rawclk_freq);
-}
-
static void intel_update_czclk(struct drm_i915_private *dev_priv)
{
if (!(IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)))
@@ -5791,888 +5731,6 @@ static void modeset_put_power_domains(struct drm_i915_private *dev_priv,
intel_display_power_put(dev_priv, domain);
}
-static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
-{
- int max_cdclk_freq = dev_priv->max_cdclk_freq;
-
- if (IS_GEMINILAKE(dev_priv))
- return 2 * max_cdclk_freq;
- else if (INTEL_INFO(dev_priv)->gen >= 9 ||
- IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
- return max_cdclk_freq;
- else if (IS_CHERRYVIEW(dev_priv))
- return max_cdclk_freq*95/100;
- else if (INTEL_INFO(dev_priv)->gen < 4)
- return 2*max_cdclk_freq*90/100;
- else
- return max_cdclk_freq*90/100;
-}
-
-static int skl_calc_cdclk(int max_pixclk, int vco);
-
-static void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
-{
- if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
- u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
- int max_cdclk, vco;
-
- vco = dev_priv->skl_preferred_vco_freq;
- WARN_ON(vco != 8100000 && vco != 8640000);
-
- /*
- * Use the lower (vco 8640) cdclk values as a
- * first guess. skl_calc_cdclk() will correct it
- * if the preferred vco is 8100 instead.
- */
- if (limit == SKL_DFSM_CDCLK_LIMIT_675)
- max_cdclk = 617143;
- else if (limit == SKL_DFSM_CDCLK_LIMIT_540)
- max_cdclk = 540000;
- else if (limit == SKL_DFSM_CDCLK_LIMIT_450)
- max_cdclk = 432000;
- else
- max_cdclk = 308571;
-
- dev_priv->max_cdclk_freq = skl_calc_cdclk(max_cdclk, vco);
- } else if (IS_GEMINILAKE(dev_priv)) {
- dev_priv->max_cdclk_freq = 316800;
- } else if (IS_BROXTON(dev_priv)) {
- dev_priv->max_cdclk_freq = 624000;
- } else if (IS_BROADWELL(dev_priv)) {
- /*
- * FIXME with extra cooling we can allow
- * 540 MHz for ULX and 675 Mhz for ULT.
- * How can we know if extra cooling is
- * available? PCI ID, VTB, something else?
- */
- if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
- dev_priv->max_cdclk_freq = 450000;
- else if (IS_BDW_ULX(dev_priv))
- dev_priv->max_cdclk_freq = 450000;
- else if (IS_BDW_ULT(dev_priv))
- dev_priv->max_cdclk_freq = 540000;
- else
- dev_priv->max_cdclk_freq = 675000;
- } else if (IS_CHERRYVIEW(dev_priv)) {
- dev_priv->max_cdclk_freq = 320000;
- } else if (IS_VALLEYVIEW(dev_priv)) {
- dev_priv->max_cdclk_freq = 400000;
- } else {
- /* otherwise assume cdclk is fixed */
- dev_priv->max_cdclk_freq = dev_priv->cdclk_freq;
- }
-
- dev_priv->max_dotclk_freq = intel_compute_max_dotclk(dev_priv);
-
- DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n",
- dev_priv->max_cdclk_freq);
-
- DRM_DEBUG_DRIVER("Max dotclock rate: %d kHz\n",
- dev_priv->max_dotclk_freq);
-}
-
-static void intel_update_cdclk(struct drm_i915_private *dev_priv)
-{
- dev_priv->cdclk_freq = dev_priv->display.get_cdclk(dev_priv);
-
- if (INTEL_GEN(dev_priv) >= 9)
- DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz, VCO: %d kHz, ref: %d kHz\n",
- dev_priv->cdclk_freq, dev_priv->cdclk_pll.vco,
- dev_priv->cdclk_pll.ref);
- else
- DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n",
- dev_priv->cdclk_freq);
-
- /*
- * 9:0 CMBUS [sic] CDCLK frequency (cdfreq):
- * Programmng [sic] note: bit[9:2] should be programmed to the number
- * of cdclk that generates 4MHz reference clock freq which is used to
- * generate GMBus clock. This will vary with the cdclk freq.
- */
- if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000));
-}
-
-/* convert from kHz to .1 fixpoint MHz with -1MHz offset */
-static int skl_cdclk_decimal(int cdclk)
-{
- return DIV_ROUND_CLOSEST(cdclk - 1000, 500);
-}
-
-static int bxt_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
-{
- int ratio;
-
- if (cdclk == dev_priv->cdclk_pll.ref)
- return 0;
-
- switch (cdclk) {
- default:
- MISSING_CASE(cdclk);
- case 144000:
- case 288000:
- case 384000:
- case 576000:
- ratio = 60;
- break;
- case 624000:
- ratio = 65;
- break;
- }
-
- return dev_priv->cdclk_pll.ref * ratio;
-}
-
-static int glk_de_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
-{
- int ratio;
-
- if (cdclk == dev_priv->cdclk_pll.ref)
- return 0;
-
- switch (cdclk) {
- default:
- MISSING_CASE(cdclk);
- case 79200:
- case 158400:
- case 316800:
- ratio = 33;
- break;
- }
-
- return dev_priv->cdclk_pll.ref * ratio;
-}
-
-static void bxt_de_pll_disable(struct drm_i915_private *dev_priv)
-{
- I915_WRITE(BXT_DE_PLL_ENABLE, 0);
-
- /* Timeout 200us */
- if (intel_wait_for_register(dev_priv,
- BXT_DE_PLL_ENABLE, BXT_DE_PLL_LOCK, 0,
- 1))
- DRM_ERROR("timeout waiting for DE PLL unlock\n");
-
- dev_priv->cdclk_pll.vco = 0;
-}
-
-static void bxt_de_pll_enable(struct drm_i915_private *dev_priv, int vco)
-{
- int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk_pll.ref);
- u32 val;
-
- val = I915_READ(BXT_DE_PLL_CTL);
- val &= ~BXT_DE_PLL_RATIO_MASK;
- val |= BXT_DE_PLL_RATIO(ratio);
- I915_WRITE(BXT_DE_PLL_CTL, val);
-
- I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE);
-
- /* Timeout 200us */
- if (intel_wait_for_register(dev_priv,
- BXT_DE_PLL_ENABLE,
- BXT_DE_PLL_LOCK,
- BXT_DE_PLL_LOCK,
- 1))
- DRM_ERROR("timeout waiting for DE PLL lock\n");
-
- dev_priv->cdclk_pll.vco = vco;
-}
-
-static void bxt_set_cdclk(struct drm_i915_private *dev_priv, int cdclk)
-{
- u32 val, divider;
- int vco, ret;
-
- if (IS_GEMINILAKE(dev_priv))
- vco = glk_de_pll_vco(dev_priv, cdclk);
- else
- vco = bxt_de_pll_vco(dev_priv, cdclk);
-
- DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco);
-
- /* cdclk = vco / 2 / div{1,1.5,2,4} */
- switch (DIV_ROUND_CLOSEST(vco, cdclk)) {
- case 8:
- divider = BXT_CDCLK_CD2X_DIV_SEL_4;
- break;
- case 4:
- divider = BXT_CDCLK_CD2X_DIV_SEL_2;
- break;
- case 3:
- WARN(IS_GEMINILAKE(dev_priv), "Unsupported divider\n");
- divider = BXT_CDCLK_CD2X_DIV_SEL_1_5;
- break;
- case 2:
- divider = BXT_CDCLK_CD2X_DIV_SEL_1;
- break;
- default:
- WARN_ON(cdclk != dev_priv->cdclk_pll.ref);
- WARN_ON(vco != 0);
-
- divider = BXT_CDCLK_CD2X_DIV_SEL_1;
- break;
- }
-
- /* Inform power controller of upcoming frequency change */
- mutex_lock(&dev_priv->rps.hw_lock);
- ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
- 0x80000000);
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- if (ret) {
- DRM_ERROR("PCode CDCLK freq change notify failed (err %d, freq %d)\n",
- ret, cdclk);
- return;
- }
-
- if (dev_priv->cdclk_pll.vco != 0 &&
- dev_priv->cdclk_pll.vco != vco)
- bxt_de_pll_disable(dev_priv);
-
- if (dev_priv->cdclk_pll.vco != vco)
- bxt_de_pll_enable(dev_priv, vco);
-
- val = divider | skl_cdclk_decimal(cdclk);
- /*
- * FIXME if only the cd2x divider needs changing, it could be done
- * without shutting off the pipe (if only one pipe is active).
- */
- val |= BXT_CDCLK_CD2X_PIPE_NONE;
- /*
- * Disable SSA Precharge when CD clock frequency < 500 MHz,
- * enable otherwise.
- */
- if (cdclk >= 500000)
- val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
- I915_WRITE(CDCLK_CTL, val);
-
- mutex_lock(&dev_priv->rps.hw_lock);
- ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
- DIV_ROUND_UP(cdclk, 25000));
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- if (ret) {
- DRM_ERROR("PCode CDCLK freq set failed, (err %d, freq %d)\n",
- ret, cdclk);
- return;
- }
-
- intel_update_cdclk(dev_priv);
-}
-
-static void bxt_sanitize_cdclk(struct drm_i915_private *dev_priv)
-{
- u32 cdctl, expected;
-
- intel_update_cdclk(dev_priv);
-
- if (dev_priv->cdclk_pll.vco == 0 ||
- dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
- goto sanitize;
-
- /* DPLL okay; verify the cdclock
- *
- * Some BIOS versions leave an incorrect decimal frequency value and
- * set reserved MBZ bits in CDCLK_CTL at least during exiting from S4,
- * so sanitize this register.
- */
- cdctl = I915_READ(CDCLK_CTL);
- /*
- * Let's ignore the pipe field, since BIOS could have configured the
- * dividers both synching to an active pipe, or asynchronously
- * (PIPE_NONE).
- */
- cdctl &= ~BXT_CDCLK_CD2X_PIPE_NONE;
-
- expected = (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) |
- skl_cdclk_decimal(dev_priv->cdclk_freq);
- /*
- * Disable SSA Precharge when CD clock frequency < 500 MHz,
- * enable otherwise.
- */
- if (dev_priv->cdclk_freq >= 500000)
- expected |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
-
- if (cdctl == expected)
- /* All well; nothing to sanitize */
- return;
-
-sanitize:
- DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
-
- /* force cdclk programming */
- dev_priv->cdclk_freq = 0;
-
- /* force full PLL disable + enable */
- dev_priv->cdclk_pll.vco = -1;
-}
-
-void bxt_init_cdclk(struct drm_i915_private *dev_priv)
-{
- int cdclk;
-
- bxt_sanitize_cdclk(dev_priv);
-
- if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0)
- return;
-
- /*
- * FIXME:
- * - The initial CDCLK needs to be read from VBT.
- * Need to make this change after VBT has changes for BXT.
- */
- if (IS_GEMINILAKE(dev_priv))
- cdclk = glk_calc_cdclk(0);
- else
- cdclk = bxt_calc_cdclk(0);
-
- bxt_set_cdclk(dev_priv, cdclk);
-}
-
-void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
-{
- bxt_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref);
-}
-
-static int skl_calc_cdclk(int max_pixclk, int vco)
-{
- if (vco == 8640000) {
- if (max_pixclk > 540000)
- return 617143;
- else if (max_pixclk > 432000)
- return 540000;
- else if (max_pixclk > 308571)
- return 432000;
- else
- return 308571;
- } else {
- if (max_pixclk > 540000)
- return 675000;
- else if (max_pixclk > 450000)
- return 540000;
- else if (max_pixclk > 337500)
- return 450000;
- else
- return 337500;
- }
-}
-
-static void
-skl_dpll0_update(struct drm_i915_private *dev_priv)
-{
- u32 val;
-
- dev_priv->cdclk_pll.ref = 24000;
- dev_priv->cdclk_pll.vco = 0;
-
- val = I915_READ(LCPLL1_CTL);
- if ((val & LCPLL_PLL_ENABLE) == 0)
- return;
-
- if (WARN_ON((val & LCPLL_PLL_LOCK) == 0))
- return;
-
- val = I915_READ(DPLL_CTRL1);
-
- if (WARN_ON((val & (DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) |
- DPLL_CTRL1_SSC(SKL_DPLL0) |
- DPLL_CTRL1_OVERRIDE(SKL_DPLL0))) !=
- DPLL_CTRL1_OVERRIDE(SKL_DPLL0)))
- return;
-
- switch (val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) {
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0):
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0):
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0):
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0):
- dev_priv->cdclk_pll.vco = 8100000;
- break;
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0):
- case DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0):
- dev_priv->cdclk_pll.vco = 8640000;
- break;
- default:
- MISSING_CASE(val & DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
- break;
- }
-}
-
-void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco)
-{
- bool changed = dev_priv->skl_preferred_vco_freq != vco;
-
- dev_priv->skl_preferred_vco_freq = vco;
-
- if (changed)
- intel_update_max_cdclk(dev_priv);
-}
-
-static void
-skl_dpll0_enable(struct drm_i915_private *dev_priv, int vco)
-{
- int min_cdclk = skl_calc_cdclk(0, vco);
- u32 val;
-
- WARN_ON(vco != 8100000 && vco != 8640000);
-
- /* select the minimum CDCLK before enabling DPLL 0 */
- val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_cdclk);
- I915_WRITE(CDCLK_CTL, val);
- POSTING_READ(CDCLK_CTL);
-
- /*
- * We always enable DPLL0 with the lowest link rate possible, but still
- * taking into account the VCO required to operate the eDP panel at the
- * desired frequency. The usual DP link rates operate with a VCO of
- * 8100 while the eDP 1.4 alternate link rates need a VCO of 8640.
- * The modeset code is responsible for the selection of the exact link
- * rate later on, with the constraint of choosing a frequency that
- * works with vco.
- */
- val = I915_READ(DPLL_CTRL1);
-
- val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) |
- DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
- val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
- if (vco == 8640000)
- val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
- SKL_DPLL0);
- else
- val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
- SKL_DPLL0);
-
- I915_WRITE(DPLL_CTRL1, val);
- POSTING_READ(DPLL_CTRL1);
-
- I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) | LCPLL_PLL_ENABLE);
-
- if (intel_wait_for_register(dev_priv,
- LCPLL1_CTL, LCPLL_PLL_LOCK, LCPLL_PLL_LOCK,
- 5))
- DRM_ERROR("DPLL0 not locked\n");
-
- dev_priv->cdclk_pll.vco = vco;
-
- /* We'll want to keep using the current vco from now on. */
- skl_set_preferred_cdclk_vco(dev_priv, vco);
-}
-
-static void
-skl_dpll0_disable(struct drm_i915_private *dev_priv)
-{
- I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
- if (intel_wait_for_register(dev_priv,
- LCPLL1_CTL, LCPLL_PLL_LOCK, 0,
- 1))
- DRM_ERROR("Couldn't disable DPLL0\n");
-
- dev_priv->cdclk_pll.vco = 0;
-}
-
-static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco)
-{
- u32 freq_select, pcu_ack;
- int ret;
-
- WARN_ON((cdclk == 24000) != (vco == 0));
-
- DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco);
-
- mutex_lock(&dev_priv->rps.hw_lock);
- ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL,
- SKL_CDCLK_PREPARE_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE,
- SKL_CDCLK_READY_FOR_CHANGE, 3);
- mutex_unlock(&dev_priv->rps.hw_lock);
- if (ret) {
- DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n",
- ret);
- return;
- }
-
- /* set CDCLK_CTL */
- switch (cdclk) {
- case 450000:
- case 432000:
- freq_select = CDCLK_FREQ_450_432;
- pcu_ack = 1;
- break;
- case 540000:
- freq_select = CDCLK_FREQ_540;
- pcu_ack = 2;
- break;
- case 308571:
- case 337500:
- default:
- freq_select = CDCLK_FREQ_337_308;
- pcu_ack = 0;
- break;
- case 617143:
- case 675000:
- freq_select = CDCLK_FREQ_675_617;
- pcu_ack = 3;
- break;
- }
-
- if (dev_priv->cdclk_pll.vco != 0 &&
- dev_priv->cdclk_pll.vco != vco)
- skl_dpll0_disable(dev_priv);
-
- if (dev_priv->cdclk_pll.vco != vco)
- skl_dpll0_enable(dev_priv, vco);
-
- I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(cdclk));
- POSTING_READ(CDCLK_CTL);
-
- /* inform PCU of the change */
- mutex_lock(&dev_priv->rps.hw_lock);
- sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack);
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- intel_update_cdclk(dev_priv);
-}
-
-static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv);
-
-void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
-{
- skl_set_cdclk(dev_priv, dev_priv->cdclk_pll.ref, 0);
-}
-
-void skl_init_cdclk(struct drm_i915_private *dev_priv)
-{
- int cdclk, vco;
-
- skl_sanitize_cdclk(dev_priv);
-
- if (dev_priv->cdclk_freq != 0 && dev_priv->cdclk_pll.vco != 0) {
- /*
- * Use the current vco as our initial
- * guess as to what the preferred vco is.
- */
- if (dev_priv->skl_preferred_vco_freq == 0)
- skl_set_preferred_cdclk_vco(dev_priv,
- dev_priv->cdclk_pll.vco);
- return;
- }
-
- vco = dev_priv->skl_preferred_vco_freq;
- if (vco == 0)
- vco = 8100000;
- cdclk = skl_calc_cdclk(0, vco);
-
- skl_set_cdclk(dev_priv, cdclk, vco);
-}
-
-static void skl_sanitize_cdclk(struct drm_i915_private *dev_priv)
-{
- uint32_t cdctl, expected;
-
- /*
- * check if the pre-os intialized the display
- * There is SWF18 scratchpad register defined which is set by the
- * pre-os which can be used by the OS drivers to check the status
- */
- if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0)
- goto sanitize;
-
- intel_update_cdclk(dev_priv);
- /* Is PLL enabled and locked ? */
- if (dev_priv->cdclk_pll.vco == 0 ||
- dev_priv->cdclk_freq == dev_priv->cdclk_pll.ref)
- goto sanitize;
-
- /* DPLL okay; verify the cdclock
- *
- * Noticed in some instances that the freq selection is correct but
- * decimal part is programmed wrong from BIOS where pre-os does not
- * enable display. Verify the same as well.
- */
- cdctl = I915_READ(CDCLK_CTL);
- expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
- skl_cdclk_decimal(dev_priv->cdclk_freq);
- if (cdctl == expected)
- /* All well; nothing to sanitize */
- return;
-
-sanitize:
- DRM_DEBUG_KMS("Sanitizing cdclk programmed by pre-os\n");
-
- /* force cdclk programming */
- dev_priv->cdclk_freq = 0;
- /* force full PLL disable + enable */
- dev_priv->cdclk_pll.vco = -1;
-}
-
-/* Adjust CDclk dividers to allow high res or save power if possible */
-static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
-{
- struct drm_i915_private *dev_priv = to_i915(dev);
- u32 val, cmd;
-
- WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
-
- if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
- cmd = 2;
- else if (cdclk == 266667)
- cmd = 1;
- else
- cmd = 0;
-
- mutex_lock(&dev_priv->rps.hw_lock);
- val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
- val &= ~DSPFREQGUAR_MASK;
- val |= (cmd << DSPFREQGUAR_SHIFT);
- vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
- if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
- DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT),
- 50)) {
- DRM_ERROR("timed out waiting for CDclk change\n");
- }
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- mutex_lock(&dev_priv->sb_lock);
-
- if (cdclk == 400000) {
- u32 divider;
-
- divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
-
- /* adjust cdclk divider */
- val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
- val &= ~CCK_FREQUENCY_VALUES;
- val |= divider;
- vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val);
-
- if (wait_for((vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL) &
- CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT),
- 50))
- DRM_ERROR("timed out waiting for CDclk change\n");
- }
-
- /* adjust self-refresh exit latency value */
- val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC);
- val &= ~0x7f;
-
- /*
- * For high bandwidth configs, we set a higher latency in the bunit
- * so that the core display fetch happens in time to avoid underruns.
- */
- if (cdclk == 400000)
- val |= 4500 / 250; /* 4.5 usec */
- else
- val |= 3000 / 250; /* 3.0 usec */
- vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val);
-
- mutex_unlock(&dev_priv->sb_lock);
-
- intel_update_cdclk(dev_priv);
-}
-
-static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
-{
- struct drm_i915_private *dev_priv = to_i915(dev);
- u32 val, cmd;
-
- WARN_ON(dev_priv->display.get_cdclk(dev_priv) != dev_priv->cdclk_freq);
-
- switch (cdclk) {
- case 333333:
- case 320000:
- case 266667:
- case 200000:
- break;
- default:
- MISSING_CASE(cdclk);
- return;
- }
-
- /*
- * Specs are full of misinformation, but testing on actual
- * hardware has shown that we just need to write the desired
- * CCK divider into the Punit register.
- */
- cmd = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
-
- mutex_lock(&dev_priv->rps.hw_lock);
- val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
- val &= ~DSPFREQGUAR_MASK_CHV;
- val |= (cmd << DSPFREQGUAR_SHIFT_CHV);
- vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
- if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
- DSPFREQSTAT_MASK_CHV) == (cmd << DSPFREQSTAT_SHIFT_CHV),
- 50)) {
- DRM_ERROR("timed out waiting for CDclk change\n");
- }
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- intel_update_cdclk(dev_priv);
-}
-
-static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
- int max_pixclk)
-{
- int freq_320 = (dev_priv->hpll_freq << 1) % 320000 != 0 ? 333333 : 320000;
- int limit = IS_CHERRYVIEW(dev_priv) ? 95 : 90;
-
- /*
- * Really only a few cases to deal with, as only 4 CDclks are supported:
- * 200MHz
- * 267MHz
- * 320/333MHz (depends on HPLL freq)
- * 400MHz (VLV only)
- * So we check to see whether we're above 90% (VLV) or 95% (CHV)
- * of the lower bin and adjust if needed.
- *
- * We seem to get an unstable or solid color picture at 200MHz.
- * Not sure what's wrong. For now use 200MHz only when all pipes
- * are off.
- */
- if (!IS_CHERRYVIEW(dev_priv) &&
- max_pixclk > freq_320*limit/100)
- return 400000;
- else if (max_pixclk > 266667*limit/100)
- return freq_320;
- else if (max_pixclk > 0)
- return 266667;
- else
- return 200000;
-}
-
-static int glk_calc_cdclk(int max_pixclk)
-{
- if (max_pixclk > 2 * 158400)
- return 316800;
- else if (max_pixclk > 2 * 79200)
- return 158400;
- else
- return 79200;
-}
-
-static int bxt_calc_cdclk(int max_pixclk)
-{
- if (max_pixclk > 576000)
- return 624000;
- else if (max_pixclk > 384000)
- return 576000;
- else if (max_pixclk > 288000)
- return 384000;
- else if (max_pixclk > 144000)
- return 288000;
- else
- return 144000;
-}
-
-static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state)
-{
- struct drm_device *dev = state->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- int max_pixclk = intel_max_pixel_rate(state);
- struct intel_atomic_state *intel_state =
- to_intel_atomic_state(state);
-
- intel_state->cdclk = intel_state->dev_cdclk =
- valleyview_calc_cdclk(dev_priv, max_pixclk);
-
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = valleyview_calc_cdclk(dev_priv, 0);
-
- return 0;
-}
-
-static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
-{
- struct drm_i915_private *dev_priv = to_i915(state->dev);
- int max_pixclk = intel_max_pixel_rate(state);
- struct intel_atomic_state *intel_state =
- to_intel_atomic_state(state);
- int cdclk;
-
- if (IS_GEMINILAKE(dev_priv))
- cdclk = glk_calc_cdclk(max_pixclk);
- else
- cdclk = bxt_calc_cdclk(max_pixclk);
-
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
-
- if (!intel_state->active_crtcs) {
- if (IS_GEMINILAKE(dev_priv))
- cdclk = glk_calc_cdclk(0);
- else
- cdclk = bxt_calc_cdclk(0);
-
- intel_state->dev_cdclk = cdclk;
- }
-
- return 0;
-}
-
-static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
-{
- unsigned int credits, default_credits;
-
- if (IS_CHERRYVIEW(dev_priv))
- default_credits = PFI_CREDIT(12);
- else
- default_credits = PFI_CREDIT(8);
-
- if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) {
- /* CHV suggested value is 31 or 63 */
- if (IS_CHERRYVIEW(dev_priv))
- credits = PFI_CREDIT_63;
- else
- credits = PFI_CREDIT(15);
- } else {
- credits = default_credits;
- }
-
- /*
- * WA - write default credits before re-programming
- * FIXME: should we also set the resend bit here?
- */
- I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
- default_credits);
-
- I915_WRITE(GCI_CONTROL, VGA_FAST_MODE_DISABLE |
- credits | PFI_CREDIT_RESEND);
-
- /*
- * FIXME is this guaranteed to clear
- * immediately or should we poll for it?
- */
- WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
-}
-
-static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_device *dev = old_state->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
- unsigned req_cdclk = old_intel_state->dev_cdclk;
-
- /*
- * FIXME: We can end up here with all power domains off, yet
- * with a CDCLK frequency other than the minimum. To account
- * for this take the PIPE-A power domain, which covers the HW
- * blocks needed for the following programming. This can be
- * removed once it's guaranteed that we get here either with
- * the minimum CDCLK set, or the required power domains
- * enabled.
- */
- intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A);
-
- if (IS_CHERRYVIEW(dev_priv))
- cherryview_set_cdclk(dev, req_cdclk);
- else
- valleyview_set_cdclk(dev, req_cdclk);
-
- vlv_program_pfi_credits(dev_priv);
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A);
-}
-
static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config,
struct drm_atomic_state *old_state)
{
@@ -7241,428 +6299,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
return 0;
}
-static int skylake_get_cdclk(struct drm_i915_private *dev_priv)
-{
- u32 cdctl;
-
- skl_dpll0_update(dev_priv);
-
- if (dev_priv->cdclk_pll.vco == 0)
- return dev_priv->cdclk_pll.ref;
-
- cdctl = I915_READ(CDCLK_CTL);
-
- if (dev_priv->cdclk_pll.vco == 8640000) {
- switch (cdctl & CDCLK_FREQ_SEL_MASK) {
- case CDCLK_FREQ_450_432:
- return 432000;
- case CDCLK_FREQ_337_308:
- return 308571;
- case CDCLK_FREQ_540:
- return 540000;
- case CDCLK_FREQ_675_617:
- return 617143;
- default:
- MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
- }
- } else {
- switch (cdctl & CDCLK_FREQ_SEL_MASK) {
- case CDCLK_FREQ_450_432:
- return 450000;
- case CDCLK_FREQ_337_308:
- return 337500;
- case CDCLK_FREQ_540:
- return 540000;
- case CDCLK_FREQ_675_617:
- return 675000;
- default:
- MISSING_CASE(cdctl & CDCLK_FREQ_SEL_MASK);
- }
- }
-
- return dev_priv->cdclk_pll.ref;
-}
-
-static void bxt_de_pll_update(struct drm_i915_private *dev_priv)
-{
- u32 val;
-
- dev_priv->cdclk_pll.ref = 19200;
- dev_priv->cdclk_pll.vco = 0;
-
- val = I915_READ(BXT_DE_PLL_ENABLE);
- if ((val & BXT_DE_PLL_PLL_ENABLE) == 0)
- return;
-
- if (WARN_ON((val & BXT_DE_PLL_LOCK) == 0))
- return;
-
- val = I915_READ(BXT_DE_PLL_CTL);
- dev_priv->cdclk_pll.vco = (val & BXT_DE_PLL_RATIO_MASK) *
- dev_priv->cdclk_pll.ref;
-}
-
-static int broxton_get_cdclk(struct drm_i915_private *dev_priv)
-{
- u32 divider;
- int div, vco;
-
- bxt_de_pll_update(dev_priv);
-
- vco = dev_priv->cdclk_pll.vco;
- if (vco == 0)
- return dev_priv->cdclk_pll.ref;
-
- divider = I915_READ(CDCLK_CTL) & BXT_CDCLK_CD2X_DIV_SEL_MASK;
-
- switch (divider) {
- case BXT_CDCLK_CD2X_DIV_SEL_1:
- div = 2;
- break;
- case BXT_CDCLK_CD2X_DIV_SEL_1_5:
- WARN(IS_GEMINILAKE(dev_priv), "Unsupported divider\n");
- div = 3;
- break;
- case BXT_CDCLK_CD2X_DIV_SEL_2:
- div = 4;
- break;
- case BXT_CDCLK_CD2X_DIV_SEL_4:
- div = 8;
- break;
- default:
- MISSING_CASE(divider);
- return dev_priv->cdclk_pll.ref;
- }
-
- return DIV_ROUND_CLOSEST(vco, div);
-}
-
-static int broadwell_get_cdclk(struct drm_i915_private *dev_priv)
-{
- uint32_t lcpll = I915_READ(LCPLL_CTL);
- uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
-
- if (lcpll & LCPLL_CD_SOURCE_FCLK)
- return 800000;
- else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
- return 450000;
- else if (freq == LCPLL_CLK_FREQ_450)
- return 450000;
- else if (freq == LCPLL_CLK_FREQ_54O_BDW)
- return 540000;
- else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
- return 337500;
- else
- return 675000;
-}
-
-static int haswell_get_cdclk(struct drm_i915_private *dev_priv)
-{
- uint32_t lcpll = I915_READ(LCPLL_CTL);
- uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
-
- if (lcpll & LCPLL_CD_SOURCE_FCLK)
- return 800000;
- else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
- return 450000;
- else if (freq == LCPLL_CLK_FREQ_450)
- return 450000;
- else if (IS_HSW_ULT(dev_priv))
- return 337500;
- else
- return 540000;
-}
-
-static int valleyview_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return vlv_get_cck_clock_hpll(dev_priv, "cdclk",
- CCK_DISPLAY_CLOCK_CONTROL);
-}
-
-static int fixed_450mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 450000;
-}
-
-static int fixed_400mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 400000;
-}
-
-static int fixed_333mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 333333;
-}
-
-static int fixed_200mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 200000;
-}
-
-static int pnv_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- u16 gcfgc = 0;
-
- pci_read_config_word(pdev, GCFGC, &gcfgc);
-
- switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
- case GC_DISPLAY_CLOCK_267_MHZ_PNV:
- return 266667;
- case GC_DISPLAY_CLOCK_333_MHZ_PNV:
- return 333333;
- case GC_DISPLAY_CLOCK_444_MHZ_PNV:
- return 444444;
- case GC_DISPLAY_CLOCK_200_MHZ_PNV:
- return 200000;
- default:
- DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
- case GC_DISPLAY_CLOCK_133_MHZ_PNV:
- return 133333;
- case GC_DISPLAY_CLOCK_167_MHZ_PNV:
- return 166667;
- }
-}
-
-static int i915gm_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- u16 gcfgc = 0;
-
- pci_read_config_word(pdev, GCFGC, &gcfgc);
-
- if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
- return 133333;
- else {
- switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
- case GC_DISPLAY_CLOCK_333_MHZ:
- return 333333;
- default:
- case GC_DISPLAY_CLOCK_190_200_MHZ:
- return 190000;
- }
- }
-}
-
-static int fixed_266mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 266667;
-}
-
-static int i85x_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- u16 hpllcc = 0;
-
- /*
- * 852GM/852GMV only supports 133 MHz and the HPLLCC
- * encoding is different :(
- * FIXME is this the right way to detect 852GM/852GMV?
- */
- if (pdev->revision == 0x1)
- return 133333;
-
- pci_bus_read_config_word(pdev->bus,
- PCI_DEVFN(0, 3), HPLLCC, &hpllcc);
-
- /* Assume that the hardware is in the high speed state. This
- * should be the default.
- */
- switch (hpllcc & GC_CLOCK_CONTROL_MASK) {
- case GC_CLOCK_133_200:
- case GC_CLOCK_133_200_2:
- case GC_CLOCK_100_200:
- return 200000;
- case GC_CLOCK_166_250:
- return 250000;
- case GC_CLOCK_100_133:
- return 133333;
- case GC_CLOCK_133_266:
- case GC_CLOCK_133_266_2:
- case GC_CLOCK_166_266:
- return 266667;
- }
-
- /* Shouldn't happen */
- return 0;
-}
-
-static int fixed_133mhz_get_cdclk(struct drm_i915_private *dev_priv)
-{
- return 133333;
-}
-
-static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv)
-{
- static const unsigned int blb_vco[8] = {
- [0] = 3200000,
- [1] = 4000000,
- [2] = 5333333,
- [3] = 4800000,
- [4] = 6400000,
- };
- static const unsigned int pnv_vco[8] = {
- [0] = 3200000,
- [1] = 4000000,
- [2] = 5333333,
- [3] = 4800000,
- [4] = 2666667,
- };
- static const unsigned int cl_vco[8] = {
- [0] = 3200000,
- [1] = 4000000,
- [2] = 5333333,
- [3] = 6400000,
- [4] = 3333333,
- [5] = 3566667,
- [6] = 4266667,
- };
- static const unsigned int elk_vco[8] = {
- [0] = 3200000,
- [1] = 4000000,
- [2] = 5333333,
- [3] = 4800000,
- };
- static const unsigned int ctg_vco[8] = {
- [0] = 3200000,
- [1] = 4000000,
- [2] = 5333333,
- [3] = 6400000,
- [4] = 2666667,
- [5] = 4266667,
- };
- const unsigned int *vco_table;
- unsigned int vco;
- uint8_t tmp = 0;
-
- /* FIXME other chipsets? */
- if (IS_GM45(dev_priv))
- vco_table = ctg_vco;
- else if (IS_G4X(dev_priv))
- vco_table = elk_vco;
- else if (IS_I965GM(dev_priv))
- vco_table = cl_vco;
- else if (IS_PINEVIEW(dev_priv))
- vco_table = pnv_vco;
- else if (IS_G33(dev_priv))
- vco_table = blb_vco;
- else
- return 0;
-
- tmp = I915_READ(IS_MOBILE(dev_priv) ? HPLLVCO_MOBILE : HPLLVCO);
-
- vco = vco_table[tmp & 0x7];
- if (vco == 0)
- DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp);
- else
- DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco);
-
- return vco;
-}
-
-static int gm45_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
- uint16_t tmp = 0;
-
- pci_read_config_word(pdev, GCFGC, &tmp);
-
- cdclk_sel = (tmp >> 12) & 0x1;
-
- switch (vco) {
- case 2666667:
- case 4000000:
- case 5333333:
- return cdclk_sel ? 333333 : 222222;
- case 3200000:
- return cdclk_sel ? 320000 : 228571;
- default:
- DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", vco, tmp);
- return 222222;
- }
-}
-
-static int i965gm_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- static const uint8_t div_3200[] = { 16, 10, 8 };
- static const uint8_t div_4000[] = { 20, 12, 10 };
- static const uint8_t div_5333[] = { 24, 16, 14 };
- const uint8_t *div_table;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
- uint16_t tmp = 0;
-
- pci_read_config_word(pdev, GCFGC, &tmp);
-
- cdclk_sel = ((tmp >> 8) & 0x1f) - 1;
-
- if (cdclk_sel >= ARRAY_SIZE(div_3200))
- goto fail;
-
- switch (vco) {
- case 3200000:
- div_table = div_3200;
- break;
- case 4000000:
- div_table = div_4000;
- break;
- case 5333333:
- div_table = div_5333;
- break;
- default:
- goto fail;
- }
-
- return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
-
-fail:
- DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp);
- return 200000;
-}
-
-static int g33_get_cdclk(struct drm_i915_private *dev_priv)
-{
- struct pci_dev *pdev = dev_priv->drm.pdev;
- static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 };
- static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 };
- static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 };
- static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 };
- const uint8_t *div_table;
- unsigned int cdclk_sel, vco = intel_hpll_vco(dev_priv);
- uint16_t tmp = 0;
-
- pci_read_config_word(pdev, GCFGC, &tmp);
-
- cdclk_sel = (tmp >> 4) & 0x7;
-
- if (cdclk_sel >= ARRAY_SIZE(div_3200))
- goto fail;
-
- switch (vco) {
- case 3200000:
- div_table = div_3200;
- break;
- case 4000000:
- div_table = div_4000;
- break;
- case 4800000:
- div_table = div_4800;
- break;
- case 5333333:
- div_table = div_5333;
- break;
- default:
- goto fail;
- }
-
- return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]);
-
-fail:
- DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp);
- return 190476;
-}
-
static void
intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
{
@@ -10225,245 +8861,6 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
}
}
-static void bxt_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_device *dev = old_state->dev;
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
- unsigned int req_cdclk = old_intel_state->dev_cdclk;
-
- bxt_set_cdclk(to_i915(dev), req_cdclk);
-}
-
-static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
- int pixel_rate)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
-
- /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */
- if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled)
- pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95);
-
- /* BSpec says "Do not use DisplayPort with CDCLK less than
- * 432 MHz, audio enabled, port width x4, and link rate
- * HBR2 (5.4 GHz), or else there may be audio corruption or
- * screen corruption."
- */
- if (intel_crtc_has_dp_encoder(crtc_state) &&
- crtc_state->has_audio &&
- crtc_state->port_clock >= 540000 &&
- crtc_state->lane_count == 4)
- pixel_rate = max(432000, pixel_rate);
-
- return pixel_rate;
-}
-
-/* compute the max rate for new configuration */
-static int intel_max_pixel_rate(struct drm_atomic_state *state)
-{
- struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
- struct drm_i915_private *dev_priv = to_i915(state->dev);
- struct drm_crtc *crtc;
- struct drm_crtc_state *cstate;
- struct intel_crtc_state *crtc_state;
- unsigned max_pixel_rate = 0, i;
- enum pipe pipe;
-
- memcpy(intel_state->min_pixclk, dev_priv->min_pixclk,
- sizeof(intel_state->min_pixclk));
-
- for_each_crtc_in_state(state, crtc, cstate, i) {
- int pixel_rate;
-
- crtc_state = to_intel_crtc_state(cstate);
- if (!crtc_state->base.enable) {
- intel_state->min_pixclk[i] = 0;
- continue;
- }
-
- pixel_rate = crtc_state->pixel_rate;
-
- if (IS_BROADWELL(dev_priv) || IS_GEN9(dev_priv))
- pixel_rate = bdw_adjust_min_pipe_pixel_rate(crtc_state,
- pixel_rate);
-
- intel_state->min_pixclk[i] = pixel_rate;
- }
-
- for_each_pipe(dev_priv, pipe)
- max_pixel_rate = max(intel_state->min_pixclk[pipe], max_pixel_rate);
-
- return max_pixel_rate;
-}
-
-static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
-{
- struct drm_i915_private *dev_priv = to_i915(dev);
- uint32_t val, data;
- int ret;
-
- if (WARN((I915_READ(LCPLL_CTL) &
- (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK |
- LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE |
- LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW |
- LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK,
- "trying to change cdclk frequency with cdclk not enabled\n"))
- return;
-
- mutex_lock(&dev_priv->rps.hw_lock);
- ret = sandybridge_pcode_write(dev_priv,
- BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0);
- mutex_unlock(&dev_priv->rps.hw_lock);
- if (ret) {
- DRM_ERROR("failed to inform pcode about cdclk change\n");
- return;
- }
-
- val = I915_READ(LCPLL_CTL);
- val |= LCPLL_CD_SOURCE_FCLK;
- I915_WRITE(LCPLL_CTL, val);
-
- if (wait_for_us(I915_READ(LCPLL_CTL) &
- LCPLL_CD_SOURCE_FCLK_DONE, 1))
- DRM_ERROR("Switching to FCLK failed\n");
-
- val = I915_READ(LCPLL_CTL);
- val &= ~LCPLL_CLK_FREQ_MASK;
-
- switch (cdclk) {
- case 450000:
- val |= LCPLL_CLK_FREQ_450;
- data = 0;
- break;
- case 540000:
- val |= LCPLL_CLK_FREQ_54O_BDW;
- data = 1;
- break;
- case 337500:
- val |= LCPLL_CLK_FREQ_337_5_BDW;
- data = 2;
- break;
- case 675000:
- val |= LCPLL_CLK_FREQ_675_BDW;
- data = 3;
- break;
- default:
- WARN(1, "invalid cdclk frequency\n");
- return;
- }
-
- I915_WRITE(LCPLL_CTL, val);
-
- val = I915_READ(LCPLL_CTL);
- val &= ~LCPLL_CD_SOURCE_FCLK;
- I915_WRITE(LCPLL_CTL, val);
-
- if (wait_for_us((I915_READ(LCPLL_CTL) &
- LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
- DRM_ERROR("Switching back to LCPLL failed\n");
-
- mutex_lock(&dev_priv->rps.hw_lock);
- sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, data);
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- I915_WRITE(CDCLK_FREQ, DIV_ROUND_CLOSEST(cdclk, 1000) - 1);
-
- intel_update_cdclk(dev_priv);
-
- WARN(cdclk != dev_priv->cdclk_freq,
- "cdclk requested %d kHz but got %d kHz\n",
- cdclk, dev_priv->cdclk_freq);
-}
-
-static int broadwell_calc_cdclk(int max_pixclk)
-{
- if (max_pixclk > 540000)
- return 675000;
- else if (max_pixclk > 450000)
- return 540000;
- else if (max_pixclk > 337500)
- return 450000;
- else
- return 337500;
-}
-
-static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state)
-{
- struct drm_i915_private *dev_priv = to_i915(state->dev);
- struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
- int max_pixclk = intel_max_pixel_rate(state);
- int cdclk;
-
- /*
- * FIXME should also account for plane ratio
- * once 64bpp pixel formats are supported.
- */
- cdclk = broadwell_calc_cdclk(max_pixclk);
-
- if (cdclk > dev_priv->max_cdclk_freq) {
- DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
- cdclk, dev_priv->max_cdclk_freq);
- return -EINVAL;
- }
-
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = broadwell_calc_cdclk(0);
-
- return 0;
-}
-
-static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_device *dev = old_state->dev;
- struct intel_atomic_state *old_intel_state =
- to_intel_atomic_state(old_state);
- unsigned req_cdclk = old_intel_state->dev_cdclk;
-
- broadwell_set_cdclk(dev, req_cdclk);
-}
-
-static int skl_modeset_calc_cdclk(struct drm_atomic_state *state)
-{
- struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
- struct drm_i915_private *dev_priv = to_i915(state->dev);
- const int max_pixclk = intel_max_pixel_rate(state);
- int vco = intel_state->cdclk_pll_vco;
- int cdclk;
-
- /*
- * FIXME should also account for plane ratio
- * once 64bpp pixel formats are supported.
- */
- cdclk = skl_calc_cdclk(max_pixclk, vco);
-
- /*
- * FIXME move the cdclk caclulation to
- * compute_config() so we can fail gracegully.
- */
- if (cdclk > dev_priv->max_cdclk_freq) {
- DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
- cdclk, dev_priv->max_cdclk_freq);
- cdclk = dev_priv->max_cdclk_freq;
- }
-
- intel_state->cdclk = intel_state->dev_cdclk = cdclk;
- if (!intel_state->active_crtcs)
- intel_state->dev_cdclk = skl_calc_cdclk(0, vco);
-
- return 0;
-}
-
-static void skl_modeset_commit_cdclk(struct drm_atomic_state *old_state)
-{
- struct drm_i915_private *dev_priv = to_i915(old_state->dev);
- struct intel_atomic_state *intel_state = to_intel_atomic_state(old_state);
- unsigned int req_cdclk = intel_state->dev_cdclk;
- unsigned int req_vco = intel_state->cdclk_pll_vco;
-
- skl_set_cdclk(dev_priv, req_cdclk, req_vco);
-}
-
static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state)
{
@@ -16019,6 +14416,8 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
*/
void intel_init_display_hooks(struct drm_i915_private *dev_priv)
{
+ intel_init_cdclk_hooks(dev_priv);
+
if (INTEL_INFO(dev_priv)->gen >= 9) {
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
dev_priv->display.get_initial_plane_config =
@@ -16087,52 +14486,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
dev_priv->display.crtc_disable = i9xx_crtc_disable;
}
- /* Returns the core display clock speed */
- if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
- dev_priv->display.get_cdclk = skylake_get_cdclk;
- else if (IS_GEN9_LP(dev_priv))
- dev_priv->display.get_cdclk = broxton_get_cdclk;
- else if (IS_BROADWELL(dev_priv))
- dev_priv->display.get_cdclk = broadwell_get_cdclk;
- else if (IS_HASWELL(dev_priv))
- dev_priv->display.get_cdclk = haswell_get_cdclk;
- else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
- dev_priv->display.get_cdclk = valleyview_get_cdclk;
- else if (IS_GEN6(dev_priv) || IS_IVYBRIDGE(dev_priv))
- dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
- else if (IS_GEN5(dev_priv))
- dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk;
- else if (IS_GM45(dev_priv))
- dev_priv->display.get_cdclk = gm45_get_cdclk;
- else if (IS_G4X(dev_priv))
- dev_priv->display.get_cdclk = g33_get_cdclk;
- else if (IS_I965GM(dev_priv))
- dev_priv->display.get_cdclk = i965gm_get_cdclk;
- else if (IS_I965G(dev_priv))
- dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
- else if (IS_PINEVIEW(dev_priv))
- dev_priv->display.get_cdclk = pnv_get_cdclk;
- else if (IS_G33(dev_priv))
- dev_priv->display.get_cdclk = g33_get_cdclk;
- else if (IS_I945GM(dev_priv))
- dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk;
- else if (IS_I945G(dev_priv))
- dev_priv->display.get_cdclk = fixed_400mhz_get_cdclk;
- else if (IS_I915GM(dev_priv))
- dev_priv->display.get_cdclk = i915gm_get_cdclk;
- else if (IS_I915G(dev_priv))
- dev_priv->display.get_cdclk = fixed_333mhz_get_cdclk;
- else if (IS_I865G(dev_priv))
- dev_priv->display.get_cdclk = fixed_266mhz_get_cdclk;
- else if (IS_I85X(dev_priv))
- dev_priv->display.get_cdclk = i85x_get_cdclk;
- else if (IS_I845G(dev_priv))
- dev_priv->display.get_cdclk = fixed_200mhz_get_cdclk;
- else { /* 830 */
- WARN(!IS_I830(dev_priv), "Unknown platform. Assuming 133 MHz CDCLK\n");
- dev_priv->display.get_cdclk = fixed_133mhz_get_cdclk;
- }
-
if (IS_GEN5(dev_priv)) {
dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
} else if (IS_GEN6(dev_priv)) {
@@ -16144,28 +14497,6 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
dev_priv->display.fdi_link_train = hsw_fdi_link_train;
}
- if (IS_BROADWELL(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- broadwell_modeset_commit_cdclk;
- dev_priv->display.modeset_calc_cdclk =
- broadwell_modeset_calc_cdclk;
- } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- valleyview_modeset_commit_cdclk;
- dev_priv->display.modeset_calc_cdclk =
- valleyview_modeset_calc_cdclk;
- } else if (IS_GEN9_LP(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- bxt_modeset_commit_cdclk;
- dev_priv->display.modeset_calc_cdclk =
- bxt_modeset_calc_cdclk;
- } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
- dev_priv->display.modeset_commit_cdclk =
- skl_modeset_commit_cdclk;
- dev_priv->display.modeset_calc_cdclk =
- skl_modeset_calc_cdclk;
- }
-
if (dev_priv->info.gen >= 9)
dev_priv->display.update_crtcs = skl_update_crtcs;
else
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3969e786d566..8d93b7bda3ff 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1220,12 +1220,19 @@ void intel_audio_codec_disable(struct intel_encoder *encoder);
void i915_audio_component_init(struct drm_i915_private *dev_priv);
void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
+/* intel_cdclk.c */
+void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv);
+void intel_update_max_cdclk(struct drm_i915_private *dev_priv);
+void intel_update_cdclk(struct drm_i915_private *dev_priv);
+void intel_update_rawclk(struct drm_i915_private *dev_priv);
+
/* intel_display.c */
enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc);
-void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco);
void intel_update_rawclk(struct drm_i915_private *dev_priv);
int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
const char *name, u32 reg, int ref_freq);
+int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
+ const char *name, u32 reg);
void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv);
void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
extern const struct drm_plane_funcs intel_plane_funcs;
--
2.10.2
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox