Merge tag 'drm-intel-next-2014-12-19' of git://anongit.freedesktop.org/drm-intel into drm-next

- plane handling refactoring from Matt Roper and Gustavo Padovan in prep for
  atomic updates
- fixes and more patches for the seqno to request transformation from John
- docbook for fbc from Rodrigo
- prep work for dual-link dsi from Gaurav Signh
- crc fixes from Ville
- special ggtt views infrastructure from Tvrtko Ursulin
- shadow patch copying for the cmd parser from Brad Volkin
- execlist and full ppgtt by default on gen8, for testing for now

* tag 'drm-intel-next-2014-12-19' of git://anongit.freedesktop.org/drm-intel: (131 commits)
  drm/i915: Update DRIVER_DATE to 20141219
  drm/i915: Hold runtime PM during plane commit
  drm/i915: Organize bind_vma funcs
  drm/i915: Organize INSTDONE report for future.
  drm/i915: Organize PDP regs report for future.
  drm/i915: Organize PPGTT init
  drm/i915: Organize Fence registers for future enablement.
  drm/i915: tame the chattermouth (v2)
  drm/i915: Warn about missing context state workarounds only once
  drm/i915: Use true PPGTT in Gen8+ when execlists are enabled
  drm/i915: Skip gunit save/restore for cherryview
  drm/i915/chv: Use timeout mode for RC6 on chv
  drm/i915: Add GPGPU_THREADS_DISPATCHED to the register whitelist
  drm/i915: Tidy up execbuffer command parsing code
  drm/i915: Mark shadow batch buffers as purgeable
  drm/i915: Use batch length instead of object size in command parser
  drm/i915: Use batch pools with the command parser
  drm/i915: Implement a framework for batch buffer pools
  drm/i915: fix use after free during eDP encoder destroying
  drm/i915/skl: Skylake also supports DP MST
  ...
This commit is contained in:
Dave Airlie 2015-01-10 08:46:24 +10:00
Родитель c93546a5e3 0e2cfc005b
Коммит adc31849b2
52 изменённых файлов: 3896 добавлений и 2822 удалений

Просмотреть файл

@ -4035,6 +4035,11 @@ int num_ioctls;</synopsis>
<title>Panel Self Refresh PSR (PSR/SRD)</title> <title>Panel Self Refresh PSR (PSR/SRD)</title>
!Pdrivers/gpu/drm/i915/intel_psr.c Panel Self Refresh (PSR/SRD) !Pdrivers/gpu/drm/i915/intel_psr.c Panel Self Refresh (PSR/SRD)
!Idrivers/gpu/drm/i915/intel_psr.c !Idrivers/gpu/drm/i915/intel_psr.c
</sect2>
<sect2>
<title>Frame Buffer Compression (FBC)</title>
!Pdrivers/gpu/drm/i915/intel_fbc.c Frame Buffer Compression (FBC)
!Idrivers/gpu/drm/i915/intel_fbc.c
</sect2> </sect2>
<sect2> <sect2>
<title>DPIO</title> <title>DPIO</title>
@ -4138,12 +4143,22 @@ int num_ioctls;</synopsis>
<title>Batchbuffer Parsing</title> <title>Batchbuffer Parsing</title>
!Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
!Idrivers/gpu/drm/i915/i915_cmd_parser.c !Idrivers/gpu/drm/i915/i915_cmd_parser.c
</sect2>
<sect2>
<title>Batchbuffer Pools</title>
!Pdrivers/gpu/drm/i915/i915_gem_batch_pool.c batch pool
!Idrivers/gpu/drm/i915/i915_gem_batch_pool.c
</sect2> </sect2>
<sect2> <sect2>
<title>Logical Rings, Logical Ring Contexts and Execlists</title> <title>Logical Rings, Logical Ring Contexts and Execlists</title>
!Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists !Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
!Idrivers/gpu/drm/i915/intel_lrc.c !Idrivers/gpu/drm/i915/intel_lrc.c
</sect2> </sect2>
<sect2>
<title>Global GTT views</title>
!Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views
!Idrivers/gpu/drm/i915/i915_gem_gtt.c
</sect2>
</sect1> </sect1>
<sect1> <sect1>

Просмотреть файл

@ -2658,6 +2658,27 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
} }
EXPORT_SYMBOL(drm_mode_set_config_internal); EXPORT_SYMBOL(drm_mode_set_config_internal);
/**
* drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
* @mode: mode to query
* @hdisplay: hdisplay value to fill in
* @vdisplay: vdisplay value to fill in
*
* The vdisplay value will be doubled if the specified mode is a stereo mode of
* the appropriate layout.
*/
void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
int *hdisplay, int *vdisplay)
{
struct drm_display_mode adjusted;
drm_mode_copy(&adjusted, mode);
drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
*hdisplay = adjusted.crtc_hdisplay;
*vdisplay = adjusted.crtc_vdisplay;
}
EXPORT_SYMBOL(drm_crtc_get_hv_timing);
/** /**
* drm_crtc_check_viewport - Checks that a framebuffer is big enough for the * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
* CRTC viewport * CRTC viewport
@ -2675,16 +2696,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
{ {
int hdisplay, vdisplay; int hdisplay, vdisplay;
hdisplay = mode->hdisplay; drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
vdisplay = mode->vdisplay;
if (drm_mode_is_stereo(mode)) {
struct drm_display_mode adjusted = *mode;
drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
hdisplay = adjusted.crtc_hdisplay;
vdisplay = adjusted.crtc_vdisplay;
}
if (crtc->invert_dimensions) if (crtc->invert_dimensions)
swap(hdisplay, vdisplay); swap(hdisplay, vdisplay);

Просмотреть файл

@ -739,6 +739,8 @@ EXPORT_SYMBOL(drm_mode_vrefresh);
* - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
* buffers containing two eyes (only adjust the timings when needed, eg. for * buffers containing two eyes (only adjust the timings when needed, eg. for
* "frame packing" or "side by side full"). * "frame packing" or "side by side full").
* - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
* be performed for doublescan and vscan > 1 modes respectively.
*/ */
void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
{ {
@ -765,18 +767,22 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
} }
} }
if (p->flags & DRM_MODE_FLAG_DBLSCAN) { if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
p->crtc_vdisplay *= 2; if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
p->crtc_vsync_start *= 2; p->crtc_vdisplay *= 2;
p->crtc_vsync_end *= 2; p->crtc_vsync_start *= 2;
p->crtc_vtotal *= 2; p->crtc_vsync_end *= 2;
p->crtc_vtotal *= 2;
}
} }
if (p->vscan > 1) { if (!(adjust_flags & CRTC_NO_VSCAN)) {
p->crtc_vdisplay *= p->vscan; if (p->vscan > 1) {
p->crtc_vsync_start *= p->vscan; p->crtc_vdisplay *= p->vscan;
p->crtc_vsync_end *= p->vscan; p->crtc_vsync_start *= p->vscan;
p->crtc_vtotal *= p->vscan; p->crtc_vsync_end *= p->vscan;
p->crtc_vtotal *= p->vscan;
}
} }
if (adjust_flags & CRTC_STEREO_DOUBLE) { if (adjust_flags & CRTC_STEREO_DOUBLE) {

Просмотреть файл

@ -19,6 +19,7 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
# GEM code # GEM code
i915-y += i915_cmd_parser.o \ i915-y += i915_cmd_parser.o \
i915_gem_batch_pool.o \
i915_gem_context.o \ i915_gem_context.o \
i915_gem_render_state.o \ i915_gem_render_state.o \
i915_gem_debug.o \ i915_gem_debug.o \
@ -47,6 +48,7 @@ i915-y += intel_renderstate_gen6.o \
i915-y += intel_audio.o \ i915-y += intel_audio.o \
intel_bios.o \ intel_bios.o \
intel_display.o \ intel_display.o \
intel_fbc.o \
intel_fifo_underrun.o \ intel_fifo_underrun.o \
intel_frontbuffer.o \ intel_frontbuffer.o \
intel_modes.o \ intel_modes.o \

Просмотреть файл

@ -152,6 +152,7 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = {
CMD( MI_PREDICATE, SMI, F, 1, S ), CMD( MI_PREDICATE, SMI, F, 1, S ),
CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ),
CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ),
CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ),
CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B,
@ -210,6 +211,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
CMD( MI_SET_PREDICATE, SMI, F, 1, S ), CMD( MI_SET_PREDICATE, SMI, F, 1, S ),
CMD( MI_RS_CONTROL, SMI, F, 1, S ), CMD( MI_RS_CONTROL, SMI, F, 1, S ),
CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ), CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ),
CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_RS_CONTEXT, SMI, F, 1, S ), CMD( MI_RS_CONTEXT, SMI, F, 1, S ),
CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ), CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ),
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ), CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
@ -229,6 +231,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
static const struct drm_i915_cmd_descriptor video_cmds[] = { static const struct drm_i915_cmd_descriptor video_cmds[] = {
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
.bits = {{ .bits = {{
.offset = 0, .offset = 0,
@ -272,6 +275,7 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = {
static const struct drm_i915_cmd_descriptor vecs_cmds[] = { static const struct drm_i915_cmd_descriptor vecs_cmds[] = {
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B, CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
.bits = {{ .bits = {{
.offset = 0, .offset = 0,
@ -401,6 +405,7 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = {
#define REG64(addr) (addr), (addr + sizeof(u32)) #define REG64(addr) (addr), (addr + sizeof(u32))
static const u32 gen7_render_regs[] = { static const u32 gen7_render_regs[] = {
REG64(GPGPU_THREADS_DISPATCHED),
REG64(HS_INVOCATION_COUNT), REG64(HS_INVOCATION_COUNT),
REG64(DS_INVOCATION_COUNT), REG64(DS_INVOCATION_COUNT),
REG64(IA_VERTICES_COUNT), REG64(IA_VERTICES_COUNT),
@ -481,13 +486,17 @@ static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT; u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
u32 subclient = u32 subclient =
(cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT; (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;
u32 op = (cmd_header & INSTR_26_TO_24_MASK) >> INSTR_26_TO_24_SHIFT;
if (client == INSTR_MI_CLIENT) if (client == INSTR_MI_CLIENT)
return 0x3F; return 0x3F;
else if (client == INSTR_RC_CLIENT) { else if (client == INSTR_RC_CLIENT) {
if (subclient == INSTR_MEDIA_SUBCLIENT) if (subclient == INSTR_MEDIA_SUBCLIENT) {
return 0xFFF; if (op == 6)
else return 0xFFFF;
else
return 0xFFF;
} else
return 0xFF; return 0xFF;
} }
@ -716,13 +725,13 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring)
BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count));
BUG_ON(!validate_regs_sorted(ring)); BUG_ON(!validate_regs_sorted(ring));
if (hash_empty(ring->cmd_hash)) { WARN_ON(!hash_empty(ring->cmd_hash));
ret = init_hash_table(ring, cmd_tables, cmd_table_count);
if (ret) { ret = init_hash_table(ring, cmd_tables, cmd_table_count);
DRM_ERROR("CMD: cmd_parser_init failed!\n"); if (ret) {
fini_hash_table(ring); DRM_ERROR("CMD: cmd_parser_init failed!\n");
return ret; fini_hash_table(ring);
} return ret;
} }
ring->needs_cmd_parser = true; ring->needs_cmd_parser = true;
@ -840,6 +849,69 @@ finish:
return (u32*)addr; return (u32*)addr;
} }
/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
struct drm_i915_gem_object *src_obj,
u32 batch_start_offset,
u32 batch_len)
{
int ret = 0;
int needs_clflush = 0;
u32 *src_base, *dest_base = NULL;
u32 *src_addr, *dest_addr;
u32 offset = batch_start_offset / sizeof(*dest_addr);
u32 end = batch_start_offset + batch_len;
if (end > dest_obj->base.size || end > src_obj->base.size)
return ERR_PTR(-E2BIG);
ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
if (ret) {
DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
return ERR_PTR(ret);
}
src_base = vmap_batch(src_obj);
if (!src_base) {
DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
ret = -ENOMEM;
goto unpin_src;
}
src_addr = src_base + offset;
if (needs_clflush)
drm_clflush_virt_range((char *)src_addr, batch_len);
ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
if (ret) {
DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n");
goto unmap_src;
}
dest_base = vmap_batch(dest_obj);
if (!dest_base) {
DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
ret = -ENOMEM;
goto unmap_src;
}
dest_addr = dest_base + offset;
if (batch_start_offset != 0)
memset((u8 *)dest_base, 0, batch_start_offset);
memcpy(dest_addr, src_addr, batch_len);
memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end);
unmap_src:
vunmap(src_base);
unpin_src:
i915_gem_object_unpin_pages(src_obj);
return ret ? ERR_PTR(ret) : dest_base;
}
/** /**
* i915_needs_cmd_parser() - should a given ring use software command parsing? * i915_needs_cmd_parser() - should a given ring use software command parsing?
* @ring: the ring in question * @ring: the ring in question
@ -956,7 +1028,9 @@ static bool check_cmd(const struct intel_engine_cs *ring,
* i915_parse_cmds() - parse a submitted batch buffer for privilege violations * i915_parse_cmds() - parse a submitted batch buffer for privilege violations
* @ring: the ring on which the batch is to execute * @ring: the ring on which the batch is to execute
* @batch_obj: the batch buffer in question * @batch_obj: the batch buffer in question
* @shadow_batch_obj: copy of the batch buffer in question
* @batch_start_offset: byte offset in the batch at which execution starts * @batch_start_offset: byte offset in the batch at which execution starts
* @batch_len: length of the commands in batch_obj
* @is_master: is the submitting process the drm master? * @is_master: is the submitting process the drm master?
* *
* Parses the specified batch buffer looking for privilege violations as * Parses the specified batch buffer looking for privilege violations as
@ -967,33 +1041,38 @@ static bool check_cmd(const struct intel_engine_cs *ring,
*/ */
int i915_parse_cmds(struct intel_engine_cs *ring, int i915_parse_cmds(struct intel_engine_cs *ring,
struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *batch_obj,
struct drm_i915_gem_object *shadow_batch_obj,
u32 batch_start_offset, u32 batch_start_offset,
u32 batch_len,
bool is_master) bool is_master)
{ {
int ret = 0; int ret = 0;
u32 *cmd, *batch_base, *batch_end; u32 *cmd, *batch_base, *batch_end;
struct drm_i915_cmd_descriptor default_desc = { 0 }; struct drm_i915_cmd_descriptor default_desc = { 0 };
int needs_clflush = 0;
bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */ bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush); ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0);
if (ret) { if (ret) {
DRM_DEBUG_DRIVER("CMD: failed to prep read\n"); DRM_DEBUG_DRIVER("CMD: Failed to pin shadow batch\n");
return ret; return -1;
} }
batch_base = vmap_batch(batch_obj); batch_base = copy_batch(shadow_batch_obj, batch_obj,
if (!batch_base) { batch_start_offset, batch_len);
DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n"); if (IS_ERR(batch_base)) {
i915_gem_object_unpin_pages(batch_obj); DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
return -ENOMEM; i915_gem_object_ggtt_unpin(shadow_batch_obj);
return PTR_ERR(batch_base);
} }
if (needs_clflush)
drm_clflush_virt_range((char *)batch_base, batch_obj->base.size);
cmd = batch_base + (batch_start_offset / sizeof(*cmd)); cmd = batch_base + (batch_start_offset / sizeof(*cmd));
batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));
/*
* We use the batch length as size because the shadow object is as
* large or larger and copy_batch() will write MI_NOPs to the extra
* space. Parsing should be faster in some cases this way.
*/
batch_end = cmd + (batch_len / sizeof(*batch_end));
while (cmd < batch_end) { while (cmd < batch_end) {
const struct drm_i915_cmd_descriptor *desc; const struct drm_i915_cmd_descriptor *desc;
@ -1053,8 +1132,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
} }
vunmap(batch_base); vunmap(batch_base);
i915_gem_object_ggtt_unpin(shadow_batch_obj);
i915_gem_object_unpin_pages(batch_obj);
return ret; return ret;
} }
@ -1076,6 +1154,7 @@ int i915_cmd_parser_get_version(void)
* hardware parsing enabled (so does not allow new use cases). * hardware parsing enabled (so does not allow new use cases).
* 2. Allow access to the MI_PREDICATE_SRC0 and * 2. Allow access to the MI_PREDICATE_SRC0 and
* MI_PREDICATE_SRC1 registers. * MI_PREDICATE_SRC1 registers.
* 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
*/ */
return 2; return 3;
} }

Просмотреть файл

@ -96,9 +96,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
static const char *get_pin_flag(struct drm_i915_gem_object *obj) static const char *get_pin_flag(struct drm_i915_gem_object *obj)
{ {
if (obj->user_pin_count > 0) if (i915_gem_obj_is_pinned(obj))
return "P";
else if (i915_gem_obj_is_pinned(obj))
return "p"; return "p";
else else
return " "; return " ";
@ -133,9 +131,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->base.size / 1024, obj->base.size / 1024,
obj->base.read_domains, obj->base.read_domains,
obj->base.write_domain, obj->base.write_domain,
obj->last_read_seqno, i915_gem_request_get_seqno(obj->last_read_req),
obj->last_write_seqno, i915_gem_request_get_seqno(obj->last_write_req),
obj->last_fenced_seqno, i915_gem_request_get_seqno(obj->last_fenced_req),
i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level), i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
obj->dirty ? " dirty" : "", obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : ""); obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
@ -154,8 +152,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_puts(m, " (pp"); seq_puts(m, " (pp");
else else
seq_puts(m, " (g"); seq_puts(m, " (g");
seq_printf(m, "gtt offset: %08lx, size: %08lx)", seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
vma->node.start, vma->node.size); vma->node.start, vma->node.size,
vma->ggtt_view.type);
} }
if (obj->stolen) if (obj->stolen)
seq_printf(m, " (stolen: %08lx)", obj->stolen->start); seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
@ -168,8 +167,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
*t = '\0'; *t = '\0';
seq_printf(m, " (%s mappable)", s); seq_printf(m, " (%s mappable)", s);
} }
if (obj->ring != NULL) if (obj->last_read_req != NULL)
seq_printf(m, " (%s)", obj->ring->name); seq_printf(m, " (%s)",
i915_gem_request_get_ring(obj->last_read_req)->name);
if (obj->frontbuffer_bits) if (obj->frontbuffer_bits)
seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits); seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits);
} }
@ -336,7 +336,7 @@ static int per_file_stats(int id, void *ptr, void *data)
if (ppgtt->file_priv != stats->file_priv) if (ppgtt->file_priv != stats->file_priv)
continue; continue;
if (obj->ring) /* XXX per-vma statistic */ if (obj->active) /* XXX per-vma statistic */
stats->active += obj->base.size; stats->active += obj->base.size;
else else
stats->inactive += obj->base.size; stats->inactive += obj->base.size;
@ -346,7 +346,7 @@ static int per_file_stats(int id, void *ptr, void *data)
} else { } else {
if (i915_gem_obj_ggtt_bound(obj)) { if (i915_gem_obj_ggtt_bound(obj)) {
stats->global += obj->base.size; stats->global += obj->base.size;
if (obj->ring) if (obj->active)
stats->active += obj->base.size; stats->active += obj->base.size;
else else
stats->inactive += obj->base.size; stats->inactive += obj->base.size;
@ -360,6 +360,33 @@ static int per_file_stats(int id, void *ptr, void *data)
return 0; return 0;
} }
#define print_file_stats(m, name, stats) \
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \
name, \
stats.count, \
stats.total, \
stats.active, \
stats.inactive, \
stats.global, \
stats.shared, \
stats.unbound)
static void print_batch_pool_stats(struct seq_file *m,
struct drm_i915_private *dev_priv)
{
struct drm_i915_gem_object *obj;
struct file_stats stats;
memset(&stats, 0, sizeof(stats));
list_for_each_entry(obj,
&dev_priv->mm.batch_pool.cache_list,
batch_pool_list)
per_file_stats(0, obj, &stats);
print_file_stats(m, "batch pool", stats);
}
#define count_vmas(list, member) do { \ #define count_vmas(list, member) do { \
list_for_each_entry(vma, list, member) { \ list_for_each_entry(vma, list, member) { \
size += i915_gem_obj_ggtt_size(vma->obj); \ size += i915_gem_obj_ggtt_size(vma->obj); \
@ -441,6 +468,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
dev_priv->gtt.base.total, dev_priv->gtt.base.total,
dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); dev_priv->gtt.mappable_end - dev_priv->gtt.base.start);
seq_putc(m, '\n');
print_batch_pool_stats(m, dev_priv);
seq_putc(m, '\n'); seq_putc(m, '\n');
list_for_each_entry_reverse(file, &dev->filelist, lhead) { list_for_each_entry_reverse(file, &dev->filelist, lhead) {
struct file_stats stats; struct file_stats stats;
@ -459,15 +489,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
*/ */
rcu_read_lock(); rcu_read_lock();
task = pid_task(file->pid, PIDTYPE_PID); task = pid_task(file->pid, PIDTYPE_PID);
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", print_file_stats(m, task ? task->comm : "<unknown>", stats);
task ? task->comm : "<unknown>",
stats.count,
stats.total,
stats.active,
stats.inactive,
stats.global,
stats.shared,
stats.unbound);
rcu_read_unlock(); rcu_read_unlock();
} }
@ -543,14 +565,16 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
pipe, plane); pipe, plane);
} }
if (work->flip_queued_ring) { if (work->flip_queued_req) {
struct intel_engine_cs *ring =
i915_gem_request_get_ring(work->flip_queued_req);
seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n", seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
work->flip_queued_ring->name, ring->name,
work->flip_queued_seqno, i915_gem_request_get_seqno(work->flip_queued_req),
dev_priv->next_seqno, dev_priv->next_seqno,
work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), ring->get_seqno(ring, true),
i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true), i915_gem_request_completed(work->flip_queued_req, true));
work->flip_queued_seqno));
} else } else
seq_printf(m, "Flip not associated with any ring\n"); seq_printf(m, "Flip not associated with any ring\n");
seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n", seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
@ -582,6 +606,36 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
int count = 0;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_puts(m, "cache:\n");
list_for_each_entry(obj,
&dev_priv->mm.batch_pool.cache_list,
batch_pool_list) {
seq_puts(m, " ");
describe_obj(m, obj);
seq_putc(m, '\n');
count++;
}
seq_printf(m, "total: %d\n", count);
mutex_unlock(&dev->struct_mutex);
return 0;
}
static int i915_gem_request_info(struct seq_file *m, void *data) static int i915_gem_request_info(struct seq_file *m, void *data)
{ {
struct drm_info_node *node = m->private; struct drm_info_node *node = m->private;
@ -2155,6 +2209,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 psrperf = 0; u32 psrperf = 0;
u32 stat[3];
enum pipe pipe;
bool enabled = false; bool enabled = false;
intel_runtime_pm_get(dev_priv); intel_runtime_pm_get(dev_priv);
@ -2169,14 +2225,36 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
seq_printf(m, "Re-enable work scheduled: %s\n", seq_printf(m, "Re-enable work scheduled: %s\n",
yesno(work_busy(&dev_priv->psr.work.work))); yesno(work_busy(&dev_priv->psr.work.work)));
enabled = HAS_PSR(dev) && if (HAS_PSR(dev)) {
I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; if (HAS_DDI(dev))
seq_printf(m, "HW Enabled & Active bit: %s\n", yesno(enabled)); enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
else {
for_each_pipe(dev_priv, pipe) {
stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
VLV_EDP_PSR_CURR_STATE_MASK;
if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
(stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
enabled = true;
}
}
}
seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled));
if (HAS_PSR(dev)) if (!HAS_DDI(dev))
for_each_pipe(dev_priv, pipe) {
if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
(stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
seq_printf(m, " pipe %c", pipe_name(pipe));
}
seq_puts(m, "\n");
/* CHV PSR has no kind of performance counter */
if (HAS_PSR(dev) && HAS_DDI(dev)) {
psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) & psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
EDP_PSR_PERF_CNT_MASK; EDP_PSR_PERF_CNT_MASK;
seq_printf(m, "Performance_Counter: %u\n", psrperf);
seq_printf(m, "Performance_Counter: %u\n", psrperf);
}
mutex_unlock(&dev_priv->psr.lock); mutex_unlock(&dev_priv->psr.lock);
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
@ -2322,7 +2400,7 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
case POWER_DOMAIN_INIT: case POWER_DOMAIN_INIT:
return "INIT"; return "INIT";
default: default:
WARN_ON(1); MISSING_CASE(domain);
return "?"; return "?";
} }
} }
@ -2718,6 +2796,9 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
enum pipe pipe; enum pipe pipe;
int plane; int plane;
if (INTEL_INFO(dev)->gen < 9)
return 0;
drm_modeset_lock_all(dev); drm_modeset_lock_all(dev);
ddb = &dev_priv->wm.skl_hw.ddb; ddb = &dev_priv->wm.skl_hw.ddb;
@ -2830,7 +2911,7 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe]; struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
char buf[PIPE_CRC_BUFFER_LEN]; char buf[PIPE_CRC_BUFFER_LEN];
int head, tail, n_entries, n; int n_entries;
ssize_t bytes_read; ssize_t bytes_read;
/* /*
@ -2862,36 +2943,39 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
} }
/* We now have one or more entries to read */ /* We now have one or more entries to read */
head = pipe_crc->head; n_entries = count / PIPE_CRC_LINE_LEN;
tail = pipe_crc->tail;
n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR),
count / PIPE_CRC_LINE_LEN);
spin_unlock_irq(&pipe_crc->lock);
bytes_read = 0; bytes_read = 0;
n = 0; while (n_entries > 0) {
do { struct intel_pipe_crc_entry *entry =
struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail]; &pipe_crc->entries[pipe_crc->tail];
int ret; int ret;
if (CIRC_CNT(pipe_crc->head, pipe_crc->tail,
INTEL_PIPE_CRC_ENTRIES_NR) < 1)
break;
BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
pipe_crc->tail = (pipe_crc->tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN, bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN,
"%8u %8x %8x %8x %8x %8x\n", "%8u %8x %8x %8x %8x %8x\n",
entry->frame, entry->crc[0], entry->frame, entry->crc[0],
entry->crc[1], entry->crc[2], entry->crc[1], entry->crc[2],
entry->crc[3], entry->crc[4]); entry->crc[3], entry->crc[4]);
ret = copy_to_user(user_buf + n * PIPE_CRC_LINE_LEN, spin_unlock_irq(&pipe_crc->lock);
buf, PIPE_CRC_LINE_LEN);
ret = copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN);
if (ret == PIPE_CRC_LINE_LEN) if (ret == PIPE_CRC_LINE_LEN)
return -EFAULT; return -EFAULT;
BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR); user_buf += PIPE_CRC_LINE_LEN;
tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1); n_entries--;
n++;
} while (--n_entries); spin_lock_irq(&pipe_crc->lock);
}
spin_lock_irq(&pipe_crc->lock);
pipe_crc->tail = tail;
spin_unlock_irq(&pipe_crc->lock); spin_unlock_irq(&pipe_crc->lock);
return bytes_read; return bytes_read;
@ -3072,6 +3156,12 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV; *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV;
need_stable_symbols = true; need_stable_symbols = true;
break; break;
case INTEL_PIPE_CRC_SOURCE_DP_D:
if (!IS_CHERRYVIEW(dev))
return -EINVAL;
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_VLV;
need_stable_symbols = true;
break;
case INTEL_PIPE_CRC_SOURCE_NONE: case INTEL_PIPE_CRC_SOURCE_NONE:
*val = 0; *val = 0;
break; break;
@ -3092,11 +3182,19 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
uint32_t tmp = I915_READ(PORT_DFT2_G4X); uint32_t tmp = I915_READ(PORT_DFT2_G4X);
tmp |= DC_BALANCE_RESET_VLV; tmp |= DC_BALANCE_RESET_VLV;
if (pipe == PIPE_A) switch (pipe) {
case PIPE_A:
tmp |= PIPE_A_SCRAMBLE_RESET; tmp |= PIPE_A_SCRAMBLE_RESET;
else break;
case PIPE_B:
tmp |= PIPE_B_SCRAMBLE_RESET; tmp |= PIPE_B_SCRAMBLE_RESET;
break;
case PIPE_C:
tmp |= PIPE_C_SCRAMBLE_RESET;
break;
default:
return -EINVAL;
}
I915_WRITE(PORT_DFT2_G4X, tmp); I915_WRITE(PORT_DFT2_G4X, tmp);
} }
@ -3185,10 +3283,19 @@ static void vlv_undo_pipe_scramble_reset(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp = I915_READ(PORT_DFT2_G4X); uint32_t tmp = I915_READ(PORT_DFT2_G4X);
if (pipe == PIPE_A) switch (pipe) {
case PIPE_A:
tmp &= ~PIPE_A_SCRAMBLE_RESET; tmp &= ~PIPE_A_SCRAMBLE_RESET;
else break;
case PIPE_B:
tmp &= ~PIPE_B_SCRAMBLE_RESET; tmp &= ~PIPE_B_SCRAMBLE_RESET;
break;
case PIPE_C:
tmp &= ~PIPE_C_SCRAMBLE_RESET;
break;
default:
return;
}
if (!(tmp & PIPE_SCRAMBLE_RESET_MASK)) if (!(tmp & PIPE_SCRAMBLE_RESET_MASK))
tmp &= ~DC_BALANCE_RESET_VLV; tmp &= ~DC_BALANCE_RESET_VLV;
I915_WRITE(PORT_DFT2_G4X, tmp); I915_WRITE(PORT_DFT2_G4X, tmp);
@ -3359,13 +3466,15 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
/* none -> real source transition */ /* none -> real source transition */
if (source) { if (source) {
struct intel_pipe_crc_entry *entries;
DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n", DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n",
pipe_name(pipe), pipe_crc_source_name(source)); pipe_name(pipe), pipe_crc_source_name(source));
pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) * entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
INTEL_PIPE_CRC_ENTRIES_NR, sizeof(pipe_crc->entries[0]),
GFP_KERNEL); GFP_KERNEL);
if (!pipe_crc->entries) if (!entries)
return -ENOMEM; return -ENOMEM;
/* /*
@ -3377,6 +3486,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
hsw_disable_ips(crtc); hsw_disable_ips(crtc);
spin_lock_irq(&pipe_crc->lock); spin_lock_irq(&pipe_crc->lock);
kfree(pipe_crc->entries);
pipe_crc->entries = entries;
pipe_crc->head = 0; pipe_crc->head = 0;
pipe_crc->tail = 0; pipe_crc->tail = 0;
spin_unlock_irq(&pipe_crc->lock); spin_unlock_irq(&pipe_crc->lock);
@ -3404,6 +3515,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
spin_lock_irq(&pipe_crc->lock); spin_lock_irq(&pipe_crc->lock);
entries = pipe_crc->entries; entries = pipe_crc->entries;
pipe_crc->entries = NULL; pipe_crc->entries = NULL;
pipe_crc->head = 0;
pipe_crc->tail = 0;
spin_unlock_irq(&pipe_crc->lock); spin_unlock_irq(&pipe_crc->lock);
kfree(entries); kfree(entries);
@ -4296,6 +4409,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS}, {"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS}, {"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS}, {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
{"i915_frequency_info", i915_frequency_info, 0}, {"i915_frequency_info", i915_frequency_info, 0},
{"i915_drpc_info", i915_drpc_info, 0}, {"i915_drpc_info", i915_drpc_info, 0},
{"i915_emon_status", i915_emon_status, 0}, {"i915_emon_status", i915_emon_status, 0},

Просмотреть файл

@ -928,6 +928,7 @@ int i915_driver_unload(struct drm_device *dev)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
i915_gem_context_fini(dev); i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_stolen(dev); i915_gem_cleanup_stolen(dev);
@ -1004,6 +1005,13 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
kfree(file_priv); kfree(file_priv);
} }
static int
i915_gem_reject_pin_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
return -ENODEV;
}
const struct drm_ioctl_desc i915_ioctls[] = { const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH), DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH),
@ -1025,8 +1033,8 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),

Просмотреть файл

@ -841,6 +841,8 @@ int i915_reset(struct drm_device *dev)
return ret; return ret;
} }
intel_overlay_reset(dev_priv);
/* Ok, now get things going again... */ /* Ok, now get things going again... */
/* /*
@ -1299,7 +1301,9 @@ static int vlv_suspend_complete(struct drm_i915_private *dev_priv)
err = vlv_allow_gt_wake(dev_priv, false); err = vlv_allow_gt_wake(dev_priv, false);
if (err) if (err)
goto err2; goto err2;
vlv_save_gunit_s0ix_state(dev_priv);
if (!IS_CHERRYVIEW(dev_priv->dev))
vlv_save_gunit_s0ix_state(dev_priv);
err = vlv_force_gfx_clock(dev_priv, false); err = vlv_force_gfx_clock(dev_priv, false);
if (err) if (err)
@ -1330,7 +1334,8 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
*/ */
ret = vlv_force_gfx_clock(dev_priv, true); ret = vlv_force_gfx_clock(dev_priv, true);
vlv_restore_gunit_s0ix_state(dev_priv); if (!IS_CHERRYVIEW(dev_priv->dev))
vlv_restore_gunit_s0ix_state(dev_priv);
err = vlv_allow_gt_wake(dev_priv, true); err = vlv_allow_gt_wake(dev_priv, true);
if (!ret) if (!ret)

Просмотреть файл

