diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
100 files changed, 5849 insertions, 2866 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 459f8f88a34c..9e36ffb5eb7c 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -30,6 +30,7 @@ config DRM_I915_DEBUG select SW_SYNC # signaling validation framework (igt/syncobj*) select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST + select DRM_I915_DEBUG_RUNTIME_PM default n help Choose this option to turn on extra driver debugging that may affect @@ -167,3 +168,14 @@ config DRM_I915_DEBUG_VBLANK_EVADE the vblank. If in doubt, say "N". + +config DRM_I915_DEBUG_RUNTIME_PM + bool "Enable extra state checking for runtime PM" + depends on DRM_I915 + default n + help + Choose this option to turn on extra state checking for the + runtime PM functionality. This may introduce overhead during + driver loading, suspend and resume operations. + + If in doubt, say "N" diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index c62346fdc05d..19cf1bbe059d 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -56,6 +56,10 @@ static const u8 pci_cfg_space_rw_bmp[PCI_INTERRUPT_LINE + 4] = { /** * vgpu_pci_cfg_mem_write - write virtual cfg space memory + * @vgpu: target vgpu + * @off: offset + * @src: src ptr to write + * @bytes: number of bytes * * Use this function to write virtual cfg space memory. * For standard cfg space, only RW bits can be changed, @@ -91,6 +95,10 @@ static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off, /** * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read + * @vgpu: target vgpu + * @offset: offset + * @p_data: return data ptr + * @bytes: number of bytes to read * * Returns: * Zero on success, negative error code if failed. @@ -278,6 +286,10 @@ static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset, /** * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write + * @vgpu: target vgpu + * @offset: offset + * @p_data: write data ptr + * @bytes: number of bytes to write * * Returns: * Zero on success, negative error code if failed. diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index a614db310ea2..77edbfcb0f75 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -1840,6 +1840,8 @@ static int cmd_handler_mi_batch_buffer_start(struct parser_exec_state *s) return ret; } +static int mi_noop_index; + static struct cmd_info cmd_info[] = { {"MI_NOOP", OP_MI_NOOP, F_LEN_CONST, R_ALL, D_ALL, 0, 1, NULL}, @@ -2525,7 +2527,12 @@ static int cmd_parser_exec(struct parser_exec_state *s) cmd = cmd_val(s, 0); - info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id); + /* fastpath for MI_NOOP */ + if (cmd == MI_NOOP) + info = &cmd_info[mi_noop_index]; + else + info = get_cmd_info(s->vgpu->gvt, cmd, s->ring_id); + if (info == NULL) { gvt_vgpu_err("unknown cmd 0x%x, opcode=0x%x, addr_type=%s, ring %d, workload=%p\n", cmd, get_opcode(cmd, s->ring_id), @@ -2928,6 +2935,8 @@ static int init_cmd_table(struct intel_gvt *gvt) kfree(e); return -EEXIST; } + if (cmd_info[i].opcode == OP_MI_NOOP) + mi_noop_index = i; INIT_HLIST_NODE(&e->hlist); add_cmd_entry(gvt, e); diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 3019dbc39aef..df1e14145747 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -462,6 +462,7 @@ void intel_vgpu_clean_display(struct intel_vgpu *vgpu) /** * intel_vgpu_init_display- initialize vGPU virtual display emulation * @vgpu: a vGPU + * @resolution: resolution index for intel_vgpu_edid * * This function is used to initialize vGPU virtual display emulation stuffs * diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index 4b98539025c5..5d4bb35bb889 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -340,6 +340,9 @@ static int gmbus2_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, /** * intel_gvt_i2c_handle_gmbus_read - emulate gmbus register mmio read * @vgpu: a vGPU + * @offset: reg offset + * @p_data: data return buffer + * @bytes: access data length * * This function is used to emulate gmbus register mmio read * @@ -365,6 +368,9 @@ int intel_gvt_i2c_handle_gmbus_read(struct intel_vgpu *vgpu, /** * intel_gvt_i2c_handle_gmbus_write - emulate gmbus register mmio write * @vgpu: a vGPU + * @offset: reg offset + * @p_data: data return buffer + * @bytes: access data length * * This function is used to emulate gmbus register mmio write * @@ -437,6 +443,9 @@ static inline int get_aux_ch_reg(unsigned int offset) /** * intel_gvt_i2c_handle_aux_ch_write - emulate AUX channel register write * @vgpu: a vGPU + * @port_idx: port index + * @offset: reg offset + * @p_data: write ptr * * This function is used to emulate AUX channel register write * diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 00aad8164dec..2402395a068d 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -1113,6 +1113,10 @@ static inline void ppgtt_generate_shadow_entry(struct intel_gvt_gtt_entry *se, } /** + * Check if can do 2M page + * @vgpu: target vgpu + * @entry: target pfn's gtt entry + * * Return 1 if 2MB huge gtt shadowing is possilbe, 0 if miscondition, * negtive if found err. */ @@ -1945,7 +1949,7 @@ void intel_vgpu_unpin_mm(struct intel_vgpu_mm *mm) /** * intel_vgpu_pin_mm - increase the pin count of a vGPU mm object - * @vgpu: a vGPU + * @mm: target vgpu mm * * This function is called when user wants to use a vGPU mm object. If this * mm object hasn't been shadowed yet, the shadow will be populated at this @@ -2521,8 +2525,7 @@ fail: /** * intel_vgpu_find_ppgtt_mm - find a PPGTT mm object * @vgpu: a vGPU - * @page_table_level: PPGTT page table level - * @root_entry: PPGTT page table root pointers + * @pdps: pdp root array * * This function is used to find a PPGTT mm object from mm object pool * diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 46c8b720e336..6ef5a7fc70df 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -189,7 +189,6 @@ static const struct intel_gvt_ops intel_gvt_ops = { /** * intel_gvt_init_host - Load MPT modules and detect if we're running in host - * @gvt: intel gvt device * * This function is called at the driver loading stage. If failed to find a * loadable MPT module or detect currently we're running in a VM, then GVT-g @@ -303,7 +302,7 @@ static int init_service_thread(struct intel_gvt *gvt) /** * intel_gvt_clean_device - clean a GVT device - * @gvt: intel gvt device + * @dev_priv: i915 private * * This function is called at the driver unloading stage, to free the * resources owned by a GVT device. diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 94c1089ecf59..90f50f67909a 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -1287,12 +1287,13 @@ static int power_well_ctl_mmio_write(struct intel_vgpu *vgpu, { write_vreg(vgpu, offset, p_data, bytes); - if (vgpu_vreg(vgpu, offset) & HSW_PWR_WELL_CTL_REQ(HSW_DISP_PW_GLOBAL)) + if (vgpu_vreg(vgpu, offset) & + HSW_PWR_WELL_CTL_REQ(HSW_PW_CTL_IDX_GLOBAL)) vgpu_vreg(vgpu, offset) |= - HSW_PWR_WELL_CTL_STATE(HSW_DISP_PW_GLOBAL); + HSW_PWR_WELL_CTL_STATE(HSW_PW_CTL_IDX_GLOBAL); else vgpu_vreg(vgpu, offset) &= - ~HSW_PWR_WELL_CTL_STATE(HSW_DISP_PW_GLOBAL); + ~HSW_PWR_WELL_CTL_STATE(HSW_PW_CTL_IDX_GLOBAL); return 0; } @@ -2137,7 +2138,7 @@ static int init_generic_mmio_info(struct intel_gvt *gvt) MMIO_F(PCH_GMBUS0, 4 * 4, 0, 0, 0, D_ALL, gmbus_mmio_read, gmbus_mmio_write); - MMIO_F(PCH_GPIOA, 6 * 4, F_UNALIGN, 0, 0, D_ALL, NULL, NULL); + MMIO_F(PCH_GPIO_BASE, 6 * 4, F_UNALIGN, 0, 0, D_ALL, NULL, NULL); MMIO_F(_MMIO(0xe4f00), 0x28, 0, 0, 0, D_ALL, NULL, NULL); MMIO_F(_MMIO(_PCH_DPB_AUX_CH_CTL), 6 * 4, 0, 0, 0, D_PRE_SKL, NULL, @@ -2462,17 +2463,10 @@ static int init_generic_mmio_info(struct intel_gvt *gvt) MMIO_D(GEN6_RC6p_THRESHOLD, D_ALL); MMIO_D(GEN6_RC6pp_THRESHOLD, D_ALL); MMIO_D(GEN6_PMINTRMSK, D_ALL); - /* - * Use an arbitrary power well controlled by the PWR_WELL_CTL - * register. - */ - MMIO_DH(HSW_PWR_WELL_CTL_BIOS(HSW_DISP_PW_GLOBAL), D_BDW, NULL, - power_well_ctl_mmio_write); - MMIO_DH(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL), D_BDW, NULL, - power_well_ctl_mmio_write); - MMIO_DH(HSW_PWR_WELL_CTL_KVMR, D_BDW, NULL, power_well_ctl_mmio_write); - MMIO_DH(HSW_PWR_WELL_CTL_DEBUG(HSW_DISP_PW_GLOBAL), D_BDW, NULL, - power_well_ctl_mmio_write); + MMIO_DH(HSW_PWR_WELL_CTL1, D_BDW, NULL, power_well_ctl_mmio_write); + MMIO_DH(HSW_PWR_WELL_CTL2, D_BDW, NULL, power_well_ctl_mmio_write); + MMIO_DH(HSW_PWR_WELL_CTL3, D_BDW, NULL, power_well_ctl_mmio_write); + MMIO_DH(HSW_PWR_WELL_CTL4, D_BDW, NULL, power_well_ctl_mmio_write); MMIO_DH(HSW_PWR_WELL_CTL5, D_BDW, NULL, power_well_ctl_mmio_write); MMIO_DH(HSW_PWR_WELL_CTL6, D_BDW, NULL, power_well_ctl_mmio_write); @@ -2823,13 +2817,8 @@ static int init_skl_mmio_info(struct intel_gvt *gvt) MMIO_F(_MMIO(_DPD_AUX_CH_CTL), 6 * 4, 0, 0, 0, D_SKL_PLUS, NULL, dp_aux_ch_ctl_mmio_write); - /* - * Use an arbitrary power well controlled by the PWR_WELL_CTL - * register. - */ - MMIO_D(HSW_PWR_WELL_CTL_BIOS(SKL_DISP_PW_MISC_IO), D_SKL_PLUS); - MMIO_DH(HSW_PWR_WELL_CTL_DRIVER(SKL_DISP_PW_MISC_IO), D_SKL_PLUS, NULL, - skl_power_well_ctl_write); + MMIO_D(HSW_PWR_WELL_CTL1, D_SKL_PLUS); + MMIO_DH(HSW_PWR_WELL_CTL2, D_SKL_PLUS, NULL, skl_power_well_ctl_write); MMIO_DH(DBUF_CTL, D_SKL_PLUS, NULL, gen9_dbuf_ctl_mmio_write); @@ -3456,6 +3445,7 @@ bool intel_gvt_in_force_nonpriv_whitelist(struct intel_gvt *gvt, * @offset: register offset * @pdata: data buffer * @bytes: data length + * @is_read: read or write * * Returns: * Zero on success, negative error code if failed. diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 9ad89e38f6c0..c1072143da1d 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -1713,7 +1713,7 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) return pfn; } -int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn, +static int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn, unsigned long size, dma_addr_t *dma_addr) { struct kvmgt_guest_info *info; @@ -1762,7 +1762,7 @@ static void __gvt_dma_release(struct kref *ref) __gvt_cache_remove_entry(entry->vgpu, entry); } -void kvmgt_dma_unmap_guest_page(unsigned long handle, dma_addr_t dma_addr) +static void kvmgt_dma_unmap_guest_page(unsigned long handle, dma_addr_t dma_addr) { struct kvmgt_guest_info *info; struct gvt_dma *entry; diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index 9bb9a85c992c..43f65848ecd6 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -39,6 +39,7 @@ /** * intel_vgpu_gpa_to_mmio_offset - translate a GPA to MMIO offset * @vgpu: a vGPU + * @gpa: guest physical address * * Returns: * Zero on success, negative error code if failed @@ -228,7 +229,7 @@ out: /** * intel_vgpu_reset_mmio - reset virtual MMIO space * @vgpu: a vGPU - * + * @dmlr: whether this is device model level reset */ void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu, bool dmlr) { diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index e872f4847fbe..10e63eea5492 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -37,19 +37,6 @@ #include "gvt.h" #include "trace.h" -/** - * Defined in Intel Open Source PRM. - * Ref: https://01.org/linuxgraphics/documentation/hardware-specification-prms - */ -#define TRVATTL3PTRDW(i) _MMIO(0x4de0 + (i)*4) -#define TRNULLDETCT _MMIO(0x4de8) -#define TRINVTILEDETCT _MMIO(0x4dec) -#define TRVADR _MMIO(0x4df0) -#define TRTTE _MMIO(0x4df4) -#define RING_EXCC(base) _MMIO((base) + 0x28) -#define RING_GFX_MODE(base) _MMIO((base) + 0x29c) -#define VF_GUARDBAND _MMIO(0x83a4) - #define GEN9_MOCS_SIZE 64 /* Raw offset is appened to each line for convenience. */ diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h index 5c3b9ff9f96a..f7eaa442403f 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.h +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h @@ -53,5 +53,8 @@ bool is_inhibit_context(struct intel_context *ce); int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu, struct i915_request *req); +#define IS_RESTORE_INHIBIT(a) \ + (_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT) == \ + ((a) & _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT))) #endif diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c index b0d3a43ccd03..276db53f1bf1 100644 --- a/drivers/gpu/drm/i915/gvt/opregion.c +++ b/drivers/gpu/drm/i915/gvt/opregion.c @@ -214,7 +214,6 @@ static void virt_vbt_generation(struct vbt *v) /** * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion * @vgpu: a vGPU - * @gpa: guest physical address of opregion * * Returns: * Zero on success, negative error code if failed. diff --git a/drivers/gpu/drm/i915/gvt/page_track.c b/drivers/gpu/drm/i915/gvt/page_track.c index 256d0db8bbb1..84856022528e 100644 --- a/drivers/gpu/drm/i915/gvt/page_track.c +++ b/drivers/gpu/drm/i915/gvt/page_track.c @@ -41,6 +41,8 @@ struct intel_vgpu_page_track *intel_vgpu_find_page_track( * intel_vgpu_register_page_track - register a guest page to be tacked * @vgpu: a vGPU * @gfn: the gfn of guest page + * @handler: page track handler + * @priv: tracker private * * Returns: * zero on success, negative error code if failed. diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h index d4f7ce6dc1d7..428d252344f1 100644 --- a/drivers/gpu/drm/i915/gvt/reg.h +++ b/drivers/gpu/drm/i915/gvt/reg.h @@ -77,4 +77,22 @@ #define _RING_CTL_BUF_SIZE(ctl) (((ctl) & RB_TAIL_SIZE_MASK) + \ I915_GTT_PAGE_SIZE) +#define PCH_GPIO_BASE _MMIO(0xc5010) + +#define PCH_GMBUS0 _MMIO(0xc5100) +#define PCH_GMBUS1 _MMIO(0xc5104) +#define PCH_GMBUS2 _MMIO(0xc5108) +#define PCH_GMBUS3 _MMIO(0xc510c) +#define PCH_GMBUS4 _MMIO(0xc5110) +#define PCH_GMBUS5 _MMIO(0xc5120) + +#define TRVATTL3PTRDW(i) _MMIO(0x4de0 + (i) * 4) +#define TRNULLDETCT _MMIO(0x4de8) +#define TRINVTILEDETCT _MMIO(0x4dec) +#define TRVADR _MMIO(0x4df0) +#define TRTTE _MMIO(0x4df4) +#define RING_EXCC(base) _MMIO((base) + 0x28) +#define RING_GFX_MODE(base) _MMIO((base) + 0x29c) +#define VF_GUARDBAND _MMIO(0x83a4) + #endif diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 43aa058e29fc..ea34003d6dd2 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -132,35 +132,6 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) unsigned long context_gpa, context_page_num; int i; - gvt_dbg_sched("ring id %d workload lrca %x", ring_id, - workload->ctx_desc.lrca); - - context_page_num = gvt->dev_priv->engine[ring_id]->context_size; - - context_page_num = context_page_num >> PAGE_SHIFT; - - if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS) - context_page_num = 19; - - i = 2; - - while (i < context_page_num) { - context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm, - (u32)((workload->ctx_desc.lrca + i) << - I915_GTT_PAGE_SHIFT)); - if (context_gpa == INTEL_GVT_INVALID_ADDR) { - gvt_vgpu_err("Invalid guest context descriptor\n"); - return -EFAULT; - } - - page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i); - dst = kmap(page); - intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst, - I915_GTT_PAGE_SIZE); - kunmap(page); - i++; - } - page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN); shadow_ring_context = kmap(page); @@ -195,6 +166,37 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) sr_oa_regs(workload, (u32 *)shadow_ring_context, false); kunmap(page); + + if (IS_RESTORE_INHIBIT(shadow_ring_context->ctx_ctrl.val)) + return 0; + + gvt_dbg_sched("ring id %d workload lrca %x", ring_id, + workload->ctx_desc.lrca); + + context_page_num = gvt->dev_priv->engine[ring_id]->context_size; + + context_page_num = context_page_num >> PAGE_SHIFT; + + if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS) + context_page_num = 19; + + i = 2; + while (i < context_page_num) { + context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm, + (u32)((workload->ctx_desc.lrca + i) << + I915_GTT_PAGE_SHIFT)); + if (context_gpa == INTEL_GVT_INVALID_ADDR) { + gvt_vgpu_err("Invalid guest context descriptor\n"); + return -EFAULT; + } + + page = i915_gem_object_get_page(ctx_obj, LRC_HEADER_PAGES + i); + dst = kmap(page); + intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst, + I915_GTT_PAGE_SIZE); + kunmap(page); + i++; + } return 0; } @@ -1138,6 +1140,7 @@ out_shadow_ctx: /** * intel_vgpu_select_submission_ops - select virtual submission interface * @vgpu: a vGPU + * @engine_mask: either ALL_ENGINES or target engine mask * @interface: expected vGPU virtual submission interface * * This function is called when guest configures submission interface. @@ -1190,7 +1193,7 @@ int intel_vgpu_select_submission_ops(struct intel_vgpu *vgpu, /** * intel_vgpu_destroy_workload - destroy a vGPU workload - * @vgpu: a vGPU + * @workload: workload to destroy * * This function is called when destroy a vGPU workload. * @@ -1282,6 +1285,7 @@ static int prepare_mm(struct intel_vgpu_workload *workload) /** * intel_vgpu_create_workload - create a vGPU workload * @vgpu: a vGPU + * @ring_id: ring index * @desc: a guest context descriptor * * This function is called when creating a vGPU workload. diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f9ce35da4123..4f3ac0a12889 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1953,7 +1953,10 @@ static int i915_context_status(struct seq_file *m, void *unused) return ret; list_for_each_entry(ctx, &dev_priv->contexts.list, link) { - seq_printf(m, "HW context %u ", ctx->hw_id); + seq_puts(m, "HW context "); + if (!list_empty(&ctx->hw_id_link)) + seq_printf(m, "%x [pin %u]", ctx->hw_id, + atomic_read(&ctx->hw_id_pin_count)); if (ctx->pid) { struct task_struct *task; @@ -2708,7 +2711,9 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) intel_runtime_pm_get(dev_priv); mutex_lock(&dev_priv->psr.lock); - seq_printf(m, "Enabled: %s\n", yesno((bool)dev_priv->psr.enabled)); + seq_printf(m, "PSR mode: %s\n", + dev_priv->psr.psr2_enabled ? "PSR2" : "PSR1"); + seq_printf(m, "Enabled: %s\n", yesno(dev_priv->psr.enabled)); seq_printf(m, "Busy frontbuffer bits: 0x%03x\n", dev_priv->psr.busy_frontbuffer_bits); @@ -2735,7 +2740,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) psr_source_status(dev_priv, m); mutex_unlock(&dev_priv->psr.lock); - if (READ_ONCE(dev_priv->psr.debug)) { + if (READ_ONCE(dev_priv->psr.debug) & I915_PSR_DEBUG_IRQ) { seq_printf(m, "Last attempted entry at: %lld\n", dev_priv->psr.last_entry_attempt); seq_printf(m, "Last exit at: %lld\n", @@ -2750,17 +2755,32 @@ static int i915_edp_psr_debug_set(void *data, u64 val) { struct drm_i915_private *dev_priv = data; + struct drm_modeset_acquire_ctx ctx; + int ret; if (!CAN_PSR(dev_priv)) return -ENODEV; - DRM_DEBUG_KMS("PSR debug %s\n", enableddisabled(val)); + DRM_DEBUG_KMS("Setting PSR debug to %llx\n", val); intel_runtime_pm_get(dev_priv); - intel_psr_irq_control(dev_priv, !!val); + + drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); + +retry: + ret = intel_psr_set_debugfs_mode(dev_priv, &ctx, val); + if (ret == -EDEADLK) { + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + intel_runtime_pm_put(dev_priv); - return 0; + return ret; } static int @@ -2845,10 +2865,10 @@ static int i915_power_domain_info(struct seq_file *m, void *unused) enum intel_display_power_domain power_domain; power_well = &power_domains->power_wells[i]; - seq_printf(m, "%-25s %d\n", power_well->name, + seq_printf(m, "%-25s %d\n", power_well->desc->name, power_well->count); - for_each_power_domain(power_domain, power_well->domains) + for_each_power_domain(power_domain, power_well->desc->domains) seq_printf(m, " %-23s %d\n", intel_display_power_domain_str(power_domain), power_domains->domain_use_count[power_domain]); @@ -4097,6 +4117,17 @@ i915_ring_test_irq_set(void *data, u64 val) { struct drm_i915_private *i915 = data; + /* GuC keeps the user interrupt permanently enabled for submission */ + if (USES_GUC_SUBMISSION(i915)) + return -ENODEV; + + /* + * From icl, we can no longer individually mask interrupt generation + * from each engine. + */ + if (INTEL_GEN(i915) >= 11) + return -ENODEV; + val &= INTEL_INFO(i915)->ring_mask; DRM_DEBUG_DRIVER("Masking interrupts on rings 0x%08llx\n", val); @@ -4114,13 +4145,17 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_ring_test_irq_fops, #define DROP_FREED BIT(4) #define DROP_SHRINK_ALL BIT(5) #define DROP_IDLE BIT(6) +#define DROP_RESET_ACTIVE BIT(7) +#define DROP_RESET_SEQNO BIT(8) #define DROP_ALL (DROP_UNBOUND | \ DROP_BOUND | \ DROP_RETIRE | \ DROP_ACTIVE | \ DROP_FREED | \ DROP_SHRINK_ALL |\ - DROP_IDLE) + DROP_IDLE | \ + DROP_RESET_ACTIVE | \ + DROP_RESET_SEQNO) static int i915_drop_caches_get(void *data, u64 *val) { @@ -4132,53 +4167,69 @@ i915_drop_caches_get(void *data, u64 *val) static int i915_drop_caches_set(void *data, u64 val) { - struct drm_i915_private *dev_priv = data; - struct drm_device *dev = &dev_priv->drm; + struct drm_i915_private *i915 = data; int ret = 0; DRM_DEBUG("Dropping caches: 0x%08llx [0x%08llx]\n", val, val & DROP_ALL); + if (val & DROP_RESET_ACTIVE && !intel_engines_are_idle(i915)) + i915_gem_set_wedged(i915); + /* No need to check and wait for gpu resets, only libdrm auto-restarts * on ioctls on -EAGAIN. */ - if (val & (DROP_ACTIVE | DROP_RETIRE)) { - ret = mutex_lock_interruptible(&dev->struct_mutex); + if (val & (DROP_ACTIVE | DROP_RETIRE | DROP_RESET_SEQNO)) { + ret = mutex_lock_interruptible(&i915->drm.struct_mutex); if (ret) return ret; if (val & DROP_ACTIVE) - ret = i915_gem_wait_for_idle(dev_priv, + ret = i915_gem_wait_for_idle(i915, I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT); + if (ret == 0 && val & DROP_RESET_SEQNO) { + intel_runtime_pm_get(i915); + ret = i915_gem_set_global_seqno(&i915->drm, 1); + intel_runtime_pm_put(i915); + } + if (val & DROP_RETIRE) - i915_retire_requests(dev_priv); + i915_retire_requests(i915); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&i915->drm.struct_mutex); + } + + if (val & DROP_RESET_ACTIVE && + i915_terminally_wedged(&i915->gpu_error)) { + i915_handle_error(i915, ALL_ENGINES, 0, NULL); + wait_on_bit(&i915->gpu_error.flags, + I915_RESET_HANDOFF, + TASK_UNINTERRUPTIBLE); } fs_reclaim_acquire(GFP_KERNEL); if (val & DROP_BOUND) - i915_gem_shrink(dev_priv, LONG_MAX, NULL, I915_SHRINK_BOUND); + i915_gem_shrink(i915, LONG_MAX, NULL, I915_SHRINK_BOUND); if (val & DROP_UNBOUND) - i915_gem_shrink(dev_priv, LONG_MAX, NULL, I915_SHRINK_UNBOUND); + i915_gem_shrink(i915, LONG_MAX, NULL, I915_SHRINK_UNBOUND); if (val & DROP_SHRINK_ALL) - i915_gem_shrink_all(dev_priv); + i915_gem_shrink_all(i915); fs_reclaim_release(GFP_KERNEL); if (val & DROP_IDLE) { do { - if (READ_ONCE(dev_priv->gt.active_requests)) - flush_delayed_work(&dev_priv->gt.retire_work); - drain_delayed_work(&dev_priv->gt.idle_work); - } while (READ_ONCE(dev_priv->gt.awake)); + if (READ_ONCE(i915->gt.active_requests)) + flush_delayed_work(&i915->gt.retire_work); + drain_delayed_work(&i915->gt.idle_work); + } while (READ_ONCE(i915->gt.awake)); } if (val & DROP_FREED) - i915_gem_drain_freed_objects(dev_priv); + i915_gem_drain_freed_objects(i915); return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f8cfd16be534..44e2c0f5ec50 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -373,7 +373,7 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, value = 2; break; case I915_PARAM_HAS_RESOURCE_STREAMER: - value = HAS_RESOURCE_STREAMER(dev_priv); + value = 0; break; case I915_PARAM_HAS_POOLED_EU: value = HAS_POOLED_EU(dev_priv); @@ -441,6 +441,9 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data, case I915_PARAM_CS_TIMESTAMP_FREQUENCY: value = 1000 * INTEL_INFO(dev_priv)->cs_timestamp_frequency_khz; break; + case I915_PARAM_MMAP_GTT_COHERENT: + value = INTEL_INFO(dev_priv)->has_coherent_ggtt; + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; @@ -709,7 +712,7 @@ cleanup_irq: intel_teardown_gmbus(dev_priv); cleanup_csr: intel_csr_ucode_fini(dev_priv); - intel_power_domains_fini(dev_priv); + intel_power_domains_fini_hw(dev_priv); vga_switcheroo_unregister_client(pdev); cleanup_vga_client: vga_client_register(pdev, NULL, NULL, NULL); @@ -867,7 +870,6 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) /** * i915_driver_init_early - setup state not requiring device access * @dev_priv: device private - * @ent: the matching pci_device_id * * Initialize everything that is a "SW-only" state, that is state not * requiring accessing the device or exposing the driver via kernel internal @@ -875,25 +877,13 @@ static void intel_detect_preproduction_hw(struct drm_i915_private *dev_priv) * system memory allocation, setting up device specific attributes and * function hooks not requiring accessing the device. */ -static int i915_driver_init_early(struct drm_i915_private *dev_priv, - const struct pci_device_id *ent) +static int i915_driver_init_early(struct drm_i915_private *dev_priv) { - const struct intel_device_info *match_info = - (struct intel_device_info *)ent->driver_data; - struct intel_device_info *device_info; int ret = 0; if (i915_inject_load_failure()) return -ENODEV; - /* Setup the write-once "constant" device info */ - device_info = mkwrite_device_info(dev_priv); - memcpy(device_info, match_info, sizeof(*device_info)); - device_info->device_id = dev_priv->drm.pdev->device; - - BUILD_BUG_ON(INTEL_MAX_PLATFORMS > - sizeof(device_info->platform_mask) * BITS_PER_BYTE); - BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE); spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); mutex_init(&dev_priv->backlight_lock); @@ -921,7 +911,9 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, intel_uc_init_early(dev_priv); intel_pm_setup(dev_priv); intel_init_dpio(dev_priv); - intel_power_domains_init(dev_priv); + ret = intel_power_domains_init(dev_priv); + if (ret < 0) + goto err_uc; intel_irq_init(dev_priv); intel_hangcheck_init(dev_priv); intel_init_display_hooks(dev_priv); @@ -933,6 +925,9 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, return 0; +err_uc: + intel_uc_cleanup_early(dev_priv); + i915_gem_cleanup_early(dev_priv); err_workqueues: i915_workqueues_cleanup(dev_priv); err_engines: @@ -947,6 +942,7 @@ err_engines: static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv) { intel_irq_fini(dev_priv); + intel_power_domains_cleanup(dev_priv); intel_uc_cleanup_early(dev_priv); i915_gem_cleanup_early(dev_priv); i915_workqueues_cleanup(dev_priv); @@ -1067,6 +1063,300 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) intel_gvt_sanitize_options(dev_priv); } +static enum dram_rank skl_get_dimm_rank(u8 size, u32 rank) +{ + if (size == 0) + return I915_DRAM_RANK_INVALID; + if (rank == SKL_DRAM_RANK_SINGLE) + return I915_DRAM_RANK_SINGLE; + else if (rank == SKL_DRAM_RANK_DUAL) + return I915_DRAM_RANK_DUAL; + + return I915_DRAM_RANK_INVALID; +} + +static bool +skl_is_16gb_dimm(enum dram_rank rank, u8 size, u8 width) +{ + if (rank == I915_DRAM_RANK_SINGLE && width == 8 && size == 16) + return true; + else if (rank == I915_DRAM_RANK_DUAL && width == 8 && size == 32) + return true; + else if (rank == SKL_DRAM_RANK_SINGLE && width == 16 && size == 8) + return true; + else if (rank == SKL_DRAM_RANK_DUAL && width == 16 && size == 16) + return true; + + return false; +} + +static int +skl_dram_get_channel_info(struct dram_channel_info *ch, u32 val) +{ + u32 tmp_l, tmp_s; + u32 s_val = val >> SKL_DRAM_S_SHIFT; + + if (!val) + return -EINVAL; + + tmp_l = val & SKL_DRAM_SIZE_MASK; + tmp_s = s_val & SKL_DRAM_SIZE_MASK; + + if (tmp_l == 0 && tmp_s == 0) + return -EINVAL; + + ch->l_info.size = tmp_l; + ch->s_info.size = tmp_s; + + tmp_l = (val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT; + tmp_s = (s_val & SKL_DRAM_WIDTH_MASK) >> SKL_DRAM_WIDTH_SHIFT; + ch->l_info.width = (1 << tmp_l) * 8; + ch->s_info.width = (1 << tmp_s) * 8; + + tmp_l = val & SKL_DRAM_RANK_MASK; + tmp_s = s_val & SKL_DRAM_RANK_MASK; + ch->l_info.rank = skl_get_dimm_rank(ch->l_info.size, tmp_l); + ch->s_info.rank = skl_get_dimm_rank(ch->s_info.size, tmp_s); + + if (ch->l_info.rank == I915_DRAM_RANK_DUAL || + ch->s_info.rank == I915_DRAM_RANK_DUAL) + ch->rank = I915_DRAM_RANK_DUAL; + else if (ch->l_info.rank == I915_DRAM_RANK_SINGLE && + ch->s_info.rank == I915_DRAM_RANK_SINGLE) + ch->rank = I915_DRAM_RANK_DUAL; + else + ch->rank = I915_DRAM_RANK_SINGLE; + + ch->is_16gb_dimm = skl_is_16gb_dimm(ch->l_info.rank, ch->l_info.size, + ch->l_info.width) || + skl_is_16gb_dimm(ch->s_info.rank, ch->s_info.size, + ch->s_info.width); + + DRM_DEBUG_KMS("(size:width:rank) L(%dGB:X%d:%s) S(%dGB:X%d:%s)\n", + ch->l_info.size, ch->l_info.width, + ch->l_info.rank ? "dual" : "single", + ch->s_info.size, ch->s_info.width, + ch->s_info.rank ? "dual" : "single"); + + return 0; +} + +static bool +intel_is_dram_symmetric(u32 val_ch0, u32 val_ch1, + struct dram_channel_info *ch0) +{ + return (val_ch0 == val_ch1 && + (ch0->s_info.size == 0 || + (ch0->l_info.size == ch0->s_info.size && + ch0->l_info.width == ch0->s_info.width && + ch0->l_info.rank == ch0->s_info.rank))); +} + +static int +skl_dram_get_channels_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + struct dram_channel_info ch0, ch1; + u32 val_ch0, val_ch1; + int ret; + + val_ch0 = I915_READ(SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN); + ret = skl_dram_get_channel_info(&ch0, val_ch0); + if (ret == 0) + dram_info->num_channels++; + + val_ch1 = I915_READ(SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN); + ret = skl_dram_get_channel_info(&ch1, val_ch1); + if (ret == 0) + dram_info->num_channels++; + + if (dram_info->num_channels == 0) { + DRM_INFO("Number of memory channels is zero\n"); + return -EINVAL; + } + + dram_info->valid_dimm = true; + + /* + * If any of the channel is single rank channel, worst case output + * will be same as if single rank memory, so consider single rank + * memory. + */ + if (ch0.rank == I915_DRAM_RANK_SINGLE || + ch1.rank == I915_DRAM_RANK_SINGLE) + dram_info->rank = I915_DRAM_RANK_SINGLE; + else + dram_info->rank = max(ch0.rank, ch1.rank); + + if (dram_info->rank == I915_DRAM_RANK_INVALID) { + DRM_INFO("couldn't get memory rank information\n"); + return -EINVAL; + } + + if (ch0.is_16gb_dimm || ch1.is_16gb_dimm) + dram_info->is_16gb_dimm = true; + + dev_priv->dram_info.symmetric_memory = intel_is_dram_symmetric(val_ch0, + val_ch1, + &ch0); + + DRM_DEBUG_KMS("memory configuration is %sSymmetric memory\n", + dev_priv->dram_info.symmetric_memory ? "" : "not "); + return 0; +} + +static int +skl_get_dram_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + u32 mem_freq_khz, val; + int ret; + + ret = skl_dram_get_channels_info(dev_priv); + if (ret) + return ret; + + val = I915_READ(SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU); + mem_freq_khz = DIV_ROUND_UP((val & SKL_REQ_DATA_MASK) * + SKL_MEMORY_FREQ_MULTIPLIER_HZ, 1000); + + dram_info->bandwidth_kbps = dram_info->num_channels * + mem_freq_khz * 8; + + if (dram_info->bandwidth_kbps == 0) { + DRM_INFO("Couldn't get system memory bandwidth\n"); + return -EINVAL; + } + + dram_info->valid = true; + return 0; +} + +static int +bxt_get_dram_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + u32 dram_channels; + u32 mem_freq_khz, val; + u8 num_active_channels; + int i; + + val = I915_READ(BXT_P_CR_MC_BIOS_REQ_0_0_0); + mem_freq_khz = DIV_ROUND_UP((val & BXT_REQ_DATA_MASK) * + BXT_MEMORY_FREQ_MULTIPLIER_HZ, 1000); + + dram_channels = val & BXT_DRAM_CHANNEL_ACTIVE_MASK; + num_active_channels = hweight32(dram_channels); + + /* Each active bit represents 4-byte channel */ + dram_info->bandwidth_kbps = (mem_freq_khz * num_active_channels * 4); + + if (dram_info->bandwidth_kbps == 0) { + DRM_INFO("Couldn't get system memory bandwidth\n"); + return -EINVAL; + } + + /* + * Now read each DUNIT8/9/10/11 to check the rank of each dimms. + */ + for (i = BXT_D_CR_DRP0_DUNIT_START; i <= BXT_D_CR_DRP0_DUNIT_END; i++) { + u8 size, width; + enum dram_rank rank; + u32 tmp; + + val = I915_READ(BXT_D_CR_DRP0_DUNIT(i)); + if (val == 0xFFFFFFFF) + continue; + + dram_info->num_channels++; + tmp = val & BXT_DRAM_RANK_MASK; + + if (tmp == BXT_DRAM_RANK_SINGLE) + rank = I915_DRAM_RANK_SINGLE; + else if (tmp == BXT_DRAM_RANK_DUAL) + rank = I915_DRAM_RANK_DUAL; + else + rank = I915_DRAM_RANK_INVALID; + + tmp = val & BXT_DRAM_SIZE_MASK; + if (tmp == BXT_DRAM_SIZE_4GB) + size = 4; + else if (tmp == BXT_DRAM_SIZE_6GB) + size = 6; + else if (tmp == BXT_DRAM_SIZE_8GB) + size = 8; + else if (tmp == BXT_DRAM_SIZE_12GB) + size = 12; + else if (tmp == BXT_DRAM_SIZE_16GB) + size = 16; + else + size = 0; + + tmp = (val & BXT_DRAM_WIDTH_MASK) >> BXT_DRAM_WIDTH_SHIFT; + width = (1 << tmp) * 8; + DRM_DEBUG_KMS("dram size:%dGB width:X%d rank:%s\n", size, + width, rank == I915_DRAM_RANK_SINGLE ? "single" : + rank == I915_DRAM_RANK_DUAL ? "dual" : "unknown"); + + /* + * If any of the channel is single rank channel, + * worst case output will be same as if single rank + * memory, so consider single rank memory. + */ + if (dram_info->rank == I915_DRAM_RANK_INVALID) + dram_info->rank = rank; + else if (rank == I915_DRAM_RANK_SINGLE) + dram_info->rank = I915_DRAM_RANK_SINGLE; + } + + if (dram_info->rank == I915_DRAM_RANK_INVALID) { + DRM_INFO("couldn't get memory rank information\n"); + return -EINVAL; + } + + dram_info->valid_dimm = true; + dram_info->valid = true; + return 0; +} + +static void +intel_get_dram_info(struct drm_i915_private *dev_priv) +{ + struct dram_info *dram_info = &dev_priv->dram_info; + char bandwidth_str[32]; + int ret; + + dram_info->valid = false; + dram_info->valid_dimm = false; + dram_info->is_16gb_dimm = false; + dram_info->rank = I915_DRAM_RANK_INVALID; + dram_info->bandwidth_kbps = 0; + dram_info->num_channels = 0; + + if (INTEL_GEN(dev_priv) < 9 || IS_GEMINILAKE(dev_priv)) + return; + + /* Need to calculate bandwidth only for Gen9 */ + if (IS_BROXTON(dev_priv)) + ret = bxt_get_dram_info(dev_priv); + else if (INTEL_GEN(dev_priv) == 9) + ret = skl_get_dram_info(dev_priv); + else + ret = skl_dram_get_channels_info(dev_priv); + if (ret) + return; + + if (dram_info->bandwidth_kbps) + sprintf(bandwidth_str, "%d KBps", dram_info->bandwidth_kbps); + else + sprintf(bandwidth_str, "unknown"); + DRM_DEBUG_KMS("DRAM bandwidth:%s, total-channels: %u\n", + bandwidth_str, dram_info->num_channels); + DRM_DEBUG_KMS("DRAM rank: %s rank 16GB-dimm:%s\n", + (dram_info->rank == I915_DRAM_RANK_DUAL) ? + "dual" : "single", yesno(dram_info->is_16gb_dimm)); +} + /** * i915_driver_init_hw - setup state requiring device access * @dev_priv: device private @@ -1184,6 +1474,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) goto err_msi; intel_opregion_setup(dev_priv); + /* + * Fill the dram structure to get the system raw bandwidth and + * dram info. This will be used for memory latency calculation. + */ + intel_get_dram_info(dev_priv); + return 0; @@ -1272,6 +1568,9 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) */ if (INTEL_INFO(dev_priv)->num_pipes) drm_kms_helper_poll_init(dev); + + intel_power_domains_enable(dev_priv); + intel_runtime_pm_enable(dev_priv); } /** @@ -1280,6 +1579,9 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) */ static void i915_driver_unregister(struct drm_i915_private *dev_priv) { + intel_runtime_pm_disable(dev_priv); + intel_power_domains_disable(dev_priv); + intel_fbdev_unregister(dev_priv); intel_audio_deinit(dev_priv); @@ -1316,6 +1618,52 @@ static void i915_welcome_messages(struct drm_i915_private *dev_priv) DRM_INFO("DRM_I915_DEBUG enabled\n"); if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) DRM_INFO("DRM_I915_DEBUG_GEM enabled\n"); + if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM)) + DRM_INFO("DRM_I915_DEBUG_RUNTIME_PM enabled\n"); +} + +static struct drm_i915_private * +i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + const struct intel_device_info *match_info = + (struct intel_device_info *)ent->driver_data; + struct intel_device_info *device_info; + struct drm_i915_private *i915; + + i915 = kzalloc(sizeof(*i915), GFP_KERNEL); + if (!i915) + return NULL; + + if (drm_dev_init(&i915->drm, &driver, &pdev->dev)) { + kfree(i915); + return NULL; + } + + i915->drm.pdev = pdev; + i915->drm.dev_private = i915; + pci_set_drvdata(pdev, &i915->drm); + + /* Setup the write-once "constant" device info */ + device_info = mkwrite_device_info(i915); + memcpy(device_info, match_info, sizeof(*device_info)); + device_info->device_id = pdev->device; + + BUILD_BUG_ON(INTEL_MAX_PLATFORMS > + sizeof(device_info->platform_mask) * BITS_PER_BYTE); + BUG_ON(device_info->gen > sizeof(device_info->gen_mask) * BITS_PER_BYTE); + + return i915; +} + +static void i915_driver_destroy(struct drm_i915_private *i915) +{ + struct pci_dev *pdev = i915->drm.pdev; + + drm_dev_fini(&i915->drm); + kfree(i915); + + /* And make sure we never chase our dangling pointer from pci_dev */ + pci_set_drvdata(pdev, NULL); } /** @@ -1336,42 +1684,23 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_i915_private *dev_priv; int ret; - /* Enable nuclear pageflip on ILK+ */ - if (!i915_modparams.nuclear_pageflip && match_info->gen < 5) - driver.driver_features &= ~DRIVER_ATOMIC; - - ret = -ENOMEM; - dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); - if (dev_priv) - ret = drm_dev_init(&dev_priv->drm, &driver, &pdev->dev); - if (ret) { - DRM_DEV_ERROR(&pdev->dev, "allocation failed\n"); - goto out_free; - } + dev_priv = i915_driver_create(pdev, ent); + if (!dev_priv) + return -ENOMEM; - dev_priv->drm.pdev = pdev; - dev_priv->drm.dev_private = dev_priv; + /* Disable nuclear pageflip by default on pre-ILK */ + if (!i915_modparams.nuclear_pageflip && match_info->gen < 5) + dev_priv->drm.driver_features &= ~DRIVER_ATOMIC; ret = pci_enable_device(pdev); if (ret) goto out_fini; - pci_set_drvdata(pdev, &dev_priv->drm); - /* - * Disable the system suspend direct complete optimization, which can - * leave the device suspended skipping the driver's suspend handlers - * if the device was already runtime suspended. This is needed due to - * the difference in our runtime and system suspend sequence and - * becaue the HDA driver may require us to enable the audio power - * domain during system suspend. - */ - dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP); - - ret = i915_driver_init_early(dev_priv, ent); + ret = i915_driver_init_early(dev_priv); if (ret < 0) goto out_pci_disable; - intel_runtime_pm_get(dev_priv); + disable_rpm_wakeref_asserts(dev_priv); ret = i915_driver_init_mmio(dev_priv); if (ret < 0) @@ -1399,11 +1728,9 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent) i915_driver_register(dev_priv); - intel_runtime_pm_enable(dev_priv); - intel_init_ipc(dev_priv); - intel_runtime_pm_put(dev_priv); + enable_rpm_wakeref_asserts(dev_priv); i915_welcome_messages(dev_priv); @@ -1414,16 +1741,13 @@ out_cleanup_hw: out_cleanup_mmio: i915_driver_cleanup_mmio(dev_priv); out_runtime_pm_put: - intel_runtime_pm_put(dev_priv); + enable_rpm_wakeref_asserts(dev_priv); i915_driver_cleanup_early(dev_priv); out_pci_disable: pci_disable_device(pdev); out_fini: i915_load_error(dev_priv, "Device initialization failed (%d)\n", ret); - drm_dev_fini(&dev_priv->drm); -out_free: - kfree(dev_priv); - pci_set_drvdata(pdev, NULL); + i915_driver_destroy(dev_priv); return ret; } @@ -1432,13 +1756,13 @@ void i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; + disable_rpm_wakeref_asserts(dev_priv); + i915_driver_unregister(dev_priv); if (i915_gem_suspend(dev_priv)) DRM_ERROR("failed to idle hardware; continuing to unload!\n"); - intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); - drm_atomic_helper_shutdown(dev); intel_gvt_cleanup(dev_priv); @@ -1459,12 +1783,14 @@ void i915_driver_unload(struct drm_device *dev) i915_gem_fini(dev_priv); intel_fbc_cleanup_cfb(dev_priv); - intel_power_domains_fini(dev_priv); + intel_power_domains_fini_hw(dev_priv); i915_driver_cleanup_hw(dev_priv); i915_driver_cleanup_mmio(dev_priv); - intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + enable_rpm_wakeref_asserts(dev_priv); + + WARN_ON(atomic_read(&dev_priv->runtime_pm.wakeref_count)); } static void i915_driver_release(struct drm_device *dev) @@ -1472,9 +1798,7 @@ static void i915_driver_release(struct drm_device *dev) struct drm_i915_private *dev_priv = to_i915(dev); i915_driver_cleanup_early(dev_priv); - drm_dev_fini(&dev_priv->drm); - - kfree(dev_priv); + i915_driver_destroy(dev_priv); } static int i915_driver_open(struct drm_device *dev, struct drm_file *file) @@ -1573,7 +1897,7 @@ static int i915_drm_suspend(struct drm_device *dev) /* We do a lot of poking in a lot of registers, make sure they work * properly. */ - intel_display_set_init_power(dev_priv, true); + intel_power_domains_disable(dev_priv); drm_kms_helper_poll_disable(dev); @@ -1610,6 +1934,18 @@ static int i915_drm_suspend(struct drm_device *dev) return 0; } +static enum i915_drm_suspend_mode +get_suspend_mode(struct drm_i915_private *dev_priv, bool hibernate) +{ + if (hibernate) + return I915_DRM_SUSPEND_HIBERNATE; + + if (suspend_to_idle(dev_priv)) + return I915_DRM_SUSPEND_IDLE; + + return I915_DRM_SUSPEND_MEM; +} + static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -1620,21 +1956,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) i915_gem_suspend_late(dev_priv); - intel_display_set_init_power(dev_priv, false); intel_uncore_suspend(dev_priv); - /* - * In case of firmware assisted context save/restore don't manually - * deinit the power domains. This also means the CSR/DMC firmware will - * stay active, it will power down any HW resources as required and - * also enable deeper system power states that would be blocked if the - * firmware was inactive. - */ - if (IS_GEN9_LP(dev_priv) || hibernation || !suspend_to_idle(dev_priv) || - dev_priv->csr.dmc_payload == NULL) { - intel_power_domains_suspend(dev_priv); - dev_priv->power_domains_suspended = true; - } + intel_power_domains_suspend(dev_priv, + get_suspend_mode(dev_priv, hibernation)); ret = 0; if (IS_GEN9_LP(dev_priv)) @@ -1646,10 +1971,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) if (ret) { DRM_ERROR("Suspend complete failed: %d\n", ret); - if (dev_priv->power_domains_suspended) { - intel_power_domains_init_hw(dev_priv, true); - dev_priv->power_domains_suspended = false; - } + intel_power_domains_resume(dev_priv); goto out; } @@ -1755,7 +2077,7 @@ static int i915_drm_resume(struct drm_device *dev) /* * ... but also need to make sure that hotplug processing * doesn't cause havoc. Like in the driver load code we don't - * bother with the tiny race here where we might loose hotplug + * bother with the tiny race here where we might lose hotplug * notifications. * */ intel_hpd_init(dev_priv); @@ -1766,6 +2088,8 @@ static int i915_drm_resume(struct drm_device *dev) intel_opregion_notify_adapter(dev_priv, PCI_D0); + intel_power_domains_enable(dev_priv); + enable_rpm_wakeref_asserts(dev_priv); return 0; @@ -1800,7 +2124,7 @@ static int i915_drm_resume_early(struct drm_device *dev) ret = pci_set_power_state(pdev, PCI_D0); if (ret) { DRM_ERROR("failed to set PCI D0 power state (%d)\n", ret); - goto out; + return ret; } /* @@ -1816,10 +2140,8 @@ static int i915_drm_resume_early(struct drm_device *dev) * depend on the device enable refcount we can't anyway depend on them * disabling/enabling the device. */ - if (pci_enable_device(pdev)) { - ret = -EIO; - goto out; - } + if (pci_enable_device(pdev)) + return -EIO; pci_set_master(pdev); @@ -1842,18 +2164,12 @@ static int i915_drm_resume_early(struct drm_device *dev) intel_uncore_sanitize(dev_priv); - if (dev_priv->power_domains_suspended) - intel_power_domains_init_hw(dev_priv, true); - else - intel_display_set_init_power(dev_priv, true); + intel_power_domains_resume(dev_priv); intel_engines_sanitize(dev_priv); enable_rpm_wakeref_asserts(dev_priv); -out: - dev_priv->power_domains_suspended = false; - return ret; } @@ -1915,7 +2231,6 @@ void i915_reset(struct drm_i915_private *i915, dev_notice(i915->drm.dev, "Resetting chip for %s\n", reason); error->reset_count++; - disable_irq(i915->drm.irq); ret = i915_gem_reset_prepare(i915); if (ret) { dev_err(i915->drm.dev, "GPU recovery failed\n"); @@ -1977,8 +2292,6 @@ void i915_reset(struct drm_i915_private *i915, finish: i915_gem_reset_finish(i915); - enable_irq(i915->drm.irq); - wakeup: clear_bit(I915_RESET_HANDOFF, &error->flags); wake_up_bit(&error->flags, I915_RESET_HANDOFF); @@ -2073,6 +2386,7 @@ int i915_reset_engine(struct intel_engine_cs *engine, const char *msg) goto out; out: + intel_engine_cancel_stop_cs(engine); i915_gem_reset_finish_engine(engine); return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4aca5344863d..8624b4bdc242 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -52,6 +52,7 @@ #include <drm/drm_gem.h> #include <drm/drm_auth.h> #include <drm/drm_cache.h> +#include <drm/drm_util.h> #include "i915_params.h" #include "i915_reg.h" @@ -86,8 +87,8 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20180719" -#define DRIVER_TIMESTAMP 1532015279 +#define DRIVER_DATE "20180921" +#define DRIVER_TIMESTAMP 1537521997 /* 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 @@ -611,8 +612,18 @@ struct i915_drrs { struct i915_psr { struct mutex lock; + +#define I915_PSR_DEBUG_MODE_MASK 0x0f +#define I915_PSR_DEBUG_DEFAULT 0x00 +#define I915_PSR_DEBUG_DISABLE 0x01 +#define I915_PSR_DEBUG_ENABLE 0x02 +#define I915_PSR_DEBUG_FORCE_PSR1 0x03 +#define I915_PSR_DEBUG_IRQ 0x10 + + u32 debug; bool sink_support; - struct intel_dp *enabled; + bool prepared, enabled; + struct intel_dp *dp; bool active; struct work_struct work; unsigned busy_frontbuffer_bits; @@ -622,7 +633,6 @@ struct i915_psr { bool alpm; bool psr2_enabled; u8 sink_sync_latency; - bool debug; ktime_t last_entry_attempt; ktime_t last_exit; }; @@ -867,14 +877,17 @@ struct i915_power_well_ops { struct i915_power_well *power_well); }; +struct i915_power_well_regs { + i915_reg_t bios; + i915_reg_t driver; + i915_reg_t kvmr; + i915_reg_t debug; +}; + /* Power well structure for haswell */ -struct i915_power_well { +struct i915_power_well_desc { const char *name; bool always_on; - /* power well enable/disable usage count */ - int count; - /* cached hw enabled state */ - bool hw_enabled; u64 domains; /* unique identifier for this power well */ enum i915_power_well_id id; @@ -884,9 +897,22 @@ struct i915_power_well { */ union { struct { + /* + * request/status flag index in the PUNIT power well + * control/status registers. + */ + u8 idx; + } vlv; + struct { enum dpio_phy phy; } bxt; struct { + const struct i915_power_well_regs *regs; + /* + * request/status flag index in the power well + * constrol/status registers. + */ + u8 idx; /* Mask of pipes whose IRQ logic is backed by the pw */ u8 irq_pipe_mask; /* The pw is backing the VGA functionality */ @@ -897,13 +923,21 @@ struct i915_power_well { const struct i915_power_well_ops *ops; }; +struct i915_power_well { + const struct i915_power_well_desc *desc; + /* power well enable/disable usage count */ + int count; + /* cached hw enabled state */ + bool hw_enabled; +}; + struct i915_power_domains { /* * Power wells needed for initialization at driver init and suspend * time are on. They are kept on until after the first modeset. */ - bool init_power_on; bool initializing; + bool display_core_suspended; int power_well_count; struct mutex lock; @@ -1610,7 +1644,8 @@ struct drm_i915_private { struct mutex gmbus_mutex; /** - * Base address of the gmbus and gpio block. + * Base address of where the gmbus and gpio blocks are located (either + * on PCH or on SoC for platforms without PCH). */ uint32_t gpio_mmio_base; @@ -1632,7 +1667,6 @@ struct drm_i915_private { struct intel_engine_cs *engine_class[MAX_ENGINE_CLASS + 1] [MAX_ENGINE_INSTANCE + 1]; - struct drm_dma_handle *status_page_dmah; struct resource mch_res; /* protects the irq masks */ @@ -1828,6 +1862,7 @@ struct drm_i915_private { struct mutex av_mutex; struct { + struct mutex mutex; struct list_head list; struct llist_head free_list; struct work_struct free_work; @@ -1840,6 +1875,7 @@ struct drm_i915_private { #define MAX_CONTEXT_HW_ID (1<<21) /* exclusive */ #define MAX_GUC_CONTEXT_HW_ID (1 << 20) /* exclusive */ #define GEN11_MAX_CONTEXT_HW_ID (1<<11) /* exclusive */ + struct list_head hw_id_list; } contexts; u32 fdi_rx_config; @@ -1910,6 +1946,20 @@ struct drm_i915_private { bool distrust_bios_wm; } wm; + struct dram_info { + bool valid; + bool valid_dimm; + bool is_16gb_dimm; + u8 num_channels; + enum dram_rank { + I915_DRAM_RANK_INVALID = 0, + I915_DRAM_RANK_SINGLE, + I915_DRAM_RANK_DUAL + } rank; + u32 bandwidth_kbps; + bool symmetric_memory; + } dram_info; + struct i915_runtime_pm runtime_pm; struct { @@ -2123,6 +2173,15 @@ struct drm_i915_private { */ }; +struct dram_channel_info { + struct info { + u8 size, width; + enum dram_rank rank; + } l_info, s_info; + enum dram_rank rank; + bool is_16gb_dimm; +}; + static inline struct drm_i915_private *to_i915(const struct drm_device *dev) { return container_of(dev, struct drm_i915_private, drm); @@ -2248,7 +2307,7 @@ static inline struct scatterlist *__sg_next(struct scatterlist *sg) #define for_each_sgt_dma(__dmap, __iter, __sgt) \ for ((__iter) = __sgt_iter((__sgt)->sgl, true); \ ((__dmap) = (__iter).dma + (__iter).curr); \ - (((__iter).curr += PAGE_SIZE) >= (__iter).max) ? \ + (((__iter).curr += I915_GTT_PAGE_SIZE) >= (__iter).max) ? \ (__iter) = __sgt_iter(__sg_next((__iter).sgp), true), 0 : 0) /** @@ -2610,8 +2669,6 @@ intel_info(const struct drm_i915_private *dev_priv) #define USES_GUC_SUBMISSION(dev_priv) intel_uc_is_using_guc_submission() #define USES_HUC(dev_priv) intel_uc_is_using_huc() -#define HAS_RESOURCE_STREAMER(dev_priv) ((dev_priv)->info.has_resource_streamer) - #define HAS_POOLED_EU(dev_priv) ((dev_priv)->info.has_pooled_eu) #define INTEL_PCH_DEVICE_ID_MASK 0xff80 @@ -2775,6 +2832,8 @@ extern void intel_irq_fini(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); void intel_irq_uninstall(struct drm_i915_private *dev_priv); +void i915_clear_error_registers(struct drm_i915_private *dev_priv); + static inline bool intel_gvt_active(struct drm_i915_private *dev_priv) { return dev_priv->gvt; @@ -3038,6 +3097,12 @@ enum i915_map_type { I915_MAP_FORCE_WC = I915_MAP_WC | I915_MAP_OVERRIDE, }; +static inline enum i915_map_type +i915_coherent_map_type(struct drm_i915_private *i915) +{ + return HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC; +} + /** * i915_gem_object_pin_map - return a contiguous mapping of the entire object * @obj: the object to map into kernel address space @@ -3275,7 +3340,7 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv, void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node); int i915_gem_init_stolen(struct drm_i915_private *dev_priv); -void i915_gem_cleanup_stolen(struct drm_device *dev); +void i915_gem_cleanup_stolen(struct drm_i915_private *dev_priv); struct drm_i915_gem_object * i915_gem_object_create_stolen(struct drm_i915_private *dev_priv, resource_size_t size); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 316730b45f84..0c8aa57ce83b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -802,6 +802,11 @@ void i915_gem_flush_ggtt_writes(struct drm_i915_private *dev_priv) * that was!). */ + wmb(); + + if (INTEL_INFO(dev_priv)->has_coherent_ggtt) + return; + i915_gem_chipset_flush(dev_priv); intel_runtime_pm_get(dev_priv); @@ -1122,11 +1127,7 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, offset = offset_in_page(args->offset); for (idx = args->offset >> PAGE_SHIFT; remain; idx++) { struct page *page = i915_gem_object_get_page(obj, idx); - int length; - - length = remain; - if (offset + length > PAGE_SIZE) - length = PAGE_SIZE - offset; + unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); ret = shmem_pread(page, offset, length, user_data, page_to_phys(page) & obj_do_bit17_swizzling, @@ -1570,11 +1571,7 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, offset = offset_in_page(args->offset); for (idx = args->offset >> PAGE_SHIFT; remain; idx++) { struct page *page = i915_gem_object_get_page(obj, idx); - int length; - - length = remain; - if (offset + length > PAGE_SIZE) - length = PAGE_SIZE - offset; + unsigned int length = min_t(u64, remain, PAGE_SIZE - offset); ret = shmem_pwrite(page, offset, length, user_data, page_to_phys(page) & obj_do_bit17_swizzling, @@ -1906,7 +1903,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, return 0; } -static unsigned int tile_row_pages(struct drm_i915_gem_object *obj) +static unsigned int tile_row_pages(const struct drm_i915_gem_object *obj) { return i915_gem_object_get_tile_row_size(obj) >> PAGE_SHIFT; } @@ -1965,7 +1962,7 @@ int i915_gem_mmap_gtt_version(void) } static inline struct i915_ggtt_view -compute_partial_view(struct drm_i915_gem_object *obj, +compute_partial_view(const struct drm_i915_gem_object *obj, pgoff_t page_offset, unsigned int chunk) { @@ -2013,7 +2010,7 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf) struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct i915_ggtt *ggtt = &dev_priv->ggtt; - bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + bool write = area->vm_flags & VM_WRITE; struct i915_vma *vma; pgoff_t page_offset; int ret; @@ -2501,7 +2498,9 @@ static bool i915_sg_trim(struct sg_table *orig_st) new_sg = new_st.sgl; for_each_sg(orig_st->sgl, sg, orig_st->nents, i) { sg_set_page(new_sg, sg_page(sg), sg->length, 0); - /* called before being DMA mapped, no need to copy sg->dma_* */ + sg_dma_address(new_sg) = sg_dma_address(sg); + sg_dma_len(new_sg) = sg_dma_len(sg); + new_sg = sg_next(new_sg); } GEM_BUG_ON(new_sg); /* Should walk exactly nents and hit the end */ @@ -2528,13 +2527,21 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) gfp_t noreclaim; int ret; - /* Assert that the object is not currently in any GPU domain. As it + /* + * Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache */ GEM_BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); GEM_BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); + /* + * If there's no chance of allocating enough pages for the whole + * object, bail early. + */ + if (page_count > totalram_pages) + return -ENOMEM; + st = kmalloc(sizeof(*st), GFP_KERNEL); if (st == NULL) return -ENOMEM; @@ -2545,7 +2552,8 @@ rebuild_st: return -ENOMEM; } - /* Get the list of pages out of our struct file. They'll be pinned + /* + * Get the list of pages out of our struct file. They'll be pinned * at this point until we release them. * * Fail silently without starting the shrinker @@ -2577,7 +2585,8 @@ rebuild_st: i915_gem_shrink(dev_priv, 2 * page_count, NULL, *s++); cond_resched(); - /* We've tried hard to allocate the memory by reaping + /* + * We've tried hard to allocate the memory by reaping * our own buffer, now let the real VM do its job and * go down in flames if truly OOM. * @@ -2589,7 +2598,8 @@ rebuild_st: /* reclaim and warn, but no oom */ gfp = mapping_gfp_mask(mapping); - /* Our bo are always dirty and so we require + /* + * Our bo are always dirty and so we require * kswapd to reclaim our pages (direct reclaim * does not effectively begin pageout of our * buffers on its own). However, direct reclaim @@ -2633,7 +2643,8 @@ rebuild_st: ret = i915_gem_gtt_prepare_pages(obj, st); if (ret) { - /* DMA remapping failed? One possible cause is that + /* + * DMA remapping failed? One possible cause is that * it could not reserve enough large entries, asking * for PAGE_SIZE chunks instead may be helpful. */ @@ -2667,7 +2678,8 @@ err_pages: sg_free_table(st); kfree(st); - /* shmemfs first checks if there is enough memory to allocate the page + /* + * shmemfs first checks if there is enough memory to allocate the page * and reports ENOSPC should there be insufficient, along with the usual * ENOMEM for a genuine allocation failure. * @@ -3307,8 +3319,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) intel_engine_dump(engine, &p, "%s\n", engine->name); } - set_bit(I915_WEDGED, &i915->gpu_error.flags); - smp_mb__after_atomic(); + if (test_and_set_bit(I915_WEDGED, &i915->gpu_error.flags)) + goto out; /* * First, stop submission to hw, but do not yet complete requests by @@ -3324,7 +3336,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) i915->caps.scheduler = 0; /* Even if the GPU reset fails, it should still stop the engines */ - intel_gpu_reset(i915, ALL_ENGINES); + if (INTEL_GEN(i915) >= 5) + intel_gpu_reset(i915, ALL_ENGINES); /* * Make sure no one is running the old callback before we proceed with @@ -3367,6 +3380,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915) i915_gem_reset_finish_engine(engine); } +out: GEM_TRACE("end\n"); wake_up_all(&i915->gpu_error.reset_queue); @@ -3418,6 +3432,9 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915) i915_retire_requests(i915); GEM_BUG_ON(i915->gt.active_requests); + if (!intel_gpu_reset(i915, ALL_ENGINES)) + intel_engines_sanitize(i915); + /* * Undo nop_submit_request. We prevent all new i915 requests from * being queued (by disallowing execbuf whilst wedged) so having @@ -3816,6 +3833,12 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, if (timeout < 0) return timeout; } + if (GEM_SHOW_DEBUG() && !timeout) { + /* Presume that timeout was non-zero to begin with! */ + dev_warn(&i915->drm.pdev->dev, + "Missed idle-completion interrupt!\n"); + GEM_TRACE_DUMP(); + } err = wait_for_engines(i915); if (err) @@ -5388,8 +5411,19 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) assert_kernel_context_is_current(i915); + /* + * Immediately park the GPU so that we enable powersaving and + * treat it as idle. The next time we issue a request, we will + * unpark and start using the engine->pinned_default_state, otherwise + * it is in limbo and an early reset may fail. + */ + __i915_gem_park(i915); + for_each_engine(engine, i915, id) { struct i915_vma *state; + void *vaddr; + + GEM_BUG_ON(to_intel_context(ctx, engine)->pin_count); state = to_intel_context(ctx, engine)->state; if (!state) @@ -5412,6 +5446,16 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915) goto err_active; engine->default_state = i915_gem_object_get(state->obj); + + /* Check we can acquire the image of the context state */ + vaddr = i915_gem_object_pin_map(engine->default_state, + I915_MAP_FORCE_WB); + if (IS_ERR(vaddr)) { + err = PTR_ERR(vaddr); + goto err_active; + } + + i915_gem_object_unpin_map(engine->default_state); } if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) { @@ -5592,6 +5636,8 @@ err_uc_misc: i915_gem_cleanup_userptr(dev_priv); if (ret == -EIO) { + mutex_lock(&dev_priv->drm.struct_mutex); + /* * Allow engine initialisation to fail by marking the GPU as * wedged. But we only want to do this where the GPU is angry, @@ -5602,7 +5648,14 @@ err_uc_misc: "Failed to initialize GPU, declaring it wedged!\n"); i915_gem_set_wedged(dev_priv); } - ret = 0; + + /* Minimal basic recovery for KMS */ + ret = i915_ggtt_enable_hw(dev_priv); + i915_gem_restore_gtt_mappings(dev_priv); + i915_gem_restore_fences(dev_priv); + intel_init_clock_gating(dev_priv); + + mutex_unlock(&dev_priv->drm.struct_mutex); } i915_gem_drain_freed_objects(dev_priv); @@ -5612,6 +5665,7 @@ err_uc_misc: void i915_gem_fini(struct drm_i915_private *dev_priv) { i915_gem_suspend_late(dev_priv); + intel_disable_gt_powersave(dev_priv); /* Flush any outstanding unpin_work. */ i915_gem_drain_workqueue(dev_priv); @@ -5623,6 +5677,8 @@ void i915_gem_fini(struct drm_i915_private *dev_priv) i915_gem_contexts_fini(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); + intel_cleanup_gt_powersave(dev_priv); + intel_uc_fini_misc(dev_priv); i915_gem_cleanup_userptr(dev_priv); @@ -6179,4 +6235,5 @@ err_unlock: #include "selftests/huge_pages.c" #include "selftests/i915_gem_object.c" #include "selftests/i915_gem_coherency.c" +#include "selftests/i915_gem.c" #endif diff --git a/drivers/gpu/drm/i915/i915_gem.h b/drivers/gpu/drm/i915/i915_gem.h index e46592956872..599c4f6eb1ea 100644 --- a/drivers/gpu/drm/i915/i915_gem.h +++ b/drivers/gpu/drm/i915/i915_gem.h @@ -82,12 +82,6 @@ static inline void __tasklet_disable_sync_once(struct tasklet_struct *t) tasklet_unlock_wait(t); } -static inline void __tasklet_enable_sync_once(struct tasklet_struct *t) -{ - if (atomic_dec_return(&t->count) == 0) - tasklet_kill(t); -} - static inline bool __tasklet_is_enabled(const struct tasklet_struct *t) { return !atomic_read(&t->count); diff --git a/drivers/gpu/drm/i915/i915_gem_clflush.c b/drivers/gpu/drm/i915/i915_gem_clflush.c index f5c570d35b2a..8e74c23cbd91 100644 --- a/drivers/gpu/drm/i915/i915_gem_clflush.c +++ b/drivers/gpu/drm/i915/i915_gem_clflush.c @@ -45,11 +45,6 @@ static const char *i915_clflush_get_timeline_name(struct dma_fence *fence) return "clflush"; } -static bool i915_clflush_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static void i915_clflush_release(struct dma_fence *fence) { struct clflush *clflush = container_of(fence, typeof(*clflush), dma); @@ -63,8 +58,6 @@ static void i915_clflush_release(struct dma_fence *fence) static const struct dma_fence_ops i915_clflush_ops = { .get_driver_name = i915_clflush_get_driver_name, .get_timeline_name = i915_clflush_get_timeline_name, - .enable_signaling = i915_clflush_enable_signaling, - .wait = dma_fence_default_wait, .release = i915_clflush_release, }; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index b10770cfccd2..f772593b99ab 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -115,6 +115,95 @@ static void lut_close(struct i915_gem_context *ctx) rcu_read_unlock(); } +static inline int new_hw_id(struct drm_i915_private *i915, gfp_t gfp) +{ + unsigned int max; + + lockdep_assert_held(&i915->contexts.mutex); + + if (INTEL_GEN(i915) >= 11) + max = GEN11_MAX_CONTEXT_HW_ID; + else if (USES_GUC_SUBMISSION(i915)) + /* + * When using GuC in proxy submission, GuC consumes the + * highest bit in the context id to indicate proxy submission. + */ + max = MAX_GUC_CONTEXT_HW_ID; + else + max = MAX_CONTEXT_HW_ID; + + return ida_simple_get(&i915->contexts.hw_ida, 0, max, gfp); +} + +static int steal_hw_id(struct drm_i915_private *i915) +{ + struct i915_gem_context *ctx, *cn; + LIST_HEAD(pinned); + int id = -ENOSPC; + + lockdep_assert_held(&i915->contexts.mutex); + + list_for_each_entry_safe(ctx, cn, + &i915->contexts.hw_id_list, hw_id_link) { + if (atomic_read(&ctx->hw_id_pin_count)) { + list_move_tail(&ctx->hw_id_link, &pinned); + continue; + } + + GEM_BUG_ON(!ctx->hw_id); /* perma-pinned kernel context */ + list_del_init(&ctx->hw_id_link); + id = ctx->hw_id; + break; + } + + /* + * Remember how far we got up on the last repossesion scan, so the + * list is kept in a "least recently scanned" order. + */ + list_splice_tail(&pinned, &i915->contexts.hw_id_list); + return id; +} + +static int assign_hw_id(struct drm_i915_private *i915, unsigned int *out) +{ + int ret; + + lockdep_assert_held(&i915->contexts.mutex); + + /* + * We prefer to steal/stall ourselves and our users over that of the + * entire system. That may be a little unfair to our users, and + * even hurt high priority clients. The choice is whether to oomkill + * something else, or steal a context id. + */ + ret = new_hw_id(i915, GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); + if (unlikely(ret < 0)) { + ret = steal_hw_id(i915); + if (ret < 0) /* once again for the correct errno code */ + ret = new_hw_id(i915, GFP_KERNEL); + if (ret < 0) + return ret; + } + + *out = ret; + return 0; +} + +static void release_hw_id(struct i915_gem_context *ctx) +{ + struct drm_i915_private *i915 = ctx->i915; + + if (list_empty(&ctx->hw_id_link)) + return; + + mutex_lock(&i915->contexts.mutex); + if (!list_empty(&ctx->hw_id_link)) { + ida_simple_remove(&i915->contexts.hw_ida, ctx->hw_id); + list_del_init(&ctx->hw_id_link); + } + mutex_unlock(&i915->contexts.mutex); +} + static void i915_gem_context_free(struct i915_gem_context *ctx) { unsigned int n; @@ -122,6 +211,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) lockdep_assert_held(&ctx->i915->drm.struct_mutex); GEM_BUG_ON(!i915_gem_context_is_closed(ctx)); + release_hw_id(ctx); i915_ppgtt_put(ctx->ppgtt); for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { @@ -136,7 +226,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) list_del(&ctx->link); - ida_simple_remove(&ctx->i915->contexts.hw_ida, ctx->hw_id); kfree_rcu(ctx, rcu); } @@ -191,6 +280,12 @@ static void context_close(struct i915_gem_context *ctx) i915_gem_context_set_closed(ctx); /* + * This context will never again be assinged to HW, so we can + * reuse its ID for the next context. + */ + release_hw_id(ctx); + + /* * The LUT uses the VMA as a backpointer to unref the object, * so we need to clear the LUT before we close all the VMA (inside * the ppgtt). @@ -203,43 +298,6 @@ static void context_close(struct i915_gem_context *ctx) i915_gem_context_put(ctx); } -static int assign_hw_id(struct drm_i915_private *dev_priv, unsigned *out) -{ - int ret; - unsigned int max; - - if (INTEL_GEN(dev_priv) >= 11) { - max = GEN11_MAX_CONTEXT_HW_ID; - } else { - /* - * When using GuC in proxy submission, GuC consumes the - * highest bit in the context id to indicate proxy submission. - */ - if (USES_GUC_SUBMISSION(dev_priv)) - max = MAX_GUC_CONTEXT_HW_ID; - else - max = MAX_CONTEXT_HW_ID; - } - - - ret = ida_simple_get(&dev_priv->contexts.hw_ida, - 0, max, GFP_KERNEL); - if (ret < 0) { - /* Contexts are only released when no longer active. - * Flush any pending retires to hopefully release some - * stale contexts and try again. - */ - i915_retire_requests(dev_priv); - ret = ida_simple_get(&dev_priv->contexts.hw_ida, - 0, max, GFP_KERNEL); - if (ret < 0) - return ret; - } - - *out = ret; - return 0; -} - static u32 default_desc_template(const struct drm_i915_private *i915, const struct i915_hw_ppgtt *ppgtt) { @@ -276,12 +334,6 @@ __create_hw_context(struct drm_i915_private *dev_priv, if (ctx == NULL) return ERR_PTR(-ENOMEM); - ret = assign_hw_id(dev_priv, &ctx->hw_id); - if (ret) { - kfree(ctx); - return ERR_PTR(ret); - } - kref_init(&ctx->ref); list_add_tail(&ctx->link, &dev_priv->contexts.list); ctx->i915 = dev_priv; @@ -295,6 +347,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); + INIT_LIST_HEAD(&ctx->hw_id_link); /* Default context will never have a file_priv */ ret = DEFAULT_CONTEXT_HANDLE; @@ -329,16 +382,6 @@ __create_hw_context(struct drm_i915_private *dev_priv, ctx->desc_template = default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt); - /* - * GuC requires the ring to be placed in Non-WOPCM memory. If GuC is not - * present or not in use we still need a small bias as ring wraparound - * at offset 0 sometimes hangs. No idea why. - */ - if (USES_GUC(dev_priv)) - ctx->ggtt_offset_bias = dev_priv->guc.ggtt_pin_bias; - else - ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE; - return ctx; err_pid: @@ -431,15 +474,35 @@ out: return ctx; } +static void +destroy_kernel_context(struct i915_gem_context **ctxp) +{ + struct i915_gem_context *ctx; + + /* Keep the context ref so that we can free it immediately ourselves */ + ctx = i915_gem_context_get(fetch_and_zero(ctxp)); + GEM_BUG_ON(!i915_gem_context_is_kernel(ctx)); + + context_close(ctx); + i915_gem_context_free(ctx); +} + struct i915_gem_context * i915_gem_context_create_kernel(struct drm_i915_private *i915, int prio) { struct i915_gem_context *ctx; + int err; ctx = i915_gem_create_context(i915, NULL); if (IS_ERR(ctx)) return ctx; + err = i915_gem_context_pin_hw_id(ctx); + if (err) { + destroy_kernel_context(&ctx); + return ERR_PTR(err); + } + i915_gem_context_clear_bannable(ctx); ctx->sched.priority = prio; ctx->ring_size = PAGE_SIZE; @@ -449,17 +512,19 @@ i915_gem_context_create_kernel(struct drm_i915_private *i915, int prio) return ctx; } -static void -destroy_kernel_context(struct i915_gem_context **ctxp) +static void init_contexts(struct drm_i915_private *i915) { - struct i915_gem_context *ctx; + mutex_init(&i915->contexts.mutex); + INIT_LIST_HEAD(&i915->contexts.list); - /* Keep the context ref so that we can free it immediately ourselves */ - ctx = i915_gem_context_get(fetch_and_zero(ctxp)); - GEM_BUG_ON(!i915_gem_context_is_kernel(ctx)); + /* Using the simple ida interface, the max is limited by sizeof(int) */ + BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX); + BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > INT_MAX); + ida_init(&i915->contexts.hw_ida); + INIT_LIST_HEAD(&i915->contexts.hw_id_list); - context_close(ctx); - i915_gem_context_free(ctx); + INIT_WORK(&i915->contexts.free_work, contexts_free_worker); + init_llist_head(&i915->contexts.free_list); } static bool needs_preempt_context(struct drm_i915_private *i915) @@ -480,14 +545,7 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv) if (ret) return ret; - INIT_LIST_HEAD(&dev_priv->contexts.list); - INIT_WORK(&dev_priv->contexts.free_work, contexts_free_worker); - init_llist_head(&dev_priv->contexts.free_list); - - /* Using the simple ida interface, the max is limited by sizeof(int) */ - BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX); - BUILD_BUG_ON(GEN11_MAX_CONTEXT_HW_ID > INT_MAX); - ida_init(&dev_priv->contexts.hw_ida); + init_contexts(dev_priv); /* lowest priority; idle task */ ctx = i915_gem_context_create_kernel(dev_priv, I915_PRIORITY_MIN); @@ -497,9 +555,13 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv) } /* * For easy recognisablity, we want the kernel context to be 0 and then - * all user contexts will have non-zero hw_id. + * all user contexts will have non-zero hw_id. Kernel contexts are + * permanently pinned, so that we never suffer a stall and can + * use them from any allocation context (e.g. for evicting other + * contexts and from inside the shrinker). */ GEM_BUG_ON(ctx->hw_id); + GEM_BUG_ON(!atomic_read(&ctx->hw_id_pin_count)); dev_priv->kernel_context = ctx; /* highest priority; preempting task */ @@ -537,6 +599,7 @@ void i915_gem_contexts_fini(struct drm_i915_private *i915) destroy_kernel_context(&i915->kernel_context); /* Must free all deferred contexts (via flush_workqueue) first */ + GEM_BUG_ON(!list_empty(&i915->contexts.hw_id_list)); ida_destroy(&i915->contexts.hw_ida); } @@ -799,7 +862,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; break; case I915_CONTEXT_PARAM_NO_ZEROMAP: - args->value = ctx->flags & CONTEXT_NO_ZEROMAP; + args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags); break; case I915_CONTEXT_PARAM_GTT_SIZE: if (ctx->ppgtt) @@ -833,27 +896,23 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, struct drm_i915_file_private *file_priv = file->driver_priv; struct drm_i915_gem_context_param *args = data; struct i915_gem_context *ctx; - int ret; + int ret = 0; ctx = i915_gem_context_lookup(file_priv, args->ctx_id); if (!ctx) return -ENOENT; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto out; - switch (args->param) { case I915_CONTEXT_PARAM_BAN_PERIOD: ret = -EINVAL; break; case I915_CONTEXT_PARAM_NO_ZEROMAP: - if (args->size) { + if (args->size) ret = -EINVAL; - } else { - ctx->flags &= ~CONTEXT_NO_ZEROMAP; - ctx->flags |= args->value ? CONTEXT_NO_ZEROMAP : 0; - } + else if (args->value) + set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags); + else + clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags); break; case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE: if (args->size) @@ -897,9 +956,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; break; } - mutex_unlock(&dev->struct_mutex); -out: i915_gem_context_put(ctx); return ret; } @@ -942,6 +999,33 @@ out: return ret; } +int __i915_gem_context_pin_hw_id(struct i915_gem_context *ctx) +{ + struct drm_i915_private *i915 = ctx->i915; + int err = 0; + + mutex_lock(&i915->contexts.mutex); + + GEM_BUG_ON(i915_gem_context_is_closed(ctx)); + + if (list_empty(&ctx->hw_id_link)) { + GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count)); + + err = assign_hw_id(i915, &ctx->hw_id); + if (err) + goto out_unlock; + + list_add_tail(&ctx->hw_id_link, &i915->contexts.hw_id_list); + } + + GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count) == ~0u); + atomic_inc(&ctx->hw_id_pin_count); + +out_unlock: + mutex_unlock(&i915->contexts.mutex); + return err; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/mock_context.c" #include "selftests/i915_gem_context.c" diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index b116e4942c10..08165f6a0a84 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -117,15 +117,20 @@ struct i915_gem_context { struct rcu_head rcu; /** + * @user_flags: small set of booleans controlled by the user + */ + unsigned long user_flags; +#define UCONTEXT_NO_ZEROMAP 0 +#define UCONTEXT_NO_ERROR_CAPTURE 1 +#define UCONTEXT_BANNABLE 2 + + /** * @flags: small set of booleans */ unsigned long flags; -#define CONTEXT_NO_ZEROMAP BIT(0) -#define CONTEXT_NO_ERROR_CAPTURE 1 -#define CONTEXT_CLOSED 2 -#define CONTEXT_BANNABLE 3 -#define CONTEXT_BANNED 4 -#define CONTEXT_FORCE_SINGLE_SUBMISSION 5 +#define CONTEXT_BANNED 0 +#define CONTEXT_CLOSED 1 +#define CONTEXT_FORCE_SINGLE_SUBMISSION 2 /** * @hw_id: - unique identifier for the context @@ -134,8 +139,16 @@ struct i915_gem_context { * functions like fault reporting, PASID, scheduling. The * &drm_i915_private.context_hw_ida is used to assign a unqiue * id for the lifetime of the context. + * + * @hw_id_pin_count: - number of times this context had been pinned + * for use (should be, at most, once per engine). + * + * @hw_id_link: - all contexts with an assigned id are tracked + * for possible repossession. */ unsigned int hw_id; + atomic_t hw_id_pin_count; + struct list_head hw_id_link; /** * @user_handle: userspace identifier @@ -147,9 +160,6 @@ struct i915_gem_context { struct i915_sched_attr sched; - /** ggtt_offset_bias: placement restriction for context objects */ - u32 ggtt_offset_bias; - /** engine: per-engine logical HW state */ struct intel_context { struct i915_gem_context *gem_context; @@ -204,37 +214,37 @@ static inline bool i915_gem_context_is_closed(const struct i915_gem_context *ctx static inline void i915_gem_context_set_closed(struct i915_gem_context *ctx) { GEM_BUG_ON(i915_gem_context_is_closed(ctx)); - __set_bit(CONTEXT_CLOSED, &ctx->flags); + set_bit(CONTEXT_CLOSED, &ctx->flags); } static inline bool i915_gem_context_no_error_capture(const struct i915_gem_context *ctx) { - return test_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags); + return test_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags); } static inline void i915_gem_context_set_no_error_capture(struct i915_gem_context *ctx) { - __set_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags); + set_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags); } static inline void i915_gem_context_clear_no_error_capture(struct i915_gem_context *ctx) { - __clear_bit(CONTEXT_NO_ERROR_CAPTURE, &ctx->flags); + clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &ctx->user_flags); } static inline bool i915_gem_context_is_bannable(const struct i915_gem_context *ctx) { - return test_bit(CONTEXT_BANNABLE, &ctx->flags); + return test_bit(UCONTEXT_BANNABLE, &ctx->user_flags); } static inline void i915_gem_context_set_bannable(struct i915_gem_context *ctx) { - __set_bit(CONTEXT_BANNABLE, &ctx->flags); + set_bit(UCONTEXT_BANNABLE, &ctx->user_flags); } static inline void i915_gem_context_clear_bannable(struct i915_gem_context *ctx) { - __clear_bit(CONTEXT_BANNABLE, &ctx->flags); + clear_bit(UCONTEXT_BANNABLE, &ctx->user_flags); } static inline bool i915_gem_context_is_banned(const struct i915_gem_context *ctx) @@ -244,7 +254,7 @@ static inline bool i915_gem_context_is_banned(const struct i915_gem_context *ctx static inline void i915_gem_context_set_banned(struct i915_gem_context *ctx) { - __set_bit(CONTEXT_BANNED, &ctx->flags); + set_bit(CONTEXT_BANNED, &ctx->flags); } static inline bool i915_gem_context_force_single_submission(const struct i915_gem_context *ctx) @@ -257,6 +267,21 @@ static inline void i915_gem_context_set_force_single_submission(struct i915_gem_ __set_bit(CONTEXT_FORCE_SINGLE_SUBMISSION, &ctx->flags); } +int __i915_gem_context_pin_hw_id(struct i915_gem_context *ctx); +static inline int i915_gem_context_pin_hw_id(struct i915_gem_context *ctx) +{ + if (atomic_inc_not_zero(&ctx->hw_id_pin_count)) + return 0; + + return __i915_gem_context_pin_hw_id(ctx); +} + +static inline void i915_gem_context_unpin_hw_id(struct i915_gem_context *ctx) +{ + GEM_BUG_ON(atomic_read(&ctx->hw_id_pin_count) == 0u); + atomic_dec(&ctx->hw_id_pin_count); +} + static inline bool i915_gem_context_is_default(const struct i915_gem_context *c) { return c->user_handle == DEFAULT_CONTEXT_HANDLE; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3f0c612d42e7..09187286d346 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -64,7 +64,9 @@ enum { #define BATCH_OFFSET_BIAS (256*1024) #define __I915_EXEC_ILLEGAL_FLAGS \ - (__I915_EXEC_UNKNOWN_FLAGS | I915_EXEC_CONSTANTS_MASK) + (__I915_EXEC_UNKNOWN_FLAGS | \ + I915_EXEC_CONSTANTS_MASK | \ + I915_EXEC_RESOURCE_STREAMER) /* Catch emission of unexpected errors for CI! */ #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) @@ -691,9 +693,14 @@ static int eb_reserve(struct i915_execbuffer *eb) eb_unreserve_vma(vma, &eb->flags[i]); if (flags & EXEC_OBJECT_PINNED) + /* Pinned must have their slot */ list_add(&vma->exec_link, &eb->unbound); else if (flags & __EXEC_OBJECT_NEEDS_MAP) + /* Map require the lowest 256MiB (aperture) */ list_add_tail(&vma->exec_link, &eb->unbound); + else if (!(flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS)) + /* Prioritise 4GiB region for restricted bo */ + list_add(&vma->exec_link, &last); else list_add_tail(&vma->exec_link, &last); } @@ -733,10 +740,15 @@ static int eb_select_context(struct i915_execbuffer *eb) return -ENOENT; eb->ctx = ctx; - eb->vm = ctx->ppgtt ? &ctx->ppgtt->vm : &eb->i915->ggtt.vm; + if (ctx->ppgtt) { + eb->vm = &ctx->ppgtt->vm; + eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT; + } else { + eb->vm = &eb->i915->ggtt.vm; + } eb->context_flags = 0; - if (ctx->flags & CONTEXT_NO_ZEROMAP) + if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags)) eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS; return 0; @@ -1120,6 +1132,13 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, u32 *cmd; int err; + if (DBG_FORCE_RELOC == FORCE_GPU_RELOC) { + obj = vma->obj; + if (obj->cache_dirty & ~obj->cache_coherent) + i915_gem_clflush_object(obj, 0); + obj->write_domain = 0; + } + GEM_BUG_ON(vma->obj->write_domain & I915_GEM_DOMAIN_CPU); obj = i915_gem_batch_pool_get(&eb->engine->batch_pool, PAGE_SIZE); @@ -1484,8 +1503,10 @@ static int eb_relocate_vma(struct i915_execbuffer *eb, struct i915_vma *vma) * can read from this userspace address. */ offset = gen8_canonical_addr(offset & ~UPDATE); - __put_user(offset, - &urelocs[r-stack].presumed_offset); + if (unlikely(__put_user(offset, &urelocs[r-stack].presumed_offset))) { + remain = -EFAULT; + goto out; + } } } while (r++, --count); urelocs += ARRAY_SIZE(stack); @@ -1570,7 +1591,6 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb) relocs = kvmalloc_array(size, 1, GFP_KERNEL); if (!relocs) { - kvfree(relocs); err = -ENOMEM; goto err; } @@ -1584,6 +1604,7 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb) if (__copy_from_user((char *)relocs + copied, (char __user *)urelocs + copied, len)) { +end_user: kvfree(relocs); err = -EFAULT; goto err; @@ -1607,7 +1628,6 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb) unsafe_put_user(-1, &urelocs[copied].presumed_offset, end_user); -end_user: user_access_end(); eb->exec[i].relocs_ptr = (uintptr_t)relocs; @@ -2166,7 +2186,7 @@ signal_fence_array(struct i915_execbuffer *eb, if (!(flags & I915_EXEC_FENCE_SIGNAL)) continue; - drm_syncobj_replace_fence(syncobj, fence); + drm_syncobj_replace_fence(syncobj, 0, fence); } } @@ -2199,8 +2219,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.flags = (unsigned int *)(eb.vma + args->buffer_count + 1); eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; - if (USES_FULL_PPGTT(eb.i915)) - eb.invalid_flags |= EXEC_OBJECT_NEEDS_GTT; reloc_cache_init(&eb.reloc_cache, eb.i915); eb.buffer_count = args->buffer_count; @@ -2221,20 +2239,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, if (!eb.engine) return -EINVAL; - if (args->flags & I915_EXEC_RESOURCE_STREAMER) { - if (!HAS_RESOURCE_STREAMER(eb.i915)) { - DRM_DEBUG("RS is only allowed for Haswell, Gen8 and above\n"); - return -EINVAL; - } - if (eb.engine->id != RCS) { - DRM_DEBUG("RS is not available on %s\n", - eb.engine->name); - return -EINVAL; - } - - eb.batch_flags |= I915_DISPATCH_RS; - } - if (args->flags & I915_EXEC_FENCE_IN) { in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2)); if (!in_fence) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f00c7fbef79e..56c7f8637311 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -173,19 +173,11 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv, return 0; } - /* Early VLV doesn't have this */ - if (IS_VALLEYVIEW(dev_priv) && dev_priv->drm.pdev->revision < 0xb) { - DRM_DEBUG_DRIVER("disabling PPGTT on pre-B3 step VLV\n"); - return 0; - } - - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv)) { - if (has_full_48bit_ppgtt) - return 3; + if (has_full_48bit_ppgtt) + return 3; - if (has_full_ppgtt) - return 2; - } + if (has_full_ppgtt) + return 2; return 1; } @@ -1058,7 +1050,7 @@ gen8_ppgtt_insert_pte_entries(struct i915_hw_ppgtt *ppgtt, do { vaddr[idx->pte] = pte_encode | iter->dma; - iter->dma += PAGE_SIZE; + iter->dma += I915_GTT_PAGE_SIZE; if (iter->dma >= iter->max) { iter->sg = __sg_next(iter->sg); if (!iter->sg) { @@ -1152,7 +1144,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma, vma->page_sizes.sg & I915_GTT_PAGE_SIZE_64K && IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) && (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) || - rem >= (max - index) << PAGE_SHIFT)) + rem >= (max - index) * I915_GTT_PAGE_SIZE)) maybe_64K = true; vaddr = kmap_atomic_px(pt); @@ -1177,7 +1169,7 @@ static void gen8_ppgtt_insert_huge_entries(struct i915_vma *vma, if (maybe_64K && index < max && !(IS_ALIGNED(iter->dma, I915_GTT_PAGE_SIZE_64K) && (IS_ALIGNED(rem, I915_GTT_PAGE_SIZE_64K) || - rem >= (max - index) << PAGE_SHIFT))) + rem >= (max - index) * I915_GTT_PAGE_SIZE))) maybe_64K = false; if (unlikely(!IS_ALIGNED(iter->dma, page_size))) @@ -1259,9 +1251,6 @@ static void gen8_free_page_tables(struct i915_address_space *vm, { int i; - if (!px_page(pd)) - return; - for (i = 0; i < I915_PDES; i++) { if (pd->page_table[i] != vm->scratch_pt) free_pt(vm, pd->page_table[i]); @@ -1770,7 +1759,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *base, struct seq_file *m) seq_printf(m, "\t\t(%03d, %04d) %08lx: ", pde, pte, - (pde * GEN6_PTES + pte) * PAGE_SIZE); + (pde * GEN6_PTES + pte) * I915_GTT_PAGE_SIZE); for (i = 0; i < 4; i++) { if (vaddr[pte + i] != scratch_pte) seq_printf(m, " %08x", vaddr[pte + i]); @@ -1853,10 +1842,10 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, u64 start, u64 length) { struct gen6_hw_ppgtt *ppgtt = to_gen6_ppgtt(i915_vm_to_ppgtt(vm)); - unsigned int first_entry = start >> PAGE_SHIFT; + unsigned int first_entry = start / I915_GTT_PAGE_SIZE; unsigned int pde = first_entry / GEN6_PTES; unsigned int pte = first_entry % GEN6_PTES; - unsigned int num_entries = length >> PAGE_SHIFT; + unsigned int num_entries = length / I915_GTT_PAGE_SIZE; const gen6_pte_t scratch_pte = ppgtt->scratch_pte; while (num_entries) { @@ -1897,7 +1886,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, u32 flags) { struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); - unsigned first_entry = vma->node.start >> PAGE_SHIFT; + unsigned first_entry = vma->node.start / I915_GTT_PAGE_SIZE; unsigned act_pt = first_entry / GEN6_PTES; unsigned act_pte = first_entry % GEN6_PTES; const u32 pte_encode = vm->pte_encode(0, cache_level, flags); @@ -1910,7 +1899,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, do { vaddr[act_pte] = pte_encode | GEN6_PTE_ADDR_ENCODE(iter.dma); - iter.dma += PAGE_SIZE; + iter.dma += I915_GTT_PAGE_SIZE; if (iter.dma == iter.max) { iter.sg = __sg_next(iter.sg); if (!iter.sg) @@ -2048,7 +2037,7 @@ static int pd_vma_bind(struct i915_vma *vma, { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vma->vm); struct gen6_hw_ppgtt *ppgtt = vma->private; - u32 ggtt_offset = i915_ggtt_offset(vma) / PAGE_SIZE; + u32 ggtt_offset = i915_ggtt_offset(vma) / I915_GTT_PAGE_SIZE; struct i915_page_table *pt; unsigned int pde; @@ -2174,7 +2163,7 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915) ppgtt->base.vm.i915 = i915; ppgtt->base.vm.dma = &i915->drm.pdev->dev; - ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE; + ppgtt->base.vm.total = I915_PDES * GEN6_PTES * I915_GTT_PAGE_SIZE; i915_address_space_init(&ppgtt->base.vm, i915); @@ -2348,7 +2337,7 @@ static bool needs_idle_maps(struct drm_i915_private *dev_priv) return IS_GEN5(dev_priv) && IS_MOBILE(dev_priv) && intel_vtd_active(); } -static void gen6_check_and_clear_faults(struct drm_i915_private *dev_priv) +static void gen6_check_faults(struct drm_i915_private *dev_priv) { struct intel_engine_cs *engine; enum intel_engine_id id; @@ -2366,15 +2355,11 @@ static void gen6_check_and_clear_faults(struct drm_i915_private *dev_priv) fault & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT", RING_FAULT_SRCID(fault), RING_FAULT_FAULT_TYPE(fault)); - I915_WRITE(RING_FAULT_REG(engine), - fault & ~RING_FAULT_VALID); } } - - POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS])); } -static void gen8_check_and_clear_faults(struct drm_i915_private *dev_priv) +static void gen8_check_faults(struct drm_i915_private *dev_priv) { u32 fault = I915_READ(GEN8_RING_FAULT_REG); @@ -2399,22 +2384,20 @@ static void gen8_check_and_clear_faults(struct drm_i915_private *dev_priv) GEN8_RING_FAULT_ENGINE_ID(fault), RING_FAULT_SRCID(fault), RING_FAULT_FAULT_TYPE(fault)); - I915_WRITE(GEN8_RING_FAULT_REG, - fault & ~RING_FAULT_VALID); } - - POSTING_READ(GEN8_RING_FAULT_REG); } void i915_check_and_clear_faults(struct drm_i915_private *dev_priv) { /* From GEN8 onwards we only have one 'All Engine Fault Register' */ if (INTEL_GEN(dev_priv) >= 8) - gen8_check_and_clear_faults(dev_priv); + gen8_check_faults(dev_priv); else if (INTEL_GEN(dev_priv) >= 6) - gen6_check_and_clear_faults(dev_priv); + gen6_check_faults(dev_priv); else return; + + i915_clear_error_registers(dev_priv); } void i915_gem_suspend_gtt_mappings(struct drm_i915_private *dev_priv) @@ -2473,7 +2456,7 @@ static void gen8_ggtt_insert_page(struct i915_address_space *vm, { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); gen8_pte_t __iomem *pte = - (gen8_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT); + (gen8_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; gen8_set_pte(pte, gen8_pte_encode(addr, level, 0)); @@ -2497,7 +2480,7 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, */ gtt_entries = (gen8_pte_t __iomem *)ggtt->gsm; - gtt_entries += vma->node.start >> PAGE_SHIFT; + gtt_entries += vma->node.start / I915_GTT_PAGE_SIZE; for_each_sgt_dma(addr, sgt_iter, vma->pages) gen8_set_pte(gtt_entries++, pte_encode | addr); @@ -2516,7 +2499,7 @@ static void gen6_ggtt_insert_page(struct i915_address_space *vm, { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); gen6_pte_t __iomem *pte = - (gen6_pte_t __iomem *)ggtt->gsm + (offset >> PAGE_SHIFT); + (gen6_pte_t __iomem *)ggtt->gsm + offset / I915_GTT_PAGE_SIZE; iowrite32(vm->pte_encode(addr, level, flags), pte); @@ -2536,7 +2519,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm, { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); gen6_pte_t __iomem *entries = (gen6_pte_t __iomem *)ggtt->gsm; - unsigned int i = vma->node.start >> PAGE_SHIFT; + unsigned int i = vma->node.start / I915_GTT_PAGE_SIZE; struct sgt_iter iter; dma_addr_t addr; for_each_sgt_dma(addr, iter, vma->pages) @@ -2558,8 +2541,8 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, u64 start, u64 length) { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); - unsigned first_entry = start >> PAGE_SHIFT; - unsigned num_entries = length >> PAGE_SHIFT; + unsigned first_entry = start / I915_GTT_PAGE_SIZE; + unsigned num_entries = length / I915_GTT_PAGE_SIZE; const gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr, I915_CACHE_LLC, 0); gen8_pte_t __iomem *gtt_base = @@ -2674,8 +2657,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm, u64 start, u64 length) { struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm); - unsigned first_entry = start >> PAGE_SHIFT; - unsigned num_entries = length >> PAGE_SHIFT; + unsigned first_entry = start / I915_GTT_PAGE_SIZE; + unsigned num_entries = length / I915_GTT_PAGE_SIZE; gen6_pte_t scratch_pte, __iomem *gtt_base = (gen6_pte_t __iomem *)ggtt->gsm + first_entry; const int max_entries = ggtt_total_entries(ggtt) - first_entry; @@ -2937,6 +2920,15 @@ int i915_gem_init_ggtt(struct drm_i915_private *dev_priv) struct drm_mm_node *entry; int ret; + /* + * GuC requires all resources that we're sharing with it to be placed in + * non-WOPCM memory. If GuC is not present or not in use we still need a + * small bias as ring wraparound at offset 0 sometimes hangs. No idea + * why. + */ + ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE, + intel_guc_reserved_gtt_size(&dev_priv->guc)); + ret = intel_vgt_balloon(dev_priv); if (ret) return ret; @@ -3013,7 +3005,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv) arch_phys_wc_del(ggtt->mtrr); io_mapping_fini(&ggtt->iomap); - i915_gem_cleanup_stolen(&dev_priv->drm); + i915_gem_cleanup_stolen(dev_priv); } static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) @@ -3031,7 +3023,7 @@ static unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl) bdw_gmch_ctl = 1 << bdw_gmch_ctl; #ifdef CONFIG_X86_32 - /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * PAGE_SIZE */ + /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * I915_GTT_PAGE_SIZE */ if (bdw_gmch_ctl > 4) bdw_gmch_ctl = 4; #endif @@ -3406,7 +3398,7 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) else size = gen8_get_total_gtt_size(snb_gmch_ctl); - ggtt->vm.total = (size / sizeof(gen8_pte_t)) << PAGE_SHIFT; + ggtt->vm.total = (size / sizeof(gen8_pte_t)) * I915_GTT_PAGE_SIZE; ggtt->vm.cleanup = gen6_gmch_remove; ggtt->vm.insert_page = gen8_ggtt_insert_page; ggtt->vm.clear_range = nop_clear_range; @@ -3464,7 +3456,7 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt) pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl); size = gen6_get_total_gtt_size(snb_gmch_ctl); - ggtt->vm.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT; + ggtt->vm.total = (size / sizeof(gen6_pte_t)) * I915_GTT_PAGE_SIZE; ggtt->vm.clear_range = gen6_ggtt_clear_range; ggtt->vm.insert_page = gen6_ggtt_insert_page; @@ -3612,6 +3604,8 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv) mutex_lock(&dev_priv->drm.struct_mutex); i915_address_space_init(&ggtt->vm, dev_priv); + ggtt->vm.is_ggtt = true; + /* Only VLV supports read-only GGTT mappings */ ggtt->vm.has_read_only = IS_VALLEYVIEW(dev_priv); @@ -3662,6 +3656,10 @@ void i915_ggtt_enable_guc(struct drm_i915_private *i915) void i915_ggtt_disable_guc(struct drm_i915_private *i915) { + /* XXX Temporary pardon for error unload */ + if (i915->ggtt.invalidate == gen6_ggtt_invalidate) + return; + /* We should only be called after i915_ggtt_enable_guc() */ GEM_BUG_ON(i915->ggtt.invalidate != guc_ggtt_invalidate); @@ -3729,9 +3727,9 @@ rotate_pages(const dma_addr_t *in, unsigned int offset, * the entries so the sg list can be happily traversed. * The only thing we need are DMA addresses. */ - sg_set_page(sg, NULL, PAGE_SIZE, 0); + sg_set_page(sg, NULL, I915_GTT_PAGE_SIZE, 0); sg_dma_address(sg) = in[offset + src_idx]; - sg_dma_len(sg) = PAGE_SIZE; + sg_dma_len(sg) = I915_GTT_PAGE_SIZE; sg = sg_next(sg); src_idx -= stride; } @@ -3744,7 +3742,7 @@ static noinline struct sg_table * intel_rotate_pages(struct intel_rotation_info *rot_info, struct drm_i915_gem_object *obj) { - const unsigned long n_pages = obj->base.size / PAGE_SIZE; + const unsigned long n_pages = obj->base.size / I915_GTT_PAGE_SIZE; unsigned int size = intel_rotation_info_size(rot_info); struct sgt_iter sgt_iter; dma_addr_t dma_addr; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 2a116a91420b..7e2af5f4f39b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -167,29 +167,22 @@ struct intel_rotation_info { } plane[2]; } __packed; -static inline void assert_intel_rotation_info_is_packed(void) -{ - BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 8*sizeof(unsigned int)); -} - struct intel_partial_info { u64 offset; unsigned int size; } __packed; -static inline void assert_intel_partial_info_is_packed(void) -{ - BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int)); -} - enum i915_ggtt_view_type { I915_GGTT_VIEW_NORMAL = 0, I915_GGTT_VIEW_ROTATED = sizeof(struct intel_rotation_info), I915_GGTT_VIEW_PARTIAL = sizeof(struct intel_partial_info), }; -static inline void assert_i915_ggtt_view_type_is_unique(void) +static inline void assert_i915_gem_gtt_types(void) { + BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 8*sizeof(unsigned int)); + BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int)); + /* As we encode the size of each branch inside the union into its type, * we have to be careful that each branch has a unique size. */ @@ -229,7 +222,6 @@ struct i915_page_dma { }; #define px_base(px) (&(px)->base) -#define px_page(px) (px_base(px)->page) #define px_dma(px) (px_base(px)->daddr) struct i915_page_table { @@ -332,6 +324,9 @@ struct i915_address_space { struct pagestash free_pages; + /* Global GTT */ + bool is_ggtt:1; + /* Some systems require uncached updates of the page directories */ bool pt_kmap_wc:1; @@ -365,7 +360,7 @@ struct i915_address_space { I915_SELFTEST_DECLARE(bool scrub_64K); }; -#define i915_is_ggtt(V) (!(V)->file) +#define i915_is_ggtt(vm) ((vm)->is_ggtt) static inline bool i915_vm_is_48bit(const struct i915_address_space *vm) @@ -401,6 +396,8 @@ struct i915_ggtt { int mtrr; + u32 pin_bias; + struct drm_mm_node error_capture; }; diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index 83e5e01fa9ea..a6dd7c46de0d 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -421,19 +421,19 @@ i915_gem_object_is_framebuffer(const struct drm_i915_gem_object *obj) } static inline unsigned int -i915_gem_object_get_tiling(struct drm_i915_gem_object *obj) +i915_gem_object_get_tiling(const struct drm_i915_gem_object *obj) { return obj->tiling_and_stride & TILING_MASK; } static inline bool -i915_gem_object_is_tiled(struct drm_i915_gem_object *obj) +i915_gem_object_is_tiled(const struct drm_i915_gem_object *obj) { return i915_gem_object_get_tiling(obj) != I915_TILING_NONE; } static inline unsigned int -i915_gem_object_get_stride(struct drm_i915_gem_object *obj) +i915_gem_object_get_stride(const struct drm_i915_gem_object *obj) { return obj->tiling_and_stride & STRIDE_MASK; } @@ -446,13 +446,13 @@ i915_gem_tile_height(unsigned int tiling) } static inline unsigned int -i915_gem_object_get_tile_height(struct drm_i915_gem_object *obj) +i915_gem_object_get_tile_height(const struct drm_i915_gem_object *obj) { return i915_gem_tile_height(i915_gem_object_get_tiling(obj)); } static inline unsigned int -i915_gem_object_get_tile_row_size(struct drm_i915_gem_object *obj) +i915_gem_object_get_tile_row_size(const struct drm_i915_gem_object *obj) { return (i915_gem_object_get_stride(obj) * i915_gem_object_get_tile_height(obj)); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 53440bf87650..f29a7ff7c362 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -167,10 +167,8 @@ static int i915_adjust_stolen(struct drm_i915_private *dev_priv, return 0; } -void i915_gem_cleanup_stolen(struct drm_device *dev) +void i915_gem_cleanup_stolen(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); - if (!drm_mm_initialized(&dev_priv->mm.stolen)) return; diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index a262a64f5625..8762d17b6659 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1403,15 +1403,20 @@ static void request_record_user_bo(struct i915_request *request, { struct i915_capture_list *c; struct drm_i915_error_object **bo; - long count; + long count, max; - count = 0; + max = 0; for (c = request->capture_list; c; c = c->next) - count++; + max++; + if (!max) + return; - bo = NULL; - if (count) - bo = kcalloc(count, sizeof(*bo), GFP_ATOMIC); + bo = kmalloc_array(max, sizeof(*bo), GFP_ATOMIC); + if (!bo) { + /* If we can't capture everything, try to capture something. */ + max = min_t(long, max, PAGE_SIZE / sizeof(*bo)); + bo = kmalloc_array(max, sizeof(*bo), GFP_ATOMIC); + } if (!bo) return; @@ -1420,7 +1425,8 @@ static void request_record_user_bo(struct i915_request *request, bo[count] = i915_error_object_create(request->i915, c->vma); if (!bo[count]) break; - count++; + if (++count == max) + break; } ee->user_bo = bo; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 29877969310d..2e242270e270 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -478,7 +478,7 @@ void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv) void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv) { spin_lock_irq(&dev_priv->irq_lock); - gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events); + gen6_reset_pm_iir(dev_priv, GEN6_PM_RPS_EVENTS); dev_priv->gt_pm.rps.pm_iir = 0; spin_unlock_irq(&dev_priv->irq_lock); } @@ -516,7 +516,7 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u)); - gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events); + gen6_disable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS); spin_unlock_irq(&dev_priv->irq_lock); synchronize_irq(dev_priv->drm.irq); @@ -1534,11 +1534,8 @@ static void gen8_gt_irq_ack(struct drm_i915_private *i915, if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) { gt_iir[2] = raw_reg_read(regs, GEN8_GT_IIR(2)); - if (likely(gt_iir[2] & (i915->pm_rps_events | - i915->pm_guc_events))) - raw_reg_write(regs, GEN8_GT_IIR(2), - gt_iir[2] & (i915->pm_rps_events | - i915->pm_guc_events)); + if (likely(gt_iir[2])) + raw_reg_write(regs, GEN8_GT_IIR(2), gt_iir[2]); } if (master_ctl & GEN8_GT_VECS_IRQ) { @@ -3209,7 +3206,7 @@ static void i915_reset_device(struct drm_i915_private *dev_priv, kobject_uevent_env(kobj, KOBJ_CHANGE, reset_done_event); } -static void i915_clear_error_registers(struct drm_i915_private *dev_priv) +void i915_clear_error_registers(struct drm_i915_private *dev_priv) { u32 eir; @@ -3232,6 +3229,22 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv) I915_WRITE(EMR, I915_READ(EMR) | eir); I915_WRITE(IIR, I915_MASTER_ERROR_INTERRUPT); } + + if (INTEL_GEN(dev_priv) >= 8) { + I915_WRITE(GEN8_RING_FAULT_REG, + I915_READ(GEN8_RING_FAULT_REG) & ~RING_FAULT_VALID); + POSTING_READ(GEN8_RING_FAULT_REG); + } else if (INTEL_GEN(dev_priv) >= 6) { + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, dev_priv, id) { + I915_WRITE(RING_FAULT_REG(engine), + I915_READ(RING_FAULT_REG(engine)) & + ~RING_FAULT_VALID); + } + POSTING_READ(RING_FAULT_REG(dev_priv->engine[RCS])); + } } /** @@ -3287,7 +3300,8 @@ void i915_handle_error(struct drm_i915_private *dev_priv, * Try engine reset when available. We fall back to full reset if * single reset fails. */ - if (intel_has_reset_engine(dev_priv)) { + if (intel_has_reset_engine(dev_priv) && + !i915_terminally_wedged(&dev_priv->gpu_error)) { for_each_engine_masked(engine, dev_priv, engine_mask, tmp) { BUILD_BUG_ON(I915_RESET_MODESET >= I915_RESET_ENGINE); if (test_and_set_bit(I915_RESET_ENGINE + engine->id, @@ -4772,7 +4786,9 @@ void intel_irq_init(struct drm_i915_private *dev_priv) /* WaGsvRC0ResidencyMethod:vlv */ dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED; else - dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; + dev_priv->pm_rps_events = (GEN6_PM_RP_UP_THRESHOLD | + GEN6_PM_RP_DOWN_THRESHOLD | + GEN6_PM_RP_DOWN_TIMEOUT); rps->pm_intrmsk_mbz = 0; diff --git a/drivers/gpu/drm/i915/i915_pci.c b/drivers/gpu/drm/i915/i915_pci.c index 1df3ce134cd0..d6f7b9fe1d26 100644 --- a/drivers/gpu/drm/i915/i915_pci.c +++ b/drivers/gpu/drm/i915/i915_pci.c @@ -74,6 +74,7 @@ .unfenced_needs_alignment = 1, \ .ring_mask = RENDER_RING, \ .has_snoop = true, \ + .has_coherent_ggtt = false, \ GEN_DEFAULT_PIPEOFFSETS, \ GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS @@ -110,6 +111,7 @@ static const struct intel_device_info intel_i865g_info = { .has_gmch_display = 1, \ .ring_mask = RENDER_RING, \ .has_snoop = true, \ + .has_coherent_ggtt = true, \ GEN_DEFAULT_PIPEOFFSETS, \ GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS @@ -117,6 +119,7 @@ static const struct intel_device_info intel_i865g_info = { static const struct intel_device_info intel_i915g_info = { GEN3_FEATURES, PLATFORM(INTEL_I915G), + .has_coherent_ggtt = false, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .hws_needs_physical = 1, @@ -178,6 +181,7 @@ static const struct intel_device_info intel_pineview_info = { .has_gmch_display = 1, \ .ring_mask = RENDER_RING, \ .has_snoop = true, \ + .has_coherent_ggtt = true, \ GEN_DEFAULT_PIPEOFFSETS, \ GEN_DEFAULT_PAGE_SIZES, \ CURSOR_OFFSETS @@ -220,6 +224,7 @@ static const struct intel_device_info intel_gm45_info = { .has_hotplug = 1, \ .ring_mask = RENDER_RING | BSD_RING, \ .has_snoop = true, \ + .has_coherent_ggtt = true, \ /* ilk does support rc6, but we do not implement [power] contexts */ \ .has_rc6 = 0, \ GEN_DEFAULT_PIPEOFFSETS, \ @@ -243,6 +248,7 @@ static const struct intel_device_info intel_ironlake_m_info = { .has_hotplug = 1, \ .has_fbc = 1, \ .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \ + .has_coherent_ggtt = true, \ .has_llc = 1, \ .has_rc6 = 1, \ .has_rc6p = 1, \ @@ -287,6 +293,7 @@ static const struct intel_device_info intel_sandybridge_m_gt2_info = { .has_hotplug = 1, \ .has_fbc = 1, \ .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \ + .has_coherent_ggtt = true, \ .has_llc = 1, \ .has_rc6 = 1, \ .has_rc6p = 1, \ @@ -347,6 +354,7 @@ static const struct intel_device_info intel_valleyview_info = { .has_aliasing_ppgtt = 1, .has_full_ppgtt = 1, .has_snoop = true, + .has_coherent_ggtt = false, .ring_mask = RENDER_RING | BSD_RING | BLT_RING, .display_mmio_offset = VLV_DISPLAY_BASE, GEN_DEFAULT_PAGE_SIZES, @@ -360,7 +368,6 @@ static const struct intel_device_info intel_valleyview_info = { .has_ddi = 1, \ .has_fpga_dbg = 1, \ .has_psr = 1, \ - .has_resource_streamer = 1, \ .has_dp_mst = 1, \ .has_rc6p = 0 /* RC6p removed-by HSW */, \ .has_runtime_pm = 1 @@ -433,7 +440,6 @@ static const struct intel_device_info intel_cherryview_info = { .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, .has_64bit_reloc = 1, .has_runtime_pm = 1, - .has_resource_streamer = 1, .has_rc6 = 1, .has_logical_ring_contexts = 1, .has_gmch_display = 1, @@ -441,6 +447,7 @@ static const struct intel_device_info intel_cherryview_info = { .has_full_ppgtt = 1, .has_reset_engine = 1, .has_snoop = true, + .has_coherent_ggtt = false, .display_mmio_offset = VLV_DISPLAY_BASE, GEN_DEFAULT_PAGE_SIZES, GEN_CHV_PIPEOFFSETS, @@ -506,7 +513,6 @@ static const struct intel_device_info intel_skylake_gt4_info = { .has_runtime_pm = 1, \ .has_pooled_eu = 0, \ .has_csr = 1, \ - .has_resource_streamer = 1, \ .has_rc6 = 1, \ .has_dp_mst = 1, \ .has_logical_ring_contexts = 1, \ @@ -517,6 +523,7 @@ static const struct intel_device_info intel_skylake_gt4_info = { .has_full_48bit_ppgtt = 1, \ .has_reset_engine = 1, \ .has_snoop = true, \ + .has_coherent_ggtt = false, \ .has_ipc = 1, \ GEN9_DEFAULT_PAGE_SIZES, \ GEN_DEFAULT_PIPEOFFSETS, \ @@ -580,6 +587,7 @@ static const struct intel_device_info intel_coffeelake_gt3_info = { GEN9_FEATURES, \ GEN(10), \ .ddb_size = 1024, \ + .has_coherent_ggtt = false, \ GLK_COLORS static const struct intel_device_info intel_cannonlake_info = { @@ -598,7 +606,6 @@ static const struct intel_device_info intel_icelake_11_info = { GEN11_FEATURES, PLATFORM(INTEL_ICELAKE), .is_alpha_support = 1, - .has_resource_streamer = 0, .ring_mask = RENDER_RING | BLT_RING | VEBOX_RING | BSD_RING | BSD3_RING, }; diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index 6bf10952c724..664b96bb65a3 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -210,6 +210,7 @@ #include "i915_oa_cflgt3.h" #include "i915_oa_cnl.h" #include "i915_oa_icl.h" +#include "intel_lrc_reg.h" /* HW requires this to be a power of two, between 128k and 16M, though driver * is currently generally designed assuming the largest 16M size is used such @@ -1338,14 +1339,12 @@ free_oa_buffer(struct drm_i915_private *i915) { mutex_lock(&i915->drm.struct_mutex); - i915_gem_object_unpin_map(i915->perf.oa.oa_buffer.vma->obj); - i915_vma_unpin(i915->perf.oa.oa_buffer.vma); - i915_gem_object_put(i915->perf.oa.oa_buffer.vma->obj); - - i915->perf.oa.oa_buffer.vma = NULL; - i915->perf.oa.oa_buffer.vaddr = NULL; + i915_vma_unpin_and_release(&i915->perf.oa.oa_buffer.vma, + I915_VMA_RELEASE_MAP); mutex_unlock(&i915->drm.struct_mutex); + + i915->perf.oa.oa_buffer.vaddr = NULL; } static void i915_oa_stream_destroy(struct i915_perf_stream *stream) @@ -1638,27 +1637,25 @@ static void gen8_update_reg_state_unlocked(struct i915_gem_context *ctx, u32 ctx_oactxctrl = dev_priv->perf.oa.ctx_oactxctrl_offset; u32 ctx_flexeu0 = dev_priv->perf.oa.ctx_flexeu0_offset; /* The MMIO offsets for Flex EU registers aren't contiguous */ - u32 flex_mmio[] = { - i915_mmio_reg_offset(EU_PERF_CNTL0), - i915_mmio_reg_offset(EU_PERF_CNTL1), - i915_mmio_reg_offset(EU_PERF_CNTL2), - i915_mmio_reg_offset(EU_PERF_CNTL3), - i915_mmio_reg_offset(EU_PERF_CNTL4), - i915_mmio_reg_offset(EU_PERF_CNTL5), - i915_mmio_reg_offset(EU_PERF_CNTL6), + i915_reg_t flex_regs[] = { + EU_PERF_CNTL0, + EU_PERF_CNTL1, + EU_PERF_CNTL2, + EU_PERF_CNTL3, + EU_PERF_CNTL4, + EU_PERF_CNTL5, + EU_PERF_CNTL6, }; int i; - reg_state[ctx_oactxctrl] = i915_mmio_reg_offset(GEN8_OACTXCONTROL); - reg_state[ctx_oactxctrl+1] = (dev_priv->perf.oa.period_exponent << - GEN8_OA_TIMER_PERIOD_SHIFT) | - (dev_priv->perf.oa.periodic ? - GEN8_OA_TIMER_ENABLE : 0) | - GEN8_OA_COUNTER_RESUME; + CTX_REG(reg_state, ctx_oactxctrl, GEN8_OACTXCONTROL, + (dev_priv->perf.oa.period_exponent << GEN8_OA_TIMER_PERIOD_SHIFT) | + (dev_priv->perf.oa.periodic ? GEN8_OA_TIMER_ENABLE : 0) | + GEN8_OA_COUNTER_RESUME); - for (i = 0; i < ARRAY_SIZE(flex_mmio); i++) { + for (i = 0; i < ARRAY_SIZE(flex_regs); i++) { u32 state_offset = ctx_flexeu0 + i * 2; - u32 mmio = flex_mmio[i]; + u32 mmio = i915_mmio_reg_offset(flex_regs[i]); /* * This arbitrary default will select the 'EU FPU0 Pipeline @@ -1678,110 +1675,8 @@ static void gen8_update_reg_state_unlocked(struct i915_gem_context *ctx, } } - reg_state[state_offset] = mmio; - reg_state[state_offset+1] = value; - } -} - -/* - * Same as gen8_update_reg_state_unlocked only through the batchbuffer. This - * is only used by the kernel context. - */ -static int gen8_emit_oa_config(struct i915_request *rq, - const struct i915_oa_config *oa_config) -{ - struct drm_i915_private *dev_priv = rq->i915; - /* The MMIO offsets for Flex EU registers aren't contiguous */ - u32 flex_mmio[] = { - i915_mmio_reg_offset(EU_PERF_CNTL0), - i915_mmio_reg_offset(EU_PERF_CNTL1), - i915_mmio_reg_offset(EU_PERF_CNTL2), - i915_mmio_reg_offset(EU_PERF_CNTL3), - i915_mmio_reg_offset(EU_PERF_CNTL4), - i915_mmio_reg_offset(EU_PERF_CNTL5), - i915_mmio_reg_offset(EU_PERF_CNTL6), - }; - u32 *cs; - int i; - - cs = intel_ring_begin(rq, ARRAY_SIZE(flex_mmio) * 2 + 4); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - *cs++ = MI_LOAD_REGISTER_IMM(ARRAY_SIZE(flex_mmio) + 1); - - *cs++ = i915_mmio_reg_offset(GEN8_OACTXCONTROL); - *cs++ = (dev_priv->perf.oa.period_exponent << GEN8_OA_TIMER_PERIOD_SHIFT) | - (dev_priv->perf.oa.periodic ? GEN8_OA_TIMER_ENABLE : 0) | - GEN8_OA_COUNTER_RESUME; - - for (i = 0; i < ARRAY_SIZE(flex_mmio); i++) { - u32 mmio = flex_mmio[i]; - - /* - * This arbitrary default will select the 'EU FPU0 Pipeline - * Active' event. In the future it's anticipated that there - * will be an explicit 'No Event' we can select, but not - * yet... - */ - u32 value = 0; - - if (oa_config) { - u32 j; - - for (j = 0; j < oa_config->flex_regs_len; j++) { - if (i915_mmio_reg_offset(oa_config->flex_regs[j].addr) == mmio) { - value = oa_config->flex_regs[j].value; - break; - } - } - } - - *cs++ = mmio; - *cs++ = value; + CTX_REG(reg_state, state_offset, flex_regs[i], value); } - - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); - - return 0; -} - -static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_priv, - const struct i915_oa_config *oa_config) -{ - struct intel_engine_cs *engine = dev_priv->engine[RCS]; - struct i915_timeline *timeline; - struct i915_request *rq; - int ret; - - lockdep_assert_held(&dev_priv->drm.struct_mutex); - - i915_retire_requests(dev_priv); - - rq = i915_request_alloc(engine, dev_priv->kernel_context); - if (IS_ERR(rq)) - return PTR_ERR(rq); - - ret = gen8_emit_oa_config(rq, oa_config); - if (ret) { - i915_request_add(rq); - return ret; - } - - /* Queue this switch after all other activity */ - list_for_each_entry(timeline, &dev_priv->gt.timelines, link) { - struct i915_request *prev; - - prev = i915_gem_active_raw(&timeline->last_request, - &dev_priv->drm.struct_mutex); - if (prev) - i915_request_await_dma_fence(rq, &prev->fence); - } - - i915_request_add(rq); - - return 0; } /* @@ -1812,17 +1707,13 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, const struct i915_oa_config *oa_config) { struct intel_engine_cs *engine = dev_priv->engine[RCS]; + unsigned int map_type = i915_coherent_map_type(dev_priv); struct i915_gem_context *ctx; + struct i915_request *rq; int ret; - unsigned int wait_flags = I915_WAIT_LOCKED; lockdep_assert_held(&dev_priv->drm.struct_mutex); - /* Switch away from any user context. */ - ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config); - if (ret) - goto out; - /* * The OA register config is setup through the context image. This image * might be written to by the GPU on context switch (in particular on @@ -1837,10 +1728,10 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, * the GPU from any submitted work. */ ret = i915_gem_wait_for_idle(dev_priv, - wait_flags, + I915_WAIT_LOCKED, MAX_SCHEDULE_TIMEOUT); if (ret) - goto out; + return ret; /* Update all contexts now that we've stalled the submission. */ list_for_each_entry(ctx, &dev_priv->contexts.list, link) { @@ -1851,11 +1742,9 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, if (!ce->state) continue; - regs = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB); - if (IS_ERR(regs)) { - ret = PTR_ERR(regs); - goto out; - } + regs = i915_gem_object_pin_map(ce->state->obj, map_type); + if (IS_ERR(regs)) + return PTR_ERR(regs); ce->state->obj->mm.dirty = true; regs += LRC_STATE_PN * PAGE_SIZE / sizeof(*regs); @@ -1865,8 +1754,17 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv, i915_gem_object_unpin_map(ce->state->obj); } - out: - return ret; + /* + * Apply the configuration by doing one context restore of the edited + * context image. + */ + rq = i915_request_alloc(engine, dev_priv->kernel_context); + if (IS_ERR(rq)) + return PTR_ERR(rq); + + i915_request_add(rq); + + return 0; } static int gen8_enable_metric_set(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9e63cd47b60f..7c491ea3d052 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -344,6 +344,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) #define GEN8_RPCS_S_CNT_ENABLE (1 << 18) #define GEN8_RPCS_S_CNT_SHIFT 15 #define GEN8_RPCS_S_CNT_MASK (0x7 << GEN8_RPCS_S_CNT_SHIFT) +#define GEN11_RPCS_S_CNT_SHIFT 12 +#define GEN11_RPCS_S_CNT_MASK (0x3f << GEN11_RPCS_S_CNT_SHIFT) #define GEN8_RPCS_SS_CNT_ENABLE (1 << 11) #define GEN8_RPCS_SS_CNT_SHIFT 8 #define GEN8_RPCS_SS_CNT_MASK (0x7 << GEN8_RPCS_SS_CNT_SHIFT) @@ -1029,126 +1031,43 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) /* * i915_power_well_id: * - * Platform specific IDs used to look up power wells and - except for custom - * power wells - to define request/status register flag bit positions. As such - * the set of IDs on a given platform must be unique and except for custom - * power wells their value must stay fixed. + * IDs used to look up power wells. Power wells accessed directly bypassing + * the power domains framework must be assigned a unique ID. The rest of power + * wells must be assigned DISP_PW_ID_NONE. */ enum i915_power_well_id { - /* - * I830 - * - custom power well - */ - I830_DISP_PW_PIPES = 0, - - /* - * VLV/CHV - * - PUNIT_REG_PWRGT_CTRL (bit: id*2), - * PUNIT_REG_PWRGT_STATUS (bit: id*2) (PUNIT HAS v0.8) - */ - PUNIT_POWER_WELL_RENDER = 0, - PUNIT_POWER_WELL_MEDIA = 1, - PUNIT_POWER_WELL_DISP2D = 3, - PUNIT_POWER_WELL_DPIO_CMN_BC = 5, - PUNIT_POWER_WELL_DPIO_TX_B_LANES_01 = 6, - PUNIT_POWER_WELL_DPIO_TX_B_LANES_23 = 7, - PUNIT_POWER_WELL_DPIO_TX_C_LANES_01 = 8, - PUNIT_POWER_WELL_DPIO_TX_C_LANES_23 = 9, - PUNIT_POWER_WELL_DPIO_RX0 = 10, - PUNIT_POWER_WELL_DPIO_RX1 = 11, - PUNIT_POWER_WELL_DPIO_CMN_D = 12, - /* - custom power well */ - CHV_DISP_PW_PIPE_A, /* 13 */ - - /* - * HSW/BDW - * - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1) - */ - HSW_DISP_PW_GLOBAL = 15, - - /* - * GEN9+ - * - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1) - */ - SKL_DISP_PW_MISC_IO = 0, - SKL_DISP_PW_DDI_A_E, - GLK_DISP_PW_DDI_A = SKL_DISP_PW_DDI_A_E, - CNL_DISP_PW_DDI_A = SKL_DISP_PW_DDI_A_E, - SKL_DISP_PW_DDI_B, - SKL_DISP_PW_DDI_C, - SKL_DISP_PW_DDI_D, - CNL_DISP_PW_DDI_F = 6, - - GLK_DISP_PW_AUX_A = 8, - GLK_DISP_PW_AUX_B, - GLK_DISP_PW_AUX_C, - CNL_DISP_PW_AUX_A = GLK_DISP_PW_AUX_A, - CNL_DISP_PW_AUX_B = GLK_DISP_PW_AUX_B, - CNL_DISP_PW_AUX_C = GLK_DISP_PW_AUX_C, - CNL_DISP_PW_AUX_D, - CNL_DISP_PW_AUX_F, - - SKL_DISP_PW_1 = 14, + DISP_PW_ID_NONE, + + VLV_DISP_PW_DISP2D, + BXT_DISP_PW_DPIO_CMN_A, + VLV_DISP_PW_DPIO_CMN_BC, + GLK_DISP_PW_DPIO_CMN_C, + CHV_DISP_PW_DPIO_CMN_D, + HSW_DISP_PW_GLOBAL, + SKL_DISP_PW_MISC_IO, + SKL_DISP_PW_1, SKL_DISP_PW_2, - - /* - custom power wells */ - BXT_DPIO_CMN_A, - BXT_DPIO_CMN_BC, - GLK_DPIO_CMN_C, /* 18 */ - - /* - * GEN11+ - * - _HSW_PWR_WELL_CTL1-4 - * (status bit: (id&15)*2, req bit:(id&15)*2+1) - */ - ICL_DISP_PW_1 = 0, - ICL_DISP_PW_2, - ICL_DISP_PW_3, - ICL_DISP_PW_4, - - /* - * - _HSW_PWR_WELL_CTL_AUX1/2/4 - * (status bit: (id&15)*2, req bit:(id&15)*2+1) - */ - ICL_DISP_PW_AUX_A = 16, - ICL_DISP_PW_AUX_B, - ICL_DISP_PW_AUX_C, - ICL_DISP_PW_AUX_D, - ICL_DISP_PW_AUX_E, - ICL_DISP_PW_AUX_F, - - ICL_DISP_PW_AUX_TBT1 = 24, - ICL_DISP_PW_AUX_TBT2, - ICL_DISP_PW_AUX_TBT3, - ICL_DISP_PW_AUX_TBT4, - - /* - * - _HSW_PWR_WELL_CTL_DDI1/2/4 - * (status bit: (id&15)*2, req bit:(id&15)*2+1) - */ - ICL_DISP_PW_DDI_A = 32, - ICL_DISP_PW_DDI_B, - ICL_DISP_PW_DDI_C, - ICL_DISP_PW_DDI_D, - ICL_DISP_PW_DDI_E, - ICL_DISP_PW_DDI_F, /* 37 */ - - /* - * Multiple platforms. - * Must start following the highest ID of any platform. - * - custom power wells - */ - SKL_DISP_PW_DC_OFF = 38, - I915_DISP_PW_ALWAYS_ON, }; #define PUNIT_REG_PWRGT_CTRL 0x60 #define PUNIT_REG_PWRGT_STATUS 0x61 -#define PUNIT_PWRGT_MASK(power_well) (3 << ((power_well) * 2)) -#define PUNIT_PWRGT_PWR_ON(power_well) (0 << ((power_well) * 2)) -#define PUNIT_PWRGT_CLK_GATE(power_well) (1 << ((power_well) * 2)) -#define PUNIT_PWRGT_RESET(power_well) (2 << ((power_well) * 2)) -#define PUNIT_PWRGT_PWR_GATE(power_well) (3 << ((power_well) * 2)) +#define PUNIT_PWRGT_MASK(pw_idx) (3 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_PWR_ON(pw_idx) (0 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_CLK_GATE(pw_idx) (1 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_RESET(pw_idx) (2 << ((pw_idx) * 2)) +#define PUNIT_PWRGT_PWR_GATE(pw_idx) (3 << ((pw_idx) * 2)) + +#define PUNIT_PWGT_IDX_RENDER 0 +#define PUNIT_PWGT_IDX_MEDIA 1 +#define PUNIT_PWGT_IDX_DISP2D 3 +#define PUNIT_PWGT_IDX_DPIO_CMN_BC 5 +#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_01 6 +#define PUNIT_PWGT_IDX_DPIO_TX_B_LANES_23 7 +#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_01 8 +#define PUNIT_PWGT_IDX_DPIO_TX_C_LANES_23 9 +#define PUNIT_PWGT_IDX_DPIO_RX0 10 +#define PUNIT_PWGT_IDX_DPIO_RX1 11 +#define PUNIT_PWGT_IDX_DPIO_CMN_D 12 #define PUNIT_REG_GPU_LFM 0xd3 #define PUNIT_REG_GPU_FREQ_REQ 0xd4 @@ -1932,121 +1851,200 @@ enum i915_power_well_id { #define N_SCALAR(x) ((x) << 24) #define N_SCALAR_MASK (0x7F << 24) -#define _ICL_MG_PHY_PORT_LN(port, ln, ln0p1, ln0p2, ln1p1) \ +#define MG_PHY_PORT_LN(port, ln, ln0p1, ln0p2, ln1p1) \ _MMIO(_PORT((port) - PORT_C, ln0p1, ln0p2) + (ln) * ((ln1p1) - (ln0p1))) -#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT1 0x16812C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT1 0x16852C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT2 0x16912C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT2 0x16952C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT3 0x16A12C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT3 0x16A52C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT4 0x16B12C -#define _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT4 0x16B52C -#define ICL_PORT_MG_TX1_LINK_PARAMS(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT1, \ - _ICL_MG_TX_LINK_PARAMS_TX1LN0_PORT2, \ - _ICL_MG_TX_LINK_PARAMS_TX1LN1_PORT1) - -#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT1 0x1680AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT1 0x1684AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT2 0x1690AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT2 0x1694AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT3 0x16A0AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT3 0x16A4AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT4 0x16B0AC -#define _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT4 0x16B4AC -#define ICL_PORT_MG_TX2_LINK_PARAMS(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT1, \ - _ICL_MG_TX_LINK_PARAMS_TX2LN0_PORT2, \ - _ICL_MG_TX_LINK_PARAMS_TX2LN1_PORT1) -#define CRI_USE_FS32 (1 << 5) - -#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT1 0x16814C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT1 0x16854C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT2 0x16914C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT2 0x16954C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT3 0x16A14C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT3 0x16A54C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT4 0x16B14C -#define _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT4 0x16B54C -#define ICL_PORT_MG_TX1_PISO_READLOAD(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT1, \ - _ICL_MG_TX_PISO_READLOAD_TX1LN0_PORT2, \ - _ICL_MG_TX_PISO_READLOAD_TX1LN1_PORT1) - -#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT1 0x1680CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT1 0x1684CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT2 0x1690CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT2 0x1694CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT3 0x16A0CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT3 0x16A4CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT4 0x16B0CC -#define _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT4 0x16B4CC -#define ICL_PORT_MG_TX2_PISO_READLOAD(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT1, \ - _ICL_MG_TX_PISO_READLOAD_TX2LN0_PORT2, \ - _ICL_MG_TX_PISO_READLOAD_TX2LN1_PORT1) -#define CRI_CALCINIT (1 << 1) - -#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT1 0x168148 -#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT1 0x168548 -#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT2 0x169148 -#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT2 0x169548 -#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT3 0x16A148 -#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT3 0x16A548 -#define _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT4 0x16B148 -#define _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT4 0x16B548 -#define ICL_PORT_MG_TX1_SWINGCTRL(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT1, \ - _ICL_MG_TX_SWINGCTRL_TX1LN0_PORT2, \ - _ICL_MG_TX_SWINGCTRL_TX1LN1_PORT1) - -#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT1 0x1680C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT1 0x1684C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT2 0x1690C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT2 0x1694C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT3 0x16A0C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT3 0x16A4C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT4 0x16B0C8 -#define _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT4 0x16B4C8 -#define ICL_PORT_MG_TX2_SWINGCTRL(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT1, \ - _ICL_MG_TX_SWINGCTRL_TX2LN0_PORT2, \ - _ICL_MG_TX_SWINGCTRL_TX2LN1_PORT1) -#define CRI_TXDEEMPH_OVERRIDE_17_12(x) ((x) << 0) -#define CRI_TXDEEMPH_OVERRIDE_17_12_MASK (0x3F << 0) - -#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT1 0x168144 -#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT1 0x168544 -#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT2 0x169144 -#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT2 0x169544 -#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT3 0x16A144 -#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT3 0x16A544 -#define _ICL_MG_TX_DRVCTRL_TX1LN0_PORT4 0x16B144 -#define _ICL_MG_TX_DRVCTRL_TX1LN1_PORT4 0x16B544 -#define ICL_PORT_MG_TX1_DRVCTRL(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_DRVCTRL_TX1LN0_PORT1, \ - _ICL_MG_TX_DRVCTRL_TX1LN0_PORT2, \ - _ICL_MG_TX_DRVCTRL_TX1LN1_PORT1) - -#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT1 0x1680C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT1 0x1684C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT2 0x1690C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT2 0x1694C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT3 0x16A0C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT3 0x16A4C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN0_PORT4 0x16B0C4 -#define _ICL_MG_TX_DRVCTRL_TX2LN1_PORT4 0x16B4C4 -#define ICL_PORT_MG_TX2_DRVCTRL(port, ln) \ - _ICL_MG_PHY_PORT_LN(port, ln, _ICL_MG_TX_DRVCTRL_TX2LN0_PORT1, \ - _ICL_MG_TX_DRVCTRL_TX2LN0_PORT2, \ - _ICL_MG_TX_DRVCTRL_TX2LN1_PORT1) -#define CRI_TXDEEMPH_OVERRIDE_11_6(x) ((x) << 24) -#define CRI_TXDEEMPH_OVERRIDE_11_6_MASK (0x3F << 24) -#define CRI_TXDEEMPH_OVERRIDE_EN (1 << 22) -#define CRI_TXDEEMPH_OVERRIDE_5_0(x) ((x) << 16) -#define CRI_TXDEEMPH_OVERRIDE_5_0_MASK (0x3F << 16) +#define MG_TX_LINK_PARAMS_TX1LN0_PORT1 0x16812C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT1 0x16852C +#define MG_TX_LINK_PARAMS_TX1LN0_PORT2 0x16912C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT2 0x16952C +#define MG_TX_LINK_PARAMS_TX1LN0_PORT3 0x16A12C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT3 0x16A52C +#define MG_TX_LINK_PARAMS_TX1LN0_PORT4 0x16B12C +#define MG_TX_LINK_PARAMS_TX1LN1_PORT4 0x16B52C +#define MG_TX1_LINK_PARAMS(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_LINK_PARAMS_TX1LN0_PORT1, \ + MG_TX_LINK_PARAMS_TX1LN0_PORT2, \ + MG_TX_LINK_PARAMS_TX1LN1_PORT1) + +#define MG_TX_LINK_PARAMS_TX2LN0_PORT1 0x1680AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT1 0x1684AC +#define MG_TX_LINK_PARAMS_TX2LN0_PORT2 0x1690AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT2 0x1694AC +#define MG_TX_LINK_PARAMS_TX2LN0_PORT3 0x16A0AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT3 0x16A4AC +#define MG_TX_LINK_PARAMS_TX2LN0_PORT4 0x16B0AC +#define MG_TX_LINK_PARAMS_TX2LN1_PORT4 0x16B4AC +#define MG_TX2_LINK_PARAMS(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_LINK_PARAMS_TX2LN0_PORT1, \ + MG_TX_LINK_PARAMS_TX2LN0_PORT2, \ + MG_TX_LINK_PARAMS_TX2LN1_PORT1) +#define CRI_USE_FS32 (1 << 5) + +#define MG_TX_PISO_READLOAD_TX1LN0_PORT1 0x16814C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT1 0x16854C +#define MG_TX_PISO_READLOAD_TX1LN0_PORT2 0x16914C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT2 0x16954C +#define MG_TX_PISO_READLOAD_TX1LN0_PORT3 0x16A14C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT3 0x16A54C +#define MG_TX_PISO_READLOAD_TX1LN0_PORT4 0x16B14C +#define MG_TX_PISO_READLOAD_TX1LN1_PORT4 0x16B54C +#define MG_TX1_PISO_READLOAD(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_PISO_READLOAD_TX1LN0_PORT1, \ + MG_TX_PISO_READLOAD_TX1LN0_PORT2, \ + MG_TX_PISO_READLOAD_TX1LN1_PORT1) + +#define MG_TX_PISO_READLOAD_TX2LN0_PORT1 0x1680CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT1 0x1684CC +#define MG_TX_PISO_READLOAD_TX2LN0_PORT2 0x1690CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT2 0x1694CC +#define MG_TX_PISO_READLOAD_TX2LN0_PORT3 0x16A0CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT3 0x16A4CC +#define MG_TX_PISO_READLOAD_TX2LN0_PORT4 0x16B0CC +#define MG_TX_PISO_READLOAD_TX2LN1_PORT4 0x16B4CC +#define MG_TX2_PISO_READLOAD(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_PISO_READLOAD_TX2LN0_PORT1, \ + MG_TX_PISO_READLOAD_TX2LN0_PORT2, \ + MG_TX_PISO_READLOAD_TX2LN1_PORT1) +#define CRI_CALCINIT (1 << 1) + +#define MG_TX_SWINGCTRL_TX1LN0_PORT1 0x168148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT1 0x168548 +#define MG_TX_SWINGCTRL_TX1LN0_PORT2 0x169148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT2 0x169548 +#define MG_TX_SWINGCTRL_TX1LN0_PORT3 0x16A148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT3 0x16A548 +#define MG_TX_SWINGCTRL_TX1LN0_PORT4 0x16B148 +#define MG_TX_SWINGCTRL_TX1LN1_PORT4 0x16B548 +#define MG_TX1_SWINGCTRL(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_SWINGCTRL_TX1LN0_PORT1, \ + MG_TX_SWINGCTRL_TX1LN0_PORT2, \ + MG_TX_SWINGCTRL_TX1LN1_PORT1) + +#define MG_TX_SWINGCTRL_TX2LN0_PORT1 0x1680C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT1 0x1684C8 +#define MG_TX_SWINGCTRL_TX2LN0_PORT2 0x1690C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT2 0x1694C8 +#define MG_TX_SWINGCTRL_TX2LN0_PORT3 0x16A0C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT3 0x16A4C8 +#define MG_TX_SWINGCTRL_TX2LN0_PORT4 0x16B0C8 +#define MG_TX_SWINGCTRL_TX2LN1_PORT4 0x16B4C8 +#define MG_TX2_SWINGCTRL(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_SWINGCTRL_TX2LN0_PORT1, \ + MG_TX_SWINGCTRL_TX2LN0_PORT2, \ + MG_TX_SWINGCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_17_12(x) ((x) << 0) +#define CRI_TXDEEMPH_OVERRIDE_17_12_MASK (0x3F << 0) + +#define MG_TX_DRVCTRL_TX1LN0_TXPORT1 0x168144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT1 0x168544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT2 0x169144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT2 0x169544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT3 0x16A144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT3 0x16A544 +#define MG_TX_DRVCTRL_TX1LN0_TXPORT4 0x16B144 +#define MG_TX_DRVCTRL_TX1LN1_TXPORT4 0x16B544 +#define MG_TX1_DRVCTRL(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_DRVCTRL_TX1LN0_TXPORT1, \ + MG_TX_DRVCTRL_TX1LN0_TXPORT2, \ + MG_TX_DRVCTRL_TX1LN1_TXPORT1) + +#define MG_TX_DRVCTRL_TX2LN0_PORT1 0x1680C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT1 0x1684C4 +#define MG_TX_DRVCTRL_TX2LN0_PORT2 0x1690C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT2 0x1694C4 +#define MG_TX_DRVCTRL_TX2LN0_PORT3 0x16A0C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT3 0x16A4C4 +#define MG_TX_DRVCTRL_TX2LN0_PORT4 0x16B0C4 +#define MG_TX_DRVCTRL_TX2LN1_PORT4 0x16B4C4 +#define MG_TX2_DRVCTRL(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_DRVCTRL_TX2LN0_PORT1, \ + MG_TX_DRVCTRL_TX2LN0_PORT2, \ + MG_TX_DRVCTRL_TX2LN1_PORT1) +#define CRI_TXDEEMPH_OVERRIDE_11_6(x) ((x) << 24) +#define CRI_TXDEEMPH_OVERRIDE_11_6_MASK (0x3F << 24) +#define CRI_TXDEEMPH_OVERRIDE_EN (1 << 22) +#define CRI_TXDEEMPH_OVERRIDE_5_0(x) ((x) << 16) +#define CRI_TXDEEMPH_OVERRIDE_5_0_MASK (0x3F << 16) +#define CRI_LOADGEN_SEL(x) ((x) << 12) +#define CRI_LOADGEN_SEL_MASK (0x3 << 12) + +#define MG_CLKHUB_LN0_PORT1 0x16839C +#define MG_CLKHUB_LN1_PORT1 0x16879C +#define MG_CLKHUB_LN0_PORT2 0x16939C +#define MG_CLKHUB_LN1_PORT2 0x16979C +#define MG_CLKHUB_LN0_PORT3 0x16A39C +#define MG_CLKHUB_LN1_PORT3 0x16A79C +#define MG_CLKHUB_LN0_PORT4 0x16B39C +#define MG_CLKHUB_LN1_PORT4 0x16B79C +#define MG_CLKHUB(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_CLKHUB_LN0_PORT1, \ + MG_CLKHUB_LN0_PORT2, \ + MG_CLKHUB_LN1_PORT1) +#define CFG_LOW_RATE_LKREN_EN (1 << 11) + +#define MG_TX_DCC_TX1LN0_PORT1 0x168110 +#define MG_TX_DCC_TX1LN1_PORT1 0x168510 +#define MG_TX_DCC_TX1LN0_PORT2 0x169110 +#define MG_TX_DCC_TX1LN1_PORT2 0x169510 +#define MG_TX_DCC_TX1LN0_PORT3 0x16A110 +#define MG_TX_DCC_TX1LN1_PORT3 0x16A510 +#define MG_TX_DCC_TX1LN0_PORT4 0x16B110 +#define MG_TX_DCC_TX1LN1_PORT4 0x16B510 +#define MG_TX1_DCC(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_DCC_TX1LN0_PORT1, \ + MG_TX_DCC_TX1LN0_PORT2, \ + MG_TX_DCC_TX1LN1_PORT1) +#define MG_TX_DCC_TX2LN0_PORT1 0x168090 +#define MG_TX_DCC_TX2LN1_PORT1 0x168490 +#define MG_TX_DCC_TX2LN0_PORT2 0x169090 +#define MG_TX_DCC_TX2LN1_PORT2 0x169490 +#define MG_TX_DCC_TX2LN0_PORT3 0x16A090 +#define MG_TX_DCC_TX2LN1_PORT3 0x16A490 +#define MG_TX_DCC_TX2LN0_PORT4 0x16B090 +#define MG_TX_DCC_TX2LN1_PORT4 0x16B490 +#define MG_TX2_DCC(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_TX_DCC_TX2LN0_PORT1, \ + MG_TX_DCC_TX2LN0_PORT2, \ + MG_TX_DCC_TX2LN1_PORT1) +#define CFG_AMI_CK_DIV_OVERRIDE_VAL(x) ((x) << 25) +#define CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK (0x3 << 25) +#define CFG_AMI_CK_DIV_OVERRIDE_EN (1 << 24) + +#define MG_DP_MODE_LN0_ACU_PORT1 0x1683A0 +#define MG_DP_MODE_LN1_ACU_PORT1 0x1687A0 +#define MG_DP_MODE_LN0_ACU_PORT2 0x1693A0 +#define MG_DP_MODE_LN1_ACU_PORT2 0x1697A0 +#define MG_DP_MODE_LN0_ACU_PORT3 0x16A3A0 +#define MG_DP_MODE_LN1_ACU_PORT3 0x16A7A0 +#define MG_DP_MODE_LN0_ACU_PORT4 0x16B3A0 +#define MG_DP_MODE_LN1_ACU_PORT4 0x16B7A0 +#define MG_DP_MODE(port, ln) \ + MG_PHY_PORT_LN(port, ln, MG_DP_MODE_LN0_ACU_PORT1, \ + MG_DP_MODE_LN0_ACU_PORT2, \ + MG_DP_MODE_LN1_ACU_PORT1) +#define MG_DP_MODE_CFG_DP_X2_MODE (1 << 7) +#define MG_DP_MODE_CFG_DP_X1_MODE (1 << 6) +#define MG_DP_MODE_CFG_TR2PWR_GATING (1 << 5) +#define MG_DP_MODE_CFG_TRPWR_GATING (1 << 4) +#define MG_DP_MODE_CFG_CLNPWR_GATING (1 << 3) +#define MG_DP_MODE_CFG_DIGPWR_GATING (1 << 2) +#define MG_DP_MODE_CFG_GAONPWR_GATING (1 << 1) + +#define MG_MISC_SUS0_PORT1 0x168814 +#define MG_MISC_SUS0_PORT2 0x169814 +#define MG_MISC_SUS0_PORT3 0x16A814 +#define MG_MISC_SUS0_PORT4 0x16B814 +#define MG_MISC_SUS0(tc_port) \ + _MMIO(_PORT(tc_port, MG_MISC_SUS0_PORT1, MG_MISC_SUS0_PORT2)) +#define MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK (3 << 14) +#define MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(x) ((x) << 14) +#define MG_MISC_SUS0_CFG_TR2PWR_GATING (1 << 12) +#define MG_MISC_SUS0_CFG_CL2PWR_GATING (1 << 11) +#define MG_MISC_SUS0_CFG_GAONPWR_GATING (1 << 10) +#define MG_MISC_SUS0_CFG_TRPWR_GATING (1 << 7) +#define MG_MISC_SUS0_CFG_CL1PWR_GATING (1 << 6) +#define MG_MISC_SUS0_CFG_DGPWR_GATING (1 << 5) /* The spec defines this only for BXT PHY0, but lets assume that this * would exist for PHY1 too if it had a second channel. @@ -3086,18 +3084,9 @@ enum i915_power_well_id { /* * GPIO regs */ -#define GPIOA _MMIO(0x5010) -#define GPIOB _MMIO(0x5014) -#define GPIOC _MMIO(0x5018) -#define GPIOD _MMIO(0x501c) -#define GPIOE _MMIO(0x5020) -#define GPIOF _MMIO(0x5024) -#define GPIOG _MMIO(0x5028) -#define GPIOH _MMIO(0x502c) -#define GPIOJ _MMIO(0x5034) -#define GPIOK _MMIO(0x5038) -#define GPIOL _MMIO(0x503C) -#define GPIOM _MMIO(0x5040) +#define GPIO(gpio) _MMIO(dev_priv->gpio_mmio_base + 0x5010 + \ + 4 * (gpio)) + # define GPIO_CLOCK_DIR_MASK (1 << 0) # define GPIO_CLOCK_DIR_IN (0 << 1) # define GPIO_CLOCK_DIR_OUT (1 << 1) @@ -5476,6 +5465,7 @@ enum { #define DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL (1 << 14) #define DP_AUX_CH_CTL_FS_DATA_AUX_REG_SKL (1 << 13) #define DP_AUX_CH_CTL_GTC_DATA_AUX_REG_SKL (1 << 12) +#define DP_AUX_CH_CTL_TBT_IO (1 << 11) #define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL_MASK (0x1f << 5) #define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(c) (((c) - 1) << 5) #define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) ((c) - 1) @@ -6527,7 +6517,7 @@ enum { #define PLANE_CTL_YUV422_UYVY (1 << 16) #define PLANE_CTL_YUV422_YVYU (2 << 16) #define PLANE_CTL_YUV422_VYUY (3 << 16) -#define PLANE_CTL_DECOMPRESSION_ENABLE (1 << 15) +#define PLANE_CTL_RENDER_DECOMPRESSION_ENABLE (1 << 15) #define PLANE_CTL_TRICKLE_FEED_DISABLE (1 << 14) #define PLANE_CTL_PLANE_GAMMA_DISABLE (1 << 13) /* Pre-GLK */ #define PLANE_CTL_TILED_MASK (0x7 << 10) @@ -7207,6 +7197,7 @@ enum { #define GEN11_TC3_HOTPLUG (1 << 18) #define GEN11_TC2_HOTPLUG (1 << 17) #define GEN11_TC1_HOTPLUG (1 << 16) +#define GEN11_TC_HOTPLUG(tc_port) (1 << ((tc_port) + 16)) #define GEN11_DE_TC_HOTPLUG_MASK (GEN11_TC4_HOTPLUG | \ GEN11_TC3_HOTPLUG | \ GEN11_TC2_HOTPLUG | \ @@ -7215,6 +7206,7 @@ enum { #define GEN11_TBT3_HOTPLUG (1 << 2) #define GEN11_TBT2_HOTPLUG (1 << 1) #define GEN11_TBT1_HOTPLUG (1 << 0) +#define GEN11_TBT_HOTPLUG(tc_port) (1 << (tc_port)) #define GEN11_DE_TBT_HOTPLUG_MASK (GEN11_TBT4_HOTPLUG | \ GEN11_TBT3_HOTPLUG | \ GEN11_TBT2_HOTPLUG | \ @@ -7490,6 +7482,8 @@ enum { /* PCH */ +#define PCH_DISPLAY_BASE 0xc0000u + /* south display engine interrupt: IBX */ #define SDE_AUDIO_POWER_D (1 << 27) #define SDE_AUDIO_POWER_C (1 << 26) @@ -7587,6 +7581,8 @@ enum { #define SDE_GMBUS_ICP (1 << 23) #define SDE_DDIB_HOTPLUG_ICP (1 << 17) #define SDE_DDIA_HOTPLUG_ICP (1 << 16) +#define SDE_TC_HOTPLUG_ICP(tc_port) (1 << ((tc_port) + 24)) +#define SDE_DDI_HOTPLUG_ICP(port) (1 << ((port) + 16)) #define SDE_DDI_MASK_ICP (SDE_DDIB_HOTPLUG_ICP | \ SDE_DDIA_HOTPLUG_ICP) #define SDE_TC_MASK_ICP (SDE_TC4_HOTPLUG_ICP | \ @@ -7782,20 +7778,6 @@ enum { #define ICP_TC_HPD_LONG_DETECT(tc_port) (2 << (tc_port) * 4) #define ICP_TC_HPD_SHORT_DETECT(tc_port) (1 << (tc_port) * 4) -#define PCH_GPIOA _MMIO(0xc5010) -#define PCH_GPIOB _MMIO(0xc5014) -#define PCH_GPIOC _MMIO(0xc5018) -#define PCH_GPIOD _MMIO(0xc501c) -#define PCH_GPIOE _MMIO(0xc5020) -#define PCH_GPIOF _MMIO(0xc5024) - -#define PCH_GMBUS0 _MMIO(0xc5100) -#define PCH_GMBUS1 _MMIO(0xc5104) -#define PCH_GMBUS2 _MMIO(0xc5108) -#define PCH_GMBUS3 _MMIO(0xc510c) -#define PCH_GMBUS4 _MMIO(0xc5110) -#define PCH_GMBUS5 _MMIO(0xc5120) - #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 #define PCH_DPLL(pll) _MMIO((pll) == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) @@ -8498,8 +8480,10 @@ enum { #define GEN6_PM_RP_DOWN_THRESHOLD (1 << 4) #define GEN6_PM_RP_UP_EI_EXPIRED (1 << 2) #define GEN6_PM_RP_DOWN_EI_EXPIRED (1 << 1) -#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \ - GEN6_PM_RP_DOWN_THRESHOLD | \ +#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_EI_EXPIRED | \ + GEN6_PM_RP_UP_THRESHOLD | \ + GEN6_PM_RP_DOWN_EI_EXPIRED | \ + GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) #define GEN7_GT_SCRATCH(i) _MMIO(0x4F100 + (i) * 4) @@ -8827,46 +8811,78 @@ enum { #define HSW_AUD_CHICKENBIT _MMIO(0x65f10) #define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) -/* HSW Power Wells */ -#define _HSW_PWR_WELL_CTL1 0x45400 -#define _HSW_PWR_WELL_CTL2 0x45404 -#define _HSW_PWR_WELL_CTL3 0x45408 -#define _HSW_PWR_WELL_CTL4 0x4540C - -#define _ICL_PWR_WELL_CTL_AUX1 0x45440 -#define _ICL_PWR_WELL_CTL_AUX2 0x45444 -#define _ICL_PWR_WELL_CTL_AUX4 0x4544C - -#define _ICL_PWR_WELL_CTL_DDI1 0x45450 -#define _ICL_PWR_WELL_CTL_DDI2 0x45454 -#define _ICL_PWR_WELL_CTL_DDI4 0x4545C - /* - * Each power well control register contains up to 16 (request, status) HW - * flag tuples. The register index and HW flag shift is determined by the - * power well ID (see i915_power_well_id). There are 4 possible sources of - * power well requests each source having its own set of control registers: - * BIOS, DRIVER, KVMR, DEBUG. + * HSW - ICL power wells + * + * Platforms have up to 3 power well control register sets, each set + * controlling up to 16 power wells via a request/status HW flag tuple: + * - main (HSW_PWR_WELL_CTL[1-4]) + * - AUX (ICL_PWR_WELL_CTL_AUX[1-4]) + * - DDI (ICL_PWR_WELL_CTL_DDI[1-4]) + * Each control register set consists of up to 4 registers used by different + * sources that can request a power well to be enabled: + * - BIOS (HSW_PWR_WELL_CTL1/ICL_PWR_WELL_CTL_AUX1/ICL_PWR_WELL_CTL_DDI1) + * - DRIVER (HSW_PWR_WELL_CTL2/ICL_PWR_WELL_CTL_AUX2/ICL_PWR_WELL_CTL_DDI2) + * - KVMR (HSW_PWR_WELL_CTL3) (only in the main register set) + * - DEBUG (HSW_PWR_WELL_CTL4/ICL_PWR_WELL_CTL_AUX4/ICL_PWR_WELL_CTL_DDI4) */ -#define _HSW_PW_REG_IDX(pw) ((pw) >> 4) -#define _HSW_PW_SHIFT(pw) (((pw) & 0xf) * 2) -#define HSW_PWR_WELL_CTL_BIOS(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL1, \ - _ICL_PWR_WELL_CTL_AUX1, \ - _ICL_PWR_WELL_CTL_DDI1)) -#define HSW_PWR_WELL_CTL_DRIVER(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL2, \ - _ICL_PWR_WELL_CTL_AUX2, \ - _ICL_PWR_WELL_CTL_DDI2)) -/* KVMR doesn't have a reg for AUX or DDI power well control */ -#define HSW_PWR_WELL_CTL_KVMR _MMIO(_HSW_PWR_WELL_CTL3) -#define HSW_PWR_WELL_CTL_DEBUG(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \ - _HSW_PWR_WELL_CTL4, \ - _ICL_PWR_WELL_CTL_AUX4, \ - _ICL_PWR_WELL_CTL_DDI4)) - -#define HSW_PWR_WELL_CTL_REQ(pw) (1 << (_HSW_PW_SHIFT(pw) + 1)) -#define HSW_PWR_WELL_CTL_STATE(pw) (1 << _HSW_PW_SHIFT(pw)) +#define HSW_PWR_WELL_CTL1 _MMIO(0x45400) +#define HSW_PWR_WELL_CTL2 _MMIO(0x45404) +#define HSW_PWR_WELL_CTL3 _MMIO(0x45408) +#define HSW_PWR_WELL_CTL4 _MMIO(0x4540C) +#define HSW_PWR_WELL_CTL_REQ(pw_idx) (0x2 << ((pw_idx) * 2)) +#define HSW_PWR_WELL_CTL_STATE(pw_idx) (0x1 << ((pw_idx) * 2)) + +/* HSW/BDW power well */ +#define HSW_PW_CTL_IDX_GLOBAL 15 + +/* SKL/BXT/GLK/CNL power wells */ +#define SKL_PW_CTL_IDX_PW_2 15 +#define SKL_PW_CTL_IDX_PW_1 14 +#define CNL_PW_CTL_IDX_AUX_F 12 +#define CNL_PW_CTL_IDX_AUX_D 11 +#define GLK_PW_CTL_IDX_AUX_C 10 +#define GLK_PW_CTL_IDX_AUX_B 9 +#define GLK_PW_CTL_IDX_AUX_A 8 +#define CNL_PW_CTL_IDX_DDI_F 6 +#define SKL_PW_CTL_IDX_DDI_D 4 +#define SKL_PW_CTL_IDX_DDI_C 3 +#define SKL_PW_CTL_IDX_DDI_B 2 +#define SKL_PW_CTL_IDX_DDI_A_E 1 +#define GLK_PW_CTL_IDX_DDI_A 1 +#define SKL_PW_CTL_IDX_MISC_IO 0 + +/* ICL - power wells */ +#define ICL_PW_CTL_IDX_PW_4 3 +#define ICL_PW_CTL_IDX_PW_3 2 +#define ICL_PW_CTL_IDX_PW_2 1 +#define ICL_PW_CTL_IDX_PW_1 0 + +#define ICL_PWR_WELL_CTL_AUX1 _MMIO(0x45440) +#define ICL_PWR_WELL_CTL_AUX2 _MMIO(0x45444) +#define ICL_PWR_WELL_CTL_AUX4 _MMIO(0x4544C) +#define ICL_PW_CTL_IDX_AUX_TBT4 11 +#define ICL_PW_CTL_IDX_AUX_TBT3 10 +#define ICL_PW_CTL_IDX_AUX_TBT2 9 +#define ICL_PW_CTL_IDX_AUX_TBT1 8 +#define ICL_PW_CTL_IDX_AUX_F 5 +#define ICL_PW_CTL_IDX_AUX_E 4 +#define ICL_PW_CTL_IDX_AUX_D 3 +#define ICL_PW_CTL_IDX_AUX_C 2 +#define ICL_PW_CTL_IDX_AUX_B 1 +#define ICL_PW_CTL_IDX_AUX_A 0 + +#define ICL_PWR_WELL_CTL_DDI1 _MMIO(0x45450) +#define ICL_PWR_WELL_CTL_DDI2 _MMIO(0x45454) +#define ICL_PWR_WELL_CTL_DDI4 _MMIO(0x4545C) +#define ICL_PW_CTL_IDX_DDI_F 5 +#define ICL_PW_CTL_IDX_DDI_E 4 +#define ICL_PW_CTL_IDX_DDI_D 3 +#define ICL_PW_CTL_IDX_DDI_C 2 +#define ICL_PW_CTL_IDX_DDI_B 1 +#define ICL_PW_CTL_IDX_DDI_A 0 + +/* HSW - power well misc debug registers */ #define HSW_PWR_WELL_CTL5 _MMIO(0x45410) #define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1 << 31) #define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1 << 20) @@ -8878,22 +8894,32 @@ enum skl_power_gate { SKL_PG0, SKL_PG1, SKL_PG2, + ICL_PG3, + ICL_PG4, }; #define SKL_FUSE_STATUS _MMIO(0x42000) #define SKL_FUSE_DOWNLOAD_STATUS (1 << 31) -/* PG0 (HW control->no power well ID), PG1..PG2 (SKL_DISP_PW1..SKL_DISP_PW2) */ -#define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) -/* PG0 (HW control->no power well ID), PG1..PG4 (ICL_DISP_PW1..ICL_DISP_PW4) */ -#define ICL_PW_TO_PG(pw) ((pw) - ICL_DISP_PW_1 + SKL_PG1) +/* + * PG0 is HW controlled, so doesn't have a corresponding power well control knob + * SKL_DISP_PW1_IDX..SKL_DISP_PW2_IDX -> PG1..PG2 + */ +#define SKL_PW_CTL_IDX_TO_PG(pw_idx) \ + ((pw_idx) - SKL_PW_CTL_IDX_PW_1 + SKL_PG1) +/* + * PG0 is HW controlled, so doesn't have a corresponding power well control knob + * ICL_DISP_PW1_IDX..ICL_DISP_PW4_IDX -> PG1..PG4 + */ +#define ICL_PW_CTL_IDX_TO_PG(pw_idx) \ + ((pw_idx) - ICL_PW_CTL_IDX_PW_1 + SKL_PG1) #define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) -#define _CNL_AUX_REG_IDX(pw) ((pw) - 9) +#define _CNL_AUX_REG_IDX(pw_idx) ((pw_idx) - GLK_PW_CTL_IDX_AUX_B) #define _CNL_AUX_ANAOVRD1_B 0x162250 #define _CNL_AUX_ANAOVRD1_C 0x162210 #define _CNL_AUX_ANAOVRD1_D 0x1622D0 #define _CNL_AUX_ANAOVRD1_F 0x162A90 -#define CNL_AUX_ANAOVRD1(pw) _MMIO(_PICK(_CNL_AUX_REG_IDX(pw), \ +#define CNL_AUX_ANAOVRD1(pw_idx) _MMIO(_PICK(_CNL_AUX_REG_IDX(pw_idx), \ _CNL_AUX_ANAOVRD1_B, \ _CNL_AUX_ANAOVRD1_C, \ _CNL_AUX_ANAOVRD1_D, \ @@ -9313,6 +9339,9 @@ enum skl_power_gate { #define DPCLKA_CFGCR0_ICL _MMIO(0x164280) #define DPCLKA_CFGCR0_DDI_CLK_OFF(port) (1 << ((port) == PORT_F ? 23 : \ (port) + 10)) +#define ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(port) (1 << ((port) + 10)) +#define ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port) (1 << ((tc_port) == PORT_TC4 ? \ + 21 : (tc_port) + 12)) #define DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port) ((port) == PORT_F ? 21 : \ (port) * 2) #define DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port) (3 << DPCLKA_CFGCR0_DDI_CLK_SEL_SHIFT(port)) @@ -9367,9 +9396,13 @@ enum skl_power_gate { #define MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK (0x1 << 16) #define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(x) ((x) << 14) #define MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK (0x3 << 14) -#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO(x) ((x) << 12) #define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK (0x3 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2 (0 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3 (1 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5 (2 << 12) +#define MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7 (3 << 12) #define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(x) ((x) << 8) +#define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT 8 #define MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK (0xf << 8) #define MG_CLKTOP2_HSCLKCTL(port) _MMIO_PORT((port) - PORT_C, \ _MG_CLKTOP2_HSCLKCTL_PORT1, \ @@ -9380,7 +9413,10 @@ enum skl_power_gate { #define _MG_PLL_DIV0_PORT3 0x16AA00 #define _MG_PLL_DIV0_PORT4 0x16BA00 #define MG_PLL_DIV0_FRACNEN_H (1 << 30) +#define MG_PLL_DIV0_FBDIV_FRAC_MASK (0x3fffff << 8) +#define MG_PLL_DIV0_FBDIV_FRAC_SHIFT 8 #define MG_PLL_DIV0_FBDIV_FRAC(x) ((x) << 8) +#define MG_PLL_DIV0_FBDIV_INT_MASK (0xff << 0) #define MG_PLL_DIV0_FBDIV_INT(x) ((x) << 0) #define MG_PLL_DIV0(port) _MMIO_PORT((port) - PORT_C, _MG_PLL_DIV0_PORT1, \ _MG_PLL_DIV0_PORT2) @@ -9395,6 +9431,7 @@ enum skl_power_gate { #define MG_PLL_DIV1_DITHER_DIV_4 (2 << 12) #define MG_PLL_DIV1_DITHER_DIV_8 (3 << 12) #define MG_PLL_DIV1_NDIVRATIO(x) ((x) << 4) +#define MG_PLL_DIV1_FBPREDIV_MASK (0xf << 0) #define MG_PLL_DIV1_FBPREDIV(x) ((x) << 0) #define MG_PLL_DIV1(port) _MMIO_PORT((port) - PORT_C, _MG_PLL_DIV1_PORT1, \ _MG_PLL_DIV1_PORT2) @@ -9549,6 +9586,54 @@ enum skl_power_gate { #define DC_STATE_DEBUG_MASK_CORES (1 << 0) #define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1) +#define BXT_P_CR_MC_BIOS_REQ_0_0_0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7114) +#define BXT_REQ_DATA_MASK 0x3F +#define BXT_DRAM_CHANNEL_ACTIVE_SHIFT 12 +#define BXT_DRAM_CHANNEL_ACTIVE_MASK (0xF << 12) +#define BXT_MEMORY_FREQ_MULTIPLIER_HZ 133333333 + +#define BXT_D_CR_DRP0_DUNIT8 0x1000 +#define BXT_D_CR_DRP0_DUNIT9 0x1200 +#define BXT_D_CR_DRP0_DUNIT_START 8 +#define BXT_D_CR_DRP0_DUNIT_END 11 +#define BXT_D_CR_DRP0_DUNIT(x) _MMIO(MCHBAR_MIRROR_BASE_SNB + \ + _PICK_EVEN((x) - 8, BXT_D_CR_DRP0_DUNIT8,\ + BXT_D_CR_DRP0_DUNIT9)) +#define BXT_DRAM_RANK_MASK 0x3 +#define BXT_DRAM_RANK_SINGLE 0x1 +#define BXT_DRAM_RANK_DUAL 0x3 +#define BXT_DRAM_WIDTH_MASK (0x3 << 4) +#define BXT_DRAM_WIDTH_SHIFT 4 +#define BXT_DRAM_WIDTH_X8 (0x0 << 4) +#define BXT_DRAM_WIDTH_X16 (0x1 << 4) +#define BXT_DRAM_WIDTH_X32 (0x2 << 4) +#define BXT_DRAM_WIDTH_X64 (0x3 << 4) +#define BXT_DRAM_SIZE_MASK (0x7 << 6) +#define BXT_DRAM_SIZE_SHIFT 6 +#define BXT_DRAM_SIZE_4GB (0x0 << 6) +#define BXT_DRAM_SIZE_6GB (0x1 << 6) +#define BXT_DRAM_SIZE_8GB (0x2 << 6) +#define BXT_DRAM_SIZE_12GB (0x3 << 6) +#define BXT_DRAM_SIZE_16GB (0x4 << 6) + +#define SKL_MEMORY_FREQ_MULTIPLIER_HZ 266666666 +#define SKL_MC_BIOS_DATA_0_0_0_MCHBAR_PCU _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5E04) +#define SKL_REQ_DATA_MASK (0xF << 0) + +#define SKL_MAD_DIMM_CH0_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) +#define SKL_MAD_DIMM_CH1_0_0_0_MCHBAR_MCMAIN _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5010) +#define SKL_DRAM_S_SHIFT 16 +#define SKL_DRAM_SIZE_MASK 0x3F +#define SKL_DRAM_WIDTH_MASK (0x3 << 8) +#define SKL_DRAM_WIDTH_SHIFT 8 +#define SKL_DRAM_WIDTH_X8 (0x0 << 8) +#define SKL_DRAM_WIDTH_X16 (0x1 << 8) +#define SKL_DRAM_WIDTH_X32 (0x2 << 8) +#define SKL_DRAM_RANK_MASK (0x1 << 10) +#define SKL_DRAM_RANK_SHIFT 10 +#define SKL_DRAM_RANK_SINGLE (0x0 << 10) +#define SKL_DRAM_RANK_DUAL (0x1 << 10) + /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, * since on HSW we can't write to it using I915_WRITE. */ #define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C) @@ -10197,6 +10282,12 @@ enum skl_power_gate { #define PREPARE_COUNT_SHIFT 0 #define PREPARE_COUNT_MASK (0x3f << 0) +#define _ICL_DSI_T_INIT_MASTER_0 0x6b088 +#define _ICL_DSI_T_INIT_MASTER_1 0x6b888 +#define ICL_DSI_T_INIT_MASTER(port) _MMIO_PORT(port, \ + _ICL_DSI_T_INIT_MASTER_0,\ + _ICL_DSI_T_INIT_MASTER_1) + /* bits 31:0 */ #define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084) #define _MIPIC_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884) @@ -10347,8 +10438,8 @@ enum skl_power_gate { #define ICL_PHY_MISC_DE_IO_COMP_PWR_DOWN (1 << 23) /* Icelake Display Stream Compression Registers */ -#define DSCA_PICTURE_PARAMETER_SET_0 0x6B200 -#define DSCC_PICTURE_PARAMETER_SET_0 0x6BA00 +#define DSCA_PICTURE_PARAMETER_SET_0 _MMIO(0x6B200) +#define DSCC_PICTURE_PARAMETER_SET_0 _MMIO(0x6BA00) #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PB 0x78270 #define _ICL_DSC1_PICTURE_PARAMETER_SET_0_PB 0x78370 #define _ICL_DSC0_PICTURE_PARAMETER_SET_0_PC 0x78470 @@ -10368,8 +10459,8 @@ enum skl_power_gate { #define DSC_VER_MIN_SHIFT 4 #define DSC_VER_MAJ (0x1 << 0) -#define DSCA_PICTURE_PARAMETER_SET_1 0x6B204 -#define DSCC_PICTURE_PARAMETER_SET_1 0x6BA04 +#define DSCA_PICTURE_PARAMETER_SET_1 _MMIO(0x6B204) +#define DSCC_PICTURE_PARAMETER_SET_1 _MMIO(0x6BA04) #define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PB 0x78274 #define _ICL_DSC1_PICTURE_PARAMETER_SET_1_PB 0x78374 #define _ICL_DSC0_PICTURE_PARAMETER_SET_1_PC 0x78474 @@ -10382,8 +10473,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_1_PC) #define DSC_BPP(bpp) ((bpp) << 0) -#define DSCA_PICTURE_PARAMETER_SET_2 0x6B208 -#define DSCC_PICTURE_PARAMETER_SET_2 0x6BA08 +#define DSCA_PICTURE_PARAMETER_SET_2 _MMIO(0x6B208) +#define DSCC_PICTURE_PARAMETER_SET_2 _MMIO(0x6BA08) #define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PB 0x78278 #define _ICL_DSC1_PICTURE_PARAMETER_SET_2_PB 0x78378 #define _ICL_DSC0_PICTURE_PARAMETER_SET_2_PC 0x78478 @@ -10397,8 +10488,8 @@ enum skl_power_gate { #define DSC_PIC_WIDTH(pic_width) ((pic_width) << 16) #define DSC_PIC_HEIGHT(pic_height) ((pic_height) << 0) -#define DSCA_PICTURE_PARAMETER_SET_3 0x6B20C -#define DSCC_PICTURE_PARAMETER_SET_3 0x6BA0C +#define DSCA_PICTURE_PARAMETER_SET_3 _MMIO(0x6B20C) +#define DSCC_PICTURE_PARAMETER_SET_3 _MMIO(0x6BA0C) #define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PB 0x7827C #define _ICL_DSC1_PICTURE_PARAMETER_SET_3_PB 0x7837C #define _ICL_DSC0_PICTURE_PARAMETER_SET_3_PC 0x7847C @@ -10412,8 +10503,8 @@ enum skl_power_gate { #define DSC_SLICE_WIDTH(slice_width) ((slice_width) << 16) #define DSC_SLICE_HEIGHT(slice_height) ((slice_height) << 0) -#define DSCA_PICTURE_PARAMETER_SET_4 0x6B210 -#define DSCC_PICTURE_PARAMETER_SET_4 0x6BA10 +#define DSCA_PICTURE_PARAMETER_SET_4 _MMIO(0x6B210) +#define DSCC_PICTURE_PARAMETER_SET_4 _MMIO(0x6BA10) #define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PB 0x78280 #define _ICL_DSC1_PICTURE_PARAMETER_SET_4_PB 0x78380 #define _ICL_DSC0_PICTURE_PARAMETER_SET_4_PC 0x78480 @@ -10427,8 +10518,8 @@ enum skl_power_gate { #define DSC_INITIAL_DEC_DELAY(dec_delay) ((dec_delay) << 16) #define DSC_INITIAL_XMIT_DELAY(xmit_delay) ((xmit_delay) << 0) -#define DSCA_PICTURE_PARAMETER_SET_5 0x6B214 -#define DSCC_PICTURE_PARAMETER_SET_5 0x6BA14 +#define DSCA_PICTURE_PARAMETER_SET_5 _MMIO(0x6B214) +#define DSCC_PICTURE_PARAMETER_SET_5 _MMIO(0x6BA14) #define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PB 0x78284 #define _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB 0x78384 #define _ICL_DSC0_PICTURE_PARAMETER_SET_5_PC 0x78484 @@ -10439,11 +10530,11 @@ enum skl_power_gate { #define ICL_DSC1_PICTURE_PARAMETER_SET_5(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ _ICL_DSC1_PICTURE_PARAMETER_SET_5_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_5_PC) -#define DSC_SCALE_DEC_INTINT(scale_dec) ((scale_dec) << 16) +#define DSC_SCALE_DEC_INT(scale_dec) ((scale_dec) << 16) #define DSC_SCALE_INC_INT(scale_inc) ((scale_inc) << 0) -#define DSCA_PICTURE_PARAMETER_SET_6 0x6B218 -#define DSCC_PICTURE_PARAMETER_SET_6 0x6BA18 +#define DSCA_PICTURE_PARAMETER_SET_6 _MMIO(0x6B218) +#define DSCC_PICTURE_PARAMETER_SET_6 _MMIO(0x6BA18) #define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PB 0x78288 #define _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB 0x78388 #define _ICL_DSC0_PICTURE_PARAMETER_SET_6_PC 0x78488 @@ -10454,13 +10545,13 @@ enum skl_power_gate { #define ICL_DSC1_PICTURE_PARAMETER_SET_6(pipe) _MMIO_PIPE((pipe) - PIPE_B, \ _ICL_DSC1_PICTURE_PARAMETER_SET_6_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_6_PC) -#define DSC_FLATNESS_MAX_QP(max_qp) (qp << 24) -#define DSC_FLATNESS_MIN_QP(min_qp) (qp << 16) +#define DSC_FLATNESS_MAX_QP(max_qp) ((max_qp) << 24) +#define DSC_FLATNESS_MIN_QP(min_qp) ((min_qp) << 16) #define DSC_FIRST_LINE_BPG_OFFSET(offset) ((offset) << 8) #define DSC_INITIAL_SCALE_VALUE(value) ((value) << 0) -#define DSCA_PICTURE_PARAMETER_SET_7 0x6B21C -#define DSCC_PICTURE_PARAMETER_SET_7 0x6BA1C +#define DSCA_PICTURE_PARAMETER_SET_7 _MMIO(0x6B21C) +#define DSCC_PICTURE_PARAMETER_SET_7 _MMIO(0x6BA1C) #define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PB 0x7828C #define _ICL_DSC1_PICTURE_PARAMETER_SET_7_PB 0x7838C #define _ICL_DSC0_PICTURE_PARAMETER_SET_7_PC 0x7848C @@ -10474,8 +10565,8 @@ enum skl_power_gate { #define DSC_NFL_BPG_OFFSET(bpg_offset) ((bpg_offset) << 16) #define DSC_SLICE_BPG_OFFSET(bpg_offset) ((bpg_offset) << 0) -#define DSCA_PICTURE_PARAMETER_SET_8 0x6B220 -#define DSCC_PICTURE_PARAMETER_SET_8 0x6BA20 +#define DSCA_PICTURE_PARAMETER_SET_8 _MMIO(0x6B220) +#define DSCC_PICTURE_PARAMETER_SET_8 _MMIO(0x6BA20) #define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PB 0x78290 #define _ICL_DSC1_PICTURE_PARAMETER_SET_8_PB 0x78390 #define _ICL_DSC0_PICTURE_PARAMETER_SET_8_PC 0x78490 @@ -10489,8 +10580,8 @@ enum skl_power_gate { #define DSC_INITIAL_OFFSET(initial_offset) ((initial_offset) << 16) #define DSC_FINAL_OFFSET(final_offset) ((final_offset) << 0) -#define DSCA_PICTURE_PARAMETER_SET_9 0x6B224 -#define DSCC_PICTURE_PARAMETER_SET_9 0x6BA24 +#define DSCA_PICTURE_PARAMETER_SET_9 _MMIO(0x6B224) +#define DSCC_PICTURE_PARAMETER_SET_9 _MMIO(0x6BA24) #define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PB 0x78294 #define _ICL_DSC1_PICTURE_PARAMETER_SET_9_PB 0x78394 #define _ICL_DSC0_PICTURE_PARAMETER_SET_9_PC 0x78494 @@ -10504,8 +10595,8 @@ enum skl_power_gate { #define DSC_RC_EDGE_FACTOR(rc_edge_fact) ((rc_edge_fact) << 16) #define DSC_RC_MODEL_SIZE(rc_model_size) ((rc_model_size) << 0) -#define DSCA_PICTURE_PARAMETER_SET_10 0x6B228 -#define DSCC_PICTURE_PARAMETER_SET_10 0x6BA28 +#define DSCA_PICTURE_PARAMETER_SET_10 _MMIO(0x6B228) +#define DSCC_PICTURE_PARAMETER_SET_10 _MMIO(0x6BA28) #define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PB 0x78298 #define _ICL_DSC1_PICTURE_PARAMETER_SET_10_PB 0x78398 #define _ICL_DSC0_PICTURE_PARAMETER_SET_10_PC 0x78498 @@ -10521,8 +10612,8 @@ enum skl_power_gate { #define DSC_RC_QUANT_INC_LIMIT1(lim) ((lim) << 8) #define DSC_RC_QUANT_INC_LIMIT0(lim) ((lim) << 0) -#define DSCA_PICTURE_PARAMETER_SET_11 0x6B22C -#define DSCC_PICTURE_PARAMETER_SET_11 0x6BA2C +#define DSCA_PICTURE_PARAMETER_SET_11 _MMIO(0x6B22C) +#define DSCC_PICTURE_PARAMETER_SET_11 _MMIO(0x6BA2C) #define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PB 0x7829C #define _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB 0x7839C #define _ICL_DSC0_PICTURE_PARAMETER_SET_11_PC 0x7849C @@ -10534,8 +10625,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_11_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_11_PC) -#define DSCA_PICTURE_PARAMETER_SET_12 0x6B260 -#define DSCC_PICTURE_PARAMETER_SET_12 0x6BA60 +#define DSCA_PICTURE_PARAMETER_SET_12 _MMIO(0x6B260) +#define DSCC_PICTURE_PARAMETER_SET_12 _MMIO(0x6BA60) #define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PB 0x782A0 #define _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB 0x783A0 #define _ICL_DSC0_PICTURE_PARAMETER_SET_12_PC 0x784A0 @@ -10547,8 +10638,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_12_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_12_PC) -#define DSCA_PICTURE_PARAMETER_SET_13 0x6B264 -#define DSCC_PICTURE_PARAMETER_SET_13 0x6BA64 +#define DSCA_PICTURE_PARAMETER_SET_13 _MMIO(0x6B264) +#define DSCC_PICTURE_PARAMETER_SET_13 _MMIO(0x6BA64) #define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PB 0x782A4 #define _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB 0x783A4 #define _ICL_DSC0_PICTURE_PARAMETER_SET_13_PC 0x784A4 @@ -10560,8 +10651,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_13_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_13_PC) -#define DSCA_PICTURE_PARAMETER_SET_14 0x6B268 -#define DSCC_PICTURE_PARAMETER_SET_14 0x6BA68 +#define DSCA_PICTURE_PARAMETER_SET_14 _MMIO(0x6B268) +#define DSCC_PICTURE_PARAMETER_SET_14 _MMIO(0x6BA68) #define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PB 0x782A8 #define _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB 0x783A8 #define _ICL_DSC0_PICTURE_PARAMETER_SET_14_PC 0x784A8 @@ -10573,8 +10664,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_14_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_14_PC) -#define DSCA_PICTURE_PARAMETER_SET_15 0x6B26C -#define DSCC_PICTURE_PARAMETER_SET_15 0x6BA6C +#define DSCA_PICTURE_PARAMETER_SET_15 _MMIO(0x6B26C) +#define DSCC_PICTURE_PARAMETER_SET_15 _MMIO(0x6BA6C) #define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PB 0x782AC #define _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB 0x783AC #define _ICL_DSC0_PICTURE_PARAMETER_SET_15_PC 0x784AC @@ -10586,8 +10677,8 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_15_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_15_PC) -#define DSCA_PICTURE_PARAMETER_SET_16 0x6B270 -#define DSCC_PICTURE_PARAMETER_SET_16 0x6BA70 +#define DSCA_PICTURE_PARAMETER_SET_16 _MMIO(0x6B270) +#define DSCC_PICTURE_PARAMETER_SET_16 _MMIO(0x6BA70) #define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PB 0x782B0 #define _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB 0x783B0 #define _ICL_DSC0_PICTURE_PARAMETER_SET_16_PC 0x784B0 @@ -10599,7 +10690,7 @@ enum skl_power_gate { _ICL_DSC1_PICTURE_PARAMETER_SET_16_PB, \ _ICL_DSC1_PICTURE_PARAMETER_SET_16_PC) #define DSC_SLICE_PER_LINE(slice_per_line) ((slice_per_line) << 16) -#define DSC_SLICE_CHUNK_SIZE(slice_chunk_aize) (slice_chunk_size << 0) +#define DSC_SLICE_CHUNK_SIZE(slice_chunk_size) ((slice_chunk_size) << 0) /* Icelake Rate Control Buffer Threshold Registers */ #define DSCA_RC_BUF_THRESH_0 _MMIO(0x6B230) @@ -10652,4 +10743,17 @@ enum skl_power_gate { _ICL_DSC1_RC_BUF_THRESH_1_UDW_PB, \ _ICL_DSC1_RC_BUF_THRESH_1_UDW_PC) +#define PORT_TX_DFLEXDPSP _MMIO(0x1638A0) +#define TC_LIVE_STATE_TBT(tc_port) (1 << ((tc_port) * 8 + 6)) +#define TC_LIVE_STATE_TC(tc_port) (1 << ((tc_port) * 8 + 5)) +#define DP_LANE_ASSIGNMENT_SHIFT(tc_port) ((tc_port) * 8) +#define DP_LANE_ASSIGNMENT_MASK(tc_port) (0xf << ((tc_port) * 8)) +#define DP_LANE_ASSIGNMENT(tc_port, x) ((x) << ((tc_port) * 8)) + +#define PORT_TX_DFLEXDPPMS _MMIO(0x163890) +#define DP_PHY_MODE_STATUS_COMPLETED(tc_port) (1 << (tc_port)) + +#define PORT_TX_DFLEXDPCSSS _MMIO(0x163894) +#define DP_PHY_MODE_STATUS_NOT_SAFE(tc_port) (1 << (tc_port)) + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 5c2c93cbab12..a492385b2089 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -527,7 +527,7 @@ void __i915_request_submit(struct i915_request *request) seqno = timeline_get_seqno(&engine->timeline); GEM_BUG_ON(!seqno); - GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), seqno)); + GEM_BUG_ON(intel_engine_signaled(engine, seqno)); /* We may be recursing from the signal callback of another i915 fence */ spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING); @@ -579,8 +579,7 @@ void __i915_request_unsubmit(struct i915_request *request) */ GEM_BUG_ON(!request->global_seqno); GEM_BUG_ON(request->global_seqno != engine->timeline.seqno); - GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), - request->global_seqno)); + GEM_BUG_ON(intel_engine_has_completed(engine, request->global_seqno)); engine->timeline.seqno--; /* We may be recursing from the signal callback of another i915 fence */ @@ -733,13 +732,13 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) rq = kmem_cache_alloc(i915->requests, GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); if (unlikely(!rq)) { + i915_retire_requests(i915); + /* Ratelimit ourselves to prevent oom from malicious clients */ - ret = i915_gem_wait_for_idle(i915, - I915_WAIT_LOCKED | - I915_WAIT_INTERRUPTIBLE, - MAX_SCHEDULE_TIMEOUT); - if (ret) - goto err_unreserve; + rq = i915_gem_active_raw(&ce->ring->timeline->last_request, + &i915->drm.struct_mutex); + if (rq) + cond_synchronize_rcu(rq->rcustate); /* * We've forced the client to stall and catch up with whatever @@ -759,6 +758,8 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) } } + rq->rcustate = get_state_synchronize_rcu(); + INIT_LIST_HEAD(&rq->active_list); rq->i915 = i915; rq->engine = engine; @@ -1205,7 +1206,7 @@ static bool __i915_spin_request(const struct i915_request *rq, * it is a fair assumption that it will not complete within our * relatively short timeout. */ - if (!i915_seqno_passed(intel_engine_get_seqno(engine), seqno - 1)) + if (!intel_engine_has_started(engine, seqno)) return false; /* @@ -1222,7 +1223,7 @@ static bool __i915_spin_request(const struct i915_request *rq, irq = READ_ONCE(engine->breadcrumbs.irq_count); timeout_us += local_clock_us(&cpu); do { - if (i915_seqno_passed(intel_engine_get_seqno(engine), seqno)) + if (intel_engine_has_completed(engine, seqno)) return seqno == i915_request_global_seqno(rq); /* diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index e1c9365dfefb..7fa94b024968 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -101,6 +101,14 @@ struct i915_request { struct intel_signal_node signaling; /* + * The rcu epoch of when this request was allocated. Used to judiciously + * apply backpressure on future allocations to ensure that under + * mempressure there is sufficient RCU ticks for us to reclaim our + * RCU protected slabs. + */ + unsigned long rcustate; + + /* * Fences for the various phases in the request's lifetime. * * The submit fence is used to await upon all of the request's @@ -272,7 +280,10 @@ long i915_request_wait(struct i915_request *rq, #define I915_WAIT_ALL BIT(2) /* used by i915_gem_object_wait() */ #define I915_WAIT_FOR_IDLE_BOOST BIT(3) -static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine); +static inline bool intel_engine_has_started(struct intel_engine_cs *engine, + u32 seqno); +static inline bool intel_engine_has_completed(struct intel_engine_cs *engine, + u32 seqno); /** * Returns true if seq1 is later than seq2. @@ -282,11 +293,31 @@ static inline bool i915_seqno_passed(u32 seq1, u32 seq2) return (s32)(seq1 - seq2) >= 0; } +/** + * i915_request_started - check if the request has begun being executed + * @rq: the request + * + * Returns true if the request has been submitted to hardware, and the hardware + * has advanced passed the end of the previous request and so should be either + * currently processing the request (though it may be preempted and so + * not necessarily the next request to complete) or have completed the request. + */ +static inline bool i915_request_started(const struct i915_request *rq) +{ + u32 seqno; + + seqno = i915_request_global_seqno(rq); + if (!seqno) /* not yet submitted to HW */ + return false; + + return intel_engine_has_started(rq->engine, seqno); +} + static inline bool __i915_request_completed(const struct i915_request *rq, u32 seqno) { GEM_BUG_ON(!seqno); - return i915_seqno_passed(intel_engine_get_seqno(rq->engine), seqno) && + return intel_engine_has_completed(rq->engine, seqno) && seqno == i915_request_global_seqno(rq); } @@ -301,18 +332,6 @@ static inline bool i915_request_completed(const struct i915_request *rq) return __i915_request_completed(rq, seqno); } -static inline bool i915_request_started(const struct i915_request *rq) -{ - u32 seqno; - - seqno = i915_request_global_seqno(rq); - if (!seqno) - return false; - - return i915_seqno_passed(intel_engine_get_seqno(rq->engine), - seqno - 1); -} - static inline bool i915_sched_node_signaled(const struct i915_sched_node *node) { const struct i915_request *rq = diff --git a/drivers/gpu/drm/i915/i915_sw_fence.c b/drivers/gpu/drm/i915/i915_sw_fence.c index 1de5173e53a2..6dbeed079ae5 100644 --- a/drivers/gpu/drm/i915/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/i915_sw_fence.c @@ -24,13 +24,13 @@ enum { DEBUG_FENCE_NOTIFY, }; -#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS - static void *i915_sw_fence_debug_hint(void *addr) { return (void *)(((struct i915_sw_fence *)addr)->flags & I915_SW_FENCE_MASK); } +#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS + static struct debug_obj_descr i915_sw_fence_debug_descr = { .name = "i915_sw_fence", .debug_hint = i915_sw_fence_debug_hint, @@ -393,10 +393,11 @@ static void timer_i915_sw_fence_wake(struct timer_list *t) if (!fence) return; - pr_warn("asynchronous wait on fence %s:%s:%x timed out\n", - cb->dma->ops->get_driver_name(cb->dma), - cb->dma->ops->get_timeline_name(cb->dma), - cb->dma->seqno); + pr_notice("Asynchronous wait on fence %s:%s:%x timed out (hint:%pS)\n", + cb->dma->ops->get_driver_name(cb->dma), + cb->dma->ops->get_timeline_name(cb->dma), + cb->dma->seqno, + i915_sw_fence_debug_hint(fence)); i915_sw_fence_complete(fence); } diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 98358b4b36de..31efc971a3a8 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -405,7 +405,7 @@ void i915_vma_unpin_iomap(struct i915_vma *vma) i915_vma_unpin(vma); } -void i915_vma_unpin_and_release(struct i915_vma **p_vma) +void i915_vma_unpin_and_release(struct i915_vma **p_vma, unsigned int flags) { struct i915_vma *vma; struct drm_i915_gem_object *obj; @@ -420,6 +420,9 @@ void i915_vma_unpin_and_release(struct i915_vma **p_vma) i915_vma_unpin(vma); i915_vma_close(vma); + if (flags & I915_VMA_RELEASE_MAP) + i915_gem_object_unpin_map(obj); + __i915_gem_object_release_unless_active(obj); } diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h index f06d66377107..4f7c1c7599f4 100644 --- a/drivers/gpu/drm/i915/i915_vma.h +++ b/drivers/gpu/drm/i915/i915_vma.h @@ -138,7 +138,8 @@ i915_vma_instance(struct drm_i915_gem_object *obj, struct i915_address_space *vm, const struct i915_ggtt_view *view); -void i915_vma_unpin_and_release(struct i915_vma **p_vma); +void i915_vma_unpin_and_release(struct i915_vma **p_vma, unsigned int flags); +#define I915_VMA_RELEASE_MAP BIT(0) static inline bool i915_vma_is_active(struct i915_vma *vma) { @@ -207,6 +208,11 @@ static inline u32 i915_ggtt_offset(const struct i915_vma *vma) return lower_32_bits(vma->node.start); } +static inline u32 i915_ggtt_pin_bias(struct i915_vma *vma) +{ + return i915_vm_to_ggtt(vma->vm)->pin_bias; +} + static inline struct i915_vma *i915_vma_get(struct i915_vma *vma) { i915_gem_object_get(vma->obj); @@ -245,6 +251,8 @@ i915_vma_compare(struct i915_vma *vma, if (cmp) return cmp; + assert_i915_gem_gtt_types(); + /* ggtt_view.type also encodes its size so that we both distinguish * different views using it as a "type" and also use a compact (no * accessing of uninitialised padding bytes) memcmp without storing diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index dcba645cabb8..aabebe0d2e9b 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -113,69 +113,18 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ struct intel_plane_state *intel_state) { struct drm_plane *plane = intel_state->base.plane; - struct drm_i915_private *dev_priv = to_i915(plane->dev); struct drm_plane_state *state = &intel_state->base; struct intel_plane *intel_plane = to_intel_plane(plane); - const struct drm_display_mode *adjusted_mode = - &crtc_state->base.adjusted_mode; int ret; if (!intel_state->base.crtc && !old_plane_state->base.crtc) return 0; - if (state->fb && drm_rotation_90_or_270(state->rotation)) { - struct drm_format_name_buf format_name; - - if (state->fb->modifier != I915_FORMAT_MOD_Y_TILED && - state->fb->modifier != I915_FORMAT_MOD_Yf_TILED) { - DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); - return -EINVAL; - } - - /* - * 90/270 is not allowed with RGB64 16:16:16:16, - * RGB 16-bit 5:6:5, and Indexed 8-bit. - * TBD: Add RGB64 case once its added in supported format list. - */ - switch (state->fb->format->format) { - case DRM_FORMAT_C8: - case DRM_FORMAT_RGB565: - DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", - drm_get_format_name(state->fb->format->format, - &format_name)); - return -EINVAL; - - default: - break; - } - } - - /* CHV ignores the mirror bit when the rotate bit is set :( */ - if (IS_CHERRYVIEW(dev_priv) && - state->rotation & DRM_MODE_ROTATE_180 && - state->rotation & DRM_MODE_REFLECT_X) { - DRM_DEBUG_KMS("Cannot rotate and reflect at the same time\n"); - return -EINVAL; - } - intel_state->base.visible = false; - ret = intel_plane->check_plane(intel_plane, crtc_state, intel_state); + ret = intel_plane->check_plane(crtc_state, intel_state); if (ret) return ret; - /* - * Y-tiling is not supported in IF-ID Interlace mode in - * GEN9 and above. - */ - if (state->fb && INTEL_GEN(dev_priv) >= 9 && crtc_state->base.enable && - adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { - if (state->fb->modifier == I915_FORMAT_MOD_Y_TILED || - state->fb->modifier == I915_FORMAT_MOD_Yf_TILED) { - DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n"); - return -EINVAL; - } - } - /* FIXME pre-g4x don't work like this */ if (state->visible) crtc_state->active_planes |= BIT(intel_plane->id); diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c index 1db6ba7d926e..84bf8d827136 100644 --- a/drivers/gpu/drm/i915/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c @@ -256,8 +256,7 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) spin_unlock(&b->irq_lock); rbtree_postorder_for_each_entry_safe(wait, n, &b->waiters, node) { - GEM_BUG_ON(!i915_seqno_passed(intel_engine_get_seqno(engine), - wait->seqno)); + GEM_BUG_ON(!intel_engine_signaled(engine, wait->seqno)); RB_CLEAR_NODE(&wait->node); wake_up_process(wait->tsk); } @@ -508,8 +507,7 @@ bool intel_engine_add_wait(struct intel_engine_cs *engine, return armed; /* Make the caller recheck if its request has already started. */ - return i915_seqno_passed(intel_engine_get_seqno(engine), - wait->seqno - 1); + return intel_engine_has_started(engine, wait->seqno); } static inline bool chain_wakeup(struct rb_node *rb, int priority) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index cf9b600cca79..d48186e9ddad 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -34,6 +34,10 @@ * low-power state and comes back to normal. */ +#define I915_CSR_ICL "i915/icl_dmc_ver1_07.bin" +MODULE_FIRMWARE(I915_CSR_ICL); +#define ICL_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) + #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin" MODULE_FIRMWARE(I915_CSR_GLK); #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4) @@ -55,7 +59,9 @@ MODULE_FIRMWARE(I915_CSR_BXT); #define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7) -#define CSR_MAX_FW_SIZE 0x2FFF +#define BXT_CSR_MAX_FW_SIZE 0x3000 +#define GLK_CSR_MAX_FW_SIZE 0x4000 +#define ICL_CSR_MAX_FW_SIZE 0x6000 #define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF struct intel_css_header { @@ -279,6 +285,7 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, struct intel_csr *csr = &dev_priv->csr; const struct stepping_info *si = intel_get_stepping_info(dev_priv); uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; + uint32_t max_fw_size = 0; uint32_t i; uint32_t *dmc_payload; uint32_t required_version; @@ -301,6 +308,8 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, if (csr->fw_path == i915_modparams.dmc_firmware_path) { /* Bypass version check for firmware override. */ required_version = csr->version; + } else if (IS_ICELAKE(dev_priv)) { + required_version = ICL_CSR_VERSION_REQUIRED; } else if (IS_CANNONLAKE(dev_priv)) { required_version = CNL_CSR_VERSION_REQUIRED; } else if (IS_GEMINILAKE(dev_priv)) { @@ -359,6 +368,8 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, si->stepping); return NULL; } + /* Convert dmc_offset into number of bytes. By default it is in dwords*/ + dmc_offset *= 4; readcount += dmc_offset; /* Extract dmc_header information. */ @@ -391,8 +402,16 @@ static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ nbytes = dmc_header->fw_size * 4; - if (nbytes > CSR_MAX_FW_SIZE) { - DRM_ERROR("DMC firmware too big (%u bytes)\n", nbytes); + if (INTEL_GEN(dev_priv) >= 11) + max_fw_size = ICL_CSR_MAX_FW_SIZE; + else if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) + max_fw_size = GLK_CSR_MAX_FW_SIZE; + else if (IS_GEN9(dev_priv)) + max_fw_size = BXT_CSR_MAX_FW_SIZE; + else + MISSING_CASE(INTEL_REVID(dev_priv)); + if (nbytes > max_fw_size) { + DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes); return NULL; } csr->dmc_fw_size = dmc_header->fw_size; @@ -458,6 +477,8 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) if (i915_modparams.dmc_firmware_path) csr->fw_path = i915_modparams.dmc_firmware_path; + else if (IS_ICELAKE(dev_priv)) + csr->fw_path = I915_CSR_ICL; else if (IS_CANNONLAKE(dev_priv)) csr->fw_path = I915_CSR_CNL; else if (IS_GEMINILAKE(dev_priv)) @@ -468,12 +489,6 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) csr->fw_path = I915_CSR_SKL; else if (IS_BROXTON(dev_priv)) csr->fw_path = I915_CSR_BXT; - else { - DRM_ERROR("Unexpected: no known CSR firmware for platform\n"); - return; - } - - DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); /* * Obtain a runtime pm reference, until CSR is loaded, @@ -481,6 +496,14 @@ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) */ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + if (csr->fw_path == NULL) { + DRM_DEBUG_KMS("No known CSR firmware for platform, disabling runtime PM\n"); + WARN_ON(!IS_ALPHA_SUPPORT(INTEL_INFO(dev_priv))); + + return; + } + + DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); schedule_work(&dev_priv->csr.work); } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c9af34861d9e..5186cd7075f9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -916,7 +916,7 @@ static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port por level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; if (IS_ICELAKE(dev_priv)) { - if (port == PORT_A || port == PORT_B) + if (intel_port_is_combophy(dev_priv, port)) icl_get_combo_buf_trans(dev_priv, port, INTEL_OUTPUT_HDMI, &n_entries); else @@ -1414,7 +1414,7 @@ static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv, break; } - ref_clock = dev_priv->cdclk.hw.ref; + ref_clock = cnl_hdmi_pll_ref_clock(dev_priv); dco_freq = (cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) * ref_clock; @@ -1427,6 +1427,81 @@ static int cnl_calc_wrpll_link(struct drm_i915_private *dev_priv, return dco_freq / (p0 * p1 * p2 * 5); } +static int icl_calc_tbt_pll_link(struct drm_i915_private *dev_priv, + enum port port) +{ + u32 val = I915_READ(DDI_CLK_SEL(port)) & DDI_CLK_SEL_MASK; + + switch (val) { + case DDI_CLK_SEL_NONE: + return 0; + case DDI_CLK_SEL_TBT_162: + return 162000; + case DDI_CLK_SEL_TBT_270: + return 270000; + case DDI_CLK_SEL_TBT_540: + return 540000; + case DDI_CLK_SEL_TBT_810: + return 810000; + default: + MISSING_CASE(val); + return 0; + } +} + +static int icl_calc_mg_pll_link(struct drm_i915_private *dev_priv, + enum port port) +{ + u32 mg_pll_div0, mg_clktop_hsclkctl; + u32 m1, m2_int, m2_frac, div1, div2, refclk; + u64 tmp; + + refclk = dev_priv->cdclk.hw.ref; + + mg_pll_div0 = I915_READ(MG_PLL_DIV0(port)); + mg_clktop_hsclkctl = I915_READ(MG_CLKTOP2_HSCLKCTL(port)); + + m1 = I915_READ(MG_PLL_DIV1(port)) & MG_PLL_DIV1_FBPREDIV_MASK; + m2_int = mg_pll_div0 & MG_PLL_DIV0_FBDIV_INT_MASK; + m2_frac = (mg_pll_div0 & MG_PLL_DIV0_FRACNEN_H) ? + (mg_pll_div0 & MG_PLL_DIV0_FBDIV_FRAC_MASK) >> + MG_PLL_DIV0_FBDIV_FRAC_SHIFT : 0; + + switch (mg_clktop_hsclkctl & MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK) { + case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2: + div1 = 2; + break; + case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3: + div1 = 3; + break; + case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5: + div1 = 5; + break; + case MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7: + div1 = 7; + break; + default: + MISSING_CASE(mg_clktop_hsclkctl); + return 0; + } + + div2 = (mg_clktop_hsclkctl & MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK) >> + MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_SHIFT; + /* div2 value of 0 is same as 1 means no div */ + if (div2 == 0) + div2 = 1; + + /* + * Adjust the original formula to delay the division by 2^22 in order to + * minimize possible rounding errors. + */ + tmp = (u64)m1 * m2_int * refclk + + (((u64)m1 * m2_frac * refclk) >> 22); + tmp = div_u64(tmp, 5 * div1 * div2); + + return tmp; +} + static void ddi_dotclock_get(struct intel_crtc_state *pipe_config) { int dotclock; @@ -1460,15 +1535,17 @@ static void icl_ddi_clock_get(struct intel_encoder *encoder, uint32_t pll_id; pll_id = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll); - if (port == PORT_A || port == PORT_B) { + if (intel_port_is_combophy(dev_priv, port)) { if (intel_crtc_has_type(pipe_config, INTEL_OUTPUT_HDMI)) link_clock = cnl_calc_wrpll_link(dev_priv, pll_id); else link_clock = icl_calc_dp_combo_pll_link(dev_priv, pll_id); } else { - /* FIXME - Add for MG PLL */ - WARN(1, "MG PLL clock_get code not implemented yet\n"); + if (pll_id == DPLL_ID_ICL_TBTPLL) + link_clock = icl_calc_tbt_pll_link(dev_priv, port); + else + link_clock = icl_calc_mg_pll_link(dev_priv, port); } pipe_config->port_clock = link_clock; @@ -2000,7 +2077,7 @@ out: static inline enum intel_display_power_domain intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp) { - /* CNL HW requires corresponding AUX IOs to be powered up for PSR with + /* CNL+ HW requires corresponding AUX IOs to be powered up for PSR with * DC states enabled at the same time, while for driver initiated AUX * transfers we need the same AUX IOs to be powered but with DC states * disabled. Accordingly use the AUX power domain here which leaves DC @@ -2158,7 +2235,7 @@ u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder) int n_entries; if (IS_ICELAKE(dev_priv)) { - if (port == PORT_A || port == PORT_B) + if (intel_port_is_combophy(dev_priv, port)) icl_get_combo_buf_trans(dev_priv, port, encoder->type, &n_entries); else @@ -2468,16 +2545,137 @@ static void icl_combo_phy_ddi_vswing_sequence(struct intel_encoder *encoder, I915_WRITE(ICL_PORT_TX_DW5_GRP(port), val); } -static void icl_ddi_vswing_sequence(struct intel_encoder *encoder, u32 level, +static void icl_mg_phy_ddi_vswing_sequence(struct intel_encoder *encoder, + int link_clock, + u32 level) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = encoder->port; + const struct icl_mg_phy_ddi_buf_trans *ddi_translations; + u32 n_entries, val; + int ln; + + n_entries = ARRAY_SIZE(icl_mg_phy_ddi_translations); + ddi_translations = icl_mg_phy_ddi_translations; + /* The table does not have values for level 3 and level 9. */ + if (level >= n_entries || level == 3 || level == 9) { + DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.", + level, n_entries - 2); + level = n_entries - 2; + } + + /* Set MG_TX_LINK_PARAMS cri_use_fs32 to 0. */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_TX1_LINK_PARAMS(port, ln)); + val &= ~CRI_USE_FS32; + I915_WRITE(MG_TX1_LINK_PARAMS(port, ln), val); + + val = I915_READ(MG_TX2_LINK_PARAMS(port, ln)); + val &= ~CRI_USE_FS32; + I915_WRITE(MG_TX2_LINK_PARAMS(port, ln), val); + } + + /* Program MG_TX_SWINGCTRL with values from vswing table */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_TX1_SWINGCTRL(port, ln)); + val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK; + val |= CRI_TXDEEMPH_OVERRIDE_17_12( + ddi_translations[level].cri_txdeemph_override_17_12); + I915_WRITE(MG_TX1_SWINGCTRL(port, ln), val); + + val = I915_READ(MG_TX2_SWINGCTRL(port, ln)); + val &= ~CRI_TXDEEMPH_OVERRIDE_17_12_MASK; + val |= CRI_TXDEEMPH_OVERRIDE_17_12( + ddi_translations[level].cri_txdeemph_override_17_12); + I915_WRITE(MG_TX2_SWINGCTRL(port, ln), val); + } + + /* Program MG_TX_DRVCTRL with values from vswing table */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_TX1_DRVCTRL(port, ln)); + val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK | + CRI_TXDEEMPH_OVERRIDE_5_0_MASK); + val |= CRI_TXDEEMPH_OVERRIDE_5_0( + ddi_translations[level].cri_txdeemph_override_5_0) | + CRI_TXDEEMPH_OVERRIDE_11_6( + ddi_translations[level].cri_txdeemph_override_11_6) | + CRI_TXDEEMPH_OVERRIDE_EN; + I915_WRITE(MG_TX1_DRVCTRL(port, ln), val); + + val = I915_READ(MG_TX2_DRVCTRL(port, ln)); + val &= ~(CRI_TXDEEMPH_OVERRIDE_11_6_MASK | + CRI_TXDEEMPH_OVERRIDE_5_0_MASK); + val |= CRI_TXDEEMPH_OVERRIDE_5_0( + ddi_translations[level].cri_txdeemph_override_5_0) | + CRI_TXDEEMPH_OVERRIDE_11_6( + ddi_translations[level].cri_txdeemph_override_11_6) | + CRI_TXDEEMPH_OVERRIDE_EN; + I915_WRITE(MG_TX2_DRVCTRL(port, ln), val); + + /* FIXME: Program CRI_LOADGEN_SEL after the spec is updated */ + } + + /* + * Program MG_CLKHUB<LN, port being used> with value from frequency table + * In case of Legacy mode on MG PHY, both TX1 and TX2 enabled so use the + * values from table for which TX1 and TX2 enabled. + */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_CLKHUB(port, ln)); + if (link_clock < 300000) + val |= CFG_LOW_RATE_LKREN_EN; + else + val &= ~CFG_LOW_RATE_LKREN_EN; + I915_WRITE(MG_CLKHUB(port, ln), val); + } + + /* Program the MG_TX_DCC<LN, port being used> based on the link frequency */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_TX1_DCC(port, ln)); + val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK; + if (link_clock <= 500000) { + val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN; + } else { + val |= CFG_AMI_CK_DIV_OVERRIDE_EN | + CFG_AMI_CK_DIV_OVERRIDE_VAL(1); + } + I915_WRITE(MG_TX1_DCC(port, ln), val); + + val = I915_READ(MG_TX2_DCC(port, ln)); + val &= ~CFG_AMI_CK_DIV_OVERRIDE_VAL_MASK; + if (link_clock <= 500000) { + val &= ~CFG_AMI_CK_DIV_OVERRIDE_EN; + } else { + val |= CFG_AMI_CK_DIV_OVERRIDE_EN | + CFG_AMI_CK_DIV_OVERRIDE_VAL(1); + } + I915_WRITE(MG_TX2_DCC(port, ln), val); + } + + /* Program MG_TX_PISO_READLOAD with values from vswing table */ + for (ln = 0; ln < 2; ln++) { + val = I915_READ(MG_TX1_PISO_READLOAD(port, ln)); + val |= CRI_CALCINIT; + I915_WRITE(MG_TX1_PISO_READLOAD(port, ln), val); + + val = I915_READ(MG_TX2_PISO_READLOAD(port, ln)); + val |= CRI_CALCINIT; + I915_WRITE(MG_TX2_PISO_READLOAD(port, ln), val); + } +} + +static void icl_ddi_vswing_sequence(struct intel_encoder *encoder, + int link_clock, + u32 level, enum intel_output_type type) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = encoder->port; - if (port == PORT_A || port == PORT_B) + if (intel_port_is_combophy(dev_priv, port)) icl_combo_phy_ddi_vswing_sequence(encoder, level, type); else - /* Not Implemented Yet */ - WARN_ON(1); + icl_mg_phy_ddi_vswing_sequence(encoder, link_clock, level); } static uint32_t translate_signal_level(int signal_levels) @@ -2512,7 +2710,8 @@ u32 bxt_signal_levels(struct intel_dp *intel_dp) int level = intel_ddi_dp_level(intel_dp); if (IS_ICELAKE(dev_priv)) - icl_ddi_vswing_sequence(encoder, level, encoder->type); + icl_ddi_vswing_sequence(encoder, intel_dp->link_rate, + level, encoder->type); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_vswing_sequence(encoder, level, encoder->type); else @@ -2534,6 +2733,21 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp) return DDI_BUF_TRANS_SELECT(level); } +static inline +uint32_t icl_dpclka_cfgcr0_clk_off(struct drm_i915_private *dev_priv, + enum port port) +{ + if (intel_port_is_combophy(dev_priv, port)) { + return ICL_DPCLKA_CFGCR0_DDI_CLK_OFF(port); + } else if (intel_port_is_tc(dev_priv, port)) { + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + + return ICL_DPCLKA_CFGCR0_TC_CLK_OFF(tc_port); + } + + return 0; +} + void icl_map_plls_to_ports(struct drm_crtc *crtc, struct intel_crtc_state *crtc_state, struct drm_atomic_state *old_state) @@ -2557,16 +2771,16 @@ void icl_map_plls_to_ports(struct drm_crtc *crtc, mutex_lock(&dev_priv->dpll_lock); val = I915_READ(DPCLKA_CFGCR0_ICL); - WARN_ON((val & DPCLKA_CFGCR0_DDI_CLK_OFF(port)) == 0); + WARN_ON((val & icl_dpclka_cfgcr0_clk_off(dev_priv, port)) == 0); - if (port == PORT_A || port == PORT_B) { + if (intel_port_is_combophy(dev_priv, port)) { val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port); val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll->info->id, port); I915_WRITE(DPCLKA_CFGCR0_ICL, val); POSTING_READ(DPCLKA_CFGCR0_ICL); } - val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port); + val &= ~icl_dpclka_cfgcr0_clk_off(dev_priv, port); I915_WRITE(DPCLKA_CFGCR0_ICL, val); mutex_unlock(&dev_priv->dpll_lock); @@ -2594,7 +2808,7 @@ void icl_unmap_plls_to_ports(struct drm_crtc *crtc, mutex_lock(&dev_priv->dpll_lock); I915_WRITE(DPCLKA_CFGCR0_ICL, I915_READ(DPCLKA_CFGCR0_ICL) | - DPCLKA_CFGCR0_DDI_CLK_OFF(port)); + icl_dpclka_cfgcr0_clk_off(dev_priv, port)); mutex_unlock(&dev_priv->dpll_lock); } } @@ -2612,7 +2826,7 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder, mutex_lock(&dev_priv->dpll_lock); if (IS_ICELAKE(dev_priv)) { - if (port >= PORT_C) + if (!intel_port_is_combophy(dev_priv, port)) I915_WRITE(DDI_CLK_SEL(port), icl_pll_to_ddi_pll_sel(encoder, pll)); } else if (IS_CANNONLAKE(dev_priv)) { @@ -2654,7 +2868,7 @@ static void intel_ddi_clk_disable(struct intel_encoder *encoder) enum port port = encoder->port; if (IS_ICELAKE(dev_priv)) { - if (port >= PORT_C) + if (!intel_port_is_combophy(dev_priv, port)) I915_WRITE(DDI_CLK_SEL(port), DDI_CLK_SEL_NONE); } else if (IS_CANNONLAKE(dev_priv)) { I915_WRITE(DPCLKA_CFGCR0, I915_READ(DPCLKA_CFGCR0) | @@ -2692,8 +2906,12 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); + icl_program_mg_dp_mode(intel_dp); + icl_disable_phy_clock_gating(dig_port); + if (IS_ICELAKE(dev_priv)) - icl_ddi_vswing_sequence(encoder, level, encoder->type); + icl_ddi_vswing_sequence(encoder, crtc_state->port_clock, + level, encoder->type); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_vswing_sequence(encoder, level, encoder->type); else if (IS_GEN9_LP(dev_priv)) @@ -2708,6 +2926,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder, if (port != PORT_A || INTEL_GEN(dev_priv) >= 9) intel_dp_stop_link_train(intel_dp); + icl_enable_phy_clock_gating(dig_port); + if (!is_mst) intel_ddi_enable_pipe_clock(crtc_state); } @@ -2729,7 +2949,8 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain); if (IS_ICELAKE(dev_priv)) - icl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI); + icl_ddi_vswing_sequence(encoder, crtc_state->port_clock, + level, INTEL_OUTPUT_HDMI); else if (IS_CANNONLAKE(dev_priv)) cnl_ddi_vswing_sequence(encoder, level, INTEL_OUTPUT_HDMI); else if (IS_GEN9_LP(dev_priv)) diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h index 633f9fbf72ea..6eecd64734d5 100644 --- a/drivers/gpu/drm/i915/intel_device_info.h +++ b/drivers/gpu/drm/i915/intel_device_info.h @@ -103,9 +103,9 @@ enum intel_platform { func(has_psr); \ func(has_rc6); \ func(has_rc6p); \ - func(has_resource_streamer); \ func(has_runtime_pm); \ func(has_snoop); \ + func(has_coherent_ggtt); \ func(unfenced_needs_alignment); \ func(cursor_needs_physical); \ func(hws_needs_physical); \ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d2951096bca0..9741cc419e1b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -46,6 +46,7 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_rect.h> +#include <drm/drm_atomic_uapi.h> #include <linux/dma_remapping.h> #include <linux/reservation.h> @@ -1916,10 +1917,10 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv) } static unsigned int -intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane) +intel_tile_width_bytes(const struct drm_framebuffer *fb, int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); - unsigned int cpp = fb->format->cpp[plane]; + unsigned int cpp = fb->format->cpp[color_plane]; switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: @@ -1930,7 +1931,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane) else return 512; case I915_FORMAT_MOD_Y_TILED_CCS: - if (plane == 1) + if (color_plane == 1) return 128; /* fall through */ case I915_FORMAT_MOD_Y_TILED: @@ -1939,7 +1940,7 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane) else return 512; case I915_FORMAT_MOD_Yf_TILED_CCS: - if (plane == 1) + if (color_plane == 1) return 128; /* fall through */ case I915_FORMAT_MOD_Yf_TILED: @@ -1964,22 +1965,22 @@ intel_tile_width_bytes(const struct drm_framebuffer *fb, int plane) } static unsigned int -intel_tile_height(const struct drm_framebuffer *fb, int plane) +intel_tile_height(const struct drm_framebuffer *fb, int color_plane) { if (fb->modifier == DRM_FORMAT_MOD_LINEAR) return 1; else return intel_tile_size(to_i915(fb->dev)) / - intel_tile_width_bytes(fb, plane); + intel_tile_width_bytes(fb, color_plane); } /* Return the tile dimensions in pixel units */ -static void intel_tile_dims(const struct drm_framebuffer *fb, int plane, +static void intel_tile_dims(const struct drm_framebuffer *fb, int color_plane, unsigned int *tile_width, unsigned int *tile_height) { - unsigned int tile_width_bytes = intel_tile_width_bytes(fb, plane); - unsigned int cpp = fb->format->cpp[plane]; + unsigned int tile_width_bytes = intel_tile_width_bytes(fb, color_plane); + unsigned int cpp = fb->format->cpp[color_plane]; *tile_width = tile_width_bytes / cpp; *tile_height = intel_tile_size(to_i915(fb->dev)) / tile_width_bytes; @@ -1987,9 +1988,9 @@ static void intel_tile_dims(const struct drm_framebuffer *fb, int plane, unsigned int intel_fb_align_height(const struct drm_framebuffer *fb, - int plane, unsigned int height) + int color_plane, unsigned int height) { - unsigned int tile_height = intel_tile_height(fb, plane); + unsigned int tile_height = intel_tile_height(fb, color_plane); return ALIGN(height, tile_height); } @@ -2043,12 +2044,12 @@ static unsigned int intel_linear_alignment(const struct drm_i915_private *dev_pr } static unsigned int intel_surf_alignment(const struct drm_framebuffer *fb, - int plane) + int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); /* AUX_DIST needs only 4K alignment */ - if (plane == 1) + if (color_plane == 1) return 4096; switch (fb->modifier) { @@ -2079,14 +2080,13 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) struct i915_vma * intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, - unsigned int rotation, + const struct i915_ggtt_view *view, bool uses_fence, unsigned long *out_flags) { struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct i915_ggtt_view view; struct i915_vma *vma; unsigned int pinctl; u32 alignment; @@ -2095,8 +2095,6 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, alignment = intel_surf_alignment(fb, 0); - intel_fill_fb_ggtt_view(&view, fb, rotation); - /* Note that the w/a also requires 64 PTE of padding following the * bo. We currently fill all unused PTE with the shadow page and so * we should always have valid PTE following the scanout preventing @@ -2129,7 +2127,7 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, pinctl |= PIN_MAPPABLE; vma = i915_gem_object_pin_to_display_plane(obj, - alignment, &view, pinctl); + alignment, view, pinctl); if (IS_ERR(vma)) goto err; @@ -2181,13 +2179,13 @@ void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags) i915_vma_put(vma); } -static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane, +static int intel_fb_pitch(const struct drm_framebuffer *fb, int color_plane, unsigned int rotation) { if (drm_rotation_90_or_270(rotation)) - return to_intel_framebuffer(fb)->rotated[plane].pitch; + return to_intel_framebuffer(fb)->rotated[color_plane].pitch; else - return fb->pitches[plane]; + return fb->pitches[color_plane]; } /* @@ -2198,11 +2196,11 @@ static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane, */ u32 intel_fb_xy_to_linear(int x, int y, const struct intel_plane_state *state, - int plane) + int color_plane) { const struct drm_framebuffer *fb = state->base.fb; - unsigned int cpp = fb->format->cpp[plane]; - unsigned int pitch = fb->pitches[plane]; + unsigned int cpp = fb->format->cpp[color_plane]; + unsigned int pitch = state->color_plane[color_plane].stride; return y * pitch + x * cpp; } @@ -2214,28 +2212,28 @@ u32 intel_fb_xy_to_linear(int x, int y, */ void intel_add_fb_offsets(int *x, int *y, const struct intel_plane_state *state, - int plane) + int color_plane) { const struct intel_framebuffer *intel_fb = to_intel_framebuffer(state->base.fb); unsigned int rotation = state->base.rotation; if (drm_rotation_90_or_270(rotation)) { - *x += intel_fb->rotated[plane].x; - *y += intel_fb->rotated[plane].y; + *x += intel_fb->rotated[color_plane].x; + *y += intel_fb->rotated[color_plane].y; } else { - *x += intel_fb->normal[plane].x; - *y += intel_fb->normal[plane].y; + *x += intel_fb->normal[color_plane].x; + *y += intel_fb->normal[color_plane].y; } } -static u32 __intel_adjust_tile_offset(int *x, int *y, - unsigned int tile_width, - unsigned int tile_height, - unsigned int tile_size, - unsigned int pitch_tiles, - u32 old_offset, - u32 new_offset) +static u32 intel_adjust_tile_offset(int *x, int *y, + unsigned int tile_width, + unsigned int tile_height, + unsigned int tile_size, + unsigned int pitch_tiles, + u32 old_offset, + u32 new_offset) { unsigned int pitch_pixels = pitch_tiles * tile_width; unsigned int tiles; @@ -2256,14 +2254,15 @@ static u32 __intel_adjust_tile_offset(int *x, int *y, return new_offset; } -static u32 _intel_adjust_tile_offset(int *x, int *y, - const struct drm_framebuffer *fb, int plane, - unsigned int rotation, - u32 old_offset, u32 new_offset) +static u32 intel_adjust_aligned_offset(int *x, int *y, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int rotation, + unsigned int pitch, + u32 old_offset, u32 new_offset) { - const struct drm_i915_private *dev_priv = to_i915(fb->dev); - unsigned int cpp = fb->format->cpp[plane]; - unsigned int pitch = intel_fb_pitch(fb, plane, rotation); + struct drm_i915_private *dev_priv = to_i915(fb->dev); + unsigned int cpp = fb->format->cpp[color_plane]; WARN_ON(new_offset > old_offset); @@ -2272,7 +2271,7 @@ static u32 _intel_adjust_tile_offset(int *x, int *y, unsigned int pitch_tiles; tile_size = intel_tile_size(dev_priv); - intel_tile_dims(fb, plane, &tile_width, &tile_height); + intel_tile_dims(fb, color_plane, &tile_width, &tile_height); if (drm_rotation_90_or_270(rotation)) { pitch_tiles = pitch / tile_height; @@ -2281,9 +2280,9 @@ static u32 _intel_adjust_tile_offset(int *x, int *y, pitch_tiles = pitch / (tile_width * cpp); } - __intel_adjust_tile_offset(x, y, tile_width, tile_height, - tile_size, pitch_tiles, - old_offset, new_offset); + intel_adjust_tile_offset(x, y, tile_width, tile_height, + tile_size, pitch_tiles, + old_offset, new_offset); } else { old_offset += *y * pitch + *x * cpp; @@ -2298,17 +2297,19 @@ static u32 _intel_adjust_tile_offset(int *x, int *y, * Adjust the tile offset by moving the difference into * the x/y offsets. */ -static u32 intel_adjust_tile_offset(int *x, int *y, - const struct intel_plane_state *state, int plane, - u32 old_offset, u32 new_offset) -{ - return _intel_adjust_tile_offset(x, y, state->base.fb, plane, - state->base.rotation, - old_offset, new_offset); +static u32 intel_plane_adjust_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane, + u32 old_offset, u32 new_offset) +{ + return intel_adjust_aligned_offset(x, y, state->base.fb, color_plane, + state->base.rotation, + state->color_plane[color_plane].stride, + old_offset, new_offset); } /* - * Computes the linear offset to the base tile and adjusts + * Computes the aligned offset to the base tile and adjusts * x, y. bytes per pixel is assumed to be a power-of-two. * * In the 90/270 rotated case, x and y are assumed @@ -2321,15 +2322,16 @@ static u32 intel_adjust_tile_offset(int *x, int *y, * used. This is why the user has to pass in the pitch since it * is specified in the rotated orientation. */ -static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, - int *x, int *y, - const struct drm_framebuffer *fb, int plane, - unsigned int pitch, - unsigned int rotation, - u32 alignment) +static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv, + int *x, int *y, + const struct drm_framebuffer *fb, + int color_plane, + unsigned int pitch, + unsigned int rotation, + u32 alignment) { uint64_t fb_modifier = fb->modifier; - unsigned int cpp = fb->format->cpp[plane]; + unsigned int cpp = fb->format->cpp[color_plane]; u32 offset, offset_aligned; if (alignment) @@ -2340,7 +2342,7 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, unsigned int tile_rows, tiles, pitch_tiles; tile_size = intel_tile_size(dev_priv); - intel_tile_dims(fb, plane, &tile_width, &tile_height); + intel_tile_dims(fb, color_plane, &tile_width, &tile_height); if (drm_rotation_90_or_270(rotation)) { pitch_tiles = pitch / tile_height; @@ -2358,9 +2360,9 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, offset = (tile_rows * pitch_tiles + tiles) * tile_size; offset_aligned = offset & ~alignment; - __intel_adjust_tile_offset(x, y, tile_width, tile_height, - tile_size, pitch_tiles, - offset, offset_aligned); + intel_adjust_tile_offset(x, y, tile_width, tile_height, + tile_size, pitch_tiles, + offset, offset_aligned); } else { offset = *y * pitch + *x * cpp; offset_aligned = offset & ~alignment; @@ -2372,42 +2374,44 @@ static u32 _intel_compute_tile_offset(const struct drm_i915_private *dev_priv, return offset_aligned; } -u32 intel_compute_tile_offset(int *x, int *y, - const struct intel_plane_state *state, - int plane) +static u32 intel_plane_compute_aligned_offset(int *x, int *y, + const struct intel_plane_state *state, + int color_plane) { struct intel_plane *intel_plane = to_intel_plane(state->base.plane); struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev); const struct drm_framebuffer *fb = state->base.fb; unsigned int rotation = state->base.rotation; - int pitch = intel_fb_pitch(fb, plane, rotation); + int pitch = state->color_plane[color_plane].stride; u32 alignment; if (intel_plane->id == PLANE_CURSOR) alignment = intel_cursor_alignment(dev_priv); else - alignment = intel_surf_alignment(fb, plane); + alignment = intel_surf_alignment(fb, color_plane); - return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch, - rotation, alignment); + return intel_compute_aligned_offset(dev_priv, x, y, fb, color_plane, + pitch, rotation, alignment); } /* Convert the fb->offset[] into x/y offsets */ static int intel_fb_offset_to_xy(int *x, int *y, - const struct drm_framebuffer *fb, int plane) + const struct drm_framebuffer *fb, + int color_plane) { struct drm_i915_private *dev_priv = to_i915(fb->dev); if (fb->modifier != DRM_FORMAT_MOD_LINEAR && - fb->offsets[plane] % intel_tile_size(dev_priv)) + fb->offsets[color_plane] % intel_tile_size(dev_priv)) return -EINVAL; *x = 0; *y = 0; - _intel_adjust_tile_offset(x, y, - fb, plane, DRM_MODE_ROTATE_0, - fb->offsets[plane], 0); + intel_adjust_aligned_offset(x, y, + fb, color_plane, DRM_MODE_ROTATE_0, + fb->pitches[color_plane], + fb->offsets[color_plane], 0); return 0; } @@ -2474,6 +2478,12 @@ intel_get_format_info(const struct drm_mode_fb_cmd2 *cmd) } } +bool is_ccs_modifier(u64 modifier) +{ + return modifier == I915_FORMAT_MOD_Y_TILED_CCS || + modifier == I915_FORMAT_MOD_Yf_TILED_CCS; +} + static int intel_fill_fb_info(struct drm_i915_private *dev_priv, struct drm_framebuffer *fb) @@ -2504,8 +2514,7 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, return ret; } - if ((fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) && i == 1) { + if (is_ccs_modifier(fb->modifier) && i == 1) { int hsub = fb->format->hsub; int vsub = fb->format->vsub; int tile_width, tile_height; @@ -2559,9 +2568,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, intel_fb->normal[i].x = x; intel_fb->normal[i].y = y; - offset = _intel_compute_tile_offset(dev_priv, &x, &y, - fb, i, fb->pitches[i], - DRM_MODE_ROTATE_0, tile_size); + offset = intel_compute_aligned_offset(dev_priv, &x, &y, fb, i, + fb->pitches[i], + DRM_MODE_ROTATE_0, + tile_size); offset /= tile_size; if (fb->modifier != DRM_FORMAT_MOD_LINEAR) { @@ -2608,10 +2618,10 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, * We only keep the x/y offsets, so push all of the * gtt offset into the x/y offsets. */ - __intel_adjust_tile_offset(&x, &y, - tile_width, tile_height, - tile_size, pitch_tiles, - gtt_offset_rotated * tile_size, 0); + intel_adjust_tile_offset(&x, &y, + tile_width, tile_height, + tile_size, pitch_tiles, + gtt_offset_rotated * tile_size, 0); gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height; @@ -2630,9 +2640,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, max_size = max(max_size, offset + size); } - if (max_size * tile_size > obj->base.size) { - DRM_DEBUG_KMS("fb too big for bo (need %u bytes, have %zu bytes)\n", - max_size * tile_size, obj->base.size); + if (mul_u32_u32(max_size, tile_size) > obj->base.size) { + DRM_DEBUG_KMS("fb too big for bo (need %llu bytes, have %zu bytes)\n", + mul_u32_u32(max_size, tile_size), obj->base.size); return -EINVAL; } @@ -2712,6 +2722,17 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, if (size_aligned * 2 > dev_priv->stolen_usable_size) return false; + switch (fb->modifier) { + case DRM_FORMAT_MOD_LINEAR: + case I915_FORMAT_MOD_X_TILED: + case I915_FORMAT_MOD_Y_TILED: + break; + default: + DRM_DEBUG_DRIVER("Unsupported modifier for initial FB: 0x%llx\n", + fb->modifier); + return false; + } + mutex_lock(&dev->struct_mutex); obj = i915_gem_object_create_stolen_for_preallocated(dev_priv, base_aligned, @@ -2721,8 +2742,17 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc, if (!obj) return false; - if (plane_config->tiling == I915_TILING_X) - obj->tiling_and_stride = fb->pitches[0] | I915_TILING_X; + switch (plane_config->tiling) { + case I915_TILING_NONE: + break; + case I915_TILING_X: + case I915_TILING_Y: + obj->tiling_and_stride = fb->pitches[0] | plane_config->tiling; + break; + default: + MISSING_CASE(plane_config->tiling); + return false; + } mode_cmd.pixel_format = fb->format->format; mode_cmd.width = fb->width; @@ -2754,20 +2784,33 @@ intel_set_plane_visible(struct intel_crtc_state *crtc_state, plane_state->base.visible = visible; - /* FIXME pre-g4x don't work like this */ - if (visible) { + if (visible) crtc_state->base.plane_mask |= drm_plane_mask(&plane->base); - crtc_state->active_planes |= BIT(plane->id); - } else { + else crtc_state->base.plane_mask &= ~drm_plane_mask(&plane->base); - crtc_state->active_planes &= ~BIT(plane->id); - } DRM_DEBUG_KMS("%s active planes 0x%x\n", crtc_state->base.crtc->name, crtc_state->active_planes); } +static void fixup_active_planes(struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev); + struct drm_plane *plane; + + /* + * Active_planes aliases if multiple "primary" or cursor planes + * have been used on the same (or wrong) pipe. plane_mask uses + * unique ids, hence we can use that to reconstruct active_planes. + */ + crtc_state->active_planes = 0; + + drm_for_each_plane_mask(plane, &dev_priv->drm, + crtc_state->base.plane_mask) + crtc_state->active_planes |= BIT(to_intel_plane(plane)->id); +} + static void intel_plane_disable_noatomic(struct intel_crtc *crtc, struct intel_plane *plane) { @@ -2777,6 +2820,7 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, to_intel_plane_state(plane->base.state); intel_set_plane_visible(crtc_state, plane_state, false); + fixup_active_planes(crtc_state); if (plane->id == PLANE_PRIMARY) intel_pre_disable_primary_noatomic(&crtc->base); @@ -2795,7 +2839,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct drm_i915_gem_object *obj; struct drm_plane *primary = intel_crtc->base.primary; struct drm_plane_state *plane_state = primary->state; - struct drm_crtc_state *crtc_state = intel_crtc->base.state; struct intel_plane *intel_plane = to_intel_plane(primary); struct intel_plane_state *intel_state = to_intel_plane_state(plane_state); @@ -2847,10 +2890,15 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: + intel_fill_fb_ggtt_view(&intel_state->view, fb, + intel_state->base.rotation); + intel_state->color_plane[0].stride = + intel_fb_pitch(fb, 0, intel_state->base.rotation); + mutex_lock(&dev->struct_mutex); intel_state->vma = intel_pin_and_fence_fb_obj(fb, - primary->state->rotation, + &intel_state->view, intel_plane_uses_fence(intel_state), &intel_state->flags); mutex_unlock(&dev->struct_mutex); @@ -2885,18 +2933,15 @@ valid_fb: plane_state->fb = fb; plane_state->crtc = &intel_crtc->base; - intel_set_plane_visible(to_intel_crtc_state(crtc_state), - to_intel_plane_state(plane_state), - true); - atomic_or(to_intel_plane(primary)->frontbuffer_bit, &obj->frontbuffer_bits); } -static int skl_max_plane_width(const struct drm_framebuffer *fb, int plane, +static int skl_max_plane_width(const struct drm_framebuffer *fb, + int color_plane, unsigned int rotation) { - int cpp = fb->format->cpp[plane]; + int cpp = fb->format->cpp[color_plane]; switch (fb->modifier) { case DRM_FORMAT_MOD_LINEAR: @@ -2944,9 +2989,9 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state const struct drm_framebuffer *fb = plane_state->base.fb; int hsub = fb->format->hsub; int vsub = fb->format->vsub; - int aux_x = plane_state->aux.x; - int aux_y = plane_state->aux.y; - u32 aux_offset = plane_state->aux.offset; + int aux_x = plane_state->color_plane[1].x; + int aux_y = plane_state->color_plane[1].y; + u32 aux_offset = plane_state->color_plane[1].offset; u32 alignment = intel_surf_alignment(fb, 1); while (aux_offset >= main_offset && aux_y <= main_y) { @@ -2960,8 +3005,8 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state x = aux_x / hsub; y = aux_y / vsub; - aux_offset = intel_adjust_tile_offset(&x, &y, plane_state, 1, - aux_offset, aux_offset - alignment); + aux_offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 1, + aux_offset, aux_offset - alignment); aux_x = x * hsub + aux_x % hsub; aux_y = y * vsub + aux_y % vsub; } @@ -2969,30 +3014,24 @@ static bool skl_check_main_ccs_coordinates(struct intel_plane_state *plane_state if (aux_x != main_x || aux_y != main_y) return false; - plane_state->aux.offset = aux_offset; - plane_state->aux.x = aux_x; - plane_state->aux.y = aux_y; + plane_state->color_plane[1].offset = aux_offset; + plane_state->color_plane[1].x = aux_x; + plane_state->color_plane[1].y = aux_y; return true; } -static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +static int skl_check_main_surface(struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = - to_i915(plane_state->base.plane->dev); const struct drm_framebuffer *fb = plane_state->base.fb; unsigned int rotation = plane_state->base.rotation; int x = plane_state->base.src.x1 >> 16; int y = plane_state->base.src.y1 >> 16; int w = drm_rect_width(&plane_state->base.src) >> 16; int h = drm_rect_height(&plane_state->base.src) >> 16; - int dst_x = plane_state->base.dst.x1; - int dst_w = drm_rect_width(&plane_state->base.dst); - int pipe_src_w = crtc_state->pipe_src_w; int max_width = skl_max_plane_width(fb, 0, rotation); int max_height = 4096; - u32 alignment, offset, aux_offset = plane_state->aux.offset; + u32 alignment, offset, aux_offset = plane_state->color_plane[1].offset; if (w > max_width || h > max_height) { DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n", @@ -3000,26 +3039,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, return -EINVAL; } - /* - * Display WA #1175: cnl,glk - * Planes other than the cursor may cause FIFO underflow and display - * corruption if starting less than 4 pixels from the right edge of - * the screen. - * Besides the above WA fix the similar problem, where planes other - * than the cursor ending less than 4 pixels from the left edge of the - * screen may cause FIFO underflow and display corruption. - */ - if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && - (dst_x + dst_w < 4 || dst_x > pipe_src_w - 4)) { - DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n", - dst_x + dst_w < 4 ? "end" : "start", - dst_x + dst_w < 4 ? dst_x + dst_w : dst_x, - 4, pipe_src_w - 4); - return -ERANGE; - } - intel_add_fb_offsets(&x, &y, plane_state, 0); - offset = intel_compute_tile_offset(&x, &y, plane_state, 0); + offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 0); alignment = intel_surf_alignment(fb, 0); /* @@ -3028,8 +3049,8 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, * sure that is what we will get. */ if (offset > aux_offset) - offset = intel_adjust_tile_offset(&x, &y, plane_state, 0, - offset, aux_offset & ~(alignment - 1)); + offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + offset, aux_offset & ~(alignment - 1)); /* * When using an X-tiled surface, the plane blows up @@ -3040,14 +3061,14 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, if (fb->modifier == I915_FORMAT_MOD_X_TILED) { int cpp = fb->format->cpp[0]; - while ((x + w) * cpp > fb->pitches[0]) { + while ((x + w) * cpp > plane_state->color_plane[0].stride) { if (offset == 0) { DRM_DEBUG_KMS("Unable to find suitable display surface offset due to X-tiling\n"); return -EINVAL; } - offset = intel_adjust_tile_offset(&x, &y, plane_state, 0, - offset, offset - alignment); + offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + offset, offset - alignment); } } @@ -3055,32 +3076,30 @@ static int skl_check_main_surface(const struct intel_crtc_state *crtc_state, * CCS AUX surface doesn't have its own x/y offsets, we must make sure * they match with the main surface x/y offsets. */ - if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) { + if (is_ccs_modifier(fb->modifier)) { while (!skl_check_main_ccs_coordinates(plane_state, x, y, offset)) { if (offset == 0) break; - offset = intel_adjust_tile_offset(&x, &y, plane_state, 0, - offset, offset - alignment); + offset = intel_plane_adjust_aligned_offset(&x, &y, plane_state, 0, + offset, offset - alignment); } - if (x != plane_state->aux.x || y != plane_state->aux.y) { + if (x != plane_state->color_plane[1].x || y != plane_state->color_plane[1].y) { DRM_DEBUG_KMS("Unable to find suitable display surface offset due to CCS\n"); return -EINVAL; } } - plane_state->main.offset = offset; - plane_state->main.x = x; - plane_state->main.y = y; + plane_state->color_plane[0].offset = offset; + plane_state->color_plane[0].x = x; + plane_state->color_plane[0].y = y; return 0; } static int -skl_check_nv12_surface(const struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +skl_check_nv12_surface(struct intel_plane_state *plane_state) { /* Display WA #1106 */ if (plane_state->base.rotation != @@ -3114,7 +3133,7 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) u32 offset; intel_add_fb_offsets(&x, &y, plane_state, 1); - offset = intel_compute_tile_offset(&x, &y, plane_state, 1); + offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1); /* FIXME not quite sure how/if these apply to the chroma plane */ if (w > max_width || h > max_height) { @@ -3123,9 +3142,9 @@ static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state) return -EINVAL; } - plane_state->aux.offset = offset; - plane_state->aux.x = x; - plane_state->aux.y = y; + plane_state->color_plane[1].offset = offset; + plane_state->color_plane[1].x = x; + plane_state->color_plane[1].y = y; return 0; } @@ -3141,34 +3160,29 @@ static int skl_check_ccs_aux_surface(struct intel_plane_state *plane_state) int y = src_y / vsub; u32 offset; - if (plane_state->base.rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180)) { - DRM_DEBUG_KMS("RC support only with 0/180 degree rotation %x\n", - plane_state->base.rotation); - return -EINVAL; - } - intel_add_fb_offsets(&x, &y, plane_state, 1); - offset = intel_compute_tile_offset(&x, &y, plane_state, 1); + offset = intel_plane_compute_aligned_offset(&x, &y, plane_state, 1); - plane_state->aux.offset = offset; - plane_state->aux.x = x * hsub + src_x % hsub; - plane_state->aux.y = y * vsub + src_y % vsub; + plane_state->color_plane[1].offset = offset; + plane_state->color_plane[1].x = x * hsub + src_x % hsub; + plane_state->color_plane[1].y = y * vsub + src_y % vsub; return 0; } -int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +int skl_check_plane_surface(struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; unsigned int rotation = plane_state->base.rotation; int ret; - if (rotation & DRM_MODE_REFLECT_X && - fb->modifier == DRM_FORMAT_MOD_LINEAR) { - DRM_DEBUG_KMS("horizontal flip is not supported with linear surface formats\n"); - return -EINVAL; - } + intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation); + plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation); + plane_state->color_plane[1].stride = intel_fb_pitch(fb, 1, rotation); + + ret = intel_plane_check_stride(plane_state); + if (ret) + return ret; if (!plane_state->base.visible) return 0; @@ -3184,30 +3198,56 @@ int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, * the main surface setup depends on it. */ if (fb->format->format == DRM_FORMAT_NV12) { - ret = skl_check_nv12_surface(crtc_state, plane_state); + ret = skl_check_nv12_surface(plane_state); if (ret) return ret; ret = skl_check_nv12_aux_surface(plane_state); if (ret) return ret; - } else if (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS) { + } else if (is_ccs_modifier(fb->modifier)) { ret = skl_check_ccs_aux_surface(plane_state); if (ret) return ret; } else { - plane_state->aux.offset = ~0xfff; - plane_state->aux.x = 0; - plane_state->aux.y = 0; + plane_state->color_plane[1].offset = ~0xfff; + plane_state->color_plane[1].x = 0; + plane_state->color_plane[1].y = 0; } - ret = skl_check_main_surface(crtc_state, plane_state); + ret = skl_check_main_surface(plane_state); if (ret) return ret; return 0; } +unsigned int +i9xx_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + + if (!HAS_GMCH_DISPLAY(dev_priv)) { + return 32*1024; + } else if (INTEL_GEN(dev_priv) >= 4) { + if (modifier == I915_FORMAT_MOD_X_TILED) + return 16*1024; + else + return 32*1024; + } else if (INTEL_GEN(dev_priv) >= 3) { + if (modifier == I915_FORMAT_MOD_X_TILED) + return 8*1024; + else + return 16*1024; + } else { + if (plane->i9xx_plane == PLANE_C) + return 4*1024; + else + return 8*1024; + } +} + static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -3274,21 +3314,30 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(plane_state->base.plane->dev); + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; int src_x = plane_state->base.src.x1 >> 16; int src_y = plane_state->base.src.y1 >> 16; u32 offset; + int ret; + + intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation); + plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation); + + ret = intel_plane_check_stride(plane_state); + if (ret) + return ret; intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); if (INTEL_GEN(dev_priv) >= 4) - offset = intel_compute_tile_offset(&src_x, &src_y, - plane_state, 0); + offset = intel_plane_compute_aligned_offset(&src_x, &src_y, + plane_state, 0); else offset = 0; /* HSW/BDW do this automagically in hardware */ if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) { - unsigned int rotation = plane_state->base.rotation; int src_w = drm_rect_width(&plane_state->base.src) >> 16; int src_h = drm_rect_height(&plane_state->base.src) >> 16; @@ -3300,9 +3349,43 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state) } } - plane_state->main.offset = offset; - plane_state->main.x = src_x; - plane_state->main.y = src_y; + plane_state->color_plane[0].offset = offset; + plane_state->color_plane[0].x = src_x; + plane_state->color_plane[0].y = src_y; + + return 0; +} + +static int +i9xx_plane_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + int ret; + + ret = chv_plane_check_rotation(plane_state); + if (ret) + return ret; + + ret = drm_atomic_helper_check_plane_state(&plane_state->base, + &crtc_state->base, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + false, true); + if (ret) + return ret; + + if (!plane_state->base.visible) + return 0; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = i9xx_check_plane_surface(plane_state); + if (ret) + return ret; + + plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state); return 0; } @@ -3312,20 +3395,19 @@ static void i9xx_update_plane(struct intel_plane *plane, const struct intel_plane_state *plane_state) { struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct drm_framebuffer *fb = plane_state->base.fb; enum i9xx_plane_id i9xx_plane = plane->i9xx_plane; u32 linear_offset; u32 dspcntr = plane_state->ctl; i915_reg_t reg = DSPCNTR(i9xx_plane); - int x = plane_state->main.x; - int y = plane_state->main.y; + int x = plane_state->color_plane[0].x; + int y = plane_state->color_plane[0].y; unsigned long irqflags; u32 dspaddr_offset; linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0); if (INTEL_GEN(dev_priv) >= 4) - dspaddr_offset = plane_state->main.offset; + dspaddr_offset = plane_state->color_plane[0].offset; else dspaddr_offset = linear_offset; @@ -3349,7 +3431,7 @@ static void i9xx_update_plane(struct intel_plane *plane, I915_WRITE_FW(reg, dspcntr); - I915_WRITE_FW(DSPSTRIDE(i9xx_plane), fb->pitches[0]); + I915_WRITE_FW(DSPSTRIDE(i9xx_plane), plane_state->color_plane[0].stride); if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { I915_WRITE_FW(DSPSURF(i9xx_plane), intel_plane_ggtt_offset(plane_state) + @@ -3424,12 +3506,12 @@ static bool i9xx_plane_get_hw_state(struct intel_plane *plane, } static u32 -intel_fb_stride_alignment(const struct drm_framebuffer *fb, int plane) +intel_fb_stride_alignment(const struct drm_framebuffer *fb, int color_plane) { if (fb->modifier == DRM_FORMAT_MOD_LINEAR) return 64; else - return intel_tile_width_bytes(fb, plane); + return intel_tile_width_bytes(fb, color_plane); } static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) @@ -3459,24 +3541,24 @@ static void skl_detach_scalers(struct intel_crtc *intel_crtc) } } -u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, - unsigned int rotation) +u32 skl_plane_stride(const struct intel_plane_state *plane_state, + int color_plane) { - u32 stride; + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; + u32 stride = plane_state->color_plane[color_plane].stride; - if (plane >= fb->format->num_planes) + if (color_plane >= fb->format->num_planes) return 0; - stride = intel_fb_pitch(fb, plane, rotation); - /* * The stride is either expressed as a multiple of 64 bytes chunks for * linear buffers or in number of tiles for tiled buffers. */ if (drm_rotation_90_or_270(rotation)) - stride /= intel_tile_height(fb, plane); + stride /= intel_tile_height(fb, color_plane); else - stride /= intel_fb_stride_alignment(fb, plane); + stride /= intel_fb_stride_alignment(fb, color_plane); return stride; } @@ -3552,11 +3634,11 @@ static u32 skl_plane_ctl_tiling(uint64_t fb_modifier) case I915_FORMAT_MOD_Y_TILED: return PLANE_CTL_TILED_Y; case I915_FORMAT_MOD_Y_TILED_CCS: - return PLANE_CTL_TILED_Y | PLANE_CTL_DECOMPRESSION_ENABLE; + return PLANE_CTL_TILED_Y | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; case I915_FORMAT_MOD_Yf_TILED: return PLANE_CTL_TILED_YF; case I915_FORMAT_MOD_Yf_TILED_CCS: - return PLANE_CTL_TILED_YF | PLANE_CTL_DECOMPRESSION_ENABLE; + return PLANE_CTL_TILED_YF | PLANE_CTL_RENDER_DECOMPRESSION_ENABLE; default: MISSING_CASE(fb_modifier); } @@ -5879,6 +5961,17 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +bool intel_port_is_combophy(struct drm_i915_private *dev_priv, enum port port) +{ + if (port == PORT_NONE) + return false; + + if (IS_ICELAKE(dev_priv)) + return port <= PORT_B; + + return false; +} + bool intel_port_is_tc(struct drm_i915_private *dev_priv, enum port port) { if (IS_ICELAKE(dev_priv)) @@ -6010,6 +6103,8 @@ static void valleyview_crtc_enable(struct intel_crtc_state *pipe_config, i9xx_set_pipeconf(intel_crtc); + intel_color_set_csc(&pipe_config->base); + intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); @@ -6109,8 +6204,8 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc) assert_pipe_disabled(dev_priv, crtc->pipe); - DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", - I915_READ(PFIT_CONTROL)); + DRM_DEBUG_KMS("disabling pfit, current: 0x%08x\n", + I915_READ(PFIT_CONTROL)); I915_WRITE(PFIT_CONTROL, 0); } @@ -6681,22 +6776,20 @@ intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) static void compute_m_n(unsigned int m, unsigned int n, uint32_t *ret_m, uint32_t *ret_n, - bool reduce_m_n) + bool constant_n) { /* - * Reduce M/N as much as possible without loss in precision. Several DP - * dongles in particular seem to be fussy about too large *link* M/N - * values. The passed in values are more likely to have the least - * significant bits zero than M after rounding below, so do this first. + * Several DP dongles in particular seem to be fussy about + * too large link M/N values. Give N value as 0x8000 that + * should be acceptable by specific devices. 0x8000 is the + * specified fixed N value for asynchronous clock mode, + * which the devices expect also in synchronous clock mode. */ - if (reduce_m_n) { - while ((m & 1) == 0 && (n & 1) == 0) { - m >>= 1; - n >>= 1; - } - } + if (constant_n) + *ret_n = 0x8000; + else + *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); - *ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX); *ret_m = div_u64((uint64_t) m * *ret_n, n); intel_reduce_m_n_ratio(ret_m, ret_n); } @@ -6705,18 +6798,18 @@ void intel_link_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n, - bool reduce_m_n) + bool constant_n) { m_n->tu = 64; compute_m_n(bits_per_pixel * pixel_clock, link_clock * nlanes * 8, &m_n->gmch_m, &m_n->gmch_n, - reduce_m_n); + constant_n); compute_m_n(pixel_clock, link_clock, &m_n->link_m, &m_n->link_n, - reduce_m_n); + constant_n); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) @@ -8632,8 +8725,8 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc, ironlake_compute_dpll(crtc, crtc_state, NULL); if (!intel_get_shared_dpll(crtc, crtc_state, NULL)) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", - pipe_name(crtc->pipe)); + DRM_DEBUG_KMS("failed to find PLL for pipe %c\n", + pipe_name(crtc->pipe)); return -EINVAL; } @@ -8803,13 +8896,14 @@ skylake_get_initial_plane_config(struct intel_crtc *crtc, fb->modifier = I915_FORMAT_MOD_X_TILED; break; case PLANE_CTL_TILED_Y: - if (val & PLANE_CTL_DECOMPRESSION_ENABLE) + plane_config->tiling = I915_TILING_Y; + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) fb->modifier = I915_FORMAT_MOD_Y_TILED_CCS; else fb->modifier = I915_FORMAT_MOD_Y_TILED; break; case PLANE_CTL_TILED_YF: - if (val & PLANE_CTL_DECOMPRESSION_ENABLE) + if (val & PLANE_CTL_RENDER_DECOMPRESSION_ENABLE) fb->modifier = I915_FORMAT_MOD_Yf_TILED_CCS; else fb->modifier = I915_FORMAT_MOD_Yf_TILED; @@ -8978,7 +9072,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); - I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL)), + I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL2), "Display power well on\n"); I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n"); I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n"); @@ -9200,8 +9294,8 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc, intel_get_crtc_new_encoder(state, crtc_state); if (!intel_get_shared_dpll(crtc, crtc_state, encoder)) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", - pipe_name(crtc->pipe)); + DRM_DEBUG_KMS("failed to find PLL for pipe %c\n", + pipe_name(crtc->pipe)); return -EINVAL; } } @@ -9590,7 +9684,7 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) else base = intel_plane_ggtt_offset(plane_state); - base += plane_state->main.offset; + base += plane_state->color_plane[0].offset; /* ILK+ do this automagically */ if (HAS_GMCH_DISPLAY(dev_priv) && @@ -9633,55 +9727,86 @@ static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state) height > 0 && height <= config->cursor_height; } -static int intel_check_cursor(struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state) +static int intel_cursor_check_surface(struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; int src_x, src_y; u32 offset; int ret; - ret = drm_atomic_helper_check_plane_state(&plane_state->base, - &crtc_state->base, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, - true, true); + intel_fill_fb_ggtt_view(&plane_state->view, fb, rotation); + plane_state->color_plane[0].stride = intel_fb_pitch(fb, 0, rotation); + + ret = intel_plane_check_stride(plane_state); if (ret) return ret; - if (!fb) - return 0; - - if (fb->modifier != DRM_FORMAT_MOD_LINEAR) { - DRM_DEBUG_KMS("cursor cannot be tiled\n"); - return -EINVAL; - } - src_x = plane_state->base.src_x >> 16; src_y = plane_state->base.src_y >> 16; intel_add_fb_offsets(&src_x, &src_y, plane_state, 0); - offset = intel_compute_tile_offset(&src_x, &src_y, plane_state, 0); + offset = intel_plane_compute_aligned_offset(&src_x, &src_y, + plane_state, 0); if (src_x != 0 || src_y != 0) { DRM_DEBUG_KMS("Arbitrary cursor panning not supported\n"); return -EINVAL; } - plane_state->main.offset = offset; + plane_state->color_plane[0].offset = offset; return 0; } -static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) +static int intel_check_cursor(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; + int ret; + if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) { + DRM_DEBUG_KMS("cursor cannot be tiled\n"); + return -EINVAL; + } + + ret = drm_atomic_helper_check_plane_state(&plane_state->base, + &crtc_state->base, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) + return ret; + + if (!plane_state->base.visible) + return 0; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = intel_cursor_check_surface(plane_state); + if (ret) + return ret; + + return 0; +} + +static unsigned int +i845_cursor_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + return 2048; +} + +static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ return CURSOR_ENABLE | CURSOR_GAMMA_ENABLE | CURSOR_FORMAT_ARGB | - CURSOR_STRIDE(fb->pitches[0]); + CURSOR_STRIDE(plane_state->color_plane[0].stride); } static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state) @@ -9695,8 +9820,7 @@ static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state) return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64); } -static int i845_check_cursor(struct intel_plane *plane, - struct intel_crtc_state *crtc_state, +static int i845_check_cursor(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->base.fb; @@ -9718,6 +9842,9 @@ static int i845_check_cursor(struct intel_plane *plane, return -EINVAL; } + WARN_ON(plane_state->base.visible && + plane_state->color_plane[0].stride != fb->pitches[0]); + switch (fb->pitches[0]) { case 256: case 512: @@ -9806,6 +9933,14 @@ static bool i845_cursor_get_hw_state(struct intel_plane *plane, return ret; } +static unsigned int +i9xx_cursor_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + return plane->base.dev->mode_config.cursor_width * 4; +} + static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -9886,10 +10021,10 @@ static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state) return true; } -static int i9xx_check_cursor(struct intel_plane *plane, - struct intel_crtc_state *crtc_state, +static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); const struct drm_framebuffer *fb = plane_state->base.fb; enum pipe pipe = plane->pipe; @@ -9911,6 +10046,9 @@ static int i9xx_check_cursor(struct intel_plane *plane, return -EINVAL; } + WARN_ON(plane_state->base.visible && + plane_state->color_plane[0].stride != fb->pitches[0]); + if (fb->pitches[0] != plane_state->base.crtc_w * fb->format->cpp[0]) { DRM_DEBUG_KMS("Invalid cursor stride (%u) (cursor width %d)\n", fb->pitches[0], plane_state->base.crtc_w); @@ -12743,7 +12881,7 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state) * down. */ INIT_WORK(&state->commit_work, intel_atomic_cleanup_work); - schedule_work(&state->commit_work); + queue_work(system_highpri_wq, &state->commit_work); } static void intel_atomic_commit_work(struct work_struct *work) @@ -12900,6 +13038,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .atomic_duplicate_state = intel_crtc_duplicate_state, .atomic_destroy_state = intel_crtc_destroy_state, .set_crc_source = intel_crtc_set_crc_source, + .verify_crc_source = intel_crtc_verify_crc_source, + .get_crc_sources = intel_crtc_get_crc_sources, }; struct wait_rps_boost { @@ -12971,12 +13111,15 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state) INTEL_INFO(dev_priv)->cursor_needs_physical) { struct drm_i915_gem_object *obj = intel_fb_obj(fb); const int align = intel_cursor_alignment(dev_priv); + int err; - return i915_gem_object_attach_phys(obj, align); + err = i915_gem_object_attach_phys(obj, align); + if (err) + return err; } vma = intel_pin_and_fence_fb_obj(fb, - plane_state->base.rotation, + &plane_state->view, intel_plane_uses_fence(plane_state), &plane_state->flags); if (IS_ERR(vma)) @@ -13154,19 +13297,17 @@ intel_cleanup_plane_fb(struct drm_plane *plane, } int -skl_max_scale(struct intel_crtc *intel_crtc, - struct intel_crtc_state *crtc_state, - uint32_t pixel_format) +skl_max_scale(const struct intel_crtc_state *crtc_state, + u32 pixel_format) { - struct drm_i915_private *dev_priv; + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); int max_scale, mult; int crtc_clock, max_dotclk, tmpclk1, tmpclk2; - if (!intel_crtc || !crtc_state->base.enable) + if (!crtc_state->base.enable) return DRM_PLANE_HELPER_NO_SCALING; - dev_priv = to_i915(intel_crtc->base.dev); - crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; max_dotclk = to_intel_atomic_state(crtc_state->base.state)->cdclk.logical.cdclk; @@ -13190,61 +13331,6 @@ skl_max_scale(struct intel_crtc *intel_crtc, return max_scale; } -static int -intel_check_primary_plane(struct intel_plane *plane, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct drm_crtc *crtc = state->base.crtc; - int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; - bool can_position = false; - int ret; - uint32_t pixel_format = 0; - - if (INTEL_GEN(dev_priv) >= 9) { - /* use scaler when colorkey is not required */ - if (!state->ckey.flags) { - min_scale = 1; - if (state->base.fb) - pixel_format = state->base.fb->format->format; - max_scale = skl_max_scale(to_intel_crtc(crtc), - crtc_state, pixel_format); - } - can_position = true; - } - - ret = drm_atomic_helper_check_plane_state(&state->base, - &crtc_state->base, - min_scale, max_scale, - can_position, true); - if (ret) - return ret; - - if (!state->base.fb) - return 0; - - if (INTEL_GEN(dev_priv) >= 9) { - ret = skl_check_plane_surface(crtc_state, state); - if (ret) - return ret; - - state->ctl = skl_plane_ctl(crtc_state, state); - } else { - ret = i9xx_check_plane_surface(state); - if (ret) - return ret; - - state->ctl = i9xx_plane_ctl(crtc_state, state); - } - - if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - state->color_ctl = glk_plane_color_ctl(crtc_state, state); - - return 0; -} - static void intel_begin_crtc_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -13402,8 +13488,7 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane, case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: - if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_CCS) + if (is_ccs_modifier(modifier)) return true; /* fall through */ case DRM_FORMAT_RGB565: @@ -13622,24 +13707,22 @@ static bool skl_plane_has_fbc(struct drm_i915_private *dev_priv, bool skl_plane_has_planar(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id) { - if (plane_id == PLANE_PRIMARY) { - if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) - return false; - else if ((INTEL_GEN(dev_priv) == 9 && pipe == PIPE_C) && - !IS_GEMINILAKE(dev_priv)) - return false; - } else if (plane_id >= PLANE_SPRITE0) { - if (plane_id == PLANE_CURSOR) - return false; - if (IS_GEMINILAKE(dev_priv) || INTEL_GEN(dev_priv) == 10) { - if (plane_id != PLANE_SPRITE0) - return false; - } else { - if (plane_id != PLANE_SPRITE0 || pipe == PIPE_C || - IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) - return false; - } - } + /* + * FIXME: ICL requires two hardware planes for scanning out NV12 + * framebuffers. Do not advertize support until this is implemented. + */ + if (INTEL_GEN(dev_priv) >= 11) + return false; + + if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv)) + return false; + + if (INTEL_GEN(dev_priv) == 9 && !IS_GEMINILAKE(dev_priv) && pipe == PIPE_C) + return false; + + if (plane_id != PLANE_PRIMARY && plane_id != PLANE_SPRITE0) + return false; + return true; } @@ -13669,12 +13752,8 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) primary->base.state = &state->base; - primary->can_scale = false; - primary->max_downscale = 1; - if (INTEL_GEN(dev_priv) >= 9) { - primary->can_scale = true; + if (INTEL_GEN(dev_priv) >= 9) state->scaler_id = -1; - } primary->pipe = pipe; /* * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS @@ -13701,8 +13780,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) fbc->possible_framebuffer_bits |= primary->frontbuffer_bit; } - primary->check_plane = intel_check_primary_plane; - if (INTEL_GEN(dev_priv) >= 9) { primary->has_ccs = skl_plane_has_ccs(dev_priv, pipe, PLANE_PRIMARY); @@ -13720,9 +13797,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) else modifiers = skl_format_modifiers_noccs; + primary->max_stride = skl_plane_max_stride; primary->update_plane = skl_update_plane; primary->disable_plane = skl_disable_plane; primary->get_hw_state = skl_plane_get_hw_state; + primary->check_plane = skl_plane_check; plane_funcs = &skl_plane_funcs; } else if (INTEL_GEN(dev_priv) >= 4) { @@ -13730,9 +13809,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) num_formats = ARRAY_SIZE(i965_primary_formats); modifiers = i9xx_format_modifiers; + primary->max_stride = i9xx_plane_max_stride; primary->update_plane = i9xx_update_plane; primary->disable_plane = i9xx_disable_plane; primary->get_hw_state = i9xx_plane_get_hw_state; + primary->check_plane = i9xx_plane_check; plane_funcs = &i965_plane_funcs; } else { @@ -13740,9 +13821,11 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe) num_formats = ARRAY_SIZE(i8xx_primary_formats); modifiers = i9xx_format_modifiers; + primary->max_stride = i9xx_plane_max_stride; primary->update_plane = i9xx_update_plane; primary->disable_plane = i9xx_disable_plane; primary->get_hw_state = i9xx_plane_get_hw_state; + primary->check_plane = i9xx_plane_check; plane_funcs = &i8xx_plane_funcs; } @@ -13839,19 +13922,19 @@ intel_cursor_plane_create(struct drm_i915_private *dev_priv, cursor->base.state = &state->base; - cursor->can_scale = false; - cursor->max_downscale = 1; cursor->pipe = pipe; cursor->i9xx_plane = (enum i9xx_plane_id) pipe; cursor->id = PLANE_CURSOR; cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id); if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) { + cursor->max_stride = i845_cursor_max_stride; cursor->update_plane = i845_update_cursor; cursor->disable_plane = i845_disable_cursor; cursor->get_hw_state = i845_cursor_get_hw_state; cursor->check_plane = i845_check_cursor; } else { + cursor->max_stride = i9xx_cursor_max_stride; cursor->update_plane = i9xx_update_cursor; cursor->disable_plane = i9xx_disable_cursor; cursor->get_hw_state = i9xx_cursor_get_hw_state; @@ -14133,6 +14216,9 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv) intel_pps_init(dev_priv); + if (INTEL_INFO(dev_priv)->num_pipes == 0) + return; + /* * intel_edp_init_connector() depends on this completing first, to * prevent the registeration of both eDP and LVDS and the incorrect @@ -14374,31 +14460,18 @@ static u32 intel_fb_pitch_limit(struct drm_i915_private *dev_priv, uint64_t fb_modifier, uint32_t pixel_format) { - u32 gen = INTEL_GEN(dev_priv); + struct intel_crtc *crtc; + struct intel_plane *plane; - if (gen >= 9) { - int cpp = drm_format_plane_cpp(pixel_format, 0); + /* + * We assume the primary plane for pipe A has + * the highest stride limits of them all. + */ + crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A); + plane = to_intel_plane(crtc->base.primary); - /* "The stride in bytes must not exceed the of the size of 8K - * pixels and 32K bytes." - */ - return min(8192 * cpp, 32768); - } else if (gen >= 5 && !HAS_GMCH_DISPLAY(dev_priv)) { - return 32*1024; - } else if (gen >= 4) { - if (fb_modifier == I915_FORMAT_MOD_X_TILED) - return 16*1024; - else - return 32*1024; - } else if (gen >= 3) { - if (fb_modifier == I915_FORMAT_MOD_X_TILED) - return 8*1024; - else - return 16*1024; - } else { - /* XXX DSPC is limited to 4k tiled */ - return 8*1024; - } + return plane->max_stride(plane, pixel_format, fb_modifier, + DRM_MODE_ROTATE_0); } static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, @@ -14549,7 +14622,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, break; case DRM_FORMAT_NV12: if (INTEL_GEN(dev_priv) < 9 || IS_SKYLAKE(dev_priv) || - IS_BROXTON(dev_priv)) { + IS_BROXTON(dev_priv) || INTEL_GEN(dev_priv) >= 11) { DRM_DEBUG_KMS("unsupported pixel format: %s\n", drm_get_format_name(mode_cmd->pixel_format, &format_name)); @@ -14596,8 +14669,7 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb, * potential runtime errors at plane configuration time. */ if (IS_GEN9(dev_priv) && i == 0 && fb->width > 3840 && - (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || - fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS)) + is_ccs_modifier(fb->modifier)) stride_alignment *= 4; if (fb->pitches[i] & (stride_alignment - 1)) { @@ -15133,12 +15205,61 @@ static void intel_update_fdi_pll_freq(struct drm_i915_private *dev_priv) DRM_DEBUG_DRIVER("FDI PLL freq=%d\n", dev_priv->fdi_pll_freq); } +static int intel_initial_commit(struct drm_device *dev) +{ + struct drm_atomic_state *state = NULL; + struct drm_modeset_acquire_ctx ctx; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret = 0; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + state->acquire_ctx = &ctx; + + drm_for_each_crtc(crtc, dev) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto out; + } + + if (crtc_state->active) { + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + goto out; + } + } + + ret = drm_atomic_commit(state); + +out: + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + int intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct i915_ggtt *ggtt = &dev_priv->ggtt; enum pipe pipe; struct intel_crtc *crtc; + int ret; dev_priv->modeset_wq = alloc_ordered_workqueue("i915_modeset", 0); @@ -15162,9 +15283,6 @@ int intel_modeset_init(struct drm_device *dev) intel_init_pm(dev_priv); - if (INTEL_INFO(dev_priv)->num_pipes == 0) - return 0; - /* * There may be no VBT; and if the BIOS enabled SSC we can * just keep using it to avoid unnecessary flicker. Whereas if the @@ -15213,8 +15331,6 @@ int intel_modeset_init(struct drm_device *dev) INTEL_INFO(dev_priv)->num_pipes > 1 ? "s" : ""); for_each_pipe(dev_priv, pipe) { - int ret; - ret = intel_crtc_init(dev_priv, pipe); if (ret) { drm_mode_config_cleanup(dev); @@ -15270,6 +15386,16 @@ int intel_modeset_init(struct drm_device *dev) if (!HAS_GMCH_DISPLAY(dev_priv)) sanitize_watermarks(dev); + /* + * Force all active planes to recompute their states. So that on + * mode_setcrtc after probe, all the intel_plane_state variables + * are already calculated and there is no assert_plane warnings + * during bootup. + */ + ret = intel_initial_commit(dev); + if (ret) + DRM_DEBUG_KMS("Initial commit in probe failed.\n"); + return 0; } @@ -15365,17 +15491,6 @@ void i830_disable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe) POSTING_READ(DPLL(pipe)); } -static bool intel_plane_mapping_ok(struct intel_crtc *crtc, - struct intel_plane *plane) -{ - enum pipe pipe; - - if (!plane->get_hw_state(plane, &pipe)) - return true; - - return pipe == crtc->pipe; -} - static void intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv) { @@ -15387,13 +15502,20 @@ intel_sanitize_plane_mapping(struct drm_i915_private *dev_priv) for_each_intel_crtc(&dev_priv->drm, crtc) { struct intel_plane *plane = to_intel_plane(crtc->base.primary); + struct intel_crtc *plane_crtc; + enum pipe pipe; + + if (!plane->get_hw_state(plane, &pipe)) + continue; - if (intel_plane_mapping_ok(crtc, plane)) + if (pipe == crtc->pipe) continue; DRM_DEBUG_KMS("%s attached to the wrong pipe, disabling plane\n", plane->base.name); - intel_plane_disable_noatomic(crtc, plane); + + plane_crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + intel_plane_disable_noatomic(plane_crtc, plane); } } @@ -15441,13 +15563,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); } - /* restore vblank interrupts to correct state */ - drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { struct intel_plane *plane; - drm_crtc_vblank_on(&crtc->base); - /* Disable everything but the primary plane */ for_each_intel_plane_on_crtc(dev, crtc, plane) { const struct intel_plane_state *plane_state = @@ -15565,23 +15683,32 @@ void i915_redisable_vga(struct drm_i915_private *dev_priv) } /* FIXME read out full plane state for all planes */ -static void readout_plane_state(struct intel_crtc *crtc) +static void readout_plane_state(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - struct intel_crtc_state *crtc_state = - to_intel_crtc_state(crtc->base.state); struct intel_plane *plane; + struct intel_crtc *crtc; - for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { + for_each_intel_plane(&dev_priv->drm, plane) { struct intel_plane_state *plane_state = to_intel_plane_state(plane->base.state); - enum pipe pipe; + struct intel_crtc_state *crtc_state; + enum pipe pipe = PIPE_A; bool visible; visible = plane->get_hw_state(plane, &pipe); + crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + crtc_state = to_intel_crtc_state(crtc->base.state); + intel_set_plane_visible(crtc_state, plane_state, visible); } + + for_each_intel_crtc(&dev_priv->drm, crtc) { + struct intel_crtc_state *crtc_state = + to_intel_crtc_state(crtc->base.state); + + fixup_active_planes(crtc_state); + } } static void intel_modeset_readout_hw_state(struct drm_device *dev) @@ -15613,13 +15740,13 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) if (crtc_state->base.active) dev_priv->active_crtcs |= 1 << crtc->pipe; - readout_plane_state(crtc); - DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n", crtc->base.base.id, crtc->base.name, enableddisabled(crtc_state->base.active)); } + readout_plane_state(dev_priv); + for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; @@ -15789,26 +15916,35 @@ intel_modeset_setup_hw_state(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx) { struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe; struct intel_crtc *crtc; struct intel_encoder *encoder; int i; + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + intel_early_display_was(dev_priv); intel_modeset_readout_hw_state(dev); /* HW state is read out, now we need to sanitize this mess. */ get_encoder_power_domains(dev_priv); - intel_sanitize_plane_mapping(dev_priv); + /* + * intel_sanitize_plane_mapping() may need to do vblank + * waits, so we need vblank interrupts restored beforehand. + */ + for_each_intel_crtc(&dev_priv->drm, crtc) { + drm_crtc_vblank_reset(&crtc->base); - for_each_intel_encoder(dev, encoder) { - intel_sanitize_encoder(encoder); + if (crtc->active) + drm_crtc_vblank_on(&crtc->base); } - for_each_pipe(dev_priv, pipe) { - crtc = intel_get_crtc_for_pipe(dev_priv, pipe); + intel_sanitize_plane_mapping(dev_priv); + for_each_intel_encoder(dev, encoder) + intel_sanitize_encoder(encoder); + + for_each_intel_crtc(&dev_priv->drm, crtc) { intel_sanitize_crtc(crtc, ctx); intel_dump_pipe_config(crtc, crtc->config, "[setup_hw_state]"); @@ -15848,9 +15984,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev, if (WARN_ON(put_domains)) modeset_put_power_domains(dev_priv, put_domains); } - intel_display_set_init_power(dev_priv, false); - intel_power_domains_verify_state(dev_priv); + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); intel_fbc_init_pipe_state(dev_priv); } @@ -15939,8 +16074,6 @@ void intel_modeset_cleanup(struct drm_device *dev) flush_work(&dev_priv->atomic_helper.free_work); WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list)); - intel_disable_gt_powersave(dev_priv); - /* * Interrupts and polling as the first thing to avoid creating havoc. * Too much stuff here (turning of connectors, ...) would @@ -15968,8 +16101,6 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_cleanup_overlay(dev_priv); - intel_cleanup_gt_powersave(dev_priv); - intel_teardown_gmbus(dev_priv); destroy_workqueue(dev_priv->modeset_wq); @@ -16077,8 +16208,7 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv) return NULL; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - error->power_well_driver = - I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL)); + error->power_well_driver = I915_READ(HSW_PWR_WELL_CTL2); for_each_pipe(dev_priv, i) { error->pipe[i].power_domain_on = diff --git a/drivers/gpu/drm/i915/intel_display.h b/drivers/gpu/drm/i915/intel_display.h index 138a1bc1818c..9fac67e31205 100644 --- a/drivers/gpu/drm/i915/intel_display.h +++ b/drivers/gpu/drm/i915/intel_display.h @@ -25,6 +25,24 @@ #ifndef _INTEL_DISPLAY_H_ #define _INTEL_DISPLAY_H_ +#include <drm/drm_util.h> + +enum i915_gpio { + GPIOA, + GPIOB, + GPIOC, + GPIOD, + GPIOE, + GPIOF, + GPIOG, + GPIOH, + __GPIOI_UNUSED, + GPIOJ, + GPIOK, + GPIOL, + GPIOM, +}; + enum pipe { INVALID_PIPE = -1, @@ -161,6 +179,13 @@ enum tc_port { I915_MAX_TC_PORTS }; +enum tc_port_type { + TC_PORT_UNKNOWN = 0, + TC_PORT_TYPEC, + TC_PORT_TBT, + TC_PORT_LEGACY, +}; + enum dpio_channel { DPIO_CH0, DPIO_CH1 @@ -346,11 +371,11 @@ struct intel_link_m_n { #define for_each_power_domain_well(__dev_priv, __power_well, __domain_mask) \ for_each_power_well(__dev_priv, __power_well) \ - for_each_if((__power_well)->domains & (__domain_mask)) + for_each_if((__power_well)->desc->domains & (__domain_mask)) #define for_each_power_domain_well_rev(__dev_priv, __power_well, __domain_mask) \ for_each_power_well_rev(__dev_priv, __power_well) \ - for_each_if((__power_well)->domains & (__domain_mask)) + for_each_if((__power_well)->desc->domains & (__domain_mask)) #define for_each_new_intel_plane_in_state(__state, plane, new_plane_state, __i) \ for ((__i) = 0; \ @@ -380,6 +405,7 @@ struct intel_link_m_n { void intel_link_compute_m_n(int bpp, int nlanes, int pixel_clock, int link_clock, struct intel_link_m_n *m_n, - bool reduce_m_n); + bool constant_n); +bool is_ccs_modifier(u64 modifier); #endif diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1193202766a2..3fae4dab295f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -107,13 +107,6 @@ bool intel_dp_is_edp(struct intel_dp *intel_dp) return intel_dig_port->base.type == INTEL_OUTPUT_EDP; } -static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp) -{ - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - - return intel_dig_port->base.base.dev; -} - static struct intel_dp *intel_attached_dp(struct drm_connector *connector) { return enc_to_intel_dp(&intel_attached_encoder(connector)->base); @@ -176,14 +169,45 @@ static int intel_dp_max_common_rate(struct intel_dp *intel_dp) return intel_dp->common_rates[intel_dp->num_common_rates - 1]; } +static int intel_dp_get_fia_supported_lane_count(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 lane_info; + + if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) + return 4; + + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); + + switch (lane_info) { + default: + MISSING_CASE(lane_info); + case 1: + case 2: + case 4: + case 8: + return 1; + case 3: + case 12: + return 2; + case 15: + return 4; + } +} + /* Theoretical max between source and sink */ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dig_port->max_lanes; int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); + int fia_max = intel_dp_get_fia_supported_lane_count(intel_dp); - return min(source_max, sink_max); + return min3(source_max, sink_max, fia_max); } int intel_dp_max_lane_count(struct intel_dp *intel_dp) @@ -198,6 +222,138 @@ intel_dp_link_required(int pixel_clock, int bpp) return DIV_ROUND_UP(pixel_clock * bpp, 8); } +void icl_program_mg_dp_mode(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + enum port port = intel_dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + u32 ln0, ln1, lane_info; + + if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT) + return; + + ln0 = I915_READ(MG_DP_MODE(port, 0)); + ln1 = I915_READ(MG_DP_MODE(port, 1)); + + switch (intel_dig_port->tc_type) { + case TC_PORT_TYPEC: + ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); + ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); + + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); + + switch (lane_info) { + case 0x1: + case 0x4: + break; + case 0x2: + ln0 |= MG_DP_MODE_CFG_DP_X1_MODE; + break; + case 0x3: + ln0 |= MG_DP_MODE_CFG_DP_X1_MODE | + MG_DP_MODE_CFG_DP_X2_MODE; + break; + case 0x8: + ln1 |= MG_DP_MODE_CFG_DP_X1_MODE; + break; + case 0xC: + ln1 |= MG_DP_MODE_CFG_DP_X1_MODE | + MG_DP_MODE_CFG_DP_X2_MODE; + break; + case 0xF: + ln0 |= MG_DP_MODE_CFG_DP_X1_MODE | + MG_DP_MODE_CFG_DP_X2_MODE; + ln1 |= MG_DP_MODE_CFG_DP_X1_MODE | + MG_DP_MODE_CFG_DP_X2_MODE; + break; + default: + MISSING_CASE(lane_info); + } + break; + + case TC_PORT_LEGACY: + ln0 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE; + ln1 |= MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE; + break; + + default: + MISSING_CASE(intel_dig_port->tc_type); + return; + } + + I915_WRITE(MG_DP_MODE(port, 0), ln0); + I915_WRITE(MG_DP_MODE(port, 1), ln1); +} + +void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) }; + u32 val; + int i; + + if (tc_port == PORT_TC_NONE) + return; + + for (i = 0; i < ARRAY_SIZE(mg_regs); i++) { + val = I915_READ(mg_regs[i]); + val |= MG_DP_MODE_CFG_TR2PWR_GATING | + MG_DP_MODE_CFG_TRPWR_GATING | + MG_DP_MODE_CFG_CLNPWR_GATING | + MG_DP_MODE_CFG_DIGPWR_GATING | + MG_DP_MODE_CFG_GAONPWR_GATING; + I915_WRITE(mg_regs[i], val); + } + + val = I915_READ(MG_MISC_SUS0(tc_port)); + val |= MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE(3) | + MG_MISC_SUS0_CFG_TR2PWR_GATING | + MG_MISC_SUS0_CFG_CL2PWR_GATING | + MG_MISC_SUS0_CFG_GAONPWR_GATING | + MG_MISC_SUS0_CFG_TRPWR_GATING | + MG_MISC_SUS0_CFG_CL1PWR_GATING | + MG_MISC_SUS0_CFG_DGPWR_GATING; + I915_WRITE(MG_MISC_SUS0(tc_port), val); +} + +void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + i915_reg_t mg_regs[2] = { MG_DP_MODE(port, 0), MG_DP_MODE(port, 1) }; + u32 val; + int i; + + if (tc_port == PORT_TC_NONE) + return; + + for (i = 0; i < ARRAY_SIZE(mg_regs); i++) { + val = I915_READ(mg_regs[i]); + val &= ~(MG_DP_MODE_CFG_TR2PWR_GATING | + MG_DP_MODE_CFG_TRPWR_GATING | + MG_DP_MODE_CFG_CLNPWR_GATING | + MG_DP_MODE_CFG_DIGPWR_GATING | + MG_DP_MODE_CFG_GAONPWR_GATING); + I915_WRITE(mg_regs[i], val); + } + + val = I915_READ(MG_MISC_SUS0(tc_port)); + val &= ~(MG_MISC_SUS0_SUSCLK_DYNCLKGATE_MODE_MASK | + MG_MISC_SUS0_CFG_TR2PWR_GATING | + MG_MISC_SUS0_CFG_CL2PWR_GATING | + MG_MISC_SUS0_CFG_GAONPWR_GATING | + MG_MISC_SUS0_CFG_TRPWR_GATING | + MG_MISC_SUS0_CFG_CL1PWR_GATING | + MG_MISC_SUS0_CFG_DGPWR_GATING); + I915_WRITE(MG_MISC_SUS0(tc_port), val); +} + int intel_dp_max_data_rate(int max_link_clock, int max_lanes) { @@ -401,6 +557,22 @@ static bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, return true; } +static bool intel_dp_can_link_train_fallback_for_edp(struct intel_dp *intel_dp, + int link_rate, + uint8_t lane_count) +{ + const struct drm_display_mode *fixed_mode = + intel_dp->attached_connector->panel.fixed_mode; + int mode_rate, max_rate; + + mode_rate = intel_dp_link_required(fixed_mode->clock, 18); + max_rate = intel_dp_max_data_rate(link_rate, lane_count); + if (mode_rate > max_rate) + return false; + + return true; +} + int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, int link_rate, uint8_t lane_count) { @@ -410,9 +582,23 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, intel_dp->num_common_rates, link_rate); if (index > 0) { + if (intel_dp_is_edp(intel_dp) && + !intel_dp_can_link_train_fallback_for_edp(intel_dp, + intel_dp->common_rates[index - 1], + lane_count)) { + DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n"); + return 0; + } intel_dp->max_link_rate = intel_dp->common_rates[index - 1]; intel_dp->max_link_lane_count = lane_count; } else if (lane_count > 1) { + if (intel_dp_is_edp(intel_dp) && + !intel_dp_can_link_train_fallback_for_edp(intel_dp, + intel_dp_max_common_rate(intel_dp), + lane_count >> 1)) { + DRM_DEBUG_KMS("Retrying Link training for eDP with same parameters\n"); + return 0; + } intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp); intel_dp->max_link_lane_count = lane_count >> 1; } else { @@ -498,7 +684,7 @@ intel_dp_pps_init(struct intel_dp *intel_dp); static void pps_lock(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); /* * See intel_power_sequencer_reset() why we need @@ -511,7 +697,7 @@ static void pps_lock(struct intel_dp *intel_dp) static void pps_unlock(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); mutex_unlock(&dev_priv->pps_mutex); @@ -521,7 +707,7 @@ static void pps_unlock(struct intel_dp *intel_dp) static void vlv_power_sequencer_kick(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum pipe pipe = intel_dp->pps_pipe; bool pll_enabled, release_cl_override = false; @@ -626,7 +812,7 @@ static enum pipe vlv_find_free_pps(struct drm_i915_private *dev_priv) static enum pipe vlv_power_sequencer_pipe(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum pipe pipe; @@ -673,7 +859,7 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) static int bxt_power_sequencer_idx(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); int backlight_controller = dev_priv->vbt.backlight.controller; lockdep_assert_held(&dev_priv->pps_mutex); @@ -742,7 +928,7 @@ vlv_initial_pps_pipe(struct drm_i915_private *dev_priv, static void vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->base.port; @@ -819,7 +1005,7 @@ struct pps_registers { static void intel_pps_get_registers(struct intel_dp *intel_dp, struct pps_registers *regs) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); int pps_idx = 0; memset(regs, 0, sizeof(*regs)); @@ -865,7 +1051,7 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code, { struct intel_dp *intel_dp = container_of(this, typeof(* intel_dp), edp_notifier); - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!intel_dp_is_edp(intel_dp) || code != SYS_RESTART) return 0; @@ -895,7 +1081,7 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code, static bool edp_have_panel_power(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); lockdep_assert_held(&dev_priv->pps_mutex); @@ -908,7 +1094,7 @@ static bool edp_have_panel_power(struct intel_dp *intel_dp) static bool edp_have_panel_vdd(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); lockdep_assert_held(&dev_priv->pps_mutex); @@ -922,7 +1108,7 @@ static bool edp_have_panel_vdd(struct intel_dp *intel_dp) static void intel_dp_check_edp(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!intel_dp_is_edp(intel_dp)) return; @@ -938,7 +1124,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp) static uint32_t intel_dp_aux_wait_done(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); uint32_t status; bool done; @@ -955,7 +1141,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp) static uint32_t g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (index) return 0; @@ -969,7 +1155,7 @@ static uint32_t g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (index) return 0; @@ -987,7 +1173,7 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (intel_dp->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) { /* Workaround for non-ULT HSW */ @@ -1045,15 +1231,23 @@ static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp, int send_bytes, uint32_t unused) { - return DP_AUX_CH_CTL_SEND_BUSY | - DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_INTERRUPT | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_TIME_OUT_MAX | - DP_AUX_CH_CTL_RECEIVE_ERROR | - (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | - DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | - DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + uint32_t ret; + + ret = DP_AUX_CH_CTL_SEND_BUSY | + DP_AUX_CH_CTL_DONE | + DP_AUX_CH_CTL_INTERRUPT | + DP_AUX_CH_CTL_TIME_OUT_ERROR | + DP_AUX_CH_CTL_TIME_OUT_MAX | + DP_AUX_CH_CTL_RECEIVE_ERROR | + (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | + DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | + DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); + + if (intel_dig_port->tc_type == TC_PORT_TBT) + ret |= DP_AUX_CH_CTL_TBT_IO; + + return ret; } static int @@ -1381,7 +1575,7 @@ intel_aux_power_domain(struct intel_dp *intel_dp) static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1397,7 +1591,7 @@ static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1413,7 +1607,7 @@ static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1431,7 +1625,7 @@ static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1449,7 +1643,7 @@ static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1468,7 +1662,7 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum aux_ch aux_ch = intel_dp->aux_ch; switch (aux_ch) { @@ -1494,7 +1688,7 @@ intel_dp_aux_fini(struct intel_dp *intel_dp) static void intel_dp_aux_init(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; intel_dp->aux_ch = intel_aux_ch(intel_dp); @@ -1662,7 +1856,7 @@ struct link_config_limits { static int intel_dp_compute_bpp(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_connector *intel_connector = intel_dp->attached_connector; int bpp, bpc; @@ -1834,8 +2028,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_connector *intel_connector = intel_dp->attached_connector; struct intel_digital_connector_state *intel_conn_state = to_intel_digital_connector_state(conn_state); - bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, - DP_DPCD_QUIRK_LIMITED_M_N); + bool constant_n = drm_dp_has_quirk(&intel_dp->desc, + DP_DPCD_QUIRK_CONSTANT_N); if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && port != PORT_A) pipe_config->has_pch_encoder = true; @@ -1900,7 +2094,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, adjusted_mode->crtc_clock, pipe_config->port_clock, &pipe_config->dp_m_n, - reduce_m_n); + constant_n); if (intel_connector->panel.downclock_mode != NULL && dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) { @@ -1910,7 +2104,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_connector->panel.downclock_mode->clock, pipe_config->port_clock, &pipe_config->dp_m2_n2, - reduce_m_n); + constant_n); } if (!HAS_DDI(dev_priv)) @@ -2030,7 +2224,7 @@ static void wait_panel_status(struct intel_dp *intel_dp, u32 mask, u32 value) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); i915_reg_t pp_stat_reg, pp_ctrl_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -2106,7 +2300,7 @@ static void edp_wait_backlight_off(struct intel_dp *intel_dp) static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 control; lockdep_assert_held(&dev_priv->pps_mutex); @@ -2127,7 +2321,7 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) */ static bool edp_panel_vdd_on(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); u32 pp; i915_reg_t pp_stat_reg, pp_ctrl_reg; @@ -2198,7 +2392,7 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp) static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); u32 pp; @@ -2264,7 +2458,7 @@ static void edp_panel_vdd_schedule_off(struct intel_dp *intel_dp) */ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); lockdep_assert_held(&dev_priv->pps_mutex); @@ -2284,7 +2478,7 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) static void edp_panel_on(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp; i915_reg_t pp_ctrl_reg; @@ -2342,7 +2536,7 @@ void intel_edp_panel_on(struct intel_dp *intel_dp) static void edp_panel_off(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp; i915_reg_t pp_ctrl_reg; @@ -2390,7 +2584,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp) /* Enable backlight in the panel power control. */ static void _intel_edp_backlight_on(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp; i915_reg_t pp_ctrl_reg; @@ -2433,7 +2627,7 @@ void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state, /* Disable backlight in the panel power control. */ static void _intel_edp_backlight_off(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp; i915_reg_t pp_ctrl_reg; @@ -2864,7 +3058,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t *DP, uint8_t dp_train_pat) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->base.port; uint8_t train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd); @@ -2946,7 +3140,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp, static void intel_dp_enable_port(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); /* enable with pattern 1 (as per spec) */ @@ -3203,7 +3397,7 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ uint8_t intel_dp_voltage_max(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; enum port port = encoder->port; @@ -3222,7 +3416,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) uint8_t intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; enum port port = encoder->port; @@ -3534,13 +3728,13 @@ ivb_cpu_edp_signal_levels(uint8_t train_set) void intel_dp_set_signal_levels(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->base.port; uint32_t signal_levels, mask = 0; uint8_t train_set = intel_dp->train_set[0]; - if (IS_GEN9_LP(dev_priv) || IS_CANNONLAKE(dev_priv)) { + if (IS_GEN9_LP(dev_priv) || INTEL_GEN(dev_priv) >= 10) { signal_levels = bxt_signal_levels(intel_dp); } else if (HAS_DDI(dev_priv)) { signal_levels = ddi_signal_levels(intel_dp); @@ -3591,7 +3785,7 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->base.port; uint32_t val; @@ -4090,12 +4284,14 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) int ret = 0; int retry; bool handled; + + WARN_ON_ONCE(intel_dp->active_mst_links < 0); bret = intel_dp_get_sink_irq_esi(intel_dp, esi); go_again: if (bret == true) { /* check link status - esi[10] = 0x200c */ - if (intel_dp->active_mst_links && + if (intel_dp->active_mst_links > 0 && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) { DRM_DEBUG_KMS("channel EQ not ok, retraining\n"); intel_dp_start_link_train(intel_dp); @@ -4282,7 +4478,7 @@ static bool intel_dp_hotplug(struct intel_encoder *encoder, static bool intel_dp_short_pulse(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 sink_irq_vector = 0; u8 old_sink_count = intel_dp->sink_count; bool ret; @@ -4574,10 +4770,205 @@ static bool bxt_digital_port_connected(struct intel_encoder *encoder) return I915_READ(GEN8_DE_PORT_ISR) & bit; } +static bool icl_combo_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port) +{ + enum port port = intel_dig_port->base.port; + + return I915_READ(SDEISR) & SDE_DDI_HOTPLUG_ICP(port); +} + +static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port, + bool is_legacy, bool is_typec, bool is_tbt) +{ + enum port port = intel_dig_port->base.port; + enum tc_port_type old_type = intel_dig_port->tc_type; + const char *type_str; + + WARN_ON(is_legacy + is_typec + is_tbt != 1); + + if (is_legacy) { + intel_dig_port->tc_type = TC_PORT_LEGACY; + type_str = "legacy"; + } else if (is_typec) { + intel_dig_port->tc_type = TC_PORT_TYPEC; + type_str = "typec"; + } else if (is_tbt) { + intel_dig_port->tc_type = TC_PORT_TBT; + type_str = "tbt"; + } else { + return; + } + + /* Types are not supposed to be changed at runtime. */ + WARN_ON(old_type != TC_PORT_UNKNOWN && + old_type != intel_dig_port->tc_type); + + if (old_type != intel_dig_port->tc_type) + DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), + type_str); +} + +/* + * This function implements the first part of the Connect Flow described by our + * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading + * lanes, EDID, etc) is done as needed in the typical places. + * + * Unlike the other ports, type-C ports are not available to use as soon as we + * get a hotplug. The type-C PHYs can be shared between multiple controllers: + * display, USB, etc. As a result, handshaking through FIA is required around + * connect and disconnect to cleanly transfer ownership with the controller and + * set the type-C power state. + * + * We could opt to only do the connect flow when we actually try to use the AUX + * channels or do a modeset, then immediately run the disconnect flow after + * usage, but there are some implications on this for a dynamic environment: + * things may go away or change behind our backs. So for now our driver is + * always trying to acquire ownership of the controller as soon as it gets an + * interrupt (or polls state and sees a port is connected) and only gives it + * back when it sees a disconnect. Implementation of a more fine-grained model + * will require a lot of coordination with user space and thorough testing for + * the extra possible cases. + */ +static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port) +{ + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; + + if (dig_port->tc_type != TC_PORT_LEGACY && + dig_port->tc_type != TC_PORT_TYPEC) + return true; + + val = I915_READ(PORT_TX_DFLEXDPPMS); + if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { + DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); + return false; + } + + /* + * This function may be called many times in a row without an HPD event + * in between, so try to avoid the write when we can. + */ + val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { + val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } + + /* + * Now we have to re-check the live state, in case the port recently + * became disconnected. Not necessary for legacy mode. + */ + if (dig_port->tc_type == TC_PORT_TYPEC && + !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { + DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); + val = I915_READ(PORT_TX_DFLEXDPCSSS); + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + return false; + } + + return true; +} + +/* + * See the comment at the connect function. This implements the Disconnect + * Flow. + */ +static void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port) +{ + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; + + if (dig_port->tc_type != TC_PORT_LEGACY && + dig_port->tc_type != TC_PORT_TYPEC) + return; + + /* + * This function may be called many times in a row without an HPD event + * in between, so try to avoid the write when we can. + */ + val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port)) { + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } +} + +/* + * The type-C ports are different because even when they are connected, they may + * not be available/usable by the graphics driver: see the comment on + * icl_tc_phy_connect(). So in our driver instead of adding the additional + * concept of "usable" and make everything check for "connected and usable" we + * define a port as "connected" when it is not only connected, but also when it + * is usable by the rest of the driver. That maintains the old assumption that + * connected ports are usable, and avoids exposing to the users objects they + * can't really use. + */ +static bool icl_tc_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port) +{ + enum port port = intel_dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + bool is_legacy, is_typec, is_tbt; + u32 dpsp; + + is_legacy = I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port); + + /* + * The spec says we shouldn't be using the ISR bits for detecting + * between TC and TBT. We should use DFLEXDPSP. + */ + dpsp = I915_READ(PORT_TX_DFLEXDPSP); + is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); + is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); + + if (!is_legacy && !is_typec && !is_tbt) { + icl_tc_phy_disconnect(dev_priv, intel_dig_port); + return false; + } + + icl_update_tc_port_type(dev_priv, intel_dig_port, is_legacy, is_typec, + is_tbt); + + if (!icl_tc_phy_connect(dev_priv, intel_dig_port)) + return false; + + return true; +} + +static bool icl_digital_port_connected(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); + + switch (encoder->hpd_pin) { + case HPD_PORT_A: + case HPD_PORT_B: + return icl_combo_port_connected(dev_priv, dig_port); + case HPD_PORT_C: + case HPD_PORT_D: + case HPD_PORT_E: + case HPD_PORT_F: + return icl_tc_port_connected(dev_priv, dig_port); + default: + MISSING_CASE(encoder->hpd_pin); + return false; + } +} + /* * intel_digital_port_connected - is the specified port connected? * @encoder: intel_encoder * + * In cases where there's a connector physically connected but it can't be used + * by our hardware we also return false, since the rest of the driver should + * pretty much treat the port as disconnected. This is relevant for type-C + * (starting on ICL) where there's ownership involved. + * * Return %true if port is connected, %false otherwise. */ bool intel_digital_port_connected(struct intel_encoder *encoder) @@ -4601,8 +4992,10 @@ bool intel_digital_port_connected(struct intel_encoder *encoder) return bdw_digital_port_connected(encoder); else if (IS_GEN9_LP(dev_priv)) return bxt_digital_port_connected(encoder); - else + else if (IS_GEN9_BC(dev_priv) || IS_GEN10(dev_priv)) return spt_digital_port_connected(encoder); + else + return icl_digital_port_connected(encoder); } static struct edid * @@ -5177,7 +5570,7 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = { static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); lockdep_assert_held(&dev_priv->pps_mutex); @@ -5198,7 +5591,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) static enum pipe vlv_active_pipe(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; enum pipe pipe; @@ -5265,7 +5658,7 @@ enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) { struct intel_dp *intel_dp = &intel_dig_port->dp; - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum irqreturn ret = IRQ_NONE; if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) { @@ -5381,7 +5774,7 @@ static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp) static void intel_pps_readout_hw_state(struct intel_dp *intel_dp, struct edp_power_seq *seq) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0; struct pps_registers regs; @@ -5449,7 +5842,7 @@ intel_pps_verify_state(struct intel_dp *intel_dp) static void intel_dp_init_panel_power_sequencer(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct edp_power_seq cur, vbt, spec, *final = &intel_dp->pps_delays; @@ -5542,7 +5935,7 @@ static void intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, bool force_disable_vdd) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 pp_on, pp_off, pp_div, port_sel = 0; int div = dev_priv->rawclk_freq / 1000; struct pps_registers regs; @@ -5638,7 +6031,7 @@ intel_dp_init_panel_power_sequencer_registers(struct intel_dp *intel_dp, static void intel_dp_pps_init(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { vlv_initial_power_sequencer_setup(intel_dp); @@ -5755,7 +6148,7 @@ static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv, void intel_edp_drrs_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!crtc_state->has_drrs) { DRM_DEBUG_KMS("Panel doesn't support DRRS\n"); @@ -5790,7 +6183,7 @@ unlock: void intel_edp_drrs_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state) { - struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!old_crtc_state->has_drrs) return; @@ -6022,8 +6415,8 @@ intel_dp_drrs_init(struct intel_connector *connector, static bool intel_edp_init_connector(struct intel_dp *intel_dp, struct intel_connector *intel_connector) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_device *dev = &dev_priv->drm; struct drm_connector *connector = &intel_connector->base; struct drm_display_mode *fixed_mode = NULL; struct drm_display_mode *downclock_mode = NULL; diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c index 4da6e33c7fa1..30be0e39bd5f 100644 --- a/drivers/gpu/drm/i915/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -129,7 +129,8 @@ static bool intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) { uint8_t voltage; - int voltage_tries, max_vswing_tries; + int voltage_tries, cr_tries, max_cr_tries; + bool max_vswing_reached = false; uint8_t link_config[2]; uint8_t link_bw, rate_select; @@ -170,9 +171,21 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) return false; } + /* + * The DP 1.4 spec defines the max clock recovery retries value + * as 10 but for pre-DP 1.4 devices we set a very tolerant + * retry limit of 80 (4 voltage levels x 4 preemphasis levels x + * x 5 identical voltage retries). Since the previous specs didn't + * define a limit and created the possibility of an infinite loop + * we want to prevent any sync from triggering that corner case. + */ + if (intel_dp->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) + max_cr_tries = 10; + else + max_cr_tries = 80; + voltage_tries = 1; - max_vswing_tries = 0; - for (;;) { + for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) { uint8_t link_status[DP_LINK_STATUS_SIZE]; drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); @@ -192,7 +205,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) return false; } - if (max_vswing_tries == 1) { + if (max_vswing_reached) { DRM_DEBUG_KMS("Max Voltage Swing reached\n"); return false; } @@ -213,9 +226,11 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) voltage_tries = 1; if (intel_dp_link_max_vswing_reached(intel_dp)) - ++max_vswing_tries; + max_vswing_reached = true; } + DRM_ERROR("Failed clock recovery %d times, giving up!\n", max_cr_tries); + return false; } /* @@ -352,22 +367,14 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) return; failure_handling: - /* Dont fallback and prune modes if its eDP */ - if (!intel_dp_is_edp(intel_dp)) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", - intel_connector->base.base.id, - intel_connector->base.name, - intel_dp->link_rate, intel_dp->lane_count); - if (!intel_dp_get_link_train_fallback_values(intel_dp, - intel_dp->link_rate, - intel_dp->lane_count)) - /* Schedule a Hotplug Uevent to userspace to start modeset */ - schedule_work(&intel_connector->modeset_retry_work); - } else { - DRM_ERROR("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", - intel_connector->base.base.id, - intel_connector->base.name, - intel_dp->link_rate, intel_dp->lane_count); - } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d", + intel_connector->base.base.id, + intel_connector->base.name, + intel_dp->link_rate, intel_dp->lane_count); + if (!intel_dp_get_link_train_fallback_values(intel_dp, + intel_dp->link_rate, + intel_dp->lane_count)) + /* Schedule a Hotplug Uevent to userspace to start modeset */ + schedule_work(&intel_connector->modeset_retry_work); return; } diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 4ecd65375603..7f155b4f1a7d 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -38,15 +38,15 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; - struct intel_connector *connector = - to_intel_connector(conn_state->connector); + struct drm_connector *connector = conn_state->connector; + void *port = to_intel_connector(connector)->port; struct drm_atomic_state *state = pipe_config->base.state; int bpp; - int lane_count, slots; + int lane_count, slots = 0; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; int mst_pbn; - bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc, - DP_DPCD_QUIRK_LIMITED_M_N); + bool constant_n = drm_dp_has_quirk(&intel_dp->desc, + DP_DPCD_QUIRK_CONSTANT_N); if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return false; @@ -70,24 +70,30 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->port_clock = intel_dp_max_link_rate(intel_dp); - if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, connector->port)) + if (drm_dp_mst_port_has_audio(&intel_dp->mst_mgr, port)) pipe_config->has_audio = true; mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); pipe_config->pbn = mst_pbn; - slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, - connector->port, mst_pbn); - if (slots < 0) { - DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", slots); - return false; + /* Zombie connectors can't have VCPI slots */ + if (READ_ONCE(connector->registered)) { + slots = drm_dp_atomic_find_vcpi_slots(state, + &intel_dp->mst_mgr, + port, + mst_pbn); + if (slots < 0) { + DRM_DEBUG_KMS("failed finding vcpi slots:%d\n", + slots); + return false; + } } intel_link_compute_m_n(bpp, lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, &pipe_config->dp_m_n, - reduce_m_n); + constant_n); pipe_config->dp_m_n.tu = slots; @@ -243,11 +249,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, connector->port, pipe_config->pbn, pipe_config->dp_m_n.tu); - if (ret == false) { + if (!ret) DRM_ERROR("failed to allocate vcpi\n"); - return; - } - intel_dp->active_mst_links++; temp = I915_READ(DP_TP_STATUS(port)); @@ -267,7 +270,6 @@ static void intel_mst_enable_dp(struct intel_encoder *encoder, struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum port port = intel_dig_port->base.port; - int ret; DRM_DEBUG_KMS("active links %d\n", intel_dp->active_mst_links); @@ -278,9 +280,9 @@ static void intel_mst_enable_dp(struct intel_encoder *encoder, 1)) DRM_ERROR("Timed out waiting for ACT sent\n"); - ret = drm_dp_check_act_status(&intel_dp->mst_mgr); + drm_dp_check_act_status(&intel_dp->mst_mgr); - ret = drm_dp_update_payload_part2(&intel_dp->mst_mgr); + drm_dp_update_payload_part2(&intel_dp->mst_mgr); if (pipe_config->has_audio) intel_audio_codec_enable(encoder, pipe_config, conn_state); } @@ -311,9 +313,8 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) struct edid *edid; int ret; - if (!intel_dp) { + if (!READ_ONCE(connector->registered)) return intel_connector_update_modes(connector, NULL); - } edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); ret = intel_connector_update_modes(connector, edid); @@ -328,9 +329,10 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force) struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_connector->mst_port; - if (!intel_dp) + if (!READ_ONCE(connector->registered)) return connector_status_disconnected; - return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port); + return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, + intel_connector->port); } static void @@ -370,7 +372,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, int bpp = 24; /* MST uses fixed bpp */ int max_rate, mode_rate, max_lanes, max_link_clock; - if (!intel_dp) + if (!READ_ONCE(connector->registered)) return MODE_ERROR; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -402,8 +404,6 @@ static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *c struct intel_dp *intel_dp = intel_connector->mst_port; struct intel_crtc *crtc = to_intel_crtc(state->crtc); - if (!intel_dp) - return NULL; return &intel_dp->mst_encoders[crtc->pipe]->base.base; } @@ -503,7 +503,6 @@ static void intel_dp_register_mst_connector(struct drm_connector *connector) static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_connector *connector) { - struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_i915_private *dev_priv = to_i915(connector->dev); DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -512,10 +511,6 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, if (dev_priv->fbdev) drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, connector); - /* prevent race with the check in ->detect */ - drm_modeset_lock(&connector->dev->mode_config.connection_mutex, NULL); - intel_connector->mst_port = NULL; - drm_modeset_unlock(&connector->dev->mode_config.connection_mutex); drm_connector_put(connector); } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index b51ad2917dbe..e6cac9225536 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -2212,6 +2212,20 @@ static void cnl_wrpll_params_populate(struct skl_wrpll_params *params, params->dco_fraction = dco & 0x7fff; } +int cnl_hdmi_pll_ref_clock(struct drm_i915_private *dev_priv) +{ + int ref_clock = dev_priv->cdclk.hw.ref; + + /* + * For ICL+, the spec states: if reference frequency is 38.4, + * use 19.2 because the DPLL automatically divides that by 2. + */ + if (INTEL_GEN(dev_priv) >= 11 && ref_clock == 38400) + ref_clock = 19200; + + return ref_clock; +} + static bool cnl_ddi_calculate_wrpll(int clock, struct drm_i915_private *dev_priv, @@ -2251,14 +2265,7 @@ cnl_ddi_calculate_wrpll(int clock, cnl_wrpll_get_multipliers(best_div, &pdiv, &qdiv, &kdiv); - ref_clock = dev_priv->cdclk.hw.ref; - - /* - * For ICL, the spec states: if reference frequency is 38.4, use 19.2 - * because the DPLL automatically divides that by 2. - */ - if (IS_ICELAKE(dev_priv) && ref_clock == 38400) - ref_clock = 19200; + ref_clock = cnl_hdmi_pll_ref_clock(dev_priv); cnl_wrpll_params_populate(wrpll_params, best_dco, ref_clock, pdiv, qdiv, kdiv); @@ -2452,6 +2459,16 @@ static const struct skl_wrpll_params icl_dp_combo_pll_19_2MHz_values[] = { .pdiv = 0x1 /* 2 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0}, }; +static const struct skl_wrpll_params icl_tbt_pll_24MHz_values = { + .dco_integer = 0x151, .dco_fraction = 0x4000, + .pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, +}; + +static const struct skl_wrpll_params icl_tbt_pll_19_2MHz_values = { + .dco_integer = 0x1A5, .dco_fraction = 0x7000, + .pdiv = 0x4 /* 5 */, .kdiv = 1, .qdiv_mode = 0, .qdiv_ratio = 0, +}; + static bool icl_calc_dp_combo_pll(struct drm_i915_private *dev_priv, int clock, struct skl_wrpll_params *pll_params) { @@ -2494,6 +2511,14 @@ static bool icl_calc_dp_combo_pll(struct drm_i915_private *dev_priv, int clock, return true; } +static bool icl_calc_tbt_pll(struct drm_i915_private *dev_priv, int clock, + struct skl_wrpll_params *pll_params) +{ + *pll_params = dev_priv->cdclk.hw.ref == 24000 ? + icl_tbt_pll_24MHz_values : icl_tbt_pll_19_2MHz_values; + return true; +} + static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder, int clock, struct intel_dpll_hw_state *pll_state) @@ -2503,7 +2528,9 @@ static bool icl_calc_dpll_state(struct intel_crtc_state *crtc_state, struct skl_wrpll_params pll_params = { 0 }; bool ret; - if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) + if (intel_port_is_tc(dev_priv, encoder->port)) + ret = icl_calc_tbt_pll(dev_priv, clock, &pll_params); + else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) ret = cnl_ddi_calculate_wrpll(clock, dev_priv, &pll_params); else ret = icl_calc_dp_combo_pll(dev_priv, clock, &pll_params); @@ -2623,7 +2650,8 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, for (div2 = 10; div2 > 0; div2--) { int dco = div1 * div2 * clock_khz * 5; - int a_divratio, tlinedrv, inputsel, hsdiv; + int a_divratio, tlinedrv, inputsel; + u32 hsdiv; if (dco < dco_min_freq || dco > dco_max_freq) continue; @@ -2642,16 +2670,16 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, MISSING_CASE(div1); /* fall through */ case 2: - hsdiv = 0; + hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_2; break; case 3: - hsdiv = 1; + hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_3; break; case 5: - hsdiv = 2; + hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_5; break; case 7: - hsdiv = 3; + hsdiv = MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_7; break; } @@ -2665,7 +2693,7 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc, state->mg_clktop2_hsclkctl = MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(tlinedrv) | MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(inputsel) | - MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO(hsdiv) | + hsdiv | MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(div2); return true; @@ -2846,6 +2874,8 @@ static struct intel_shared_dpll * icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_encoder *encoder) { + struct intel_digital_port *intel_dig_port = + enc_to_dig_port(&encoder->base); struct intel_shared_dpll *pll; struct intel_dpll_hw_state pll_state = {}; enum port port = encoder->port; @@ -2865,7 +2895,7 @@ icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, case PORT_D: case PORT_E: case PORT_F: - if (0 /* TODO: TBT PLLs */) { + if (intel_dig_port->tc_type == TC_PORT_TBT) { min = DPLL_ID_ICL_TBTPLL; max = min; ret = icl_calc_dpll_state(crtc_state, encoder, clock, diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h index 7e522cf4f13f..bf0de8a4dc63 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h @@ -344,5 +344,6 @@ void intel_dpll_dump_hw_state(struct drm_i915_private *dev_priv, struct intel_dpll_hw_state *hw_state); int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv, uint32_t pll_id); +int cnl_hdmi_pll_ref_clock(struct drm_i915_private *dev_priv); #endif /* _INTEL_DPLL_MGR_H_ */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8fc61e96754f..f8dc84b2d2d3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -497,18 +497,21 @@ struct intel_atomic_state { struct intel_plane_state { struct drm_plane_state base; + struct i915_ggtt_view view; struct i915_vma *vma; unsigned long flags; #define PLANE_HAS_FENCE BIT(0) struct { u32 offset; + /* + * Plane stride in: + * bytes for 0/180 degree rotation + * pixels for 90/270 degree rotation + */ + u32 stride; int x, y; - } main; - struct { - u32 offset; - int x, y; - } aux; + } color_plane[2]; /* plane control register */ u32 ctl; @@ -950,10 +953,8 @@ struct intel_plane { enum i9xx_plane_id i9xx_plane; enum plane_id id; enum pipe pipe; - bool can_scale; bool has_fbc; bool has_ccs; - int max_downscale; uint32_t frontbuffer_bit; struct { @@ -966,15 +967,17 @@ struct intel_plane { * the intel_plane_state structure and accessed via plane_state. */ + unsigned int (*max_stride)(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation); void (*update_plane)(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); void (*disable_plane)(struct intel_plane *plane, struct intel_crtc *crtc); bool (*get_hw_state)(struct intel_plane *plane, enum pipe *pipe); - int (*check_plane)(struct intel_plane *plane, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *state); + int (*check_plane)(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); }; struct intel_watermark_params { @@ -1168,6 +1171,7 @@ struct intel_digital_port { bool release_cl2_override; uint8_t max_lanes; enum intel_display_power_domain ddi_io_power_domain; + enum tc_port_type tc_type; void (*write_infoframe)(struct drm_encoder *encoder, const struct intel_crtc_state *crtc_state, @@ -1314,6 +1318,12 @@ dp_to_lspcon(struct intel_dp *intel_dp) return &dp_to_dig_port(intel_dp)->lspcon; } +static inline struct drm_i915_private * +dp_to_i915(struct intel_dp *intel_dp) +{ + return to_i915(dp_to_dig_port(intel_dp)->base.base.dev); +} + static inline struct intel_digital_port * hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) { @@ -1436,7 +1446,7 @@ void icl_unmap_plls_to_ports(struct drm_crtc *crtc, struct drm_atomic_state *old_state); unsigned int intel_fb_align_height(const struct drm_framebuffer *fb, - int plane, unsigned int height); + int color_plane, unsigned int height); /* intel_audio.c */ void intel_init_audio_hooks(struct drm_i915_private *dev_priv); @@ -1507,6 +1517,7 @@ void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); struct drm_display_mode * intel_encoder_current_mode(struct intel_encoder *encoder); +bool intel_port_is_combophy(struct drm_i915_private *dev_priv, enum port port); bool intel_port_is_tc(struct drm_i915_private *dev_priv, enum port port); enum tc_port intel_port_to_tc(struct drm_i915_private *dev_priv, enum port port); @@ -1559,7 +1570,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx); struct i915_vma * intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, - unsigned int rotation, + const struct i915_ggtt_view *view, bool uses_fence, unsigned long *out_flags); void intel_unpin_fb_vma(struct i915_vma *vma, unsigned long flags); @@ -1608,8 +1619,6 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -u32 intel_compute_tile_offset(int *x, int *y, - const struct intel_plane_state *state, int plane); void intel_prepare_reset(struct drm_i915_private *dev_priv); void intel_finish_reset(struct drm_i915_private *dev_priv); void hsw_enable_pc8(struct drm_i915_private *dev_priv); @@ -1639,8 +1648,8 @@ void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc, u16 skl_scaler_calc_phase(int sub, bool chroma_center); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); -int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, - uint32_t pixel_format); +int skl_max_scale(const struct intel_crtc_state *crtc_state, + u32 pixel_format); static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state) { @@ -1652,12 +1661,14 @@ u32 glk_plane_color_ctl(const struct intel_crtc_state *crtc_state, u32 skl_plane_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state); u32 glk_color_ctl(const struct intel_plane_state *plane_state); -u32 skl_plane_stride(const struct drm_framebuffer *fb, int plane, - unsigned int rotation); -int skl_check_plane_surface(const struct intel_crtc_state *crtc_state, - struct intel_plane_state *plane_state); +u32 skl_plane_stride(const struct intel_plane_state *plane_state, + int plane); +int skl_check_plane_surface(struct intel_plane_state *plane_state); int i9xx_check_plane_surface(struct intel_plane_state *plane_state); int skl_format_to_fourcc(int format, bool rgb_order, bool alpha); +unsigned int i9xx_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation); /* intel_csr.c */ void intel_csr_ucode_init(struct drm_i915_private *); @@ -1717,6 +1728,9 @@ void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); void intel_edp_drrs_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); +void icl_program_mg_dp_mode(struct intel_dp *intel_dp); +void icl_enable_phy_clock_gating(struct intel_digital_port *dig_port); +void icl_disable_phy_clock_gating(struct intel_digital_port *dig_port); void intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, @@ -1930,6 +1944,9 @@ void intel_psr_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state); +int intel_psr_set_debugfs_mode(struct drm_i915_private *dev_priv, + struct drm_modeset_acquire_ctx *ctx, + u64 value); void intel_psr_invalidate(struct drm_i915_private *dev_priv, unsigned frontbuffer_bits, enum fb_op_origin origin); @@ -1939,20 +1956,33 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, void intel_psr_init(struct drm_i915_private *dev_priv); void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state); -void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug); +void intel_psr_irq_control(struct drm_i915_private *dev_priv, u32 debug); void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir); void intel_psr_short_pulse(struct intel_dp *intel_dp); -int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); +int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state, + u32 *out_value); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); -void intel_power_domains_fini(struct drm_i915_private *); +void intel_power_domains_cleanup(struct drm_i915_private *dev_priv); void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume); -void intel_power_domains_suspend(struct drm_i915_private *dev_priv); -void intel_power_domains_verify_state(struct drm_i915_private *dev_priv); +void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv); +void intel_power_domains_enable(struct drm_i915_private *dev_priv); +void intel_power_domains_disable(struct drm_i915_private *dev_priv); + +enum i915_drm_suspend_mode { + I915_DRM_SUSPEND_IDLE, + I915_DRM_SUSPEND_MEM, + I915_DRM_SUSPEND_HIBERNATE, +}; + +void intel_power_domains_suspend(struct drm_i915_private *dev_priv, + enum i915_drm_suspend_mode); +void intel_power_domains_resume(struct drm_i915_private *dev_priv); void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume); void bxt_display_core_uninit(struct drm_i915_private *dev_priv); void intel_runtime_pm_enable(struct drm_i915_private *dev_priv); +void intel_runtime_pm_disable(struct drm_i915_private *dev_priv); const char * intel_display_power_domain_str(enum intel_display_power_domain domain); @@ -2030,8 +2060,6 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv); void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv); void intel_runtime_pm_put(struct drm_i915_private *dev_priv); -void intel_display_set_init_power(struct drm_i915_private *dev, bool enable); - void chv_phy_powergate_lanes(struct intel_encoder *encoder, bool override, unsigned int mask); bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy, @@ -2108,6 +2136,14 @@ bool skl_plane_has_ccs(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); bool skl_plane_has_planar(struct drm_i915_private *dev_priv, enum pipe pipe, enum plane_id plane_id); +unsigned int skl_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation); +int skl_plane_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); +int intel_plane_check_stride(const struct intel_plane_state *plane_state); +int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state); +int chv_plane_check_rotation(const struct intel_plane_state *plane_state); /* intel_tv.c */ void intel_tv_init(struct drm_i915_private *dev_priv); @@ -2172,12 +2208,17 @@ void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon); /* intel_pipe_crc.c */ #ifdef CONFIG_DEBUG_FS -int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, - size_t *values_cnt); +int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name); +int intel_crtc_verify_crc_source(struct drm_crtc *crtc, + const char *source_name, size_t *values_cnt); +const char *const *intel_crtc_get_crc_sources(struct drm_crtc *crtc, + size_t *count); void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc); void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc); #else #define intel_crtc_set_crc_source NULL +#define intel_crtc_verify_crc_source NULL +#define intel_crtc_get_crc_sources NULL static inline void intel_crtc_disable_pipe_crc(struct intel_crtc *crtc) { } diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index 2d1952849d69..217ed3ee1cab 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -513,7 +513,7 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, goto err_unref; } - ret = i915_vma_pin(vma, 0, 4096, PIN_GLOBAL | PIN_HIGH); + ret = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH); if (ret) goto err_unref; @@ -527,36 +527,19 @@ err_unref: void intel_engine_cleanup_scratch(struct intel_engine_cs *engine) { - i915_vma_unpin_and_release(&engine->scratch); -} - -static void cleanup_phys_status_page(struct intel_engine_cs *engine) -{ - struct drm_i915_private *dev_priv = engine->i915; - - if (!dev_priv->status_page_dmah) - return; - - drm_pci_free(&dev_priv->drm, dev_priv->status_page_dmah); - engine->status_page.page_addr = NULL; + i915_vma_unpin_and_release(&engine->scratch, 0); } static void cleanup_status_page(struct intel_engine_cs *engine) { - struct i915_vma *vma; - struct drm_i915_gem_object *obj; - - vma = fetch_and_zero(&engine->status_page.vma); - if (!vma) - return; - - obj = vma->obj; + if (HWS_NEEDS_PHYSICAL(engine->i915)) { + void *addr = fetch_and_zero(&engine->status_page.page_addr); - i915_vma_unpin(vma); - i915_vma_close(vma); + __free_page(virt_to_page(addr)); + } - i915_gem_object_unpin_map(obj); - __i915_gem_object_release_unless_active(obj); + i915_vma_unpin_and_release(&engine->status_page.vma, + I915_VMA_RELEASE_MAP); } static int init_status_page(struct intel_engine_cs *engine) @@ -598,7 +581,7 @@ static int init_status_page(struct intel_engine_cs *engine) flags |= PIN_MAPPABLE; else flags |= PIN_HIGH; - ret = i915_vma_pin(vma, 0, 4096, flags); + ret = i915_vma_pin(vma, 0, 0, flags); if (ret) goto err; @@ -622,17 +605,18 @@ err: static int init_phys_status_page(struct intel_engine_cs *engine) { - struct drm_i915_private *dev_priv = engine->i915; + struct page *page; - GEM_BUG_ON(engine->id != RCS); - - dev_priv->status_page_dmah = - drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE); - if (!dev_priv->status_page_dmah) + /* + * Though the HWS register does support 36bit addresses, historically + * we have had hangs and corruption reported due to wild writes if + * the HWS is placed above 4G. + */ + page = alloc_page(GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO); + if (!page) return -ENOMEM; - engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - memset(engine->status_page.page_addr, 0, PAGE_SIZE); + engine->status_page.page_addr = page_address(page); return 0; } @@ -722,10 +706,7 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) intel_engine_cleanup_scratch(engine); - if (HWS_NEEDS_PHYSICAL(engine->i915)) - cleanup_phys_status_page(engine); - else - cleanup_status_page(engine); + cleanup_status_page(engine); intel_engine_fini_breadcrumbs(engine); intel_engine_cleanup_cmd_parser(engine); @@ -800,6 +781,16 @@ int intel_engine_stop_cs(struct intel_engine_cs *engine) return err; } +void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine) +{ + struct drm_i915_private *dev_priv = engine->i915; + + GEM_TRACE("%s\n", engine->name); + + I915_WRITE_FW(RING_MI_MODE(engine->mmio_base), + _MASKED_BIT_DISABLE(STOP_RING)); +} + const char *i915_cache_level_str(struct drm_i915_private *i915, int type) { switch (type) { @@ -980,8 +971,7 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) return true; /* Any inflight/incomplete requests? */ - if (!i915_seqno_passed(intel_engine_get_seqno(engine), - intel_engine_last_submit(engine))) + if (!intel_engine_signaled(engine, intel_engine_last_submit(engine))) return false; if (I915_SELFTEST_ONLY(engine->breadcrumbs.mock)) @@ -1000,6 +990,9 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine) } local_bh_enable(); + /* Otherwise flush the tasklet if it was on another cpu */ + tasklet_unlock_wait(t); + if (READ_ONCE(engine->execlists.active)) return false; } @@ -1348,20 +1341,19 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, if (HAS_EXECLISTS(dev_priv)) { const u32 *hws = &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX]; - u32 ptr, read, write; unsigned int idx; + u8 read, write; drm_printf(m, "\tExeclist status: 0x%08x %08x\n", I915_READ(RING_EXECLIST_STATUS_LO(engine)), I915_READ(RING_EXECLIST_STATUS_HI(engine))); - ptr = I915_READ(RING_CONTEXT_STATUS_PTR(engine)); - read = GEN8_CSB_READ_PTR(ptr); - write = GEN8_CSB_WRITE_PTR(ptr); - drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], tasklet queued? %s (%s)\n", - read, execlists->csb_head, - write, - intel_read_status_page(engine, intel_hws_csb_write_index(engine->i915)), + read = execlists->csb_head; + write = READ_ONCE(*execlists->csb_write); + + drm_printf(m, "\tExeclist CSB read %d, write %d [mmio:%d], tasklet queued? %s (%s)\n", + read, write, + GEN8_CSB_WRITE_PTR(I915_READ(RING_CONTEXT_STATUS_PTR(engine))), yesno(test_bit(TASKLET_STATE_SCHED, &engine->execlists.tasklet.state)), enableddisabled(!atomic_read(&engine->execlists.tasklet.count))); @@ -1373,12 +1365,12 @@ static void intel_engine_print_registers(const struct intel_engine_cs *engine, write += GEN8_CSB_ENTRIES; while (read < write) { idx = ++read % GEN8_CSB_ENTRIES; - drm_printf(m, "\tExeclist CSB[%d]: 0x%08x [0x%08x in hwsp], context: %d [%d in hwsp]\n", + drm_printf(m, "\tExeclist CSB[%d]: 0x%08x [mmio:0x%08x], context: %d [mmio:%d]\n", idx, - I915_READ(RING_CONTEXT_STATUS_BUF_LO(engine, idx)), hws[idx * 2], - I915_READ(RING_CONTEXT_STATUS_BUF_HI(engine, idx)), - hws[idx * 2 + 1]); + I915_READ(RING_CONTEXT_STATUS_BUF_LO(engine, idx)), + hws[idx * 2 + 1], + I915_READ(RING_CONTEXT_STATUS_BUF_HI(engine, idx))); } rcu_read_lock(); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 01d1d2088f04..74d425c700ef 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -670,8 +670,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, cache->plane.src_w = drm_rect_width(&plane_state->base.src) >> 16; cache->plane.src_h = drm_rect_height(&plane_state->base.src) >> 16; cache->plane.visible = plane_state->base.visible; - cache->plane.adjusted_x = plane_state->main.x; - cache->plane.adjusted_y = plane_state->main.y; + cache->plane.adjusted_x = plane_state->color_plane[0].x; + cache->plane.adjusted_y = plane_state->color_plane[0].y; cache->plane.y = plane_state->base.src.y1 >> 16; if (!cache->plane.visible) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index fb2f9fce34cd..f99332972b7a 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -175,6 +175,9 @@ static int intelfb_create(struct drm_fb_helper *helper, struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; struct i915_ggtt *ggtt = &dev_priv->ggtt; + const struct i915_ggtt_view view = { + .type = I915_GGTT_VIEW_NORMAL, + }; struct fb_info *info; struct drm_framebuffer *fb; struct i915_vma *vma; @@ -214,8 +217,7 @@ static int intelfb_create(struct drm_fb_helper *helper, * BIOS is suitable for own access. */ vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, - DRM_MODE_ROTATE_0, - false, &flags); + &view, false, &flags); if (IS_ERR(vma)) { ret = PTR_ERR(vma); goto out_unlock; diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c index 560c7406ae40..230aea69385d 100644 --- a/drivers/gpu/drm/i915/intel_guc.c +++ b/drivers/gpu/drm/i915/intel_guc.c @@ -27,8 +27,6 @@ #include "intel_guc_submission.h" #include "i915_drv.h" -static void guc_init_ggtt_pin_bias(struct intel_guc *guc); - static void gen8_guc_raise_irq(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -128,13 +126,15 @@ static int guc_init_wq(struct intel_guc *guc) static void guc_fini_wq(struct intel_guc *guc) { - struct drm_i915_private *dev_priv = guc_to_i915(guc); + struct workqueue_struct *wq; - if (HAS_LOGICAL_RING_PREEMPTION(dev_priv) && - USES_GUC_SUBMISSION(dev_priv)) - destroy_workqueue(guc->preempt_wq); + wq = fetch_and_zero(&guc->preempt_wq); + if (wq) + destroy_workqueue(wq); - destroy_workqueue(guc->log.relay.flush_wq); + wq = fetch_and_zero(&guc->log.relay.flush_wq); + if (wq) + destroy_workqueue(wq); } int intel_guc_init_misc(struct intel_guc *guc) @@ -142,8 +142,6 @@ int intel_guc_init_misc(struct intel_guc *guc) struct drm_i915_private *i915 = guc_to_i915(guc); int ret; - guc_init_ggtt_pin_bias(guc); - ret = guc_init_wq(guc); if (ret) return ret; @@ -170,7 +168,7 @@ static int guc_shared_data_create(struct intel_guc *guc) vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB); if (IS_ERR(vaddr)) { - i915_vma_unpin_and_release(&vma); + i915_vma_unpin_and_release(&vma, 0); return PTR_ERR(vaddr); } @@ -182,8 +180,7 @@ static int guc_shared_data_create(struct intel_guc *guc) static void guc_shared_data_destroy(struct intel_guc *guc) { - i915_gem_object_unpin_map(guc->shared_data->obj); - i915_vma_unpin_and_release(&guc->shared_data); + i915_vma_unpin_and_release(&guc->shared_data, I915_VMA_RELEASE_MAP); } int intel_guc_init(struct intel_guc *guc) @@ -584,53 +581,28 @@ int intel_guc_resume(struct intel_guc *guc) * * :: * - * +==============> +====================+ <== GUC_GGTT_TOP - * ^ | | - * | | | - * | | DRAM | - * | | Memory | - * | | | - * GuC | | - * Address +========> +====================+ <== WOPCM Top - * Space ^ | HW contexts RSVD | - * | | | WOPCM | - * | | +==> +--------------------+ <== GuC WOPCM Top - * | GuC ^ | | - * | GGTT | | | - * | Pin GuC | GuC | - * | Bias WOPCM | WOPCM | - * | | Size | | - * | | | | | - * v v v | | - * +=====+=====+==> +====================+ <== GuC WOPCM Base - * | Non-GuC WOPCM | - * | (HuC/Reserved) | - * +====================+ <== WOPCM Base + * +===========> +====================+ <== FFFF_FFFF + * ^ | Reserved | + * | +====================+ <== GUC_GGTT_TOP + * | | | + * | | DRAM | + * GuC | | + * Address +===> +====================+ <== GuC ggtt_pin_bias + * Space ^ | | + * | | | | + * | GuC | GuC | + * | WOPCM | WOPCM | + * | Size | | + * | | | | + * v v | | + * +=======+===> +====================+ <== 0000_0000 * - * The lower part of GuC Address Space [0, ggtt_pin_bias) is mapped to WOPCM + * The lower part of GuC Address Space [0, ggtt_pin_bias) is mapped to GuC WOPCM * while upper part of GuC Address Space [ggtt_pin_bias, GUC_GGTT_TOP) is mapped - * to DRAM. The value of the GuC ggtt_pin_bias is determined by WOPCM size and - * actual GuC WOPCM size. + * to DRAM. The value of the GuC ggtt_pin_bias is the GuC WOPCM size. */ /** - * guc_init_ggtt_pin_bias() - Initialize the GuC ggtt_pin_bias value. - * @guc: intel_guc structure. - * - * This function will calculate and initialize the ggtt_pin_bias value based on - * overall WOPCM size and GuC WOPCM size. - */ -static void guc_init_ggtt_pin_bias(struct intel_guc *guc) -{ - struct drm_i915_private *i915 = guc_to_i915(guc); - - GEM_BUG_ON(!i915->wopcm.size); - GEM_BUG_ON(i915->wopcm.size < i915->wopcm.guc.base); - - guc->ggtt_pin_bias = i915->wopcm.size - i915->wopcm.guc.base; -} - -/** * intel_guc_allocate_vma() - Allocate a GGTT VMA for GuC usage * @guc: the guc * @size: size of area to allocate (both virtual space and memory) @@ -648,6 +620,7 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) struct drm_i915_private *dev_priv = guc_to_i915(guc); struct drm_i915_gem_object *obj; struct i915_vma *vma; + u64 flags; int ret; obj = i915_gem_object_create(dev_priv, size); @@ -658,8 +631,8 @@ struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) if (IS_ERR(vma)) goto err; - ret = i915_vma_pin(vma, 0, PAGE_SIZE, - PIN_GLOBAL | PIN_OFFSET_BIAS | guc->ggtt_pin_bias); + flags = PIN_GLOBAL | PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma); + ret = i915_vma_pin(vma, 0, 0, flags); if (ret) { vma = ERR_PTR(ret); goto err; @@ -671,3 +644,20 @@ err: i915_gem_object_put(obj); return vma; } + +/** + * intel_guc_reserved_gtt_size() + * @guc: intel_guc structure + * + * The GuC WOPCM mapping shadows the lower part of the GGTT, so if we are using + * GuC we can't have any objects pinned in that region. This function returns + * the size of the shadowed region. + * + * Returns: + * 0 if GuC is not present or not in use. + * Otherwise, the GuC WOPCM size. + */ +u32 intel_guc_reserved_gtt_size(struct intel_guc *guc) +{ + return guc_to_i915(guc)->wopcm.guc.size; +} diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 4121928a495e..ad42faf48c46 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -49,9 +49,6 @@ struct intel_guc { struct intel_guc_log log; struct intel_guc_ct ct; - /* Offset where Non-WOPCM memory starts. */ - u32 ggtt_pin_bias; - /* Log snapshot if GuC errors during load */ struct drm_i915_gem_object *load_err_log; @@ -130,10 +127,10 @@ static inline void intel_guc_to_host_event_handler(struct intel_guc *guc) * @vma: i915 graphics virtual memory area. * * GuC does not allow any gfx GGTT address that falls into range - * [0, GuC ggtt_pin_bias), which is reserved for Boot ROM, SRAM and WOPCM. - * Currently, in order to exclude [0, GuC ggtt_pin_bias) address space from + * [0, ggtt.pin_bias), which is reserved for Boot ROM, SRAM and WOPCM. + * Currently, in order to exclude [0, ggtt.pin_bias) address space from * GGTT, all gfx objects used by GuC are allocated with intel_guc_allocate_vma() - * and pinned with PIN_OFFSET_BIAS along with the value of GuC ggtt_pin_bias. + * and pinned with PIN_OFFSET_BIAS along with the value of ggtt.pin_bias. * * Return: GGTT offset of the @vma. */ @@ -142,7 +139,7 @@ static inline u32 intel_guc_ggtt_offset(struct intel_guc *guc, { u32 offset = i915_ggtt_offset(vma); - GEM_BUG_ON(offset < guc->ggtt_pin_bias); + GEM_BUG_ON(offset < i915_ggtt_pin_bias(vma)); GEM_BUG_ON(range_overflows_t(u64, offset, vma->size, GUC_GGTT_TOP)); return offset; @@ -168,6 +165,7 @@ int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset); int intel_guc_suspend(struct intel_guc *guc); int intel_guc_resume(struct intel_guc *guc); struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size); +u32 intel_guc_reserved_gtt_size(struct intel_guc *guc); static inline int intel_guc_sanitize(struct intel_guc *guc) { diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c index dcaa3fb71765..f0db62887f50 100644 --- a/drivers/gpu/drm/i915/intel_guc_ads.c +++ b/drivers/gpu/drm/i915/intel_guc_ads.c @@ -148,5 +148,5 @@ int intel_guc_ads_create(struct intel_guc *guc) void intel_guc_ads_destroy(struct intel_guc *guc) { - i915_vma_unpin_and_release(&guc->ads_vma); + i915_vma_unpin_and_release(&guc->ads_vma, 0); } diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 371b6005954a..a52883e9146f 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -204,7 +204,7 @@ static int ctch_init(struct intel_guc *guc, return 0; err_vma: - i915_vma_unpin_and_release(&ctch->vma); + i915_vma_unpin_and_release(&ctch->vma, 0); err_out: CT_DEBUG_DRIVER("CT: channel %d initialization failed; err=%d\n", ctch->owner, err); @@ -214,10 +214,7 @@ err_out: static void ctch_fini(struct intel_guc *guc, struct intel_guc_ct_channel *ctch) { - GEM_BUG_ON(!ctch->vma); - - i915_gem_object_unpin_map(ctch->vma->obj); - i915_vma_unpin_and_release(&ctch->vma); + i915_vma_unpin_and_release(&ctch->vma, I915_VMA_RELEASE_MAP); } static int ctch_open(struct intel_guc *guc, diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 1a0f2a39cef9..8382d591c784 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -49,6 +49,7 @@ #define WQ_TYPE_BATCH_BUF (0x1 << WQ_TYPE_SHIFT) #define WQ_TYPE_PSEUDO (0x2 << WQ_TYPE_SHIFT) #define WQ_TYPE_INORDER (0x3 << WQ_TYPE_SHIFT) +#define WQ_TYPE_NOOP (0x4 << WQ_TYPE_SHIFT) #define WQ_TARGET_SHIFT 10 #define WQ_LEN_SHIFT 16 #define WQ_NO_WCFLUSH_WAIT (1 << 27) diff --git a/drivers/gpu/drm/i915/intel_guc_log.c b/drivers/gpu/drm/i915/intel_guc_log.c index 6da61a71d28f..d3ebdbc0182e 100644 --- a/drivers/gpu/drm/i915/intel_guc_log.c +++ b/drivers/gpu/drm/i915/intel_guc_log.c @@ -498,7 +498,7 @@ err: void intel_guc_log_destroy(struct intel_guc_log *log) { - i915_vma_unpin_and_release(&log->vma); + i915_vma_unpin_and_release(&log->vma, 0); } int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index 4aa5e6463e7b..a81f04d46e87 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -317,7 +317,7 @@ static int guc_stage_desc_pool_create(struct intel_guc *guc) vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB); if (IS_ERR(vaddr)) { - i915_vma_unpin_and_release(&vma); + i915_vma_unpin_and_release(&vma, 0); return PTR_ERR(vaddr); } @@ -331,8 +331,7 @@ static int guc_stage_desc_pool_create(struct intel_guc *guc) static void guc_stage_desc_pool_destroy(struct intel_guc *guc) { ida_destroy(&guc->stage_ids); - i915_gem_object_unpin_map(guc->stage_desc_pool->obj); - i915_vma_unpin_and_release(&guc->stage_desc_pool); + i915_vma_unpin_and_release(&guc->stage_desc_pool, I915_VMA_RELEASE_MAP); } /* @@ -457,6 +456,9 @@ static void guc_wq_item_append(struct intel_guc_client *client, */ BUILD_BUG_ON(wqi_size != 16); + /* We expect the WQ to be active if we're appending items to it */ + GEM_BUG_ON(desc->wq_status != WQ_STATUS_ACTIVE); + /* Free space is guaranteed. */ wq_off = READ_ONCE(desc->tail); GEM_BUG_ON(CIRC_SPACE(wq_off, READ_ONCE(desc->head), @@ -466,15 +468,19 @@ static void guc_wq_item_append(struct intel_guc_client *client, /* WQ starts from the page after doorbell / process_desc */ wqi = client->vaddr + wq_off + GUC_DB_SIZE; - /* Now fill in the 4-word work queue item */ - wqi->header = WQ_TYPE_INORDER | - (wqi_len << WQ_LEN_SHIFT) | - (target_engine << WQ_TARGET_SHIFT) | - WQ_NO_WCFLUSH_WAIT; - wqi->context_desc = context_desc; - wqi->submit_element_info = ring_tail << WQ_RING_TAIL_SHIFT; - GEM_BUG_ON(ring_tail > WQ_RING_TAIL_MAX); - wqi->fence_id = fence_id; + if (I915_SELFTEST_ONLY(client->use_nop_wqi)) { + wqi->header = WQ_TYPE_NOOP | (wqi_len << WQ_LEN_SHIFT); + } else { + /* Now fill in the 4-word work queue item */ + wqi->header = WQ_TYPE_INORDER | + (wqi_len << WQ_LEN_SHIFT) | + (target_engine << WQ_TARGET_SHIFT) | + WQ_NO_WCFLUSH_WAIT; + wqi->context_desc = context_desc; + wqi->submit_element_info = ring_tail << WQ_RING_TAIL_SHIFT; + GEM_BUG_ON(ring_tail > WQ_RING_TAIL_MAX); + wqi->fence_id = fence_id; + } /* Make the update visible to GuC */ WRITE_ONCE(desc->tail, (wq_off + wqi_size) & (GUC_WQ_SIZE - 1)); @@ -551,16 +557,36 @@ static void inject_preempt_context(struct work_struct *work) preempt_work[engine->id]); struct intel_guc_client *client = guc->preempt_client; struct guc_stage_desc *stage_desc = __get_stage_desc(client); - u32 ctx_desc = lower_32_bits(to_intel_context(client->owner, - engine)->lrc_desc); + struct intel_context *ce = to_intel_context(client->owner, engine); u32 data[7]; - /* - * The ring contains commands to write GUC_PREEMPT_FINISHED into HWSP. - * See guc_fill_preempt_context(). - */ + if (!ce->ring->emit) { /* recreate upon load/resume */ + u32 addr = intel_hws_preempt_done_address(engine); + u32 *cs; + + cs = ce->ring->vaddr; + if (engine->id == RCS) { + cs = gen8_emit_ggtt_write_rcs(cs, + GUC_PREEMPT_FINISHED, + addr); + } else { + cs = gen8_emit_ggtt_write(cs, + GUC_PREEMPT_FINISHED, + addr); + *cs++ = MI_NOOP; + *cs++ = MI_NOOP; + } + *cs++ = MI_USER_INTERRUPT; + *cs++ = MI_NOOP; + + ce->ring->emit = GUC_PREEMPT_BREADCRUMB_BYTES; + GEM_BUG_ON((void *)cs - ce->ring->vaddr != ce->ring->emit); + + flush_ggtt_writes(ce->ring->vma); + } + spin_lock_irq(&client->wq_lock); - guc_wq_item_append(client, engine->guc_id, ctx_desc, + guc_wq_item_append(client, engine->guc_id, lower_32_bits(ce->lrc_desc), GUC_PREEMPT_BREADCRUMB_BYTES / sizeof(u64), 0); spin_unlock_irq(&client->wq_lock); @@ -1008,7 +1034,7 @@ guc_client_alloc(struct drm_i915_private *dev_priv, err_vaddr: i915_gem_object_unpin_map(client->vma->obj); err_vma: - i915_vma_unpin_and_release(&client->vma); + i915_vma_unpin_and_release(&client->vma, 0); err_id: ida_simple_remove(&guc->stage_ids, client->stage_id); err_client: @@ -1020,8 +1046,7 @@ static void guc_client_free(struct intel_guc_client *client) { unreserve_doorbell(client); guc_stage_desc_fini(client->guc, client); - i915_gem_object_unpin_map(client->vma->obj); - i915_vma_unpin_and_release(&client->vma); + i915_vma_unpin_and_release(&client->vma, I915_VMA_RELEASE_MAP); ida_simple_remove(&client->guc->stage_ids, client->stage_id); kfree(client); } @@ -1039,50 +1064,6 @@ static inline bool ctx_save_restore_disabled(struct intel_context *ce) #undef SR_DISABLED } -static void guc_fill_preempt_context(struct intel_guc *guc) -{ - struct drm_i915_private *dev_priv = guc_to_i915(guc); - struct intel_guc_client *client = guc->preempt_client; - struct intel_engine_cs *engine; - enum intel_engine_id id; - - for_each_engine(engine, dev_priv, id) { - struct intel_context *ce = - to_intel_context(client->owner, engine); - u32 addr = intel_hws_preempt_done_address(engine); - u32 *cs; - - GEM_BUG_ON(!ce->pin_count); - - /* - * We rely on this context image *not* being saved after - * preemption. This ensures that the RING_HEAD / RING_TAIL - * remain pointing at initial values forever. - */ - GEM_BUG_ON(!ctx_save_restore_disabled(ce)); - - cs = ce->ring->vaddr; - if (id == RCS) { - cs = gen8_emit_ggtt_write_rcs(cs, - GUC_PREEMPT_FINISHED, - addr); - } else { - cs = gen8_emit_ggtt_write(cs, - GUC_PREEMPT_FINISHED, - addr); - *cs++ = MI_NOOP; - *cs++ = MI_NOOP; - } - *cs++ = MI_USER_INTERRUPT; - *cs++ = MI_NOOP; - - GEM_BUG_ON((void *)cs - ce->ring->vaddr != - GUC_PREEMPT_BREADCRUMB_BYTES); - - flush_ggtt_writes(ce->ring->vma); - } -} - static int guc_clients_create(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); @@ -1113,8 +1094,6 @@ static int guc_clients_create(struct intel_guc *guc) return PTR_ERR(client); } guc->preempt_client = client; - - guc_fill_preempt_context(guc); } return 0; diff --git a/drivers/gpu/drm/i915/intel_guc_submission.h b/drivers/gpu/drm/i915/intel_guc_submission.h index fb081cefef93..169c54568340 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.h +++ b/drivers/gpu/drm/i915/intel_guc_submission.h @@ -28,6 +28,7 @@ #include <linux/spinlock.h> #include "i915_gem.h" +#include "i915_selftest.h" struct drm_i915_private; @@ -71,6 +72,9 @@ struct intel_guc_client { spinlock_t wq_lock; /* Per-engine counts of GuC submissions */ u64 submissions[I915_NUM_ENGINES]; + + /* For testing purposes, use nop WQ items instead of real ones */ + I915_SELFTEST_DECLARE(bool use_nop_wqi); }; int intel_guc_submission_init(struct intel_guc *guc); diff --git a/drivers/gpu/drm/i915/intel_hangcheck.c b/drivers/gpu/drm/i915/intel_hangcheck.c index 2fc7a0dd0df9..e26d05a46451 100644 --- a/drivers/gpu/drm/i915/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/intel_hangcheck.c @@ -142,7 +142,7 @@ static int semaphore_passed(struct intel_engine_cs *engine) if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES) return -1; - if (i915_seqno_passed(intel_engine_get_seqno(signaller), seqno)) + if (intel_engine_signaled(signaller, seqno)) return 1; /* cursory check for an unkickable deadlock */ diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 0cc6a861bcf8..26e48fc95543 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -57,9 +57,9 @@ static bool hdcp_key_loadable(struct drm_i915_private *dev_priv) /* PG1 (power well #1) needs to be enabled */ for_each_power_well(dev_priv, power_well) { - if (power_well->id == id) { - enabled = power_well->ops->is_enabled(dev_priv, - power_well); + if (power_well->desc->id == id) { + enabled = power_well->desc->ops->is_enabled(dev_priv, + power_well); break; } } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 192972a7d287..a2dab0b6bde6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1911,22 +1911,26 @@ intel_hdmi_set_edid(struct drm_connector *connector) static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { - enum drm_connector_status status; + enum drm_connector_status status = connector_status_disconnected; struct drm_i915_private *dev_priv = to_i915(connector->dev); struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_encoder *encoder = &hdmi_to_dig_port(intel_hdmi)->base; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); + if (IS_ICELAKE(dev_priv) && + !intel_digital_port_connected(encoder)) + goto out; + intel_hdmi_unset_edid(connector); if (intel_hdmi_set_edid(connector)) status = connector_status_connected; - else - status = connector_status_disconnected; +out: intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); if (status != connector_status_connected) diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c index ffcad5fad6a7..37ef540dd280 100644 --- a/drivers/gpu/drm/i915/intel_huc.c +++ b/drivers/gpu/drm/i915/intel_huc.c @@ -63,7 +63,7 @@ int intel_huc_auth(struct intel_huc *huc) return -ENOEXEC; vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0, - PIN_OFFSET_BIAS | guc->ggtt_pin_bias); + PIN_OFFSET_BIAS | i915->ggtt.pin_bias); if (IS_ERR(vma)) { ret = PTR_ERR(vma); DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index bef32b7c248e..33d87ab93fdd 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -37,7 +37,7 @@ struct gmbus_pin { const char *name; - i915_reg_t reg; + enum i915_gpio gpio; }; /* Map gmbus pin pairs to names and registers. */ @@ -121,8 +121,7 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, else size = ARRAY_SIZE(gmbus_pins); - return pin < size && - i915_mmio_reg_valid(get_gmbus_pin(dev_priv, pin)->reg); + return pin < size && get_gmbus_pin(dev_priv, pin)->name; } /* Intel GPIO access functions */ @@ -292,8 +291,7 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin) algo = &bus->bit_algo; - bus->gpio_reg = _MMIO(dev_priv->gpio_mmio_base + - i915_mmio_reg_offset(get_gmbus_pin(dev_priv, pin)->reg)); + bus->gpio_reg = GPIO(get_gmbus_pin(dev_priv, pin)->gpio); bus->adapter.algo_data = algo; algo->setsda = set_data; algo->setscl = set_clock; @@ -825,9 +823,11 @@ int intel_setup_gmbus(struct drm_i915_private *dev_priv) if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; else if (!HAS_GMCH_DISPLAY(dev_priv)) - dev_priv->gpio_mmio_base = - i915_mmio_reg_offset(PCH_GPIOA) - - i915_mmio_reg_offset(GPIOA); + /* + * Broxton uses the same PCH offsets for South Display Engine, + * even though it doesn't have a PCH. + */ + dev_priv->gpio_mmio_base = PCH_DISPLAY_BASE; mutex_init(&dev_priv->gmbus_mutex); init_waitqueue_head(&dev_priv->gmbus_wait_queue); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 174479232e94..43957bb37a42 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -541,11 +541,6 @@ static void inject_preempt_context(struct intel_engine_cs *engine) GEM_BUG_ON(execlists->preempt_complete_status != upper_32_bits(ce->lrc_desc)); - GEM_BUG_ON((ce->lrc_reg_state[CTX_CONTEXT_CONTROL + 1] & - _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | - CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)) != - _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | - CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT)); /* * Switch to our empty preempt context so @@ -1277,6 +1272,8 @@ static void execlists_context_destroy(struct intel_context *ce) static void execlists_context_unpin(struct intel_context *ce) { + i915_gem_context_unpin_hw_id(ce->gem_context); + intel_ring_unpin(ce->ring); ce->state->obj->pin_global--; @@ -1297,16 +1294,15 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) * on an active context (which by nature is already on the GPU). */ if (!(vma->flags & I915_VMA_GLOBAL_BIND)) { - err = i915_gem_object_set_to_gtt_domain(vma->obj, true); + err = i915_gem_object_set_to_wc_domain(vma->obj, true); if (err) return err; } flags = PIN_GLOBAL | PIN_HIGH; - if (ctx->ggtt_offset_bias) - flags |= PIN_OFFSET_BIAS | ctx->ggtt_offset_bias; + flags |= PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma); - return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags); + return i915_vma_pin(vma, 0, 0, flags); } static struct intel_context * @@ -1326,28 +1322,38 @@ __execlists_context_pin(struct intel_engine_cs *engine, if (ret) goto err; - vaddr = i915_gem_object_pin_map(ce->state->obj, I915_MAP_WB); + vaddr = i915_gem_object_pin_map(ce->state->obj, + i915_coherent_map_type(ctx->i915) | + I915_MAP_OVERRIDE); if (IS_ERR(vaddr)) { ret = PTR_ERR(vaddr); goto unpin_vma; } - ret = intel_ring_pin(ce->ring, ctx->i915, ctx->ggtt_offset_bias); + ret = intel_ring_pin(ce->ring); if (ret) goto unpin_map; + ret = i915_gem_context_pin_hw_id(ctx); + if (ret) + goto unpin_ring; + intel_lr_context_descriptor_update(ctx, engine, ce); + GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head)); + ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = i915_ggtt_offset(ce->ring->vma); - GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head)); - ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head; + ce->lrc_reg_state[CTX_RING_HEAD + 1] = ce->ring->head; + ce->lrc_reg_state[CTX_RING_TAIL + 1] = ce->ring->tail; ce->state->obj->pin_global++; i915_gem_context_get(ctx); return ce; +unpin_ring: + intel_ring_unpin(ce->ring); unpin_map: i915_gem_object_unpin_map(ce->state->obj); unpin_vma: @@ -1643,7 +1649,7 @@ static int lrc_setup_wa_ctx(struct intel_engine_cs *engine) goto err; } - err = i915_vma_pin(vma, 0, PAGE_SIZE, PIN_GLOBAL | PIN_HIGH); + err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH); if (err) goto err; @@ -1657,7 +1663,7 @@ err: static void lrc_destroy_wa_ctx(struct intel_engine_cs *engine) { - i915_vma_unpin_and_release(&engine->wa_ctx.vma); + i915_vma_unpin_and_release(&engine->wa_ctx.vma, 0); } typedef u32 *(*wa_bb_func_t)(struct intel_engine_cs *engine, u32 *batch); @@ -1775,11 +1781,7 @@ static bool unexpected_starting_state(struct intel_engine_cs *engine) static int gen8_init_common_ring(struct intel_engine_cs *engine) { - int ret; - - ret = intel_mocs_init_engine(engine); - if (ret) - return ret; + intel_mocs_init_engine(engine); intel_engine_reset_breadcrumbs(engine); @@ -1838,7 +1840,8 @@ execlists_reset_prepare(struct intel_engine_cs *engine) struct i915_request *request, *active; unsigned long flags; - GEM_TRACE("%s\n", engine->name); + GEM_TRACE("%s: depth<-%d\n", engine->name, + atomic_read(&execlists->tasklet.count)); /* * Prevent request submission to the hardware until we have @@ -1971,22 +1974,18 @@ static void execlists_reset_finish(struct intel_engine_cs *engine) { struct intel_engine_execlists * const execlists = &engine->execlists; - /* After a GPU reset, we may have requests to replay */ - if (!RB_EMPTY_ROOT(&execlists->queue.rb_root)) - tasklet_schedule(&execlists->tasklet); - /* - * Flush the tasklet while we still have the forcewake to be sure - * that it is not allowed to sleep before we restart and reload a - * context. + * After a GPU reset, we may have requests to replay. Do so now while + * we still have the forcewake to be sure that the GPU is not allowed + * to sleep before we restart and reload a context. * - * As before (with execlists_reset_prepare) we rely on the caller - * serialising multiple attempts to reset so that we know that we - * are the only one manipulating tasklet state. */ - __tasklet_enable_sync_once(&execlists->tasklet); + if (!RB_EMPTY_ROOT(&execlists->queue.rb_root)) + execlists->tasklet.func(execlists->tasklet.data); - GEM_TRACE("%s\n", engine->name); + tasklet_enable(&execlists->tasklet); + GEM_TRACE("%s: depth->%d\n", engine->name, + atomic_read(&execlists->tasklet.count)); } static int intel_logical_ring_emit_pdps(struct i915_request *rq) @@ -2066,8 +2065,7 @@ static int gen8_emit_bb_start(struct i915_request *rq, /* FIXME(BDW): Address space and security selectors. */ *cs++ = MI_BATCH_BUFFER_START_GEN8 | - (flags & I915_DISPATCH_SECURE ? 0 : BIT(8)) | - (flags & I915_DISPATCH_RS ? MI_BATCH_RESOURCE_STREAMER : 0); + (flags & I915_DISPATCH_SECURE ? 0 : BIT(8)); *cs++ = lower_32_bits(offset); *cs++ = upper_32_bits(offset); @@ -2398,7 +2396,7 @@ static int logical_ring_init(struct intel_engine_cs *engine) ret = intel_engine_init_common(engine); if (ret) - goto error; + return ret; if (HAS_LOGICAL_RING_ELSQ(i915)) { execlists->submit_reg = i915->regs + @@ -2440,10 +2438,6 @@ static int logical_ring_init(struct intel_engine_cs *engine) reset_csb_pointers(execlists); return 0; - -error: - intel_logical_ring_cleanup(engine); - return ret; } int logical_render_ring_init(struct intel_engine_cs *engine) @@ -2466,10 +2460,14 @@ int logical_render_ring_init(struct intel_engine_cs *engine) engine->emit_breadcrumb = gen8_emit_breadcrumb_rcs; engine->emit_breadcrumb_sz = gen8_emit_breadcrumb_rcs_sz; - ret = intel_engine_create_scratch(engine, PAGE_SIZE); + ret = logical_ring_init(engine); if (ret) return ret; + ret = intel_engine_create_scratch(engine, PAGE_SIZE); + if (ret) + goto err_cleanup_common; + ret = intel_init_workaround_bb(engine); if (ret) { /* @@ -2481,7 +2479,11 @@ int logical_render_ring_init(struct intel_engine_cs *engine) ret); } - return logical_ring_init(engine); + return 0; + +err_cleanup_common: + intel_engine_cleanup_common(engine); + return ret; } int logical_xcs_ring_init(struct intel_engine_cs *engine) @@ -2494,6 +2496,9 @@ int logical_xcs_ring_init(struct intel_engine_cs *engine) static u32 make_rpcs(struct drm_i915_private *dev_priv) { + bool subslice_pg = INTEL_INFO(dev_priv)->sseu.has_subslice_pg; + u8 slices = hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask); + u8 subslices = hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]); u32 rpcs = 0; /* @@ -2504,30 +2509,88 @@ make_rpcs(struct drm_i915_private *dev_priv) return 0; /* + * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits + * wide and Icelake has up to eight subslices, specfial programming is + * needed in order to correctly enable all subslices. + * + * According to documentation software must consider the configuration + * as 2x4x8 and hardware will translate this to 1x8x8. + * + * Furthemore, even though SScount is three bits, maximum documented + * value for it is four. From this some rules/restrictions follow: + * + * 1. + * If enabled subslice count is greater than four, two whole slices must + * be enabled instead. + * + * 2. + * When more than one slice is enabled, hardware ignores the subslice + * count altogether. + * + * From these restrictions it follows that it is not possible to enable + * a count of subslices between the SScount maximum of four restriction, + * and the maximum available number on a particular SKU. Either all + * subslices are enabled, or a count between one and four on the first + * slice. + */ + if (IS_GEN11(dev_priv) && slices == 1 && subslices >= 4) { + GEM_BUG_ON(subslices & 1); + + subslice_pg = false; + slices *= 2; + } + + /* * Starting in Gen9, render power gating can leave * slice/subslice/EU in a partially enabled state. We * must make an explicit request through RPCS for full * enablement. */ if (INTEL_INFO(dev_priv)->sseu.has_slice_pg) { - rpcs |= GEN8_RPCS_S_CNT_ENABLE; - rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask) << - GEN8_RPCS_S_CNT_SHIFT; - rpcs |= GEN8_RPCS_ENABLE; + u32 mask, val = slices; + + if (INTEL_GEN(dev_priv) >= 11) { + mask = GEN11_RPCS_S_CNT_MASK; + val <<= GEN11_RPCS_S_CNT_SHIFT; + } else { + mask = GEN8_RPCS_S_CNT_MASK; + val <<= GEN8_RPCS_S_CNT_SHIFT; + } + + GEM_BUG_ON(val & ~mask); + val &= mask; + + rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val; } - if (INTEL_INFO(dev_priv)->sseu.has_subslice_pg) { - rpcs |= GEN8_RPCS_SS_CNT_ENABLE; - rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask[0]) << - GEN8_RPCS_SS_CNT_SHIFT; - rpcs |= GEN8_RPCS_ENABLE; + if (subslice_pg) { + u32 val = subslices; + + val <<= GEN8_RPCS_SS_CNT_SHIFT; + + GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK); + val &= GEN8_RPCS_SS_CNT_MASK; + + rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val; } if (INTEL_INFO(dev_priv)->sseu.has_eu_pg) { - rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice << - GEN8_RPCS_EU_MIN_SHIFT; - rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice << - GEN8_RPCS_EU_MAX_SHIFT; + u32 val; + + val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice << + GEN8_RPCS_EU_MIN_SHIFT; + GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK); + val &= GEN8_RPCS_EU_MIN_MASK; + + rpcs |= val; + + val = INTEL_INFO(dev_priv)->sseu.eu_per_subslice << + GEN8_RPCS_EU_MAX_SHIFT; + GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK); + val &= GEN8_RPCS_EU_MAX_MASK; + + rpcs |= val; + rpcs |= GEN8_RPCS_ENABLE; } @@ -2584,11 +2647,13 @@ static void execlists_init_reg_state(u32 *regs, MI_LRI_FORCE_POSTED; CTX_REG(regs, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(engine), - _MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | - CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT) | - _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | - (HAS_RESOURCE_STREAMER(dev_priv) ? - CTX_CTRL_RS_CTX_ENABLE : 0))); + _MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT) | + _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH)); + if (INTEL_GEN(dev_priv) < 11) { + regs[CTX_CONTEXT_CONTROL + 1] |= + _MASKED_BIT_DISABLE(CTX_CTRL_ENGINE_CTX_SAVE_INHIBIT | + CTX_CTRL_RS_CTX_ENABLE); + } CTX_REG(regs, CTX_RING_HEAD, RING_HEAD(base), 0); CTX_REG(regs, CTX_RING_TAIL, RING_TAIL(base), 0); CTX_REG(regs, CTX_RING_BUFFER_START, RING_START(base), 0); @@ -2654,6 +2719,10 @@ static void execlists_init_reg_state(u32 *regs, i915_oa_init_reg_state(engine, ctx, regs); } + + regs[CTX_END] = MI_BATCH_BUFFER_END; + if (INTEL_GEN(dev_priv) >= 10) + regs[CTX_END] |= BIT(0); } static int @@ -2780,13 +2849,14 @@ error_deref_obj: return ret; } -void intel_lr_context_resume(struct drm_i915_private *dev_priv) +void intel_lr_context_resume(struct drm_i915_private *i915) { struct intel_engine_cs *engine; struct i915_gem_context *ctx; enum intel_engine_id id; - /* Because we emit WA_TAIL_DWORDS there may be a disparity + /* + * Because we emit WA_TAIL_DWORDS there may be a disparity * between our bookkeeping in ce->ring->head and ce->ring->tail and * that stored in context. As we only write new commands from * ce->ring->tail onwards, everything before that is junk. If the GPU @@ -2796,28 +2866,22 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv) * So to avoid that we reset the context images upon resume. For * simplicity, we just zero everything out. */ - list_for_each_entry(ctx, &dev_priv->contexts.list, link) { - for_each_engine(engine, dev_priv, id) { + list_for_each_entry(ctx, &i915->contexts.list, link) { + for_each_engine(engine, i915, id) { struct intel_context *ce = to_intel_context(ctx, engine); - u32 *reg; if (!ce->state) continue; - reg = i915_gem_object_pin_map(ce->state->obj, - I915_MAP_WB); - if (WARN_ON(IS_ERR(reg))) - continue; - - reg += LRC_STATE_PN * PAGE_SIZE / sizeof(*reg); - reg[CTX_RING_HEAD+1] = 0; - reg[CTX_RING_TAIL+1] = 0; + intel_ring_reset(ce->ring, 0); - ce->state->obj->mm.dirty = true; - i915_gem_object_unpin_map(ce->state->obj); + if (ce->pin_count) { /* otherwise done in context_pin */ + u32 *regs = ce->lrc_reg_state; - intel_ring_reset(ce->ring, 0); + regs[CTX_RING_HEAD + 1] = ce->ring->head; + regs[CTX_RING_TAIL + 1] = ce->ring->tail; + } } } } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4dfb78e3ec7e..f5a5502ecf70 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -27,8 +27,6 @@ #include "intel_ringbuffer.h" #include "i915_gem_context.h" -#define GEN8_LR_CONTEXT_ALIGN I915_GTT_MIN_ALIGNMENT - /* Execlists regs */ #define RING_ELSP(engine) _MMIO((engine)->mmio_base + 0x230) #define RING_EXECLIST_STATUS_LO(engine) _MMIO((engine)->mmio_base + 0x234) diff --git a/drivers/gpu/drm/i915/intel_lrc_reg.h b/drivers/gpu/drm/i915/intel_lrc_reg.h index 169a2239d6c7..5ef932d810a7 100644 --- a/drivers/gpu/drm/i915/intel_lrc_reg.h +++ b/drivers/gpu/drm/i915/intel_lrc_reg.h @@ -37,7 +37,7 @@ #define CTX_PDP0_LDW 0x32 #define CTX_LRI_HEADER_2 0x41 #define CTX_R_PWR_CLK_STATE 0x42 -#define CTX_GPGPU_CSR_BASE_ADDRESS 0x44 +#define CTX_END 0x44 #define CTX_REG(reg_state, pos, reg, val) do { \ u32 *reg_state__ = (reg_state); \ diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c index 9f0bd6a4cb79..77e9871a8c9a 100644 --- a/drivers/gpu/drm/i915/intel_mocs.c +++ b/drivers/gpu/drm/i915/intel_mocs.c @@ -232,20 +232,17 @@ static i915_reg_t mocs_register(enum intel_engine_id engine_id, int index) * * This function simply emits a MI_LOAD_REGISTER_IMM command for the * given table starting at the given address. - * - * Return: 0 on success, otherwise the error status. */ -int intel_mocs_init_engine(struct intel_engine_cs *engine) +void intel_mocs_init_engine(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; struct drm_i915_mocs_table table; unsigned int index; if (!get_mocs_settings(dev_priv, &table)) - return 0; + return; - if (WARN_ON(table.size > GEN9_NUM_MOCS_ENTRIES)) - return -ENODEV; + GEM_BUG_ON(table.size > GEN9_NUM_MOCS_ENTRIES); for (index = 0; index < table.size; index++) I915_WRITE(mocs_register(engine->id, index), @@ -262,8 +259,6 @@ int intel_mocs_init_engine(struct intel_engine_cs *engine) for (; index < GEN9_NUM_MOCS_ENTRIES; index++) I915_WRITE(mocs_register(engine->id, index), table.table[0].control_value); - - return 0; } /** diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h index d1751f91c1a4..d89080d75b80 100644 --- a/drivers/gpu/drm/i915/intel_mocs.h +++ b/drivers/gpu/drm/i915/intel_mocs.h @@ -54,6 +54,6 @@ int intel_rcs_context_init_mocs(struct i915_request *rq); void intel_mocs_init_l3cc_table(struct drm_i915_private *dev_priv); -int intel_mocs_init_engine(struct intel_engine_cs *engine); +void intel_mocs_init_engine(struct intel_engine_cs *engine); #endif diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 443dfaefd7a6..72eb7e48e8bc 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -487,23 +487,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv) overlay->active = false; } -struct put_image_params { - int format; - short dst_x; - short dst_y; - short dst_w; - short dst_h; - short src_w; - short src_scan_h; - short src_scan_w; - short src_h; - short stride_Y; - short stride_UV; - int offset_Y; - int offset_U; - int offset_V; -}; - static int packed_depth_bytes(u32 format) { switch (format & I915_OVERLAY_DEPTH_MASK) { @@ -618,25 +601,25 @@ static void update_polyphase_filter(struct overlay_registers __iomem *regs) static bool update_scaling_factors(struct intel_overlay *overlay, struct overlay_registers __iomem *regs, - struct put_image_params *params) + struct drm_intel_overlay_put_image *params) { /* fixed point with a 12 bit shift */ u32 xscale, yscale, xscale_UV, yscale_UV; #define FP_SHIFT 12 #define FRACT_MASK 0xfff bool scale_changed = false; - int uv_hscale = uv_hsubsampling(params->format); - int uv_vscale = uv_vsubsampling(params->format); + int uv_hscale = uv_hsubsampling(params->flags); + int uv_vscale = uv_vsubsampling(params->flags); - if (params->dst_w > 1) - xscale = ((params->src_scan_w - 1) << FP_SHIFT) - /(params->dst_w); + if (params->dst_width > 1) + xscale = ((params->src_scan_width - 1) << FP_SHIFT) / + params->dst_width; else xscale = 1 << FP_SHIFT; - if (params->dst_h > 1) - yscale = ((params->src_scan_h - 1) << FP_SHIFT) - /(params->dst_h); + if (params->dst_height > 1) + yscale = ((params->src_scan_height - 1) << FP_SHIFT) / + params->dst_height; else yscale = 1 << FP_SHIFT; @@ -713,12 +696,12 @@ static void update_colorkey(struct intel_overlay *overlay, iowrite32(flags, ®s->DCLRKM); } -static u32 overlay_cmd_reg(struct put_image_params *params) +static u32 overlay_cmd_reg(struct drm_intel_overlay_put_image *params) { u32 cmd = OCMD_ENABLE | OCMD_BUF_TYPE_FRAME | OCMD_BUFFER0; - if (params->format & I915_OVERLAY_YUV_PLANAR) { - switch (params->format & I915_OVERLAY_DEPTH_MASK) { + if (params->flags & I915_OVERLAY_YUV_PLANAR) { + switch (params->flags & I915_OVERLAY_DEPTH_MASK) { case I915_OVERLAY_YUV422: cmd |= OCMD_YUV_422_PLANAR; break; @@ -731,7 +714,7 @@ static u32 overlay_cmd_reg(struct put_image_params *params) break; } } else { /* YUV packed */ - switch (params->format & I915_OVERLAY_DEPTH_MASK) { + switch (params->flags & I915_OVERLAY_DEPTH_MASK) { case I915_OVERLAY_YUV422: cmd |= OCMD_YUV_422_PACKED; break; @@ -740,7 +723,7 @@ static u32 overlay_cmd_reg(struct put_image_params *params) break; } - switch (params->format & I915_OVERLAY_SWAP_MASK) { + switch (params->flags & I915_OVERLAY_SWAP_MASK) { case I915_OVERLAY_NO_SWAP: break; case I915_OVERLAY_UV_SWAP: @@ -760,7 +743,7 @@ static u32 overlay_cmd_reg(struct put_image_params *params) static int intel_overlay_do_put_image(struct intel_overlay *overlay, struct drm_i915_gem_object *new_bo, - struct put_image_params *params) + struct drm_intel_overlay_put_image *params) { struct overlay_registers __iomem *regs = overlay->regs; struct drm_i915_private *dev_priv = overlay->i915; @@ -806,35 +789,40 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, goto out_unpin; } - iowrite32((params->dst_y << 16) | params->dst_x, ®s->DWINPOS); - iowrite32((params->dst_h << 16) | params->dst_w, ®s->DWINSZ); + iowrite32(params->dst_y << 16 | params->dst_x, ®s->DWINPOS); + iowrite32(params->dst_height << 16 | params->dst_width, ®s->DWINSZ); - if (params->format & I915_OVERLAY_YUV_PACKED) - tmp_width = packed_width_bytes(params->format, params->src_w); + if (params->flags & I915_OVERLAY_YUV_PACKED) + tmp_width = packed_width_bytes(params->flags, + params->src_width); else - tmp_width = params->src_w; + tmp_width = params->src_width; - swidth = params->src_w; + swidth = params->src_width; swidthsw = calc_swidthsw(dev_priv, params->offset_Y, tmp_width); - sheight = params->src_h; + sheight = params->src_height; iowrite32(i915_ggtt_offset(vma) + params->offset_Y, ®s->OBUF_0Y); ostride = params->stride_Y; - if (params->format & I915_OVERLAY_YUV_PLANAR) { - int uv_hscale = uv_hsubsampling(params->format); - int uv_vscale = uv_vsubsampling(params->format); + if (params->flags & I915_OVERLAY_YUV_PLANAR) { + int uv_hscale = uv_hsubsampling(params->flags); + int uv_vscale = uv_vsubsampling(params->flags); u32 tmp_U, tmp_V; - swidth |= (params->src_w/uv_hscale) << 16; + + swidth |= (params->src_width / uv_hscale) << 16; + sheight |= (params->src_height / uv_vscale) << 16; + tmp_U = calc_swidthsw(dev_priv, params->offset_U, - params->src_w/uv_hscale); + params->src_width / uv_hscale); tmp_V = calc_swidthsw(dev_priv, params->offset_V, - params->src_w/uv_hscale); - swidthsw |= max_t(u32, tmp_U, tmp_V) << 16; - sheight |= (params->src_h/uv_vscale) << 16; + params->src_width / uv_hscale); + swidthsw |= max(tmp_U, tmp_V) << 16; + iowrite32(i915_ggtt_offset(vma) + params->offset_U, ®s->OBUF_0U); iowrite32(i915_ggtt_offset(vma) + params->offset_V, ®s->OBUF_0V); + ostride |= params->stride_UV << 16; } @@ -938,15 +926,16 @@ static int check_overlay_dst(struct intel_overlay *overlay, return -EINVAL; } -static int check_overlay_scaling(struct put_image_params *rec) +static int check_overlay_scaling(struct drm_intel_overlay_put_image *rec) { u32 tmp; /* downscaling limit is 8.0 */ - tmp = ((rec->src_scan_h << 16) / rec->dst_h) >> 16; + tmp = ((rec->src_scan_height << 16) / rec->dst_height) >> 16; if (tmp > 7) return -EINVAL; - tmp = ((rec->src_scan_w << 16) / rec->dst_w) >> 16; + + tmp = ((rec->src_scan_width << 16) / rec->dst_width) >> 16; if (tmp > 7) return -EINVAL; @@ -1067,13 +1056,12 @@ static int check_overlay_src(struct drm_i915_private *dev_priv, int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_intel_overlay_put_image *put_image_rec = data; + struct drm_intel_overlay_put_image *params = data; struct drm_i915_private *dev_priv = to_i915(dev); struct intel_overlay *overlay; struct drm_crtc *drmmode_crtc; struct intel_crtc *crtc; struct drm_i915_gem_object *new_bo; - struct put_image_params *params; int ret; overlay = dev_priv->overlay; @@ -1082,7 +1070,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, return -ENODEV; } - if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { + if (!(params->flags & I915_OVERLAY_ENABLE)) { drm_modeset_lock_all(dev); mutex_lock(&dev->struct_mutex); @@ -1094,22 +1082,14 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, return ret; } - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - drmmode_crtc = drm_crtc_find(dev, file_priv, put_image_rec->crtc_id); - if (!drmmode_crtc) { - ret = -ENOENT; - goto out_free; - } + drmmode_crtc = drm_crtc_find(dev, file_priv, params->crtc_id); + if (!drmmode_crtc) + return -ENOENT; crtc = to_intel_crtc(drmmode_crtc); - new_bo = i915_gem_object_lookup(file_priv, put_image_rec->bo_handle); - if (!new_bo) { - ret = -ENOENT; - goto out_free; - } + new_bo = i915_gem_object_lookup(file_priv, params->bo_handle); + if (!new_bo) + return -ENOENT; drm_modeset_lock_all(dev); mutex_lock(&dev->struct_mutex); @@ -1145,42 +1125,27 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, overlay->pfit_active = false; } - ret = check_overlay_dst(overlay, put_image_rec); + ret = check_overlay_dst(overlay, params); if (ret != 0) goto out_unlock; if (overlay->pfit_active) { - params->dst_y = ((((u32)put_image_rec->dst_y) << 12) / + params->dst_y = (((u32)params->dst_y << 12) / overlay->pfit_vscale_ratio); /* shifting right rounds downwards, so add 1 */ - params->dst_h = ((((u32)put_image_rec->dst_height) << 12) / + params->dst_height = (((u32)params->dst_height << 12) / overlay->pfit_vscale_ratio) + 1; - } else { - params->dst_y = put_image_rec->dst_y; - params->dst_h = put_image_rec->dst_height; } - params->dst_x = put_image_rec->dst_x; - params->dst_w = put_image_rec->dst_width; - - params->src_w = put_image_rec->src_width; - params->src_h = put_image_rec->src_height; - params->src_scan_w = put_image_rec->src_scan_width; - params->src_scan_h = put_image_rec->src_scan_height; - if (params->src_scan_h > params->src_h || - params->src_scan_w > params->src_w) { + + if (params->src_scan_height > params->src_height || + params->src_scan_width > params->src_width) { ret = -EINVAL; goto out_unlock; } - ret = check_overlay_src(dev_priv, put_image_rec, new_bo); + ret = check_overlay_src(dev_priv, params, new_bo); if (ret != 0) goto out_unlock; - params->format = put_image_rec->flags & ~I915_OVERLAY_FLAGS_MASK; - params->stride_Y = put_image_rec->stride_Y; - params->stride_UV = put_image_rec->stride_UV; - params->offset_Y = put_image_rec->offset_Y; - params->offset_U = put_image_rec->offset_U; - params->offset_V = put_image_rec->offset_V; /* Check scaling after src size to prevent a divide-by-zero. */ ret = check_overlay_scaling(params); @@ -1195,16 +1160,12 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data, drm_modeset_unlock_all(dev); i915_gem_object_put(new_bo); - kfree(params); - return 0; out_unlock: mutex_unlock(&dev->struct_mutex); drm_modeset_unlock_all(dev); i915_gem_object_put(new_bo); -out_free: - kfree(params); return ret; } diff --git a/drivers/gpu/drm/i915/intel_pipe_crc.c b/drivers/gpu/drm/i915/intel_pipe_crc.c index 849e1b69ba73..f3c9010e332a 100644 --- a/drivers/gpu/drm/i915/intel_pipe_crc.c +++ b/drivers/gpu/drm/i915/intel_pipe_crc.c @@ -468,8 +468,122 @@ void intel_display_crc_init(struct drm_i915_private *dev_priv) } } -int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, - size_t *values_cnt) +static int i8xx_crc_source_valid(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PIPE: + case INTEL_PIPE_CRC_SOURCE_NONE: + return 0; + default: + return -EINVAL; + } +} + +static int i9xx_crc_source_valid(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PIPE: + case INTEL_PIPE_CRC_SOURCE_TV: + case INTEL_PIPE_CRC_SOURCE_DP_B: + case INTEL_PIPE_CRC_SOURCE_DP_C: + case INTEL_PIPE_CRC_SOURCE_DP_D: + case INTEL_PIPE_CRC_SOURCE_NONE: + return 0; + default: + return -EINVAL; + } +} + +static int vlv_crc_source_valid(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PIPE: + case INTEL_PIPE_CRC_SOURCE_DP_B: + case INTEL_PIPE_CRC_SOURCE_DP_C: + case INTEL_PIPE_CRC_SOURCE_DP_D: + case INTEL_PIPE_CRC_SOURCE_NONE: + return 0; + default: + return -EINVAL; + } +} + +static int ilk_crc_source_valid(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PIPE: + case INTEL_PIPE_CRC_SOURCE_PLANE1: + case INTEL_PIPE_CRC_SOURCE_PLANE2: + case INTEL_PIPE_CRC_SOURCE_NONE: + return 0; + default: + return -EINVAL; + } +} + +static int ivb_crc_source_valid(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + switch (source) { + case INTEL_PIPE_CRC_SOURCE_PIPE: + case INTEL_PIPE_CRC_SOURCE_PLANE1: + case INTEL_PIPE_CRC_SOURCE_PLANE2: + case INTEL_PIPE_CRC_SOURCE_PF: + case INTEL_PIPE_CRC_SOURCE_NONE: + return 0; + default: + return -EINVAL; + } +} + +static int +intel_is_valid_crc_source(struct drm_i915_private *dev_priv, + const enum intel_pipe_crc_source source) +{ + if (IS_GEN2(dev_priv)) + return i8xx_crc_source_valid(dev_priv, source); + else if (INTEL_GEN(dev_priv) < 5) + return i9xx_crc_source_valid(dev_priv, source); + else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + return vlv_crc_source_valid(dev_priv, source); + else if (IS_GEN5(dev_priv) || IS_GEN6(dev_priv)) + return ilk_crc_source_valid(dev_priv, source); + else + return ivb_crc_source_valid(dev_priv, source); +} + +const char *const *intel_crtc_get_crc_sources(struct drm_crtc *crtc, + size_t *count) +{ + *count = ARRAY_SIZE(pipe_crc_sources); + return pipe_crc_sources; +} + +int intel_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, + size_t *values_cnt) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum intel_pipe_crc_source source; + + if (display_crc_ctl_parse_source(source_name, &source) < 0) { + DRM_DEBUG_DRIVER("unknown source %s\n", source_name); + return -EINVAL; + } + + if (source == INTEL_PIPE_CRC_SOURCE_AUTO || + intel_is_valid_crc_source(dev_priv, source) == 0) { + *values_cnt = 5; + return 0; + } + + return -EINVAL; +} + +int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[crtc->index]; @@ -508,7 +622,6 @@ int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name, } pipe_crc->skipped = 0; - *values_cnt = 5; out: intel_display_power_put(dev_priv, power_domain); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 43ae9de12ba3..1db9b8328275 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -26,6 +26,7 @@ */ #include <linux/cpufreq.h> +#include <linux/pm_runtime.h> #include <drm/drm_plane_helper.h> #include "i915_drv.h" #include "intel_drv.h" @@ -2874,6 +2875,16 @@ static void intel_read_wm_latency(struct drm_i915_private *dev_priv, } } + /* + * WA Level-0 adjustment for 16GB DIMMs: SKL+ + * If we could not get dimm info enable this WA to prevent from + * any underrun. If not able to get Dimm info assume 16GB dimm + * to avoid any underrun. + */ + if (!dev_priv->dram_info.valid_dimm || + dev_priv->dram_info.is_16gb_dimm) + wm[0] += 1; + } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { uint64_t sskpd = I915_READ64(MCH_SSKPD); @@ -2942,8 +2953,8 @@ static void intel_print_wm_latency(struct drm_i915_private *dev_priv, unsigned int latency = wm[level]; if (latency == 0) { - DRM_ERROR("%s WM%d latency not provided\n", - name, level); + DRM_DEBUG_KMS("%s WM%d latency not provided\n", + name, level); continue; } @@ -3771,11 +3782,11 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state) return true; } -static unsigned int intel_get_ddb_size(struct drm_i915_private *dev_priv, - const struct intel_crtc_state *cstate, - const unsigned int total_data_rate, - const int num_active, - struct skl_ddb_allocation *ddb) +static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, + const struct intel_crtc_state *cstate, + const unsigned int total_data_rate, + const int num_active, + struct skl_ddb_allocation *ddb) { const struct drm_display_mode *adjusted_mode; u64 total_data_bw; @@ -3814,8 +3825,12 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *for_crtc = cstate->base.crtc; - unsigned int pipe_size, ddb_size; - int nth_active_pipe; + const struct drm_crtc_state *crtc_state; + const struct drm_crtc *crtc; + u32 pipe_width = 0, total_width = 0, width_before_pipe = 0; + enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe; + u16 ddb_size; + u32 i; if (WARN_ON(!state) || !cstate->base.active) { alloc->start = 0; @@ -3833,14 +3848,14 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, *num_active, ddb); /* - * If the state doesn't change the active CRTC's, then there's - * no need to recalculate; the existing pipe allocation limits - * should remain unchanged. Note that we're safe from racing - * commits since any racing commit that changes the active CRTC - * list would need to grab _all_ crtc locks, including the one - * we currently hold. + * If the state doesn't change the active CRTC's or there is no + * modeset request, then there's no need to recalculate; + * the existing pipe allocation limits should remain unchanged. + * Note that we're safe from racing commits since any racing commit + * that changes the active CRTC list or do modeset would need to + * grab _all_ crtc locks, including the one we currently hold. */ - if (!intel_state->active_pipe_changes) { + if (!intel_state->active_pipe_changes && !intel_state->modeset) { /* * alloc may be cleared by clear_intel_crtc_state, * copy from old state to be sure @@ -3849,11 +3864,32 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, return; } - nth_active_pipe = hweight32(intel_state->active_crtcs & - (drm_crtc_mask(for_crtc) - 1)); - pipe_size = ddb_size / hweight32(intel_state->active_crtcs); - alloc->start = nth_active_pipe * ddb_size / *num_active; - alloc->end = alloc->start + pipe_size; + /* + * Watermark/ddb requirement highly depends upon width of the + * framebuffer, So instead of allocating DDB equally among pipes + * distribute DDB based on resolution/width of the display. + */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + const struct drm_display_mode *adjusted_mode; + int hdisplay, vdisplay; + enum pipe pipe; + + if (!crtc_state->enable) + continue; + + pipe = to_intel_crtc(crtc)->pipe; + adjusted_mode = &crtc_state->adjusted_mode; + drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay); + total_width += hdisplay; + + if (pipe < for_pipe) + width_before_pipe += hdisplay; + else if (pipe == for_pipe) + pipe_width = hdisplay; + } + + alloc->start = ddb_size * width_before_pipe / total_width; + alloc->end = ddb_size * (width_before_pipe + pipe_width) / total_width; } static unsigned int skl_cursor_allocation(int num_active) @@ -3909,7 +3945,12 @@ skl_ddb_get_hw_plane_state(struct drm_i915_private *dev_priv, val & PLANE_CTL_ALPHA_MASK); val = I915_READ(PLANE_BUF_CFG(pipe, plane_id)); - val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id)); + /* + * FIXME: add proper NV12 support for ICL. Avoid reading unclaimed + * registers for now. + */ + if (INTEL_GEN(dev_priv) < 11) + val2 = I915_READ(PLANE_NV12_BUF_CFG(pipe, plane_id)); if (fourcc == DRM_FORMAT_NV12) { skl_ddb_entry_init_from_hw(dev_priv, @@ -4977,6 +5018,7 @@ static void skl_write_plane_wm(struct intel_crtc *intel_crtc, skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id), &ddb->plane[pipe][plane_id]); + /* FIXME: add proper NV12 support for ICL. */ if (INTEL_GEN(dev_priv) >= 11) return skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane_id), @@ -5142,17 +5184,6 @@ skl_compute_ddb(struct drm_atomic_state *state) } static void -skl_copy_ddb_for_pipe(struct skl_ddb_values *dst, - struct skl_ddb_values *src, - enum pipe pipe) -{ - memcpy(dst->ddb.uv_plane[pipe], src->ddb.uv_plane[pipe], - sizeof(dst->ddb.uv_plane[pipe])); - memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe], - sizeof(dst->ddb.plane[pipe])); -} - -static void skl_print_wm_changes(const struct drm_atomic_state *state) { const struct drm_device *dev = state->dev; @@ -5259,7 +5290,7 @@ skl_ddb_add_affected_pipes(struct drm_atomic_state *state, bool *changed) * any other display updates race with this transaction, so we need * to grab the lock on *all* CRTC's. */ - if (intel_state->active_pipe_changes) { + if (intel_state->active_pipe_changes || intel_state->modeset) { realloc_pipes = ~0; intel_state->wm_results.dirty_pipes = ~0; } @@ -5381,7 +5412,10 @@ static void skl_initial_wm(struct intel_atomic_state *state, if (cstate->base.active_changed) skl_atomic_update_crtc_wm(state, cstate); - skl_copy_ddb_for_pipe(hw_vals, results, pipe); + memcpy(hw_vals->ddb.uv_plane[pipe], results->ddb.uv_plane[pipe], + sizeof(hw_vals->ddb.uv_plane[pipe])); + memcpy(hw_vals->ddb.plane[pipe], results->ddb.plane[pipe], + sizeof(hw_vals->ddb.plane[pipe])); mutex_unlock(&dev_priv->wm.wm_mutex); } @@ -6084,10 +6118,13 @@ void intel_enable_ipc(struct drm_i915_private *dev_priv) u32 val; /* Display WA #0477 WaDisableIPC: skl */ - if (IS_SKYLAKE(dev_priv)) { + if (IS_SKYLAKE(dev_priv)) + dev_priv->ipc_enabled = false; + + /* Display WA #1141: SKL:all KBL:all CFL */ + if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) && + !dev_priv->dram_info.symmetric_memory) dev_priv->ipc_enabled = false; - return; - } val = I915_READ(DISP_ARB_CTL2); @@ -6379,7 +6416,6 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val) new_power = HIGH_POWER; rps_set_power(dev_priv, new_power); mutex_unlock(&rps->power.mutex); - rps->last_adj = 0; } void intel_rps_mark_interactive(struct drm_i915_private *i915, bool interactive) @@ -8159,7 +8195,7 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv) */ if (!sanitize_rc6(dev_priv)) { DRM_INFO("RC6 disabled, disabling runtime PM support\n"); - intel_runtime_pm_get(dev_priv); + pm_runtime_get(&dev_priv->drm.pdev->dev); } mutex_lock(&dev_priv->pcu_lock); @@ -8211,7 +8247,7 @@ void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv) valleyview_cleanup_gt_powersave(dev_priv); if (!HAS_RC6(dev_priv)) - intel_runtime_pm_put(dev_priv); + pm_runtime_put(&dev_priv->drm.pdev->dev); } /** @@ -8238,7 +8274,7 @@ void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv) if (INTEL_GEN(dev_priv) >= 11) gen11_reset_rps_interrupts(dev_priv); - else + else if (INTEL_GEN(dev_priv) >= 6) gen6_reset_rps_interrupts(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 4bd5768731ee..b6838b525502 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -56,7 +56,30 @@ #include "intel_drv.h" #include "i915_drv.h" -void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug) +static bool psr_global_enabled(u32 debug) +{ + switch (debug & I915_PSR_DEBUG_MODE_MASK) { + case I915_PSR_DEBUG_DEFAULT: + return i915_modparams.enable_psr; + case I915_PSR_DEBUG_DISABLE: + return false; + default: + return true; + } +} + +static bool intel_psr2_enabled(struct drm_i915_private *dev_priv, + const struct intel_crtc_state *crtc_state) +{ + switch (dev_priv->psr.debug & I915_PSR_DEBUG_MODE_MASK) { + case I915_PSR_DEBUG_FORCE_PSR1: + return false; + default: + return crtc_state->has_psr2; + } +} + +void intel_psr_irq_control(struct drm_i915_private *dev_priv, u32 debug) { u32 debug_mask, mask; @@ -77,10 +100,9 @@ void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug) EDP_PSR_PRE_ENTRY(TRANSCODER_C); } - if (debug) + if (debug & I915_PSR_DEBUG_IRQ) mask |= debug_mask; - WRITE_ONCE(dev_priv->psr.debug, debug); I915_WRITE(EDP_PSR_IMR, ~mask); } @@ -213,6 +235,9 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) dev_priv->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); + WARN_ON(dev_priv->psr.dp); + dev_priv->psr.dp = intel_dp; + if (INTEL_GEN(dev_priv) >= 9 && (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { bool y_req = intel_dp->psr_dpcd[1] & @@ -245,7 +270,7 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct edp_vsc_psr psr_vsc; if (dev_priv->psr.psr2_enabled) { @@ -275,8 +300,7 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp, static void hsw_psr_setup_aux(struct intel_dp *intel_dp) { - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 aux_clock_divider, aux_ctl; int i; static const uint8_t aux_msg[] = { @@ -309,9 +333,7 @@ static void hsw_psr_setup_aux(struct intel_dp *intel_dp) static void intel_psr_enable_sink(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 = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 dpcd_val = DP_PSR_ENABLE; /* Enable ALPM at sink for psr2 */ @@ -332,9 +354,7 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) static void hsw_activate_psr1(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 = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 max_sleep_time = 0x1f; u32 val = EDP_PSR_ENABLE; @@ -389,9 +409,7 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) static void hsw_activate_psr2(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 = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 val; /* Let's use 6 as the minimum to cover all known cases including the @@ -427,8 +445,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); int crtc_hdisplay = crtc_state->base.adjusted_mode.crtc_hdisplay; int crtc_vdisplay = crtc_state->base.adjusted_mode.crtc_vdisplay; int psr_max_h = 0, psr_max_v = 0; @@ -463,7 +480,7 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; int psr_setup_time; @@ -471,10 +488,8 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, if (!CAN_PSR(dev_priv)) return; - if (!i915_modparams.enable_psr) { - DRM_DEBUG_KMS("PSR disable by flag\n"); + if (intel_dp != dev_priv->psr.dp) return; - } /* * HSW spec explicitly says PSR is tied to port A. @@ -517,14 +532,11 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, crtc_state->has_psr = true; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); - DRM_DEBUG_KMS("Enabling PSR%s\n", crtc_state->has_psr2 ? "2" : ""); } static void intel_psr_activate(struct intel_dp *intel_dp) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (INTEL_GEN(dev_priv) >= 9) WARN_ON(I915_READ(EDP_PSR2_CTL) & EDP_PSR2_ENABLE); @@ -544,9 +556,7 @@ static void intel_psr_activate(struct intel_dp *intel_dp) static void intel_psr_enable_source(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { - 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 = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; /* Only HSW and BDW have PSR AUX registers that need to be setup. SKL+ @@ -589,6 +599,24 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, } } +static void intel_psr_enable_locked(struct drm_i915_private *dev_priv, + const struct intel_crtc_state *crtc_state) +{ + struct intel_dp *intel_dp = dev_priv->psr.dp; + + if (dev_priv->psr.enabled) + return; + + DRM_DEBUG_KMS("Enabling PSR%s\n", + dev_priv->psr.psr2_enabled ? "2" : "1"); + intel_psr_setup_vsc(intel_dp, crtc_state); + intel_psr_enable_sink(intel_dp); + intel_psr_enable_source(intel_dp, crtc_state); + dev_priv->psr.enabled = true; + + intel_psr_activate(intel_dp); +} + /** * intel_psr_enable - Enable PSR * @intel_dp: Intel DP @@ -599,9 +627,7 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, void intel_psr_enable(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!crtc_state->has_psr) return; @@ -610,21 +636,21 @@ void intel_psr_enable(struct intel_dp *intel_dp, return; WARN_ON(dev_priv->drrs.dp); + mutex_lock(&dev_priv->psr.lock); - if (dev_priv->psr.enabled) { + if (dev_priv->psr.prepared) { DRM_DEBUG_KMS("PSR already in use\n"); goto unlock; } - dev_priv->psr.psr2_enabled = crtc_state->has_psr2; + dev_priv->psr.psr2_enabled = intel_psr2_enabled(dev_priv, crtc_state); dev_priv->psr.busy_frontbuffer_bits = 0; + dev_priv->psr.prepared = true; - intel_psr_setup_vsc(intel_dp, crtc_state); - intel_psr_enable_sink(intel_dp); - intel_psr_enable_source(intel_dp, crtc_state); - dev_priv->psr.enabled = intel_dp; - - intel_psr_activate(intel_dp); + if (psr_global_enabled(dev_priv->psr.debug)) + intel_psr_enable_locked(dev_priv, crtc_state); + else + DRM_DEBUG_KMS("PSR disabled by flag\n"); unlock: mutex_unlock(&dev_priv->psr.lock); @@ -633,9 +659,7 @@ unlock: static void intel_psr_disable_source(struct intel_dp *intel_dp) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (dev_priv->psr.active) { i915_reg_t psr_status; @@ -674,21 +698,21 @@ intel_psr_disable_source(struct intel_dp *intel_dp) static void intel_psr_disable_locked(struct intel_dp *intel_dp) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); lockdep_assert_held(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) return; + DRM_DEBUG_KMS("Disabling PSR%s\n", + dev_priv->psr.psr2_enabled ? "2" : "1"); intel_psr_disable_source(intel_dp); /* Disable PSR on Sink */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, 0); - dev_priv->psr.enabled = NULL; + dev_priv->psr.enabled = false; } /** @@ -701,9 +725,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) void intel_psr_disable(struct intel_dp *intel_dp, const struct intel_crtc_state *old_crtc_state) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); if (!old_crtc_state->has_psr) return; @@ -712,57 +734,61 @@ void intel_psr_disable(struct intel_dp *intel_dp, return; mutex_lock(&dev_priv->psr.lock); + if (!dev_priv->psr.prepared) { + mutex_unlock(&dev_priv->psr.lock); + return; + } + intel_psr_disable_locked(intel_dp); + + dev_priv->psr.prepared = false; mutex_unlock(&dev_priv->psr.lock); cancel_work_sync(&dev_priv->psr.work); } -int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) +/** + * intel_psr_wait_for_idle - wait for PSR1 to idle + * @new_crtc_state: new CRTC state + * @out_value: PSR status in case of failure + * + * This function is expected to be called from pipe_update_start() where it is + * not expected to race with PSR enable or disable. + * + * Returns: 0 on success or -ETIMEOUT if PSR status does not idle. + */ +int intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state, + u32 *out_value) { struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - i915_reg_t reg; - u32 mask; - if (!new_crtc_state->has_psr) + if (!dev_priv->psr.enabled || !new_crtc_state->has_psr) return 0; - /* - * The sole user right now is intel_pipe_update_start(), - * which won't race with psr_enable/disable, which is - * where psr2_enabled is written to. So, we don't need - * to acquire the psr.lock. More importantly, we want the - * latency inside intel_pipe_update_start() to be as low - * as possible, so no need to acquire psr.lock when it is - * not needed and will induce latencies in the atomic - * update path. - */ - if (dev_priv->psr.psr2_enabled) { - reg = EDP_PSR2_STATUS; - mask = EDP_PSR2_STATUS_STATE_MASK; - } else { - reg = EDP_PSR_STATUS; - mask = EDP_PSR_STATUS_STATE_MASK; - } + /* FIXME: Update this for PSR2 if we need to wait for idle */ + if (READ_ONCE(dev_priv->psr.psr2_enabled)) + return 0; /* - * Max time for PSR to idle = Inverse of the refresh rate + - * 6 ms of exit training time + 1.5 ms of aux channel - * handshake. 50 msec is defesive enough to cover everything. + * From bspec: Panel Self Refresh (BDW+) + * Max. time for PSR to idle = Inverse of the refresh rate + 6 ms of + * exit training time + 1.5 ms of aux channel handshake. 50 ms is + * defensive enough to cover everything. */ - return intel_wait_for_register(dev_priv, reg, mask, - EDP_PSR_STATUS_STATE_IDLE, 50); + + return __intel_wait_for_register(dev_priv, EDP_PSR_STATUS, + EDP_PSR_STATUS_STATE_MASK, + EDP_PSR_STATUS_STATE_IDLE, 2, 50, + out_value); } static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv) { - struct intel_dp *intel_dp; i915_reg_t reg; u32 mask; int err; - intel_dp = dev_priv->psr.enabled; - if (!intel_dp) + if (!dev_priv->psr.enabled) return false; if (dev_priv->psr.psr2_enabled) { @@ -784,6 +810,89 @@ static bool __psr_wait_for_idle_locked(struct drm_i915_private *dev_priv) return err == 0 && dev_priv->psr.enabled; } +static bool switching_psr(struct drm_i915_private *dev_priv, + struct intel_crtc_state *crtc_state, + u32 mode) +{ + /* Can't switch psr state anyway if PSR2 is not supported. */ + if (!crtc_state || !crtc_state->has_psr2) + return false; + + if (dev_priv->psr.psr2_enabled && mode == I915_PSR_DEBUG_FORCE_PSR1) + return true; + + if (!dev_priv->psr.psr2_enabled && mode != I915_PSR_DEBUG_FORCE_PSR1) + return true; + + return false; +} + +int intel_psr_set_debugfs_mode(struct drm_i915_private *dev_priv, + struct drm_modeset_acquire_ctx *ctx, + u64 val) +{ + struct drm_device *dev = &dev_priv->drm; + struct drm_connector_state *conn_state; + struct intel_crtc_state *crtc_state = NULL; + struct drm_crtc_commit *commit; + struct drm_crtc *crtc; + struct intel_dp *dp; + int ret; + bool enable; + u32 mode = val & I915_PSR_DEBUG_MODE_MASK; + + if (val & ~(I915_PSR_DEBUG_IRQ | I915_PSR_DEBUG_MODE_MASK) || + mode > I915_PSR_DEBUG_FORCE_PSR1) { + DRM_DEBUG_KMS("Invalid debug mask %llx\n", val); + return -EINVAL; + } + + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); + if (ret) + return ret; + + /* dev_priv->psr.dp should be set once and then never touched again. */ + dp = READ_ONCE(dev_priv->psr.dp); + conn_state = dp->attached_connector->base.state; + crtc = conn_state->crtc; + if (crtc) { + ret = drm_modeset_lock(&crtc->mutex, ctx); + if (ret) + return ret; + + crtc_state = to_intel_crtc_state(crtc->state); + commit = crtc_state->base.commit; + } else { + commit = conn_state->commit; + } + if (commit) { + ret = wait_for_completion_interruptible(&commit->hw_done); + if (ret) + return ret; + } + + ret = mutex_lock_interruptible(&dev_priv->psr.lock); + if (ret) + return ret; + + enable = psr_global_enabled(val); + + if (!enable || switching_psr(dev_priv, crtc_state, mode)) + intel_psr_disable_locked(dev_priv->psr.dp); + + dev_priv->psr.debug = val; + if (crtc) + dev_priv->psr.psr2_enabled = intel_psr2_enabled(dev_priv, crtc_state); + + intel_psr_irq_control(dev_priv, dev_priv->psr.debug); + + if (dev_priv->psr.prepared && enable) + intel_psr_enable_locked(dev_priv, crtc_state); + + mutex_unlock(&dev_priv->psr.lock); + return ret; +} + static void intel_psr_work(struct work_struct *work) { struct drm_i915_private *dev_priv = @@ -811,7 +920,7 @@ static void intel_psr_work(struct work_struct *work) if (dev_priv->psr.busy_frontbuffer_bits || dev_priv->psr.active) goto unlock; - intel_psr_activate(dev_priv->psr.enabled); + intel_psr_activate(dev_priv->psr.dp); unlock: mutex_unlock(&dev_priv->psr.lock); } @@ -866,7 +975,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv, return; } - crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; + crtc = dp_to_dig_port(dev_priv->psr.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); @@ -909,7 +1018,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, return; } - crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; + crtc = dp_to_dig_port(dev_priv->psr.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); @@ -977,9 +1086,7 @@ void intel_psr_init(struct drm_i915_private *dev_priv) void intel_psr_short_pulse(struct intel_dp *intel_dp) { - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct i915_psr *psr = &dev_priv->psr; u8 val; const u8 errors = DP_PSR_RFB_STORAGE_ERROR | @@ -991,7 +1098,7 @@ void intel_psr_short_pulse(struct intel_dp *intel_dp) mutex_lock(&psr->lock); - if (psr->enabled != intel_dp) + if (!psr->enabled || psr->dp != intel_dp) goto exit; if (drm_dp_dpcd_readb(&intel_dp->aux, DP_PSR_STATUS, &val) != 1) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6a8f27d0a742..d0ef50bf930a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -344,11 +344,14 @@ gen7_render_ring_flush(struct i915_request *rq, u32 mode) static void ring_setup_phys_status_page(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; + struct page *page = virt_to_page(engine->status_page.page_addr); + phys_addr_t phys = PFN_PHYS(page_to_pfn(page)); u32 addr; - addr = dev_priv->status_page_dmah->busaddr; + addr = lower_32_bits(phys); if (INTEL_GEN(dev_priv) >= 4) - addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + addr |= (phys >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); } @@ -537,6 +540,8 @@ static int init_ring_common(struct intel_engine_cs *engine) if (INTEL_GEN(dev_priv) > 2) I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING)); + /* Papering over lost _interrupts_ immediately following the restart */ + intel_engine_wakeup(engine); out: intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); @@ -1013,24 +1018,22 @@ i915_emit_bb_start(struct i915_request *rq, return 0; } - - -int intel_ring_pin(struct intel_ring *ring, - struct drm_i915_private *i915, - unsigned int offset_bias) +int intel_ring_pin(struct intel_ring *ring) { - enum i915_map_type map = HAS_LLC(i915) ? I915_MAP_WB : I915_MAP_WC; struct i915_vma *vma = ring->vma; + enum i915_map_type map = + HAS_LLC(vma->vm->i915) ? I915_MAP_WB : I915_MAP_WC; unsigned int flags; void *addr; int ret; GEM_BUG_ON(ring->vaddr); - flags = PIN_GLOBAL; - if (offset_bias) - flags |= PIN_OFFSET_BIAS | offset_bias; + + /* Ring wraparound at offset 0 sometimes hangs. No idea why. */ + flags |= PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma); + if (vma->obj->stolen) flags |= PIN_MAPPABLE; else @@ -1045,7 +1048,7 @@ int intel_ring_pin(struct intel_ring *ring, return ret; } - ret = i915_vma_pin(vma, 0, PAGE_SIZE, flags); + ret = i915_vma_pin(vma, 0, 0, flags); if (unlikely(ret)) return ret; @@ -1230,8 +1233,7 @@ static int __context_pin(struct intel_context *ce) return err; } - err = i915_vma_pin(vma, 0, I915_GTT_MIN_ALIGNMENT, - PIN_GLOBAL | PIN_HIGH); + err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH); if (err) return err; @@ -1419,8 +1421,7 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) goto err; } - /* Ring wraparound at offset 0 sometimes hangs. No idea why. */ - err = intel_ring_pin(ring, engine->i915, I915_GTT_PAGE_SIZE); + err = intel_ring_pin(ring); if (err) goto err_ring; @@ -1676,9 +1677,26 @@ static int switch_context(struct i915_request *rq) GEM_BUG_ON(HAS_EXECLISTS(rq->i915)); if (ppgtt) { - ret = load_pd_dir(rq, ppgtt); - if (ret) - goto err; + int loops; + + /* + * Baytail takes a little more convincing that it really needs + * to reload the PD between contexts. It is not just a little + * longer, as adding more stalls after the load_pd_dir (i.e. + * adding a long loop around flush_pd_dir) is not as effective + * as reloading the PD umpteen times. 32 is derived from + * experimentation (gem_exec_parallel/fds) and has no good + * explanation. + */ + loops = 1; + if (engine->id == BCS && IS_VALLEYVIEW(engine->i915)) + loops = 32; + + do { + ret = load_pd_dir(rq, ppgtt); + if (ret) + goto err; + } while (--loops); if (intel_engine_flag(engine) & ppgtt->pd_dirty_rings) { unwind_mm = intel_engine_flag(engine); @@ -1706,9 +1724,29 @@ static int switch_context(struct i915_request *rq) } if (ppgtt) { + ret = engine->emit_flush(rq, EMIT_INVALIDATE); + if (ret) + goto err_mm; + ret = flush_pd_dir(rq); if (ret) goto err_mm; + + /* + * Not only do we need a full barrier (post-sync write) after + * invalidating the TLBs, but we need to wait a little bit + * longer. Whether this is merely delaying us, or the + * subsequent flush is a key part of serialising with the + * post-sync op, this extra pass appears vital before a + * mm switch! + */ + ret = engine->emit_flush(rq, EMIT_INVALIDATE); + if (ret) + goto err_mm; + + ret = engine->emit_flush(rq, EMIT_FLUSH); + if (ret) + goto err_mm; } if (ctx->remap_slice) { @@ -1946,7 +1984,7 @@ static void gen6_bsd_submit_request(struct i915_request *request) intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); } -static int gen6_bsd_ring_flush(struct i915_request *rq, u32 mode) +static int mi_flush_dw(struct i915_request *rq, u32 flags) { u32 cmd, *cs; @@ -1956,7 +1994,8 @@ static int gen6_bsd_ring_flush(struct i915_request *rq, u32 mode) cmd = MI_FLUSH_DW; - /* We always require a command barrier so that subsequent + /* + * We always require a command barrier so that subsequent * commands, such as breadcrumb interrupts, are strictly ordered * wrt the contents of the write cache being flushed to memory * (and thus being coherent from the CPU). @@ -1964,22 +2003,33 @@ static int gen6_bsd_ring_flush(struct i915_request *rq, u32 mode) cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW; /* - * Bspec vol 1c.5 - video engine command streamer: + * Bspec vol 1c.3 - blitter engine command streamer: * "If ENABLED, all TLBs will be invalidated once the flush * operation is complete. This bit is only valid when the * Post-Sync Operation field is a value of 1h or 3h." */ - if (mode & EMIT_INVALIDATE) - cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD; + cmd |= flags; *cs++ = cmd; *cs++ = I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT; *cs++ = 0; *cs++ = MI_NOOP; + intel_ring_advance(rq, cs); + return 0; } +static int gen6_flush_dw(struct i915_request *rq, u32 mode, u32 invflags) +{ + return mi_flush_dw(rq, mode & EMIT_INVALIDATE ? invflags : 0); +} + +static int gen6_bsd_ring_flush(struct i915_request *rq, u32 mode) +{ + return gen6_flush_dw(rq, mode, MI_INVALIDATE_TLB | MI_INVALIDATE_BSD); +} + static int hsw_emit_bb_start(struct i915_request *rq, u64 offset, u32 len, @@ -1992,9 +2042,7 @@ hsw_emit_bb_start(struct i915_request *rq, return PTR_ERR(cs); *cs++ = MI_BATCH_BUFFER_START | (dispatch_flags & I915_DISPATCH_SECURE ? - 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) | - (dispatch_flags & I915_DISPATCH_RS ? - MI_BATCH_RESOURCE_STREAMER : 0); + 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW); /* bit0-7 is the length on GEN6+ */ *cs++ = offset; intel_ring_advance(rq, cs); @@ -2026,36 +2074,7 @@ gen6_emit_bb_start(struct i915_request *rq, static int gen6_ring_flush(struct i915_request *rq, u32 mode) { - u32 cmd, *cs; - - cs = intel_ring_begin(rq, 4); - if (IS_ERR(cs)) - return PTR_ERR(cs); - - cmd = MI_FLUSH_DW; - - /* We always require a command barrier so that subsequent - * commands, such as breadcrumb interrupts, are strictly ordered - * wrt the contents of the write cache being flushed to memory - * (and thus being coherent from the CPU). - */ - cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW; - - /* - * Bspec vol 1c.3 - blitter engine command streamer: - * "If ENABLED, all TLBs will be invalidated once the flush - * operation is complete. This bit is only valid when the - * Post-Sync Operation field is a value of 1h or 3h." - */ - if (mode & EMIT_INVALIDATE) - cmd |= MI_INVALIDATE_TLB; - *cs++ = cmd; - *cs++ = I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT; - *cs++ = 0; - *cs++ = MI_NOOP; - intel_ring_advance(rq, cs); - - return 0; + return gen6_flush_dw(rq, mode, MI_INVALIDATE_TLB); } static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index f5ffa6d31e82..2dfa585712c2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -2,6 +2,8 @@ #ifndef _INTEL_RINGBUFFER_H_ #define _INTEL_RINGBUFFER_H_ +#include <drm/drm_util.h> + #include <linux/hashtable.h> #include <linux/seqlock.h> @@ -474,7 +476,6 @@ struct intel_engine_cs { unsigned int dispatch_flags); #define I915_DISPATCH_SECURE BIT(0) #define I915_DISPATCH_PINNED BIT(1) -#define I915_DISPATCH_RS BIT(2) void (*emit_breadcrumb)(struct i915_request *rq, u32 *cs); int emit_breadcrumb_sz; @@ -797,9 +798,7 @@ struct intel_ring * intel_engine_create_ring(struct intel_engine_cs *engine, struct i915_timeline *timeline, int size); -int intel_ring_pin(struct intel_ring *ring, - struct drm_i915_private *i915, - unsigned int offset_bias); +int intel_ring_pin(struct intel_ring *ring); void intel_ring_reset(struct intel_ring *ring, u32 tail); unsigned int intel_ring_update_space(struct intel_ring *ring); void intel_ring_unpin(struct intel_ring *ring); @@ -909,18 +908,15 @@ int intel_init_blt_ring_buffer(struct intel_engine_cs *engine); int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine); int intel_engine_stop_cs(struct intel_engine_cs *engine); +void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine); u64 intel_engine_get_active_head(const struct intel_engine_cs *engine); u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine); -static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine) -{ - return intel_read_status_page(engine, I915_GEM_HWS_INDEX); -} - static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine) { - /* We are only peeking at the tail of the submit queue (and not the + /* + * We are only peeking at the tail of the submit queue (and not the * queue itself) in order to gain a hint as to the current active * state of the engine. Callers are not expected to be taking * engine->timeline->lock, nor are they expected to be concerned @@ -930,6 +926,31 @@ static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine) return READ_ONCE(engine->timeline.seqno); } +static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine) +{ + return intel_read_status_page(engine, I915_GEM_HWS_INDEX); +} + +static inline bool intel_engine_signaled(struct intel_engine_cs *engine, + u32 seqno) +{ + return i915_seqno_passed(intel_engine_get_seqno(engine), seqno); +} + +static inline bool intel_engine_has_completed(struct intel_engine_cs *engine, + u32 seqno) +{ + GEM_BUG_ON(!seqno); + return intel_engine_signaled(engine, seqno); +} + +static inline bool intel_engine_has_started(struct intel_engine_cs *engine, + u32 seqno) +{ + GEM_BUG_ON(!seqno); + return intel_engine_signaled(engine, seqno - 1); +} + void intel_engine_get_instdone(struct intel_engine_cs *engine, struct intel_instdone *instdone); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6b5aa3b074ec..0fdabce647ab 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -52,10 +52,6 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, enum i915_power_well_id power_well_id); -static struct i915_power_well * -lookup_power_well(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id); - const char * intel_display_power_domain_str(enum intel_display_power_domain domain) { @@ -159,17 +155,17 @@ intel_display_power_domain_str(enum intel_display_power_domain domain) static void intel_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - DRM_DEBUG_KMS("enabling %s\n", power_well->name); - power_well->ops->enable(dev_priv, power_well); + DRM_DEBUG_KMS("enabling %s\n", power_well->desc->name); + power_well->desc->ops->enable(dev_priv, power_well); power_well->hw_enabled = true; } static void intel_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - DRM_DEBUG_KMS("disabling %s\n", power_well->name); + DRM_DEBUG_KMS("disabling %s\n", power_well->desc->name); power_well->hw_enabled = false; - power_well->ops->disable(dev_priv, power_well); + power_well->desc->ops->disable(dev_priv, power_well); } static void intel_power_well_get(struct drm_i915_private *dev_priv, @@ -183,7 +179,7 @@ static void intel_power_well_put(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { WARN(!power_well->count, "Use count on power well %s is already zero", - power_well->name); + power_well->desc->name); if (!--power_well->count) intel_power_well_disable(dev_priv, power_well); @@ -213,7 +209,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv, is_enabled = true; for_each_power_domain_well_rev(dev_priv, power_well, BIT_ULL(domain)) { - if (power_well->always_on) + if (power_well->desc->always_on) continue; if (!power_well->hw_enabled) { @@ -257,30 +253,6 @@ bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv, return ret; } -/** - * intel_display_set_init_power - set the initial power domain state - * @dev_priv: i915 device instance - * @enable: whether to enable or disable the initial power domain state - * - * For simplicity our driver load/unload and system suspend/resume code assumes - * that all power domains are always enabled. This functions controls the state - * of this little hack. While the initial power domain state is enabled runtime - * pm is effectively disabled. - */ -void intel_display_set_init_power(struct drm_i915_private *dev_priv, - bool enable) -{ - if (dev_priv->power_domains.init_power_on == enable) - return; - - if (enable) - intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); - else - intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); - - dev_priv->power_domains.init_power_on = enable; -} - /* * Starting with Haswell, we have a "Power Down Well" that can be turned off * when not needed anymore. We have 4 registers that can request the power well @@ -323,26 +295,29 @@ static void hsw_power_well_pre_disable(struct drm_i915_private *dev_priv, static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; /* Timeout for PW1:10 us, AUX:not specified, other PWs:20 us. */ WARN_ON(intel_wait_for_register(dev_priv, - HSW_PWR_WELL_CTL_DRIVER(id), - HSW_PWR_WELL_CTL_STATE(id), - HSW_PWR_WELL_CTL_STATE(id), + regs->driver, + HSW_PWR_WELL_CTL_STATE(pw_idx), + HSW_PWR_WELL_CTL_STATE(pw_idx), 1)); } static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv, - enum i915_power_well_id id) + const struct i915_power_well_regs *regs, + int pw_idx) { - u32 req_mask = HSW_PWR_WELL_CTL_REQ(id); + u32 req_mask = HSW_PWR_WELL_CTL_REQ(pw_idx); u32 ret; - ret = I915_READ(HSW_PWR_WELL_CTL_BIOS(id)) & req_mask ? 1 : 0; - ret |= I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & req_mask ? 2 : 0; - ret |= I915_READ(HSW_PWR_WELL_CTL_KVMR) & req_mask ? 4 : 0; - ret |= I915_READ(HSW_PWR_WELL_CTL_DEBUG(id)) & req_mask ? 8 : 0; + ret = I915_READ(regs->bios) & req_mask ? 1 : 0; + ret |= I915_READ(regs->driver) & req_mask ? 2 : 0; + if (regs->kvmr.reg) + ret |= I915_READ(regs->kvmr) & req_mask ? 4 : 0; + ret |= I915_READ(regs->debug) & req_mask ? 8 : 0; return ret; } @@ -350,7 +325,8 @@ static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv, static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; bool disabled; u32 reqs; @@ -363,14 +339,14 @@ static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv, * Skip the wait in case any of the request bits are set and print a * diagnostic message. */ - wait_for((disabled = !(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & - HSW_PWR_WELL_CTL_STATE(id))) || - (reqs = hsw_power_well_requesters(dev_priv, id)), 1); + wait_for((disabled = !(I915_READ(regs->driver) & + HSW_PWR_WELL_CTL_STATE(pw_idx))) || + (reqs = hsw_power_well_requesters(dev_priv, regs, pw_idx)), 1); if (disabled) return; DRM_DEBUG_KMS("%s forced on (bios:%d driver:%d kvmr:%d debug:%d)\n", - power_well->name, + power_well->desc->name, !!(reqs & 1), !!(reqs & 2), !!(reqs & 4), !!(reqs & 8)); } @@ -386,14 +362,15 @@ static void gen9_wait_for_power_well_fuses(struct drm_i915_private *dev_priv, static void hsw_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; - bool wait_fuses = power_well->hsw.has_fuses; + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; + bool wait_fuses = power_well->desc->hsw.has_fuses; enum skl_power_gate uninitialized_var(pg); u32 val; if (wait_fuses) { - pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_TO_PG(id) : - SKL_PW_TO_PG(id); + pg = INTEL_GEN(dev_priv) >= 11 ? ICL_PW_CTL_IDX_TO_PG(pw_idx) : + SKL_PW_CTL_IDX_TO_PG(pw_idx); /* * For PW1 we have to wait both for the PW0/PG0 fuse state * before enabling the power well and PW1/PG1's own fuse @@ -405,52 +382,55 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv, gen9_wait_for_power_well_fuses(dev_priv, SKL_PG0); } - val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); - I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id)); + val = I915_READ(regs->driver); + I915_WRITE(regs->driver, val | HSW_PWR_WELL_CTL_REQ(pw_idx)); hsw_wait_for_power_well_enable(dev_priv, power_well); /* Display WA #1178: cnl */ if (IS_CANNONLAKE(dev_priv) && - (id == CNL_DISP_PW_AUX_B || id == CNL_DISP_PW_AUX_C || - id == CNL_DISP_PW_AUX_D || id == CNL_DISP_PW_AUX_F)) { - val = I915_READ(CNL_AUX_ANAOVRD1(id)); + pw_idx >= GLK_PW_CTL_IDX_AUX_B && + pw_idx <= CNL_PW_CTL_IDX_AUX_F) { + val = I915_READ(CNL_AUX_ANAOVRD1(pw_idx)); val |= CNL_AUX_ANAOVRD1_ENABLE | CNL_AUX_ANAOVRD1_LDO_BYPASS; - I915_WRITE(CNL_AUX_ANAOVRD1(id), val); + I915_WRITE(CNL_AUX_ANAOVRD1(pw_idx), val); } if (wait_fuses) gen9_wait_for_power_well_fuses(dev_priv, pg); - hsw_power_well_post_enable(dev_priv, power_well->hsw.irq_pipe_mask, - power_well->hsw.has_vga); + hsw_power_well_post_enable(dev_priv, + power_well->desc->hsw.irq_pipe_mask, + power_well->desc->hsw.has_vga); } static void hsw_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; u32 val; - hsw_power_well_pre_disable(dev_priv, power_well->hsw.irq_pipe_mask); + hsw_power_well_pre_disable(dev_priv, + power_well->desc->hsw.irq_pipe_mask); - val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); - I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), - val & ~HSW_PWR_WELL_CTL_REQ(id)); + val = I915_READ(regs->driver); + I915_WRITE(regs->driver, val & ~HSW_PWR_WELL_CTL_REQ(pw_idx)); hsw_wait_for_power_well_disable(dev_priv, power_well); } -#define ICL_AUX_PW_TO_PORT(pw) ((pw) - ICL_DISP_PW_AUX_A) +#define ICL_AUX_PW_TO_PORT(pw_idx) ((pw_idx) - ICL_PW_CTL_IDX_AUX_A) static void icl_combo_phy_aux_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; - enum port port = ICL_AUX_PW_TO_PORT(id); + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; + enum port port = ICL_AUX_PW_TO_PORT(pw_idx); u32 val; - val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); - I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id)); + val = I915_READ(regs->driver); + I915_WRITE(regs->driver, val | HSW_PWR_WELL_CTL_REQ(pw_idx)); val = I915_READ(ICL_PORT_CL_DW12(port)); I915_WRITE(ICL_PORT_CL_DW12(port), val | ICL_LANE_ENABLE_AUX); @@ -462,16 +442,16 @@ static void icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; - enum port port = ICL_AUX_PW_TO_PORT(id); + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; + enum port port = ICL_AUX_PW_TO_PORT(pw_idx); u32 val; val = I915_READ(ICL_PORT_CL_DW12(port)); I915_WRITE(ICL_PORT_CL_DW12(port), val & ~ICL_LANE_ENABLE_AUX); - val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); - I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), - val & ~HSW_PWR_WELL_CTL_REQ(id)); + val = I915_READ(regs->driver); + I915_WRITE(regs->driver, val & ~HSW_PWR_WELL_CTL_REQ(pw_idx)); hsw_wait_for_power_well_disable(dev_priv, power_well); } @@ -484,22 +464,22 @@ icl_combo_phy_aux_power_well_disable(struct drm_i915_private *dev_priv, static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; - u32 mask = HSW_PWR_WELL_CTL_REQ(id) | HSW_PWR_WELL_CTL_STATE(id); + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; + u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx) | + HSW_PWR_WELL_CTL_STATE(pw_idx); - return (I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & mask) == mask; + return (I915_READ(regs->driver) & mask) == mask; } static void assert_can_enable_dc9(struct drm_i915_private *dev_priv) { - enum i915_power_well_id id = SKL_DISP_PW_2; - WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9), "DC9 already programmed to be enabled.\n"); WARN_ONCE(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5, "DC5 still not disabled to enable DC9.\n"); - WARN_ONCE(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & - HSW_PWR_WELL_CTL_REQ(id), + WARN_ONCE(I915_READ(HSW_PWR_WELL_CTL2) & + HSW_PWR_WELL_CTL_REQ(SKL_PW_CTL_IDX_PW_2), "Power well 2 on.\n"); WARN_ONCE(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n"); @@ -668,6 +648,27 @@ static void assert_csr_loaded(struct drm_i915_private *dev_priv) WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); } +static struct i915_power_well * +lookup_power_well(struct drm_i915_private *dev_priv, + enum i915_power_well_id power_well_id) +{ + struct i915_power_well *power_well; + + for_each_power_well(dev_priv, power_well) + if (power_well->desc->id == power_well_id) + return power_well; + + /* + * It's not feasible to add error checking code to the callers since + * this condition really shouldn't happen and it doesn't even make sense + * to abort things like display initialization sequences. Just return + * the first power well and hope the WARN gets reported so we can fix + * our driver. + */ + WARN(1, "Power well %d not defined for this platform\n", power_well_id); + return &dev_priv->power_domains.power_wells[0]; +} + static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) { bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, @@ -723,54 +724,57 @@ static void skl_enable_dc6(struct drm_i915_private *dev_priv) static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id id = power_well->id; - u32 mask = HSW_PWR_WELL_CTL_REQ(id); - u32 bios_req = I915_READ(HSW_PWR_WELL_CTL_BIOS(id)); + const struct i915_power_well_regs *regs = power_well->desc->hsw.regs; + int pw_idx = power_well->desc->hsw.idx; + u32 mask = HSW_PWR_WELL_CTL_REQ(pw_idx); + u32 bios_req = I915_READ(regs->bios); /* Take over the request bit if set by BIOS. */ if (bios_req & mask) { - u32 drv_req = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)); + u32 drv_req = I915_READ(regs->driver); if (!(drv_req & mask)) - I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), drv_req | mask); - I915_WRITE(HSW_PWR_WELL_CTL_BIOS(id), bios_req & ~mask); + I915_WRITE(regs->driver, drv_req | mask); + I915_WRITE(regs->bios, bios_req & ~mask); } } static void bxt_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - bxt_ddi_phy_init(dev_priv, power_well->bxt.phy); + bxt_ddi_phy_init(dev_priv, power_well->desc->bxt.phy); } static void bxt_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - bxt_ddi_phy_uninit(dev_priv, power_well->bxt.phy); + bxt_ddi_phy_uninit(dev_priv, power_well->desc->bxt.phy); } static bool bxt_dpio_cmn_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - return bxt_ddi_phy_is_enabled(dev_priv, power_well->bxt.phy); + return bxt_ddi_phy_is_enabled(dev_priv, power_well->desc->bxt.phy); } static void bxt_verify_ddi_phy_power_wells(struct drm_i915_private *dev_priv) { struct i915_power_well *power_well; - power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_A); + power_well = lookup_power_well(dev_priv, BXT_DISP_PW_DPIO_CMN_A); if (power_well->count > 0) - bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy); + bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy); - power_well = lookup_power_well(dev_priv, BXT_DPIO_CMN_BC); + power_well = lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC); if (power_well->count > 0) - bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy); + bxt_ddi_phy_verify_state(dev_priv, power_well->desc->bxt.phy); if (IS_GEMINILAKE(dev_priv)) { - power_well = lookup_power_well(dev_priv, GLK_DPIO_CMN_C); + power_well = lookup_power_well(dev_priv, + GLK_DISP_PW_DPIO_CMN_C); if (power_well->count > 0) - bxt_ddi_phy_verify_state(dev_priv, power_well->bxt.phy); + bxt_ddi_phy_verify_state(dev_priv, + power_well->desc->bxt.phy); } } @@ -869,14 +873,14 @@ static void i830_pipes_power_well_sync_hw(struct drm_i915_private *dev_priv, static void vlv_set_power_well(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool enable) { - enum i915_power_well_id power_well_id = power_well->id; + int pw_idx = power_well->desc->vlv.idx; u32 mask; u32 state; u32 ctrl; - mask = PUNIT_PWRGT_MASK(power_well_id); - state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) : - PUNIT_PWRGT_PWR_GATE(power_well_id); + mask = PUNIT_PWRGT_MASK(pw_idx); + state = enable ? PUNIT_PWRGT_PWR_ON(pw_idx) : + PUNIT_PWRGT_PWR_GATE(pw_idx); mutex_lock(&dev_priv->pcu_lock); @@ -917,14 +921,14 @@ static void vlv_power_well_disable(struct drm_i915_private *dev_priv, static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - enum i915_power_well_id power_well_id = power_well->id; + int pw_idx = power_well->desc->vlv.idx; bool enabled = false; u32 mask; u32 state; u32 ctrl; - mask = PUNIT_PWRGT_MASK(power_well_id); - ctrl = PUNIT_PWRGT_PWR_ON(power_well_id); + mask = PUNIT_PWRGT_MASK(pw_idx); + ctrl = PUNIT_PWRGT_PWR_ON(pw_idx); mutex_lock(&dev_priv->pcu_lock); @@ -933,8 +937,8 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, * We only ever set the power-on and power-gate states, anything * else is unexpected. */ - WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) && - state != PUNIT_PWRGT_PWR_GATE(power_well_id)); + WARN_ON(state != PUNIT_PWRGT_PWR_ON(pw_idx) && + state != PUNIT_PWRGT_PWR_GATE(pw_idx)); if (state == ctrl) enabled = true; @@ -1045,8 +1049,6 @@ static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv) static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DISP2D); - vlv_set_power_well(dev_priv, power_well, true); vlv_display_power_well_init(dev_priv); @@ -1055,8 +1057,6 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DISP2D); - vlv_display_power_well_deinit(dev_priv); vlv_set_power_well(dev_priv, power_well, false); @@ -1065,8 +1065,6 @@ static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv, static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC); - /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -1091,8 +1089,6 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, { enum pipe pipe; - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC); - for_each_pipe(dev_priv, pipe) assert_pll_disabled(dev_priv, pipe); @@ -1104,32 +1100,14 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, #define POWER_DOMAIN_MASK (GENMASK_ULL(POWER_DOMAIN_NUM - 1, 0)) -static struct i915_power_well * -lookup_power_well(struct drm_i915_private *dev_priv, - enum i915_power_well_id power_well_id) -{ - struct i915_power_domains *power_domains = &dev_priv->power_domains; - int i; - - for (i = 0; i < power_domains->power_well_count; i++) { - struct i915_power_well *power_well; - - power_well = &power_domains->power_wells[i]; - if (power_well->id == power_well_id) - return power_well; - } - - return NULL; -} - #define BITS_SET(val, bits) (((val) & (bits)) == (bits)) static void assert_chv_phy_status(struct drm_i915_private *dev_priv) { struct i915_power_well *cmn_bc = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC); + lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC); struct i915_power_well *cmn_d = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); + lookup_power_well(dev_priv, CHV_DISP_PW_DPIO_CMN_D); u32 phy_control = dev_priv->chv_phy_control; u32 phy_status = 0; u32 phy_status_mask = 0xffffffff; @@ -1154,7 +1132,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0) | PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1)); - if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { + if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) { phy_status |= PHY_POWERGOOD(DPIO_PHY0); /* this assumes override is only used to enable lanes */ @@ -1195,7 +1173,7 @@ static void assert_chv_phy_status(struct drm_i915_private *dev_priv) phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1); } - if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { + if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) { phy_status |= PHY_POWERGOOD(DPIO_PHY1); /* this assumes override is only used to enable lanes */ @@ -1239,10 +1217,10 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, enum pipe pipe; uint32_t tmp; - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC && - power_well->id != PUNIT_POWER_WELL_DPIO_CMN_D); + WARN_ON_ONCE(power_well->desc->id != VLV_DISP_PW_DPIO_CMN_BC && + power_well->desc->id != CHV_DISP_PW_DPIO_CMN_D); - if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) { + if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) { pipe = PIPE_A; phy = DPIO_PHY0; } else { @@ -1270,7 +1248,7 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, DPIO_SUS_CLK_CONFIG_GATE_CLKREQ; vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp); - if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) { + if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) { tmp = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW6_CH1); tmp |= DPIO_DYNPWRDOWNEN_CH1; vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW6_CH1, tmp); @@ -1301,10 +1279,10 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, { enum dpio_phy phy; - WARN_ON_ONCE(power_well->id != PUNIT_POWER_WELL_DPIO_CMN_BC && - power_well->id != PUNIT_POWER_WELL_DPIO_CMN_D); + WARN_ON_ONCE(power_well->desc->id != VLV_DISP_PW_DPIO_CMN_BC && + power_well->desc->id != CHV_DISP_PW_DPIO_CMN_D); - if (power_well->id == PUNIT_POWER_WELL_DPIO_CMN_BC) { + if (power_well->desc->id == VLV_DISP_PW_DPIO_CMN_BC) { phy = DPIO_PHY0; assert_pll_disabled(dev_priv, PIPE_A); assert_pll_disabled(dev_priv, PIPE_B); @@ -1516,8 +1494,6 @@ out: static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->id != CHV_DISP_PW_PIPE_A); - chv_set_pipe_power_well(dev_priv, power_well, true); vlv_display_power_well_init(dev_priv); @@ -1526,8 +1502,6 @@ static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->id != CHV_DISP_PW_PIPE_A); - vlv_display_power_well_deinit(dev_priv); chv_set_pipe_power_well(dev_priv, power_well, false); @@ -2022,6 +1996,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, BIT_ULL(POWER_DOMAIN_PORT_DDI_F_IO)) #define ICL_AUX_A_IO_POWER_DOMAINS ( \ + BIT_ULL(POWER_DOMAIN_AUX_IO_A) | \ BIT_ULL(POWER_DOMAIN_AUX_A)) #define ICL_AUX_B_IO_POWER_DOMAINS ( \ BIT_ULL(POWER_DOMAIN_AUX_B)) @@ -2063,13 +2038,13 @@ static const struct i915_power_well_ops chv_dpio_cmn_power_well_ops = { .is_enabled = vlv_power_well_enabled, }; -static struct i915_power_well i9xx_always_on_power_well[] = { +static const struct i915_power_well_desc i9xx_always_on_power_well[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, }; @@ -2080,19 +2055,19 @@ static const struct i915_power_well_ops i830_pipes_power_well_ops = { .is_enabled = i830_pipes_power_well_enabled, }; -static struct i915_power_well i830_power_wells[] = { +static const struct i915_power_well_desc i830_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "pipes", .domains = I830_PIPES_POWER_DOMAINS, .ops = &i830_pipes_power_well_ops, - .id = I830_DISP_PW_PIPES, + .id = DISP_PW_ID_NONE, }, }; @@ -2117,13 +2092,20 @@ static const struct i915_power_well_ops bxt_dpio_cmn_power_well_ops = { .is_enabled = bxt_dpio_cmn_power_well_enabled, }; -static struct i915_power_well hsw_power_wells[] = { +static const struct i915_power_well_regs hsw_power_well_regs = { + .bios = HSW_PWR_WELL_CTL1, + .driver = HSW_PWR_WELL_CTL2, + .kvmr = HSW_PWR_WELL_CTL3, + .debug = HSW_PWR_WELL_CTL4, +}; + +static const struct i915_power_well_desc hsw_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "display", @@ -2131,18 +2113,20 @@ static struct i915_power_well hsw_power_wells[] = { .ops = &hsw_power_well_ops, .id = HSW_DISP_PW_GLOBAL, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = HSW_PW_CTL_IDX_GLOBAL, .hsw.has_vga = true, }, }, }; -static struct i915_power_well bdw_power_wells[] = { +static const struct i915_power_well_desc bdw_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "display", @@ -2150,6 +2134,8 @@ static struct i915_power_well bdw_power_wells[] = { .ops = &hsw_power_well_ops, .id = HSW_DISP_PW_GLOBAL, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = HSW_PW_CTL_IDX_GLOBAL, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, }, @@ -2177,19 +2163,22 @@ static const struct i915_power_well_ops vlv_dpio_power_well_ops = { .is_enabled = vlv_power_well_enabled, }; -static struct i915_power_well vlv_power_wells[] = { +static const struct i915_power_well_desc vlv_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "display", .domains = VLV_DISPLAY_POWER_DOMAINS, - .id = PUNIT_POWER_WELL_DISP2D, .ops = &vlv_display_power_well_ops, + .id = VLV_DISP_PW_DISP2D, + { + .vlv.idx = PUNIT_PWGT_IDX_DISP2D, + }, }, { .name = "dpio-tx-b-01", @@ -2198,7 +2187,10 @@ static struct i915_power_well vlv_power_wells[] = { VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, .ops = &vlv_dpio_power_well_ops, - .id = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01, + .id = DISP_PW_ID_NONE, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_B_LANES_01, + }, }, { .name = "dpio-tx-b-23", @@ -2207,7 +2199,10 @@ static struct i915_power_well vlv_power_wells[] = { VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, .ops = &vlv_dpio_power_well_ops, - .id = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23, + .id = DISP_PW_ID_NONE, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_B_LANES_23, + }, }, { .name = "dpio-tx-c-01", @@ -2216,7 +2211,10 @@ static struct i915_power_well vlv_power_wells[] = { VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, .ops = &vlv_dpio_power_well_ops, - .id = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01, + .id = DISP_PW_ID_NONE, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_C_LANES_01, + }, }, { .name = "dpio-tx-c-23", @@ -2225,23 +2223,29 @@ static struct i915_power_well vlv_power_wells[] = { VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS | VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS, .ops = &vlv_dpio_power_well_ops, - .id = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23, + .id = DISP_PW_ID_NONE, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_TX_C_LANES_23, + }, }, { .name = "dpio-common", .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS, - .id = PUNIT_POWER_WELL_DPIO_CMN_BC, .ops = &vlv_dpio_cmn_power_well_ops, + .id = VLV_DISP_PW_DPIO_CMN_BC, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_BC, + }, }, }; -static struct i915_power_well chv_power_wells[] = { +static const struct i915_power_well_desc chv_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "display", @@ -2251,20 +2255,26 @@ static struct i915_power_well chv_power_wells[] = { * required for any pipe to work. */ .domains = CHV_DISPLAY_POWER_DOMAINS, - .id = CHV_DISP_PW_PIPE_A, .ops = &chv_pipe_power_well_ops, + .id = DISP_PW_ID_NONE, }, { .name = "dpio-common-bc", .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS, - .id = PUNIT_POWER_WELL_DPIO_CMN_BC, .ops = &chv_dpio_cmn_power_well_ops, + .id = VLV_DISP_PW_DPIO_CMN_BC, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_BC, + }, }, { .name = "dpio-common-d", .domains = CHV_DPIO_CMN_D_POWER_DOMAINS, - .id = PUNIT_POWER_WELL_DPIO_CMN_D, .ops = &chv_dpio_cmn_power_well_ops, + .id = CHV_DISP_PW_DPIO_CMN_D, + { + .vlv.idx = PUNIT_PWGT_IDX_DPIO_CMN_D, + }, }, }; @@ -2275,18 +2285,18 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, bool ret; power_well = lookup_power_well(dev_priv, power_well_id); - ret = power_well->ops->is_enabled(dev_priv, power_well); + ret = power_well->desc->ops->is_enabled(dev_priv, power_well); return ret; } -static struct i915_power_well skl_power_wells[] = { +static const struct i915_power_well_desc skl_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "power well 1", @@ -2295,6 +2305,8 @@ static struct i915_power_well skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, }, @@ -2304,12 +2316,16 @@ static struct i915_power_well skl_power_wells[] = { .domains = 0, .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_MISC_IO, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_MISC_IO, + }, }, { .name = "DC off", .domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS, .ops = &gen9_dc_off_power_well_ops, - .id = SKL_DISP_PW_DC_OFF, + .id = DISP_PW_ID_NONE, }, { .name = "power well 2", @@ -2317,6 +2333,8 @@ static struct i915_power_well skl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, .hsw.has_fuses = true, @@ -2326,35 +2344,51 @@ static struct i915_power_well skl_power_wells[] = { .name = "DDI A/E IO power well", .domains = SKL_DISPLAY_DDI_IO_A_E_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_A_E, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_A_E, + }, }, { .name = "DDI B IO power well", .domains = SKL_DISPLAY_DDI_IO_B_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_B, + }, }, { .name = "DDI C IO power well", .domains = SKL_DISPLAY_DDI_IO_C_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_C, + }, }, { .name = "DDI D IO power well", .domains = SKL_DISPLAY_DDI_IO_D_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_D, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_D, + }, }, }; -static struct i915_power_well bxt_power_wells[] = { +static const struct i915_power_well_desc bxt_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "power well 1", @@ -2362,6 +2396,8 @@ static struct i915_power_well bxt_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, }, @@ -2369,7 +2405,7 @@ static struct i915_power_well bxt_power_wells[] = { .name = "DC off", .domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS, .ops = &gen9_dc_off_power_well_ops, - .id = SKL_DISP_PW_DC_OFF, + .id = DISP_PW_ID_NONE, }, { .name = "power well 2", @@ -2377,6 +2413,8 @@ static struct i915_power_well bxt_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, .hsw.has_fuses = true, @@ -2386,7 +2424,7 @@ static struct i915_power_well bxt_power_wells[] = { .name = "dpio-common-a", .domains = BXT_DPIO_CMN_A_POWER_DOMAINS, .ops = &bxt_dpio_cmn_power_well_ops, - .id = BXT_DPIO_CMN_A, + .id = BXT_DISP_PW_DPIO_CMN_A, { .bxt.phy = DPIO_PHY1, }, @@ -2395,20 +2433,20 @@ static struct i915_power_well bxt_power_wells[] = { .name = "dpio-common-bc", .domains = BXT_DPIO_CMN_BC_POWER_DOMAINS, .ops = &bxt_dpio_cmn_power_well_ops, - .id = BXT_DPIO_CMN_BC, + .id = VLV_DISP_PW_DPIO_CMN_BC, { .bxt.phy = DPIO_PHY0, }, }, }; -static struct i915_power_well glk_power_wells[] = { +static const struct i915_power_well_desc glk_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "power well 1", @@ -2417,6 +2455,8 @@ static struct i915_power_well glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, }, @@ -2424,7 +2464,7 @@ static struct i915_power_well glk_power_wells[] = { .name = "DC off", .domains = GLK_DISPLAY_DC_OFF_POWER_DOMAINS, .ops = &gen9_dc_off_power_well_ops, - .id = SKL_DISP_PW_DC_OFF, + .id = DISP_PW_ID_NONE, }, { .name = "power well 2", @@ -2432,6 +2472,8 @@ static struct i915_power_well glk_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, .hsw.has_fuses = true, @@ -2441,7 +2483,7 @@ static struct i915_power_well glk_power_wells[] = { .name = "dpio-common-a", .domains = GLK_DPIO_CMN_A_POWER_DOMAINS, .ops = &bxt_dpio_cmn_power_well_ops, - .id = BXT_DPIO_CMN_A, + .id = BXT_DISP_PW_DPIO_CMN_A, { .bxt.phy = DPIO_PHY1, }, @@ -2450,7 +2492,7 @@ static struct i915_power_well glk_power_wells[] = { .name = "dpio-common-b", .domains = GLK_DPIO_CMN_B_POWER_DOMAINS, .ops = &bxt_dpio_cmn_power_well_ops, - .id = BXT_DPIO_CMN_BC, + .id = VLV_DISP_PW_DPIO_CMN_BC, { .bxt.phy = DPIO_PHY0, }, @@ -2459,7 +2501,7 @@ static struct i915_power_well glk_power_wells[] = { .name = "dpio-common-c", .domains = GLK_DPIO_CMN_C_POWER_DOMAINS, .ops = &bxt_dpio_cmn_power_well_ops, - .id = GLK_DPIO_CMN_C, + .id = GLK_DISP_PW_DPIO_CMN_C, { .bxt.phy = DPIO_PHY2, }, @@ -2468,47 +2510,71 @@ static struct i915_power_well glk_power_wells[] = { .name = "AUX A", .domains = GLK_DISPLAY_AUX_A_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = GLK_DISP_PW_AUX_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_A, + }, }, { .name = "AUX B", .domains = GLK_DISPLAY_AUX_B_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = GLK_DISP_PW_AUX_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_B, + }, }, { .name = "AUX C", .domains = GLK_DISPLAY_AUX_C_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = GLK_DISP_PW_AUX_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_C, + }, }, { .name = "DDI A IO power well", .domains = GLK_DISPLAY_DDI_IO_A_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = GLK_DISP_PW_DDI_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_DDI_A, + }, }, { .name = "DDI B IO power well", .domains = GLK_DISPLAY_DDI_IO_B_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_B, + }, }, { .name = "DDI C IO power well", .domains = GLK_DISPLAY_DDI_IO_C_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_C, + }, }, }; -static struct i915_power_well cnl_power_wells[] = { +static const struct i915_power_well_desc cnl_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "power well 1", @@ -2517,6 +2583,8 @@ static struct i915_power_well cnl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_1, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_1, .hsw.has_fuses = true, }, }, @@ -2524,31 +2592,47 @@ static struct i915_power_well cnl_power_wells[] = { .name = "AUX A", .domains = CNL_DISPLAY_AUX_A_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_AUX_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_A, + }, }, { .name = "AUX B", .domains = CNL_DISPLAY_AUX_B_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_AUX_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_B, + }, }, { .name = "AUX C", .domains = CNL_DISPLAY_AUX_C_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_AUX_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_AUX_C, + }, }, { .name = "AUX D", .domains = CNL_DISPLAY_AUX_D_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_AUX_D, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = CNL_PW_CTL_IDX_AUX_D, + }, }, { .name = "DC off", .domains = CNL_DISPLAY_DC_OFF_POWER_DOMAINS, .ops = &gen9_dc_off_power_well_ops, - .id = SKL_DISP_PW_DC_OFF, + .id = DISP_PW_ID_NONE, }, { .name = "power well 2", @@ -2556,6 +2640,8 @@ static struct i915_power_well cnl_power_wells[] = { .ops = &hsw_power_well_ops, .id = SKL_DISP_PW_2, { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_PW_2, .hsw.irq_pipe_mask = BIT(PIPE_B) | BIT(PIPE_C), .hsw.has_vga = true, .hsw.has_fuses = true, @@ -2565,37 +2651,61 @@ static struct i915_power_well cnl_power_wells[] = { .name = "DDI A IO power well", .domains = CNL_DISPLAY_DDI_A_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_DDI_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = GLK_PW_CTL_IDX_DDI_A, + }, }, { .name = "DDI B IO power well", .domains = CNL_DISPLAY_DDI_B_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_B, + }, }, { .name = "DDI C IO power well", .domains = CNL_DISPLAY_DDI_C_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_C, + }, }, { .name = "DDI D IO power well", .domains = CNL_DISPLAY_DDI_D_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = SKL_DISP_PW_DDI_D, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = SKL_PW_CTL_IDX_DDI_D, + }, }, { .name = "DDI F IO power well", .domains = CNL_DISPLAY_DDI_F_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_DDI_F, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = CNL_PW_CTL_IDX_DDI_F, + }, }, { .name = "AUX F", .domains = CNL_DISPLAY_AUX_F_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = CNL_DISP_PW_AUX_F, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = CNL_PW_CTL_IDX_AUX_F, + }, }, }; @@ -2606,147 +2716,239 @@ static const struct i915_power_well_ops icl_combo_phy_aux_power_well_ops = { .is_enabled = hsw_power_well_enabled, }; -static struct i915_power_well icl_power_wells[] = { +static const struct i915_power_well_regs icl_aux_power_well_regs = { + .bios = ICL_PWR_WELL_CTL_AUX1, + .driver = ICL_PWR_WELL_CTL_AUX2, + .debug = ICL_PWR_WELL_CTL_AUX4, +}; + +static const struct i915_power_well_regs icl_ddi_power_well_regs = { + .bios = ICL_PWR_WELL_CTL_DDI1, + .driver = ICL_PWR_WELL_CTL_DDI2, + .debug = ICL_PWR_WELL_CTL_DDI4, +}; + +static const struct i915_power_well_desc icl_power_wells[] = { { .name = "always-on", .always_on = 1, .domains = POWER_DOMAIN_MASK, .ops = &i9xx_always_on_power_well_ops, - .id = I915_DISP_PW_ALWAYS_ON, + .id = DISP_PW_ID_NONE, }, { .name = "power well 1", /* Handled by the DMC firmware */ .domains = 0, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_1, - .hsw.has_fuses = true, + .id = SKL_DISP_PW_1, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_1, + .hsw.has_fuses = true, + }, }, { .name = "power well 2", .domains = ICL_PW_2_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_2, - .hsw.has_fuses = true, + .id = SKL_DISP_PW_2, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_2, + .hsw.has_fuses = true, + }, }, { .name = "DC off", .domains = ICL_DISPLAY_DC_OFF_POWER_DOMAINS, .ops = &gen9_dc_off_power_well_ops, - .id = SKL_DISP_PW_DC_OFF, + .id = DISP_PW_ID_NONE, }, { .name = "power well 3", .domains = ICL_PW_3_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_3, - .hsw.irq_pipe_mask = BIT(PIPE_B), - .hsw.has_vga = true, - .hsw.has_fuses = true, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_3, + .hsw.irq_pipe_mask = BIT(PIPE_B), + .hsw.has_vga = true, + .hsw.has_fuses = true, + }, }, { .name = "DDI A IO", .domains = ICL_DDI_IO_A_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_A, + }, }, { .name = "DDI B IO", .domains = ICL_DDI_IO_B_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_B, + }, }, { .name = "DDI C IO", .domains = ICL_DDI_IO_C_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_C, + }, }, { .name = "DDI D IO", .domains = ICL_DDI_IO_D_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_D, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_D, + }, }, { .name = "DDI E IO", .domains = ICL_DDI_IO_E_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_E, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_E, + }, }, { .name = "DDI F IO", .domains = ICL_DDI_IO_F_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_DDI_F, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_ddi_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_DDI_F, + }, }, { .name = "AUX A", .domains = ICL_AUX_A_IO_POWER_DOMAINS, .ops = &icl_combo_phy_aux_power_well_ops, - .id = ICL_DISP_PW_AUX_A, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_A, + }, }, { .name = "AUX B", .domains = ICL_AUX_B_IO_POWER_DOMAINS, .ops = &icl_combo_phy_aux_power_well_ops, - .id = ICL_DISP_PW_AUX_B, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_B, + }, }, { .name = "AUX C", .domains = ICL_AUX_C_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_C, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_C, + }, }, { .name = "AUX D", .domains = ICL_AUX_D_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_D, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_D, + }, }, { .name = "AUX E", .domains = ICL_AUX_E_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_E, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_E, + }, }, { .name = "AUX F", .domains = ICL_AUX_F_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_F, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_F, + }, }, { .name = "AUX TBT1", .domains = ICL_AUX_TBT1_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_TBT1, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT1, + }, }, { .name = "AUX TBT2", .domains = ICL_AUX_TBT2_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_TBT2, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT2, + }, }, { .name = "AUX TBT3", .domains = ICL_AUX_TBT3_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_TBT3, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT3, + }, }, { .name = "AUX TBT4", .domains = ICL_AUX_TBT4_IO_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_AUX_TBT4, + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &icl_aux_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_AUX_TBT4, + }, }, { .name = "power well 4", .domains = ICL_PW_4_POWER_DOMAINS, .ops = &hsw_power_well_ops, - .id = ICL_DISP_PW_4, - .hsw.has_fuses = true, - .hsw.irq_pipe_mask = BIT(PIPE_C), + .id = DISP_PW_ID_NONE, + { + .hsw.regs = &hsw_power_well_regs, + .hsw.idx = ICL_PW_CTL_IDX_PW_4, + .hsw.has_fuses = true, + .hsw.irq_pipe_mask = BIT(PIPE_C), + }, }, }; @@ -2809,26 +3011,41 @@ static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv, return mask; } -static void assert_power_well_ids_unique(struct drm_i915_private *dev_priv) +static int +__set_power_wells(struct i915_power_domains *power_domains, + const struct i915_power_well_desc *power_well_descs, + int power_well_count) { - struct i915_power_domains *power_domains = &dev_priv->power_domains; - u64 power_well_ids; + u64 power_well_ids = 0; int i; - power_well_ids = 0; - for (i = 0; i < power_domains->power_well_count; i++) { - enum i915_power_well_id id = power_domains->power_wells[i].id; + power_domains->power_well_count = power_well_count; + power_domains->power_wells = + kcalloc(power_well_count, + sizeof(*power_domains->power_wells), + GFP_KERNEL); + if (!power_domains->power_wells) + return -ENOMEM; + + for (i = 0; i < power_well_count; i++) { + enum i915_power_well_id id = power_well_descs[i].id; + + power_domains->power_wells[i].desc = &power_well_descs[i]; + + if (id == DISP_PW_ID_NONE) + continue; WARN_ON(id >= sizeof(power_well_ids) * 8); WARN_ON(power_well_ids & BIT_ULL(id)); power_well_ids |= BIT_ULL(id); } + + return 0; } -#define set_power_wells(power_domains, __power_wells) ({ \ - (power_domains)->power_wells = (__power_wells); \ - (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \ -}) +#define set_power_wells(power_domains, __power_well_descs) \ + __set_power_wells(power_domains, __power_well_descs, \ + ARRAY_SIZE(__power_well_descs)) /** * intel_power_domains_init - initializes the power domain structures @@ -2840,6 +3057,7 @@ static void assert_power_well_ids_unique(struct drm_i915_private *dev_priv) int intel_power_domains_init(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; + int err; i915_modparams.disable_power_well = sanitize_disable_power_well_option(dev_priv, @@ -2856,15 +3074,15 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) * the disabling order is reversed. */ if (IS_ICELAKE(dev_priv)) { - set_power_wells(power_domains, icl_power_wells); + err = set_power_wells(power_domains, icl_power_wells); } else if (IS_HASWELL(dev_priv)) { - set_power_wells(power_domains, hsw_power_wells); + err = set_power_wells(power_domains, hsw_power_wells); } else if (IS_BROADWELL(dev_priv)) { - set_power_wells(power_domains, bdw_power_wells); + err = set_power_wells(power_domains, bdw_power_wells); } else if (IS_GEN9_BC(dev_priv)) { - set_power_wells(power_domains, skl_power_wells); + err = set_power_wells(power_domains, skl_power_wells); } else if (IS_CANNONLAKE(dev_priv)) { - set_power_wells(power_domains, cnl_power_wells); + err = set_power_wells(power_domains, cnl_power_wells); /* * DDI and Aux IO are getting enabled for all ports @@ -2876,57 +3094,31 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) power_domains->power_well_count -= 2; } else if (IS_BROXTON(dev_priv)) { - set_power_wells(power_domains, bxt_power_wells); + err = set_power_wells(power_domains, bxt_power_wells); } else if (IS_GEMINILAKE(dev_priv)) { - set_power_wells(power_domains, glk_power_wells); + err = set_power_wells(power_domains, glk_power_wells); } else if (IS_CHERRYVIEW(dev_priv)) { - set_power_wells(power_domains, chv_power_wells); + err = set_power_wells(power_domains, chv_power_wells); } else if (IS_VALLEYVIEW(dev_priv)) { - set_power_wells(power_domains, vlv_power_wells); + err = set_power_wells(power_domains, vlv_power_wells); } else if (IS_I830(dev_priv)) { - set_power_wells(power_domains, i830_power_wells); + err = set_power_wells(power_domains, i830_power_wells); } else { - set_power_wells(power_domains, i9xx_always_on_power_well); + err = set_power_wells(power_domains, i9xx_always_on_power_well); } - assert_power_well_ids_unique(dev_priv); - - return 0; + return err; } /** - * intel_power_domains_fini - finalizes the power domain structures + * intel_power_domains_cleanup - clean up power domains resources * @dev_priv: i915 device instance * - * Finalizes the power domain structures for @dev_priv depending upon the - * supported platform. This function also disables runtime pm and ensures that - * the device stays powered up so that the driver can be reloaded. + * Release any resources acquired by intel_power_domains_init() */ -void intel_power_domains_fini(struct drm_i915_private *dev_priv) +void intel_power_domains_cleanup(struct drm_i915_private *dev_priv) { - struct device *kdev = &dev_priv->drm.pdev->dev; - - /* - * The i915.ko module is still not prepared to be loaded when - * the power well is not enabled, so just enable it in case - * we're going to unload/reload. - * The following also reacquires the RPM reference the core passed - * to the driver during loading, which is dropped in - * intel_runtime_pm_enable(). We have to hand back the control of the - * device to the core with this reference held. - */ - intel_display_set_init_power(dev_priv, true); - - /* Remove the refcount we took to keep power well support disabled. */ - if (!i915_modparams.disable_power_well) - intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); - - /* - * Remove the refcount we took in intel_runtime_pm_enable() in case - * the platform doesn't support runtime PM. - */ - if (!HAS_RUNTIME_PM(dev_priv)) - pm_runtime_put(kdev); + kfree(dev_priv->power_domains.power_wells); } static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) @@ -2936,9 +3128,9 @@ static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) mutex_lock(&power_domains->lock); for_each_power_well(dev_priv, power_well) { - power_well->ops->sync_hw(dev_priv, power_well); - power_well->hw_enabled = power_well->ops->is_enabled(dev_priv, - power_well); + power_well->desc->ops->sync_hw(dev_priv, power_well); + power_well->hw_enabled = + power_well->desc->ops->is_enabled(dev_priv, power_well); } mutex_unlock(&power_domains->lock); } @@ -3360,7 +3552,7 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, * The AUX IO power wells will be enabled on demand. */ mutex_lock(&power_domains->lock); - well = lookup_power_well(dev_priv, ICL_DISP_PW_1); + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); intel_power_well_enable(dev_priv, well); mutex_unlock(&power_domains->lock); @@ -3373,9 +3565,8 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, /* 7. Setup MBUS. */ icl_mbus_init(dev_priv); - /* 8. CHICKEN_DCPR_1 */ - I915_WRITE(GEN8_CHICKEN_DCPR_1, I915_READ(GEN8_CHICKEN_DCPR_1) | - CNL_DDI_CLOCK_REG_ACCESS_ON); + if (resume && dev_priv->csr.dmc_payload) + intel_csr_load_program(dev_priv); } static void icl_display_core_uninit(struct drm_i915_private *dev_priv) @@ -3401,7 +3592,7 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv) * disabled at this point. */ mutex_lock(&power_domains->lock); - well = lookup_power_well(dev_priv, ICL_DISP_PW_1); + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); intel_power_well_disable(dev_priv, well); mutex_unlock(&power_domains->lock); @@ -3416,9 +3607,9 @@ static void icl_display_core_uninit(struct drm_i915_private *dev_priv) static void chv_phy_control_init(struct drm_i915_private *dev_priv) { struct i915_power_well *cmn_bc = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC); + lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC); struct i915_power_well *cmn_d = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); + lookup_power_well(dev_priv, CHV_DISP_PW_DPIO_CMN_D); /* * DISPLAY_PHY_CONTROL can get corrupted if read. As a @@ -3441,7 +3632,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) * override and set the lane powerdown bits accding to the * current lane status. */ - if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) { + if (cmn_bc->desc->ops->is_enabled(dev_priv, cmn_bc)) { uint32_t status = I915_READ(DPLL(PIPE_A)); unsigned int mask; @@ -3472,7 +3663,7 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) dev_priv->chv_phy_assert[DPIO_PHY0] = true; } - if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) { + if (cmn_d->desc->ops->is_enabled(dev_priv, cmn_d)) { uint32_t status = I915_READ(DPIO_PHY_STATUS); unsigned int mask; @@ -3503,20 +3694,20 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv) static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) { struct i915_power_well *cmn = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC); + lookup_power_well(dev_priv, VLV_DISP_PW_DPIO_CMN_BC); struct i915_power_well *disp2d = - lookup_power_well(dev_priv, PUNIT_POWER_WELL_DISP2D); + lookup_power_well(dev_priv, VLV_DISP_PW_DISP2D); /* If the display might be already active skip this */ - if (cmn->ops->is_enabled(dev_priv, cmn) && - disp2d->ops->is_enabled(dev_priv, disp2d) && + if (cmn->desc->ops->is_enabled(dev_priv, cmn) && + disp2d->desc->ops->is_enabled(dev_priv, disp2d) && I915_READ(DPIO_CTL) & DPIO_CMNRST) return; DRM_DEBUG_KMS("toggling display PHY side reset\n"); /* cmnlane needs DPLL registers */ - disp2d->ops->enable(dev_priv, disp2d); + disp2d->desc->ops->enable(dev_priv, disp2d); /* * From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx: @@ -3525,9 +3716,11 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) * Simply ungating isn't enough to reset the PHY enough to get * ports and lanes running. */ - cmn->ops->disable(dev_priv, cmn); + cmn->desc->ops->disable(dev_priv, cmn); } +static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv); + /** * intel_power_domains_init_hw - initialize hardware power domain state * @dev_priv: i915 device instance @@ -3535,9 +3728,14 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) * * This function initializes the hardware power domain state and enables all * power wells belonging to the INIT power domain. Power wells in other - * domains (and not in the INIT domain) are referenced or disabled during the - * modeset state HW readout. After that the reference count of each power well - * must match its HW enabled state, see intel_power_domains_verify_state(). + * domains (and not in the INIT domain) are referenced or disabled by + * intel_modeset_readout_hw_state(). After that the reference count of each + * power well must match its HW enabled state, see + * intel_power_domains_verify_state(). + * + * It will return with power domains disabled (to be enabled later by + * intel_power_domains_enable()) and must be paired with + * intel_power_domains_fini_hw(). */ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume) { @@ -3563,30 +3761,117 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume) mutex_unlock(&power_domains->lock); } - /* For now, we need the power well to be always enabled. */ - intel_display_set_init_power(dev_priv, true); + /* + * Keep all power wells enabled for any dependent HW access during + * initialization and to make sure we keep BIOS enabled display HW + * resources powered until display HW readout is complete. We drop + * this reference in intel_power_domains_enable(). + */ + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); /* Disable power support if the user asked so. */ if (!i915_modparams.disable_power_well) intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); intel_power_domains_sync_hw(dev_priv); + power_domains->initializing = false; } /** + * intel_power_domains_fini_hw - deinitialize hw power domain state + * @dev_priv: i915 device instance + * + * De-initializes the display power domain HW state. It also ensures that the + * device stays powered up so that the driver can be reloaded. + * + * It must be called with power domains already disabled (after a call to + * intel_power_domains_disable()) and must be paired with + * intel_power_domains_init_hw(). + */ +void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv) +{ + /* Keep the power well enabled, but cancel its rpm wakeref. */ + intel_runtime_pm_put(dev_priv); + + /* Remove the refcount we took to keep power well support disabled. */ + if (!i915_modparams.disable_power_well) + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + + intel_power_domains_verify_state(dev_priv); +} + +/** + * intel_power_domains_enable - enable toggling of display power wells + * @dev_priv: i915 device instance + * + * Enable the ondemand enabling/disabling of the display power wells. Note that + * power wells not belonging to POWER_DOMAIN_INIT are allowed to be toggled + * only at specific points of the display modeset sequence, thus they are not + * affected by the intel_power_domains_enable()/disable() calls. The purpose + * of these function is to keep the rest of power wells enabled until the end + * of display HW readout (which will acquire the power references reflecting + * the current HW state). + */ +void intel_power_domains_enable(struct drm_i915_private *dev_priv) +{ + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + + intel_power_domains_verify_state(dev_priv); +} + +/** + * intel_power_domains_disable - disable toggling of display power wells + * @dev_priv: i915 device instance + * + * Disable the ondemand enabling/disabling of the display power wells. See + * intel_power_domains_enable() for which power wells this call controls. + */ +void intel_power_domains_disable(struct drm_i915_private *dev_priv) +{ + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + + intel_power_domains_verify_state(dev_priv); +} + +/** * intel_power_domains_suspend - suspend power domain state * @dev_priv: i915 device instance + * @suspend_mode: specifies the target suspend state (idle, mem, hibernation) * * This function prepares the hardware power domain state before entering - * system suspend. It must be paired with intel_power_domains_init_hw(). + * system suspend. + * + * It must be called with power domains already disabled (after a call to + * intel_power_domains_disable()) and paired with intel_power_domains_resume(). */ -void intel_power_domains_suspend(struct drm_i915_private *dev_priv) +void intel_power_domains_suspend(struct drm_i915_private *dev_priv, + enum i915_drm_suspend_mode suspend_mode) { + struct i915_power_domains *power_domains = &dev_priv->power_domains; + + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + + /* + * In case of suspend-to-idle (aka S0ix) on a DMC platform without DC9 + * support don't manually deinit the power domains. This also means the + * CSR/DMC firmware will stay active, it will power down any HW + * resources as required and also enable deeper system power states + * that would be blocked if the firmware was inactive. + */ + if (!(dev_priv->csr.allowed_dc_mask & DC_STATE_EN_DC9) && + suspend_mode == I915_DRM_SUSPEND_IDLE && + dev_priv->csr.dmc_payload != NULL) { + intel_power_domains_verify_state(dev_priv); + return; + } + /* * Even if power well support was disabled we still want to disable - * power wells while we are system suspended. + * power wells if power domains must be deinitialized for suspend. */ - if (!i915_modparams.disable_power_well) + if (!i915_modparams.disable_power_well) { intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + intel_power_domains_verify_state(dev_priv); + } if (IS_ICELAKE(dev_priv)) icl_display_core_uninit(dev_priv); @@ -3596,8 +3881,36 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv) skl_display_core_uninit(dev_priv); else if (IS_GEN9_LP(dev_priv)) bxt_display_core_uninit(dev_priv); + + power_domains->display_core_suspended = true; } +/** + * intel_power_domains_resume - resume power domain state + * @dev_priv: i915 device instance + * + * This function resume the hardware power domain state during system resume. + * + * It will return with power domain support disabled (to be enabled later by + * intel_power_domains_enable()) and must be paired with + * intel_power_domains_suspend(). + */ +void intel_power_domains_resume(struct drm_i915_private *dev_priv) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + + if (power_domains->display_core_suspended) { + intel_power_domains_init_hw(dev_priv, true); + power_domains->display_core_suspended = false; + } else { + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + } + + intel_power_domains_verify_state(dev_priv); +} + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) + static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; @@ -3607,9 +3920,9 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv) enum intel_display_power_domain domain; DRM_DEBUG_DRIVER("%-25s %d\n", - power_well->name, power_well->count); + power_well->desc->name, power_well->count); - for_each_power_domain(domain, power_well->domains) + for_each_power_domain(domain, power_well->desc->domains) DRM_DEBUG_DRIVER(" %-23s %d\n", intel_display_power_domain_str(domain), power_domains->domain_use_count[domain]); @@ -3626,7 +3939,7 @@ static void intel_power_domains_dump_info(struct drm_i915_private *dev_priv) * acquiring reference counts for any power wells in use and disabling the * ones left on by BIOS but not required by any active output. */ -void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) +static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; @@ -3645,22 +3958,25 @@ void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) * and PW1 power wells) are under FW control, so ignore them, * since their state can change asynchronously. */ - if (!power_well->domains) + if (!power_well->desc->domains) continue; - enabled = power_well->ops->is_enabled(dev_priv, power_well); - if ((power_well->count || power_well->always_on) != enabled) + enabled = power_well->desc->ops->is_enabled(dev_priv, + power_well); + if ((power_well->count || power_well->desc->always_on) != + enabled) DRM_ERROR("power well %s state mismatch (refcount %d/enabled %d)", - power_well->name, power_well->count, enabled); + power_well->desc->name, + power_well->count, enabled); domains_count = 0; - for_each_power_domain(domain, power_well->domains) + for_each_power_domain(domain, power_well->desc->domains) domains_count += power_domains->domain_use_count[domain]; if (power_well->count != domains_count) { DRM_ERROR("power well %s refcount/domain refcount mismatch " "(refcount %d/domains refcount %d)\n", - power_well->name, power_well->count, + power_well->desc->name, power_well->count, domains_count); dump_domain_info = true; } @@ -3678,6 +3994,14 @@ void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) mutex_unlock(&power_domains->lock); } +#else + +static void intel_power_domains_verify_state(struct drm_i915_private *dev_priv) +{ +} + +#endif + /** * intel_runtime_pm_get - grab a runtime pm reference * @dev_priv: i915 device instance @@ -3791,14 +4115,24 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv) * This function enables runtime pm at the end of the driver load sequence. * * Note that this function does currently not enable runtime pm for the - * subordinate display power domains. That is only done on the first modeset - * using intel_display_set_init_power(). + * subordinate display power domains. That is done by + * intel_power_domains_enable(). */ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) { struct pci_dev *pdev = dev_priv->drm.pdev; struct device *kdev = &pdev->dev; + /* + * Disable the system suspend direct complete optimization, which can + * leave the device suspended skipping the driver's suspend handlers + * if the device was already runtime suspended. This is needed due to + * the difference in our runtime and system suspend sequence and + * becaue the HDA driver may require us to enable the audio power + * domain during system suspend. + */ + dev_pm_set_driver_flags(kdev, DPM_FLAG_NEVER_SKIP); + pm_runtime_set_autosuspend_delay(kdev, 10000); /* 10s */ pm_runtime_mark_last_busy(kdev); @@ -3825,3 +4159,18 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv) */ pm_runtime_put_autosuspend(kdev); } + +void intel_runtime_pm_disable(struct drm_i915_private *dev_priv) +{ + struct pci_dev *pdev = dev_priv->drm.pdev; + struct device *kdev = &pdev->dev; + + /* Transfer rpm ownership back to core */ + WARN(pm_runtime_get_sync(&dev_priv->drm.pdev->dev) < 0, + "Failed to pass rpm ownership back to core\n"); + + pm_runtime_dont_use_autosuspend(kdev); + + if (!HAS_RUNTIME_PM(dev_priv)) + pm_runtime_put(kdev); +} diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 812fe7b06f87..701372e512a8 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -99,32 +99,13 @@ struct intel_sdvo { */ uint16_t hotplug_active; - /** - * This is set if we're going to treat the device as TV-out. - * - * While we have these nice friendly flags for output types that ought - * to decide this for us, the S-Video output on our HDMI+S-Video card - * shows up as RGB1 (VGA). - */ - bool is_tv; - enum port port; - /** - * This is set if we treat the device as HDMI, instead of DVI. - */ - bool is_hdmi; bool has_hdmi_monitor; bool has_hdmi_audio; bool rgb_quant_range_selectable; /** - * This is set if we detect output of sdvo device as LVDS and - * have a valid fixed mode to use with the panel. - */ - bool is_lvds; - - /** * This is sdvo fixed pannel mode pointer */ struct drm_display_mode *sdvo_lvds_fixed_mode; @@ -172,6 +153,11 @@ struct intel_sdvo_connector { /* this is to get the range of margin.*/ u32 max_hscan, max_vscan; + + /** + * This is set if we treat the device as HDMI, instead of DVI. + */ + bool is_hdmi; }; struct intel_sdvo_connector_state { @@ -766,6 +752,7 @@ static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, uint16_t clock, uint16_t width, uint16_t height) @@ -778,7 +765,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, args.height = height; args.interlace = 0; - if (intel_sdvo->is_lvds && + if (IS_LVDS(intel_sdvo_connector) && (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width || intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height)) args.scaled = 1; @@ -1067,6 +1054,7 @@ intel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo, */ static bool intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *intel_sdvo_connector, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -1077,6 +1065,7 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo, return false; if (!intel_sdvo_create_preferred_input_timing(intel_sdvo, + intel_sdvo_connector, mode->clock / 10, mode->hdisplay, mode->vdisplay)) @@ -1127,6 +1116,8 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, struct intel_sdvo *intel_sdvo = to_sdvo(encoder); struct intel_sdvo_connector_state *intel_sdvo_state = to_intel_sdvo_connector_state(conn_state); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(conn_state->connector); struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; struct drm_display_mode *mode = &pipe_config->base.mode; @@ -1142,20 +1133,22 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, * timings, even though this isn't really the right place in * the sequence to do it. Oh well. */ - if (intel_sdvo->is_tv) { + if (IS_TV(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode)) return false; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, + intel_sdvo_connector, mode, adjusted_mode); pipe_config->sdvo_tv_clock = true; - } else if (intel_sdvo->is_lvds) { + } else if (IS_LVDS(intel_sdvo_connector)) { if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, intel_sdvo->sdvo_lvds_fixed_mode)) return false; (void) intel_sdvo_get_preferred_input_mode(intel_sdvo, + intel_sdvo_connector, mode, adjusted_mode); } @@ -1194,11 +1187,11 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder, } /* Clock computation needs to happen after pixel multiplier. */ - if (intel_sdvo->is_tv) + if (IS_TV(intel_sdvo_connector)) i9xx_adjust_sdvo_tv_clock(pipe_config); /* Set user selected PAR to incoming mode's member */ - if (intel_sdvo->is_hdmi) + if (intel_sdvo_connector->is_hdmi) adjusted_mode->picture_aspect_ratio = conn_state->picture_aspect_ratio; return true; @@ -1275,6 +1268,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; const struct intel_sdvo_connector_state *sdvo_state = to_intel_sdvo_connector_state(conn_state); + const struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(conn_state->connector); const struct drm_display_mode *mode = &crtc_state->base.mode; struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder); u32 sdvox; @@ -1304,7 +1299,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, return; /* lvds has a special fixed output timing. */ - if (intel_sdvo->is_lvds) + if (IS_LVDS(intel_sdvo_connector)) intel_sdvo_get_dtd_from_mode(&output_dtd, intel_sdvo->sdvo_lvds_fixed_mode); else @@ -1325,13 +1320,13 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder, } else intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); - if (intel_sdvo->is_tv && + if (IS_TV(intel_sdvo_connector) && !intel_sdvo_set_tv_format(intel_sdvo, conn_state)) return; intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); - if (intel_sdvo->is_tv || intel_sdvo->is_lvds) + if (IS_TV(intel_sdvo_connector) || IS_LVDS(intel_sdvo_connector)) input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags; if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd)) DRM_INFO("Setting input timings on %s failed\n", @@ -1630,6 +1625,8 @@ intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(connector); int max_dotclk = to_i915(connector->dev)->max_dotclk_freq; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -1644,7 +1641,7 @@ intel_sdvo_mode_valid(struct drm_connector *connector, if (mode->clock > max_dotclk) return MODE_CLOCK_HIGH; - if (intel_sdvo->is_lvds) { + if (IS_LVDS(intel_sdvo_connector)) { if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay) return MODE_PANEL; @@ -1759,6 +1756,8 @@ static enum drm_connector_status intel_sdvo_tmds_sink_detect(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct intel_sdvo_connector *intel_sdvo_connector = + to_intel_sdvo_connector(connector); enum drm_connector_status status; struct edid *edid; @@ -1797,7 +1796,7 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) /* DDC bus is shared, match EDID to connector type */ if (edid->input & DRM_EDID_INPUT_DIGITAL) { status = connector_status_connected; - if (intel_sdvo->is_hdmi) { + if (intel_sdvo_connector->is_hdmi) { intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); intel_sdvo->rgb_quant_range_selectable = @@ -1875,17 +1874,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; } - /* May update encoder flag for like clock for SDVO TV, etc.*/ - if (ret == connector_status_connected) { - intel_sdvo->is_tv = false; - intel_sdvo->is_lvds = false; - - if (response & SDVO_TV_MASK) - intel_sdvo->is_tv = true; - if (response & SDVO_LVDS_MASK) - intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL; - } - return ret; } @@ -2054,16 +2042,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * arranged in priority order. */ intel_ddc_get_modes(connector, &intel_sdvo->ddc); - - list_for_each_entry(newmode, &connector->probed_modes, head) { - if (newmode->type & DRM_MODE_TYPE_PREFERRED) { - intel_sdvo->sdvo_lvds_fixed_mode = - drm_mode_duplicate(connector->dev, newmode); - - intel_sdvo->is_lvds = true; - break; - } - } } static int intel_sdvo_get_modes(struct drm_connector *connector) @@ -2555,7 +2533,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) if (INTEL_GEN(dev_priv) >= 4 && intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; - intel_sdvo->is_hdmi = true; + intel_sdvo_connector->is_hdmi = true; } if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { @@ -2563,7 +2541,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) return false; } - if (intel_sdvo->is_hdmi) + if (intel_sdvo_connector->is_hdmi) intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); return true; @@ -2591,8 +2569,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->controlled_output |= type; intel_sdvo_connector->output_flag = type; - intel_sdvo->is_tv = true; - if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) { kfree(intel_sdvo_connector); return false; @@ -2654,6 +2630,7 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) struct drm_connector *connector; struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; + struct drm_display_mode *mode; DRM_DEBUG_KMS("initialising LVDS device %d\n", device); @@ -2682,6 +2659,19 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; + intel_sdvo_get_lvds_modes(connector); + + list_for_each_entry(mode, &connector->probed_modes, head) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + intel_sdvo->sdvo_lvds_fixed_mode = + drm_mode_duplicate(connector->dev, mode); + break; + } + } + + if (!intel_sdvo->sdvo_lvds_fixed_mode) + goto err; + return true; err: @@ -2692,9 +2682,6 @@ err: static bool intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags) { - intel_sdvo->is_tv = false; - intel_sdvo->is_lvds = false; - /* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/ if (flags & SDVO_OUTPUT_TMDS0) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f7026e887fa9..5fd2f7bf3927 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -83,6 +83,7 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI); DEFINE_WAIT(wait); + u32 psr_status; vblank_start = adjusted_mode->crtc_vblank_start; if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) @@ -104,8 +105,9 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state) * VBL interrupts will start the PSR exit and prevent a PSR * re-entry as well. */ - if (intel_psr_wait_for_idle(new_crtc_state)) - DRM_ERROR("PSR idle timed out, atomic update may fail\n"); + if (intel_psr_wait_for_idle(new_crtc_state, &psr_status)) + DRM_ERROR("PSR idle timed out 0x%x, atomic update may fail\n", + psr_status); local_irq_disable(); @@ -228,6 +230,78 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) #endif } +int intel_plane_check_stride(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; + u32 stride, max_stride; + + /* FIXME other color planes? */ + stride = plane_state->color_plane[0].stride; + max_stride = plane->max_stride(plane, fb->format->format, + fb->modifier, rotation); + + if (stride > max_stride) { + DRM_DEBUG_KMS("[FB:%d] stride (%d) exceeds [PLANE:%d:%s] max stride (%d)\n", + fb->base.id, stride, + plane->base.base.id, plane->base.name, max_stride); + return -EINVAL; + } + + return 0; +} + +int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->base.fb; + struct drm_rect *src = &plane_state->base.src; + u32 src_x, src_y, src_w, src_h; + + /* + * Hardware doesn't handle subpixel coordinates. + * Adjust to (macro)pixel boundary, but be careful not to + * increase the source viewport size, because that could + * push the downscaling factor out of bounds. + */ + src_x = src->x1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_y = src->y1 >> 16; + src_h = drm_rect_height(src) >> 16; + + src->x1 = src_x << 16; + src->x2 = (src_x + src_w) << 16; + src->y1 = src_y << 16; + src->y2 = (src_y + src_h) << 16; + + if (fb->format->is_yuv && + fb->format->format != DRM_FORMAT_NV12 && + (src_x & 1 || src_w & 1)) { + DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n", + src_x, src_w); + return -EINVAL; + } + + return 0; +} + +unsigned int +skl_plane_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + int cpp = drm_format_plane_cpp(pixel_format, 0); + + /* + * "The stride in bytes must not exceed the + * of the size of 8K pixels and 32K bytes." + */ + if (drm_rotation_90_or_270(rotation)) + return min(8192, 32768 / cpp); + else + return min(8192 * cpp, 32768); +} + void skl_update_plane(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -239,16 +313,15 @@ skl_update_plane(struct intel_plane *plane, enum pipe pipe = plane->pipe; u32 plane_ctl = plane_state->ctl; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; - u32 surf_addr = plane_state->main.offset; - unsigned int rotation = plane_state->base.rotation; - u32 stride = skl_plane_stride(fb, 0, rotation); - u32 aux_stride = skl_plane_stride(fb, 1, rotation); + u32 surf_addr = plane_state->color_plane[0].offset; + u32 stride = skl_plane_stride(plane_state, 0); + u32 aux_stride = skl_plane_stride(plane_state, 1); int crtc_x = plane_state->base.dst.x1; int crtc_y = plane_state->base.dst.y1; uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); - uint32_t x = plane_state->main.x; - uint32_t y = plane_state->main.y; + uint32_t x = plane_state->color_plane[0].x; + uint32_t y = plane_state->color_plane[0].y; uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; unsigned long irqflags; @@ -275,9 +348,10 @@ skl_update_plane(struct intel_plane *plane, I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride); I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w); I915_WRITE_FW(PLANE_AUX_DIST(pipe, plane_id), - (plane_state->aux.offset - surf_addr) | aux_stride); + (plane_state->color_plane[1].offset - surf_addr) | aux_stride); I915_WRITE_FW(PLANE_AUX_OFFSET(pipe, plane_id), - (plane_state->aux.y << 16) | plane_state->aux.x); + (plane_state->color_plane[1].y << 16) | + plane_state->color_plane[1].x); /* program plane scaler */ if (plane_state->scaler_id >= 0) { @@ -543,15 +617,15 @@ vlv_update_plane(struct intel_plane *plane, enum pipe pipe = plane->pipe; enum plane_id plane_id = plane->id; u32 sprctl = plane_state->ctl; - u32 sprsurf_offset = plane_state->main.offset; + u32 sprsurf_offset = plane_state->color_plane[0].offset; u32 linear_offset; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->base.dst.x1; int crtc_y = plane_state->base.dst.y1; uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); - uint32_t x = plane_state->main.x; - uint32_t y = plane_state->main.y; + uint32_t x = plane_state->color_plane[0].x; + uint32_t y = plane_state->color_plane[0].y; unsigned long irqflags; /* Sizes are 0 based */ @@ -572,7 +646,8 @@ vlv_update_plane(struct intel_plane *plane, I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value); I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask); } - I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]); + I915_WRITE_FW(SPSTRIDE(pipe, plane_id), + plane_state->color_plane[0].stride); I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x); if (fb->modifier == I915_FORMAT_MOD_X_TILED) @@ -702,15 +777,15 @@ ivb_update_plane(struct intel_plane *plane, const struct drm_framebuffer *fb = plane_state->base.fb; enum pipe pipe = plane->pipe; u32 sprctl = plane_state->ctl, sprscale = 0; - u32 sprsurf_offset = plane_state->main.offset; + u32 sprsurf_offset = plane_state->color_plane[0].offset; u32 linear_offset; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->base.dst.x1; int crtc_y = plane_state->base.dst.y1; uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); - uint32_t x = plane_state->main.x; - uint32_t y = plane_state->main.y; + uint32_t x = plane_state->color_plane[0].x; + uint32_t y = plane_state->color_plane[0].y; uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; unsigned long irqflags; @@ -734,7 +809,7 @@ ivb_update_plane(struct intel_plane *plane, I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask); } - I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]); + I915_WRITE_FW(SPRSTRIDE(pipe), plane_state->color_plane[0].stride); I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x); /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET @@ -747,7 +822,7 @@ ivb_update_plane(struct intel_plane *plane, I915_WRITE_FW(SPRLINOFF(pipe), linear_offset); I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); - if (plane->can_scale) + if (IS_IVYBRIDGE(dev_priv)) I915_WRITE_FW(SPRSCALE(pipe), sprscale); I915_WRITE_FW(SPRCTL(pipe), sprctl); I915_WRITE_FW(SPRSURF(pipe), @@ -768,7 +843,7 @@ ivb_disable_plane(struct intel_plane *plane, struct intel_crtc *crtc) I915_WRITE_FW(SPRCTL(pipe), 0); /* Can't leave the scaler enabled... */ - if (plane->can_scale) + if (IS_IVYBRIDGE(dev_priv)) I915_WRITE_FW(SPRSCALE(pipe), 0); I915_WRITE_FW(SPRSURF(pipe), 0); @@ -798,6 +873,14 @@ ivb_plane_get_hw_state(struct intel_plane *plane, return ret; } +static unsigned int +g4x_sprite_max_stride(struct intel_plane *plane, + u32 pixel_format, u64 modifier, + unsigned int rotation) +{ + return 16384; +} + static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { @@ -866,15 +949,15 @@ g4x_update_plane(struct intel_plane *plane, const struct drm_framebuffer *fb = plane_state->base.fb; enum pipe pipe = plane->pipe; u32 dvscntr = plane_state->ctl, dvsscale = 0; - u32 dvssurf_offset = plane_state->main.offset; + u32 dvssurf_offset = plane_state->color_plane[0].offset; u32 linear_offset; const struct drm_intel_sprite_colorkey *key = &plane_state->ckey; int crtc_x = plane_state->base.dst.x1; int crtc_y = plane_state->base.dst.y1; uint32_t crtc_w = drm_rect_width(&plane_state->base.dst); uint32_t crtc_h = drm_rect_height(&plane_state->base.dst); - uint32_t x = plane_state->main.x; - uint32_t y = plane_state->main.y; + uint32_t x = plane_state->color_plane[0].x; + uint32_t y = plane_state->color_plane[0].y; uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16; uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16; unsigned long irqflags; @@ -898,7 +981,7 @@ g4x_update_plane(struct intel_plane *plane, I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask); } - I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]); + I915_WRITE_FW(DVSSTRIDE(pipe), plane_state->color_plane[0].stride); I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x); if (fb->modifier == I915_FORMAT_MOD_X_TILED) @@ -957,144 +1040,309 @@ g4x_plane_get_hw_state(struct intel_plane *plane, } static int -intel_check_sprite_plane(struct intel_plane *plane, - struct intel_crtc_state *crtc_state, - struct intel_plane_state *state) +g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_framebuffer *fb = state->base.fb; - int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384; - int max_scale, min_scale; - bool can_scale; - int ret; - uint32_t pixel_format = 0; - - if (!fb) { - state->base.visible = false; + const struct drm_framebuffer *fb = plane_state->base.fb; + const struct drm_rect *src = &plane_state->base.src; + const struct drm_rect *dst = &plane_state->base.dst; + int src_x, src_y, src_w, src_h, crtc_w, crtc_h; + const struct drm_display_mode *adjusted_mode = + &crtc_state->base.adjusted_mode; + unsigned int cpp = fb->format->cpp[0]; + unsigned int width_bytes; + int min_width, min_height; + + crtc_w = drm_rect_width(dst); + crtc_h = drm_rect_height(dst); + + src_x = src->x1 >> 16; + src_y = src->y1 >> 16; + src_w = drm_rect_width(src) >> 16; + src_h = drm_rect_height(src) >> 16; + + if (src_w == crtc_w && src_h == crtc_h) return 0; + + min_width = 3; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) { + if (src_h & 1) { + DRM_DEBUG_KMS("Source height must be even with interlaced modes\n"); + return -EINVAL; + } + min_height = 6; + } else { + min_height = 3; } - /* Don't modify another pipe's plane */ - if (plane->pipe != crtc->pipe) { - DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n"); + width_bytes = ((src_x * cpp) & 63) + src_w * cpp; + + if (src_w < min_width || src_h < min_height || + src_w > 2048 || src_h > 2048) { + DRM_DEBUG_KMS("Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n", + src_w, src_h, min_width, min_height, 2048, 2048); return -EINVAL; } - /* FIXME check all gen limits */ - if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > max_stride) { - DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n"); + if (width_bytes > 4096) { + DRM_DEBUG_KMS("Fetch width (%d) exceeds hardware max with scaling (%u)\n", + width_bytes, 4096); return -EINVAL; } - /* setup can_scale, min_scale, max_scale */ - if (INTEL_GEN(dev_priv) >= 9) { - if (state->base.fb) - pixel_format = state->base.fb->format->format; - /* use scaler when colorkey is not required */ - if (!state->ckey.flags) { - can_scale = 1; - min_scale = 1; - max_scale = - skl_max_scale(crtc, crtc_state, pixel_format); - } else { - can_scale = 0; - min_scale = DRM_PLANE_HELPER_NO_SCALING; - max_scale = DRM_PLANE_HELPER_NO_SCALING; - } + if (width_bytes > 4096 || fb->pitches[0] > 4096) { + DRM_DEBUG_KMS("Stride (%u) exceeds hardware max with scaling (%u)\n", + fb->pitches[0], 4096); + return -EINVAL; + } + + return 0; +} + +static int +g4x_sprite_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + int max_scale, min_scale; + int ret; + + if (INTEL_GEN(dev_priv) < 7) { + min_scale = 1; + max_scale = 16 << 16; + } else if (IS_IVYBRIDGE(dev_priv)) { + min_scale = 1; + max_scale = 2 << 16; } else { - can_scale = plane->can_scale; - max_scale = plane->max_downscale << 16; - min_scale = plane->can_scale ? 1 : (1 << 16); + min_scale = DRM_PLANE_HELPER_NO_SCALING; + max_scale = DRM_PLANE_HELPER_NO_SCALING; } - ret = drm_atomic_helper_check_plane_state(&state->base, + ret = drm_atomic_helper_check_plane_state(&plane_state->base, &crtc_state->base, min_scale, max_scale, true, true); if (ret) return ret; - if (state->base.visible) { - struct drm_rect *src = &state->base.src; - struct drm_rect *dst = &state->base.dst; - unsigned int crtc_w = drm_rect_width(dst); - unsigned int crtc_h = drm_rect_height(dst); - uint32_t src_x, src_y, src_w, src_h; + if (!plane_state->base.visible) + return 0; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = g4x_sprite_check_scaling(crtc_state, plane_state); + if (ret) + return ret; + + ret = i9xx_check_plane_surface(plane_state); + if (ret) + return ret; + + if (INTEL_GEN(dev_priv) >= 7) + plane_state->ctl = ivb_sprite_ctl(crtc_state, plane_state); + else + plane_state->ctl = g4x_sprite_ctl(crtc_state, plane_state); + + return 0; +} + +int chv_plane_check_rotation(const struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + unsigned int rotation = plane_state->base.rotation; + + /* CHV ignores the mirror bit when the rotate bit is set :( */ + if (IS_CHERRYVIEW(dev_priv) && + rotation & DRM_MODE_ROTATE_180 && + rotation & DRM_MODE_REFLECT_X) { + DRM_DEBUG_KMS("Cannot rotate and reflect at the same time\n"); + return -EINVAL; + } + + return 0; +} + +static int +vlv_sprite_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + int ret; + + ret = chv_plane_check_rotation(plane_state); + if (ret) + return ret; + + ret = drm_atomic_helper_check_plane_state(&plane_state->base, + &crtc_state->base, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); + if (ret) + return ret; + + if (!plane_state->base.visible) + return 0; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = i9xx_check_plane_surface(plane_state); + if (ret) + return ret; + + plane_state->ctl = vlv_sprite_ctl(crtc_state, plane_state); + + return 0; +} + +static int skl_plane_check_fb(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + const struct drm_framebuffer *fb = plane_state->base.fb; + unsigned int rotation = plane_state->base.rotation; + struct drm_format_name_buf format_name; + + if (!fb) + return 0; + + if (rotation & ~(DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180) && + is_ccs_modifier(fb->modifier)) { + DRM_DEBUG_KMS("RC support only with 0/180 degree rotation (%x)\n", + rotation); + return -EINVAL; + } + + if (rotation & DRM_MODE_REFLECT_X && + fb->modifier == DRM_FORMAT_MOD_LINEAR) { + DRM_DEBUG_KMS("horizontal flip is not supported with linear surface formats\n"); + return -EINVAL; + } + + if (drm_rotation_90_or_270(rotation)) { + if (fb->modifier != I915_FORMAT_MOD_Y_TILED && + fb->modifier != I915_FORMAT_MOD_Yf_TILED) { + DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n"); + return -EINVAL; + } /* - * Hardware doesn't handle subpixel coordinates. - * Adjust to (macro)pixel boundary, but be careful not to - * increase the source viewport size, because that could - * push the downscaling factor out of bounds. + * 90/270 is not allowed with RGB64 16:16:16:16, + * RGB 16-bit 5:6:5, and Indexed 8-bit. + * TBD: Add RGB64 case once its added in supported format list. */ - src_x = src->x1 >> 16; - src_w = drm_rect_width(src) >> 16; - src_y = src->y1 >> 16; - src_h = drm_rect_height(src) >> 16; - - src->x1 = src_x << 16; - src->x2 = (src_x + src_w) << 16; - src->y1 = src_y << 16; - src->y2 = (src_y + src_h) << 16; - - if (fb->format->is_yuv && - fb->format->format != DRM_FORMAT_NV12 && - (src_x % 2 || src_w % 2)) { - DRM_DEBUG_KMS("src x/w (%u, %u) must be a multiple of 2 for YUV planes\n", - src_x, src_w); + switch (fb->format->format) { + case DRM_FORMAT_C8: + case DRM_FORMAT_RGB565: + DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", + drm_get_format_name(fb->format->format, + &format_name)); return -EINVAL; + default: + break; } + } - /* Check size restrictions when scaling */ - if (src_w != crtc_w || src_h != crtc_h) { - unsigned int width_bytes; - int cpp = fb->format->cpp[0]; + /* Y-tiling is not supported in IF-ID Interlace mode */ + if (crtc_state->base.enable && + crtc_state->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE && + (fb->modifier == I915_FORMAT_MOD_Y_TILED || + fb->modifier == I915_FORMAT_MOD_Yf_TILED || + fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS || + fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS)) { + DRM_DEBUG_KMS("Y/Yf tiling not supported in IF-ID mode\n"); + return -EINVAL; + } - WARN_ON(!can_scale); + return 0; +} - width_bytes = ((src_x * cpp) & 63) + src_w * cpp; +static int skl_plane_check_dst_coordinates(const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *dev_priv = + to_i915(plane_state->base.plane->dev); + int crtc_x = plane_state->base.dst.x1; + int crtc_w = drm_rect_width(&plane_state->base.dst); + int pipe_src_w = crtc_state->pipe_src_w; - /* FIXME interlacing min height is 6 */ - if (INTEL_GEN(dev_priv) < 9 && ( - src_w < 3 || src_h < 3 || - src_w > 2048 || src_h > 2048 || - crtc_w < 3 || crtc_h < 3 || - width_bytes > 4096 || fb->pitches[0] > 4096)) { - DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); - return -EINVAL; - } - } + /* + * Display WA #1175: cnl,glk + * Planes other than the cursor may cause FIFO underflow and display + * corruption if starting less than 4 pixels from the right edge of + * the screen. + * Besides the above WA fix the similar problem, where planes other + * than the cursor ending less than 4 pixels from the left edge of the + * screen may cause FIFO underflow and display corruption. + */ + if ((IS_GEMINILAKE(dev_priv) || IS_CANNONLAKE(dev_priv)) && + (crtc_x + crtc_w < 4 || crtc_x > pipe_src_w - 4)) { + DRM_DEBUG_KMS("requested plane X %s position %d invalid (valid range %d-%d)\n", + crtc_x + crtc_w < 4 ? "end" : "start", + crtc_x + crtc_w < 4 ? crtc_x + crtc_w : crtc_x, + 4, pipe_src_w - 4); + return -ERANGE; } - if (INTEL_GEN(dev_priv) >= 9) { - ret = skl_check_plane_surface(crtc_state, state); - if (ret) - return ret; + return 0; +} - state->ctl = skl_plane_ctl(crtc_state, state); - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - ret = i9xx_check_plane_surface(state); - if (ret) - return ret; +int skl_plane_check(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) +{ + struct intel_plane *plane = to_intel_plane(plane_state->base.plane); + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + int max_scale, min_scale; + int ret; - state->ctl = vlv_sprite_ctl(crtc_state, state); - } else if (INTEL_GEN(dev_priv) >= 7) { - ret = i9xx_check_plane_surface(state); - if (ret) - return ret; + ret = skl_plane_check_fb(crtc_state, plane_state); + if (ret) + return ret; - state->ctl = ivb_sprite_ctl(crtc_state, state); - } else { - ret = i9xx_check_plane_surface(state); - if (ret) - return ret; + /* use scaler when colorkey is not required */ + if (!plane_state->ckey.flags) { + const struct drm_framebuffer *fb = plane_state->base.fb; - state->ctl = g4x_sprite_ctl(crtc_state, state); + min_scale = 1; + max_scale = skl_max_scale(crtc_state, + fb ? fb->format->format : 0); + } else { + min_scale = DRM_PLANE_HELPER_NO_SCALING; + max_scale = DRM_PLANE_HELPER_NO_SCALING; } + ret = drm_atomic_helper_check_plane_state(&plane_state->base, + &crtc_state->base, + min_scale, max_scale, + true, true); + if (ret) + return ret; + + if (!plane_state->base.visible) + return 0; + + ret = skl_plane_check_dst_coordinates(crtc_state, plane_state); + if (ret) + return ret; + + ret = intel_plane_check_src_coordinates(plane_state); + if (ret) + return ret; + + ret = skl_check_plane_surface(plane_state); + if (ret) + return ret; + + plane_state->ctl = skl_plane_ctl(crtc_state, plane_state); + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) - state->color_ctl = glk_plane_color_ctl(crtc_state, state); + plane_state->color_ctl = glk_plane_color_ctl(crtc_state, + plane_state); return 0; } @@ -1407,8 +1655,7 @@ static bool skl_plane_format_mod_supported(struct drm_plane *_plane, case DRM_FORMAT_XBGR8888: case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ABGR8888: - if (modifier == I915_FORMAT_MOD_Yf_TILED_CCS || - modifier == I915_FORMAT_MOD_Y_TILED_CCS) + if (is_ccs_modifier(modifier)) return true; /* fall through */ case DRM_FORMAT_RGB565: @@ -1522,15 +1769,16 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, intel_plane->base.state = &state->base; if (INTEL_GEN(dev_priv) >= 9) { - intel_plane->can_scale = true; state->scaler_id = -1; intel_plane->has_ccs = skl_plane_has_ccs(dev_priv, pipe, PLANE_SPRITE0 + plane); + intel_plane->max_stride = skl_plane_max_stride; intel_plane->update_plane = skl_update_plane; intel_plane->disable_plane = skl_disable_plane; intel_plane->get_hw_state = skl_plane_get_hw_state; + intel_plane->check_plane = skl_plane_check; if (skl_plane_has_planar(dev_priv, pipe, PLANE_SPRITE0 + plane)) { @@ -1548,12 +1796,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_funcs = &skl_plane_funcs; } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - intel_plane->can_scale = false; - intel_plane->max_downscale = 1; - + intel_plane->max_stride = i9xx_plane_max_stride; intel_plane->update_plane = vlv_update_plane; intel_plane->disable_plane = vlv_disable_plane; intel_plane->get_hw_state = vlv_plane_get_hw_state; + intel_plane->check_plane = vlv_sprite_check; plane_formats = vlv_plane_formats; num_plane_formats = ARRAY_SIZE(vlv_plane_formats); @@ -1561,17 +1808,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_funcs = &vlv_sprite_funcs; } else if (INTEL_GEN(dev_priv) >= 7) { - if (IS_IVYBRIDGE(dev_priv)) { - intel_plane->can_scale = true; - intel_plane->max_downscale = 2; - } else { - intel_plane->can_scale = false; - intel_plane->max_downscale = 1; - } - + intel_plane->max_stride = g4x_sprite_max_stride; intel_plane->update_plane = ivb_update_plane; intel_plane->disable_plane = ivb_disable_plane; intel_plane->get_hw_state = ivb_plane_get_hw_state; + intel_plane->check_plane = g4x_sprite_check; plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); @@ -1579,12 +1820,11 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, plane_funcs = &snb_sprite_funcs; } else { - intel_plane->can_scale = true; - intel_plane->max_downscale = 16; - + intel_plane->max_stride = g4x_sprite_max_stride; intel_plane->update_plane = g4x_update_plane; intel_plane->disable_plane = g4x_disable_plane; intel_plane->get_hw_state = g4x_plane_get_hw_state; + intel_plane->check_plane = g4x_sprite_check; modifiers = i9xx_plane_format_modifiers; if (IS_GEN6(dev_priv)) { @@ -1617,7 +1857,6 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, intel_plane->i9xx_plane = plane; intel_plane->id = PLANE_SPRITE0 + plane; intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, intel_plane->id); - intel_plane->check_plane = intel_check_sprite_plane; possible_crtcs = (1 << pipe); diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index 7c95697e1a35..b1b3e81b6e24 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -401,6 +401,10 @@ int intel_uc_init_hw(struct drm_i915_private *i915) ret = intel_guc_submission_enable(guc); if (ret) goto err_communication; + } else if (INTEL_GEN(i915) < 11) { + ret = intel_guc_sample_forcewake(guc); + if (ret) + goto err_communication; } dev_info(i915->drm.dev, "GuC firmware version %u.%u\n", diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c index 6e8e0b546743..fd496416087c 100644 --- a/drivers/gpu/drm/i915/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/intel_uc_fw.c @@ -222,7 +222,7 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, goto fail; } - ggtt_pin_bias = to_i915(uc_fw->obj->base.dev)->guc.ggtt_pin_bias; + ggtt_pin_bias = to_i915(uc_fw->obj->base.dev)->ggtt.pin_bias; vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0, PIN_OFFSET_BIAS | ggtt_pin_bias); if (IS_ERR(vma)) { diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 50b39aa4ffb8..3ad302c66254 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -283,14 +283,24 @@ fw_domains_reset(struct drm_i915_private *i915, fw_domain_reset(i915, d); } +static inline u32 gt_thread_status(struct drm_i915_private *dev_priv) +{ + u32 val; + + val = __raw_i915_read32(dev_priv, GEN6_GT_THREAD_STATUS_REG); + val &= GEN6_GT_THREAD_STATUS_CORE_MASK; + + return val; +} + static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) { - /* w/a for a sporadic read returning 0 by waiting for the GT + /* + * w/a for a sporadic read returning 0 by waiting for the GT * thread to wake up. */ - if (wait_for_atomic_us((__raw_i915_read32(dev_priv, GEN6_GT_THREAD_STATUS_REG) & - GEN6_GT_THREAD_STATUS_CORE_MASK) == 0, 500)) - DRM_ERROR("GT thread status wait timed out\n"); + WARN_ONCE(wait_for_atomic_us(gt_thread_status(dev_priv) == 0, 5000), + "GT thread status wait timed out\n"); } static void fw_domains_get_with_thread_status(struct drm_i915_private *dev_priv, @@ -1729,7 +1739,7 @@ static void gen3_stop_engine(struct intel_engine_cs *engine) } static void i915_stop_engines(struct drm_i915_private *dev_priv, - unsigned engine_mask) + unsigned int engine_mask) { struct intel_engine_cs *engine; enum intel_engine_id id; @@ -1749,7 +1759,9 @@ static bool i915_in_reset(struct pci_dev *pdev) return gdrst & GRDOM_RESET_STATUS; } -static int i915_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) +static int i915_do_reset(struct drm_i915_private *dev_priv, + unsigned int engine_mask, + unsigned int retry) { struct pci_dev *pdev = dev_priv->drm.pdev; int err; @@ -1776,7 +1788,9 @@ static bool g4x_reset_complete(struct pci_dev *pdev) return (gdrst & GRDOM_RESET_ENABLE) == 0; } -static int g33_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) +static int g33_do_reset(struct drm_i915_private *dev_priv, + unsigned int engine_mask, + unsigned int retry) { struct pci_dev *pdev = dev_priv->drm.pdev; @@ -1784,7 +1798,9 @@ static int g33_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) return wait_for(g4x_reset_complete(pdev), 500); } -static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) +static int g4x_do_reset(struct drm_i915_private *dev_priv, + unsigned int engine_mask, + unsigned int retry) { struct pci_dev *pdev = dev_priv->drm.pdev; int ret; @@ -1821,7 +1837,8 @@ out: } static int ironlake_do_reset(struct drm_i915_private *dev_priv, - unsigned engine_mask) + unsigned int engine_mask, + unsigned int retry) { int ret; @@ -1877,6 +1894,7 @@ static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv, * gen6_reset_engines - reset individual engines * @dev_priv: i915 device * @engine_mask: mask of intel_ring_flag() engines or ALL_ENGINES for full reset + * @retry: the count of of previous attempts to reset. * * This function will reset the individual engines that are set in engine_mask. * If you provide ALL_ENGINES as mask, full global domain reset will be issued. @@ -1887,7 +1905,8 @@ static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv, * Returns 0 on success, nonzero on error. */ static int gen6_reset_engines(struct drm_i915_private *dev_priv, - unsigned engine_mask) + unsigned int engine_mask, + unsigned int retry) { struct intel_engine_cs *engine; const u32 hw_engine_mask[I915_NUM_ENGINES] = { @@ -1926,7 +1945,7 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv, * Returns 0 on success, nonzero on error. */ static int gen11_reset_engines(struct drm_i915_private *dev_priv, - unsigned engine_mask) + unsigned int engine_mask) { struct intel_engine_cs *engine; const u32 hw_engine_mask[I915_NUM_ENGINES] = { @@ -2066,7 +2085,7 @@ int __intel_wait_for_register(struct drm_i915_private *dev_priv, return ret; } -static int gen8_reset_engine_start(struct intel_engine_cs *engine) +static int gen8_engine_reset_prepare(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; int ret; @@ -2086,7 +2105,7 @@ static int gen8_reset_engine_start(struct intel_engine_cs *engine) return ret; } -static void gen8_reset_engine_cancel(struct intel_engine_cs *engine) +static void gen8_engine_reset_cancel(struct intel_engine_cs *engine) { struct drm_i915_private *dev_priv = engine->i915; @@ -2094,33 +2113,56 @@ static void gen8_reset_engine_cancel(struct intel_engine_cs *engine) _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET)); } +static int reset_engines(struct drm_i915_private *i915, + unsigned int engine_mask, + unsigned int retry) +{ + if (INTEL_GEN(i915) >= 11) + return gen11_reset_engines(i915, engine_mask); + else + return gen6_reset_engines(i915, engine_mask, retry); +} + static int gen8_reset_engines(struct drm_i915_private *dev_priv, - unsigned engine_mask) + unsigned int engine_mask, + unsigned int retry) { struct intel_engine_cs *engine; + const bool reset_non_ready = retry >= 1; unsigned int tmp; int ret; for_each_engine_masked(engine, dev_priv, engine_mask, tmp) { - if (gen8_reset_engine_start(engine)) { - ret = -EIO; - goto not_ready; - } + ret = gen8_engine_reset_prepare(engine); + if (ret && !reset_non_ready) + goto skip_reset; + + /* + * If this is not the first failed attempt to prepare, + * we decide to proceed anyway. + * + * By doing so we risk context corruption and with + * some gens (kbl), possible system hang if reset + * happens during active bb execution. + * + * We rather take context corruption instead of + * failed reset with a wedged driver/gpu. And + * active bb execution case should be covered by + * i915_stop_engines we have before the reset. + */ } - if (INTEL_GEN(dev_priv) >= 11) - ret = gen11_reset_engines(dev_priv, engine_mask); - else - ret = gen6_reset_engines(dev_priv, engine_mask); + ret = reset_engines(dev_priv, engine_mask, retry); -not_ready: +skip_reset: for_each_engine_masked(engine, dev_priv, engine_mask, tmp) - gen8_reset_engine_cancel(engine); + gen8_engine_reset_cancel(engine); return ret; } -typedef int (*reset_func)(struct drm_i915_private *, unsigned engine_mask); +typedef int (*reset_func)(struct drm_i915_private *, + unsigned int engine_mask, unsigned int retry); static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv) { @@ -2143,12 +2185,15 @@ static reset_func intel_get_gpu_reset(struct drm_i915_private *dev_priv) return NULL; } -int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) +int intel_gpu_reset(struct drm_i915_private *dev_priv, + const unsigned int engine_mask) { reset_func reset = intel_get_gpu_reset(dev_priv); - int retry; + unsigned int retry; int ret; + GEM_BUG_ON(!engine_mask); + /* * We want to perform per-engine reset from atomic context (e.g. * softirq), which imposes the constraint that we cannot sleep. @@ -2190,8 +2235,9 @@ int intel_gpu_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) ret = -ENODEV; if (reset) { - GEM_TRACE("engine_mask=%x\n", engine_mask); - ret = reset(dev_priv, engine_mask); + ret = reset(dev_priv, engine_mask, retry); + GEM_TRACE("engine_mask=%x, ret=%d, retry=%d\n", + engine_mask, ret, retry); } if (ret != -ETIMEDOUT || engine_mask != ALL_ENGINES) break; @@ -2237,20 +2283,28 @@ bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv) bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv) { - if (unlikely(i915_modparams.mmio_debug || - dev_priv->uncore.unclaimed_mmio_check <= 0)) - return false; + bool ret = false; + + spin_lock_irq(&dev_priv->uncore.lock); + + if (unlikely(dev_priv->uncore.unclaimed_mmio_check <= 0)) + goto out; if (unlikely(intel_uncore_unclaimed_mmio(dev_priv))) { - DRM_DEBUG("Unclaimed register detected, " - "enabling oneshot unclaimed register reporting. " - "Please use i915.mmio_debug=N for more information.\n"); - i915_modparams.mmio_debug++; + if (!i915_modparams.mmio_debug) { + DRM_DEBUG("Unclaimed register detected, " + "enabling oneshot unclaimed register reporting. " + "Please use i915.mmio_debug=N for more information.\n"); + i915_modparams.mmio_debug++; + } dev_priv->uncore.unclaimed_mmio_check--; - return true; + ret = true; } - return false; +out: + spin_unlock_irq(&dev_priv->uncore.lock); + + return ret; } static enum forcewake_domains diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 74bf76f3fddc..92cb82dd0c07 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -163,8 +163,14 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) u32 guc_wopcm_rsvd; int err; + if (!USES_GUC(dev_priv)) + return 0; + GEM_BUG_ON(!wopcm->size); + if (i915_inject_load_failure()) + return -E2BIG; + if (guc_fw_size >= wopcm->size) { DRM_ERROR("GuC FW (%uKiB) is too big to fit in WOPCM.", guc_fw_size / 1024); diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c index 7efb326badcd..8d03f64eabd7 100644 --- a/drivers/gpu/drm/i915/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c @@ -235,6 +235,8 @@ static int fake_get_huge_pages(struct drm_i915_gem_object *obj) sg = sg_next(sg); } while (1); + i915_sg_trim(st); + obj->mm.madv = I915_MADV_DONTNEED; __i915_gem_object_set_pages(obj, st, sg_page_sizes); @@ -906,7 +908,11 @@ gpu_write_dw(struct i915_vma *vma, u64 offset, u32 val) if (IS_ERR(obj)) return ERR_CAST(obj); - cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); + err = i915_gem_object_set_to_wc_domain(obj, true); + if (err) + goto err; + + cmd = i915_gem_object_pin_map(obj, I915_MAP_WC); if (IS_ERR(cmd)) { err = PTR_ERR(cmd); goto err; @@ -936,13 +942,10 @@ gpu_write_dw(struct i915_vma *vma, u64 offset, u32 val) } *cmd = MI_BATCH_BUFFER_END; + i915_gem_chipset_flush(i915); i915_gem_object_unpin_map(obj); - err = i915_gem_object_set_to_gtt_domain(obj, false); - if (err) - goto err; - batch = i915_vma_instance(obj, vma->vm, NULL); if (IS_ERR(batch)) { err = PTR_ERR(batch); diff --git a/drivers/gpu/drm/i915/selftests/i915_gem.c b/drivers/gpu/drm/i915/selftests/i915_gem.c new file mode 100644 index 000000000000..d0aa19d17653 --- /dev/null +++ b/drivers/gpu/drm/i915/selftests/i915_gem.c @@ -0,0 +1,221 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2018 Intel Corporation + */ + +#include <linux/random.h> + +#include "../i915_selftest.h" + +#include "mock_context.h" +#include "igt_flush_test.h" + +static int switch_to_context(struct drm_i915_private *i915, + struct i915_gem_context *ctx) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + int err = 0; + + intel_runtime_pm_get(i915); + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + + rq = i915_request_alloc(engine, ctx); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + break; + } + + i915_request_add(rq); + } + + intel_runtime_pm_put(i915); + + return err; +} + +static void trash_stolen(struct drm_i915_private *i915) +{ + struct i915_ggtt *ggtt = &i915->ggtt; + const u64 slot = ggtt->error_capture.start; + const resource_size_t size = resource_size(&i915->dsm); + unsigned long page; + u32 prng = 0x12345678; + + for (page = 0; page < size; page += PAGE_SIZE) { + const dma_addr_t dma = i915->dsm.start + page; + u32 __iomem *s; + int x; + + ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); + + s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); + for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) { + prng = next_pseudo_random32(prng); + iowrite32(prng, &s[x]); + } + io_mapping_unmap_atomic(s); + } + + ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); +} + +static void simulate_hibernate(struct drm_i915_private *i915) +{ + intel_runtime_pm_get(i915); + + /* + * As a final sting in the tail, invalidate stolen. Under a real S4, + * stolen is lost and needs to be refilled on resume. However, under + * CI we merely do S4-device testing (as full S4 is too unreliable + * for automated testing across a cluster), so to simulate the effect + * of stolen being trashed across S4, we trash it ourselves. + */ + trash_stolen(i915); + + intel_runtime_pm_put(i915); +} + +static int pm_prepare(struct drm_i915_private *i915) +{ + int err = 0; + + if (i915_gem_suspend(i915)) { + pr_err("i915_gem_suspend failed\n"); + err = -EINVAL; + } + + return err; +} + +static void pm_suspend(struct drm_i915_private *i915) +{ + intel_runtime_pm_get(i915); + + i915_gem_suspend_gtt_mappings(i915); + i915_gem_suspend_late(i915); + + intel_runtime_pm_put(i915); +} + +static void pm_hibernate(struct drm_i915_private *i915) +{ + intel_runtime_pm_get(i915); + + i915_gem_suspend_gtt_mappings(i915); + + i915_gem_freeze(i915); + i915_gem_freeze_late(i915); + + intel_runtime_pm_put(i915); +} + +static void pm_resume(struct drm_i915_private *i915) +{ + /* + * Both suspend and hibernate follow the same wakeup path and assume + * that runtime-pm just works. + */ + intel_runtime_pm_get(i915); + + intel_engines_sanitize(i915); + i915_gem_sanitize(i915); + i915_gem_resume(i915); + + intel_runtime_pm_put(i915); +} + +static int igt_gem_suspend(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx; + struct drm_file *file; + int err; + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + err = -ENOMEM; + mutex_lock(&i915->drm.struct_mutex); + ctx = live_context(i915, file); + if (!IS_ERR(ctx)) + err = switch_to_context(i915, ctx); + mutex_unlock(&i915->drm.struct_mutex); + if (err) + goto out; + + err = pm_prepare(i915); + if (err) + goto out; + + pm_suspend(i915); + + /* Here be dragons! Note that with S3RST any S3 may become S4! */ + simulate_hibernate(i915); + + pm_resume(i915); + + mutex_lock(&i915->drm.struct_mutex); + err = switch_to_context(i915, ctx); + if (igt_flush_test(i915, I915_WAIT_LOCKED)) + err = -EIO; + mutex_unlock(&i915->drm.struct_mutex); +out: + mock_file_free(i915, file); + return err; +} + +static int igt_gem_hibernate(void *arg) +{ + struct drm_i915_private *i915 = arg; + struct i915_gem_context *ctx; + struct drm_file *file; + int err; + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + err = -ENOMEM; + mutex_lock(&i915->drm.struct_mutex); + ctx = live_context(i915, file); + if (!IS_ERR(ctx)) + err = switch_to_context(i915, ctx); + mutex_unlock(&i915->drm.struct_mutex); + if (err) + goto out; + + err = pm_prepare(i915); + if (err) + goto out; + + pm_hibernate(i915); + + /* Here be dragons! */ + simulate_hibernate(i915); + + pm_resume(i915); + + mutex_lock(&i915->drm.struct_mutex); + err = switch_to_context(i915, ctx); + if (igt_flush_test(i915, I915_WAIT_LOCKED)) + err = -EIO; + mutex_unlock(&i915->drm.struct_mutex); +out: + mock_file_free(i915, file); + return err; +} + +int i915_gem_live_selftests(struct drm_i915_private *i915) +{ + static const struct i915_subtest tests[] = { + SUBTEST(igt_gem_suspend), + SUBTEST(igt_gem_hibernate), + }; + + return i915_subtests(tests, i915); +} diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c index 3a095c37c120..f7392c1ffe75 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_coherency.c @@ -33,7 +33,8 @@ static int cpu_set(struct drm_i915_gem_object *obj, { unsigned int needs_clflush; struct page *page; - u32 *map; + void *map; + u32 *cpu; int err; err = i915_gem_obj_prepare_shmem_write(obj, &needs_clflush); @@ -42,24 +43,19 @@ static int cpu_set(struct drm_i915_gem_object *obj, page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT); map = kmap_atomic(page); + cpu = map + offset_in_page(offset); - if (needs_clflush & CLFLUSH_BEFORE) { - mb(); - clflush(map+offset_in_page(offset) / sizeof(*map)); - mb(); - } + if (needs_clflush & CLFLUSH_BEFORE) + drm_clflush_virt_range(cpu, sizeof(*cpu)); - map[offset_in_page(offset) / sizeof(*map)] = v; + *cpu = v; - if (needs_clflush & CLFLUSH_AFTER) { - mb(); - clflush(map+offset_in_page(offset) / sizeof(*map)); - mb(); - } + if (needs_clflush & CLFLUSH_AFTER) + drm_clflush_virt_range(cpu, sizeof(*cpu)); kunmap_atomic(map); - i915_gem_obj_finish_shmem_access(obj); + return 0; } @@ -69,7 +65,8 @@ static int cpu_get(struct drm_i915_gem_object *obj, { unsigned int needs_clflush; struct page *page; - u32 *map; + void *map; + u32 *cpu; int err; err = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush); @@ -78,17 +75,16 @@ static int cpu_get(struct drm_i915_gem_object *obj, page = i915_gem_object_get_page(obj, offset >> PAGE_SHIFT); map = kmap_atomic(page); + cpu = map + offset_in_page(offset); - if (needs_clflush & CLFLUSH_BEFORE) { - mb(); - clflush(map+offset_in_page(offset) / sizeof(*map)); - mb(); - } + if (needs_clflush & CLFLUSH_BEFORE) + drm_clflush_virt_range(cpu, sizeof(*cpu)); - *v = map[offset_in_page(offset) / sizeof(*map)]; - kunmap_atomic(map); + *v = *cpu; + kunmap_atomic(map); i915_gem_obj_finish_shmem_access(obj); + return 0; } @@ -302,6 +298,7 @@ static int igt_gem_coherency(void *arg) values = offsets + ncachelines; mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); for (over = igt_coherency_mode; over->name; over++) { if (!over->set) continue; @@ -379,6 +376,7 @@ static int igt_gem_coherency(void *arg) } } unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); kfree(offsets); return err; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/selftests/i915_gem_context.c index 1c92560d35da..76df25aa90c9 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_context.c @@ -22,6 +22,8 @@ * */ +#include <linux/prime_numbers.h> + #include "../i915_selftest.h" #include "i915_random.h" #include "igt_flush_test.h" @@ -32,6 +34,200 @@ #define DW_PER_PAGE (PAGE_SIZE / sizeof(u32)) +struct live_test { + struct drm_i915_private *i915; + const char *func; + const char *name; + + unsigned int reset_count; +}; + +static int begin_live_test(struct live_test *t, + struct drm_i915_private *i915, + const char *func, + const char *name) +{ + int err; + + t->i915 = i915; + t->func = func; + t->name = name; + + err = i915_gem_wait_for_idle(i915, + I915_WAIT_LOCKED, + MAX_SCHEDULE_TIMEOUT); + if (err) { + pr_err("%s(%s): failed to idle before, with err=%d!", + func, name, err); + return err; + } + + i915->gpu_error.missed_irq_rings = 0; + t->reset_count = i915_reset_count(&i915->gpu_error); + + return 0; +} + +static int end_live_test(struct live_test *t) +{ + struct drm_i915_private *i915 = t->i915; + + if (igt_flush_test(i915, I915_WAIT_LOCKED)) + return -EIO; + + if (t->reset_count != i915_reset_count(&i915->gpu_error)) { + pr_err("%s(%s): GPU was reset %d times!\n", + t->func, t->name, + i915_reset_count(&i915->gpu_error) - t->reset_count); + return -EIO; + } + + if (i915->gpu_error.missed_irq_rings) { + pr_err("%s(%s): Missed interrupts on engines %lx\n", + t->func, t->name, i915->gpu_error.missed_irq_rings); + return -EIO; + } + + return 0; +} + +static int live_nop_switch(void *arg) +{ + const unsigned int nctx = 1024; + struct drm_i915_private *i915 = arg; + struct intel_engine_cs *engine; + struct i915_gem_context **ctx; + enum intel_engine_id id; + struct drm_file *file; + struct live_test t; + unsigned long n; + int err = -ENODEV; + + /* + * Create as many contexts as we can feasibly get away with + * and check we can switch between them rapidly. + * + * Serves as very simple stress test for submission and HW switching + * between contexts. + */ + + if (!DRIVER_CAPS(i915)->has_logical_contexts) + return 0; + + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + + mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); + + ctx = kcalloc(nctx, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + err = -ENOMEM; + goto out_unlock; + } + + for (n = 0; n < nctx; n++) { + ctx[n] = i915_gem_create_context(i915, file->driver_priv); + if (IS_ERR(ctx[n])) { + err = PTR_ERR(ctx[n]); + goto out_unlock; + } + } + + for_each_engine(engine, i915, id) { + struct i915_request *rq; + unsigned long end_time, prime; + ktime_t times[2] = {}; + + times[0] = ktime_get_raw(); + for (n = 0; n < nctx; n++) { + rq = i915_request_alloc(engine, ctx[n]); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto out_unlock; + } + i915_request_add(rq); + } + if (i915_request_wait(rq, + I915_WAIT_LOCKED, + HZ / 5) < 0) { + pr_err("Failed to populated %d contexts\n", nctx); + i915_gem_set_wedged(i915); + err = -EIO; + goto out_unlock; + } + + times[1] = ktime_get_raw(); + + pr_info("Populated %d contexts on %s in %lluns\n", + nctx, engine->name, ktime_to_ns(times[1] - times[0])); + + err = begin_live_test(&t, i915, __func__, engine->name); + if (err) + goto out_unlock; + + end_time = jiffies + i915_selftest.timeout_jiffies; + for_each_prime_number_from(prime, 2, 8192) { + times[1] = ktime_get_raw(); + + for (n = 0; n < prime; n++) { + rq = i915_request_alloc(engine, ctx[n % nctx]); + if (IS_ERR(rq)) { + err = PTR_ERR(rq); + goto out_unlock; + } + + /* + * This space is left intentionally blank. + * + * We do not actually want to perform any + * action with this request, we just want + * to measure the latency in allocation + * and submission of our breadcrumbs - + * ensuring that the bare request is sufficient + * for the system to work (i.e. proper HEAD + * tracking of the rings, interrupt handling, + * etc). It also gives us the lowest bounds + * for latency. + */ + + i915_request_add(rq); + } + if (i915_request_wait(rq, + I915_WAIT_LOCKED, + HZ / 5) < 0) { + pr_err("Switching between %ld contexts timed out\n", + prime); + i915_gem_set_wedged(i915); + break; + } + + times[1] = ktime_sub(ktime_get_raw(), times[1]); + if (prime == 2) + times[0] = times[1]; + + if (__igt_timeout(end_time, NULL)) + break; + } + + err = end_live_test(&t); + if (err) + goto out_unlock; + + pr_info("Switch latencies on %s: 1 = %lluns, %lu = %lluns\n", + engine->name, + ktime_to_ns(times[0]), + prime - 1, div64_u64(ktime_to_ns(times[1]), prime - 1)); + } + +out_unlock: + intel_runtime_pm_put(i915); + mutex_unlock(&i915->drm.struct_mutex); + mock_file_free(i915, file); + return err; +} + static struct i915_vma * gpu_fill_dw(struct i915_vma *vma, u64 offset, unsigned long count, u32 value) { @@ -195,6 +391,7 @@ err_request: i915_request_add(rq); err_batch: i915_vma_unpin(batch); + i915_vma_put(batch); err_vma: i915_vma_unpin(vma); return err; @@ -636,6 +833,8 @@ static int igt_switch_to_kernel_context(void *arg) */ mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); + ctx = kernel_context(i915); if (IS_ERR(ctx)) { mutex_unlock(&i915->drm.struct_mutex); @@ -658,6 +857,8 @@ out_unlock: GEM_TRACE_DUMP_ON(err); if (igt_flush_test(i915, I915_WAIT_LOCKED)) err = -EIO; + + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); kernel_context_close(ctx); @@ -713,6 +914,7 @@ int i915_gem_context_live_selftests(struct drm_i915_private *dev_priv) { static const struct i915_subtest tests[] = { SUBTEST(igt_switch_to_kernel_context), + SUBTEST(live_nop_switch), SUBTEST(igt_ctx_exec), SUBTEST(igt_ctx_readonly), }; diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_object.c b/drivers/gpu/drm/i915/selftests/i915_gem_object.c index ba4f322d56b8..c3999dd2021e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/selftests/i915_gem_object.c @@ -282,7 +282,7 @@ static int check_partial_mapping(struct drm_i915_gem_object *obj, view.partial.offset, view.partial.size, vma->size >> PAGE_SHIFT, - tile_row_pages(obj), + tile->tiling ? tile_row_pages(obj) : 0, vma->fence ? vma->fence->id : -1, tile->tiling, tile->stride, offset >> PAGE_SHIFT, (unsigned int)offset_in_page(offset), @@ -501,6 +501,8 @@ static bool assert_mmap_offset(struct drm_i915_private *i915, static void disable_retire_worker(struct drm_i915_private *i915) { + i915_gem_shrinker_unregister(i915); + mutex_lock(&i915->drm.struct_mutex); if (!i915->gt.active_requests++) { intel_runtime_pm_get(i915); @@ -613,6 +615,7 @@ out_park: else queue_delayed_work(i915->wq, &i915->gt.idle_work, 0); mutex_unlock(&i915->drm.struct_mutex); + i915_gem_shrinker_register(i915); return err; err_obj: i915_gem_object_put(obj); diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h index a00e2bd08bce..a15713cae3b3 100644 --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h @@ -17,6 +17,7 @@ selftest(objects, i915_gem_object_live_selftests) selftest(dmabuf, i915_gem_dmabuf_live_selftests) selftest(coherency, i915_gem_coherency_live_selftests) selftest(gtt, i915_gem_gtt_live_selftests) +selftest(gem, i915_gem_live_selftests) selftest(evict, i915_gem_evict_live_selftests) selftest(hugepages, i915_gem_huge_page_live_selftests) selftest(contexts, i915_gem_context_live_selftests) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index c4aac6141e04..07e557815308 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -342,6 +342,7 @@ static int live_nop_request(void *arg) */ mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); for_each_engine(engine, i915, id) { struct i915_request *request = NULL; @@ -402,6 +403,7 @@ static int live_nop_request(void *arg) } out_unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } @@ -487,6 +489,7 @@ static int live_empty_request(void *arg) */ mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); batch = empty_batch(i915); if (IS_ERR(batch)) { @@ -550,6 +553,7 @@ out_batch: i915_vma_unpin(batch); i915_vma_put(batch); out_unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } @@ -644,6 +648,7 @@ static int live_all_engines(void *arg) */ mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); err = begin_live_test(&t, i915, __func__, ""); if (err) @@ -726,6 +731,7 @@ out_request: i915_vma_unpin(batch); i915_vma_put(batch); out_unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } @@ -747,6 +753,7 @@ static int live_sequential_engines(void *arg) */ mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); err = begin_live_test(&t, i915, __func__, ""); if (err) @@ -853,6 +860,7 @@ out_request: i915_request_put(request[id]); } out_unlock: + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } diff --git a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c index 570e325af93e..cdbc8f134e5e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_sw_fence.c +++ b/drivers/gpu/drm/i915/selftests/i915_sw_fence.c @@ -611,17 +611,9 @@ static const char *mock_name(struct dma_fence *fence) return "mock"; } -static bool mock_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static const struct dma_fence_ops mock_fence_ops = { .get_driver_name = mock_name, .get_timeline_name = mock_name, - .enable_signaling = mock_enable_signaling, - .wait = dma_fence_default_wait, - .release = dma_fence_free, }; static DEFINE_SPINLOCK(mock_fence_lock); diff --git a/drivers/gpu/drm/i915/selftests/intel_guc.c b/drivers/gpu/drm/i915/selftests/intel_guc.c index 407c98fb9170..0c0ab82b6228 100644 --- a/drivers/gpu/drm/i915/selftests/intel_guc.c +++ b/drivers/gpu/drm/i915/selftests/intel_guc.c @@ -65,6 +65,40 @@ static int check_all_doorbells(struct intel_guc *guc) return 0; } +static int ring_doorbell_nop(struct intel_guc_client *client) +{ + struct guc_process_desc *desc = __get_process_desc(client); + int err; + + client->use_nop_wqi = true; + + spin_lock_irq(&client->wq_lock); + + guc_wq_item_append(client, 0, 0, 0, 0); + guc_ring_doorbell(client); + + spin_unlock_irq(&client->wq_lock); + + client->use_nop_wqi = false; + + /* if there are no issues GuC will update the WQ head and keep the + * WQ in active status + */ + err = wait_for(READ_ONCE(desc->head) == READ_ONCE(desc->tail), 10); + if (err) { + pr_err("doorbell %u ring failed!\n", client->doorbell_id); + return -EIO; + } + + if (desc->wq_status != WQ_STATUS_ACTIVE) { + pr_err("doorbell %u ring put WQ in bad state (%u)!\n", + client->doorbell_id, desc->wq_status); + return -EIO; + } + + return 0; +} + /* * Basic client sanity check, handy to validate create_clients. */ @@ -108,6 +142,7 @@ static int igt_guc_clients(void *args) GEM_BUG_ON(!HAS_GUC(dev_priv)); mutex_lock(&dev_priv->drm.struct_mutex); + intel_runtime_pm_get(dev_priv); guc = &dev_priv->guc; if (!guc) { @@ -235,6 +270,7 @@ out: guc_clients_create(guc); guc_clients_doorbell_init(guc); unlock: + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); return err; } @@ -253,6 +289,7 @@ static int igt_guc_doorbells(void *arg) GEM_BUG_ON(!HAS_GUC(dev_priv)); mutex_lock(&dev_priv->drm.struct_mutex); + intel_runtime_pm_get(dev_priv); guc = &dev_priv->guc; if (!guc) { @@ -332,6 +369,10 @@ static int igt_guc_doorbells(void *arg) err = check_all_doorbells(guc); if (err) goto out; + + err = ring_doorbell_nop(clients[i]); + if (err) + goto out; } out: @@ -341,6 +382,7 @@ out: guc_client_free(clients[i]); } unlock: + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->drm.struct_mutex); return err; } diff --git a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c index 65d66cdedd26..db378226ac10 100644 --- a/drivers/gpu/drm/i915/selftests/intel_hangcheck.c +++ b/drivers/gpu/drm/i915/selftests/intel_hangcheck.c @@ -1018,8 +1018,41 @@ static int evict_vma(void *data) return err; } +static int evict_fence(void *data) +{ + struct evict_vma *arg = data; + struct drm_i915_private *i915 = arg->vma->vm->i915; + int err; + + complete(&arg->completion); + + mutex_lock(&i915->drm.struct_mutex); + + /* Mark the fence register as dirty to force the mmio update. */ + err = i915_gem_object_set_tiling(arg->vma->obj, I915_TILING_Y, 512); + if (err) { + pr_err("Invalid Y-tiling settings; err:%d\n", err); + goto out_unlock; + } + + err = i915_vma_pin_fence(arg->vma); + if (err) { + pr_err("Unable to pin Y-tiled fence; err:%d\n", err); + goto out_unlock; + } + + i915_vma_unpin_fence(arg->vma); + +out_unlock: + mutex_unlock(&i915->drm.struct_mutex); + + return err; +} + static int __igt_reset_evict_vma(struct drm_i915_private *i915, - struct i915_address_space *vm) + struct i915_address_space *vm, + int (*fn)(void *), + unsigned int flags) { struct drm_i915_gem_object *obj; struct task_struct *tsk = NULL; @@ -1040,12 +1073,20 @@ static int __igt_reset_evict_vma(struct drm_i915_private *i915, if (err) goto unlock; - obj = i915_gem_object_create_internal(i915, PAGE_SIZE); + obj = i915_gem_object_create_internal(i915, SZ_1M); if (IS_ERR(obj)) { err = PTR_ERR(obj); goto fini; } + if (flags & EXEC_OBJECT_NEEDS_FENCE) { + err = i915_gem_object_set_tiling(obj, I915_TILING_X, 512); + if (err) { + pr_err("Invalid X-tiling settings; err:%d\n", err); + goto out_obj; + } + } + arg.vma = i915_vma_instance(obj, vm, NULL); if (IS_ERR(arg.vma)) { err = PTR_ERR(arg.vma); @@ -1059,11 +1100,28 @@ static int __igt_reset_evict_vma(struct drm_i915_private *i915, } err = i915_vma_pin(arg.vma, 0, 0, - i915_vma_is_ggtt(arg.vma) ? PIN_GLOBAL : PIN_USER); - if (err) + i915_vma_is_ggtt(arg.vma) ? + PIN_GLOBAL | PIN_MAPPABLE : + PIN_USER); + if (err) { + i915_request_add(rq); goto out_obj; + } + + if (flags & EXEC_OBJECT_NEEDS_FENCE) { + err = i915_vma_pin_fence(arg.vma); + if (err) { + pr_err("Unable to pin X-tiled fence; err:%d\n", err); + i915_vma_unpin(arg.vma); + i915_request_add(rq); + goto out_obj; + } + } + + err = i915_vma_move_to_active(arg.vma, rq, flags); - err = i915_vma_move_to_active(arg.vma, rq, EXEC_OBJECT_WRITE); + if (flags & EXEC_OBJECT_NEEDS_FENCE) + i915_vma_unpin_fence(arg.vma); i915_vma_unpin(arg.vma); i915_request_get(rq); @@ -1086,7 +1144,7 @@ static int __igt_reset_evict_vma(struct drm_i915_private *i915, init_completion(&arg.completion); - tsk = kthread_run(evict_vma, &arg, "igt/evict_vma"); + tsk = kthread_run(fn, &arg, "igt/evict_vma"); if (IS_ERR(tsk)) { err = PTR_ERR(tsk); tsk = NULL; @@ -1137,29 +1195,47 @@ static int igt_reset_evict_ggtt(void *arg) { struct drm_i915_private *i915 = arg; - return __igt_reset_evict_vma(i915, &i915->ggtt.vm); + return __igt_reset_evict_vma(i915, &i915->ggtt.vm, + evict_vma, EXEC_OBJECT_WRITE); } static int igt_reset_evict_ppgtt(void *arg) { struct drm_i915_private *i915 = arg; struct i915_gem_context *ctx; + struct drm_file *file; int err; + file = mock_file(i915); + if (IS_ERR(file)) + return PTR_ERR(file); + mutex_lock(&i915->drm.struct_mutex); - ctx = kernel_context(i915); + ctx = live_context(i915, file); mutex_unlock(&i915->drm.struct_mutex); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); + if (IS_ERR(ctx)) { + err = PTR_ERR(ctx); + goto out; + } err = 0; if (ctx->ppgtt) /* aliasing == global gtt locking, covered above */ - err = __igt_reset_evict_vma(i915, &ctx->ppgtt->vm); + err = __igt_reset_evict_vma(i915, &ctx->ppgtt->vm, + evict_vma, EXEC_OBJECT_WRITE); - kernel_context_close(ctx); +out: + mock_file_free(i915, file); return err; } +static int igt_reset_evict_fence(void *arg) +{ + struct drm_i915_private *i915 = arg; + + return __igt_reset_evict_vma(i915, &i915->ggtt.vm, + evict_fence, EXEC_OBJECT_NEEDS_FENCE); +} + static int wait_for_others(struct drm_i915_private *i915, struct intel_engine_cs *exclude) { @@ -1409,6 +1485,7 @@ int intel_hangcheck_live_selftests(struct drm_i915_private *i915) SUBTEST(igt_reset_wait), SUBTEST(igt_reset_evict_ggtt), SUBTEST(igt_reset_evict_ppgtt), + SUBTEST(igt_reset_evict_fence), SUBTEST(igt_handle_error), }; bool saved_hangcheck; diff --git a/drivers/gpu/drm/i915/selftests/intel_lrc.c b/drivers/gpu/drm/i915/selftests/intel_lrc.c index 582566faef09..1aea7a8f2224 100644 --- a/drivers/gpu/drm/i915/selftests/intel_lrc.c +++ b/drivers/gpu/drm/i915/selftests/intel_lrc.c @@ -221,6 +221,7 @@ static int live_sanitycheck(void *arg) return 0; mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); if (spinner_init(&spin, i915)) goto err_unlock; @@ -261,6 +262,7 @@ err_spin: spinner_fini(&spin); err_unlock: igt_flush_test(i915, I915_WAIT_LOCKED); + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } @@ -278,6 +280,7 @@ static int live_preempt(void *arg) return 0; mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); if (spinner_init(&spin_hi, i915)) goto err_unlock; @@ -350,6 +353,7 @@ err_spin_hi: spinner_fini(&spin_hi); err_unlock: igt_flush_test(i915, I915_WAIT_LOCKED); + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } @@ -368,6 +372,7 @@ static int live_late_preempt(void *arg) return 0; mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); if (spinner_init(&spin_hi, i915)) goto err_unlock; @@ -440,6 +445,7 @@ err_spin_hi: spinner_fini(&spin_hi); err_unlock: igt_flush_test(i915, I915_WAIT_LOCKED); + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; @@ -467,6 +473,7 @@ static int live_preempt_hang(void *arg) return 0; mutex_lock(&i915->drm.struct_mutex); + intel_runtime_pm_get(i915); if (spinner_init(&spin_hi, i915)) goto err_unlock; @@ -561,6 +568,7 @@ err_spin_hi: spinner_fini(&spin_hi); err_unlock: igt_flush_test(i915, I915_WAIT_LOCKED); + intel_runtime_pm_put(i915); mutex_unlock(&i915->drm.struct_mutex); return err; } diff --git a/drivers/gpu/drm/i915/selftests/intel_workarounds.c b/drivers/gpu/drm/i915/selftests/intel_workarounds.c index 0d39b3bf0c0d..d1a0923d2f38 100644 --- a/drivers/gpu/drm/i915/selftests/intel_workarounds.c +++ b/drivers/gpu/drm/i915/selftests/intel_workarounds.c @@ -44,7 +44,9 @@ read_nonprivs(struct i915_gem_context *ctx, struct intel_engine_cs *engine) if (err) goto err_obj; + intel_runtime_pm_get(engine->i915); rq = i915_request_alloc(engine, ctx); + intel_runtime_pm_put(engine->i915); if (IS_ERR(rq)) { err = PTR_ERR(rq); goto err_pin; @@ -175,7 +177,10 @@ static int switch_to_scratch_context(struct intel_engine_cs *engine) if (IS_ERR(ctx)) return PTR_ERR(ctx); + intel_runtime_pm_get(engine->i915); rq = i915_request_alloc(engine, ctx); + intel_runtime_pm_put(engine->i915); + kernel_context_close(ctx); if (IS_ERR(rq)) return PTR_ERR(rq); diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c index 8904f1ce64e3..d937bdff26f9 100644 --- a/drivers/gpu/drm/i915/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/selftests/mock_context.c @@ -43,6 +43,7 @@ mock_context(struct drm_i915_private *i915, INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); + INIT_LIST_HEAD(&ctx->hw_id_link); for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { struct intel_context *ce = &ctx->__engine[n]; @@ -50,11 +51,9 @@ mock_context(struct drm_i915_private *i915, ce->gem_context = ctx; } - ret = ida_simple_get(&i915->contexts.hw_ida, - 0, MAX_CONTEXT_HW_ID, GFP_KERNEL); + ret = i915_gem_context_pin_hw_id(ctx); if (ret < 0) goto err_handles; - ctx->hw_id = ret; if (name) { ctx->name = kstrdup(name, GFP_KERNEL); @@ -85,11 +84,7 @@ void mock_context_close(struct i915_gem_context *ctx) void mock_init_contexts(struct drm_i915_private *i915) { - INIT_LIST_HEAD(&i915->contexts.list); - ida_init(&i915->contexts.hw_ida); - - INIT_WORK(&i915->contexts.free_work, contexts_free_worker); - init_llist_head(&i915->contexts.free_list); + init_contexts(i915); } struct i915_gem_context * diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c index a140ea5c3a7c..6ae418c76015 100644 --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c @@ -118,6 +118,8 @@ void mock_init_ggtt(struct drm_i915_private *i915) ggtt->vm.vma_ops.clear_pages = clear_pages; i915_address_space_init(&ggtt->vm, i915); + + ggtt->vm.is_ggtt = true; } void mock_fini_ggtt(struct drm_i915_private *i915) |