@ -55,10 +55,51 @@
#define DRIVER_NAME "i915" #define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics" #define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20141121" #define DRIVER_DATE "20141219"
#undef WARN_ON #undef WARN_ON
#define WARN_ON(x) WARN(x, "WARN_ON(" #x ")") /* Many gcc seem to no see through this and fall over :( */
#if 0
#define WARN_ON(x) ({ \
bool __i915_warn_cond = (x); \
if (__builtin_constant_p(__i915_warn_cond)) \
BUILD_BUG_ON(__i915_warn_cond); \
WARN(__i915_warn_cond, "WARN_ON(" #x ")"); })
#else
#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
#endif
#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
(long) (x), __func__);
/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
* WARN_ON()) for hw state sanity checks to check for unexpected conditions
* which may not necessarily be a user visible problem. This will either
* WARN() or DRM_ERROR() depending on the verbose_checks moduleparam, to
* enable distros and users to tailor their preferred amount of i915 abrt
* spam.
*/
#define I915_STATE_WARN(condition, format...) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) { \
if (i915.verbose_state_checks) \
__WARN_printf(format); \
else \
DRM_ERROR(format); \
} \
unlikely(__ret_warn_on); \
})
#define I915_STATE_WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) { \
if (i915.verbose_state_checks) \
__WARN_printf("WARN_ON(" #condition ")\n"); \
else \
DRM_ERROR("WARN_ON(" #condition ")\n"); \
} \
unlikely(__ret_warn_on); \
})
enum pipe { enum pipe {
INVALID_PIPE = -1, INVALID_PIPE = -1,
@ -1130,6 +1171,11 @@ struct intel_l3_parity {
int which_slice; int which_slice;
}; };
struct i915_gem_batch_pool {
struct drm_device *dev;
struct list_head cache_list;
};
struct i915_gem_mm { struct i915_gem_mm {
/** Memory allocator for GTT stolen memory */ /** Memory allocator for GTT stolen memory */
struct drm_mm stolen; struct drm_mm stolen;
@ -1143,6 +1189,13 @@ struct i915_gem_mm {
*/ */
struct list_head unbound_list; struct list_head unbound_list;
/*
* A pool of objects to use as shadow copies of client batch buffers
* when the command parser is enabled. Prevents the client from
* modifying the batch contents after software parsing.
*/
struct i915_gem_batch_pool batch_pool;
/** Usable portion of the GTT for GEM */ /** Usable portion of the GTT for GEM */
unsigned long stolen_base; /* limited to low memory (32-bit) */ unsigned long stolen_base; /* limited to low memory (32-bit) */
@ -1307,6 +1360,13 @@ enum drrs_support_type {
SEAMLESS_DRRS_SUPPORT = 2 SEAMLESS_DRRS_SUPPORT = 2
}; };
enum psr_lines_to_wait {
PSR_0_LINES_TO_WAIT = 0,
PSR_1_LINE_TO_WAIT,
PSR_4_LINES_TO_WAIT,
PSR_8_LINES_TO_WAIT
};
struct intel_vbt_data { struct intel_vbt_data {
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@ -1335,11 +1395,21 @@ struct intel_vbt_data {
int edp_bpp; int edp_bpp;
struct edp_power_seq edp_pps; struct edp_power_seq edp_pps;
struct {
bool full_link;
bool require_aux_wakeup;
int idle_frames;
enum psr_lines_to_wait lines_to_wait;
int tp1_wakeup_time;
int tp2_tp3_wakeup_time;
} psr;
struct { struct {
u16 pwm_freq_hz; u16 pwm_freq_hz;
bool present; bool present;
bool active_low_pwm; bool active_low_pwm;
u8 min_brightness; /* min_brightness/255 of max */ u8 min_brightness; /* min_brightness/255 of max */
u8 controller; /* brightness controller number */
} backlight; } backlight;
/* MIPI DSI */ /* MIPI DSI */
@ -1772,6 +1842,8 @@ struct drm_i915_private {
void (*stop_ring)(struct intel_engine_cs *ring); void (*stop_ring)(struct intel_engine_cs *ring);
} gt; } gt;
uint32_t request_uniq;
/* /*
* NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place. * will be rejected. Instead look for a better place.
@ -1855,6 +1927,8 @@ struct drm_i915_gem_object {
/** Used in execbuf to temporarily hold a ref */ /** Used in execbuf to temporarily hold a ref */
struct list_head obj_exec_link; struct list_head obj_exec_link;
struct list_head batch_pool_list;
/** /**
* This is set if the object is on the active lists (has pending * This is set if the object is on the active lists (has pending
* rendering and so a non-zero seqno), and is not set if it i s on * rendering and so a non-zero seqno), and is not set if it i s on
@ -1926,13 +2000,11 @@ struct drm_i915_gem_object {
void *dma_buf_vmapping; void *dma_buf_vmapping;
int vmapping_count; int vmapping_count;
struct intel_engine_cs *ring;
/** Breadcrumb of last rendering to the buffer. */ /** Breadcrumb of last rendering to the buffer. */
uint32_t last_read_seqno; struct drm_i915_gem_request *last_read_req;
uint32_t last_write_seqno; struct drm_i915_gem_request *last_write_req;
/** Breadcrumb of last fenced GPU access to the buffer. */ /** Breadcrumb of last fenced GPU access to the buffer. */
uint32_t last_fenced_seqno; struct drm_i915_gem_request *last_fenced_req;
/** Current tiling stride for the object, if it's tiled. */ /** Current tiling stride for the object, if it's tiled. */
uint32_t stride; uint32_t stride;
@ -1943,10 +2015,6 @@ struct drm_i915_gem_object {
/** Record of address bit 17 of each page at last unbind. */ /** Record of address bit 17 of each page at last unbind. */
unsigned long *bit_17; unsigned long *bit_17;
/** User space pin count and filp owning the pin */
unsigned long user_pin_count;
struct drm_file *pin_filp;
union { union {
/** for phy allocated objects */ /** for phy allocated objects */
struct drm_dma_handle *phys_handle; struct drm_dma_handle *phys_handle;
@ -1975,11 +2043,14 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
* The request queue allows us to note sequence numbers that have been emitted * The request queue allows us to note sequence numbers that have been emitted
* and may be associated with active buffers to be retired. * and may be associated with active buffers to be retired.
* *
* By keeping this list, we can avoid having to do questionable * By keeping this list, we can avoid having to do questionable sequence
* sequence-number comparisons on buffer last_rendering_seqnos, and associate * number comparisons on buffer last_read|write_seqno. It also allows an
* an emission time with seqnos for tracking how far ahead of the GPU we are. * emission time to be associated with the request for tracking how far ahead
* of the GPU the submission is.
*/ */
struct drm_i915_gem_request { struct drm_i915_gem_request {
struct kref ref;
/** On Which ring this request was generated */ /** On Which ring this request was generated */
struct intel_engine_cs *ring; struct intel_engine_cs *ring;
@ -2007,8 +2078,55 @@ struct drm_i915_gem_request {
struct drm_i915_file_private *file_priv; struct drm_i915_file_private *file_priv;
/** file_priv list entry for this request */ /** file_priv list entry for this request */
struct list_head client_list; struct list_head client_list;
uint32_t uniq;
}; };
void i915_gem_request_free(struct kref *req_ref);
static inline uint32_t
i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
{
return req ? req->seqno : 0;
}
static inline struct intel_engine_cs *
i915_gem_request_get_ring(struct drm_i915_gem_request *req)
{
return req ? req->ring : NULL;
}
static inline void
i915_gem_request_reference(struct drm_i915_gem_request *req)
{
kref_get(&req->ref);
}
static inline void
i915_gem_request_unreference(struct drm_i915_gem_request *req)
{
WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
kref_put(&req->ref, i915_gem_request_free);
}
static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
struct drm_i915_gem_request *src)
{
if (src)
i915_gem_request_reference(src);
if (*pdst)
i915_gem_request_unreference(*pdst);
*pdst = src;
}
/*
* XXX: i915_gem_request_completed should be here but currently needs the
* definition of i915_seqno_passed() which is below. It will be moved in
* a later patch when the call to i915_seqno_passed() is obsoleted...
*/
struct drm_i915_file_private { struct drm_i915_file_private {
struct drm_i915_private *dev_priv; struct drm_i915_private *dev_priv;
struct drm_file *file; struct drm_file *file;
@ -2242,7 +2360,8 @@ struct drm_i915_cmd_table {
#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi) #define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi)
#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg)
#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
#define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \ #define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \
IS_BROADWELL(dev) || IS_VALLEYVIEW(dev)) IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
#define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6)
@ -2312,6 +2431,7 @@ struct i915_params {
bool disable_vtd_wa; bool disable_vtd_wa;
int use_mmio_flip; int use_mmio_flip;
bool mmio_debug; bool mmio_debug;
bool verbose_state_checks;
}; };
extern struct i915_params i915 __read_mostly; extern struct i915_params i915 __read_mostly;
@ -2412,10 +2532,6 @@ int i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_execbuffer2(struct drm_device *dev, void *data, int i915_gem_execbuffer2(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_busy_ioctl(struct drm_device *dev, void *data, int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
@ -2460,10 +2576,23 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_GLOBAL 0x4 #define PIN_GLOBAL 0x4
#define PIN_OFFSET_BIAS 0x8 #define PIN_OFFSET_BIAS 0x8
#define PIN_OFFSET_MASK (~4095) #define PIN_OFFSET_MASK (~4095)
int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
uint64_t flags,
const struct i915_ggtt_view *view);
static inline
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm, struct i915_address_space *vm,
uint32_t alignment, uint32_t alignment,
uint64_t flags); uint64_t flags)
{
return i915_gem_object_pin_view(obj, vm, alignment, flags,
&i915_ggtt_view_normal);
}
int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags);
int __must_check i915_vma_unbind(struct i915_vma *vma); int __must_check i915_vma_unbind(struct i915_vma *vma);
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv); void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
@ -2512,6 +2641,18 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1 - seq2) >= 0; return (int32_t)(seq1 - seq2) >= 0;
} }
static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
bool lazy_coherency)
{
u32 seqno;
BUG_ON(req == NULL);
seqno = req->ring->get_seqno(req->ring, lazy_coherency);
return i915_seqno_passed(seqno, req->seqno);
}
int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
@ -2527,7 +2668,7 @@ bool i915_gem_retire_requests(struct drm_device *dev);
void i915_gem_retire_requests_ring(struct intel_engine_cs *ring); void i915_gem_retire_requests_ring(struct intel_engine_cs *ring);
int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
bool interruptible); bool interruptible);
int __must_check i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno); int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req);
static inline bool i915_reset_in_progress(struct i915_gpu_error *error) static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
{ {
@ -2570,17 +2711,15 @@ int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_suspend(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev);
int __i915_add_request(struct intel_engine_cs *ring, int __i915_add_request(struct intel_engine_cs *ring,
struct drm_file *file, struct drm_file *file,
struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *batch_obj);
u32 *seqno); #define i915_add_request(ring) \
#define i915_add_request(ring, seqno) \ __i915_add_request(ring, NULL, NULL)
__i915_add_request(ring, NULL, NULL, seqno) int __i915_wait_request(struct drm_i915_gem_request *req,
int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
unsigned reset_counter, unsigned reset_counter,
bool interruptible, bool interruptible,
s64 *timeout, s64 *timeout,
struct drm_i915_file_private *file_priv); struct drm_i915_file_private *file_priv);
int __must_check i915_wait_seqno(struct intel_engine_cs *ring, int __must_check i915_wait_request(struct drm_i915_gem_request *req);
uint32_t seqno);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int __must_check int __must_check
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@ -2614,18 +2753,51 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
void i915_gem_restore_fences(struct drm_device *dev); void i915_gem_restore_fences(struct drm_device *dev);
unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view);
static inline
unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o, unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
struct i915_address_space *vm); struct i915_address_space *vm)
{
return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
}
bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o); bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
struct i915_address_space *vm,
enum i915_ggtt_view_type view);
static inline
bool i915_gem_obj_bound(struct drm_i915_gem_object *o, bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
struct i915_address_space *vm); struct i915_address_space *vm)
{
return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
}
unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
struct i915_address_space *vm); struct i915_address_space *vm);
struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);
static inline
struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm); struct i915_address_space *vm)
{
return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
}
struct i915_vma *
i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);
static inline
struct i915_vma * struct i915_vma *
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm); struct i915_address_space *vm)
{
return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
&i915_ggtt_view_normal);
}
struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj); struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) { static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
@ -2807,6 +2979,13 @@ void i915_destroy_error_state(struct drm_device *dev);
void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone); void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
const char *i915_cache_level_str(struct drm_i915_private *i915, int type); const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
/* i915_gem_batch_pool.c */
void i915_gem_batch_pool_init(struct drm_device *dev,
struct i915_gem_batch_pool *pool);
void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
struct drm_i915_gem_object*
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
/* i915_cmd_parser.c */ /* i915_cmd_parser.c */
int i915_cmd_parser_get_version(void); int i915_cmd_parser_get_version(void);
int i915_cmd_parser_init_ring(struct intel_engine_cs *ring); int i915_cmd_parser_init_ring(struct intel_engine_cs *ring);
@ -2814,7 +2993,9 @@ void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring);
bool i915_needs_cmd_parser(struct intel_engine_cs *ring); bool i915_needs_cmd_parser(struct intel_engine_cs *ring);
int i915_parse_cmds(struct intel_engine_cs *ring, int i915_parse_cmds(struct intel_engine_cs *ring,
struct drm_i915_gem_object *batch_obj, struct drm_i915_gem_object *batch_obj,
struct drm_i915_gem_object *shadow_batch_obj,
u32 batch_start_offset, u32 batch_start_offset,
u32 batch_len,
bool is_master); bool is_master);
/* i915_suspend.c */ /* i915_suspend.c */
@ -2894,9 +3075,6 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev,
bool force_restore); bool force_restore);
extern void i915_redisable_vga(struct drm_device *dev); extern void i915_redisable_vga(struct drm_device *dev);
extern void i915_redisable_vga_power_on(struct drm_device *dev); extern void i915_redisable_vga_power_on(struct drm_device *dev);
extern bool intel_fbc_enabled(struct drm_device *dev);
extern void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_init_pch_refclk(struct drm_device *dev); extern void intel_init_pch_refclk(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void gen6_set_rps(struct drm_device *dev, u8 val);
@ -3072,4 +3250,11 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
} }
} }
static inline void i915_trace_irq_get(struct intel_engine_cs *ring,
struct drm_i915_gem_request *req)
{
if (ring->trace_irq_req == NULL && ring->irq_get(ring))
i915_gem_request_assign(&ring->trace_irq_req, req);
}
#endif #endif

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,137 @@
/*
* Copyright © 2014 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 "i915_drv.h"
/**
* DOC: batch pool
*
* In order to submit batch buffers as 'secure', the software command parser
* must ensure that a batch buffer cannot be modified after parsing. It does
* this by copying the user provided batch buffer contents to a kernel owned
* buffer from which the hardware will actually execute, and by carefully
* managing the address space bindings for such buffers.
*
* The batch pool framework provides a mechanism for the driver to manage a
* set of scratch buffers to use for this purpose. The framework can be
* extended to support other uses cases should they arise.
*/
/**
* i915_gem_batch_pool_init() - initialize a batch buffer pool
* @dev: the drm device
* @pool: the batch buffer pool
*/
void i915_gem_batch_pool_init(struct drm_device *dev,
struct i915_gem_batch_pool *pool)
{
pool->dev = dev;
INIT_LIST_HEAD(&pool->cache_list);
}
/**
* i915_gem_batch_pool_fini() - clean up a batch buffer pool
* @pool: the pool to clean up
*
* Note: Callers must hold the struct_mutex.
*/
void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool)
{
WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
while (!list_empty(&pool->cache_list)) {
struct drm_i915_gem_object *obj =
list_first_entry(&pool->cache_list,
struct drm_i915_gem_object,
batch_pool_list);
WARN_ON(obj->active);
list_del_init(&obj->batch_pool_list);
drm_gem_object_unreference(&obj->base);
}
}
/**
* i915_gem_batch_pool_get() - select a buffer from the pool
* @pool: the batch buffer pool
* @size: the minimum desired size of the returned buffer
*
* Finds or allocates a batch buffer in the pool with at least the requested
* size. The caller is responsible for any domain, active/inactive, or
* purgeability management for the returned buffer.
*
* Note: Callers must hold the struct_mutex
*
* Return: the selected batch buffer object
*/
struct drm_i915_gem_object *
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
size_t size)
{
struct drm_i915_gem_object *obj = NULL;
struct drm_i915_gem_object *tmp, *next;
WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
list_for_each_entry_safe(tmp, next,
&pool->cache_list, batch_pool_list) {
if (tmp->active)
continue;
/* While we're looping, do some clean up */
if (tmp->madv == __I915_MADV_PURGED) {
list_del(&tmp->batch_pool_list);
drm_gem_object_unreference(&tmp->base);
continue;
}
/*
* Select a buffer that is at least as big as needed
* but not 'too much' bigger. A better way to do this
* might be to bucket the pool objects based on size.
*/
if (tmp->base.size >= size &&
tmp->base.size <= (2 * size)) {
obj = tmp;
break;
}
}
if (!obj) {
obj = i915_gem_alloc_object(pool->dev, size);
if (!obj)
return ERR_PTR(-ENOMEM);
list_add_tail(&obj->batch_pool_list, &pool->cache_list);
}
else
/* Keep list in LRU order */
list_move_tail(&obj->batch_pool_list, &pool->cache_list);
obj->madv = I915_MADV_WILLNEED;
return obj;
}

Просмотреть файл

@ -408,14 +408,25 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
BUG_ON(!dev_priv->ring[RCS].default_context); BUG_ON(!dev_priv->ring[RCS].default_context);
if (i915.enable_execlists) if (i915.enable_execlists) {
return 0; for_each_ring(ring, dev_priv, i) {
if (ring->init_context) {
ret = ring->init_context(ring,
ring->default_context);
if (ret) {
DRM_ERROR("ring init context: %d\n",
ret);
return ret;
}
}
}
for_each_ring(ring, dev_priv, i) { } else
ret = i915_switch_context(ring, ring->default_context); for_each_ring(ring, dev_priv, i) {
if (ret) ret = i915_switch_context(ring, ring->default_context);
return ret; if (ret)
} return ret;
}
return 0; return 0;
} }
@ -611,9 +622,14 @@ static int do_switch(struct intel_engine_cs *ring,
goto unpin_out; goto unpin_out;
vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state); vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
if (!(vma->bound & GLOBAL_BIND)) if (!(vma->bound & GLOBAL_BIND)) {
vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level, ret = i915_vma_bind(vma,
GLOBAL_BIND); to->legacy_hw_ctx.rcs_state->cache_level,
GLOBAL_BIND);
/* This shouldn't ever fail. */
if (WARN_ONCE(ret, "GGTT context bind failed!"))
goto unpin_out;
}
if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
hw_flags |= MI_RESTORE_INHIBIT; hw_flags |= MI_RESTORE_INHIBIT;
@ -651,7 +667,8 @@ static int do_switch(struct intel_engine_cs *ring,
* swapped, but there is no way to do that yet. * swapped, but there is no way to do that yet.
*/ */
from->legacy_hw_ctx.rcs_state->dirty = 1; from->legacy_hw_ctx.rcs_state->dirty = 1;
BUG_ON(from->legacy_hw_ctx.rcs_state->ring != ring); BUG_ON(i915_gem_request_get_ring(
from->legacy_hw_ctx.rcs_state->last_read_req) != ring);
/* obj is kept alive until the next request by its active ref */ /* obj is kept alive until the next request by its active ref */
i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state); i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
@ -671,10 +688,6 @@ done:
if (ret) if (ret)
DRM_ERROR("ring init context: %d\n", ret); DRM_ERROR("ring init context: %d\n", ret);
} }
ret = i915_gem_render_state_init(ring);
if (ret)
DRM_ERROR("init render state: %d\n", ret);
} }
return 0; return 0;

Просмотреть файл

@ -37,6 +37,7 @@
#define __EXEC_OBJECT_HAS_FENCE (1<<30) #define __EXEC_OBJECT_HAS_FENCE (1<<30)
#define __EXEC_OBJECT_NEEDS_MAP (1<<29) #define __EXEC_OBJECT_NEEDS_MAP (1<<29)
#define __EXEC_OBJECT_NEEDS_BIAS (1<<28) #define __EXEC_OBJECT_NEEDS_BIAS (1<<28)
#define __EXEC_OBJECT_PURGEABLE (1<<27)
#define BATCH_OFFSET_BIAS (256*1024) #define BATCH_OFFSET_BIAS (256*1024)
@ -223,7 +224,12 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
if (entry->flags & __EXEC_OBJECT_HAS_PIN) if (entry->flags & __EXEC_OBJECT_HAS_PIN)
vma->pin_count--; vma->pin_count--;
entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN); if (entry->flags & __EXEC_OBJECT_PURGEABLE)
obj->madv = I915_MADV_DONTNEED;
entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE |
__EXEC_OBJECT_HAS_PIN |
__EXEC_OBJECT_PURGEABLE);
} }
static void eb_destroy(struct eb_vmas *eb) static void eb_destroy(struct eb_vmas *eb)
@ -357,9 +363,12 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
* through the ppgtt for non_secure batchbuffers. */ * through the ppgtt for non_secure batchbuffers. */
if (unlikely(IS_GEN6(dev) && if (unlikely(IS_GEN6(dev) &&
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION && reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
!(target_vma->bound & GLOBAL_BIND))) !(target_vma->bound & GLOBAL_BIND))) {
target_vma->bind_vma(target_vma, target_i915_obj->cache_level, ret = i915_vma_bind(target_vma, target_i915_obj->cache_level,
GLOBAL_BIND); GLOBAL_BIND);
if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!"))
return ret;
}
/* Validate that the target is in a valid r/w GPU domain */ /* Validate that the target is in a valid r/w GPU domain */
if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) { if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
@ -943,7 +952,7 @@ void
i915_gem_execbuffer_move_to_active(struct list_head *vmas, i915_gem_execbuffer_move_to_active(struct list_head *vmas,
struct intel_engine_cs *ring) struct intel_engine_cs *ring)
{ {
u32 seqno = intel_ring_get_seqno(ring); struct drm_i915_gem_request *req = intel_ring_get_request(ring);
struct i915_vma *vma; struct i915_vma *vma;
list_for_each_entry(vma, vmas, exec_list) { list_for_each_entry(vma, vmas, exec_list) {
@ -960,7 +969,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
i915_vma_move_to_active(vma, ring); i915_vma_move_to_active(vma, ring);
if (obj->base.write_domain) { if (obj->base.write_domain) {
obj->dirty = 1; obj->dirty = 1;
obj->last_write_seqno = seqno; i915_gem_request_assign(&obj->last_write_req, req);
intel_fb_obj_invalidate(obj, ring); intel_fb_obj_invalidate(obj, ring);
@ -968,7 +977,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
} }
if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
obj->last_fenced_seqno = seqno; i915_gem_request_assign(&obj->last_fenced_req, req);
if (entry->flags & __EXEC_OBJECT_HAS_FENCE) { if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
struct drm_i915_private *dev_priv = to_i915(ring->dev); struct drm_i915_private *dev_priv = to_i915(ring->dev);
list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list, list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
@ -990,7 +999,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev,
ring->gpu_caches_dirty = true; ring->gpu_caches_dirty = true;
/* Add a breadcrumb for the completion of the batch buffer */ /* Add a breadcrumb for the completion of the batch buffer */
(void)__i915_add_request(ring, file, obj, NULL); (void)__i915_add_request(ring, file, obj);
} }
static int static int
@ -1060,6 +1069,65 @@ i915_emit_box(struct intel_engine_cs *ring,
return 0; return 0;
} }
static struct drm_i915_gem_object*
i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
struct drm_i915_gem_exec_object2 *shadow_exec_entry,
struct eb_vmas *eb,
struct drm_i915_gem_object *batch_obj,
u32 batch_start_offset,
u32 batch_len,
bool is_master,
u32 *flags)
{
struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
struct drm_i915_gem_object *shadow_batch_obj;
int ret;
shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool,
batch_obj->base.size);
if (IS_ERR(shadow_batch_obj))
return shadow_batch_obj;
ret = i915_parse_cmds(ring,
batch_obj,
shadow_batch_obj,
batch_start_offset,
batch_len,
is_master);
if (ret) {
if (ret == -EACCES)
return batch_obj;
} else {
struct i915_vma *vma;
memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
vma->exec_entry = shadow_exec_entry;
vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE;
drm_gem_object_reference(&shadow_batch_obj->base);
list_add_tail(&vma->exec_list, &eb->vmas);
shadow_batch_obj->base.pending_read_domains =
batch_obj->base.pending_read_domains;
/*
* Set the DISPATCH_SECURE bit to remove the NON_SECURE
* bit from MI_BATCH_BUFFER_START commands issued in the
* dispatch_execbuffer implementations. We specifically
* don't want that set when the command parser is
* enabled.
*
* FIXME: with aliasing ppgtt, buffers that should only
* be in ggtt still end up in the aliasing ppgtt. remove
* this check when that is fixed.
*/
if (USES_FULL_PPGTT(dev))
*flags |= I915_DISPATCH_SECURE;
}
return ret ? ERR_PTR(ret) : shadow_batch_obj;
}
int int
i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
@ -1208,7 +1276,7 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
return ret; return ret;
} }
trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), flags);
i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_move_to_active(vmas, ring);
i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
@ -1277,6 +1345,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct eb_vmas *eb; struct eb_vmas *eb;
struct drm_i915_gem_object *batch_obj; struct drm_i915_gem_object *batch_obj;
struct drm_i915_gem_exec_object2 shadow_exec_entry;
struct intel_engine_cs *ring; struct intel_engine_cs *ring;
struct intel_context *ctx; struct intel_context *ctx;
struct i915_address_space *vm; struct i915_address_space *vm;
@ -1393,28 +1462,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
if (i915_needs_cmd_parser(ring)) { if (i915_needs_cmd_parser(ring)) {
ret = i915_parse_cmds(ring, batch_obj = i915_gem_execbuffer_parse(ring,
batch_obj, &shadow_exec_entry,
args->batch_start_offset, eb,
file->is_master); batch_obj,
if (ret) { args->batch_start_offset,
if (ret != -EACCES) args->batch_len,
goto err; file->is_master,
} else { &flags);
/* if (IS_ERR(batch_obj)) {
* XXX: Actually do this when enabling batch copy... ret = PTR_ERR(batch_obj);
* goto err;
* Set the DISPATCH_SECURE bit to remove the NON_SECURE bit
* from MI_BATCH_BUFFER_START commands issued in the
* dispatch_execbuffer implementations. We specifically don't
* want that set when the command parser is enabled.
*/
} }
} }
batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
/* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
* batch" bit. Hence we need to pin secure batches into the global gtt. * batch" bit. Hence we need to pin secure batches into the global gtt.
* hsw should have this fixed, but bdw mucks it up again. */ * hsw should have this fixed, but bdw mucks it up again. */

Просмотреть файл

@ -30,6 +30,68 @@
#include "i915_trace.h" #include "i915_trace.h"
#include "intel_drv.h" #include "intel_drv.h"
/**
* DOC: Global GTT views
*
* Background and previous state
*
* Historically objects could exists (be bound) in global GTT space only as
* singular instances with a view representing all of the object's backing pages
* in a linear fashion. This view will be called a normal view.
*
* To support multiple views of the same object, where the number of mapped
* pages is not equal to the backing store, or where the layout of the pages
* is not linear, concept of a GGTT view was added.
*
* One example of an alternative view is a stereo display driven by a single
* image. In this case we would have a framebuffer looking like this
* (2x2 pages):
*
* 12
* 34
*
* Above would represent a normal GGTT view as normally mapped for GPU or CPU
* rendering. In contrast, fed to the display engine would be an alternative
* view which could look something like this:
*
* 1212
* 3434
*
* In this example both the size and layout of pages in the alternative view is
* different from the normal view.
*
* Implementation and usage
*
* GGTT views are implemented using VMAs and are distinguished via enum
* i915_ggtt_view_type and struct i915_ggtt_view.
*
* A new flavour of core GEM functions which work with GGTT bound objects were
* added with the _view suffix. They take the struct i915_ggtt_view parameter
* encapsulating all metadata required to implement a view.
*
* As a helper for callers which are only interested in the normal view,
* globally const i915_ggtt_view_normal singleton instance exists. All old core
* GEM API functions, the ones not taking the view parameter, are operating on,
* or with the normal GGTT view.
*
* Code wanting to add or use a new GGTT view needs to:
*
* 1. Add a new enum with a suitable name.
* 2. Extend the metadata in the i915_ggtt_view structure if required.
* 3. Add support to i915_get_vma_pages().
*
* New views are required to build a scatter-gather table from within the
* i915_get_vma_pages function. This table is stored in the vma.ggtt_view and
* exists for the lifetime of an VMA.
*
* Core API is designed to have copy semantics which means that passed in
* struct i915_ggtt_view does not need to be persistent (left around after
* calling the core API functions).
*
*/
const struct i915_ggtt_view i915_ggtt_view_normal;
static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv); static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
static void chv_setup_private_ppat(struct drm_i915_private *dev_priv); static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
@ -40,8 +102,6 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6; has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
has_full_ppgtt = INTEL_INFO(dev)->gen >= 7; has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
if (IS_GEN8(dev))
has_full_ppgtt = false; /* XXX why? */
/* /*
* We don't allow disabling PPGTT for gen9+ as it's a requirement for * We don't allow disabling PPGTT for gen9+ as it's a requirement for
@ -72,7 +132,10 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
return 0; return 0;
} }
return has_aliasing_ppgtt ? 1 : 0; if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists)
return 2;
else
return has_aliasing_ppgtt ? 1 : 0;
} }
@ -132,7 +195,7 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
pte |= GEN6_PTE_UNCACHED; pte |= GEN6_PTE_UNCACHED;
break; break;
default: default:
WARN_ON(1); MISSING_CASE(level);
} }
return pte; return pte;
@ -156,7 +219,7 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
pte |= GEN6_PTE_UNCACHED; pte |= GEN6_PTE_UNCACHED;
break; break;
default: default:
WARN_ON(1); MISSING_CASE(level);
} }
return pte; return pte;
@ -1102,10 +1165,8 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
if (INTEL_INFO(dev)->gen < 8) if (INTEL_INFO(dev)->gen < 8)
return gen6_ppgtt_init(ppgtt); return gen6_ppgtt_init(ppgtt);
else if (IS_GEN8(dev) || IS_GEN9(dev))
return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
else else
BUG(); return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
} }
int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
{ {
@ -1146,7 +1207,7 @@ int i915_ppgtt_init_hw(struct drm_device *dev)
else if (INTEL_INFO(dev)->gen >= 8) else if (INTEL_INFO(dev)->gen >= 8)
gen8_ppgtt_enable(dev); gen8_ppgtt_enable(dev);
else else
WARN_ON(1); MISSING_CASE(INTEL_INFO(dev)->gen);
if (ppgtt) { if (ppgtt) {
for_each_ring(ring, dev_priv, i) { for_each_ring(ring, dev_priv, i) {
@ -1341,9 +1402,12 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
/* The bind_vma code tries to be smart about tracking mappings. /* The bind_vma code tries to be smart about tracking mappings.
* Unfortunately above, we've just wiped out the mappings * Unfortunately above, we've just wiped out the mappings
* without telling our object about it. So we need to fake it. * without telling our object about it. So we need to fake it.
*
* Bind is not expected to fail since this is only called on
* resume and assumption is all requirements exist already.
*/ */
vma->bound &= ~GLOBAL_BIND; vma->bound &= ~GLOBAL_BIND;
vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND); WARN_ON(i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND));
} }
@ -1538,7 +1602,7 @@ static void i915_ggtt_bind_vma(struct i915_vma *vma,
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
BUG_ON(!i915_is_ggtt(vma->vm)); BUG_ON(!i915_is_ggtt(vma->vm));
intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags); intel_gtt_insert_sg_entries(vma->ggtt_view.pages, entry, flags);
vma->bound = GLOBAL_BIND; vma->bound = GLOBAL_BIND;
} }
@ -1588,7 +1652,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) { if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
if (!(vma->bound & GLOBAL_BIND) || if (!(vma->bound & GLOBAL_BIND) ||
(cache_level != obj->cache_level)) { (cache_level != obj->cache_level)) {
vma->vm->insert_entries(vma->vm, obj->pages, vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
vma->node.start, vma->node.start,
cache_level, flags); cache_level, flags);
vma->bound |= GLOBAL_BIND; vma->bound |= GLOBAL_BIND;
@ -1600,7 +1664,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
(cache_level != obj->cache_level))) { (cache_level != obj->cache_level))) {
struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
appgtt->base.insert_entries(&appgtt->base, appgtt->base.insert_entries(&appgtt->base,
vma->obj->pages, vma->ggtt_view.pages,
vma->node.start, vma->node.start,
cache_level, flags); cache_level, flags);
vma->bound |= LOCAL_BIND; vma->bound |= LOCAL_BIND;
@ -2165,7 +2229,8 @@ int i915_gem_gtt_init(struct drm_device *dev)
} }
static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj, static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
struct i915_address_space *vm) struct i915_address_space *vm,
const struct i915_ggtt_view *view)
{ {
struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
if (vma == NULL) if (vma == NULL)
@ -2176,12 +2241,9 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
INIT_LIST_HEAD(&vma->exec_list); INIT_LIST_HEAD(&vma->exec_list);
vma->vm = vm; vma->vm = vm;
vma->obj = obj; vma->obj = obj;
vma->ggtt_view = *view;
switch (INTEL_INFO(vm->dev)->gen) { if (INTEL_INFO(vm->dev)->gen >= 6) {
case 9:
case 8:
case 7:
case 6:
if (i915_is_ggtt(vm)) { if (i915_is_ggtt(vm)) {
vma->unbind_vma = ggtt_unbind_vma; vma->unbind_vma = ggtt_unbind_vma;
vma->bind_vma = ggtt_bind_vma; vma->bind_vma = ggtt_bind_vma;
@ -2189,39 +2251,73 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
vma->unbind_vma = ppgtt_unbind_vma; vma->unbind_vma = ppgtt_unbind_vma;
vma->bind_vma = ppgtt_bind_vma; vma->bind_vma = ppgtt_bind_vma;
} }
break; } else {
case 5:
case 4:
case 3:
case 2:
BUG_ON(!i915_is_ggtt(vm)); BUG_ON(!i915_is_ggtt(vm));
vma->unbind_vma = i915_ggtt_unbind_vma; vma->unbind_vma = i915_ggtt_unbind_vma;
vma->bind_vma = i915_ggtt_bind_vma; vma->bind_vma = i915_ggtt_bind_vma;
break;
default:
BUG();
} }
/* Keep GGTT vmas first to make debug easier */ list_add_tail(&vma->vma_link, &obj->vma_list);
if (i915_is_ggtt(vm)) if (!i915_is_ggtt(vm))
list_add(&vma->vma_link, &obj->vma_list);
else {
list_add_tail(&vma->vma_link, &obj->vma_list);
i915_ppgtt_get(i915_vm_to_ppgtt(vm)); i915_ppgtt_get(i915_vm_to_ppgtt(vm));
}
return vma; return vma;
} }
struct i915_vma * struct i915_vma *
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
struct i915_address_space *vm) struct i915_address_space *vm,
const struct i915_ggtt_view *view)
{ {
struct i915_vma *vma; struct i915_vma *vma;
vma = i915_gem_obj_to_vma(obj, vm); vma = i915_gem_obj_to_vma_view(obj, vm, view);
if (!vma) if (!vma)
vma = __i915_gem_vma_create(obj, vm); vma = __i915_gem_vma_create(obj, vm, view);
return vma; return vma;
} }
static inline
int i915_get_vma_pages(struct i915_vma *vma)
{
if (vma->ggtt_view.pages)
return 0;
if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
vma->ggtt_view.pages = vma->obj->pages;
else
WARN_ONCE(1, "GGTT view %u not implemented!\n",
vma->ggtt_view.type);
if (!vma->ggtt_view.pages) {
DRM_ERROR("Failed to get pages for VMA view type %u!\n",
vma->ggtt_view.type);
return -EINVAL;
}
return 0;
}
/**
* i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
* @vma: VMA to map
* @cache_level: mapping cache level
* @flags: flags like global or local mapping
*
* DMA addresses are taken from the scatter-gather table of this object (or of
* this VMA in case of non-default GGTT views) and PTE entries set up.
* Note that DMA addresses are also the only part of the SG table we care about.
*/
int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags)
{
int ret = i915_get_vma_pages(vma);
if (ret)
return ret;
vma->bind_vma(vma, cache_level, flags);
return 0;
}

Просмотреть файл

@ -109,7 +109,20 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
#define GEN8_PPAT_ELLC_OVERRIDE (0<<2) #define GEN8_PPAT_ELLC_OVERRIDE (0<<2)
#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8)) #define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8))
enum i915_ggtt_view_type {
I915_GGTT_VIEW_NORMAL = 0,
};
struct i915_ggtt_view {
enum i915_ggtt_view_type type;
struct sg_table *pages;
};
extern const struct i915_ggtt_view i915_ggtt_view_normal;
enum i915_cache_level; enum i915_cache_level;
/** /**
* A VMA represents a GEM BO that is bound into an address space. Therefore, a * A VMA represents a GEM BO that is bound into an address space. Therefore, a
* VMA's presence cannot be guaranteed before binding, or after unbinding the * VMA's presence cannot be guaranteed before binding, or after unbinding the
@ -129,6 +142,15 @@ struct i915_vma {
#define PTE_READ_ONLY (1<<2) #define PTE_READ_ONLY (1<<2)
unsigned int bound : 4; unsigned int bound : 4;
/**
* Support different GGTT views into the same object.
* This means there can be multiple VMA mappings per object and per VM.
* i915_ggtt_view_type is used to distinguish between those entries.
* The default one of zero (I915_GGTT_VIEW_NORMAL) is default and also
* assumed in GEM functions which take no ggtt view parameter.
*/
struct i915_ggtt_view ggtt_view;
/** This object's place on the active/inactive lists */ /** This object's place on the active/inactive lists */
struct list_head mm_list; struct list_head mm_list;
@ -146,11 +168,10 @@ struct i915_vma {
/** /**
* How many users have pinned this object in GTT space. The following * How many users have pinned this object in GTT space. The following
* users can each hold at most one reference: pwrite/pread, pin_ioctl * users can each hold at most one reference: pwrite/pread, execbuffer
* (via user_pin_count), execbuffer (objects are not allowed multiple * (objects are not allowed multiple times for the same batchbuffer),
* times for the same batchbuffer), and the framebuffer code. When * and the framebuffer code. When switching/pageflipping, the
* switching/pageflipping, the framebuffer code has at most two buffers * framebuffer code has at most two buffers pinned per crtc.
* pinned per crtc.
* *
* In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
* bits with absolutely no headroom. So use 4 bits. */ * bits with absolutely no headroom. So use 4 bits. */
@ -182,7 +203,7 @@ struct i915_address_space {
* List of objects currently involved in rendering. * List of objects currently involved in rendering.
* *
* Includes buffers having the contents of their GPU caches * Includes buffers having the contents of their GPU caches
* flushed, not necessarily primitives. last_rendering_seqno * flushed, not necessarily primitives. last_read_req
* represents when the rendering involved will be completed. * represents when the rendering involved will be completed.
* *
* A reference is held on the buffer while on this list. * A reference is held on the buffer while on this list.
@ -193,7 +214,7 @@ struct i915_address_space {
* LRU list of objects which are not in the ringbuffer and * LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT. * are ready to unbind, but are still in the GTT.
* *
* last_rendering_seqno is 0 while an object is in this list. * last_read_req is NULL while an object is in this list.
* *
* A reference is not held on the buffer while on this list, * A reference is not held on the buffer while on this list,
* as merely being GTT-bound shouldn't prevent its being * as merely being GTT-bound shouldn't prevent its being

Просмотреть файл

@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
ret = __i915_add_request(ring, NULL, so.obj, NULL); ret = __i915_add_request(ring, NULL, so.obj);
/* __i915_add_request moves object to inactive if it fails */ /* __i915_add_request moves object to inactive if it fails */
out: out:
i915_gem_render_state_fini(&so); i915_gem_render_state_fini(&so);

Просмотреть файл

@ -399,7 +399,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
} }
obj->fence_dirty = obj->fence_dirty =
obj->last_fenced_seqno || obj->last_fenced_req ||
obj->fence_reg != I915_FENCE_REG_NONE; obj->fence_reg != I915_FENCE_REG_NONE;
obj->tiling_mode = args->tiling_mode; obj->tiling_mode = args->tiling_mode;

Просмотреть файл

@ -670,8 +670,8 @@ static void capture_bo(struct drm_i915_error_buffer *err,
err->size = obj->base.size; err->size = obj->base.size;
err->name = obj->base.name; err->name = obj->base.name;
err->rseqno = obj->last_read_seqno; err->rseqno = i915_gem_request_get_seqno(obj->last_read_req);
err->wseqno = obj->last_write_seqno; err->wseqno = i915_gem_request_get_seqno(obj->last_write_req);
err->gtt_offset = vma->node.start; err->gtt_offset = vma->node.start;
err->read_domains = obj->base.read_domains; err->read_domains = obj->base.read_domains;
err->write_domain = obj->base.write_domain; err->write_domain = obj->base.write_domain;
@ -679,13 +679,12 @@ static void capture_bo(struct drm_i915_error_buffer *err,
err->pinned = 0; err->pinned = 0;
if (i915_gem_obj_is_pinned(obj)) if (i915_gem_obj_is_pinned(obj))
err->pinned = 1; err->pinned = 1;
if (obj->user_pin_count > 0)
err->pinned = -1;
err->tiling = obj->tiling_mode; err->tiling = obj->tiling_mode;
err->dirty = obj->dirty; err->dirty = obj->dirty;
err->purgeable = obj->madv != I915_MADV_WILLNEED; err->purgeable = obj->madv != I915_MADV_WILLNEED;
err->userptr = obj->userptr.mm != NULL; err->userptr = obj->userptr.mm != NULL;
err->ring = obj->ring ? obj->ring->id : -1; err->ring = obj->last_read_req ?
i915_gem_request_get_ring(obj->last_read_req)->id : -1;
err->cache_level = obj->cache_level; err->cache_level = obj->cache_level;
} }
@ -719,10 +718,8 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
break; break;
list_for_each_entry(vma, &obj->vma_list, vma_link) list_for_each_entry(vma, &obj->vma_list, vma_link)
if (vma->vm == vm && vma->pin_count > 0) { if (vma->vm == vm && vma->pin_count > 0)
capture_bo(err++, vma); capture_bo(err++, vma);
break;
}
} }
return err - first; return err - first;
@ -767,32 +764,21 @@ static void i915_gem_record_fences(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int i; int i;
/* Fences */ if (IS_GEN3(dev) || IS_GEN2(dev)) {
switch (INTEL_INFO(dev)->gen) {
case 9:
case 8:
case 7:
case 6:
for (i = 0; i < dev_priv->num_fence_regs; i++)
error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
break;
case 5:
case 4:
for (i = 0; i < 16; i++)
error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
break;
case 3:
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
case 2:
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
break; if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
for (i = 0; i < 8; i++)
default: error->fence[i+8] = I915_READ(FENCE_REG_945_8 +
BUG(); (i * 4));
} } else if (IS_GEN5(dev) || IS_GEN4(dev))
for (i = 0; i < 16; i++)
error->fence[i] = I915_READ64(FENCE_REG_965_0 +
(i * 8));
else if (INTEL_INFO(dev)->gen >= 6)
for (i = 0; i < dev_priv->num_fence_regs; i++)
error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 +
(i * 8));
} }
@ -926,9 +912,13 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring)); ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring));
switch (INTEL_INFO(dev)->gen) { if (IS_GEN6(dev))
case 9: ering->vm_info.pp_dir_base =
case 8: I915_READ(RING_PP_DIR_BASE_READ(ring));
else if (IS_GEN7(dev))
ering->vm_info.pp_dir_base =
I915_READ(RING_PP_DIR_BASE(ring));
else if (INTEL_INFO(dev)->gen >= 8)
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
ering->vm_info.pdp[i] = ering->vm_info.pdp[i] =
I915_READ(GEN8_RING_PDP_UDW(ring, i)); I915_READ(GEN8_RING_PDP_UDW(ring, i));
@ -936,16 +926,6 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->vm_info.pdp[i] |= ering->vm_info.pdp[i] |=
I915_READ(GEN8_RING_PDP_LDW(ring, i)); I915_READ(GEN8_RING_PDP_LDW(ring, i));
} }
break;
case 7:
ering->vm_info.pp_dir_base =
I915_READ(RING_PP_DIR_BASE(ring));
break;
case 6:
ering->vm_info.pp_dir_base =
I915_READ(RING_PP_DIR_BASE_READ(ring));
break;
}
} }
} }
@ -1097,10 +1077,8 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
list_for_each_entry(vma, &obj->vma_list, vma_link) list_for_each_entry(vma, &obj->vma_list, vma_link)
if (vma->vm == vm && vma->pin_count > 0) { if (vma->vm == vm && vma->pin_count > 0)
i++; i++;
break;
}
} }
error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx]; error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
@ -1378,26 +1356,15 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
switch (INTEL_INFO(dev)->gen) { if (IS_GEN2(dev) || IS_GEN3(dev))
case 2:
case 3:
instdone[0] = I915_READ(INSTDONE); instdone[0] = I915_READ(INSTDONE);
break; else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
case 4:
case 5:
case 6:
instdone[0] = I915_READ(INSTDONE_I965); instdone[0] = I915_READ(INSTDONE_I965);
instdone[1] = I915_READ(INSTDONE1); instdone[1] = I915_READ(INSTDONE1);
break; } else if (INTEL_INFO(dev)->gen >= 7) {
default:
WARN_ONCE(1, "Unsupported platform\n");
case 7:
case 8:
case 9:
instdone[0] = I915_READ(GEN7_INSTDONE_1); instdone[0] = I915_READ(GEN7_INSTDONE_1);
instdone[1] = I915_READ(GEN7_SC_INSTDONE); instdone[1] = I915_READ(GEN7_SC_INSTDONE);
instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
instdone[3] = I915_READ(GEN7_ROW_INSTDONE); instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
break;
} }
} }

Просмотреть файл

@ -183,6 +183,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
{ {
assert_spin_locked(&dev_priv->irq_lock); assert_spin_locked(&dev_priv->irq_lock);
WARN_ON(enabled_irq_mask & ~interrupt_mask);
if (WARN_ON(!intel_irqs_enabled(dev_priv))) if (WARN_ON(!intel_irqs_enabled(dev_priv)))
return; return;
@ -229,6 +231,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
{ {
uint32_t new_val; uint32_t new_val;
WARN_ON(enabled_irq_mask & ~interrupt_mask);
assert_spin_locked(&dev_priv->irq_lock); assert_spin_locked(&dev_priv->irq_lock);
new_val = dev_priv->pm_irq_mask; new_val = dev_priv->pm_irq_mask;
@ -332,6 +336,8 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
sdeimr &= ~interrupt_mask; sdeimr &= ~interrupt_mask;
sdeimr |= (~enabled_irq_mask & interrupt_mask); sdeimr |= (~enabled_irq_mask & interrupt_mask);
WARN_ON(enabled_irq_mask & ~interrupt_mask);
assert_spin_locked(&dev_priv->irq_lock); assert_spin_locked(&dev_priv->irq_lock);
if (WARN_ON(!intel_irqs_enabled(dev_priv))) if (WARN_ON(!intel_irqs_enabled(dev_priv)))
@ -1017,7 +1023,7 @@ static void notify_ring(struct drm_device *dev,
if (!intel_ring_initialized(ring)) if (!intel_ring_initialized(ring))
return; return;
trace_i915_gem_request_complete(ring); trace_i915_gem_request_notify(ring);
wake_up_all(&ring->irq_queue); wake_up_all(&ring->irq_queue);
} }
@ -1383,14 +1389,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (rcs & GT_RENDER_USER_INTERRUPT) if (rcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring); notify_ring(dev, ring);
if (rcs & GT_CONTEXT_SWITCH_INTERRUPT) if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
intel_execlists_handle_ctx_events(ring); intel_lrc_irq_handler(ring);
bcs = tmp >> GEN8_BCS_IRQ_SHIFT; bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
ring = &dev_priv->ring[BCS]; ring = &dev_priv->ring[BCS];
if (bcs & GT_RENDER_USER_INTERRUPT) if (bcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring); notify_ring(dev, ring);
if (bcs & GT_CONTEXT_SWITCH_INTERRUPT) if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
intel_execlists_handle_ctx_events(ring); intel_lrc_irq_handler(ring);
} else } else
DRM_ERROR("The master control interrupt lied (GT0)!\n"); DRM_ERROR("The master control interrupt lied (GT0)!\n");
} }
@ -1406,14 +1412,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (vcs & GT_RENDER_USER_INTERRUPT) if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring); notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
intel_execlists_handle_ctx_events(ring); intel_lrc_irq_handler(ring);
vcs = tmp >> GEN8_VCS2_IRQ_SHIFT; vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
ring = &dev_priv->ring[VCS2]; ring = &dev_priv->ring[VCS2];
if (vcs & GT_RENDER_USER_INTERRUPT) if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring); notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
intel_execlists_handle_ctx_events(ring); intel_lrc_irq_handler(ring);
} else } else
DRM_ERROR("The master control interrupt lied (GT1)!\n"); DRM_ERROR("The master control interrupt lied (GT1)!\n");
} }
@ -1440,7 +1446,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (vcs & GT_RENDER_USER_INTERRUPT) if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring); notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT) if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
intel_execlists_handle_ctx_events(ring); intel_lrc_irq_handler(ring);
} else } else
DRM_ERROR("The master control interrupt lied (GT3)!\n"); DRM_ERROR("The master control interrupt lied (GT3)!\n");
} }
@ -2753,18 +2759,18 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
} }
static u32 static struct drm_i915_gem_request *
ring_last_seqno(struct intel_engine_cs *ring) ring_last_request(struct intel_engine_cs *ring)
{ {
return list_entry(ring->request_list.prev, return list_entry(ring->request_list.prev,
struct drm_i915_gem_request, list)->seqno; struct drm_i915_gem_request, list);
} }
static bool static bool
ring_idle(struct intel_engine_cs *ring, u32 seqno) ring_idle(struct intel_engine_cs *ring)
{ {
return (list_empty(&ring->request_list) || return (list_empty(&ring->request_list) ||
i915_seqno_passed(seqno, ring_last_seqno(ring))); i915_gem_request_completed(ring_last_request(ring), false));
} }
static bool static bool
@ -2984,7 +2990,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
acthd = intel_ring_get_active_head(ring); acthd = intel_ring_get_active_head(ring);
if (ring->hangcheck.seqno == seqno) { if (ring->hangcheck.seqno == seqno) {
if (ring_idle(ring, seqno)) { if (ring_idle(ring)) {
ring->hangcheck.action = HANGCHECK_IDLE; ring->hangcheck.action = HANGCHECK_IDLE;
if (waitqueue_active(&ring->irq_queue)) { if (waitqueue_active(&ring->irq_queue)) {

Просмотреть файл

@ -35,7 +35,7 @@ struct i915_params i915 __read_mostly = {
.vbt_sdvo_panel_type = -1, .vbt_sdvo_panel_type = -1,
.enable_rc6 = -1, .enable_rc6 = -1,
.enable_fbc = -1, .enable_fbc = -1,
.enable_execlists = 0, .enable_execlists = -1,
.enable_hangcheck = true, .enable_hangcheck = true,
.enable_ppgtt = -1, .enable_ppgtt = -1,
.enable_psr = 0, .enable_psr = 0,
@ -51,6 +51,7 @@ struct i915_params i915 __read_mostly = {
.disable_vtd_wa = 0, .disable_vtd_wa = 0,
.use_mmio_flip = 0, .use_mmio_flip = 0,
.mmio_debug = 0, .mmio_debug = 0,
.verbose_state_checks = 1,
}; };
module_param_named(modeset, i915.modeset, int, 0400); module_param_named(modeset, i915.modeset, int, 0400);
@ -122,7 +123,7 @@ MODULE_PARM_DESC(enable_ppgtt,
module_param_named(enable_execlists, i915.enable_execlists, int, 0400); module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
MODULE_PARM_DESC(enable_execlists, MODULE_PARM_DESC(enable_execlists,
"Override execlists usage. " "Override execlists usage. "
"(-1=auto, 0=disabled [default], 1=enabled)"); "(-1=auto [default], 0=disabled, 1=enabled)");
module_param_named(enable_psr, i915.enable_psr, int, 0600); module_param_named(enable_psr, i915.enable_psr, int, 0600);
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)"); MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
@ -173,3 +174,7 @@ module_param_named(mmio_debug, i915.mmio_debug, bool, 0600);
MODULE_PARM_DESC(mmio_debug, MODULE_PARM_DESC(mmio_debug,
"Enable the MMIO debug code (default: false). This may negatively " "Enable the MMIO debug code (default: false). This may negatively "
"affect performance."); "affect performance.");
module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
MODULE_PARM_DESC(verbose_state_checks,
"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");

Просмотреть файл

@ -31,6 +31,8 @@
#define _PORT(port, a, b) ((a) + (port)*((b)-(a))) #define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
#define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \ #define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \
(pipe) == PIPE_B ? (b) : (c)) (pipe) == PIPE_B ? (b) : (c))
#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
(port) == PORT_B ? (b) : (c))
#define _MASKED_FIELD(mask, value) ({ \ #define _MASKED_FIELD(mask, value) ({ \
if (__builtin_constant_p(mask)) \ if (__builtin_constant_p(mask)) \
@ -217,6 +219,8 @@
#define INSTR_SUBCLIENT_SHIFT 27 #define INSTR_SUBCLIENT_SHIFT 27
#define INSTR_SUBCLIENT_MASK 0x18000000 #define INSTR_SUBCLIENT_MASK 0x18000000
#define INSTR_MEDIA_SUBCLIENT 0x2 #define INSTR_MEDIA_SUBCLIENT 0x2
#define INSTR_26_TO_24_MASK 0x7000000
#define INSTR_26_TO_24_SHIFT 24
/* /*
* Memory interface instructions used by the kernel * Memory interface instructions used by the kernel
@ -246,6 +250,7 @@
#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) #define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0) #define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0)
#define MI_SUSPEND_FLUSH_EN (1<<0) #define MI_SUSPEND_FLUSH_EN (1<<0)
#define MI_SET_APPID MI_INSTR(0x0e, 0)
#define MI_OVERLAY_FLIP MI_INSTR(0x11, 0) #define MI_OVERLAY_FLIP MI_INSTR(0x11, 0)
#define MI_OVERLAY_CONTINUE (0x0<<21) #define MI_OVERLAY_CONTINUE (0x0<<21)
#define MI_OVERLAY_ON (0x1<<21) #define MI_OVERLAY_ON (0x1<<21)
@ -303,8 +308,9 @@
#define MI_SEMAPHORE_POLL (1<<15) #define MI_SEMAPHORE_POLL (1<<15)
#define MI_SEMAPHORE_SAD_GTE_SDD (1<<12) #define MI_SEMAPHORE_SAD_GTE_SDD (1<<12)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) #define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
#define MI_STORE_DWORD_IMM_GEN8 MI_INSTR(0x20, 2) #define MI_STORE_DWORD_IMM_GEN4 MI_INSTR(0x20, 2)
#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ #define MI_MEM_VIRTUAL (1 << 22) /* 945,g33,965 */
#define MI_USE_GGTT (1 << 22) /* g4x+ */
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) #define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
#define MI_STORE_DWORD_INDEX_SHIFT 2 #define MI_STORE_DWORD_INDEX_SHIFT 2
/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM: /* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM:
@ -470,17 +476,18 @@
*/ */
#define BCS_SWCTRL 0x22200 #define BCS_SWCTRL 0x22200
#define HS_INVOCATION_COUNT 0x2300 #define GPGPU_THREADS_DISPATCHED 0x2290
#define DS_INVOCATION_COUNT 0x2308 #define HS_INVOCATION_COUNT 0x2300
#define IA_VERTICES_COUNT 0x2310 #define DS_INVOCATION_COUNT 0x2308
#define IA_PRIMITIVES_COUNT 0x2318 #define IA_VERTICES_COUNT 0x2310
#define VS_INVOCATION_COUNT 0x2320 #define IA_PRIMITIVES_COUNT 0x2318
#define GS_INVOCATION_COUNT 0x2328 #define VS_INVOCATION_COUNT 0x2320
#define GS_PRIMITIVES_COUNT 0x2330 #define GS_INVOCATION_COUNT 0x2328
#define CL_INVOCATION_COUNT 0x2338 #define GS_PRIMITIVES_COUNT 0x2330
#define CL_PRIMITIVES_COUNT 0x2340 #define CL_INVOCATION_COUNT 0x2338
#define PS_INVOCATION_COUNT 0x2348 #define CL_PRIMITIVES_COUNT 0x2340
#define PS_DEPTH_COUNT 0x2350 #define PS_INVOCATION_COUNT 0x2348
#define PS_DEPTH_COUNT 0x2350
/* There are the 4 64-bit counter registers, one for each stream output */ /* There are the 4 64-bit counter registers, one for each stream output */
#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8) #define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
@ -1509,7 +1516,7 @@ enum punit_power_well {
#define I915_ISP_INTERRUPT (1<<22) #define I915_ISP_INTERRUPT (1<<22)
#define I915_LPE_PIPE_B_INTERRUPT (1<<21) #define I915_LPE_PIPE_B_INTERRUPT (1<<21)
#define I915_LPE_PIPE_A_INTERRUPT (1<<20) #define I915_LPE_PIPE_A_INTERRUPT (1<<20)
#define I915_MIPIB_INTERRUPT (1<<19) #define I915_MIPIC_INTERRUPT (1<<19)
#define I915_MIPIA_INTERRUPT (1<<18) #define I915_MIPIA_INTERRUPT (1<<18)
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
#define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_DISPLAY_PORT_INTERRUPT (1<<17)
@ -2539,6 +2546,42 @@ enum punit_power_well {
#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC) #define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A) #define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
/* VLV eDP PSR registers */
#define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090)
#define _PSRCTLB (VLV_DISPLAY_BASE + 0x61090)
#define VLV_EDP_PSR_ENABLE (1<<0)
#define VLV_EDP_PSR_RESET (1<<1)
#define VLV_EDP_PSR_MODE_MASK (7<<2)
#define VLV_EDP_PSR_MODE_HW_TIMER (1<<3)
#define VLV_EDP_PSR_MODE_SW_TIMER (1<<2)
#define VLV_EDP_PSR_SINGLE_FRAME_UPDATE (1<<7)
#define VLV_EDP_PSR_ACTIVE_ENTRY (1<<8)
#define VLV_EDP_PSR_SRC_TRANSMITTER_STATE (1<<9)
#define VLV_EDP_PSR_DBL_FRAME (1<<10)
#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16)
#define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16
#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
#define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0)
#define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0)
#define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30)
#define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31)
#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30)
#define VLV_VSCSDP(pipe) _PIPE(pipe, _VSCSDPA, _VSCSDPB)
#define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094)
#define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094)
#define VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
#define VLV_EDP_PSR_CURR_STATE_MASK 7
#define VLV_EDP_PSR_DISABLED (0<<0)
#define VLV_EDP_PSR_INACTIVE (1<<0)
#define VLV_EDP_PSR_IN_TRANS_TO_ACTIVE (2<<0)
#define VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0)
#define VLV_EDP_PSR_EXIT (5<<0)
#define VLV_EDP_PSR_IN_TRANS (1<<7)
#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
/* HSW+ eDP PSR registers */ /* HSW+ eDP PSR registers */
#define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800) #define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
#define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0) #define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0)
@ -2762,7 +2805,8 @@ enum punit_power_well {
#define DC_BALANCE_RESET (1 << 25) #define DC_BALANCE_RESET (1 << 25)
#define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154) #define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154)
#define DC_BALANCE_RESET_VLV (1 << 31) #define DC_BALANCE_RESET_VLV (1 << 31)
#define PIPE_SCRAMBLE_RESET_MASK (0x3 << 0) #define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0))
#define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */
#define PIPE_B_SCRAMBLE_RESET (1 << 1) #define PIPE_B_SCRAMBLE_RESET (1 << 1)
#define PIPE_A_SCRAMBLE_RESET (1 << 0) #define PIPE_A_SCRAMBLE_RESET (1 << 0)
@ -6006,6 +6050,10 @@ enum punit_power_well {
#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31) #define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31)
#define VLV_PWRDWNUPCTL 0xA294 #define VLV_PWRDWNUPCTL 0xA294
#define VLV_CHICKEN_3 (VLV_DISPLAY_BASE + 0x7040C)
#define PIXEL_OVERLAP_CNT_MASK (3 << 30)
#define PIXEL_OVERLAP_CNT_SHIFT 30
#define GEN6_PMISR 0x44020 #define GEN6_PMISR 0x44020
#define GEN6_PMIMR 0x44024 /* rps_lock */ #define GEN6_PMIMR 0x44024 /* rps_lock */
#define GEN6_PMIIR 0x44028 #define GEN6_PMIIR 0x44028
@ -6631,29 +6679,31 @@ enum punit_power_well {
#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) #define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) #define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
/* VLV MIPI registers */ /* MIPI DSI registers */
#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */
#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190)
#define _MIPIB_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) #define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
#define MIPI_PORT_CTRL(tc) _TRANSCODER(tc, _MIPIA_PORT_CTRL, \ #define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
_MIPIB_PORT_CTRL) #define DPI_ENABLE (1 << 31) /* A + C */
#define DPI_ENABLE (1 << 31) /* A + B */
#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27
#define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) #define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27)
#define DUAL_LINK_MODE_SHIFT 26
#define DUAL_LINK_MODE_MASK (1 << 26) #define DUAL_LINK_MODE_MASK (1 << 26)
#define DUAL_LINK_MODE_FRONT_BACK (0 << 26) #define DUAL_LINK_MODE_FRONT_BACK (0 << 26)
#define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26) #define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26)
#define DITHERING_ENABLE (1 << 25) /* A + B */ #define DITHERING_ENABLE (1 << 25) /* A + C */
#define FLOPPED_HSTX (1 << 23) #define FLOPPED_HSTX (1 << 23)
#define DE_INVERT (1 << 19) /* XXX */ #define DE_INVERT (1 << 19) /* XXX */
#define MIPIA_FLISDSI_DELAY_COUNT_SHIFT 18 #define MIPIA_FLISDSI_DELAY_COUNT_SHIFT 18
#define MIPIA_FLISDSI_DELAY_COUNT_MASK (0xf << 18) #define MIPIA_FLISDSI_DELAY_COUNT_MASK (0xf << 18)
#define AFE_LATCHOUT (1 << 17) #define AFE_LATCHOUT (1 << 17)
#define LP_OUTPUT_HOLD (1 << 16) #define LP_OUTPUT_HOLD (1 << 16)
#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15 #define MIPIC_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15
#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15) #define MIPIC_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15)
#define MIPIB_MIPI4DPHY_DELAY_COUNT_SHIFT 11 #define MIPIC_MIPI4DPHY_DELAY_COUNT_SHIFT 11
#define MIPIB_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11) #define MIPIC_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11)
#define CSB_SHIFT 9 #define CSB_SHIFT 9
#define CSB_MASK (3 << 9) #define CSB_MASK (3 << 9)
#define CSB_20MHZ (0 << 9) #define CSB_20MHZ (0 << 9)
@ -6662,10 +6712,10 @@ enum punit_power_well {
#define BANDGAP_MASK (1 << 8) #define BANDGAP_MASK (1 << 8)
#define BANDGAP_PNW_CIRCUIT (0 << 8) #define BANDGAP_PNW_CIRCUIT (0 << 8)
#define BANDGAP_LNC_CIRCUIT (1 << 8) #define BANDGAP_LNC_CIRCUIT (1 << 8)
#define MIPIB_FLISDSI_DELAY_COUNT_LOW_SHIFT 5 #define MIPIC_FLISDSI_DELAY_COUNT_LOW_SHIFT 5
#define MIPIB_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5) #define MIPIC_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5)
#define TEARING_EFFECT_DELAY (1 << 4) /* A + B */ #define TEARING_EFFECT_DELAY (1 << 4) /* A + C */
#define TEARING_EFFECT_SHIFT 2 /* A + B */ #define TEARING_EFFECT_SHIFT 2 /* A + C */
#define TEARING_EFFECT_MASK (3 << 2) #define TEARING_EFFECT_MASK (3 << 2)
#define TEARING_EFFECT_OFF (0 << 2) #define TEARING_EFFECT_OFF (0 << 2)
#define TEARING_EFFECT_DSI (1 << 2) #define TEARING_EFFECT_DSI (1 << 2)
@ -6677,9 +6727,9 @@ enum punit_power_well {
#define LANE_CONFIGURATION_DUAL_LINK_B (2 << 0) #define LANE_CONFIGURATION_DUAL_LINK_B (2 << 0)
#define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194) #define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194)
#define _MIPIB_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704) #define _MIPIC_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704)
#define MIPI_TEARING_CTRL(tc) _TRANSCODER(tc, \ #define MIPI_TEARING_CTRL(port) _MIPI_PORT(port, \
_MIPIA_TEARING_CTRL, _MIPIB_TEARING_CTRL) _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
#define TEARING_EFFECT_DELAY_SHIFT 0 #define TEARING_EFFECT_DELAY_SHIFT 0
#define TEARING_EFFECT_DELAY_MASK (0xffff << 0) #define TEARING_EFFECT_DELAY_MASK (0xffff << 0)
@ -6689,9 +6739,9 @@ enum punit_power_well {
/* MIPI DSI Controller and D-PHY registers */ /* MIPI DSI Controller and D-PHY registers */
#define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000) #define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000)
#define _MIPIB_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800) #define _MIPIC_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800)
#define MIPI_DEVICE_READY(tc) _TRANSCODER(tc, _MIPIA_DEVICE_READY, \ #define MIPI_DEVICE_READY(port) _MIPI_PORT(port, _MIPIA_DEVICE_READY, \
_MIPIB_DEVICE_READY) _MIPIC_DEVICE_READY)
#define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */ #define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */
#define ULPS_STATE_MASK (3 << 1) #define ULPS_STATE_MASK (3 << 1)
#define ULPS_STATE_ENTER (2 << 1) #define ULPS_STATE_ENTER (2 << 1)
@ -6700,13 +6750,13 @@ enum punit_power_well {
#define DEVICE_READY (1 << 0) #define DEVICE_READY (1 << 0)
#define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004) #define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004)
#define _MIPIB_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804) #define _MIPIC_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804)
#define MIPI_INTR_STAT(tc) _TRANSCODER(tc, _MIPIA_INTR_STAT, \ #define MIPI_INTR_STAT(port) _MIPI_PORT(port, _MIPIA_INTR_STAT, \
_MIPIB_INTR_STAT) _MIPIC_INTR_STAT)
#define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008) #define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008)
#define _MIPIB_INTR_EN (dev_priv->mipi_mmio_base + 0xb808) #define _MIPIC_INTR_EN (dev_priv->mipi_mmio_base + 0xb808)
#define MIPI_INTR_EN(tc) _TRANSCODER(tc, _MIPIA_INTR_EN, \ #define MIPI_INTR_EN(port) _MIPI_PORT(port, _MIPIA_INTR_EN, \
_MIPIB_INTR_EN) _MIPIC_INTR_EN)
#define TEARING_EFFECT (1 << 31) #define TEARING_EFFECT (1 << 31)
#define SPL_PKT_SENT_INTERRUPT (1 << 30) #define SPL_PKT_SENT_INTERRUPT (1 << 30)
#define GEN_READ_DATA_AVAIL (1 << 29) #define GEN_READ_DATA_AVAIL (1 << 29)
@ -6741,9 +6791,9 @@ enum punit_power_well {
#define RXSOT_ERROR (1 << 0) #define RXSOT_ERROR (1 << 0)
#define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c) #define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c)
#define _MIPIB_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c) #define _MIPIC_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c)
#define MIPI_DSI_FUNC_PRG(tc) _TRANSCODER(tc, _MIPIA_DSI_FUNC_PRG, \ #define MIPI_DSI_FUNC_PRG(port) _MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \
_MIPIB_DSI_FUNC_PRG) _MIPIC_DSI_FUNC_PRG)
#define CMD_MODE_DATA_WIDTH_MASK (7 << 13) #define CMD_MODE_DATA_WIDTH_MASK (7 << 13)
#define CMD_MODE_NOT_SUPPORTED (0 << 13) #define CMD_MODE_NOT_SUPPORTED (0 << 13)
#define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13) #define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13)
@ -6765,93 +6815,93 @@ enum punit_power_well {
#define DATA_LANES_PRG_REG_MASK (7 << 0) #define DATA_LANES_PRG_REG_MASK (7 << 0)
#define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010) #define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010)
#define _MIPIB_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810) #define _MIPIC_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810)
#define MIPI_HS_TX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_HS_TX_TIMEOUT, \ #define MIPI_HS_TX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \
_MIPIB_HS_TX_TIMEOUT) _MIPIC_HS_TX_TIMEOUT)
#define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff #define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014) #define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014)
#define _MIPIB_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814) #define _MIPIC_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814)
#define MIPI_LP_RX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_LP_RX_TIMEOUT, \ #define MIPI_LP_RX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \
_MIPIB_LP_RX_TIMEOUT) _MIPIC_LP_RX_TIMEOUT)
#define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff #define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018) #define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018)
#define _MIPIB_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818) #define _MIPIC_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818)
#define MIPI_TURN_AROUND_TIMEOUT(tc) _TRANSCODER(tc, \ #define MIPI_TURN_AROUND_TIMEOUT(port) _MIPI_PORT(port, \
_MIPIA_TURN_AROUND_TIMEOUT, _MIPIB_TURN_AROUND_TIMEOUT) _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
#define TURN_AROUND_TIMEOUT_MASK 0x3f #define TURN_AROUND_TIMEOUT_MASK 0x3f
#define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c) #define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c)
#define _MIPIB_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c) #define _MIPIC_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c)
#define MIPI_DEVICE_RESET_TIMER(tc) _TRANSCODER(tc, \ #define MIPI_DEVICE_RESET_TIMER(port) _MIPI_PORT(port, \
_MIPIA_DEVICE_RESET_TIMER, _MIPIB_DEVICE_RESET_TIMER) _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
#define DEVICE_RESET_TIMER_MASK 0xffff #define DEVICE_RESET_TIMER_MASK 0xffff
#define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020) #define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020)
#define _MIPIB_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820) #define _MIPIC_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820)
#define MIPI_DPI_RESOLUTION(tc) _TRANSCODER(tc, _MIPIA_DPI_RESOLUTION, \ #define MIPI_DPI_RESOLUTION(port) _MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \
_MIPIB_DPI_RESOLUTION) _MIPIC_DPI_RESOLUTION)
#define VERTICAL_ADDRESS_SHIFT 16 #define VERTICAL_ADDRESS_SHIFT 16
#define VERTICAL_ADDRESS_MASK (0xffff << 16) #define VERTICAL_ADDRESS_MASK (0xffff << 16)
#define HORIZONTAL_ADDRESS_SHIFT 0 #define HORIZONTAL_ADDRESS_SHIFT 0
#define HORIZONTAL_ADDRESS_MASK 0xffff #define HORIZONTAL_ADDRESS_MASK 0xffff
#define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024) #define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024)
#define _MIPIB_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824) #define _MIPIC_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824)
#define MIPI_DBI_FIFO_THROTTLE(tc) _TRANSCODER(tc, \ #define MIPI_DBI_FIFO_THROTTLE(port) _MIPI_PORT(port, \
_MIPIA_DBI_FIFO_THROTTLE, _MIPIB_DBI_FIFO_THROTTLE) _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
#define DBI_FIFO_EMPTY_HALF (0 << 0) #define DBI_FIFO_EMPTY_HALF (0 << 0)
#define DBI_FIFO_EMPTY_QUARTER (1 << 0) #define DBI_FIFO_EMPTY_QUARTER (1 << 0)
#define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0) #define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0)
/* regs below are bits 15:0 */ /* regs below are bits 15:0 */
#define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028) #define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028)
#define _MIPIB_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828) #define _MIPIC_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828)
#define MIPI_HSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \ #define MIPI_HSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
_MIPIA_HSYNC_PADDING_COUNT, _MIPIB_HSYNC_PADDING_COUNT) _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
#define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c) #define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c)
#define _MIPIB_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c) #define _MIPIC_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c)
#define MIPI_HBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HBP_COUNT, \ #define MIPI_HBP_COUNT(port) _MIPI_PORT(port, _MIPIA_HBP_COUNT, \
_MIPIB_HBP_COUNT) _MIPIC_HBP_COUNT)
#define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030) #define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030)
#define _MIPIB_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830) #define _MIPIC_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830)
#define MIPI_HFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HFP_COUNT, \ #define MIPI_HFP_COUNT(port) _MIPI_PORT(port, _MIPIA_HFP_COUNT, \
_MIPIB_HFP_COUNT) _MIPIC_HFP_COUNT)
#define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034) #define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034)
#define _MIPIB_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834) #define _MIPIC_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834)
#define MIPI_HACTIVE_AREA_COUNT(tc) _TRANSCODER(tc, \ #define MIPI_HACTIVE_AREA_COUNT(port) _MIPI_PORT(port, \
_MIPIA_HACTIVE_AREA_COUNT, _MIPIB_HACTIVE_AREA_COUNT) _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
#define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038) #define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038)
#define _MIPIB_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838) #define _MIPIC_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838)
#define MIPI_VSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \ #define MIPI_VSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
_MIPIA_VSYNC_PADDING_COUNT, _MIPIB_VSYNC_PADDING_COUNT) _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
#define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c) #define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c)
#define _MIPIB_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c) #define _MIPIC_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c)
#define MIPI_VBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VBP_COUNT, \ #define MIPI_VBP_COUNT(port) _MIPI_PORT(port, _MIPIA_VBP_COUNT, \
_MIPIB_VBP_COUNT) _MIPIC_VBP_COUNT)
#define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040) #define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040)
#define _MIPIB_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840) #define _MIPIC_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840)
#define MIPI_VFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VFP_COUNT, \ #define MIPI_VFP_COUNT(port) _MIPI_PORT(port, _MIPIA_VFP_COUNT, \
_MIPIB_VFP_COUNT) _MIPIC_VFP_COUNT)
#define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044) #define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044)
#define _MIPIB_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844) #define _MIPIC_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844)
#define MIPI_HIGH_LOW_SWITCH_COUNT(tc) _TRANSCODER(tc, \ #define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MIPI_PORT(port, \
_MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIB_HIGH_LOW_SWITCH_COUNT) _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
/* regs above are bits 15:0 */ /* regs above are bits 15:0 */
#define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048) #define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048)
#define _MIPIB_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848) #define _MIPIC_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848)
#define MIPI_DPI_CONTROL(tc) _TRANSCODER(tc, _MIPIA_DPI_CONTROL, \ #define MIPI_DPI_CONTROL(port) _MIPI_PORT(port, _MIPIA_DPI_CONTROL, \
_MIPIB_DPI_CONTROL) _MIPIC_DPI_CONTROL)
#define DPI_LP_MODE (1 << 6) #define DPI_LP_MODE (1 << 6)
#define BACKLIGHT_OFF (1 << 5) #define BACKLIGHT_OFF (1 << 5)
#define BACKLIGHT_ON (1 << 4) #define BACKLIGHT_ON (1 << 4)
@ -6861,30 +6911,30 @@ enum punit_power_well {
#define SHUTDOWN (1 << 0) #define SHUTDOWN (1 << 0)
#define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c) #define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c)
#define _MIPIB_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c) #define _MIPIC_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c)
#define MIPI_DPI_DATA(tc) _TRANSCODER(tc, _MIPIA_DPI_DATA, \ #define MIPI_DPI_DATA(port) _MIPI_PORT(port, _MIPIA_DPI_DATA, \
_MIPIB_DPI_DATA) _MIPIC_DPI_DATA)
#define COMMAND_BYTE_SHIFT 0 #define COMMAND_BYTE_SHIFT 0
#define COMMAND_BYTE_MASK (0x3f << 0) #define COMMAND_BYTE_MASK (0x3f << 0)
#define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050) #define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050)
#define _MIPIB_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850) #define _MIPIC_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850)
#define MIPI_INIT_COUNT(tc) _TRANSCODER(tc, _MIPIA_INIT_COUNT, \ #define MIPI_INIT_COUNT(port) _MIPI_PORT(port, _MIPIA_INIT_COUNT, \
_MIPIB_INIT_COUNT) _MIPIC_INIT_COUNT)
#define MASTER_INIT_TIMER_SHIFT 0 #define MASTER_INIT_TIMER_SHIFT 0
#define MASTER_INIT_TIMER_MASK (0xffff << 0) #define MASTER_INIT_TIMER_MASK (0xffff << 0)
#define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054) #define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054)
#define _MIPIB_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854) #define _MIPIC_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854)
#define MIPI_MAX_RETURN_PKT_SIZE(tc) _TRANSCODER(tc, \ #define MIPI_MAX_RETURN_PKT_SIZE(port) _MIPI_PORT(port, \
_MIPIA_MAX_RETURN_PKT_SIZE, _MIPIB_MAX_RETURN_PKT_SIZE) _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE)
#define MAX_RETURN_PKT_SIZE_SHIFT 0 #define MAX_RETURN_PKT_SIZE_SHIFT 0
#define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0) #define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0)
#define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058) #define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058)
#define _MIPIB_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858) #define _MIPIC_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858)
#define MIPI_VIDEO_MODE_FORMAT(tc) _TRANSCODER(tc, \ #define MIPI_VIDEO_MODE_FORMAT(port) _MIPI_PORT(port, \
_MIPIA_VIDEO_MODE_FORMAT, _MIPIB_VIDEO_MODE_FORMAT) _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
#define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4) #define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4)
#define DISABLE_VIDEO_BTA (1 << 3) #define DISABLE_VIDEO_BTA (1 << 3)
#define IP_TG_CONFIG (1 << 2) #define IP_TG_CONFIG (1 << 2)
@ -6893,9 +6943,9 @@ enum punit_power_well {
#define VIDEO_MODE_BURST (3 << 0) #define VIDEO_MODE_BURST (3 << 0)
#define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c) #define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c)
#define _MIPIB_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c) #define _MIPIC_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c)
#define MIPI_EOT_DISABLE(tc) _TRANSCODER(tc, _MIPIA_EOT_DISABLE, \ #define MIPI_EOT_DISABLE(port) _MIPI_PORT(port, _MIPIA_EOT_DISABLE, \
_MIPIB_EOT_DISABLE) _MIPIC_EOT_DISABLE)
#define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7) #define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7)
#define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6) #define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6)
#define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5) #define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5)
@ -6906,32 +6956,32 @@ enum punit_power_well {
#define EOT_DISABLE (1 << 0) #define EOT_DISABLE (1 << 0)
#define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060) #define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060)
#define _MIPIB_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860) #define _MIPIC_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860)
#define MIPI_LP_BYTECLK(tc) _TRANSCODER(tc, _MIPIA_LP_BYTECLK, \ #define MIPI_LP_BYTECLK(port) _MIPI_PORT(port, _MIPIA_LP_BYTECLK, \
_MIPIB_LP_BYTECLK) _MIPIC_LP_BYTECLK)
#define LP_BYTECLK_SHIFT 0 #define LP_BYTECLK_SHIFT 0
#define LP_BYTECLK_MASK (0xffff << 0) #define LP_BYTECLK_MASK (0xffff << 0)
/* bits 31:0 */ /* bits 31:0 */
#define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064) #define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064)
#define _MIPIB_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864) #define _MIPIC_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864)
#define MIPI_LP_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_DATA, \ #define MIPI_LP_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \
_MIPIB_LP_GEN_DATA) _MIPIC_LP_GEN_DATA)
/* bits 31:0 */ /* bits 31:0 */
#define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068) #define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068)
#define _MIPIB_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868) #define _MIPIC_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868)
#define MIPI_HS_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_DATA, \ #define MIPI_HS_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \
_MIPIB_HS_GEN_DATA) _MIPIC_HS_GEN_DATA)
#define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c) #define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c)
#define _MIPIB_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c) #define _MIPIC_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c)
#define MIPI_LP_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_CTRL, \ #define MIPI_LP_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \
_MIPIB_LP_GEN_CTRL) _MIPIC_LP_GEN_CTRL)
#define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070) #define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070)
#define _MIPIB_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870) #define _MIPIC_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870)
#define MIPI_HS_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_CTRL, \ #define MIPI_HS_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \
_MIPIB_HS_GEN_CTRL) _MIPIC_HS_GEN_CTRL)
#define LONG_PACKET_WORD_COUNT_SHIFT 8 #define LONG_PACKET_WORD_COUNT_SHIFT 8
#define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8) #define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8)
#define SHORT_PACKET_PARAM_SHIFT 8 #define SHORT_PACKET_PARAM_SHIFT 8
@ -6943,9 +6993,9 @@ enum punit_power_well {
/* data type values, see include/video/mipi_display.h */ /* data type values, see include/video/mipi_display.h */
#define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074) #define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074)
#define _MIPIB_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874) #define _MIPIC_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874)
#define MIPI_GEN_FIFO_STAT(tc) _TRANSCODER(tc, _MIPIA_GEN_FIFO_STAT, \ #define MIPI_GEN_FIFO_STAT(port) _MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \
_MIPIB_GEN_FIFO_STAT) _MIPIC_GEN_FIFO_STAT)
#define DPI_FIFO_EMPTY (1 << 28) #define DPI_FIFO_EMPTY (1 << 28)
#define DBI_FIFO_EMPTY (1 << 27) #define DBI_FIFO_EMPTY (1 << 27)
#define LP_CTRL_FIFO_EMPTY (1 << 26) #define LP_CTRL_FIFO_EMPTY (1 << 26)
@ -6962,17 +7012,17 @@ enum punit_power_well {
#define HS_DATA_FIFO_FULL (1 << 0) #define HS_DATA_FIFO_FULL (1 << 0)
#define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078) #define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078)
#define _MIPIB_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878) #define _MIPIC_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878)
#define MIPI_HS_LP_DBI_ENABLE(tc) _TRANSCODER(tc, \ #define MIPI_HS_LP_DBI_ENABLE(port) _MIPI_PORT(port, \
_MIPIA_HS_LS_DBI_ENABLE, _MIPIB_HS_LS_DBI_ENABLE) _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
#define DBI_HS_LP_MODE_MASK (1 << 0) #define DBI_HS_LP_MODE_MASK (1 << 0)
#define DBI_LP_MODE (1 << 0) #define DBI_LP_MODE (1 << 0)
#define DBI_HS_MODE (0 << 0) #define DBI_HS_MODE (0 << 0)
#define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080) #define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080)
#define _MIPIB_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880) #define _MIPIC_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880)
#define MIPI_DPHY_PARAM(tc) _TRANSCODER(tc, _MIPIA_DPHY_PARAM, \ #define MIPI_DPHY_PARAM(port) _MIPI_PORT(port, _MIPIA_DPHY_PARAM, \
_MIPIB_DPHY_PARAM) _MIPIC_DPHY_PARAM)
#define EXIT_ZERO_COUNT_SHIFT 24 #define EXIT_ZERO_COUNT_SHIFT 24
#define EXIT_ZERO_COUNT_MASK (0x3f << 24) #define EXIT_ZERO_COUNT_MASK (0x3f << 24)
#define TRAIL_COUNT_SHIFT 16 #define TRAIL_COUNT_SHIFT 16
@ -6984,36 +7034,36 @@ enum punit_power_well {
/* bits 31:0 */ /* bits 31:0 */
#define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084) #define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084)
#define _MIPIB_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884) #define _MIPIC_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884)
#define MIPI_DBI_BW_CTRL(tc) _TRANSCODER(tc, _MIPIA_DBI_BW_CTRL, \ #define MIPI_DBI_BW_CTRL(port) _MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \
_MIPIB_DBI_BW_CTRL) _MIPIC_DBI_BW_CTRL)
#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ #define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
+ 0xb088) + 0xb088)
#define _MIPIB_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ #define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
+ 0xb888) + 0xb888)
#define MIPI_CLK_LANE_SWITCH_TIME_CNT(tc) _TRANSCODER(tc, \ #define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MIPI_PORT(port, \
_MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIB_CLK_LANE_SWITCH_TIME_CNT) _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
#define LP_HS_SSW_CNT_SHIFT 16 #define LP_HS_SSW_CNT_SHIFT 16
#define LP_HS_SSW_CNT_MASK (0xffff << 16) #define LP_HS_SSW_CNT_MASK (0xffff << 16)
#define HS_LP_PWR_SW_CNT_SHIFT 0 #define HS_LP_PWR_SW_CNT_SHIFT 0
#define HS_LP_PWR_SW_CNT_MASK (0xffff << 0) #define HS_LP_PWR_SW_CNT_MASK (0xffff << 0)
#define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c) #define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c)
#define _MIPIB_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c) #define _MIPIC_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c)
#define MIPI_STOP_STATE_STALL(tc) _TRANSCODER(tc, \ #define MIPI_STOP_STATE_STALL(port) _MIPI_PORT(port, \
_MIPIA_STOP_STATE_STALL, _MIPIB_STOP_STATE_STALL) _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
#define STOP_STATE_STALL_COUNTER_SHIFT 0 #define STOP_STATE_STALL_COUNTER_SHIFT 0
#define STOP_STATE_STALL_COUNTER_MASK (0xff << 0) #define STOP_STATE_STALL_COUNTER_MASK (0xff << 0)
#define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090) #define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090)
#define _MIPIB_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890) #define _MIPIC_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890)
#define MIPI_INTR_STAT_REG_1(tc) _TRANSCODER(tc, \ #define MIPI_INTR_STAT_REG_1(port) _MIPI_PORT(port, \
_MIPIA_INTR_STAT_REG_1, _MIPIB_INTR_STAT_REG_1) _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
#define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094) #define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094)
#define _MIPIB_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894) #define _MIPIC_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894)
#define MIPI_INTR_EN_REG_1(tc) _TRANSCODER(tc, _MIPIA_INTR_EN_REG_1, \ #define MIPI_INTR_EN_REG_1(port) _MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \
_MIPIB_INTR_EN_REG_1) _MIPIC_INTR_EN_REG_1)
#define RX_CONTENTION_DETECTED (1 << 0) #define RX_CONTENTION_DETECTED (1 << 0)
/* XXX: only pipe A ?!? */ /* XXX: only pipe A ?!? */
@ -7032,9 +7082,9 @@ enum punit_power_well {
/* MIPI adapter registers */ /* MIPI adapter registers */
#define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104) #define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104)
#define _MIPIB_CTRL (dev_priv->mipi_mmio_base + 0xb904) #define _MIPIC_CTRL (dev_priv->mipi_mmio_base + 0xb904)
#define MIPI_CTRL(tc) _TRANSCODER(tc, _MIPIA_CTRL, \ #define MIPI_CTRL(port) _MIPI_PORT(port, _MIPIA_CTRL, \
_MIPIB_CTRL) _MIPIC_CTRL)
#define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */ #define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */
#define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5) #define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5)
#define ESCAPE_CLOCK_DIVIDER_1 (0 << 5) #define ESCAPE_CLOCK_DIVIDER_1 (0 << 5)
@ -7047,24 +7097,24 @@ enum punit_power_well {
#define RGB_FLIP_TO_BGR (1 << 2) #define RGB_FLIP_TO_BGR (1 << 2)
#define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108) #define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108)
#define _MIPIB_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908) #define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908)
#define MIPI_DATA_ADDRESS(tc) _TRANSCODER(tc, _MIPIA_DATA_ADDRESS, \ #define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
_MIPIB_DATA_ADDRESS) _MIPIC_DATA_ADDRESS)
#define DATA_MEM_ADDRESS_SHIFT 5 #define DATA_MEM_ADDRESS_SHIFT 5
#define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5) #define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define DATA_VALID (1 << 0) #define DATA_VALID (1 << 0)
#define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c) #define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c)
#define _MIPIB_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c) #define _MIPIC_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c)
#define MIPI_DATA_LENGTH(tc) _TRANSCODER(tc, _MIPIA_DATA_LENGTH, \ #define MIPI_DATA_LENGTH(port) _MIPI_PORT(port, _MIPIA_DATA_LENGTH, \
_MIPIB_DATA_LENGTH) _MIPIC_DATA_LENGTH)
#define DATA_LENGTH_SHIFT 0 #define DATA_LENGTH_SHIFT 0
#define DATA_LENGTH_MASK (0xfffff << 0) #define DATA_LENGTH_MASK (0xfffff << 0)
#define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110) #define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110)
#define _MIPIB_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910) #define _MIPIC_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910)
#define MIPI_COMMAND_ADDRESS(tc) _TRANSCODER(tc, \ #define MIPI_COMMAND_ADDRESS(port) _MIPI_PORT(port, \
_MIPIA_COMMAND_ADDRESS, _MIPIB_COMMAND_ADDRESS) _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
#define COMMAND_MEM_ADDRESS_SHIFT 5 #define COMMAND_MEM_ADDRESS_SHIFT 5
#define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5) #define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define AUTO_PWG_ENABLE (1 << 2) #define AUTO_PWG_ENABLE (1 << 2)
@ -7072,22 +7122,22 @@ enum punit_power_well {
#define COMMAND_VALID (1 << 0) #define COMMAND_VALID (1 << 0)
#define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114) #define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114)
#define _MIPIB_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914) #define _MIPIC_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914)
#define MIPI_COMMAND_LENGTH(tc) _TRANSCODER(tc, _MIPIA_COMMAND_LENGTH, \ #define MIPI_COMMAND_LENGTH(port) _MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \
_MIPIB_COMMAND_LENGTH) _MIPIC_COMMAND_LENGTH)
#define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */ #define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */
#define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n))) #define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n)))
#define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118) #define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118)
#define _MIPIB_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918) #define _MIPIC_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918)
#define MIPI_READ_DATA_RETURN(tc, n) \ #define MIPI_READ_DATA_RETURN(port, n) \
(_TRANSCODER(tc, _MIPIA_READ_DATA_RETURN0, _MIPIB_READ_DATA_RETURN0) \ (_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \
+ 4 * (n)) /* n: 0...7 */ + 4 * (n)) /* n: 0...7 */
#define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138) #define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138)
#define _MIPIB_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938) #define _MIPIC_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938)
#define MIPI_READ_DATA_VALID(tc) _TRANSCODER(tc, \ #define MIPI_READ_DATA_VALID(port) _MIPI_PORT(port, \
_MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID) _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
#define READ_DATA_VALID(n) (1 << (n)) #define READ_DATA_VALID(n) (1 << (n))
/* For UMS only (deprecated): */ /* For UMS only (deprecated): */

Просмотреть файл

@ -264,7 +264,7 @@ static void i915_restore_display(struct drm_device *dev)
} }
/* only restore FBC info on the platform that supports FBC*/ /* only restore FBC info on the platform that supports FBC*/
intel_disable_fbc(dev); intel_fbc_disable(dev);
/* restore FBC interval */ /* restore FBC interval */
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))

Просмотреть файл

@ -328,8 +328,8 @@ TRACE_EVENT(i915_gem_evict_vm,
TRACE_EVENT(i915_gem_ring_sync_to, TRACE_EVENT(i915_gem_ring_sync_to,
TP_PROTO(struct intel_engine_cs *from, TP_PROTO(struct intel_engine_cs *from,
struct intel_engine_cs *to, struct intel_engine_cs *to,
u32 seqno), struct drm_i915_gem_request *req),
TP_ARGS(from, to, seqno), TP_ARGS(from, to, req),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, dev) __field(u32, dev)
@ -342,7 +342,7 @@ TRACE_EVENT(i915_gem_ring_sync_to,
__entry->dev = from->dev->primary->index; __entry->dev = from->dev->primary->index;
__entry->sync_from = from->id; __entry->sync_from = from->id;
__entry->sync_to = to->id; __entry->sync_to = to->id;
__entry->seqno = seqno; __entry->seqno = i915_gem_request_get_seqno(req);
), ),
TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u", TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u",
@ -352,8 +352,8 @@ TRACE_EVENT(i915_gem_ring_sync_to,
); );
TRACE_EVENT(i915_gem_ring_dispatch, TRACE_EVENT(i915_gem_ring_dispatch,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno, u32 flags), TP_PROTO(struct drm_i915_gem_request *req, u32 flags),
TP_ARGS(ring, seqno, flags), TP_ARGS(req, flags),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, dev) __field(u32, dev)
@ -363,11 +363,13 @@ TRACE_EVENT(i915_gem_ring_dispatch,
), ),
TP_fast_assign( TP_fast_assign(
struct intel_engine_cs *ring =
i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index; __entry->dev = ring->dev->primary->index;
__entry->ring = ring->id; __entry->ring = ring->id;
__entry->seqno = seqno; __entry->seqno = i915_gem_request_get_seqno(req);
__entry->flags = flags; __entry->flags = flags;
i915_trace_irq_get(ring, seqno); i915_trace_irq_get(ring, req);
), ),
TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x", TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x",
@ -398,31 +400,36 @@ TRACE_EVENT(i915_gem_ring_flush,
); );
DECLARE_EVENT_CLASS(i915_gem_request, DECLARE_EVENT_CLASS(i915_gem_request,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno), TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(ring, seqno), TP_ARGS(req),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, dev) __field(u32, dev)
__field(u32, ring) __field(u32, ring)
__field(u32, uniq)
__field(u32, seqno) __field(u32, seqno)
), ),
TP_fast_assign( TP_fast_assign(
struct intel_engine_cs *ring =
i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index; __entry->dev = ring->dev->primary->index;
__entry->ring = ring->id; __entry->ring = ring->id;
__entry->seqno = seqno; __entry->uniq = req ? req->uniq : 0;
__entry->seqno = i915_gem_request_get_seqno(req);
), ),
TP_printk("dev=%u, ring=%u, seqno=%u", TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u",
__entry->dev, __entry->ring, __entry->seqno) __entry->dev, __entry->ring, __entry->uniq,
__entry->seqno)
); );
DEFINE_EVENT(i915_gem_request, i915_gem_request_add, DEFINE_EVENT(i915_gem_request, i915_gem_request_add,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno), TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(ring, seqno) TP_ARGS(req)
); );
TRACE_EVENT(i915_gem_request_complete, TRACE_EVENT(i915_gem_request_notify,
TP_PROTO(struct intel_engine_cs *ring), TP_PROTO(struct intel_engine_cs *ring),
TP_ARGS(ring), TP_ARGS(ring),
@ -443,17 +450,23 @@ TRACE_EVENT(i915_gem_request_complete,
); );
DEFINE_EVENT(i915_gem_request, i915_gem_request_retire, DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno), TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(ring, seqno) TP_ARGS(req)
);
DEFINE_EVENT(i915_gem_request, i915_gem_request_complete,
TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(req)
); );
TRACE_EVENT(i915_gem_request_wait_begin, TRACE_EVENT(i915_gem_request_wait_begin,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno), TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(ring, seqno), TP_ARGS(req),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(u32, dev) __field(u32, dev)
__field(u32, ring) __field(u32, ring)
__field(u32, uniq)
__field(u32, seqno) __field(u32, seqno)
__field(bool, blocking) __field(bool, blocking)
), ),
@ -465,20 +478,24 @@ TRACE_EVENT(i915_gem_request_wait_begin,
* less desirable. * less desirable.
*/ */
TP_fast_assign( TP_fast_assign(
struct intel_engine_cs *ring =
i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index; __entry->dev = ring->dev->primary->index;
__entry->ring = ring->id; __entry->ring = ring->id;
__entry->seqno = seqno; __entry->uniq = req ? req->uniq : 0;
__entry->blocking = mutex_is_locked(&ring->dev->struct_mutex); __entry->seqno = i915_gem_request_get_seqno(req);
__entry->blocking =
mutex_is_locked(&ring->dev->struct_mutex);
), ),
TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s", TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u, blocking=%s",
__entry->dev, __entry->ring, __entry->seqno, __entry->dev, __entry->ring, __entry->uniq,
__entry->blocking ? "yes (NB)" : "no") __entry->seqno, __entry->blocking ? "yes (NB)" : "no")
); );
DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end, DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
TP_PROTO(struct intel_engine_cs *ring, u32 seqno), TP_PROTO(struct drm_i915_gem_request *req),
TP_ARGS(ring, seqno) TP_ARGS(req)
); );
DECLARE_EVENT_CLASS(i915_ring, DECLARE_EVENT_CLASS(i915_ring,

Просмотреть файл

@ -314,6 +314,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
{ {
const struct bdb_lfp_backlight_data *backlight_data; const struct bdb_lfp_backlight_data *backlight_data;
const struct bdb_lfp_backlight_data_entry *entry; const struct bdb_lfp_backlight_data_entry *entry;
const struct bdb_lfp_backlight_control_data *bl_ctrl_data;
backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
if (!backlight_data) if (!backlight_data)
@ -326,6 +327,7 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
} }
entry = &backlight_data->data[panel_type]; entry = &backlight_data->data[panel_type];
bl_ctrl_data = &backlight_data->blc_ctl[panel_type];
dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM;
if (!dev_priv->vbt.backlight.present) { if (!dev_priv->vbt.backlight.present) {
@ -337,12 +339,30 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
dev_priv->vbt.backlight.min_brightness = entry->min_brightness; dev_priv->vbt.backlight.min_brightness = entry->min_brightness;
dev_priv->vbt.backlight.controller = 0;
if (bdb->version >= 191) {
dev_priv->vbt.backlight.present =
bl_ctrl_data->pin == BLC_CONTROL_PIN_DDI;
if (!dev_priv->vbt.backlight.present) {
DRM_DEBUG_KMS("BL control pin is not DDI (pin %u)\n",
bl_ctrl_data->pin);
return;
}
if (bl_ctrl_data->controller == 1)
dev_priv->vbt.backlight.controller =
bl_ctrl_data->controller;
}
DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, "
"active %s, min brightness %u, level %u\n", "active %s, min brightness %u, level %u\n",
dev_priv->vbt.backlight.pwm_freq_hz, dev_priv->vbt.backlight.pwm_freq_hz,
dev_priv->vbt.backlight.active_low_pwm ? "low" : "high", dev_priv->vbt.backlight.active_low_pwm ? "low" : "high",
dev_priv->vbt.backlight.min_brightness, dev_priv->vbt.backlight.min_brightness,
backlight_data->level[panel_type]); backlight_data->level[panel_type]);
DRM_DEBUG_KMS("VBT BL controller %u\n",
dev_priv->vbt.backlight.controller);
} }
/* Try to find sdvo panel data */ /* Try to find sdvo panel data */
@ -664,6 +684,50 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
} }
} }
static void
parse_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
{
struct bdb_psr *psr;
struct psr_table *psr_table;
psr = find_section(bdb, BDB_PSR);
if (!psr) {
DRM_DEBUG_KMS("No PSR BDB found.\n");
return;
}
psr_table = &psr->psr_table[panel_type];
dev_priv->vbt.psr.full_link = psr_table->full_link;
dev_priv->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup;
/* Allowed VBT values goes from 0 to 15 */
dev_priv->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 :
psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames;
switch (psr_table->lines_to_wait) {
case 0:
dev_priv->vbt.psr.lines_to_wait = PSR_0_LINES_TO_WAIT;
break;
case 1:
dev_priv->vbt.psr.lines_to_wait = PSR_1_LINE_TO_WAIT;
break;
case 2:
dev_priv->vbt.psr.lines_to_wait = PSR_4_LINES_TO_WAIT;
break;
case 3:
dev_priv->vbt.psr.lines_to_wait = PSR_8_LINES_TO_WAIT;
break;
default:
DRM_DEBUG_KMS("VBT has unknown PSR lines to wait %u\n",
psr_table->lines_to_wait);
break;
}
dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time;
dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time;
}
static u8 *goto_next_sequence(u8 *data, int *size) static u8 *goto_next_sequence(u8 *data, int *size)
{ {
u16 len; u16 len;
@ -1241,6 +1305,7 @@ intel_parse_bios(struct drm_device *dev)
parse_device_mapping(dev_priv, bdb); parse_device_mapping(dev_priv, bdb);
parse_driver_features(dev_priv, bdb); parse_driver_features(dev_priv, bdb);
parse_edp(dev_priv, bdb); parse_edp(dev_priv, bdb);
parse_psr(dev_priv, bdb);
parse_mipi(dev_priv, bdb); parse_mipi(dev_priv, bdb);
parse_ddi_ports(dev_priv, bdb); parse_ddi_ports(dev_priv, bdb);

Просмотреть файл

@ -80,7 +80,7 @@ struct vbios_data {
#define BDB_EXT_MMIO_REGS 6 #define BDB_EXT_MMIO_REGS 6
#define BDB_SWF_IO 7 #define BDB_SWF_IO 7
#define BDB_SWF_MMIO 8 #define BDB_SWF_MMIO 8
#define BDB_DOT_CLOCK_TABLE 9 #define BDB_PSR 9
#define BDB_MODE_REMOVAL_TABLE 10 #define BDB_MODE_REMOVAL_TABLE 10
#define BDB_CHILD_DEVICE_TABLE 11 #define BDB_CHILD_DEVICE_TABLE 11
#define BDB_DRIVER_FEATURES 12 #define BDB_DRIVER_FEATURES 12
@ -402,10 +402,21 @@ struct bdb_lfp_backlight_data_entry {
u8 obsolete3; u8 obsolete3;
} __packed; } __packed;
#define BLC_CONTROL_PIN_PMIC 0
#define BLC_CONTROL_PIN_LPSS_PWM 1
#define BLC_CONTROL_PIN_DDI 2
#define BLC_CONTROL_PIN_CABC 3
struct bdb_lfp_backlight_control_data {
u8 controller:4;
u8 pin:4;
} __packed;
struct bdb_lfp_backlight_data { struct bdb_lfp_backlight_data {
u8 entry_size; u8 entry_size;
struct bdb_lfp_backlight_data_entry data[16]; struct bdb_lfp_backlight_data_entry data[16];
u8 level[16]; u8 level[16];
struct bdb_lfp_backlight_control_data blc_ctl[16];
} __packed; } __packed;
struct aimdb_header { struct aimdb_header {
@ -556,6 +567,26 @@ struct bdb_edp {
u16 edp_t3_optimization; u16 edp_t3_optimization;
} __packed; } __packed;
struct psr_table {
/* Feature bits */
u8 full_link:1;
u8 require_aux_to_wakeup:1;
u8 feature_bits_rsvd:6;
/* Wait times */
u8 idle_frames:4;
u8 lines_to_wait:3;
u8 wait_times_rsvd:1;
/* TP wake up time in multiple of 100 */
u16 tp1_wakeup_time;
u16 tp2_tp3_wakeup_time;
} __packed;
struct bdb_psr {
struct psr_table psr_table[16];
} __packed;
void intel_setup_bios(struct drm_device *dev); void intel_setup_bios(struct drm_device *dev);
int intel_parse_bios(struct drm_device *dev); int intel_parse_bios(struct drm_device *dev);
@ -798,7 +829,8 @@ struct mipi_config {
#define DUAL_LINK_PIXEL_ALT 2 #define DUAL_LINK_PIXEL_ALT 2
u16 dual_link:2; u16 dual_link:2;
u16 lane_cnt:2; u16 lane_cnt:2;
u16 rsvd3:12; u16 pixel_overlap:3;
u16 rsvd3:9;
u16 rsvd4; u16 rsvd4;

Просмотреть файл

@ -128,15 +128,15 @@ static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
}; };
static const struct ddi_buf_trans skl_ddi_translations_dp[] = { static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
{ 0x00000018, 0x000000a0 }, { 0x00000018, 0x000000a2 },
{ 0x00004014, 0x00000098 }, { 0x00004014, 0x0000009B },
{ 0x00006012, 0x00000088 }, { 0x00006012, 0x00000088 },
{ 0x00008010, 0x00000080 }, { 0x00008010, 0x00000087 },
{ 0x00000018, 0x00000098 }, { 0x00000018, 0x0000009B },
{ 0x00004014, 0x00000088 }, { 0x00004014, 0x00000088 },
{ 0x00006012, 0x00000080 }, { 0x00006012, 0x00000087 },
{ 0x00000018, 0x00000088 }, { 0x00000018, 0x00000088 },
{ 0x00004014, 0x00000080 }, { 0x00004014, 0x00000087 },
}; };
static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
@ -834,7 +834,12 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
void intel_ddi_clock_get(struct intel_encoder *encoder, void intel_ddi_clock_get(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config) struct intel_crtc_config *pipe_config)
{ {
hsw_ddi_clock_get(encoder, pipe_config); struct drm_device *dev = encoder->base.dev;
if (INTEL_INFO(dev)->gen <= 8)
hsw_ddi_clock_get(encoder, pipe_config);
else
skl_ddi_clock_get(encoder, pipe_config);
} }
static void static void
@ -2029,7 +2034,6 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder; enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
struct intel_hdmi *intel_hdmi; struct intel_hdmi *intel_hdmi;
u32 temp, flags = 0; u32 temp, flags = 0;
struct drm_device *dev = dev_priv->dev;
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC) if (temp & TRANS_DDI_PHSYNC)
@ -2106,10 +2110,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
} }
if (INTEL_INFO(dev)->gen <= 8) intel_ddi_clock_get(encoder, pipe_config);
hsw_ddi_clock_get(encoder, pipe_config);
else
skl_ddi_clock_get(encoder, pipe_config);
} }
static void intel_ddi_destroy(struct drm_encoder *encoder) static void intel_ddi_destroy(struct drm_encoder *encoder)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1558,7 +1558,7 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
vdd = edp_panel_vdd_on(intel_dp); vdd = edp_panel_vdd_on(intel_dp);
pps_unlock(intel_dp); pps_unlock(intel_dp);
WARN(!vdd, "eDP port %c VDD already requested on\n", I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
port_name(dp_to_dig_port(intel_dp)->port)); port_name(dp_to_dig_port(intel_dp)->port));
} }
@ -1642,7 +1642,7 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
if (!is_edp(intel_dp)) if (!is_edp(intel_dp))
return; return;
WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on", I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
port_name(dp_to_dig_port(intel_dp)->port)); port_name(dp_to_dig_port(intel_dp)->port));
intel_dp->want_panel_vdd = false; intel_dp->want_panel_vdd = false;
@ -2105,6 +2105,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
if (crtc->config.has_audio) if (crtc->config.has_audio)
intel_audio_codec_disable(encoder); intel_audio_codec_disable(encoder);
if (HAS_PSR(dev) && !HAS_DDI(dev))
intel_psr_disable(intel_dp);
/* Make sure the panel is off before trying to change the mode. But also /* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */ * ensure that we have vdd while we switch off the panel. */
intel_edp_panel_vdd_on(intel_dp); intel_edp_panel_vdd_on(intel_dp);
@ -2329,6 +2332,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
intel_edp_backlight_on(intel_dp); intel_edp_backlight_on(intel_dp);
intel_psr_enable(intel_dp);
} }
static void g4x_pre_enable_dp(struct intel_encoder *encoder) static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@ -4306,7 +4310,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
drm_dp_aux_unregister(&intel_dp->aux); drm_dp_aux_unregister(&intel_dp->aux);
intel_dp_mst_encoder_cleanup(intel_dig_port); intel_dp_mst_encoder_cleanup(intel_dig_port);
drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work); cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
/* /*
@ -4322,6 +4325,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
intel_dp->edp_notifier.notifier_call = NULL; intel_dp->edp_notifier.notifier_call = NULL;
} }
} }
drm_encoder_cleanup(encoder);
kfree(intel_dig_port); kfree(intel_dig_port);
} }
@ -4763,14 +4767,9 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
} }
/* /*
* FIXME: This needs proper synchronization with psr state. But really * FIXME: This needs proper synchronization with psr state for some
* hard to tell without seeing the user of this function of this code. * platforms that cannot have PSR and DRRS enabled at the same time.
* Check locking and ordering once that lands.
*/ */
if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {
DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
return;
}
encoder = intel_attached_encoder(&intel_connector->base); encoder = intel_attached_encoder(&intel_connector->base);
intel_dp = enc_to_intel_dp(&encoder->base); intel_dp = enc_to_intel_dp(&encoder->base);
@ -5086,7 +5085,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_dp_aux_init(intel_dp, intel_connector); intel_dp_aux_init(intel_dp, intel_connector);
/* init MST on ports that can support it */ /* init MST on ports that can support it */
if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
if (port == PORT_B || port == PORT_C || port == PORT_D) { if (port == PORT_B || port == PORT_C || port == PORT_D) {
intel_dp_mst_encoder_init(intel_dig_port, intel_dp_mst_encoder_init(intel_dig_port,
intel_connector->base.base.id); intel_connector->base.base.id);

Просмотреть файл

@ -244,8 +244,7 @@ typedef struct dpll {
} intel_clock_t; } intel_clock_t;
struct intel_plane_state { struct intel_plane_state {
struct drm_crtc *crtc; struct drm_plane_state base;
struct drm_framebuffer *fb;
struct drm_rect src; struct drm_rect src;
struct drm_rect dst; struct drm_rect dst;
struct drm_rect clip; struct drm_rect clip;
@ -406,8 +405,7 @@ struct intel_pipe_wm {
}; };
struct intel_mmio_flip { struct intel_mmio_flip {
u32 seqno; struct drm_i915_gem_request *req;
struct intel_engine_cs *ring;
struct work_struct work; struct work_struct work;
}; };
@ -510,6 +508,10 @@ struct intel_plane {
uint32_t src_w, uint32_t src_h); uint32_t src_w, uint32_t src_h);
void (*disable_plane)(struct drm_plane *plane, void (*disable_plane)(struct drm_plane *plane,
struct drm_crtc *crtc); struct drm_crtc *crtc);
int (*check_plane)(struct drm_plane *plane,
struct intel_plane_state *state);
void (*commit_plane)(struct drm_plane *plane,
struct intel_plane_state *state);
int (*update_colorkey)(struct drm_plane *plane, int (*update_colorkey)(struct drm_plane *plane,
struct drm_intel_sprite_colorkey *key); struct drm_intel_sprite_colorkey *key);
void (*get_colorkey)(struct drm_plane *plane, void (*get_colorkey)(struct drm_plane *plane,
@ -708,8 +710,7 @@ struct intel_unpin_work {
#define INTEL_FLIP_COMPLETE 2 #define INTEL_FLIP_COMPLETE 2
u32 flip_count; u32 flip_count;
u32 gtt_offset; u32 gtt_offset;
struct intel_engine_cs *flip_queued_ring; struct drm_i915_gem_request *flip_queued_req;
u32 flip_queued_seqno;
int flip_queued_vblank; int flip_queued_vblank;
int flip_ready_vblank; int flip_ready_vblank;
bool enable_stall_check; bool enable_stall_check;
@ -874,7 +875,6 @@ void intel_audio_codec_enable(struct intel_encoder *encoder);
void intel_audio_codec_disable(struct intel_encoder *encoder); void intel_audio_codec_disable(struct intel_encoder *encoder);
/* intel_display.c */ /* intel_display.c */
const char *intel_output_name(int output);
bool intel_has_pending_fb_unpin(struct drm_device *dev); bool intel_has_pending_fb_unpin(struct drm_device *dev);
int intel_pch_rawclk(struct drm_device *dev); int intel_pch_rawclk(struct drm_device *dev);
void intel_mark_busy(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev);
@ -925,6 +925,10 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane);
void intel_finish_page_flip(struct drm_device *dev, int pipe); void intel_finish_page_flip(struct drm_device *dev, int pipe);
void intel_finish_page_flip_plane(struct drm_device *dev, int plane); void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
void intel_check_page_flip(struct drm_device *dev, int pipe); void intel_check_page_flip(struct drm_device *dev, int pipe);
int intel_prepare_plane_fb(struct drm_plane *plane,
struct drm_framebuffer *fb);
void intel_cleanup_plane_fb(struct drm_plane *plane,
struct drm_framebuffer *fb);
/* shared dpll functions */ /* shared dpll functions */
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
@ -1010,6 +1014,12 @@ void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv); void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes); uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes); void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h);
int intel_disable_plane(struct drm_plane *plane);
/* intel_dp_mst.c */ /* intel_dp_mst.c */
int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@ -1053,6 +1063,13 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
} }
#endif #endif
/* intel_fbc.c */
bool intel_fbc_enabled(struct drm_device *dev);
void intel_fbc_update(struct drm_device *dev);
void intel_fbc_init(struct drm_i915_private *dev_priv);
void intel_fbc_disable(struct drm_device *dev);
void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
/* intel_hdmi.c */ /* intel_hdmi.c */
void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
@ -1083,6 +1100,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int intel_overlay_attrs(struct drm_device *dev, void *data, int intel_overlay_attrs(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
void intel_overlay_reset(struct drm_i915_private *dev_priv);
/* intel_panel.c */ /* intel_panel.c */
@ -1115,7 +1133,6 @@ void intel_backlight_unregister(struct drm_device *dev);
/* intel_psr.c */ /* intel_psr.c */
bool intel_psr_is_enabled(struct drm_device *dev);
void intel_psr_enable(struct intel_dp *intel_dp); void intel_psr_enable(struct intel_dp *intel_dp);
void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_disable(struct intel_dp *intel_dp);
void intel_psr_invalidate(struct drm_device *dev, void intel_psr_invalidate(struct drm_device *dev,
@ -1159,8 +1176,6 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
bool enabled, bool scaled); bool enabled, bool scaled);
void intel_init_pm(struct drm_device *dev); void intel_init_pm(struct drm_device *dev);
void intel_pm_setup(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev);
bool intel_fbc_enabled(struct drm_device *dev);
void intel_update_fbc(struct drm_device *dev);
void intel_gpu_ips_init(struct drm_i915_private *dev_priv); void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
void intel_gpu_ips_teardown(void); void intel_gpu_ips_teardown(void);
void intel_init_gt_powersave(struct drm_device *dev); void intel_init_gt_powersave(struct drm_device *dev);
@ -1191,7 +1206,6 @@ int intel_plane_set_property(struct drm_plane *plane,
struct drm_property *prop, struct drm_property *prop,
uint64_t val); uint64_t val);
int intel_plane_restore(struct drm_plane *plane); int intel_plane_restore(struct drm_plane *plane);
void intel_plane_disable(struct drm_plane *plane);
int intel_sprite_set_colorkey(struct drm_device *dev, void *data, int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int intel_sprite_get_colorkey(struct drm_device *dev, void *data, int intel_sprite_get_colorkey(struct drm_device *dev, void *data,

Просмотреть файл

@ -102,11 +102,62 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
return true; return true;
} }
static void intel_dsi_port_enable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
u32 temp;
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
temp = I915_READ(VLV_CHICKEN_3);
temp &= ~PIXEL_OVERLAP_CNT_MASK |
intel_dsi->pixel_overlap <<
PIXEL_OVERLAP_CNT_SHIFT;
I915_WRITE(VLV_CHICKEN_3, temp);
}
for_each_dsi_port(port, intel_dsi->ports) {
temp = I915_READ(MIPI_PORT_CTRL(port));
temp &= ~LANE_CONFIGURATION_MASK;
temp &= ~DUAL_LINK_MODE_MASK;
if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) {
temp |= (intel_dsi->dual_link - 1)
<< DUAL_LINK_MODE_SHIFT;
temp |= intel_crtc->pipe ?
LANE_CONFIGURATION_DUAL_LINK_B :
LANE_CONFIGURATION_DUAL_LINK_A;
}
/* assert ip_tg_enable signal */
I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE);
POSTING_READ(MIPI_PORT_CTRL(port));
}
}
static void intel_dsi_port_disable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
u32 temp;
for_each_dsi_port(port, intel_dsi->ports) {
/* de-assert ip_tg_enable signal */
temp = I915_READ(MIPI_PORT_CTRL(port));
I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE);
POSTING_READ(MIPI_PORT_CTRL(port));
}
}
static void intel_dsi_device_ready(struct intel_encoder *encoder) static void intel_dsi_device_ready(struct intel_encoder *encoder)
{ {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
int pipe = intel_crtc->pipe; enum port port;
u32 val; u32 val;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
@ -120,18 +171,26 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
/* bandgap reset is needed after everytime we do power gate */ /* bandgap reset is needed after everytime we do power gate */
band_gap_reset(dev_priv); band_gap_reset(dev_priv);
I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); for_each_dsi_port(port, intel_dsi->ports) {
usleep_range(2500, 3000);
val = I915_READ(MIPI_PORT_CTRL(pipe)); I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); usleep_range(2500, 3000);
usleep_range(1000, 1500);
I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT); val = I915_READ(MIPI_PORT_CTRL(port));
usleep_range(2500, 3000);
I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); /* Enable MIPI PHY transparent latch
usleep_range(2500, 3000); * Common bit for both MIPI Port A & MIPI Port C
* No similar bit in MIPI Port C reg
*/
I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
usleep_range(1000, 1500);
I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
usleep_range(2500, 3000);
I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
usleep_range(2500, 3000);
}
} }
static void intel_dsi_enable(struct intel_encoder *encoder) static void intel_dsi_enable(struct intel_encoder *encoder)
@ -140,13 +199,12 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
int pipe = intel_crtc->pipe; enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe);
u32 temp;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
if (is_cmd_mode(intel_dsi)) if (is_cmd_mode(intel_dsi))
I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
else { else {
msleep(20); /* XXX */ msleep(20); /* XXX */
dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN); dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN);
@ -157,11 +215,7 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
wait_for_dsi_fifo_empty(intel_dsi); wait_for_dsi_fifo_empty(intel_dsi);
/* assert ip_tg_enable signal */ intel_dsi_port_enable(encoder);
temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK;
temp = temp | intel_dsi->port_bits;
I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE);
POSTING_READ(MIPI_PORT_CTRL(pipe));
} }
} }
@ -235,9 +289,8 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
{ {
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
int pipe = intel_crtc->pipe; enum port port;
u32 temp; u32 temp;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
@ -245,31 +298,28 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
if (is_vid_mode(intel_dsi)) { if (is_vid_mode(intel_dsi)) {
wait_for_dsi_fifo_empty(intel_dsi); wait_for_dsi_fifo_empty(intel_dsi);
/* de-assert ip_tg_enable signal */ intel_dsi_port_disable(encoder);
temp = I915_READ(MIPI_PORT_CTRL(pipe));
I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE);
POSTING_READ(MIPI_PORT_CTRL(pipe));
msleep(2); msleep(2);
} }
/* Panel commands can be sent when clock is in LP11 */ for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0); /* Panel commands can be sent when clock is in LP11 */
I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
temp = I915_READ(MIPI_CTRL(pipe)); temp = I915_READ(MIPI_CTRL(port));
temp &= ~ESCAPE_CLOCK_DIVIDER_MASK; temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
I915_WRITE(MIPI_CTRL(pipe), temp | I915_WRITE(MIPI_CTRL(port), temp |
intel_dsi->escape_clk_div << intel_dsi->escape_clk_div <<
ESCAPE_CLOCK_DIVIDER_SHIFT); ESCAPE_CLOCK_DIVIDER_SHIFT);
I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP); I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe)); temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
temp &= ~VID_MODE_FORMAT_MASK; temp &= ~VID_MODE_FORMAT_MASK;
I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp); I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp);
I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);
I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
}
/* if disable packets are sent before sending shutdown packet then in /* if disable packets are sent before sending shutdown packet then in
* some next enable sequence send turn on packet error is observed */ * some next enable sequence send turn on packet error is observed */
if (intel_dsi->dev.dev_ops->disable) if (intel_dsi->dev.dev_ops->disable)
@ -281,31 +331,42 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
{ {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
int pipe = intel_crtc->pipe; enum port port;
u32 val; u32 val;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER); I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
usleep_range(2000, 2500); ULPS_STATE_ENTER);
usleep_range(2000, 2500);
I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT); I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
usleep_range(2000, 2500); ULPS_STATE_EXIT);
usleep_range(2000, 2500);
I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER); I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
usleep_range(2000, 2500); ULPS_STATE_ENTER);
usleep_range(2000, 2500);
if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) /* Wait till Clock lanes are in LP-00 state for MIPI Port A
== 0x00000), 30)) * only. MIPI Port C has no similar bit for checking
DRM_ERROR("DSI LP not going Low\n"); */
if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT)
== 0x00000), 30))
DRM_ERROR("DSI LP not going Low\n");
val = I915_READ(MIPI_PORT_CTRL(pipe)); val = I915_READ(MIPI_PORT_CTRL(port));
I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD); /* Disable MIPI PHY transparent latch
usleep_range(1000, 1500); * Common bit for both MIPI Port A & MIPI Port C
*/
I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD);
usleep_range(1000, 1500);
I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
usleep_range(2000, 2500); usleep_range(2000, 2500);
}
vlv_disable_dsi_pll(encoder); vlv_disable_dsi_pll(encoder);
} }
@ -337,9 +398,11 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe) enum pipe *pipe)
{ {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain; enum intel_display_power_domain power_domain;
u32 port, func; u32 dpi_enabled, func;
enum pipe p; enum port port;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
@ -348,13 +411,23 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
return false; return false;
/* XXX: this only works for one DSI output */ /* XXX: this only works for one DSI output */
for (p = PIPE_A; p <= PIPE_B; p++) { for_each_dsi_port(port, intel_dsi->ports) {
port = I915_READ(MIPI_PORT_CTRL(p)); func = I915_READ(MIPI_DSI_FUNC_PRG(port));
func = I915_READ(MIPI_DSI_FUNC_PRG(p)); dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) &
DPI_ENABLE;
if ((port & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) { /* Due to some hardware limitations on BYT, MIPI Port C DPI
if (I915_READ(MIPI_DEVICE_READY(p)) & DEVICE_READY) { * Enable bit does not get set. To check whether DSI Port C
*pipe = p; * was enabled in BIOS, check the Pipe B enable bit
*/
if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
(port == PORT_C))
dpi_enabled = I915_READ(PIPECONF(PIPE_B)) &
PIPECONF_ENABLE;
if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) {
if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) {
*pipe = port == PORT_A ? PIPE_A : PIPE_B;
return true; return true;
} }
} }
@ -437,7 +510,7 @@ static void set_dsi_timings(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
int pipe = intel_crtc->pipe; enum port port;
unsigned int bpp = intel_crtc->config.pipe_bpp; unsigned int bpp = intel_crtc->config.pipe_bpp;
unsigned int lane_count = intel_dsi->lane_count; unsigned int lane_count = intel_dsi->lane_count;
@ -448,6 +521,15 @@ static void set_dsi_timings(struct drm_encoder *encoder,
hsync = mode->hsync_end - mode->hsync_start; hsync = mode->hsync_end - mode->hsync_start;
hbp = mode->htotal - mode->hsync_end; hbp = mode->htotal - mode->hsync_end;
if (intel_dsi->dual_link) {
hactive /= 2;
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
hactive += intel_dsi->pixel_overlap;
hfp /= 2;
hsync /= 2;
hbp /= 2;
}
vfp = mode->vsync_start - mode->vdisplay; vfp = mode->vsync_start - mode->vdisplay;
vsync = mode->vsync_end - mode->vsync_start; vsync = mode->vsync_end - mode->vsync_start;
vbp = mode->vtotal - mode->vsync_end; vbp = mode->vtotal - mode->vsync_end;
@ -460,18 +542,20 @@ static void set_dsi_timings(struct drm_encoder *encoder,
intel_dsi->burst_mode_ratio); intel_dsi->burst_mode_ratio);
hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio); hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive); for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_HFP_COUNT(pipe), hfp); I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
I915_WRITE(MIPI_HFP_COUNT(port), hfp);
/* meaningful for video mode non-burst sync pulse mode only, can be zero /* meaningful for video mode non-burst sync pulse mode only,
* for non-burst sync events and burst modes */ * can be zero for non-burst sync events and burst modes */
I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync); I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
I915_WRITE(MIPI_HBP_COUNT(pipe), hbp); I915_WRITE(MIPI_HBP_COUNT(port), hbp);
/* vertical values are in terms of lines */ /* vertical values are in terms of lines */
I915_WRITE(MIPI_VFP_COUNT(pipe), vfp); I915_WRITE(MIPI_VFP_COUNT(port), vfp);
I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync); I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
I915_WRITE(MIPI_VBP_COUNT(pipe), vbp); I915_WRITE(MIPI_VBP_COUNT(port), vbp);
}
} }
static void intel_dsi_prepare(struct intel_encoder *intel_encoder) static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
@ -483,32 +567,43 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
struct drm_display_mode *adjusted_mode = struct drm_display_mode *adjusted_mode =
&intel_crtc->config.adjusted_mode; &intel_crtc->config.adjusted_mode;
int pipe = intel_crtc->pipe; enum port port;
unsigned int bpp = intel_crtc->config.pipe_bpp; unsigned int bpp = intel_crtc->config.pipe_bpp;
u32 val, tmp; u32 val, tmp;
u16 mode_hdisplay;
DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
/* escape clock divider, 20MHz, shared for A and C. device ready must be mode_hdisplay = adjusted_mode->hdisplay;
* off when doing this! txclkesc? */
tmp = I915_READ(MIPI_CTRL(0));
tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1);
/* read request priority is per pipe */ if (intel_dsi->dual_link) {
tmp = I915_READ(MIPI_CTRL(pipe)); mode_hdisplay /= 2;
tmp &= ~READ_REQUEST_PRIORITY_MASK; if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH); mode_hdisplay += intel_dsi->pixel_overlap;
}
/* XXX: why here, why like this? handling in irq handler?! */ for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); /* escape clock divider, 20MHz, shared for A and C.
I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); * device ready must be off when doing this! txclkesc? */
tmp = I915_READ(MIPI_CTRL(PORT_A));
tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1);
I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); /* read request priority is per pipe */
tmp = I915_READ(MIPI_CTRL(port));
tmp &= ~READ_REQUEST_PRIORITY_MASK;
I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH);
I915_WRITE(MIPI_DPI_RESOLUTION(pipe), /* XXX: why here, why like this? handling in irq handler?! */
adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT); I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
I915_WRITE(MIPI_DPI_RESOLUTION(port),
adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
}
set_dsi_timings(encoder, adjusted_mode); set_dsi_timings(encoder, adjusted_mode);
@ -522,95 +617,102 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
/* XXX: cross-check bpp vs. pixel format? */ /* XXX: cross-check bpp vs. pixel format? */
val |= intel_dsi->pixel_format; val |= intel_dsi->pixel_format;
} }
I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);
/* timeouts for recovery. one frame IIUC. if counter expires, EOT and tmp = 0;
* stop state. */
/*
* In burst mode, value greater than one DPI line Time in byte clock
* (txbyteclkhs) To timeout this timer 1+ of the above said value is
* recommended.
*
* In non-burst mode, Value greater than one DPI frame time in byte
* clock(txbyteclkhs) To timeout this timer 1+ of the above said value
* is recommended.
*
* In DBI only mode, value greater than one DBI frame time in byte
* clock(txbyteclkhs) To timeout this timer 1+ of the above said value
* is recommended.
*/
if (is_vid_mode(intel_dsi) &&
intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
txbyteclkhs(adjusted_mode->htotal, bpp,
intel_dsi->lane_count,
intel_dsi->burst_mode_ratio) + 1);
} else {
I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
txbyteclkhs(adjusted_mode->vtotal *
adjusted_mode->htotal,
bpp, intel_dsi->lane_count,
intel_dsi->burst_mode_ratio) + 1);
}
I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val);
/* dphy stuff */
/* in terms of low power clock */
I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100));
val = 0;
if (intel_dsi->eotp_pkt == 0) if (intel_dsi->eotp_pkt == 0)
val |= EOT_DISABLE; tmp |= EOT_DISABLE;
if (intel_dsi->clock_stop) if (intel_dsi->clock_stop)
val |= CLOCKSTOP; tmp |= CLOCKSTOP;
/* recovery disables */ for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_EOT_DISABLE(pipe), val); I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
/* in terms of low power clock */ /* timeouts for recovery. one frame IIUC. if counter expires,
I915_WRITE(MIPI_INIT_COUNT(pipe), intel_dsi->init_count); * EOT and stop state. */
/* in terms of txbyteclkhs. actual high to low switch + /*
* MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK. * In burst mode, value greater than one DPI line Time in byte
* * clock (txbyteclkhs) To timeout this timer 1+ of the above
* XXX: write MIPI_STOP_STATE_STALL? * said value is recommended.
*/ *
I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), * In non-burst mode, Value greater than one DPI frame time in
intel_dsi->hs_to_lp_count); * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
* said value is recommended.
*
* In DBI only mode, value greater than one DBI frame time in
* byte clock(txbyteclkhs) To timeout this timer 1+ of the above
* said value is recommended.
*/
/* XXX: low power clock equivalence in terms of byte clock. the number if (is_vid_mode(intel_dsi) &&
* of byte clocks occupied in one low power clock. based on txbyteclkhs intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
* and txclkesc. txclkesc time / txbyteclk time * (105 + I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
* MIPI_STOP_STATE_STALL) / 105.??? txbyteclkhs(adjusted_mode->htotal, bpp,
*/ intel_dsi->lane_count,
I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk); intel_dsi->burst_mode_ratio) + 1);
} else {
I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
txbyteclkhs(adjusted_mode->vtotal *
adjusted_mode->htotal,
bpp, intel_dsi->lane_count,
intel_dsi->burst_mode_ratio) + 1);
}
I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
intel_dsi->turn_arnd_val);
I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
intel_dsi->rst_timer_val);
/* the bw essential for transmitting 16 long packets containing 252 /* dphy stuff */
* bytes meant for dcs write memory command is programmed in this
* register in terms of byte clocks. based on dsi transfer rate and the
* number of lanes configured the time taken to transmit 16 long packets
* in a dsi stream varies. */
I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);
I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), /* in terms of low power clock */
intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | I915_WRITE(MIPI_INIT_COUNT(port),
intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); txclkesc(intel_dsi->escape_clk_div, 100));
if (is_vid_mode(intel_dsi))
/* Some panels might have resolution which is not a multiple of /* recovery disables */
* 64 like 1366 x 768. Enable RANDOM resolution support for such I915_WRITE(MIPI_EOT_DISABLE(port), val);
* panels by default */
I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), /* in terms of low power clock */
intel_dsi->video_frmt_cfg_bits | I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
intel_dsi->video_mode_format |
IP_TG_CONFIG | /* in terms of txbyteclkhs. actual high to low switch +
RANDOM_DPI_DISPLAY_RESOLUTION); * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
*
* XXX: write MIPI_STOP_STATE_STALL?
*/
I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
intel_dsi->hs_to_lp_count);
/* XXX: low power clock equivalence in terms of byte clock.
* the number of byte clocks occupied in one low power clock.
* based on txbyteclkhs and txclkesc.
* txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
* ) / 105.???
*/
I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
/* the bw essential for transmitting 16 long packets containing
* 252 bytes meant for dcs write memory command is programmed in
* this register in terms of byte clocks. based on dsi transfer
* rate and the number of lanes configured the time taken to
* transmit 16 long packets in a dsi stream varies. */
I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
if (is_vid_mode(intel_dsi))
/* Some panels might have resolution which is not a
* multiple of 64 like 1366 x 768. Enable RANDOM
* resolution support for such panels by default */
I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
intel_dsi->video_frmt_cfg_bits |
intel_dsi->video_mode_format |
IP_TG_CONFIG |
RANDOM_DPI_DISPLAY_RESOLUTION);
}
} }
static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
@ -748,6 +850,15 @@ void intel_dsi_init(struct drm_device *dev)
intel_connector->get_hw_state = intel_connector_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector->unregister = intel_connector_unregister; intel_connector->unregister = intel_connector_unregister;
/* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */
if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) {
intel_encoder->crtc_mask = (1 << PIPE_A);
intel_dsi->ports = (1 << PORT_A);
} else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) {
intel_encoder->crtc_mask = (1 << PIPE_B);
intel_dsi->ports = (1 << PORT_C);
}
for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) { for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) {
dsi = &intel_dsi_devices[i]; dsi = &intel_dsi_devices[i];
intel_dsi->dev = *dsi; intel_dsi->dev = *dsi;
@ -762,8 +873,6 @@ void intel_dsi_init(struct drm_device *dev)
} }
intel_encoder->type = INTEL_OUTPUT_DSI; intel_encoder->type = INTEL_OUTPUT_DSI;
intel_encoder->crtc_mask = (1 << 0); /* XXX */
intel_encoder->cloneable = 0; intel_encoder->cloneable = 0;
drm_connector_init(dev, connector, &intel_dsi_connector_funcs, drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
DRM_MODE_CONNECTOR_DSI); DRM_MODE_CONNECTOR_DSI);

Просмотреть файл

@ -28,6 +28,11 @@
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include "intel_drv.h" #include "intel_drv.h"
/* Dual Link support */
#define DSI_DUAL_LINK_NONE 0
#define DSI_DUAL_LINK_FRONT_BACK 1
#define DSI_DUAL_LINK_PIXEL_ALT 2
struct intel_dsi_device { struct intel_dsi_device {
unsigned int panel_id; unsigned int panel_id;
const char *name; const char *name;
@ -78,6 +83,9 @@ struct intel_dsi {
struct intel_connector *attached_connector; struct intel_connector *attached_connector;
/* bit mask of ports being driven */
u16 ports;
/* if true, use HS mode, otherwise LP */ /* if true, use HS mode, otherwise LP */
bool hs; bool hs;
@ -101,6 +109,8 @@ struct intel_dsi {
u8 clock_stop; u8 clock_stop;
u8 escape_clk_div; u8 escape_clk_div;
u8 dual_link;
u8 pixel_overlap;
u32 port_bits; u32 port_bits;
u32 bw_timer; u32 bw_timer;
u32 dphy_reg; u32 dphy_reg;
@ -127,6 +137,22 @@ struct intel_dsi {
u16 panel_pwr_cycle_delay; u16 panel_pwr_cycle_delay;
}; };
/* XXX: Transitional before dual port configuration */
static inline enum port intel_dsi_pipe_to_port(enum pipe pipe)
{
if (pipe == PIPE_A)
return PORT_A;
else if (pipe == PIPE_B)
return PORT_C;
WARN(1, "DSI on pipe %c, assuming port C\n", pipe_name(pipe));
return PORT_C;
}
#define for_each_dsi_port(__port, __ports_mask) \
for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) \
if ((__ports_mask) & (1 << (__port)))
static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
{ {
return container_of(encoder, struct intel_dsi, base.base); return container_of(encoder, struct intel_dsi, base.base);

Просмотреть файл

@ -48,21 +48,19 @@
* For memory writes, these should probably be used for performance. * For memory writes, these should probably be used for performance.
*/ */
static void print_stat(struct intel_dsi *intel_dsi) static void print_stat(struct intel_dsi *intel_dsi, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 val; u32 val;
val = I915_READ(MIPI_INTR_STAT(pipe)); val = I915_READ(MIPI_INTR_STAT(port));
#define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : "" #define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : ""
DRM_DEBUG_KMS("MIPI_INTR_STAT(%d) = %08x" DRM_DEBUG_KMS("MIPI_INTR_STAT(%c) = %08x"
"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
"\n", pipe, val, "\n", port_name(port), val,
STAT_BIT(val, TEARING_EFFECT), STAT_BIT(val, TEARING_EFFECT),
STAT_BIT(val, SPL_PKT_SENT_INTERRUPT), STAT_BIT(val, SPL_PKT_SENT_INTERRUPT),
STAT_BIT(val, GEN_READ_DATA_AVAIL), STAT_BIT(val, GEN_READ_DATA_AVAIL),
@ -104,34 +102,31 @@ enum dsi_type {
}; };
/* enable or disable command mode hs transmissions */ /* enable or disable command mode hs transmissions */
void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable) void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable,
enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 temp; u32 temp;
u32 mask = DBI_FIFO_EMPTY; u32 mask = DBI_FIFO_EMPTY;
if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 50)) if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 50))
DRM_ERROR("Timeout waiting for DBI FIFO empty\n"); DRM_ERROR("Timeout waiting for DBI FIFO empty\n");
temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(pipe)); temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(port));
temp &= DBI_HS_LP_MODE_MASK; temp &= DBI_HS_LP_MODE_MASK;
I915_WRITE(MIPI_HS_LP_DBI_ENABLE(pipe), enable ? DBI_HS_MODE : DBI_LP_MODE); I915_WRITE(MIPI_HS_LP_DBI_ENABLE(port), enable ? DBI_HS_MODE : DBI_LP_MODE);
intel_dsi->hs = enable; intel_dsi->hs = enable;
} }
static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel, static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel,
u8 data_type, u16 data) u8 data_type, u16 data, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 ctrl_reg; u32 ctrl_reg;
u32 ctrl; u32 ctrl;
u32 mask; u32 mask;
@ -140,16 +135,16 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel,
channel, data_type, data); channel, data_type, data);
if (intel_dsi->hs) { if (intel_dsi->hs) {
ctrl_reg = MIPI_HS_GEN_CTRL(pipe); ctrl_reg = MIPI_HS_GEN_CTRL(port);
mask = HS_CTRL_FIFO_FULL; mask = HS_CTRL_FIFO_FULL;
} else { } else {
ctrl_reg = MIPI_LP_GEN_CTRL(pipe); ctrl_reg = MIPI_LP_GEN_CTRL(port);
mask = LP_CTRL_FIFO_FULL; mask = LP_CTRL_FIFO_FULL;
} }
if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) { if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == 0, 50)) {
DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n"); DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
print_stat(intel_dsi); print_stat(intel_dsi, port);
} }
/* /*
@ -167,13 +162,11 @@ static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel,
} }
static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel, static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel,
u8 data_type, const u8 *data, int len) u8 data_type, const u8 *data, int len, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 data_reg; u32 data_reg;
int i, j, n; int i, j, n;
u32 mask; u32 mask;
@ -182,14 +175,14 @@ static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel,
channel, data_type, len); channel, data_type, len);
if (intel_dsi->hs) { if (intel_dsi->hs) {
data_reg = MIPI_HS_GEN_DATA(pipe); data_reg = MIPI_HS_GEN_DATA(port);
mask = HS_DATA_FIFO_FULL; mask = HS_DATA_FIFO_FULL;
} else { } else {
data_reg = MIPI_LP_GEN_DATA(pipe); data_reg = MIPI_LP_GEN_DATA(port);
mask = LP_DATA_FIFO_FULL; mask = LP_DATA_FIFO_FULL;
} }
if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == 0, 50))
DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n"); DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
for (i = 0; i < len; i += n) { for (i = 0; i < len; i += n) {
@ -204,12 +197,12 @@ static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel,
* dwords, then wait for not set, then continue. */ * dwords, then wait for not set, then continue. */
} }
return dsi_vc_send_short(intel_dsi, channel, data_type, len); return dsi_vc_send_short(intel_dsi, channel, data_type, len, port);
} }
static int dsi_vc_write_common(struct intel_dsi *intel_dsi, static int dsi_vc_write_common(struct intel_dsi *intel_dsi,
int channel, const u8 *data, int len, int channel, const u8 *data, int len,
enum dsi_type type) enum dsi_type type, enum port port)
{ {
int ret; int ret;
@ -217,50 +210,54 @@ static int dsi_vc_write_common(struct intel_dsi *intel_dsi,
BUG_ON(type == DSI_GENERIC); BUG_ON(type == DSI_GENERIC);
ret = dsi_vc_send_short(intel_dsi, channel, ret = dsi_vc_send_short(intel_dsi, channel,
MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM,
0); 0, port);
} else if (len == 1) { } else if (len == 1) {
ret = dsi_vc_send_short(intel_dsi, channel, ret = dsi_vc_send_short(intel_dsi, channel,
type == DSI_GENERIC ? type == DSI_GENERIC ?
MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
MIPI_DSI_DCS_SHORT_WRITE, data[0]); MIPI_DSI_DCS_SHORT_WRITE, data[0],
port);
} else if (len == 2) { } else if (len == 2) {
ret = dsi_vc_send_short(intel_dsi, channel, ret = dsi_vc_send_short(intel_dsi, channel,
type == DSI_GENERIC ? type == DSI_GENERIC ?
MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
MIPI_DSI_DCS_SHORT_WRITE_PARAM, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
(data[1] << 8) | data[0]); (data[1] << 8) | data[0], port);
} else { } else {
ret = dsi_vc_send_long(intel_dsi, channel, ret = dsi_vc_send_long(intel_dsi, channel,
type == DSI_GENERIC ? type == DSI_GENERIC ?
MIPI_DSI_GENERIC_LONG_WRITE : MIPI_DSI_GENERIC_LONG_WRITE :
MIPI_DSI_DCS_LONG_WRITE, data, len); MIPI_DSI_DCS_LONG_WRITE, data, len,
port);
} }
return ret; return ret;
} }
int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel, int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
const u8 *data, int len) const u8 *data, int len, enum port port)
{ {
return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS); return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS,
port);
} }
int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel, int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
const u8 *data, int len) const u8 *data, int len, enum port port)
{ {
return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC); return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC,
port);
} }
static int dsi_vc_dcs_send_read_request(struct intel_dsi *intel_dsi, static int dsi_vc_dcs_send_read_request(struct intel_dsi *intel_dsi,
int channel, u8 dcs_cmd) int channel, u8 dcs_cmd, enum port port)
{ {
return dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_DCS_READ, return dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_DCS_READ,
dcs_cmd); dcs_cmd, port);
} }
static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi, static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi,
int channel, u8 *reqdata, int channel, u8 *reqdata,
int reqlen) int reqlen, enum port port)
{ {
u16 data; u16 data;
u8 data_type; u8 data_type;
@ -282,24 +279,22 @@ static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi,
BUG(); BUG();
} }
return dsi_vc_send_short(intel_dsi, channel, data_type, data); return dsi_vc_send_short(intel_dsi, channel, data_type, data, port);
} }
static int dsi_read_data_return(struct intel_dsi *intel_dsi, static int dsi_read_data_return(struct intel_dsi *intel_dsi,
u8 *buf, int buflen) u8 *buf, int buflen, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
int i, len = 0; int i, len = 0;
u32 data_reg, val; u32 data_reg, val;
if (intel_dsi->hs) { if (intel_dsi->hs) {
data_reg = MIPI_HS_GEN_DATA(pipe); data_reg = MIPI_HS_GEN_DATA(port);
} else { } else {
data_reg = MIPI_LP_GEN_DATA(pipe); data_reg = MIPI_LP_GEN_DATA(port);
} }
while (len < buflen) { while (len < buflen) {
@ -312,13 +307,11 @@ static int dsi_read_data_return(struct intel_dsi *intel_dsi,
} }
int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
u8 *buf, int buflen) u8 *buf, int buflen, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 mask; u32 mask;
int ret; int ret;
@ -327,17 +320,17 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
* longer than MIPI_MAX_RETURN_PKT_SIZE * longer than MIPI_MAX_RETURN_PKT_SIZE
*/ */
I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL); I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd); ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd, port);
if (ret) if (ret)
return ret; return ret;
mask = GEN_READ_DATA_AVAIL; mask = GEN_READ_DATA_AVAIL;
if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50)) if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50))
DRM_ERROR("Timeout waiting for read data.\n"); DRM_ERROR("Timeout waiting for read data.\n");
ret = dsi_read_data_return(intel_dsi, buf, buflen); ret = dsi_read_data_return(intel_dsi, buf, buflen, port);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -348,13 +341,11 @@ int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
} }
int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
u8 *reqdata, int reqlen, u8 *buf, int buflen) u8 *reqdata, int reqlen, u8 *buf, int buflen, enum port port)
{ {
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe;
u32 mask; u32 mask;
int ret; int ret;
@ -363,18 +354,18 @@ int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
* longer than MIPI_MAX_RETURN_PKT_SIZE * longer than MIPI_MAX_RETURN_PKT_SIZE
*/ */
I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL); I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata, ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata,
reqlen); reqlen, port);
if (ret) if (ret)
return ret; return ret;
mask = GEN_READ_DATA_AVAIL; mask = GEN_READ_DATA_AVAIL;
if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50)) if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 50))
DRM_ERROR("Timeout waiting for read data.\n"); DRM_ERROR("Timeout waiting for read data.\n");
ret = dsi_read_data_return(intel_dsi, buf, buflen); ret = dsi_read_data_return(intel_dsi, buf, buflen, port);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -394,8 +385,7 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
struct drm_encoder *encoder = &intel_dsi->base.base; struct drm_encoder *encoder = &intel_dsi->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); enum port port;
enum pipe pipe = intel_crtc->pipe;
u32 mask; u32 mask;
/* XXX: pipe, hs */ /* XXX: pipe, hs */
@ -404,18 +394,23 @@ int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
else else
cmd |= DPI_LP_MODE; cmd |= DPI_LP_MODE;
/* clear bit */ for_each_dsi_port(port, intel_dsi->ports) {
I915_WRITE(MIPI_INTR_STAT(pipe), SPL_PKT_SENT_INTERRUPT); /* clear bit */
I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
/* XXX: old code skips write if control unchanged */ /* XXX: old code skips write if control unchanged */
if (cmd == I915_READ(MIPI_DPI_CONTROL(pipe))) if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
DRM_ERROR("Same special packet %02x twice in a row.\n", cmd); DRM_ERROR("Same special packet %02x twice in a row.\n",
cmd);
I915_WRITE(MIPI_DPI_CONTROL(pipe), cmd); I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
mask = SPL_PKT_SENT_INTERRUPT; mask = SPL_PKT_SENT_INTERRUPT;
if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 100)) if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask,
DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd); 100))
DRM_ERROR("Video mode command 0x%08x send failed.\n",
cmd);
}
return 0; return 0;
} }
@ -426,12 +421,12 @@ void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi)
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
enum pipe pipe = intel_crtc->pipe; enum port port = intel_dsi_pipe_to_port(intel_crtc->pipe);
u32 mask; u32 mask;
mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY | mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY; LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100)) if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 100))
DRM_ERROR("DPI FIFOs are not empty\n"); DRM_ERROR("DPI FIFOs are not empty\n");
} }

Просмотреть файл

@ -36,77 +36,81 @@
#define DPI_LP_MODE_EN false #define DPI_LP_MODE_EN false
#define DPI_HS_MODE_EN true #define DPI_HS_MODE_EN true
void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable); void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable,
enum port port);
int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel, int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
const u8 *data, int len); const u8 *data, int len, enum port port);
int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel, int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
const u8 *data, int len); const u8 *data, int len, enum port port);
int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd, int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
u8 *buf, int buflen); u8 *buf, int buflen, enum port port);
int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel, int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
u8 *reqdata, int reqlen, u8 *buf, int buflen); u8 *reqdata, int reqlen, u8 *buf, int buflen, enum port port);
int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs); int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs);
void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi); void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi);
/* XXX: questionable write helpers */ /* XXX: questionable write helpers */
static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi, static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi,
int channel, u8 dcs_cmd) int channel, u8 dcs_cmd, enum port port)
{ {
return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1); return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1, port);
} }
static inline int dsi_vc_dcs_write_1(struct intel_dsi *intel_dsi, static inline int dsi_vc_dcs_write_1(struct intel_dsi *intel_dsi,
int channel, u8 dcs_cmd, u8 param) int channel, u8 dcs_cmd, u8 param, enum port port)
{ {
u8 buf[2] = { dcs_cmd, param }; u8 buf[2] = { dcs_cmd, param };
return dsi_vc_dcs_write(intel_dsi, channel, buf, 2); return dsi_vc_dcs_write(intel_dsi, channel, buf, 2, port);
} }
static inline int dsi_vc_generic_write_0(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_write_0(struct intel_dsi *intel_dsi,
int channel) int channel, enum port port)
{ {
return dsi_vc_generic_write(intel_dsi, channel, NULL, 0); return dsi_vc_generic_write(intel_dsi, channel, NULL, 0, port);
} }
static inline int dsi_vc_generic_write_1(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_write_1(struct intel_dsi *intel_dsi,
int channel, u8 param) int channel, u8 param, enum port port)
{ {
return dsi_vc_generic_write(intel_dsi, channel, &param, 1); return dsi_vc_generic_write(intel_dsi, channel, &param, 1, port);
} }
static inline int dsi_vc_generic_write_2(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_write_2(struct intel_dsi *intel_dsi,
int channel, u8 param1, u8 param2) int channel, u8 param1, u8 param2, enum port port)
{ {
u8 buf[2] = { param1, param2 }; u8 buf[2] = { param1, param2 };
return dsi_vc_generic_write(intel_dsi, channel, buf, 2); return dsi_vc_generic_write(intel_dsi, channel, buf, 2, port);
} }
/* XXX: questionable read helpers */ /* XXX: questionable read helpers */
static inline int dsi_vc_generic_read_0(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_read_0(struct intel_dsi *intel_dsi,
int channel, u8 *buf, int buflen) int channel, u8 *buf, int buflen, enum port port)
{ {
return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen); return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen,
port);
} }
static inline int dsi_vc_generic_read_1(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_read_1(struct intel_dsi *intel_dsi,
int channel, u8 param, u8 *buf, int channel, u8 param, u8 *buf,
int buflen) int buflen, enum port port)
{ {
return dsi_vc_generic_read(intel_dsi, channel, &param, 1, buf, buflen); return dsi_vc_generic_read(intel_dsi, channel, &param, 1, buf, buflen,
port);
} }
static inline int dsi_vc_generic_read_2(struct intel_dsi *intel_dsi, static inline int dsi_vc_generic_read_2(struct intel_dsi *intel_dsi,
int channel, u8 param1, u8 param2, int channel, u8 param1, u8 param2,
u8 *buf, int buflen) u8 *buf, int buflen, enum port port)
{ {
u8 req[2] = { param1, param2 }; u8 req[2] = { param1, param2 };
return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen); return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen,
port);
} }

Просмотреть файл

@ -94,16 +94,31 @@ static struct gpio_table gtable[] = {
{ GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0} { GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0}
}; };
static inline enum port intel_dsi_seq_port_to_port(u8 port)
{
return port ? PORT_C : PORT_A;
}
static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data) static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
{ {
u8 type, byte, mode, vc, port; u8 type, byte, mode, vc, seq_port;
u16 len; u16 len;
enum port port;
byte = *data++; byte = *data++;
mode = (byte >> MIPI_TRANSFER_MODE_SHIFT) & 0x1; mode = (byte >> MIPI_TRANSFER_MODE_SHIFT) & 0x1;
vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3; vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3;
port = (byte >> MIPI_PORT_SHIFT) & 0x3; seq_port = (byte >> MIPI_PORT_SHIFT) & 0x3;
/* For DSI single link on Port A & C, the seq_port value which is
* parsed from Sequence Block#53 of VBT has been set to 0
* Now, read/write of packets for the DSI single link on Port A and
* Port C will based on the DVO port from VBT block 2.
*/
if (intel_dsi->ports == (1 << PORT_C))
port = PORT_C;
else
port = intel_dsi_seq_port_to_port(seq_port);
/* LP or HS mode */ /* LP or HS mode */
intel_dsi->hs = mode; intel_dsi->hs = mode;
@ -115,13 +130,13 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
switch (type) { switch (type) {
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
dsi_vc_generic_write_0(intel_dsi, vc); dsi_vc_generic_write_0(intel_dsi, vc, port);
break; break;
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
dsi_vc_generic_write_1(intel_dsi, vc, *data); dsi_vc_generic_write_1(intel_dsi, vc, *data, port);
break; break;
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1)); dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1), port);
break; break;
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
@ -129,19 +144,19 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n"); DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n");
break; break;
case MIPI_DSI_GENERIC_LONG_WRITE: case MIPI_DSI_GENERIC_LONG_WRITE:
dsi_vc_generic_write(intel_dsi, vc, data, len); dsi_vc_generic_write(intel_dsi, vc, data, len, port);
break; break;
case MIPI_DSI_DCS_SHORT_WRITE: case MIPI_DSI_DCS_SHORT_WRITE:
dsi_vc_dcs_write_0(intel_dsi, vc, *data); dsi_vc_dcs_write_0(intel_dsi, vc, *data, port);
break; break;
case MIPI_DSI_DCS_SHORT_WRITE_PARAM: case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1)); dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1), port);
break; break;
case MIPI_DSI_DCS_READ: case MIPI_DSI_DCS_READ:
DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n"); DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n");
break; break;
case MIPI_DSI_DCS_LONG_WRITE: case MIPI_DSI_DCS_LONG_WRITE:
dsi_vc_dcs_write(intel_dsi, vc, data, len); dsi_vc_dcs_write(intel_dsi, vc, data, len, port);
break; break;
} }
@ -280,6 +295,11 @@ static bool generic_init(struct intel_dsi_device *dsi)
intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0; intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
intel_dsi->lane_count = mipi_config->lane_cnt + 1; intel_dsi->lane_count = mipi_config->lane_cnt + 1;
intel_dsi->pixel_format = mipi_config->videomode_color_format << 7; intel_dsi->pixel_format = mipi_config->videomode_color_format << 7;
intel_dsi->dual_link = mipi_config->dual_link;
intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
if (intel_dsi->dual_link)
intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C));
if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666) if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666)
bits_per_pixel = 18; bits_per_pixel = 18;
@ -299,6 +319,20 @@ static bool generic_init(struct intel_dsi_device *dsi)
pclk = mode->clock; pclk = mode->clock;
/* In dual link mode each port needs half of pixel clock */
if (intel_dsi->dual_link) {
pclk = pclk / 2;
/* we can enable pixel_overlap if needed by panel. In this
* case we need to increase the pixelclock for extra pixels
*/
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
pclk += DIV_ROUND_UP(mode->vtotal *
intel_dsi->pixel_overlap *
60, 1000);
}
}
/* Burst Mode Ratio /* Burst Mode Ratio
* Target ddr frequency from VBT / non burst ddr freq * Target ddr frequency from VBT / non burst ddr freq
* multiply by 100 to preserve remainder * multiply by 100 to preserve remainder
@ -493,6 +527,12 @@ static bool generic_init(struct intel_dsi_device *dsi)
DRM_DEBUG_KMS("Clockstop %s\n", intel_dsi->clock_stop ? DRM_DEBUG_KMS("Clockstop %s\n", intel_dsi->clock_stop ?
"disabled" : "enabled"); "disabled" : "enabled");
DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video"); DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video");
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
else
DRM_DEBUG_KMS("Dual link: NONE\n");
DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format); DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format);
DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div); DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div);
DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout); DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout);

Просмотреть файл

@ -241,7 +241,11 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
return; return;
} }
dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL; if (intel_dsi->ports & (1 << PORT_A))
dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
if (intel_dsi->ports & (1 << PORT_C))
dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n", DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl); dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl);
@ -269,12 +273,14 @@ void vlv_enable_dsi_pll(struct intel_encoder *encoder)
tmp |= DSI_PLL_VCO_EN; tmp |= DSI_PLL_VCO_EN;
vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp); vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
mutex_unlock(&dev_priv->dpio_lock); if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
DSI_PLL_LOCK, 20)) {
if (wait_for(I915_READ(PIPECONF(PIPE_A)) & PIPECONF_DSI_PLL_LOCKED, 20)) { mutex_unlock(&dev_priv->dpio_lock);
DRM_ERROR("DSI PLL lock failed\n"); DRM_ERROR("DSI PLL lock failed\n");
return; return;
} }
mutex_unlock(&dev_priv->dpio_lock);
DRM_DEBUG_KMS("DSI PLL locked\n"); DRM_DEBUG_KMS("DSI PLL locked\n");
} }

Просмотреть файл

@ -0,0 +1,701 @@
/*
* Copyright © 2014 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.
*/
/**
* DOC: Frame Buffer Compression (FBC)
*
* FBC tries to save memory bandwidth (and so power consumption) by
* compressing the amount of memory used by the display. It is total
* transparent to user space and completely handled in the kernel.
*
* The benefits of FBC are mostly visible with solid backgrounds and
* variation-less patterns. It comes from keeping the memory footprint small
* and having fewer memory pages opened and accessed for refreshing the display.
*
* i915 is responsible to reserve stolen memory for FBC and configure its
* offset on proper registers. The hardware takes care of all
* compress/decompress. However there are many known cases where we have to
* forcibly disable it to allow proper screen updates.
*/
#include "intel_drv.h"
#include "i915_drv.h"
static void i8xx_fbc_disable(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 fbc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
fbc_ctl = I915_READ(FBC_CONTROL);
if ((fbc_ctl & FBC_CTL_EN) == 0)
return;
fbc_ctl &= ~FBC_CTL_EN;
I915_WRITE(FBC_CONTROL, fbc_ctl);
/* Wait for compressing bit to clear */
if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
DRM_DEBUG_KMS("FBC idle timed out\n");
return;
}
DRM_DEBUG_KMS("disabled FBC\n");
}
static void i8xx_fbc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int cfb_pitch;
int i;
u32 fbc_ctl;
dev_priv->fbc.enabled = true;
cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
if (fb->pitches[0] < cfb_pitch)
cfb_pitch = fb->pitches[0];
/* FBC_CTL wants 32B or 64B units */
if (IS_GEN2(dev))
cfb_pitch = (cfb_pitch / 32) - 1;
else
cfb_pitch = (cfb_pitch / 64) - 1;
/* Clear old tags */
for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
I915_WRITE(FBC_TAG + (i * 4), 0);
if (IS_GEN4(dev)) {
u32 fbc_ctl2;
/* Set it up... */
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
I915_WRITE(FBC_FENCE_OFF, crtc->y);
}
/* enable it... */
fbc_ctl = I915_READ(FBC_CONTROL);
fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
if (IS_I945GM(dev))
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
fbc_ctl |= obj->fence_reg;
I915_WRITE(FBC_CONTROL, fbc_ctl);
DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
}
static bool i8xx_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
}
static void g4x_fbc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
else
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
/* enable it... */
I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void g4x_fbc_disable(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpfc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
dpfc_ctl = I915_READ(DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(DPFC_CONTROL, dpfc_ctl);
DRM_DEBUG_KMS("disabled FBC\n");
}
}
static bool g4x_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}
static void snb_fbc_blit_update(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 blt_ecoskpd;
/* Make sure blitter notifies FBC of writes */
/* Blitter is part of Media powerwell on VLV. No impact of
* his param in other platforms for now */
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
GEN6_BLITTER_LOCK_SHIFT;
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
GEN6_BLITTER_LOCK_SHIFT);
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
POSTING_READ(GEN6_BLITTER_ECOSKPD);
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
}
static void ilk_fbc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dev_priv->fbc.threshold++;
switch (dev_priv->fbc.threshold) {
case 4:
case 3:
dpfc_ctl |= DPFC_CTL_LIMIT_4X;
break;
case 2:
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
break;
case 1:
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
break;
}
dpfc_ctl |= DPFC_CTL_FENCE_EN;
if (IS_GEN5(dev))
dpfc_ctl |= obj->fence_reg;
I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
if (IS_GEN6(dev)) {
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
snb_fbc_blit_update(dev);
}
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void ilk_fbc_disable(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpfc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
DRM_DEBUG_KMS("disabled FBC\n");
}
}
static bool ilk_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
}
static void gen7_fbc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dev_priv->fbc.threshold++;
switch (dev_priv->fbc.threshold) {
case 4:
case 3:
dpfc_ctl |= DPFC_CTL_LIMIT_4X;
break;
case 2:
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
break;
case 1:
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
break;
}
dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
if (dev_priv->fbc.false_color)
dpfc_ctl |= FBC_CTL_FALSE_COLOR;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
if (IS_IVYBRIDGE(dev)) {
/* WaFbcAsynchFlipDisableFbcQueue:ivb */
I915_WRITE(ILK_DISPLAY_CHICKEN1,
I915_READ(ILK_DISPLAY_CHICKEN1) |
ILK_FBCQ_DIS);
} else {
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
HSW_FBCQ_DIS);
}
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
snb_fbc_blit_update(dev);
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
/**
* intel_fbc_enabled - Is FBC enabled?
* @dev: the drm_device
*
* This function is used to verify the current state of FBC.
* FIXME: This should be tracked in the plane config eventually
* instead of queried at runtime for most callers.
*/
bool intel_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return dev_priv->fbc.enabled;
}
void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (!IS_GEN8(dev))
return;
if (!intel_fbc_enabled(dev))
return;
I915_WRITE(MSG_FBC_REND_STATE, value);
}
static void intel_fbc_work_fn(struct work_struct *__work)
{
struct intel_fbc_work *work =
container_of(to_delayed_work(__work),
struct intel_fbc_work, work);
struct drm_device *dev = work->crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
mutex_lock(&dev->struct_mutex);
if (work == dev_priv->fbc.fbc_work) {
/* Double check that we haven't switched fb without cancelling
* the prior work.
*/
if (work->crtc->primary->fb == work->fb) {
dev_priv->display.enable_fbc(work->crtc);
dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
dev_priv->fbc.y = work->crtc->y;
}
dev_priv->fbc.fbc_work = NULL;
}
mutex_unlock(&dev->struct_mutex);
kfree(work);
}
static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv)
{
if (dev_priv->fbc.fbc_work == NULL)
return;
DRM_DEBUG_KMS("cancelling pending FBC enable\n");
/* Synchronisation is provided by struct_mutex and checking of
* dev_priv->fbc.fbc_work, so we can perform the cancellation
* entirely asynchronously.
*/
if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
/* tasklet was killed before being run, clean up */
kfree(dev_priv->fbc.fbc_work);
/* Mark the work as no longer wanted so that if it does
* wake-up (because the work was already running and waiting
* for our mutex), it will discover that is no longer
* necessary to run.
*/
dev_priv->fbc.fbc_work = NULL;
}
static void intel_fbc_enable(struct drm_crtc *crtc)
{
struct intel_fbc_work *work;
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
if (!dev_priv->display.enable_fbc)
return;
intel_fbc_cancel_work(dev_priv);
work = kzalloc(sizeof(*work), GFP_KERNEL);
if (work == NULL) {
DRM_ERROR("Failed to allocate FBC work structure\n");
dev_priv->display.enable_fbc(crtc);
return;
}
work->crtc = crtc;
work->fb = crtc->primary->fb;
INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
dev_priv->fbc.fbc_work = work;
/* Delay the actual enabling to let pageflipping cease and the
* display to settle before starting the compression. Note that
* this delay also serves a second purpose: it allows for a
* vblank to pass after disabling the FBC before we attempt
* to modify the control registers.
*
* A more complicated solution would involve tracking vblanks
* following the termination of the page-flipping sequence
* and indeed performing the enable as a co-routine and not
* waiting synchronously upon the vblank.
*
* WaFbcWaitForVBlankBeforeEnable:ilk,snb
*/
schedule_delayed_work(&work->work, msecs_to_jiffies(50));
}
/**
* intel_fbc_disable - disable FBC
* @dev: the drm_device
*
* This function disables FBC.
*/
void intel_fbc_disable(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
intel_fbc_cancel_work(dev_priv);
if (!dev_priv->display.disable_fbc)
return;
dev_priv->display.disable_fbc(dev);
dev_priv->fbc.plane = -1;
}
static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
enum no_fbc_reason reason)
{
if (dev_priv->fbc.no_fbc_reason == reason)
return false;
dev_priv->fbc.no_fbc_reason = reason;
return true;
}
/**
* intel_fbc_update - enable/disable FBC as needed
* @dev: the drm_device
*
* Set up the framebuffer compression hardware at mode set time. We
* enable it if possible:
* - plane A only (on pre-965)
* - no pixel mulitply/line duplication
* - no alpha buffer discard
* - no dual wide
* - framebuffer <= max_hdisplay in width, max_vdisplay in height
*
* We can't assume that any compression will take place (worst case),
* so the compressed buffer has to be the same size as the uncompressed
* one. It also must reside (along with the line length buffer) in
* stolen memory.
*
* We need to enable/disable FBC on a global basis.
*/
void intel_fbc_update(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = NULL, *tmp_crtc;
struct intel_crtc *intel_crtc;
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode;
unsigned int max_width, max_height;
if (!HAS_FBC(dev)) {
set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
return;
}
if (!i915.powersave) {
if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
DRM_DEBUG_KMS("fbc disabled per module param\n");
return;
}
/*
* If FBC is already on, we just have to verify that we can
* keep it that way...
* Need to disable if:
* - more than one pipe is active
* - changing FBC params (stride, fence, mode)
* - new fb is too large to fit in compressed buffer
* - going to an unsupported config (interlace, pixel multiply, etc.)
*/
for_each_crtc(dev, tmp_crtc) {
if (intel_crtc_active(tmp_crtc) &&
to_intel_crtc(tmp_crtc)->primary_enabled) {
if (crtc) {
if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
goto out_disable;
}
crtc = tmp_crtc;
}
}
if (!crtc || crtc->primary->fb == NULL) {
if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
DRM_DEBUG_KMS("no output, disabling\n");
goto out_disable;
}
intel_crtc = to_intel_crtc(crtc);
fb = crtc->primary->fb;
obj = intel_fb_obj(fb);
adjusted_mode = &intel_crtc->config.adjusted_mode;
if (i915.enable_fbc < 0) {
if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
DRM_DEBUG_KMS("disabled per chip default\n");
goto out_disable;
}
if (!i915.enable_fbc) {
if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
DRM_DEBUG_KMS("fbc disabled per module param\n");
goto out_disable;
}
if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
DRM_DEBUG_KMS("mode incompatible with compression, "
"disabling\n");
goto out_disable;
}
if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
max_width = 4096;
max_height = 4096;
} else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
max_width = 4096;
max_height = 2048;
} else {
max_width = 2048;
max_height = 1536;
}
if (intel_crtc->config.pipe_src_w > max_width ||
intel_crtc->config.pipe_src_h > max_height) {
if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
goto out_disable;
}
if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
intel_crtc->plane != PLANE_A) {
if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
DRM_DEBUG_KMS("plane not A, disabling compression\n");
goto out_disable;
}
/* The use of a CPU fence is mandatory in order to detect writes
* by the CPU to the scanout and trigger updates to the FBC.
*/
if (obj->tiling_mode != I915_TILING_X ||
obj->fence_reg == I915_FENCE_REG_NONE) {
if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
goto out_disable;
}
if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
goto out_disable;
}
/* If the kernel debugger is active, always disable compression */
if (in_dbg_master())
goto out_disable;
if (i915_gem_stolen_setup_compression(dev, obj->base.size,
drm_format_plane_cpp(fb->pixel_format, 0))) {
if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
goto out_disable;
}
/* If the scanout has not changed, don't modify the FBC settings.
* Note that we make the fundamental assumption that the fb->obj
* cannot be unpinned (and have its GTT offset and fence revoked)
* without first being decoupled from the scanout and FBC disabled.
*/
if (dev_priv->fbc.plane == intel_crtc->plane &&
dev_priv->fbc.fb_id == fb->base.id &&
dev_priv->fbc.y == crtc->y)
return;
if (intel_fbc_enabled(dev)) {
/* We update FBC along two paths, after changing fb/crtc
* configuration (modeswitching) and after page-flipping
* finishes. For the latter, we know that not only did
* we disable the FBC at the start of the page-flip
* sequence, but also more than one vblank has passed.
*
* For the former case of modeswitching, it is possible
* to switch between two FBC valid configurations
* instantaneously so we do need to disable the FBC
* before we can modify its control registers. We also
* have to wait for the next vblank for that to take
* effect. However, since we delay enabling FBC we can
* assume that a vblank has passed since disabling and
* that we can safely alter the registers in the deferred
* callback.
*
* In the scenario that we go from a valid to invalid
* and then back to valid FBC configuration we have
* no strict enforcement that a vblank occurred since
* disabling the FBC. However, along all current pipe
* disabling paths we do need to wait for a vblank at
* some point. And we wait before enabling FBC anyway.
*/
DRM_DEBUG_KMS("disabling active FBC for update\n");
intel_fbc_disable(dev);
}
intel_fbc_enable(crtc);
dev_priv->fbc.no_fbc_reason = FBC_OK;
return;
out_disable:
/* Multiple disables should be harmless */
if (intel_fbc_enabled(dev)) {
DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
intel_fbc_disable(dev);
}
i915_gem_stolen_cleanup_compression(dev);
}
/**
* intel_fbc_init - Initialize FBC
* @dev_priv: the i915 device
*
* This function might be called during PM init process.
*/
void intel_fbc_init(struct drm_i915_private *dev_priv)
{
if (!HAS_FBC(dev_priv)) {
dev_priv->fbc.enabled = false;
return;
}
if (INTEL_INFO(dev_priv)->gen >= 7) {
dev_priv->display.fbc_enabled = ilk_fbc_enabled;
dev_priv->display.enable_fbc = gen7_fbc_enable;
dev_priv->display.disable_fbc = ilk_fbc_disable;
} else if (INTEL_INFO(dev_priv)->gen >= 5) {
dev_priv->display.fbc_enabled = ilk_fbc_enabled;
dev_priv->display.enable_fbc = ilk_fbc_enable;
dev_priv->display.disable_fbc = ilk_fbc_disable;
} else if (IS_GM45(dev_priv)) {
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
dev_priv->display.enable_fbc = g4x_fbc_enable;
dev_priv->display.disable_fbc = g4x_fbc_disable;
} else {
dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
dev_priv->display.enable_fbc = i8xx_fbc_enable;
dev_priv->display.disable_fbc = i8xx_fbc_disable;
/* This value was pulled out of someone's hat */
I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
}
dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
}

Просмотреть файл

@ -212,8 +212,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
* @enable_execlists: value of i915.enable_execlists module parameter. * @enable_execlists: value of i915.enable_execlists module parameter.
* *
* Only certain platforms support Execlists (the prerequisites being * Only certain platforms support Execlists (the prerequisites being
* support for Logical Ring Contexts and Aliasing PPGTT or better), * support for Logical Ring Contexts and Aliasing PPGTT or better).
* and only when enabled via module parameter.
* *
* Return: 1 if Execlists is supported and has to be enabled. * Return: 1 if Execlists is supported and has to be enabled.
*/ */
@ -474,13 +473,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
} }
/** /**
* intel_execlists_handle_ctx_events() - handle Context Switch interrupts * intel_lrc_irq_handler() - handle Context Switch interrupts
* @ring: Engine Command Streamer to handle. * @ring: Engine Command Streamer to handle.
* *
* Check the unread Context Status Buffers and manage the submission of new * Check the unread Context Status Buffers and manage the submission of new
* contexts to the ELSP accordingly. * contexts to the ELSP accordingly.
*/ */
void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring) void intel_lrc_irq_handler(struct intel_engine_cs *ring)
{ {
struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_private *dev_priv = ring->dev->dev_private;
u32 status_pointer; u32 status_pointer;
@ -876,40 +875,48 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring,
} }
} }
static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, static int logical_ring_alloc_request(struct intel_engine_cs *ring,
struct intel_context *ctx) struct intel_context *ctx)
{ {
struct drm_i915_gem_request *request;
struct drm_i915_private *dev_private = ring->dev->dev_private;
int ret; int ret;
if (ring->outstanding_lazy_seqno) if (ring->outstanding_lazy_request)
return 0; return 0;
if (ring->preallocated_lazy_request == NULL) { request = kzalloc(sizeof(*request), GFP_KERNEL);
struct drm_i915_gem_request *request; if (request == NULL)
return -ENOMEM;
request = kmalloc(sizeof(*request), GFP_KERNEL); if (ctx != ring->default_context) {
if (request == NULL) ret = intel_lr_context_pin(ring, ctx);
return -ENOMEM; if (ret) {
kfree(request);
if (ctx != ring->default_context) { return ret;
ret = intel_lr_context_pin(ring, ctx);
if (ret) {
kfree(request);
return ret;
}
} }
/* Hold a reference to the context this request belongs to
* (we will need it when the time comes to emit/retire the
* request).
*/
request->ctx = ctx;
i915_gem_context_reference(request->ctx);
ring->preallocated_lazy_request = request;
} }
return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); kref_init(&request->ref);
request->ring = ring;
request->uniq = dev_private->request_uniq++;
ret = i915_gem_get_seqno(ring->dev, &request->seqno);
if (ret) {
intel_lr_context_unpin(ring, ctx);
kfree(request);
return ret;
}
/* Hold a reference to the context this request belongs to
* (we will need it when the time comes to emit/retire the
* request).
*/
request->ctx = ctx;
i915_gem_context_reference(request->ctx);
ring->outstanding_lazy_request = request;
return 0;
} }
static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
@ -917,39 +924,38 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
{ {
struct intel_engine_cs *ring = ringbuf->ring; struct intel_engine_cs *ring = ringbuf->ring;
struct drm_i915_gem_request *request; struct drm_i915_gem_request *request;
u32 seqno = 0;
int ret; int ret;
if (ringbuf->last_retired_head != -1) { if (intel_ring_space(ringbuf) >= bytes)
ringbuf->head = ringbuf->last_retired_head; return 0;
ringbuf->last_retired_head = -1;
ringbuf->space = intel_ring_space(ringbuf);
if (ringbuf->space >= bytes)
return 0;
}
list_for_each_entry(request, &ring->request_list, list) { list_for_each_entry(request, &ring->request_list, list) {
/*
* The request queue is per-engine, so can contain requests
* from multiple ringbuffers. Here, we must ignore any that
* aren't from the ringbuffer we're considering.
*/
struct intel_context *ctx = request->ctx;
if (ctx->engine[ring->id].ringbuf != ringbuf)
continue;
/* Would completion of this request free enough space? */
if (__intel_ring_space(request->tail, ringbuf->tail, if (__intel_ring_space(request->tail, ringbuf->tail,
ringbuf->size) >= bytes) { ringbuf->size) >= bytes) {
seqno = request->seqno;
break; break;
} }
} }
if (seqno == 0) if (&request->list == &ring->request_list)
return -ENOSPC; return -ENOSPC;
ret = i915_wait_seqno(ring, seqno); ret = i915_wait_request(request);
if (ret) if (ret)
return ret; return ret;
i915_gem_retire_requests_ring(ring); i915_gem_retire_requests_ring(ring);
ringbuf->head = ringbuf->last_retired_head;
ringbuf->last_retired_head = -1;
ringbuf->space = intel_ring_space(ringbuf); return intel_ring_space(ringbuf) >= bytes ? 0 : -ENOSPC;
return 0;
} }
static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
@ -975,13 +981,10 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
* case by choosing an insanely large timeout. */ * case by choosing an insanely large timeout. */
end = jiffies + 60 * HZ; end = jiffies + 60 * HZ;
ret = 0;
do { do {
ringbuf->head = I915_READ_HEAD(ring); if (intel_ring_space(ringbuf) >= bytes)
ringbuf->space = intel_ring_space(ringbuf);
if (ringbuf->space >= bytes) {
ret = 0;
break; break;
}
msleep(1); msleep(1);
@ -1022,7 +1025,7 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
iowrite32(MI_NOOP, virt++); iowrite32(MI_NOOP, virt++);
ringbuf->tail = 0; ringbuf->tail = 0;
ringbuf->space = intel_ring_space(ringbuf); intel_ring_update_space(ringbuf);
return 0; return 0;
} }
@ -1076,7 +1079,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
return ret; return ret;
/* Preallocate the olr before touching the ring */ /* Preallocate the olr before touching the ring */
ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx); ret = logical_ring_alloc_request(ring, ringbuf->FIXME_lrc_ctx);
if (ret) if (ret)
return ret; return ret;
@ -1093,7 +1096,7 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_workarounds *w = &dev_priv->workarounds; struct i915_workarounds *w = &dev_priv->workarounds;
if (WARN_ON(w->count == 0)) if (WARN_ON_ONCE(w->count == 0))
return 0; return 0;
ring->gpu_caches_dirty = true; ring->gpu_caches_dirty = true;
@ -1159,10 +1162,6 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
*/ */
I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
ret = intel_init_pipe_control(ring);
if (ret)
return ret;
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
return init_workarounds_ring(ring); return init_workarounds_ring(ring);
@ -1321,7 +1320,7 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
if (ret) if (ret)
return ret; return ret;
cmd = MI_STORE_DWORD_IMM_GEN8; cmd = MI_STORE_DWORD_IMM_GEN4;
cmd |= MI_GLOBAL_GTT; cmd |= MI_GLOBAL_GTT;
intel_logical_ring_emit(ringbuf, cmd); intel_logical_ring_emit(ringbuf, cmd);
@ -1329,7 +1328,8 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
(ring->status_page.gfx_addr + (ring->status_page.gfx_addr +
(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT))); (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
intel_logical_ring_emit(ringbuf, 0); intel_logical_ring_emit(ringbuf, 0);
intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno); intel_logical_ring_emit(ringbuf,
i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_emit(ringbuf, MI_NOOP);
intel_logical_ring_advance_and_submit(ringbuf); intel_logical_ring_advance_and_submit(ringbuf);
@ -1337,6 +1337,18 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
return 0; return 0;
} }
static int gen8_init_rcs_context(struct intel_engine_cs *ring,
struct intel_context *ctx)
{
int ret;
ret = intel_logical_ring_workarounds_emit(ring, ctx);
if (ret)
return ret;
return intel_lr_context_render_state_init(ring, ctx);
}
/** /**
* intel_logical_ring_cleanup() - deallocate the Engine Command Streamer * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
* *
@ -1354,8 +1366,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
intel_logical_ring_stop(ring); intel_logical_ring_stop(ring);
WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
ring->preallocated_lazy_request = NULL; i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
ring->outstanding_lazy_seqno = 0;
if (ring->cleanup) if (ring->cleanup)
ring->cleanup(ring); ring->cleanup(ring);
@ -1389,12 +1400,6 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
if (ret) if (ret)
return ret; return ret;
if (ring->init) {
ret = ring->init(ring);
if (ret)
return ret;
}
ret = intel_lr_context_deferred_create(ring->default_context, ring); ret = intel_lr_context_deferred_create(ring->default_context, ring);
return ret; return ret;
@ -1404,6 +1409,7 @@ static int logical_render_ring_init(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring = &dev_priv->ring[RCS]; struct intel_engine_cs *ring = &dev_priv->ring[RCS];
int ret;
ring->name = "render ring"; ring->name = "render ring";
ring->id = RCS; ring->id = RCS;
@ -1415,8 +1421,8 @@ static int logical_render_ring_init(struct drm_device *dev)
if (HAS_L3_DPF(dev)) if (HAS_L3_DPF(dev))
ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT; ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
ring->init = gen8_init_render_ring; ring->init_hw = gen8_init_render_ring;
ring->init_context = intel_logical_ring_workarounds_emit; ring->init_context = gen8_init_rcs_context;
ring->cleanup = intel_fini_pipe_control; ring->cleanup = intel_fini_pipe_control;
ring->get_seqno = gen8_get_seqno; ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno; ring->set_seqno = gen8_set_seqno;
@ -1426,7 +1432,12 @@ static int logical_render_ring_init(struct drm_device *dev)
ring->irq_put = gen8_logical_ring_put_irq; ring->irq_put = gen8_logical_ring_put_irq;
ring->emit_bb_start = gen8_emit_bb_start; ring->emit_bb_start = gen8_emit_bb_start;
return logical_ring_init(dev, ring); ring->dev = dev;
ret = logical_ring_init(dev, ring);
if (ret)
return ret;
return intel_init_pipe_control(ring);
} }
static int logical_bsd_ring_init(struct drm_device *dev) static int logical_bsd_ring_init(struct drm_device *dev)
@ -1442,7 +1453,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
ring->irq_keep_mask = ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
ring->init = gen8_init_common_ring; ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno; ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno; ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request; ring->emit_request = gen8_emit_request;
@ -1467,7 +1478,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
ring->irq_keep_mask = ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT; GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
ring->init = gen8_init_common_ring; ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno; ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno; ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request; ring->emit_request = gen8_emit_request;
@ -1492,7 +1503,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
ring->irq_keep_mask = ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT; GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
ring->init = gen8_init_common_ring; ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno; ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno; ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request; ring->emit_request = gen8_emit_request;
@ -1517,7 +1528,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
ring->irq_keep_mask = ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT; GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
ring->init = gen8_init_common_ring; ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno; ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno; ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request; ring->emit_request = gen8_emit_request;
@ -1616,7 +1627,7 @@ int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
ret = __i915_add_request(ring, file, so.obj, NULL); ret = __i915_add_request(ring, file, so.obj);
/* intel_logical_ring_add_request moves object to inactive if it /* intel_logical_ring_add_request moves object to inactive if it
* fails */ * fails */
out: out:
@ -1835,8 +1846,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
int ret; int ret;
WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL); WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
if (ctx->engine[ring->id].state) WARN_ON(ctx->engine[ring->id].state);
return 0;
context_size = round_up(get_lr_context_size(ring), 4096); context_size = round_up(get_lr_context_size(ring), 4096);
@ -1872,8 +1882,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
ringbuf->effective_size = ringbuf->size; ringbuf->effective_size = ringbuf->size;
ringbuf->head = 0; ringbuf->head = 0;
ringbuf->tail = 0; ringbuf->tail = 0;
ringbuf->space = ringbuf->size;
ringbuf->last_retired_head = -1; ringbuf->last_retired_head = -1;
intel_ring_update_space(ringbuf);
if (ringbuf->obj == NULL) { if (ringbuf->obj == NULL) {
ret = intel_alloc_ringbuffer_obj(dev, ringbuf); ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
@ -1907,21 +1917,17 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
if (ctx == ring->default_context) if (ctx == ring->default_context)
lrc_setup_hardware_status_page(ring, ctx_obj); lrc_setup_hardware_status_page(ring, ctx_obj);
else if (ring->id == RCS && !ctx->rcs_initialized) {
if (ring->id == RCS && !ctx->rcs_initialized) {
if (ring->init_context) { if (ring->init_context) {
ret = ring->init_context(ring, ctx); ret = ring->init_context(ring, ctx);
if (ret) if (ret) {
DRM_ERROR("ring init context: %d\n", ret); DRM_ERROR("ring init context: %d\n", ret);
ctx->engine[ring->id].ringbuf = NULL;
ctx->engine[ring->id].state = NULL;
goto error;
}
} }
ret = intel_lr_context_render_state_init(ring, ctx);
if (ret) {
DRM_ERROR("Init render state failed: %d\n", ret);
ctx->engine[ring->id].ringbuf = NULL;
ctx->engine[ring->id].state = NULL;
goto error;
}
ctx->rcs_initialized = true; ctx->rcs_initialized = true;
} }

Просмотреть файл

@ -112,7 +112,7 @@ struct intel_ctx_submit_request {
int elsp_submitted; int elsp_submitted;
}; };
void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring); void intel_lrc_irq_handler(struct intel_engine_cs *ring);
void intel_execlists_retire_requests(struct intel_engine_cs *ring); void intel_execlists_retire_requests(struct intel_engine_cs *ring);
#endif /* _INTEL_LRC_H_ */ #endif /* _INTEL_LRC_H_ */

Просмотреть файл

@ -182,7 +182,7 @@ struct intel_overlay {
u32 flip_addr; u32 flip_addr;
struct drm_i915_gem_object *reg_bo; struct drm_i915_gem_object *reg_bo;
/* flip handling */ /* flip handling */
uint32_t last_flip_req; struct drm_i915_gem_request *last_flip_req;
void (*flip_tail)(struct intel_overlay *); void (*flip_tail)(struct intel_overlay *);
}; };
@ -217,17 +217,19 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
int ret; int ret;
BUG_ON(overlay->last_flip_req); BUG_ON(overlay->last_flip_req);
ret = i915_add_request(ring, &overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req,
ring->outstanding_lazy_request);
ret = i915_add_request(ring);
if (ret) if (ret)
return ret; return ret;
overlay->flip_tail = tail; overlay->flip_tail = tail;
ret = i915_wait_seqno(ring, overlay->last_flip_req); ret = i915_wait_request(overlay->last_flip_req);
if (ret) if (ret)
return ret; return ret;
i915_gem_retire_requests(dev); i915_gem_retire_requests(dev);
overlay->last_flip_req = 0; i915_gem_request_assign(&overlay->last_flip_req, NULL);
return 0; return 0;
} }
@ -286,7 +288,10 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
intel_ring_emit(ring, flip_addr); intel_ring_emit(ring, flip_addr);
intel_ring_advance(ring); intel_ring_advance(ring);
return i915_add_request(ring, &overlay->last_flip_req); WARN_ON(overlay->last_flip_req);
i915_gem_request_assign(&overlay->last_flip_req,
ring->outstanding_lazy_request);
return i915_add_request(ring);
} }
static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
@ -361,23 +366,20 @@ static int intel_overlay_off(struct intel_overlay *overlay)
* We have to be careful not to repeat work forever an make forward progess. */ * We have to be careful not to repeat work forever an make forward progess. */
static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
{ {
struct drm_device *dev = overlay->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring = &dev_priv->ring[RCS];
int ret; int ret;
if (overlay->last_flip_req == 0) if (overlay->last_flip_req == NULL)
return 0; return 0;
ret = i915_wait_seqno(ring, overlay->last_flip_req); ret = i915_wait_request(overlay->last_flip_req);
if (ret) if (ret)
return ret; return ret;
i915_gem_retire_requests(dev); i915_gem_retire_requests(overlay->dev);
if (overlay->flip_tail) if (overlay->flip_tail)
overlay->flip_tail(overlay); overlay->flip_tail(overlay);
overlay->last_flip_req = 0; i915_gem_request_assign(&overlay->last_flip_req, NULL);
return 0; return 0;
} }
@ -392,6 +394,8 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
struct intel_engine_cs *ring = &dev_priv->ring[RCS]; struct intel_engine_cs *ring = &dev_priv->ring[RCS];
int ret; int ret;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
/* Only wait if there is actually an old frame to release to /* Only wait if there is actually an old frame to release to
* guarantee forward progress. * guarantee forward progress.
*/ */
@ -422,6 +426,22 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
return 0; return 0;
} }
void intel_overlay_reset(struct drm_i915_private *dev_priv)
{
struct intel_overlay *overlay = dev_priv->overlay;
if (!overlay)
return;
intel_overlay_release_old_vid(overlay);
overlay->last_flip_req = NULL;
overlay->old_xscale = 0;
overlay->old_yscale = 0;
overlay->crtc = NULL;
overlay->active = false;
}
struct put_image_params { struct put_image_params {
int format; int format;
short dst_x; short dst_x;

Просмотреть файл

@ -52,17 +52,6 @@
#define INTEL_RC6p_ENABLE (1<<1) #define INTEL_RC6p_ENABLE (1<<1)
#define INTEL_RC6pp_ENABLE (1<<2) #define INTEL_RC6pp_ENABLE (1<<2)
/* FBC, or Frame Buffer Compression, is a technique employed to compress the
* framebuffer contents in-memory, aiming at reducing the required bandwidth
* during in-memory transfers and, therefore, reduce the power packet.
*
* The benefits of FBC are mostly visible with solid backgrounds and
* variation-less patterns.
*
* FBC-related functionality can be enabled by the means of the
* i915.i915_enable_fbc parameter
*/
static void gen9_init_clock_gating(struct drm_device *dev) static void gen9_init_clock_gating(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
@ -87,613 +76,6 @@ static void gen9_init_clock_gating(struct drm_device *dev)
_MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE)); _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
} }
static void i8xx_disable_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 fbc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
fbc_ctl = I915_READ(FBC_CONTROL);
if ((fbc_ctl & FBC_CTL_EN) == 0)
return;
fbc_ctl &= ~FBC_CTL_EN;
I915_WRITE(FBC_CONTROL, fbc_ctl);
/* Wait for compressing bit to clear */
if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
DRM_DEBUG_KMS("FBC idle timed out\n");
return;
}
DRM_DEBUG_KMS("disabled FBC\n");
}
static void i8xx_enable_fbc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int cfb_pitch;
int i;
u32 fbc_ctl;
dev_priv->fbc.enabled = true;
cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
if (fb->pitches[0] < cfb_pitch)
cfb_pitch = fb->pitches[0];
/* FBC_CTL wants 32B or 64B units */
if (IS_GEN2(dev))
cfb_pitch = (cfb_pitch / 32) - 1;
else
cfb_pitch = (cfb_pitch / 64) - 1;
/* Clear old tags */
for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
I915_WRITE(FBC_TAG + (i * 4), 0);
if (IS_GEN4(dev)) {
u32 fbc_ctl2;
/* Set it up... */
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
I915_WRITE(FBC_FENCE_OFF, crtc->y);
}
/* enable it... */
fbc_ctl = I915_READ(FBC_CONTROL);
fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
if (IS_I945GM(dev))
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
fbc_ctl |= obj->fence_reg;
I915_WRITE(FBC_CONTROL, fbc_ctl);
DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
}
static bool i8xx_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
}
static void g4x_enable_fbc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
else
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
/* enable it... */
I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void g4x_disable_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpfc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
dpfc_ctl = I915_READ(DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(DPFC_CONTROL, dpfc_ctl);
DRM_DEBUG_KMS("disabled FBC\n");
}
}
static bool g4x_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}
static void sandybridge_blit_fbc_update(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 blt_ecoskpd;
/* Make sure blitter notifies FBC of writes */
/* Blitter is part of Media powerwell on VLV. No impact of
* his param in other platforms for now */
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
GEN6_BLITTER_LOCK_SHIFT;
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
GEN6_BLITTER_LOCK_SHIFT);
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
POSTING_READ(GEN6_BLITTER_ECOSKPD);
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
}
static void ironlake_enable_fbc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dev_priv->fbc.threshold++;
switch (dev_priv->fbc.threshold) {
case 4:
case 3:
dpfc_ctl |= DPFC_CTL_LIMIT_4X;
break;
case 2:
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
break;
case 1:
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
break;
}
dpfc_ctl |= DPFC_CTL_FENCE_EN;
if (IS_GEN5(dev))
dpfc_ctl |= obj->fence_reg;
I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
if (IS_GEN6(dev)) {
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
sandybridge_blit_fbc_update(dev);
}
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void ironlake_disable_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpfc_ctl;
dev_priv->fbc.enabled = false;
/* Disable compression */
dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
if (dpfc_ctl & DPFC_CTL_EN) {
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
DRM_DEBUG_KMS("disabled FBC\n");
}
}
static bool ironlake_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
}
static void gen7_enable_fbc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
u32 dpfc_ctl;
dev_priv->fbc.enabled = true;
dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
dev_priv->fbc.threshold++;
switch (dev_priv->fbc.threshold) {
case 4:
case 3:
dpfc_ctl |= DPFC_CTL_LIMIT_4X;
break;
case 2:
dpfc_ctl |= DPFC_CTL_LIMIT_2X;
break;
case 1:
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
break;
}
dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
if (dev_priv->fbc.false_color)
dpfc_ctl |= FBC_CTL_FALSE_COLOR;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
if (IS_IVYBRIDGE(dev)) {
/* WaFbcAsynchFlipDisableFbcQueue:ivb */
I915_WRITE(ILK_DISPLAY_CHICKEN1,
I915_READ(ILK_DISPLAY_CHICKEN1) |
ILK_FBCQ_DIS);
} else {
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
HSW_FBCQ_DIS);
}
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
sandybridge_blit_fbc_update(dev);
DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
bool intel_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return dev_priv->fbc.enabled;
}
void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (!IS_GEN8(dev))
return;
if (!intel_fbc_enabled(dev))
return;
I915_WRITE(MSG_FBC_REND_STATE, value);
}
static void intel_fbc_work_fn(struct work_struct *__work)
{
struct intel_fbc_work *work =
container_of(to_delayed_work(__work),
struct intel_fbc_work, work);
struct drm_device *dev = work->crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
mutex_lock(&dev->struct_mutex);
if (work == dev_priv->fbc.fbc_work) {
/* Double check that we haven't switched fb without cancelling
* the prior work.
*/
if (work->crtc->primary->fb == work->fb) {
dev_priv->display.enable_fbc(work->crtc);
dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
dev_priv->fbc.y = work->crtc->y;
}
dev_priv->fbc.fbc_work = NULL;
}
mutex_unlock(&dev->struct_mutex);
kfree(work);
}
static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
{
if (dev_priv->fbc.fbc_work == NULL)
return;
DRM_DEBUG_KMS("cancelling pending FBC enable\n");
/* Synchronisation is provided by struct_mutex and checking of
* dev_priv->fbc.fbc_work, so we can perform the cancellation
* entirely asynchronously.
*/
if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
/* tasklet was killed before being run, clean up */
kfree(dev_priv->fbc.fbc_work);
/* Mark the work as no longer wanted so that if it does
* wake-up (because the work was already running and waiting
* for our mutex), it will discover that is no longer
* necessary to run.
*/
dev_priv->fbc.fbc_work = NULL;
}
static void intel_enable_fbc(struct drm_crtc *crtc)
{
struct intel_fbc_work *work;
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
if (!dev_priv->display.enable_fbc)
return;
intel_cancel_fbc_work(dev_priv);
work = kzalloc(sizeof(*work), GFP_KERNEL);
if (work == NULL) {
DRM_ERROR("Failed to allocate FBC work structure\n");
dev_priv->display.enable_fbc(crtc);
return;
}
work->crtc = crtc;
work->fb = crtc->primary->fb;
INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
dev_priv->fbc.fbc_work = work;
/* Delay the actual enabling to let pageflipping cease and the
* display to settle before starting the compression. Note that
* this delay also serves a second purpose: it allows for a
* vblank to pass after disabling the FBC before we attempt
* to modify the control registers.
*
* A more complicated solution would involve tracking vblanks
* following the termination of the page-flipping sequence
* and indeed performing the enable as a co-routine and not
* waiting synchronously upon the vblank.
*
* WaFbcWaitForVBlankBeforeEnable:ilk,snb
*/
schedule_delayed_work(&work->work, msecs_to_jiffies(50));
}
void intel_disable_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
intel_cancel_fbc_work(dev_priv);
if (!dev_priv->display.disable_fbc)
return;
dev_priv->display.disable_fbc(dev);
dev_priv->fbc.plane = -1;
}
static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
enum no_fbc_reason reason)
{
if (dev_priv->fbc.no_fbc_reason == reason)
return false;
dev_priv->fbc.no_fbc_reason = reason;
return true;
}
/**
* intel_update_fbc - enable/disable FBC as needed
* @dev: the drm_device
*
* Set up the framebuffer compression hardware at mode set time. We
* enable it if possible:
* - plane A only (on pre-965)
* - no pixel mulitply/line duplication
* - no alpha buffer discard
* - no dual wide
* - framebuffer <= max_hdisplay in width, max_vdisplay in height
*
* We can't assume that any compression will take place (worst case),
* so the compressed buffer has to be the same size as the uncompressed
* one. It also must reside (along with the line length buffer) in
* stolen memory.
*
* We need to enable/disable FBC on a global basis.
*/
void intel_update_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = NULL, *tmp_crtc;
struct intel_crtc *intel_crtc;
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode;
unsigned int max_width, max_height;
if (!HAS_FBC(dev)) {
set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
return;
}
if (!i915.powersave) {
if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
DRM_DEBUG_KMS("fbc disabled per module param\n");
return;
}
/*
* If FBC is already on, we just have to verify that we can
* keep it that way...
* Need to disable if:
* - more than one pipe is active
* - changing FBC params (stride, fence, mode)
* - new fb is too large to fit in compressed buffer
* - going to an unsupported config (interlace, pixel multiply, etc.)
*/
for_each_crtc(dev, tmp_crtc) {
if (intel_crtc_active(tmp_crtc) &&
to_intel_crtc(tmp_crtc)->primary_enabled) {
if (crtc) {
if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
goto out_disable;
}
crtc = tmp_crtc;
}
}
if (!crtc || crtc->primary->fb == NULL) {
if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
DRM_DEBUG_KMS("no output, disabling\n");
goto out_disable;
}
intel_crtc = to_intel_crtc(crtc);
fb = crtc->primary->fb;
obj = intel_fb_obj(fb);
adjusted_mode = &intel_crtc->config.adjusted_mode;
if (i915.enable_fbc < 0) {
if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
DRM_DEBUG_KMS("disabled per chip default\n");
goto out_disable;
}
if (!i915.enable_fbc) {
if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
DRM_DEBUG_KMS("fbc disabled per module param\n");
goto out_disable;
}
if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
DRM_DEBUG_KMS("mode incompatible with compression, "
"disabling\n");
goto out_disable;
}
if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
max_width = 4096;
max_height = 4096;
} else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
max_width = 4096;
max_height = 2048;
} else {
max_width = 2048;
max_height = 1536;
}
if (intel_crtc->config.pipe_src_w > max_width ||
intel_crtc->config.pipe_src_h > max_height) {
if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
goto out_disable;
}
if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
intel_crtc->plane != PLANE_A) {
if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
DRM_DEBUG_KMS("plane not A, disabling compression\n");
goto out_disable;
}
/* The use of a CPU fence is mandatory in order to detect writes
* by the CPU to the scanout and trigger updates to the FBC.
*/
if (obj->tiling_mode != I915_TILING_X ||
obj->fence_reg == I915_FENCE_REG_NONE) {
if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
goto out_disable;
}
if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
goto out_disable;
}
/* If the kernel debugger is active, always disable compression */
if (in_dbg_master())
goto out_disable;
if (i915_gem_stolen_setup_compression(dev, obj->base.size,
drm_format_plane_cpp(fb->pixel_format, 0))) {
if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
goto out_disable;
}
/* If the scanout has not changed, don't modify the FBC settings.
* Note that we make the fundamental assumption that the fb->obj
* cannot be unpinned (and have its GTT offset and fence revoked)
* without first being decoupled from the scanout and FBC disabled.
*/
if (dev_priv->fbc.plane == intel_crtc->plane &&
dev_priv->fbc.fb_id == fb->base.id &&
dev_priv->fbc.y == crtc->y)
return;
if (intel_fbc_enabled(dev)) {
/* We update FBC along two paths, after changing fb/crtc
* configuration (modeswitching) and after page-flipping
* finishes. For the latter, we know that not only did
* we disable the FBC at the start of the page-flip
* sequence, but also more than one vblank has passed.
*
* For the former case of modeswitching, it is possible
* to switch between two FBC valid configurations
* instantaneously so we do need to disable the FBC
* before we can modify its control registers. We also
* have to wait for the next vblank for that to take
* effect. However, since we delay enabling FBC we can
* assume that a vblank has passed since disabling and
* that we can safely alter the registers in the deferred
* callback.
*
* In the scenario that we go from a valid to invalid
* and then back to valid FBC configuration we have
* no strict enforcement that a vblank occurred since
* disabling the FBC. However, along all current pipe
* disabling paths we do need to wait for a vblank at
* some point. And we wait before enabling FBC anyway.
*/
DRM_DEBUG_KMS("disabling active FBC for update\n");
intel_disable_fbc(dev);
}
intel_enable_fbc(crtc);
dev_priv->fbc.no_fbc_reason = FBC_OK;
return;
out_disable:
/* Multiple disables should be harmless */
if (intel_fbc_enabled(dev)) {
DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
intel_disable_fbc(dev);
}
i915_gem_stolen_cleanup_compression(dev);
}
static void i915_pineview_get_mem_freq(struct drm_device *dev) static void i915_pineview_get_mem_freq(struct drm_device *dev)
{ {
@ -3286,7 +2668,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
list_for_each_entry(plane, &dev->mode_config.plane_list, head) { list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane *intel_plane = to_intel_plane(plane);
if (intel_plane->pipe == pipe) if (intel_plane->pipe == pipe &&
plane->type == DRM_PLANE_TYPE_OVERLAY)
p->plane[i++] = intel_plane->wm; p->plane[i++] = intel_plane->wm;
} }
} }
@ -3621,9 +3004,8 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
skl_ddb_entry_size(&cur_ddb->pipe[pipe])) { skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
skl_wm_flush_pipe(dev_priv, pipe, 2); skl_wm_flush_pipe(dev_priv, pipe, 2);
intel_wait_for_vblank(dev, pipe); intel_wait_for_vblank(dev, pipe);
reallocated[pipe] = true;
} }
reallocated[pipe] = true;
} }
/* /*
@ -5307,7 +4689,8 @@ static void cherryview_enable_rps(struct drm_device *dev)
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10); I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
I915_WRITE(GEN6_RC_SLEEP, 0); I915_WRITE(GEN6_RC_SLEEP, 0);
I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */ /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
/* allows RC6 residency counter to work */ /* allows RC6 residency counter to work */
I915_WRITE(VLV_COUNTER_CONTROL, I915_WRITE(VLV_COUNTER_CONTROL,
@ -5321,7 +4704,7 @@ static void cherryview_enable_rps(struct drm_device *dev)
/* 3: Enable RC6 */ /* 3: Enable RC6 */
if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) && if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) &&
(pcbr >> VLV_PCBR_ADDR_SHIFT)) (pcbr >> VLV_PCBR_ADDR_SHIFT))
rc6_mode = GEN6_RC_CTL_EI_MODE(1); rc6_mode = GEN7_RC_CTL_TO_MODE;
I915_WRITE(GEN6_RC_CONTROL, rc6_mode); I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
@ -5681,146 +5064,27 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
return ((m * x) / 127) - b; return ((m * x) / 127) - b;
} }
static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) static int _pxvid_to_vd(u8 pxvid)
{
if (pxvid == 0)
return 0;
if (pxvid >= 8 && pxvid < 31)
pxvid = 31;
return (pxvid + 2) * 125;
}
static u32 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
{ {
struct drm_device *dev = dev_priv->dev; struct drm_device *dev = dev_priv->dev;
static const struct v_table { const int vd = _pxvid_to_vd(pxvid);
u16 vd; /* in .1 mil */ const int vm = vd - 1125;
u16 vm; /* in .1 mil */
} v_table[] = {
{ 0, 0, },
{ 375, 0, },
{ 500, 0, },
{ 625, 0, },
{ 750, 0, },
{ 875, 0, },
{ 1000, 0, },
{ 1125, 0, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4125, 3000, },
{ 4250, 3125, },
{ 4375, 3250, },
{ 4500, 3375, },
{ 4625, 3500, },
{ 4750, 3625, },
{ 4875, 3750, },
{ 5000, 3875, },
{ 5125, 4000, },
{ 5250, 4125, },
{ 5375, 4250, },
{ 5500, 4375, },
{ 5625, 4500, },
{ 5750, 4625, },
{ 5875, 4750, },
{ 6000, 4875, },
{ 6125, 5000, },
{ 6250, 5125, },
{ 6375, 5250, },
{ 6500, 5375, },
{ 6625, 5500, },
{ 6750, 5625, },
{ 6875, 5750, },
{ 7000, 5875, },
{ 7125, 6000, },
{ 7250, 6125, },
{ 7375, 6250, },
{ 7500, 6375, },
{ 7625, 6500, },
{ 7750, 6625, },
{ 7875, 6750, },
{ 8000, 6875, },
{ 8125, 7000, },
{ 8250, 7125, },
{ 8375, 7250, },
{ 8500, 7375, },
{ 8625, 7500, },
{ 8750, 7625, },
{ 8875, 7750, },
{ 9000, 7875, },
{ 9125, 8000, },
{ 9250, 8125, },
{ 9375, 8250, },
{ 9500, 8375, },
{ 9625, 8500, },
{ 9750, 8625, },
{ 9875, 8750, },
{ 10000, 8875, },
{ 10125, 9000, },
{ 10250, 9125, },
{ 10375, 9250, },
{ 10500, 9375, },
{ 10625, 9500, },
{ 10750, 9625, },
{ 10875, 9750, },
{ 11000, 9875, },
{ 11125, 10000, },
{ 11250, 10125, },
{ 11375, 10250, },
{ 11500, 10375, },
{ 11625, 10500, },
{ 11750, 10625, },
{ 11875, 10750, },
{ 12000, 10875, },
{ 12125, 11000, },
{ 12250, 11125, },
{ 12375, 11250, },
{ 12500, 11375, },
{ 12625, 11500, },
{ 12750, 11625, },
{ 12875, 11750, },
{ 13000, 11875, },
{ 13125, 12000, },
{ 13250, 12125, },
{ 13375, 12250, },
{ 13500, 12375, },
{ 13625, 12500, },
{ 13750, 12625, },
{ 13875, 12750, },
{ 14000, 12875, },
{ 14125, 13000, },
{ 14250, 13125, },
{ 14375, 13250, },
{ 14500, 13375, },
{ 14625, 13500, },
{ 14750, 13625, },
{ 14875, 13750, },
{ 15000, 13875, },
{ 15125, 14000, },
{ 15250, 14125, },
{ 15375, 14250, },
{ 15500, 14375, },
{ 15625, 14500, },
{ 15750, 14625, },
{ 15875, 14750, },
{ 16000, 14875, },
{ 16125, 15000, },
};
if (INTEL_INFO(dev)->is_mobile) if (INTEL_INFO(dev)->is_mobile)
return v_table[pxvid].vm; return vm > 0 ? vm : 0;
else
return v_table[pxvid].vd; return vd;
} }
static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
@ -7051,43 +6315,12 @@ void intel_suspend_hw(struct drm_device *dev)
lpt_suspend_hw(dev); lpt_suspend_hw(dev);
} }
static void intel_init_fbc(struct drm_i915_private *dev_priv)
{
if (!HAS_FBC(dev_priv)) {
dev_priv->fbc.enabled = false;
return;
}
if (INTEL_INFO(dev_priv)->gen >= 7) {
dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
dev_priv->display.enable_fbc = gen7_enable_fbc;
dev_priv->display.disable_fbc = ironlake_disable_fbc;
} else if (INTEL_INFO(dev_priv)->gen >= 5) {
dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
dev_priv->display.enable_fbc = ironlake_enable_fbc;
dev_priv->display.disable_fbc = ironlake_disable_fbc;
} else if (IS_GM45(dev_priv)) {
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
dev_priv->display.enable_fbc = g4x_enable_fbc;
dev_priv->display.disable_fbc = g4x_disable_fbc;
} else {
dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
dev_priv->display.enable_fbc = i8xx_enable_fbc;
dev_priv->display.disable_fbc = i8xx_disable_fbc;
/* This value was pulled out of someone's hat */
I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
}
dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
}
/* Set up chip specific power management-related functions */ /* Set up chip specific power management-related functions */
void intel_init_pm(struct drm_device *dev) void intel_init_pm(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
intel_init_fbc(dev_priv); intel_fbc_init(dev_priv);
/* For cxsr */ /* For cxsr */
if (IS_PINEVIEW(dev)) if (IS_PINEVIEW(dev))

Просмотреть файл

@ -61,14 +61,15 @@ static bool is_edp_psr(struct intel_dp *intel_dp)
return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED; return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
} }
bool intel_psr_is_enabled(struct drm_device *dev) static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t val;
if (!HAS_PSR(dev)) val = I915_READ(VLV_PSRSTAT(pipe)) &
return false; VLV_EDP_PSR_CURR_STATE_MASK;
return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
} }
static void intel_psr_write_vsc(struct intel_dp *intel_dp, static void intel_psr_write_vsc(struct intel_dp *intel_dp,
@ -100,7 +101,23 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp,
POSTING_READ(ctl_reg); POSTING_READ(ctl_reg);
} }
static void intel_psr_setup_vsc(struct intel_dp *intel_dp) static void vlv_psr_setup_vsc(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 = dev->dev_private;
struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
uint32_t val;
/* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */
val = I915_READ(VLV_VSCSDP(pipe));
val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
I915_WRITE(VLV_VSCSDP(pipe), val);
}
static void hsw_psr_setup_vsc(struct intel_dp *intel_dp)
{ {
struct edp_vsc_psr psr_vsc; struct edp_vsc_psr psr_vsc;
@ -113,14 +130,20 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
intel_psr_write_vsc(intel_dp, &psr_vsc); intel_psr_write_vsc(intel_dp, &psr_vsc);
} }
static void intel_psr_enable_sink(struct intel_dp *intel_dp) static void vlv_psr_enable_sink(struct intel_dp *intel_dp)
{
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
DP_PSR_ENABLE);
}
static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev; struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t aux_clock_divider; uint32_t aux_clock_divider;
int precharge = 0x3; int precharge = 0x3;
bool only_standby = false; bool only_standby = dev_priv->vbt.psr.full_link;
static const uint8_t aux_msg[] = { static const uint8_t aux_msg[] = {
[0] = DP_AUX_NATIVE_WRITE << 4, [0] = DP_AUX_NATIVE_WRITE << 4,
[1] = DP_SET_POWER >> 8, [1] = DP_SET_POWER >> 8,
@ -157,13 +180,50 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp)
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT)); (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
} }
static void intel_psr_enable_source(struct intel_dp *intel_dp) static void vlv_psr_enable_source(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dig_port->base.base.crtc;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
/* Transition from PSR_state 0 to PSR_state 1, i.e. PSR Inactive */
I915_WRITE(VLV_PSRCTL(pipe),
VLV_EDP_PSR_MODE_SW_TIMER |
VLV_EDP_PSR_SRC_TRANSMITTER_STATE |
VLV_EDP_PSR_ENABLE);
}
static void vlv_psr_activate(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dig_port->base.base.crtc;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
/* Let's do the transition from PSR_state 1 to PSR_state 2
* that is PSR transition to active - static frame transmission.
* Then Hardware is responsible for the transition to PSR_state 3
* that is PSR active - no Remote Frame Buffer (RFB) update.
*/
I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) |
VLV_EDP_PSR_ACTIVE_ENTRY);
}
static void hsw_psr_enable_source(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev; struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t max_sleep_time = 0x1f; uint32_t max_sleep_time = 0x1f;
uint32_t idle_frames = 1; /* Lately it was identified that depending on panel idle frame count
* calculated at HW can be off by 1. So let's use what came
* from VBT + 1 and at minimum 2 to be on the safe side.
*/
uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ?
dev_priv->vbt.psr.idle_frames + 1 : 2;
uint32_t val = 0x0; uint32_t val = 0x0;
const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
bool only_standby = false; bool only_standby = false;
@ -176,7 +236,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp)
val |= EDP_PSR_TP2_TP3_TIME_0us; val |= EDP_PSR_TP2_TP3_TIME_0us;
val |= EDP_PSR_TP1_TIME_0us; val |= EDP_PSR_TP1_TIME_0us;
val |= EDP_PSR_SKIP_AUX_EXIT; val |= EDP_PSR_SKIP_AUX_EXIT;
val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0;
} else } else
val |= EDP_PSR_LINK_DISABLE; val |= EDP_PSR_LINK_DISABLE;
@ -231,7 +290,7 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
return true; return true;
} }
static void intel_psr_do_enable(struct intel_dp *intel_dp) static void intel_psr_activate(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *intel_dig_port = dp_to_dig_port(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_device *dev = intel_dig_port->base.base.dev;
@ -242,7 +301,14 @@ static void intel_psr_do_enable(struct intel_dp *intel_dp)
lockdep_assert_held(&dev_priv->psr.lock); lockdep_assert_held(&dev_priv->psr.lock);
/* Enable/Re-enable PSR on the host */ /* Enable/Re-enable PSR on the host */
intel_psr_enable_source(intel_dp); if (HAS_DDI(dev))
/* On HSW+ after we enable PSR on source it will activate it
* as soon as it match configure idle_frame count. So
* we just actually enable it here on activation time.
*/
hsw_psr_enable_source(intel_dp);
else
vlv_psr_activate(intel_dp);
dev_priv->psr.active = true; dev_priv->psr.active = true;
} }
@ -280,20 +346,83 @@ void intel_psr_enable(struct intel_dp *intel_dp)
dev_priv->psr.busy_frontbuffer_bits = 0; dev_priv->psr.busy_frontbuffer_bits = 0;
intel_psr_setup_vsc(intel_dp); if (HAS_DDI(dev)) {
hsw_psr_setup_vsc(intel_dp);
/* Avoid continuous PSR exit by masking memup and hpd */ /* Avoid continuous PSR exit by masking memup and hpd */
I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
/* Enable PSR on the panel */ /* Enable PSR on the panel */
intel_psr_enable_sink(intel_dp); hsw_psr_enable_sink(intel_dp);
} else {
vlv_psr_setup_vsc(intel_dp);
/* Enable PSR on the panel */
vlv_psr_enable_sink(intel_dp);
/* On HSW+ enable_source also means go to PSR entry/active
* state as soon as idle_frame achieved and here would be
* to soon. However on VLV enable_source just enable PSR
* but let it on inactive state. So we might do this prior
* to active transition, i.e. here.
*/
vlv_psr_enable_source(intel_dp);
}
dev_priv->psr.enabled = intel_dp; dev_priv->psr.enabled = intel_dp;
unlock: unlock:
mutex_unlock(&dev_priv->psr.lock); mutex_unlock(&dev_priv->psr.lock);
} }
static void vlv_psr_disable(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 = dev->dev_private;
struct intel_crtc *intel_crtc =
to_intel_crtc(intel_dig_port->base.base.crtc);
uint32_t val;
if (dev_priv->psr.active) {
/* Put VLV PSR back to PSR_state 0 that is PSR Disabled. */
if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
VLV_EDP_PSR_IN_TRANS) == 0, 1))
WARN(1, "PSR transition took longer than expected\n");
val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
val &= ~VLV_EDP_PSR_ENABLE;
val &= ~VLV_EDP_PSR_MODE_MASK;
I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
dev_priv->psr.active = false;
} else {
WARN_ON(vlv_is_psr_active_on_pipe(dev, intel_crtc->pipe));
}
}
static void hsw_psr_disable(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 = dev->dev_private;
if (dev_priv->psr.active) {
I915_WRITE(EDP_PSR_CTL(dev),
I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE);
/* Wait till PSR is idle */
if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
dev_priv->psr.active = false;
} else {
WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
}
}
/** /**
* intel_psr_disable - Disable PSR * intel_psr_disable - Disable PSR
* @intel_dp: Intel DP * @intel_dp: Intel DP
@ -312,19 +441,10 @@ void intel_psr_disable(struct intel_dp *intel_dp)
return; return;
} }
if (dev_priv->psr.active) { if (HAS_DDI(dev))
I915_WRITE(EDP_PSR_CTL(dev), hsw_psr_disable(intel_dp);
I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE); else
vlv_psr_disable(intel_dp);
/* Wait till PSR is idle */
if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) &
EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
dev_priv->psr.active = false;
} else {
WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
}
dev_priv->psr.enabled = NULL; dev_priv->psr.enabled = NULL;
mutex_unlock(&dev_priv->psr.lock); mutex_unlock(&dev_priv->psr.lock);
@ -337,18 +457,27 @@ static void intel_psr_work(struct work_struct *work)
struct drm_i915_private *dev_priv = struct drm_i915_private *dev_priv =
container_of(work, typeof(*dev_priv), psr.work.work); container_of(work, typeof(*dev_priv), psr.work.work);
struct intel_dp *intel_dp = dev_priv->psr.enabled; struct intel_dp *intel_dp = dev_priv->psr.enabled;
struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
/* We have to make sure PSR is ready for re-enable /* We have to make sure PSR is ready for re-enable
* otherwise it keeps disabled until next full enable/disable cycle. * otherwise it keeps disabled until next full enable/disable cycle.
* PSR might take some time to get fully disabled * PSR might take some time to get fully disabled
* and be ready for re-enable. * and be ready for re-enable.
*/ */
if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & if (HAS_DDI(dev_priv->dev)) {
EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
return; DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
return;
}
} else {
if (wait_for((I915_READ(VLV_PSRSTAT(pipe)) &
VLV_EDP_PSR_IN_TRANS) == 0, 1)) {
DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
return;
}
} }
mutex_lock(&dev_priv->psr.lock); mutex_lock(&dev_priv->psr.lock);
intel_dp = dev_priv->psr.enabled; intel_dp = dev_priv->psr.enabled;
@ -363,7 +492,7 @@ static void intel_psr_work(struct work_struct *work)
if (dev_priv->psr.busy_frontbuffer_bits) if (dev_priv->psr.busy_frontbuffer_bits)
goto unlock; goto unlock;
intel_psr_do_enable(intel_dp); intel_psr_activate(intel_dp);
unlock: unlock:
mutex_unlock(&dev_priv->psr.lock); mutex_unlock(&dev_priv->psr.lock);
} }
@ -371,17 +500,47 @@ unlock:
static void intel_psr_exit(struct drm_device *dev) static void intel_psr_exit(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp *intel_dp = dev_priv->psr.enabled;
struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
u32 val;
if (dev_priv->psr.active) { if (!dev_priv->psr.active)
u32 val = I915_READ(EDP_PSR_CTL(dev)); return;
if (HAS_DDI(dev)) {
val = I915_READ(EDP_PSR_CTL(dev));
WARN_ON(!(val & EDP_PSR_ENABLE)); WARN_ON(!(val & EDP_PSR_ENABLE));
I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE); I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
dev_priv->psr.active = false; dev_priv->psr.active = false;
} else {
val = I915_READ(VLV_PSRCTL(pipe));
/* Here we do the transition from PSR_state 3 to PSR_state 5
* directly once PSR State 4 that is active with single frame
* update can be skipped. PSR_state 5 that is PSR exit then
* Hardware is responsible to transition back to PSR_state 1
* that is PSR inactive. Same state after
* vlv_edp_psr_enable_source.
*/
val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
I915_WRITE(VLV_PSRCTL(pipe), val);
/* Send AUX wake up - Spec says after transitioning to PSR
* active we have to send AUX wake up by writing 01h in DPCD
* 600h of sink device.
* XXX: This might slow down the transition, but without this
* HW doesn't complete the transition to PSR_state 1 and we
* never get the screen updated.
*/
drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
DP_SET_POWER_D0);
} }
dev_priv->psr.active = false;
} }
/** /**
@ -459,6 +618,17 @@ void intel_psr_flush(struct drm_device *dev,
(frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe))) (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
intel_psr_exit(dev); intel_psr_exit(dev);
/*
* On Valleyview and Cherryview we don't use hardware tracking so
* sprite plane updates or cursor moves don't result in a PSR
* invalidating. Which means we need to manually fake this in
* software for all flushes, not just when we've seen a preceding
* invalidation through frontbuffer rendering. */
if (!HAS_DDI(dev) &&
((frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)) ||
(frontbuffer_bits & INTEL_FRONTBUFFER_CURSOR(pipe))))
intel_psr_exit(dev);
if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
schedule_delayed_work(&dev_priv->psr.work, schedule_delayed_work(&dev_priv->psr.work,
msecs_to_jiffies(100)); msecs_to_jiffies(100));

Просмотреть файл

@ -1,3 +1,28 @@
/*
* Copyright © 2014 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.
*
* Generated by: intel-gpu-tools-1.8-220-g01153e7
*/
#include "intel_renderstate.h" #include "intel_renderstate.h"
static const u32 gen6_null_state_relocs[] = { static const u32 gen6_null_state_relocs[] = {

Просмотреть файл

@ -1,3 +1,28 @@
/*
* Copyright © 2014 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.
*
* Generated by: intel-gpu-tools-1.8-220-g01153e7
*/
#include "intel_renderstate.h" #include "intel_renderstate.h"
static const u32 gen7_null_state_relocs[] = { static const u32 gen7_null_state_relocs[] = {

Просмотреть файл

@ -1,3 +1,28 @@
/*
* Copyright © 2014 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.
*
* Generated by: intel-gpu-tools-1.8-220-g01153e7
*/
#include "intel_renderstate.h" #include "intel_renderstate.h"
static const u32 gen8_null_state_relocs[] = { static const u32 gen8_null_state_relocs[] = {

Просмотреть файл

@ -1,3 +1,28 @@
/*
* Copyright © 2014 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.
*
* Generated by: intel-gpu-tools-1.8-220-g01153e7
*/
#include "intel_renderstate.h" #include "intel_renderstate.h"
static const u32 gen9_null_state_relocs[] = { static const u32 gen9_null_state_relocs[] = {

Просмотреть файл

@ -52,16 +52,27 @@ intel_ring_initialized(struct intel_engine_cs *ring)
int __intel_ring_space(int head, int tail, int size) int __intel_ring_space(int head, int tail, int size)
{ {
int space = head - (tail + I915_RING_FREE_SPACE); int space = head - tail;
if (space < 0) if (space <= 0)
space += size; space += size;
return space; return space - I915_RING_FREE_SPACE;
}
void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
{
if (ringbuf->last_retired_head != -1) {
ringbuf->head = ringbuf->last_retired_head;
ringbuf->last_retired_head = -1;
}
ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
ringbuf->tail, ringbuf->size);
} }
int intel_ring_space(struct intel_ringbuffer *ringbuf) int intel_ring_space(struct intel_ringbuffer *ringbuf)
{ {
return __intel_ring_space(ringbuf->head & HEAD_ADDR, intel_ring_update_space(ringbuf);
ringbuf->tail, ringbuf->size); return ringbuf->space;
} }
bool intel_ring_stopped(struct intel_engine_cs *ring) bool intel_ring_stopped(struct intel_engine_cs *ring)
@ -592,10 +603,10 @@ static int init_ring_common(struct intel_engine_cs *ring)
goto out; goto out;
} }
ringbuf->last_retired_head = -1;
ringbuf->head = I915_READ_HEAD(ring); ringbuf->head = I915_READ_HEAD(ring);
ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR; ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
ringbuf->space = intel_ring_space(ringbuf); intel_ring_update_space(ringbuf);
ringbuf->last_retired_head = -1;
memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
@ -627,8 +638,7 @@ intel_init_pipe_control(struct intel_engine_cs *ring)
{ {
int ret; int ret;
if (ring->scratch.obj) WARN_ON(ring->scratch.obj);
return 0;
ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096); ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096);
if (ring->scratch.obj == NULL) { if (ring->scratch.obj == NULL) {
@ -672,7 +682,7 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring,
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_workarounds *w = &dev_priv->workarounds; struct i915_workarounds *w = &dev_priv->workarounds;
if (WARN_ON(w->count == 0)) if (WARN_ON_ONCE(w->count == 0))
return 0; return 0;
ring->gpu_caches_dirty = true; ring->gpu_caches_dirty = true;
@ -703,6 +713,22 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring,
return 0; return 0;
} }
static int intel_rcs_ctx_init(struct intel_engine_cs *ring,
struct intel_context *ctx)
{
int ret;
ret = intel_ring_workarounds_emit(ring, ctx);
if (ret != 0)
return ret;
ret = i915_gem_render_state_init(ring);
if (ret)
DRM_ERROR("init render state: %d\n", ret);
return ret;
}
static int wa_add(struct drm_i915_private *dev_priv, static int wa_add(struct drm_i915_private *dev_priv,
const u32 addr, const u32 mask, const u32 val) const u32 addr, const u32 mask, const u32 val)
{ {
@ -762,9 +788,12 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring)
* workaround for for a possible hang in the unlikely event a TLB * workaround for for a possible hang in the unlikely event a TLB
* invalidation occurs during a PSD flush. * invalidation occurs during a PSD flush.
*/ */
/* WaForceEnableNonCoherent:bdw */
/* WaHdcDisableFetchWhenMasked:bdw */
/* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */ /* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */
WA_SET_BIT_MASKED(HDC_CHICKEN0, WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FORCE_NON_COHERENT | HDC_FORCE_NON_COHERENT |
HDC_DONOT_FETCH_MEM_WHEN_MASKED |
(IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0)); (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
/* Wa4x4STCOptimizationDisable:bdw */ /* Wa4x4STCOptimizationDisable:bdw */
@ -861,12 +890,6 @@ static int init_render_ring(struct intel_engine_cs *ring)
_MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) | _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
_MASKED_BIT_ENABLE(GFX_REPLAY_MODE)); _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
if (INTEL_INFO(dev)->gen >= 5) {
ret = intel_init_pipe_control(ring);
if (ret)
return ret;
}
if (IS_GEN6(dev)) { if (IS_GEN6(dev)) {
/* From the Sandybridge PRM, volume 1 part 3, page 24: /* From the Sandybridge PRM, volume 1 part 3, page 24:
* "If this bit is set, STCunit will have LRA as replacement * "If this bit is set, STCunit will have LRA as replacement
@ -918,17 +941,20 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller,
return ret; return ret;
for_each_ring(waiter, dev_priv, i) { for_each_ring(waiter, dev_priv, i) {
u32 seqno;
u64 gtt_offset = signaller->semaphore.signal_ggtt[i]; u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
continue; continue;
seqno = i915_gem_request_get_seqno(
signaller->outstanding_lazy_request);
intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6)); intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB | intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_QW_WRITE |
PIPE_CONTROL_FLUSH_ENABLE); PIPE_CONTROL_FLUSH_ENABLE);
intel_ring_emit(signaller, lower_32_bits(gtt_offset)); intel_ring_emit(signaller, lower_32_bits(gtt_offset));
intel_ring_emit(signaller, upper_32_bits(gtt_offset)); intel_ring_emit(signaller, upper_32_bits(gtt_offset));
intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); intel_ring_emit(signaller, seqno);
intel_ring_emit(signaller, 0); intel_ring_emit(signaller, 0);
intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL | intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
MI_SEMAPHORE_TARGET(waiter->id)); MI_SEMAPHORE_TARGET(waiter->id));
@ -956,16 +982,19 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller,
return ret; return ret;
for_each_ring(waiter, dev_priv, i) { for_each_ring(waiter, dev_priv, i) {
u32 seqno;
u64 gtt_offset = signaller->semaphore.signal_ggtt[i]; u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
continue; continue;
seqno = i915_gem_request_get_seqno(
signaller->outstanding_lazy_request);
intel_ring_emit(signaller, (MI_FLUSH_DW + 1) | intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
MI_FLUSH_DW_OP_STOREDW); MI_FLUSH_DW_OP_STOREDW);
intel_ring_emit(signaller, lower_32_bits(gtt_offset) | intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
MI_FLUSH_DW_USE_GTT); MI_FLUSH_DW_USE_GTT);
intel_ring_emit(signaller, upper_32_bits(gtt_offset)); intel_ring_emit(signaller, upper_32_bits(gtt_offset));
intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); intel_ring_emit(signaller, seqno);
intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL | intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
MI_SEMAPHORE_TARGET(waiter->id)); MI_SEMAPHORE_TARGET(waiter->id));
intel_ring_emit(signaller, 0); intel_ring_emit(signaller, 0);
@ -994,9 +1023,11 @@ static int gen6_signal(struct intel_engine_cs *signaller,
for_each_ring(useless, dev_priv, i) { for_each_ring(useless, dev_priv, i) {
u32 mbox_reg = signaller->semaphore.mbox.signal[i]; u32 mbox_reg = signaller->semaphore.mbox.signal[i];
if (mbox_reg != GEN6_NOSYNC) { if (mbox_reg != GEN6_NOSYNC) {
u32 seqno = i915_gem_request_get_seqno(
signaller->outstanding_lazy_request);
intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
intel_ring_emit(signaller, mbox_reg); intel_ring_emit(signaller, mbox_reg);
intel_ring_emit(signaller, signaller->outstanding_lazy_seqno); intel_ring_emit(signaller, seqno);
} }
} }
@ -1031,7 +1062,8 @@ gen6_add_request(struct intel_engine_cs *ring)
intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
intel_ring_emit(ring, ring->outstanding_lazy_seqno); intel_ring_emit(ring,
i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_emit(ring, MI_USER_INTERRUPT);
__intel_ring_advance(ring); __intel_ring_advance(ring);
@ -1149,7 +1181,8 @@ pc_render_add_request(struct intel_engine_cs *ring)
PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_WRITE_FLUSH |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE); PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
intel_ring_emit(ring, ring->outstanding_lazy_seqno); intel_ring_emit(ring,
i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, 0); intel_ring_emit(ring, 0);
PIPE_CONTROL_FLUSH(ring, scratch_addr); PIPE_CONTROL_FLUSH(ring, scratch_addr);
scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */ scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
@ -1168,7 +1201,8 @@ pc_render_add_request(struct intel_engine_cs *ring)
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_NOTIFY); PIPE_CONTROL_NOTIFY);
intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
intel_ring_emit(ring, ring->outstanding_lazy_seqno); intel_ring_emit(ring,
i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, 0); intel_ring_emit(ring, 0);
__intel_ring_advance(ring); __intel_ring_advance(ring);
@ -1408,7 +1442,8 @@ i9xx_add_request(struct intel_engine_cs *ring)
intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
intel_ring_emit(ring, ring->outstanding_lazy_seqno); intel_ring_emit(ring,
i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_emit(ring, MI_USER_INTERRUPT);
__intel_ring_advance(ring); __intel_ring_advance(ring);
@ -1789,15 +1824,15 @@ int intel_alloc_ringbuffer_obj(struct drm_device *dev,
static int intel_init_ring_buffer(struct drm_device *dev, static int intel_init_ring_buffer(struct drm_device *dev,
struct intel_engine_cs *ring) struct intel_engine_cs *ring)
{ {
struct intel_ringbuffer *ringbuf = ring->buffer; struct intel_ringbuffer *ringbuf;
int ret; int ret;
if (ringbuf == NULL) { WARN_ON(ring->buffer);
ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
if (!ringbuf) ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
return -ENOMEM; if (!ringbuf)
ring->buffer = ringbuf; return -ENOMEM;
} ring->buffer = ringbuf;
ring->dev = dev; ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->active_list);
@ -1820,21 +1855,21 @@ static int intel_init_ring_buffer(struct drm_device *dev,
goto error; goto error;
} }
if (ringbuf->obj == NULL) { WARN_ON(ringbuf->obj);
ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
if (ret) {
DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
ring->name, ret);
goto error;
}
ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf); ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
if (ret) { if (ret) {
DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n", DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
ring->name, ret); ring->name, ret);
intel_destroy_ringbuffer_obj(ringbuf); goto error;
goto error; }
}
ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
if (ret) {
DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
ring->name, ret);
intel_destroy_ringbuffer_obj(ringbuf);
goto error;
} }
/* Workaround an erratum on the i830 which causes a hang if /* Workaround an erratum on the i830 which causes a hang if
@ -1849,10 +1884,6 @@ static int intel_init_ring_buffer(struct drm_device *dev,
if (ret) if (ret)
goto error; goto error;
ret = ring->init(ring);
if (ret)
goto error;
return 0; return 0;
error: error:
@ -1877,8 +1908,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
intel_unpin_ringbuffer_obj(ringbuf); intel_unpin_ringbuffer_obj(ringbuf);
intel_destroy_ringbuffer_obj(ringbuf); intel_destroy_ringbuffer_obj(ringbuf);
ring->preallocated_lazy_request = NULL; i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
ring->outstanding_lazy_seqno = 0;
if (ring->cleanup) if (ring->cleanup)
ring->cleanup(ring); ring->cleanup(ring);
@ -1895,38 +1925,27 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
{ {
struct intel_ringbuffer *ringbuf = ring->buffer; struct intel_ringbuffer *ringbuf = ring->buffer;
struct drm_i915_gem_request *request; struct drm_i915_gem_request *request;
u32 seqno = 0;
int ret; int ret;
if (ringbuf->last_retired_head != -1) { if (intel_ring_space(ringbuf) >= n)
ringbuf->head = ringbuf->last_retired_head; return 0;
ringbuf->last_retired_head = -1;
ringbuf->space = intel_ring_space(ringbuf);
if (ringbuf->space >= n)
return 0;
}
list_for_each_entry(request, &ring->request_list, list) { list_for_each_entry(request, &ring->request_list, list) {
if (__intel_ring_space(request->tail, ringbuf->tail, if (__intel_ring_space(request->tail, ringbuf->tail,
ringbuf->size) >= n) { ringbuf->size) >= n) {
seqno = request->seqno;
break; break;
} }
} }
if (seqno == 0) if (&request->list == &ring->request_list)
return -ENOSPC; return -ENOSPC;
ret = i915_wait_seqno(ring, seqno); ret = i915_wait_request(request);
if (ret) if (ret)
return ret; return ret;
i915_gem_retire_requests_ring(ring); i915_gem_retire_requests_ring(ring);
ringbuf->head = ringbuf->last_retired_head;
ringbuf->last_retired_head = -1;
ringbuf->space = intel_ring_space(ringbuf);
return 0; return 0;
} }
@ -1952,14 +1971,14 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
* case by choosing an insanely large timeout. */ * case by choosing an insanely large timeout. */
end = jiffies + 60 * HZ; end = jiffies + 60 * HZ;
ret = 0;
trace_i915_ring_wait_begin(ring); trace_i915_ring_wait_begin(ring);
do { do {
ringbuf->head = I915_READ_HEAD(ring); if (intel_ring_space(ringbuf) >= n)
ringbuf->space = intel_ring_space(ringbuf); break;
if (ringbuf->space >= n) { ringbuf->head = I915_READ_HEAD(ring);
ret = 0; if (intel_ring_space(ringbuf) >= n)
break; break;
}
msleep(1); msleep(1);
@ -2000,19 +2019,19 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
iowrite32(MI_NOOP, virt++); iowrite32(MI_NOOP, virt++);
ringbuf->tail = 0; ringbuf->tail = 0;
ringbuf->space = intel_ring_space(ringbuf); intel_ring_update_space(ringbuf);
return 0; return 0;
} }
int intel_ring_idle(struct intel_engine_cs *ring) int intel_ring_idle(struct intel_engine_cs *ring)
{ {
u32 seqno; struct drm_i915_gem_request *req;
int ret; int ret;
/* We need to add any requests required to flush the objects and ring */ /* We need to add any requests required to flush the objects and ring */
if (ring->outstanding_lazy_seqno) { if (ring->outstanding_lazy_request) {
ret = i915_add_request(ring, NULL); ret = i915_add_request(ring);
if (ret) if (ret)
return ret; return ret;
} }
@ -2021,30 +2040,39 @@ int intel_ring_idle(struct intel_engine_cs *ring)
if (list_empty(&ring->request_list)) if (list_empty(&ring->request_list))
return 0; return 0;
seqno = list_entry(ring->request_list.prev, req = list_entry(ring->request_list.prev,
struct drm_i915_gem_request, struct drm_i915_gem_request,
list)->seqno; list);
return i915_wait_seqno(ring, seqno); return i915_wait_request(req);
} }
static int static int
intel_ring_alloc_seqno(struct intel_engine_cs *ring) intel_ring_alloc_request(struct intel_engine_cs *ring)
{ {
if (ring->outstanding_lazy_seqno) int ret;
struct drm_i915_gem_request *request;
struct drm_i915_private *dev_private = ring->dev->dev_private;
if (ring->outstanding_lazy_request)
return 0; return 0;
if (ring->preallocated_lazy_request == NULL) { request = kzalloc(sizeof(*request), GFP_KERNEL);
struct drm_i915_gem_request *request; if (request == NULL)
return -ENOMEM;
request = kmalloc(sizeof(*request), GFP_KERNEL); kref_init(&request->ref);
if (request == NULL) request->ring = ring;
return -ENOMEM; request->uniq = dev_private->request_uniq++;
ring->preallocated_lazy_request = request; ret = i915_gem_get_seqno(ring->dev, &request->seqno);
if (ret) {
kfree(request);
return ret;
} }
return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno); ring->outstanding_lazy_request = request;
return 0;
} }
static int __intel_ring_prepare(struct intel_engine_cs *ring, static int __intel_ring_prepare(struct intel_engine_cs *ring,
@ -2084,7 +2112,7 @@ int intel_ring_begin(struct intel_engine_cs *ring,
return ret; return ret;
/* Preallocate the olr before touching the ring */ /* Preallocate the olr before touching the ring */
ret = intel_ring_alloc_seqno(ring); ret = intel_ring_alloc_request(ring);
if (ret) if (ret)
return ret; return ret;
@ -2119,7 +2147,7 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno)
struct drm_device *dev = ring->dev; struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
BUG_ON(ring->outstanding_lazy_seqno); BUG_ON(ring->outstanding_lazy_request);
if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) { if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) {
I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); I915_WRITE(RING_SYNC_0(ring->mmio_base), 0);
@ -2341,7 +2369,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
} }
} }
ring->init_context = intel_ring_workarounds_emit; ring->init_context = intel_rcs_ctx_init;
ring->add_request = gen6_add_request; ring->add_request = gen6_add_request;
ring->flush = gen8_render_ring_flush; ring->flush = gen8_render_ring_flush;
ring->irq_get = gen8_ring_get_irq; ring->irq_get = gen8_ring_get_irq;
@ -2426,7 +2454,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->dispatch_execbuffer = i830_dispatch_execbuffer; ring->dispatch_execbuffer = i830_dispatch_execbuffer;
else else
ring->dispatch_execbuffer = i915_dispatch_execbuffer; ring->dispatch_execbuffer = i915_dispatch_execbuffer;
ring->init = init_render_ring; ring->init_hw = init_render_ring;
ring->cleanup = render_ring_cleanup; ring->cleanup = render_ring_cleanup;
/* Workaround batchbuffer to combat CS tlb bug. */ /* Workaround batchbuffer to combat CS tlb bug. */
@ -2448,7 +2476,17 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj); ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
} }
return intel_init_ring_buffer(dev, ring); ret = intel_init_ring_buffer(dev, ring);
if (ret)
return ret;
if (INTEL_INFO(dev)->gen >= 5) {
ret = intel_init_pipe_control(ring);
if (ret)
return ret;
}
return 0;
} }
int intel_init_bsd_ring_buffer(struct drm_device *dev) int intel_init_bsd_ring_buffer(struct drm_device *dev)
@ -2519,7 +2557,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
} }
ring->dispatch_execbuffer = i965_dispatch_execbuffer; ring->dispatch_execbuffer = i965_dispatch_execbuffer;
} }
ring->init = init_ring_common; ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring); return intel_init_ring_buffer(dev, ring);
} }
@ -2558,7 +2596,7 @@ int intel_init_bsd2_ring_buffer(struct drm_device *dev)
ring->semaphore.signal = gen8_xcs_signal; ring->semaphore.signal = gen8_xcs_signal;
GEN8_RING_SEMAPHORE_INIT; GEN8_RING_SEMAPHORE_INIT;
} }
ring->init = init_ring_common; ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring); return intel_init_ring_buffer(dev, ring);
} }
@ -2615,7 +2653,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
} }
} }
ring->init = init_ring_common; ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring); return intel_init_ring_buffer(dev, ring);
} }
@ -2666,7 +2704,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC; ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
} }
} }
ring->init = init_ring_common; ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring); return intel_init_ring_buffer(dev, ring);
} }

Просмотреть файл

@ -142,11 +142,11 @@ struct intel_engine_cs {
unsigned irq_refcount; /* protected by dev_priv->irq_lock */ unsigned irq_refcount; /* protected by dev_priv->irq_lock */
u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */
u32 trace_irq_seqno; struct drm_i915_gem_request *trace_irq_req;
bool __must_check (*irq_get)(struct intel_engine_cs *ring); bool __must_check (*irq_get)(struct intel_engine_cs *ring);
void (*irq_put)(struct intel_engine_cs *ring); void (*irq_put)(struct intel_engine_cs *ring);
int (*init)(struct intel_engine_cs *ring); int (*init_hw)(struct intel_engine_cs *ring);
int (*init_context)(struct intel_engine_cs *ring, int (*init_context)(struct intel_engine_cs *ring,
struct intel_context *ctx); struct intel_context *ctx);
@ -251,7 +251,7 @@ struct intel_engine_cs {
* ringbuffer. * ringbuffer.
* *
* Includes buffers having the contents of their GPU caches * Includes buffers having the contents of their GPU caches
* flushed, not necessarily primitives. last_rendering_seqno * flushed, not necessarily primitives. last_read_req
* represents when the rendering involved will be completed. * represents when the rendering involved will be completed.
* *
* A reference is held on the buffer while on this list. * A reference is held on the buffer while on this list.
@ -267,8 +267,7 @@ struct intel_engine_cs {
/** /**
* Do we have some not yet emitted requests outstanding? * Do we have some not yet emitted requests outstanding?
*/ */
struct drm_i915_gem_request *preallocated_lazy_request; struct drm_i915_gem_request *outstanding_lazy_request;
u32 outstanding_lazy_seqno;
bool gpu_caches_dirty; bool gpu_caches_dirty;
bool fbc_dirty; bool fbc_dirty;
@ -408,6 +407,7 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
ringbuf->tail &= ringbuf->size - 1; ringbuf->tail &= ringbuf->size - 1;
} }
int __intel_ring_space(int head, int tail, int size); int __intel_ring_space(int head, int tail, int size);
void intel_ring_update_space(struct intel_ringbuffer *ringbuf);
int intel_ring_space(struct intel_ringbuffer *ringbuf); int intel_ring_space(struct intel_ringbuffer *ringbuf);
bool intel_ring_stopped(struct intel_engine_cs *ring); bool intel_ring_stopped(struct intel_engine_cs *ring);
void __intel_ring_advance(struct intel_engine_cs *ring); void __intel_ring_advance(struct intel_engine_cs *ring);
@ -436,16 +436,11 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf)
return ringbuf->tail; return ringbuf->tail;
} }
static inline u32 intel_ring_get_seqno(struct intel_engine_cs *ring) static inline struct drm_i915_gem_request *
intel_ring_get_request(struct intel_engine_cs *ring)
{ {
BUG_ON(ring->outstanding_lazy_seqno == 0); BUG_ON(ring->outstanding_lazy_request == NULL);
return ring->outstanding_lazy_seqno; return ring->outstanding_lazy_request;
}
static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno)
{
if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
ring->trace_irq_seqno = seqno;
} }
#endif /* _INTEL_RINGBUFFER_H_ */ #endif /* _INTEL_RINGBUFFER_H_ */

Просмотреть файл

@ -118,7 +118,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
} }
/** /**
* intel_display_power_is_enabled - unlocked check for a power domain * intel_display_power_is_enabled - check for a power domain
* @dev_priv: i915 device instance * @dev_priv: i915 device instance
* @domain: power domain to check * @domain: power domain to check
* *
@ -633,7 +633,7 @@ static void check_power_well_state(struct drm_i915_private *dev_priv,
return; return;
mismatch: mismatch:
WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n", I915_STATE_WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
power_well->name, power_well->always_on, enabled, power_well->name, power_well->always_on, enabled,
power_well->count, i915.disable_power_well); power_well->count, i915.disable_power_well);
} }

Просмотреть файл

@ -1004,7 +1004,7 @@ intel_post_enable_primary(struct drm_crtc *crtc)
hsw_enable_ips(intel_crtc); hsw_enable_ips(intel_crtc);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev); intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
@ -1017,7 +1017,7 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (dev_priv->fbc.plane == intel_crtc->plane) if (dev_priv->fbc.plane == intel_crtc->plane)
intel_disable_fbc(dev); intel_fbc_disable(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
/* /*
@ -1096,9 +1096,9 @@ static int
intel_check_sprite_plane(struct drm_plane *plane, intel_check_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state) struct intel_plane_state *state)
{ {
struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *obj = intel_fb_obj(fb);
int crtc_x, crtc_y; int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h; unsigned int crtc_w, crtc_h;
@ -1109,7 +1109,12 @@ intel_check_sprite_plane(struct drm_plane *plane,
const struct drm_rect *clip = &state->clip; const struct drm_rect *clip = &state->clip;
int hscale, vscale; int hscale, vscale;
int max_scale, min_scale; int max_scale, min_scale;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); int pixel_size;
if (!fb) {
state->visible = false;
return 0;
}
/* Don't modify another pipe's plane */ /* Don't modify another pipe's plane */
if (intel_plane->pipe != intel_crtc->pipe) { if (intel_plane->pipe != intel_crtc->pipe) {
@ -1232,6 +1237,7 @@ intel_check_sprite_plane(struct drm_plane *plane,
if (src_w < 3 || src_h < 3) if (src_w < 3 || src_h < 3)
state->visible = false; state->visible = false;
pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
width_bytes = ((src_x * pixel_size) & 63) + width_bytes = ((src_x * pixel_size) & 63) +
src_w * pixel_size; src_w * pixel_size;
@ -1257,53 +1263,17 @@ intel_check_sprite_plane(struct drm_plane *plane,
return 0; return 0;
} }
static int
intel_prepare_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
struct drm_device *dev = plane->dev;
struct drm_crtc *crtc = state->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_plane *intel_plane = to_intel_plane(plane);
enum pipe pipe = intel_crtc->pipe;
struct drm_framebuffer *fb = state->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct drm_i915_gem_object *old_obj = intel_plane->obj;
int ret;
if (old_obj != obj) {
mutex_lock(&dev->struct_mutex);
/* Note that this will apply the VT-d workaround for scanouts,
* which is more restrictive than required for sprites. (The
* primary plane requires 256KiB alignment with 64 PTE padding,
* the sprite planes only require 128KiB alignment and 32 PTE
* padding.
*/
ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
if (ret == 0)
i915_gem_track_fb(old_obj, obj,
INTEL_FRONTBUFFER_SPRITE(pipe));
mutex_unlock(&dev->struct_mutex);
if (ret)
return ret;
}
return 0;
}
static void static void
intel_commit_sprite_plane(struct drm_plane *plane, intel_commit_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state) struct intel_plane_state *state)
{ {
struct drm_device *dev = plane->dev; struct drm_device *dev = plane->dev;
struct drm_crtc *crtc = state->crtc; struct drm_crtc *crtc = state->base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane *intel_plane = to_intel_plane(plane);
enum pipe pipe = intel_crtc->pipe; enum pipe pipe = intel_crtc->pipe;
struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct drm_i915_gem_object *old_obj = intel_plane->obj;
int crtc_x, crtc_y; int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h; unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y, src_w, src_h; uint32_t src_x, src_y, src_w, src_h;
@ -1311,6 +1281,17 @@ intel_commit_sprite_plane(struct drm_plane *plane,
const struct drm_rect *clip = &state->clip; const struct drm_rect *clip = &state->clip;
bool primary_enabled; bool primary_enabled;
/*
* 'prepare' is never called when plane is being disabled, so we need
* to handle frontbuffer tracking here
*/
if (!fb) {
mutex_lock(&dev->struct_mutex);
i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
INTEL_FRONTBUFFER_SPRITE(pipe));
mutex_unlock(&dev->struct_mutex);
}
/* /*
* If the sprite is completely covering the primary plane, * If the sprite is completely covering the primary plane,
* we can disable the primary and save power. * we can disable the primary and save power.
@ -1361,112 +1342,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
if (!primary_was_enabled && primary_enabled) if (!primary_was_enabled && primary_enabled)
intel_post_enable_primary(crtc); intel_post_enable_primary(crtc);
} }
/* Unpin old obj after new one is active to avoid ugliness */
if (old_obj && old_obj != obj) {
/*
* It's fairly common to simply update the position of
* an existing object. In that case, we don't need to
* wait for vblank to avoid ugliness, we only need to
* do the pin & ref bookkeeping.
*/
if (intel_crtc->active)
intel_wait_for_vblank(dev, intel_crtc->pipe);
mutex_lock(&dev->struct_mutex);
intel_unpin_fb_obj(old_obj);
mutex_unlock(&dev->struct_mutex);
}
}
static int
intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
struct intel_plane_state state;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int ret;
state.crtc = crtc;
state.fb = fb;
/* sample coordinates in 16.16 fixed point */
state.src.x1 = src_x;
state.src.x2 = src_x + src_w;
state.src.y1 = src_y;
state.src.y2 = src_y + src_h;
/* integer pixels */
state.dst.x1 = crtc_x;
state.dst.x2 = crtc_x + crtc_w;
state.dst.y1 = crtc_y;
state.dst.y2 = crtc_y + crtc_h;
state.clip.x1 = 0;
state.clip.y1 = 0;
state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
state.orig_src = state.src;
state.orig_dst = state.dst;
ret = intel_check_sprite_plane(plane, &state);
if (ret)
return ret;
ret = intel_prepare_sprite_plane(plane, &state);
if (ret)
return ret;
intel_commit_sprite_plane(plane, &state);
return 0;
}
static int
intel_disable_plane(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc;
enum pipe pipe;
if (!plane->fb)
return 0;
if (WARN_ON(!plane->crtc))
return -EINVAL;
intel_crtc = to_intel_crtc(plane->crtc);
pipe = intel_crtc->pipe;
if (intel_crtc->active) {
bool primary_was_enabled = intel_crtc->primary_enabled;
intel_crtc->primary_enabled = true;
intel_plane->disable_plane(plane, plane->crtc);
if (!primary_was_enabled && intel_crtc->primary_enabled)
intel_post_enable_primary(plane->crtc);
}
if (intel_plane->obj) {
if (intel_crtc->active)
intel_wait_for_vblank(dev, intel_plane->pipe);
mutex_lock(&dev->struct_mutex);
intel_unpin_fb_obj(intel_plane->obj);
i915_gem_track_fb(intel_plane->obj, NULL,
INTEL_FRONTBUFFER_SPRITE(pipe));
mutex_unlock(&dev->struct_mutex);
intel_plane->obj = NULL;
}
return 0;
} }
static void intel_destroy_plane(struct drm_plane *plane) static void intel_destroy_plane(struct drm_plane *plane)
@ -1576,14 +1451,6 @@ int intel_plane_restore(struct drm_plane *plane)
intel_plane->src_w, intel_plane->src_h); intel_plane->src_w, intel_plane->src_h);
} }
void intel_plane_disable(struct drm_plane *plane)
{
if (!plane->crtc || !plane->fb)
return;
intel_disable_plane(plane);
}
static const struct drm_plane_funcs intel_plane_funcs = { static const struct drm_plane_funcs intel_plane_funcs = {
.update_plane = intel_update_plane, .update_plane = intel_update_plane,
.disable_plane = intel_disable_plane, .disable_plane = intel_disable_plane,
@ -1720,6 +1587,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_plane->pipe = pipe; intel_plane->pipe = pipe;
intel_plane->plane = plane; intel_plane->plane = plane;
intel_plane->rotation = BIT(DRM_ROTATE_0); intel_plane->rotation = BIT(DRM_ROTATE_0);
intel_plane->check_plane = intel_check_sprite_plane;
intel_plane->commit_plane = intel_commit_sprite_plane;
possible_crtcs = (1 << pipe); possible_crtcs = (1 << pipe);
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs, &intel_plane_funcs,

Просмотреть файл

@ -647,9 +647,9 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
#define FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg) \ #define FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg) \
(REG_RANGE((reg), 0x2000, 0x4000) || \ (REG_RANGE((reg), 0x2000, 0x4000) || \
REG_RANGE((reg), 0x5000, 0x8000) || \ REG_RANGE((reg), 0x5200, 0x8000) || \
REG_RANGE((reg), 0x8300, 0x8500) || \ REG_RANGE((reg), 0x8300, 0x8500) || \
REG_RANGE((reg), 0xB000, 0xC000) || \ REG_RANGE((reg), 0xB000, 0xB480) || \
REG_RANGE((reg), 0xE000, 0xE800)) REG_RANGE((reg), 0xE000, 0xE800))
#define FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg) \ #define FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg) \
@ -658,17 +658,14 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
REG_RANGE((reg), 0x12000, 0x14000) || \ REG_RANGE((reg), 0x12000, 0x14000) || \
REG_RANGE((reg), 0x1A000, 0x1C000) || \ REG_RANGE((reg), 0x1A000, 0x1C000) || \
REG_RANGE((reg), 0x1E800, 0x1EA00) || \ REG_RANGE((reg), 0x1E800, 0x1EA00) || \
REG_RANGE((reg), 0x30000, 0x40000)) REG_RANGE((reg), 0x30000, 0x38000))
#define FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg) \ #define FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg) \
(REG_RANGE((reg), 0x4000, 0x5000) || \ (REG_RANGE((reg), 0x4000, 0x5000) || \
REG_RANGE((reg), 0x8000, 0x8300) || \ REG_RANGE((reg), 0x8000, 0x8300) || \
REG_RANGE((reg), 0x8500, 0x8600) || \ REG_RANGE((reg), 0x8500, 0x8600) || \
REG_RANGE((reg), 0x9000, 0xB000) || \ REG_RANGE((reg), 0x9000, 0xB000) || \
REG_RANGE((reg), 0xC000, 0xC800) || \ REG_RANGE((reg), 0xF000, 0x10000))
REG_RANGE((reg), 0xF000, 0x10000) || \
REG_RANGE((reg), 0x14000, 0x14400) || \
REG_RANGE((reg), 0x22000, 0x24000))
#define FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) \ #define FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) \
REG_RANGE((reg), 0xB00, 0x2000) REG_RANGE((reg), 0xB00, 0x2000)
@ -1202,7 +1199,7 @@ void intel_uncore_init(struct drm_device *dev)
switch (INTEL_INFO(dev)->gen) { switch (INTEL_INFO(dev)->gen) {
default: default:
WARN_ON(1); MISSING_CASE(INTEL_INFO(dev)->gen);
return; return;
case 9: case 9:
ASSIGN_WRITE_MMIO_VFUNCS(gen9); ASSIGN_WRITE_MMIO_VFUNCS(gen9);
@ -1300,7 +1297,7 @@ int i915_reg_read_ioctl(struct drm_device *dev,
reg->val = I915_READ8(reg->offset); reg->val = I915_READ8(reg->offset);
break; break;
default: default:
WARN_ON(1); MISSING_CASE(entry->size);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }

Просмотреть файл

@ -1247,6 +1247,8 @@ extern int drm_plane_init(struct drm_device *dev,
extern void drm_plane_cleanup(struct drm_plane *plane); extern void drm_plane_cleanup(struct drm_plane *plane);
extern unsigned int drm_plane_index(struct drm_plane *plane); extern unsigned int drm_plane_index(struct drm_plane *plane);
extern void drm_plane_force_disable(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane);
extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
int *hdisplay, int *vdisplay);
extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
int x, int y, int x, int y,
const struct drm_display_mode *mode, const struct drm_display_mode *mode,

Просмотреть файл

@ -90,6 +90,9 @@ enum drm_mode_status {
#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ #define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */
#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */ #define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */
#define CRTC_NO_DBLSCAN (1 << 2) /* don't adjust doublescan */
#define CRTC_NO_VSCAN (1 << 3) /* don't adjust doublescan */
#define CRTC_STEREO_DOUBLE_ONLY (CRTC_NO_DBLSCAN | CRTC_NO_VSCAN)
#define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF #define DRM_MODE_FLAG_3D_MAX DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF