diff options
201 files changed, 3753 insertions, 5006 deletions
@@ -10,10 +10,12 @@ # Please keep this list dictionary sorted. # Aaron Durbin <adurbin@google.com> +Abhinav Kumar <quic_abhinavk@quicinc.com> <abhinavk@codeaurora.org> Adam Oldham <oldhamca@gmail.com> Adam Radford <aradford@gmail.com> Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com> Adrian Bunk <bunk@stusta.de> +Akhil P Oommen <quic_akhilpo@quicinc.com> <akhilpo@codeaurora.org> Alan Cox <alan@lxorguk.ukuu.org.uk> Alan Cox <root@hraefn.swansea.linux.org.uk> Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com> @@ -172,6 +174,7 @@ Jeff Layton <jlayton@kernel.org> <jlayton@redhat.com> Jens Axboe <axboe@suse.de> Jens Osterkamp <Jens.Osterkamp@de.ibm.com> Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net> +Jessica Zhang <quic_jesszhan@quicinc.com> <jesszhan@codeaurora.org> Jiri Slaby <jirislaby@kernel.org> <jirislaby@gmail.com> Jiri Slaby <jirislaby@kernel.org> <jslaby@novell.com> Jiri Slaby <jirislaby@kernel.org> <jslaby@suse.com> @@ -191,6 +194,7 @@ Juha Yrjola <at solidboot.com> Juha Yrjola <juha.yrjola@nokia.com> Juha Yrjola <juha.yrjola@solidboot.com> Julien Thierry <julien.thierry.kdev@gmail.com> <julien.thierry@arm.com> +Kalyan Thota <quic_kalyant@quicinc.com> <kalyan_t@codeaurora.org> Kay Sievers <kay.sievers@vrfy.org> Kees Cook <keescook@chromium.org> <kees.cook@canonical.com> Kees Cook <keescook@chromium.org> <keescook@google.com> @@ -202,9 +206,11 @@ Kenneth W Chen <kenneth.w.chen@intel.com> Konstantin Khlebnikov <koct9i@gmail.com> <khlebnikov@yandex-team.ru> Konstantin Khlebnikov <koct9i@gmail.com> <k.khlebnikov@samsung.com> Koushik <raghavendra.koushik@neterion.com> +Krishna Manikandan <quic_mkrishn@quicinc.com> <mkrishn@codeaurora.org> Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski.k@gmail.com> Krzysztof Kozlowski <krzk@kernel.org> <k.kozlowski@samsung.com> Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> +Kuogee Hsieh <quic_khsieh@quicinc.com> <khsieh@codeaurora.org> Leonardo Bras <leobras.c@gmail.com> <leonardo@linux.ibm.com> Leonid I Ananiev <leonid.i.ananiev@intel.com> Leon Romanovsky <leon@kernel.org> <leon@leon.nu> @@ -311,6 +317,7 @@ Qais Yousef <qsyousef@gmail.com> <qais.yousef@imgtec.com> Quentin Monnet <quentin@isovalent.com> <quentin.monnet@netronome.com> Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com> Rafael J. Wysocki <rjw@rjwysocki.net> <rjw@sisk.pl> +Rajeev Nandan <quic_rajeevny@quicinc.com> <rajeevny@codeaurora.org> Rajesh Shah <rajesh.shah@intel.com> Ralf Baechle <ralf@linux-mips.org> Ralf Wildenhues <Ralf.Wildenhues@gmx.de> @@ -325,6 +332,7 @@ Rui Saraiva <rmps@joel.ist.utl.pt> Sachin P Sant <ssant@in.ibm.com> Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi> Sam Ravnborg <sam@mars.ravnborg.org> +Sankeerth Billakanti <quic_sbillaka@quicinc.com> <sbillaka@codeaurora.org> Santosh Shilimkar <santosh.shilimkar@oracle.org> Santosh Shilimkar <ssantosh@kernel.org> Sarangdhar Joshi <spjoshi@codeaurora.org> diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml index cf5a208f2f10..343598c9f473 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml @@ -10,6 +10,9 @@ title: Amlogic specific extensions to the Synopsys Designware HDMI Controller maintainers: - Neil Armstrong <narmstrong@baylibre.com> +allOf: + - $ref: /schemas/sound/name-prefix.yaml# + description: | The Amlogic Meson Synopsys Designware Integration is composed of - A Synopsys DesignWare HDMI Controller IP @@ -99,6 +102,8 @@ properties: "#sound-dai-cells": const: 0 + sound-name-prefix: true + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml index 851cb0781217..047fd69e0377 100644 --- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml +++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml @@ -78,6 +78,10 @@ properties: interrupts: maxItems: 1 + amlogic,canvas: + description: should point to a canvas provider node + $ref: /schemas/types.yaml#/definitions/phandle + power-domains: maxItems: 1 description: phandle to the associated power domain @@ -106,6 +110,7 @@ required: - port@1 - "#address-cells" - "#size-cells" + - amlogic,canvas additionalProperties: false @@ -118,6 +123,7 @@ examples: interrupts = <3>; #address-cells = <1>; #size-cells = <0>; + amlogic,canvas = <&canvas>; /* CVBS VDAC output port */ port@0 { diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 63e585f48789..5457612ab136 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -17,6 +17,8 @@ properties: compatible: enum: - qcom,sc7180-dp + - qcom,sc7280-dp + - qcom,sc7280-edp - qcom,sc8180x-dp - qcom,sc8180x-edp diff --git a/Documentation/devicetree/bindings/display/msm/edp.txt b/Documentation/devicetree/bindings/display/msm/edp.txt deleted file mode 100644 index eff9daff418c..000000000000 --- a/Documentation/devicetree/bindings/display/msm/edp.txt +++ /dev/null @@ -1,56 +0,0 @@ -Qualcomm Technologies Inc. adreno/snapdragon eDP output - -Required properties: -- compatible: - * "qcom,mdss-edp" -- reg: Physical base address and length of the registers of controller and PLL -- reg-names: The names of register regions. The following regions are required: - * "edp" - * "pll_base" -- interrupts: The interrupt signal from the eDP block. -- power-domains: Should be <&mmcc MDSS_GDSC>. -- clocks: device clocks - See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. -- clock-names: the following clocks are required: - * "core" - * "iface" - * "mdp_core" - * "pixel" - * "link" -- #clock-cells: The value should be 1. -- vdda-supply: phandle to vdda regulator device node -- lvl-vdd-supply: phandle to regulator device node which is used to supply power - to HPD receiving chip -- panel-en-gpios: GPIO pin to supply power to panel. -- panel-hpd-gpios: GPIO pin used for eDP hpd. - - -Example: - mdss_edp: qcom,mdss_edp@fd923400 { - compatible = "qcom,mdss-edp"; - reg-names = - "edp", - "pll_base"; - reg = <0xfd923400 0x700>, - <0xfd923a00 0xd4>; - interrupt-parent = <&mdss_mdp>; - interrupts = <12 0>; - power-domains = <&mmcc MDSS_GDSC>; - clock-names = - "core", - "pixel", - "iface", - "link", - "mdp_core"; - clocks = - <&mmcc MDSS_EDPAUX_CLK>, - <&mmcc MDSS_EDPPIXEL_CLK>, - <&mmcc MDSS_AHB_CLK>, - <&mmcc MDSS_EDPLINK_CLK>, - <&mmcc MDSS_MDP_CLK>; - #clock-cells = <1>; - vdda-supply = <&pma8084_l12>; - lvl-vdd-supply = <&lvl_vreg>; - panel-en-gpios = <&tlmm 137 0>; - panel-hpd-gpios = <&tlmm 103 0>; - }; diff --git a/MAINTAINERS b/MAINTAINERS index d03ad8da1f36..c25eb9e31df9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6050,6 +6050,7 @@ F: drivers/gpu/drm/tiny/mi0283qt.c DRM DRIVER FOR MSM ADRENO GPU M: Rob Clark <robdclark@gmail.com> M: Sean Paul <sean@poorly.run> +R: Abhinav Kumar <quic_abhinavk@quicinc.com> L: linux-arm-msm@vger.kernel.org L: dri-devel@lists.freedesktop.org L: freedreno@lists.freedesktop.org diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 0c05b79870f9..83f02bd51dda 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -124,10 +124,11 @@ static int cma_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, struct cma_heap_buffer *buffer = dmabuf->priv; struct dma_heap_attachment *a; + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) invalidate_kernel_vmap_range(buffer->vaddr, buffer->len); - mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { if (!a->mapped) continue; @@ -144,10 +145,11 @@ static int cma_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, struct cma_heap_buffer *buffer = dmabuf->priv; struct dma_heap_attachment *a; + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) flush_kernel_vmap_range(buffer->vaddr, buffer->len); - mutex_lock(&buffer->lock); list_for_each_entry(a, &buffer->attachments, list) { if (!a->mapped) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9eb7afa276f2..4f771f9eb0e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -812,6 +812,7 @@ struct amd_powerplay { #define AMDGPU_RESET_MAGIC_NUM 64 #define AMDGPU_MAX_DF_PERFMONS 4 +#define AMDGPU_PRODUCT_NAME_LEN 64 struct amdgpu_device { struct device *dev; struct pci_dev *pdev; @@ -1082,7 +1083,7 @@ struct amdgpu_device { /* Chip product information */ char product_number[16]; - char product_name[32]; + char product_name[AMDGPU_PRODUCT_NAME_LEN]; char serial[20]; atomic_t throttling_logging_enabled; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 46cf48b3904a..6ca1db3c243f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -514,13 +514,6 @@ out_put: return r; } -uint64_t amdgpu_amdkfd_get_vram_usage(struct amdgpu_device *adev) -{ - struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); - - return amdgpu_vram_mgr_usage(vram_man); -} - uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct amdgpu_device *dst, struct amdgpu_device *src) { @@ -721,13 +714,13 @@ bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev) return adev->have_atomics_support; } -void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev) +void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bool reset) { struct ras_err_data err_data = {0, 0, 0, NULL}; /* CPU MCA will handle page retirement if connected_to_cpu is 1 */ if (!adev->gmc.xgmi.connected_to_cpu) - amdgpu_umc_process_ras_data_cb(adev, &err_data, NULL); - else + amdgpu_umc_poison_handler(adev, &err_data, reset); + else if (reset) amdgpu_amdkfd_gpu_reset(adev); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index fcbc8a9c9e06..ac841ae8f5cc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -223,7 +223,6 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd, uint64_t *bo_size, void *metadata_buffer, size_t buffer_size, uint32_t *metadata_size, uint32_t *flags); -uint64_t amdgpu_amdkfd_get_vram_usage(struct amdgpu_device *adev); uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct amdgpu_device *dst, struct amdgpu_device *src); int amdgpu_amdkfd_get_xgmi_bandwidth_mbytes(struct amdgpu_device *dst, @@ -296,7 +295,8 @@ int amdgpu_amdkfd_gpuvm_import_dmabuf(struct amdgpu_device *adev, uint64_t *mmap_offset); int amdgpu_amdkfd_get_tile_config(struct amdgpu_device *adev, struct tile_config *config); -void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev); +void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, + bool reset); #if IS_ENABLED(CONFIG_HSA_AMD) void amdgpu_amdkfd_gpuvm_init_mem_limits(void); void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index ddfe7aff919d..1abf662a0e91 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -166,7 +166,7 @@ int kgd_gfx_v9_init_interrupts(struct amdgpu_device *adev, uint32_t pipe_id) lock_srbm(adev, mec, pipe, 0, 0); - WREG32(SOC15_REG_OFFSET(GC, 0, mmCPC_INT_CNTL), + WREG32_SOC15(GC, 0, mmCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); @@ -279,7 +279,7 @@ int kgd_gfx_v9_hqd_load(struct amdgpu_device *adev, void *mqd, lower_32_bits((uintptr_t)wptr)); WREG32_RLC(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI), upper_32_bits((uintptr_t)wptr)); - WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1), + WREG32_SOC15(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1, (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); } @@ -488,13 +488,13 @@ bool kgd_gfx_v9_hqd_is_occupied(struct amdgpu_device *adev, uint32_t low, high; acquire_queue(adev, pipe_id, queue_id); - act = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); + act = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); if (act) { low = lower_32_bits(queue_address >> 8); high = upper_32_bits(queue_address >> 8); - if (low == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE)) && - high == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE_HI))) + if (low == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE) && + high == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE_HI)) retval = true; } release_queue(adev); @@ -556,7 +556,7 @@ int kgd_gfx_v9_hqd_destroy(struct amdgpu_device *adev, void *mqd, end_jiffies = (utimeout * HZ / 1000) + jiffies; while (true) { - temp = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); + temp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK)) break; if (time_after(jiffies, end_jiffies)) { @@ -645,7 +645,7 @@ int kgd_gfx_v9_wave_control_execute(struct amdgpu_device *adev, mutex_lock(&adev->grbm_idx_mutex); WREG32_SOC15_RLC_SHADOW(GC, 0, mmGRBM_GFX_INDEX, gfx_index_val); - WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_CMD), sq_cmd); + WREG32_SOC15(GC, 0, mmSQ_CMD, sq_cmd); data = REG_SET_FIELD(data, GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES, 1); @@ -722,7 +722,7 @@ static void get_wave_count(struct amdgpu_device *adev, int queue_idx, pipe_idx = queue_idx / adev->gfx.mec.num_queue_per_pipe; queue_slot = queue_idx % adev->gfx.mec.num_queue_per_pipe; soc15_grbm_select(adev, 1, pipe_idx, queue_slot, 0); - reg_val = RREG32(SOC15_REG_OFFSET(GC, 0, mmSPI_CSQ_WF_ACTIVE_COUNT_0) + + reg_val = RREG32_SOC15_IP(GC, SOC15_REG_OFFSET(GC, 0, mmSPI_CSQ_WF_ACTIVE_COUNT_0) + queue_slot); *wave_cnt = reg_val & SPI_CSQ_WF_ACTIVE_COUNT_0__COUNT_MASK; if (*wave_cnt != 0) @@ -809,8 +809,7 @@ void kgd_gfx_v9_get_cu_occupancy(struct amdgpu_device *adev, int pasid, for (sh_idx = 0; sh_idx < sh_cnt; sh_idx++) { gfx_v9_0_select_se_sh(adev, se_idx, sh_idx, 0xffffffff); - queue_map = RREG32(SOC15_REG_OFFSET(GC, 0, - mmSPI_CSQ_WF_ACTIVE_STATUS)); + queue_map = RREG32_SOC15(GC, 0, mmSPI_CSQ_WF_ACTIVE_STATUS); /* * Assumption: queue map encodes following schema: four @@ -860,17 +859,17 @@ void kgd_gfx_v9_program_trap_handler_settings(struct amdgpu_device *adev, /* * Program TBA registers */ - WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_SHADER_TBA_LO), + WREG32_SOC15(GC, 0, mmSQ_SHADER_TBA_LO, lower_32_bits(tba_addr >> 8)); - WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_SHADER_TBA_HI), + WREG32_SOC15(GC, 0, mmSQ_SHADER_TBA_HI, upper_32_bits(tba_addr >> 8)); /* * Program TMA registers */ - WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_SHADER_TMA_LO), + WREG32_SOC15(GC, 0, mmSQ_SHADER_TMA_LO, lower_32_bits(tma_addr >> 8)); - WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_SHADER_TMA_HI), + WREG32_SOC15(GC, 0, mmSQ_SHADER_TMA_HI, upper_32_bits(tma_addr >> 8)); unlock_srbm(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 0311d799a010..06d07502a1f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -298,7 +298,6 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, { s64 time_us, increment_us; u64 free_vram, total_vram, used_vram; - struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); /* Allow a maximum of 200 accumulated ms. This is basically per-IB * throttling. * @@ -315,7 +314,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, } total_vram = adev->gmc.real_vram_size - atomic64_read(&adev->vram_pin_size); - used_vram = amdgpu_vram_mgr_usage(vram_man); + used_vram = amdgpu_vram_mgr_usage(&adev->mman.vram_mgr); free_vram = used_vram >= total_vram ? 0 : total_vram - used_vram; spin_lock(&adev->mm_stats.lock); @@ -362,7 +361,7 @@ static void amdgpu_cs_get_threshold_for_moves(struct amdgpu_device *adev, if (!amdgpu_gmc_vram_full_visible(&adev->gmc)) { u64 total_vis_vram = adev->gmc.visible_vram_size; u64 used_vis_vram = - amdgpu_vram_mgr_vis_usage(vram_man); + amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr); if (used_vis_vram < total_vis_vram) { u64 free_vis_vram = total_vis_vram - used_vis_vram; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 8219e40240ce..cf7fad88c138 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -552,7 +552,7 @@ void amdgpu_device_wreg(struct amdgpu_device *adev, } /** - * amdgpu_mm_wreg_mmio_rlc - write register either with mmio or with RLC path if in range + * amdgpu_mm_wreg_mmio_rlc - write register either with direct/indirect mmio or with RLC path if in range * * this function is invoked only the debugfs register access */ @@ -567,6 +567,8 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev, adev->gfx.rlc.funcs->is_rlcg_access_range) { if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) return adev->gfx.rlc.funcs->sriov_wreg(adev, reg, v, 0, 0); + } else if ((reg * 4) >= adev->rmmio_size) { + adev->pcie_wreg(adev, reg * 4, v); } else { writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); } @@ -1448,7 +1450,7 @@ static int amdgpu_device_init_apu_flags(struct amdgpu_device *adev) adev->apu_flags |= AMD_APU_IS_CYAN_SKILLFISH2; break; default: - return -EINVAL; + break; } return 0; @@ -2317,6 +2319,10 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) /* need to do gmc hw init early so we can allocate gpu mem */ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { + /* Try to reserve bad pages early */ + if (amdgpu_sriov_vf(adev)) + amdgpu_virt_exchange_data(adev); + r = amdgpu_device_vram_scratch_init(adev); if (r) { DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r); @@ -2348,7 +2354,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) } if (amdgpu_sriov_vf(adev)) - amdgpu_virt_init_data_exchange(adev); + amdgpu_virt_exchange_data(adev); r = amdgpu_ib_pool_init(adev); if (r) { @@ -2615,11 +2621,10 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) if (r) DRM_ERROR("enable mgpu fan boost failed (%d).\n", r); - /* For XGMI + passthrough configuration on arcturus, enable light SBR */ - if (adev->asic_type == CHIP_ARCTURUS && - amdgpu_passthrough(adev) && - adev->gmc.xgmi.num_physical_nodes > 1) - smu_set_light_sbr(&adev->smu, true); + /* For passthrough configuration on arcturus and aldebaran, enable special handling SBR */ + if (amdgpu_passthrough(adev) && ((adev->asic_type == CHIP_ARCTURUS && adev->gmc.xgmi.num_physical_nodes > 1)|| + adev->asic_type == CHIP_ALDEBARAN )) + smu_handle_passthrough_sbr(&adev->smu, true); if (adev->gmc.xgmi.num_physical_nodes > 1) { mutex_lock(&mgpu_info.mutex); @@ -3182,6 +3187,12 @@ static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev) bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) { switch (asic_type) { +#ifdef CONFIG_DRM_AMDGPU_SI + case CHIP_HAINAN: +#endif + case CHIP_TOPAZ: + /* chips with no display hardware */ + return false; #if defined(CONFIG_DRM_AMD_DC) case CHIP_TAHITI: case CHIP_PITCAIRN: @@ -3487,9 +3498,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, mutex_init(&adev->psp.mutex); mutex_init(&adev->notifier_lock); - r = amdgpu_device_init_apu_flags(adev); - if (r) - return r; + amdgpu_device_init_apu_flags(adev); r = amdgpu_device_check_arguments(adev); if (r) @@ -3573,6 +3582,13 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (r) return r; + /* Need to get xgmi info early to decide the reset behavior*/ + if (adev->gmc.xgmi.supported) { + r = adev->gfxhub.funcs->get_xgmi_info(adev); + if (r) + return r; + } + /* enable PCIE atomic ops */ if (amdgpu_sriov_vf(adev)) adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *) @@ -3817,6 +3833,7 @@ failed: static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev) { + /* Clear all CPU mappings pointing to this device */ unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1); @@ -3885,15 +3902,20 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_irq_fini_hw(adev); - ttm_device_clear_dma_mappings(&adev->mman.bdev); + if (adev->mman.initialized) + ttm_device_clear_dma_mappings(&adev->mman.bdev); amdgpu_gart_dummy_page_fini(adev); - amdgpu_device_unmap_mmio(adev); + if (drm_dev_is_unplugged(adev_to_drm(adev))) + amdgpu_device_unmap_mmio(adev); + } void amdgpu_device_fini_sw(struct amdgpu_device *adev) { + int idx; + amdgpu_fence_driver_sw_fini(adev); amdgpu_device_ip_fini(adev); release_firmware(adev->firmware.gpu_info_fw); @@ -3918,6 +3940,14 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) vga_client_unregister(adev->pdev); + if (drm_dev_enter(adev_to_drm(adev), &idx)) { + + iounmap(adev->rmmio); + adev->rmmio = NULL; + amdgpu_device_doorbell_fini(adev); + drm_dev_exit(idx); + } + if (IS_ENABLED(CONFIG_PERF_EVENTS)) amdgpu_pmu_fini(adev); if (adev->mman.discovery_bin) @@ -3938,8 +3968,8 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) */ static void amdgpu_device_evict_resources(struct amdgpu_device *adev) { - /* No need to evict vram on APUs for suspend to ram */ - if (adev->in_s3 && (adev->flags & AMD_IS_APU)) + /* No need to evict vram on APUs for suspend to ram or s2idle */ + if ((adev->in_s3 || adev->in_s0ix) && (adev->flags & AMD_IS_APU)) return; if (amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM)) @@ -3986,16 +4016,11 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) if (!adev->in_s0ix) amdgpu_amdkfd_suspend(adev, adev->in_runpm); - /* First evict vram memory */ amdgpu_device_evict_resources(adev); amdgpu_fence_driver_hw_fini(adev); amdgpu_device_ip_suspend_phase2(adev); - /* This second call to evict device resources is to evict - * the gart page table using the CPU. - */ - amdgpu_device_evict_resources(adev); return 0; } @@ -4340,8 +4365,6 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, goto error; amdgpu_virt_init_data_exchange(adev); - /* we need recover gart prior to run SMC/CP/SDMA resume */ - amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); r = amdgpu_device_fw_loading(adev); if (r) @@ -4507,7 +4530,7 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev) int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, struct amdgpu_reset_context *reset_context) { - int i, j, r = 0; + int i, r = 0; struct amdgpu_job *job = NULL; bool need_full_reset = test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); @@ -4529,15 +4552,8 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, /*clear job fence from fence drv to avoid force_completion *leave NULL and vm flush fence in fence drv */ - for (j = 0; j <= ring->fence_drv.num_fences_mask; j++) { - struct dma_fence *old, **ptr; + amdgpu_fence_driver_clear_job_fences(ring); - ptr = &ring->fence_drv.fences[j]; - old = rcu_dereference_protected(*ptr, 1); - if (old && test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &old->flags)) { - RCU_INIT_POINTER(*ptr, NULL); - } - } /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ amdgpu_fence_driver_force_completion(ring); } @@ -4668,10 +4684,6 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, amdgpu_inc_vram_lost(tmp_adev); } - r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT)); - if (r) - goto out; - r = amdgpu_device_fw_loading(tmp_adev); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 5bc072220f03..be45650250fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -550,7 +550,8 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev) } /* some IP discovery tables on Navy Flounder don't have this set correctly */ if ((adev->ip_versions[UVD_HWIP][1] == IP_VERSION(3, 0, 1)) && - (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 2))) + (adev->ip_versions[GC_HWIP][0] == IP_VERSION(10, 3, 2)) && + (adev->pdev->revision != 0xFF)) adev->vcn.harvest_config |= AMDGPU_VCN_HARVEST_VCN1; if (vcn_harvest_count == adev->vcn.num_vcn_inst) { adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK; @@ -565,10 +566,15 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev) } } +union gc_info { + struct gc_info_v1_0 v1; + struct gc_info_v2_0 v2; +}; + int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev) { struct binary_header *bhdr; - struct gc_info_v1_0 *gc_info; + union gc_info *gc_info; if (!adev->mman.discovery_bin) { DRM_ERROR("ip discovery uninitialized\n"); @@ -576,28 +582,55 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev) } bhdr = (struct binary_header *)adev->mman.discovery_bin; - gc_info = (struct gc_info_v1_0 *)(adev->mman.discovery_bin + + gc_info = (union gc_info *)(adev->mman.discovery_bin + le16_to_cpu(bhdr->table_list[GC].offset)); - - adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->gc_num_se); - adev->gfx.config.max_cu_per_sh = 2 * (le32_to_cpu(gc_info->gc_num_wgp0_per_sa) + - le32_to_cpu(gc_info->gc_num_wgp1_per_sa)); - adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->gc_num_sa_per_se); - adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->gc_num_rb_per_se); - adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->gc_num_gl2c); - adev->gfx.config.max_gprs = le32_to_cpu(gc_info->gc_num_gprs); - adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->gc_num_max_gs_thds); - adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->gc_gs_table_depth); - adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->gc_gsprim_buff_depth); - adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->gc_double_offchip_lds_buffer); - adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->gc_wave_size); - adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->gc_max_waves_per_simd); - adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->gc_max_scratch_slots_per_cu); - adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->gc_lds_size); - adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->gc_num_sc_per_se) / - le32_to_cpu(gc_info->gc_num_sa_per_se); - adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->gc_num_packer_per_sc); - + switch (gc_info->v1.header.version_major) { + case 1: + adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v1.gc_num_se); + adev->gfx.config.max_cu_per_sh = 2 * (le32_to_cpu(gc_info->v1.gc_num_wgp0_per_sa) + + le32_to_cpu(gc_info->v1.gc_num_wgp1_per_sa)); + adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->v1.gc_num_sa_per_se); + adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->v1.gc_num_rb_per_se); + adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->v1.gc_num_gl2c); + adev->gfx.config.max_gprs = le32_to_cpu(gc_info->v1.gc_num_gprs); + adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->v1.gc_num_max_gs_thds); + adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->v1.gc_gs_table_depth); + adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->v1.gc_gsprim_buff_depth); + adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->v1.gc_double_offchip_lds_buffer); + adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->v1.gc_wave_size); + adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->v1.gc_max_waves_per_simd); + adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->v1.gc_max_scratch_slots_per_cu); + adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->v1.gc_lds_size); + adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->v1.gc_num_sc_per_se) / + le32_to_cpu(gc_info->v1.gc_num_sa_per_se); + adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->v1.gc_num_packer_per_sc); + break; + case 2: + adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v2.gc_num_se); + adev->gfx.config.max_cu_per_sh = le32_to_cpu(gc_info->v2.gc_num_cu_per_sh); + adev->gfx.config.max_sh_per_se = le32_to_cpu(gc_info->v2.gc_num_sh_per_se); + adev->gfx.config.max_backends_per_se = le32_to_cpu(gc_info->v2.gc_num_rb_per_se); + adev->gfx.config.max_texture_channel_caches = le32_to_cpu(gc_info->v2.gc_num_tccs); + adev->gfx.config.max_gprs = le32_to_cpu(gc_info->v2.gc_num_gprs); + adev->gfx.config.max_gs_threads = le32_to_cpu(gc_info->v2.gc_num_max_gs_thds); + adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gc_info->v2.gc_gs_table_depth); + adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gc_info->v2.gc_gsprim_buff_depth); + adev->gfx.config.double_offchip_lds_buf = le32_to_cpu(gc_info->v2.gc_double_offchip_lds_buffer); + adev->gfx.cu_info.wave_front_size = le32_to_cpu(gc_info->v2.gc_wave_size); + adev->gfx.cu_info.max_waves_per_simd = le32_to_cpu(gc_info->v2.gc_max_waves_per_simd); + adev->gfx.cu_info.max_scratch_slots_per_cu = le32_to_cpu(gc_info->v2.gc_max_scratch_slots_per_cu); + adev->gfx.cu_info.lds_size = le32_to_cpu(gc_info->v2.gc_lds_size); + adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->v2.gc_num_sc_per_se) / + le32_to_cpu(gc_info->v2.gc_num_sh_per_se); + adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->v2.gc_num_packer_per_sc); + break; + default: + dev_err(adev->dev, + "Unhandled GC info table %d.%d\n", + gc_info->v1.header.version_major, + gc_info->v1.header.version_minor); + return -EINVAL; + } return 0; } @@ -992,7 +1025,7 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block); break; default: - break;; + break; } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index 4896c876ffec..579adfafe4d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -381,7 +381,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach) struct amdgpu_vm_bo_base *bo_base; int r; - if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM) + if (!bo->tbo.resource || bo->tbo.resource->mem_type == TTM_PL_SYSTEM) return; r = ttm_bo_validate(&bo->tbo, &placement, &ctx); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 02099058d0d6..366e475056bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -330,10 +330,11 @@ module_param_named(aspm, amdgpu_aspm, int, 0444); /** * DOC: runpm (int) - * Override for runtime power management control for dGPUs in PX/HG laptops. The amdgpu driver can dynamically power down - * the dGPU on PX/HG laptops when it is idle. The default is -1 (auto enable). Setting the value to 0 disables this functionality. + * Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down + * the dGPUs when they are idle if supported. The default is -1 (auto enable). + * Setting the value to 0 disables this functionality. */ -MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = PX only default)"); +MODULE_PARM_DESC(runpm, "PX runtime pm (2 = force enable with BAMACO, 1 = force enable with BACO, 0 = disable, -1 = auto)"); module_param_named(runpm, amdgpu_runtime_pm, int, 0444); /** @@ -2165,10 +2166,13 @@ static int amdgpu_pmops_suspend(struct device *dev) if (amdgpu_acpi_is_s0ix_active(adev)) adev->in_s0ix = true; - adev->in_s3 = true; + else + adev->in_s3 = true; r = amdgpu_device_suspend(drm_dev, true); - adev->in_s3 = false; - + if (r) + return r; + if (!adev->in_s0ix) + r = amdgpu_asic_reset(adev); return r; } @@ -2185,6 +2189,8 @@ static int amdgpu_pmops_resume(struct device *dev) r = amdgpu_device_resume(drm_dev, true); if (amdgpu_acpi_is_s0ix_active(adev)) adev->in_s0ix = false; + else + adev->in_s3 = false; return r; } @@ -2249,12 +2255,27 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) if (amdgpu_device_supports_px(drm_dev)) drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + /* + * By setting mp1_state as PP_MP1_STATE_UNLOAD, MP1 will do some + * proper cleanups and put itself into a state ready for PNP. That + * can address some random resuming failure observed on BOCO capable + * platforms. + * TODO: this may be also needed for PX capable platform. + */ + if (amdgpu_device_supports_boco(drm_dev)) + adev->mp1_state = PP_MP1_STATE_UNLOAD; + ret = amdgpu_device_suspend(drm_dev, false); if (ret) { adev->in_runpm = false; + if (amdgpu_device_supports_boco(drm_dev)) + adev->mp1_state = PP_MP1_STATE_NONE; return ret; } + if (amdgpu_device_supports_boco(drm_dev)) + adev->mp1_state = PP_MP1_STATE_NONE; + if (amdgpu_device_supports_px(drm_dev)) { /* Only need to handle PCI state in the driver for ATPX * PCI core handles it for _PR3. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 3b7e86ea7167..9afd11ca2709 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -77,11 +77,13 @@ void amdgpu_fence_slab_fini(void) * Cast helper */ static const struct dma_fence_ops amdgpu_fence_ops; +static const struct dma_fence_ops amdgpu_job_fence_ops; static inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f) { struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base); - if (__f->base.ops == &amdgpu_fence_ops) + if (__f->base.ops == &amdgpu_fence_ops || + __f->base.ops == &amdgpu_job_fence_ops) return __f; return NULL; @@ -158,19 +160,18 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd } seq = ++ring->fence_drv.sync_seq; - if (job != NULL && job->job_run_counter) { + if (job && job->job_run_counter) { /* reinit seq for resubmitted jobs */ fence->seqno = seq; } else { - dma_fence_init(fence, &amdgpu_fence_ops, - &ring->fence_drv.lock, - adev->fence_context + ring->idx, - seq); - } - - if (job != NULL) { - /* mark this fence has a parent job */ - set_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &fence->flags); + if (job) + dma_fence_init(fence, &amdgpu_job_fence_ops, + &ring->fence_drv.lock, + adev->fence_context + ring->idx, seq); + else + dma_fence_init(fence, &amdgpu_fence_ops, + &ring->fence_drv.lock, + adev->fence_context + ring->idx, seq); } amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, @@ -621,6 +622,25 @@ void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev) } /** + * amdgpu_fence_driver_clear_job_fences - clear job embedded fences of ring + * + * @ring: fence of the ring to be cleared + * + */ +void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring) +{ + int i; + struct dma_fence *old, **ptr; + + for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) { + ptr = &ring->fence_drv.fences[i]; + old = rcu_dereference_protected(*ptr, 1); + if (old && old->ops == &amdgpu_job_fence_ops) + RCU_INIT_POINTER(*ptr, NULL); + } +} + +/** * amdgpu_fence_driver_force_completion - force signal latest fence of ring * * @ring: fence of the ring to signal @@ -643,16 +663,14 @@ static const char *amdgpu_fence_get_driver_name(struct dma_fence *fence) static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f) { - struct amdgpu_ring *ring; + return (const char *)to_amdgpu_fence(f)->ring->name; +} - if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) { - struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); +static const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f) +{ + struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); - ring = to_amdgpu_ring(job->base.sched); - } else { - ring = to_amdgpu_fence(f)->ring; - } - return (const char *)ring->name; + return (const char *)to_amdgpu_ring(job->base.sched)->name; } /** @@ -665,18 +683,25 @@ static const char *amdgpu_fence_get_timeline_name(struct dma_fence *f) */ static bool amdgpu_fence_enable_signaling(struct dma_fence *f) { - struct amdgpu_ring *ring; + if (!timer_pending(&to_amdgpu_fence(f)->ring->fence_drv.fallback_timer)) + amdgpu_fence_schedule_fallback(to_amdgpu_fence(f)->ring); - if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) { - struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); + return true; +} - ring = to_amdgpu_ring(job->base.sched); - } else { - ring = to_amdgpu_fence(f)->ring; - } +/** + * amdgpu_job_fence_enable_signaling - enable signalling on job fence + * @f: fence + * + * This is the simliar function with amdgpu_fence_enable_signaling above, it + * only handles the job embedded fence. + */ +static bool amdgpu_job_fence_enable_signaling(struct dma_fence *f) +{ + struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); - if (!timer_pending(&ring->fence_drv.fallback_timer)) - amdgpu_fence_schedule_fallback(ring); + if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer)) + amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched)); return true; } @@ -692,19 +717,23 @@ static void amdgpu_fence_free(struct rcu_head *rcu) { struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); - if (test_bit(AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT, &f->flags)) { - /* free job if fence has a parent job */ - struct amdgpu_job *job; - - job = container_of(f, struct amdgpu_job, hw_fence); - kfree(job); - } else { /* free fence_slab if it's separated fence*/ - struct amdgpu_fence *fence; + kmem_cache_free(amdgpu_fence_slab, to_amdgpu_fence(f)); +} - fence = to_amdgpu_fence(f); - kmem_cache_free(amdgpu_fence_slab, fence); - } +/** + * amdgpu_job_fence_free - free up the job with embedded fence + * + * @rcu: RCU callback head + * + * Free up the job with embedded fence after the RCU grace period. + */ +static void amdgpu_job_fence_free(struct rcu_head *rcu) +{ + struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); + + /* free job if fence has a parent job */ + kfree(container_of(f, struct amdgpu_job, hw_fence)); } /** @@ -720,6 +749,19 @@ static void amdgpu_fence_release(struct dma_fence *f) call_rcu(&f->rcu, amdgpu_fence_free); } +/** + * amdgpu_job_fence_release - callback that job embedded fence can be freed + * + * @f: fence + * + * This is the simliar function with amdgpu_fence_release above, it + * only handles the job embedded fence. + */ +static void amdgpu_job_fence_release(struct dma_fence *f) +{ + call_rcu(&f->rcu, amdgpu_job_fence_free); +} + static const struct dma_fence_ops amdgpu_fence_ops = { .get_driver_name = amdgpu_fence_get_driver_name, .get_timeline_name = amdgpu_fence_get_timeline_name, @@ -727,6 +769,12 @@ static const struct dma_fence_ops amdgpu_fence_ops = { .release = amdgpu_fence_release, }; +static const struct dma_fence_ops amdgpu_job_fence_ops = { + .get_driver_name = amdgpu_fence_get_driver_name, + .get_timeline_name = amdgpu_job_fence_get_timeline_name, + .enable_signaling = amdgpu_job_fence_enable_signaling, + .release = amdgpu_job_fence_release, +}; /* * Fence debugfs diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 7709caeb233d..2a786e788627 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -56,6 +56,9 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev) return true; else return false; + case CHIP_ALDEBARAN: + /* All Aldebaran SKUs have the FRU */ + return true; default: return false; } @@ -88,13 +91,17 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr, int amdgpu_fru_get_product_info(struct amdgpu_device *adev) { - unsigned char buff[34]; + unsigned char buff[AMDGPU_PRODUCT_NAME_LEN+2]; u32 addrptr; int size, len; + int offset = 2; if (!is_fru_eeprom_supported(adev)) return 0; + if (adev->asic_type == CHIP_ALDEBARAN) + offset = 0; + /* If algo exists, it means that the i2c_adapter's initialized */ if (!adev->pm.smu_i2c.algo) { DRM_WARN("Cannot access FRU, EEPROM accessor not initialized"); @@ -131,15 +138,13 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) } len = size; - /* Product name should only be 32 characters. Any more, - * and something could be wrong. Cap it at 32 to be safe - */ - if (len >= sizeof(adev->product_name)) { - DRM_WARN("FRU Product Number is larger than 32 characters. This is likely a mistake"); - len = sizeof(adev->product_name) - 1; + if (len >= AMDGPU_PRODUCT_NAME_LEN) { + DRM_WARN("FRU Product Name is larger than %d characters. This is likely a mistake", + AMDGPU_PRODUCT_NAME_LEN); + len = AMDGPU_PRODUCT_NAME_LEN - 1; } /* Start at 2 due to buff using fields 0 and 1 for the address */ - memcpy(adev->product_name, &buff[2], len); + memcpy(adev->product_name, &buff[offset], len); adev->product_name[len] = '\0'; addrptr += size + 1; @@ -157,7 +162,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) DRM_WARN("FRU Product Number is larger than 16 characters. This is likely a mistake"); len = sizeof(adev->product_number) - 1; } - memcpy(adev->product_number, &buff[2], len); + memcpy(adev->product_number, &buff[offset], len); adev->product_number[len] = '\0'; addrptr += size + 1; @@ -184,7 +189,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) DRM_WARN("FRU Serial Number is larger than 16 characters. This is likely a mistake"); len = sizeof(adev->serial) - 1; } - memcpy(adev->serial, &buff[2], len); + memcpy(adev->serial, &buff[offset], len); adev->serial[len] = '\0'; return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index d3e4203f6217..645950a653a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -114,80 +114,12 @@ void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) */ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) { - int r; - - if (adev->gart.bo == NULL) { - struct amdgpu_bo_param bp; - - memset(&bp, 0, sizeof(bp)); - bp.size = adev->gart.table_size; - bp.byte_align = PAGE_SIZE; - bp.domain = AMDGPU_GEM_DOMAIN_VRAM; - bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | - AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; - bp.type = ttm_bo_type_kernel; - bp.resv = NULL; - bp.bo_ptr_size = sizeof(struct amdgpu_bo); - - r = amdgpu_bo_create(adev, &bp, &adev->gart.bo); - if (r) { - return r; - } - } - return 0; -} - -/** - * amdgpu_gart_table_vram_pin - pin gart page table in vram - * - * @adev: amdgpu_device pointer - * - * Pin the GART page table in vram so it will not be moved - * by the memory manager (pcie r4xx, r5xx+). These asics require the - * gart table to be in video memory. - * Returns 0 for success, error for failure. - */ -int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev) -{ - int r; - - r = amdgpu_bo_reserve(adev->gart.bo, false); - if (unlikely(r != 0)) - return r; - r = amdgpu_bo_pin(adev->gart.bo, AMDGPU_GEM_DOMAIN_VRAM); - if (r) { - amdgpu_bo_unreserve(adev->gart.bo); - return r; - } - r = amdgpu_bo_kmap(adev->gart.bo, &adev->gart.ptr); - if (r) - amdgpu_bo_unpin(adev->gart.bo); - amdgpu_bo_unreserve(adev->gart.bo); - return r; -} - -/** - * amdgpu_gart_table_vram_unpin - unpin gart page table in vram - * - * @adev: amdgpu_device pointer - * - * Unpin the GART page table in vram (pcie r4xx, r5xx+). - * These asics require the gart table to be in video memory. - */ -void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev) -{ - int r; + if (adev->gart.bo != NULL) + return 0; - if (adev->gart.bo == NULL) { - return; - } - r = amdgpu_bo_reserve(adev->gart.bo, true); - if (likely(r == 0)) { - amdgpu_bo_kunmap(adev->gart.bo); - amdgpu_bo_unpin(adev->gart.bo); - amdgpu_bo_unreserve(adev->gart.bo); - adev->gart.ptr = NULL; - } + return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo, + NULL, (void *)&adev->gart.ptr); } /** @@ -201,11 +133,7 @@ void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev) */ void amdgpu_gart_table_vram_free(struct amdgpu_device *adev) { - if (adev->gart.bo == NULL) { - return; - } - amdgpu_bo_unref(&adev->gart.bo); - adev->gart.ptr = NULL; + amdgpu_bo_free_kernel(&adev->gart.bo, NULL, (void *)&adev->gart.ptr); } /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c index 675a72ef305d..72022df264f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c @@ -77,10 +77,8 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - struct ttm_resource_manager *man; - man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); - return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(man)); + return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(&adev->mman.gtt_mgr)); } static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, @@ -206,30 +204,27 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, /** * amdgpu_gtt_mgr_usage - return usage of GTT domain * - * @man: TTM memory type manager + * @mgr: amdgpu_gtt_mgr pointer * * Return how many bytes are used in the GTT domain */ -uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) +uint64_t amdgpu_gtt_mgr_usage(struct amdgpu_gtt_mgr *mgr) { - struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); - return atomic64_read(&mgr->used) * PAGE_SIZE; } /** * amdgpu_gtt_mgr_recover - re-init gart * - * @man: TTM memory type manager + * @mgr: amdgpu_gtt_mgr pointer * * Re-init the gart for each known BO in the GTT. */ -int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) +int amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr) { - struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); - struct amdgpu_device *adev; struct amdgpu_gtt_node *node; struct drm_mm_node *mm_node; + struct amdgpu_device *adev; int r = 0; adev = container_of(mgr, typeof(*adev), mman.gtt_mgr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 651c7abfde03..289521aafb79 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -672,13 +672,13 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ui64 = atomic64_read(&adev->num_vram_cpu_page_faults); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_VRAM_USAGE: - ui64 = amdgpu_vram_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); + ui64 = amdgpu_vram_mgr_usage(&adev->mman.vram_mgr); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_VIS_VRAM_USAGE: - ui64 = amdgpu_vram_mgr_vis_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM)); + ui64 = amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_GTT_USAGE: - ui64 = amdgpu_gtt_mgr_usage(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); + ui64 = amdgpu_gtt_mgr_usage(&adev->mman.gtt_mgr); return copy_to_user(out, &ui64, min(size, 8u)) ? -EFAULT : 0; case AMDGPU_INFO_GDS_CONFIG: { struct drm_amdgpu_info_gds gds_info; @@ -709,8 +709,6 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } case AMDGPU_INFO_MEMORY: { struct drm_amdgpu_memory_info mem; - struct ttm_resource_manager *vram_man = - ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); struct ttm_resource_manager *gtt_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); memset(&mem, 0, sizeof(mem)); @@ -719,7 +717,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) atomic64_read(&adev->vram_pin_size) - AMDGPU_VM_RESERVED_VRAM; mem.vram.heap_usage = - amdgpu_vram_mgr_usage(vram_man); + amdgpu_vram_mgr_usage(&adev->mman.vram_mgr); mem.vram.max_allocation = mem.vram.usable_heap_size * 3 / 4; mem.cpu_accessible_vram.total_heap_size = @@ -729,7 +727,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) atomic64_read(&adev->visible_pin_size), mem.vram.usable_heap_size); mem.cpu_accessible_vram.heap_usage = - amdgpu_vram_mgr_vis_usage(vram_man); + amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr); mem.cpu_accessible_vram.max_allocation = mem.cpu_accessible_vram.usable_heap_size * 3 / 4; @@ -738,7 +736,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) mem.gtt.usable_heap_size = mem.gtt.total_heap_size - atomic64_read(&adev->gart_pin_size); mem.gtt.heap_usage = - amdgpu_gtt_mgr_usage(gtt_man); + amdgpu_gtt_mgr_usage(&adev->mman.gtt_mgr); mem.gtt.max_allocation = mem.gtt.usable_heap_size * 3 / 4; return copy_to_user(out, &mem, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 3a7b56e57cec..5661b82d84d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <linux/dma-buf.h> +#include <drm/drm_drv.h> #include <drm/amdgpu_drm.h> #include <drm/drm_cache.h> #include "amdgpu.h" @@ -1061,7 +1062,18 @@ int amdgpu_bo_init(struct amdgpu_device *adev) */ void amdgpu_bo_fini(struct amdgpu_device *adev) { + int idx; + amdgpu_ttm_fini(adev); + + if (drm_dev_enter(adev_to_drm(adev), &idx)) { + + if (!adev->gmc.xgmi.connected_to_cpu) { + arch_phys_wc_del(adev->gmc.vram_mtrr); + arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); + } + drm_dev_exit(idx); + } } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index cd9e5914944b..586a30ad13e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1592,6 +1592,7 @@ static void amdgpu_ras_interrupt_handler(struct ras_manager *obj) /* Let IP handle its data, maybe we need get the output * from the callback to udpate the error type/count, etc */ + memset(&err_data, 0, sizeof(err_data)); ret = data->cb(obj->adev, &err_data, &entry); /* ue will trigger an interrupt, and in that case * we need do a reset to recovery the whole system. @@ -1838,8 +1839,7 @@ static int amdgpu_ras_badpages_read(struct amdgpu_device *adev, .size = AMDGPU_GPU_PAGE_SIZE, .flags = AMDGPU_RAS_RETIRE_PAGE_RESERVED, }; - status = amdgpu_vram_mgr_query_page_status( - ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM), + status = amdgpu_vram_mgr_query_page_status(&adev->mman.vram_mgr, data->bps[i].retired_page); if (status == -EBUSY) (*bps)[i].flags = AMDGPU_RAS_RETIRE_PAGE_PENDING; @@ -1940,8 +1940,7 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, goto out; } - amdgpu_vram_mgr_reserve_range( - ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM), + amdgpu_vram_mgr_reserve_range(&adev->mman.vram_mgr, bps[i].retired_page << AMDGPU_GPU_PAGE_SHIFT, AMDGPU_GPU_PAGE_SIZE); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 4d380e79752c..fae7d185ad0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -53,9 +53,6 @@ enum amdgpu_ring_priority_level { #define AMDGPU_FENCE_FLAG_INT (1 << 1) #define AMDGPU_FENCE_FLAG_TC_WB_ONLY (1 << 2) -/* fence flag bit to indicate the face is embedded in job*/ -#define AMDGPU_FENCE_FLAG_EMBED_IN_JOB_BIT (DMA_FENCE_FLAG_USER_BITS + 1) - #define to_amdgpu_ring(s) container_of((s), struct amdgpu_ring, sched) #define AMDGPU_IB_POOL_SIZE (1024 * 1024) @@ -114,6 +111,7 @@ struct amdgpu_fence_driver { struct dma_fence **fences; }; +void amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring); void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring); int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index fb0d8bffdce2..5c3f24069f2a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -43,6 +43,7 @@ #include <linux/sizes.h> #include <linux/module.h> +#include <drm/drm_drv.h> #include <drm/ttm/ttm_bo_api.h> #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_placement.h> @@ -1804,6 +1805,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) */ void amdgpu_ttm_fini(struct amdgpu_device *adev) { + int idx; if (!adev->mman.initialized) return; @@ -1818,6 +1820,15 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) NULL, NULL); amdgpu_ttm_fw_reserve_vram_fini(adev); + if (drm_dev_enter(adev_to_drm(adev), &idx)) { + + if (adev->mman.aper_base_kaddr) + iounmap(adev->mman.aper_base_kaddr); + adev->mman.aper_base_kaddr = NULL; + + drm_dev_exit(idx); + } + amdgpu_vram_mgr_fini(adev); amdgpu_gtt_mgr_fini(adev); amdgpu_preempt_mgr_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 7346ecff4438..f8f48be16d80 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -114,8 +114,8 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev); void amdgpu_vram_mgr_fini(struct amdgpu_device *adev); bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem); -uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man); -int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man); +uint64_t amdgpu_gtt_mgr_usage(struct amdgpu_gtt_mgr *mgr); +int amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr); uint64_t amdgpu_preempt_mgr_usage(struct ttm_resource_manager *man); @@ -129,11 +129,11 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev, void amdgpu_vram_mgr_free_sgt(struct device *dev, enum dma_data_direction dir, struct sg_table *sgt); -uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man); -uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man); -int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man, +uint64_t amdgpu_vram_mgr_usage(struct amdgpu_vram_mgr *mgr); +uint64_t amdgpu_vram_mgr_vis_usage(struct amdgpu_vram_mgr *mgr); +int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr, uint64_t start, uint64_t size); -int amdgpu_vram_mgr_query_page_status(struct ttm_resource_manager *man, +int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr, uint64_t start); int amdgpu_ttm_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index 6e4bea012ea4..46264a4002f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -23,74 +23,10 @@ #include "amdgpu_ras.h" -int amdgpu_umc_ras_late_init(struct amdgpu_device *adev) -{ - int r; - struct ras_fs_if fs_info = { - .sysfs_name = "umc_err_count", - }; - struct ras_ih_if ih_info = { - .cb = amdgpu_umc_process_ras_data_cb, - }; - - if (!adev->umc.ras_if) { - adev->umc.ras_if = - kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); - if (!adev->umc.ras_if) - return -ENOMEM; - adev->umc.ras_if->block = AMDGPU_RAS_BLOCK__UMC; - adev->umc.ras_if->type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; - adev->umc.ras_if->sub_block_index = 0; - } - ih_info.head = fs_info.head = *adev->umc.ras_if; - - r = amdgpu_ras_late_init(adev, adev->umc.ras_if, - &fs_info, &ih_info); - if (r) - goto free; - - if (amdgpu_ras_is_supported(adev, adev->umc.ras_if->block)) { - r = amdgpu_irq_get(adev, &adev->gmc.ecc_irq, 0); - if (r) - goto late_fini; - } else { - r = 0; - goto free; - } - - /* ras init of specific umc version */ - if (adev->umc.ras_funcs && - adev->umc.ras_funcs->err_cnt_init) - adev->umc.ras_funcs->err_cnt_init(adev); - - return 0; - -late_fini: - amdgpu_ras_late_fini(adev, adev->umc.ras_if, &ih_info); -free: - kfree(adev->umc.ras_if); - adev->umc.ras_if = NULL; - return r; -} - -void amdgpu_umc_ras_fini(struct amdgpu_device *adev) -{ - if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC) && - adev->umc.ras_if) { - struct ras_common_if *ras_if = adev->umc.ras_if; - struct ras_ih_if ih_info = { - .head = *ras_if, - .cb = amdgpu_umc_process_ras_data_cb, - }; - - amdgpu_ras_late_fini(adev, ras_if, &ih_info); - kfree(ras_if); - } -} - -int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, +static int amdgpu_umc_do_page_retirement(struct amdgpu_device *adev, void *ras_error_status, - struct amdgpu_iv_entry *entry) + struct amdgpu_iv_entry *entry, + bool reset) { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -164,13 +100,108 @@ int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, adev->smu.ppt_funcs->send_hbm_bad_pages_num(&adev->smu, con->eeprom_control.ras_num_recs); } - amdgpu_ras_reset_gpu(adev); + if (reset) + amdgpu_ras_reset_gpu(adev); } kfree(err_data->err_addr); return AMDGPU_RAS_SUCCESS; } +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, + void *ras_error_status, + bool reset) +{ + int ret; + struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; + struct ras_common_if head = { + .block = AMDGPU_RAS_BLOCK__UMC, + }; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head); + + ret = + amdgpu_umc_do_page_retirement(adev, ras_error_status, NULL, reset); + + if (ret == AMDGPU_RAS_SUCCESS && obj) { + obj->err_data.ue_count += err_data->ue_count; + obj->err_data.ce_count += err_data->ce_count; + } + + return ret; +} + +static int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, + void *ras_error_status, + struct amdgpu_iv_entry *entry) +{ + return amdgpu_umc_do_page_retirement(adev, ras_error_status, entry, true); +} + +int amdgpu_umc_ras_late_init(struct amdgpu_device *adev) +{ + int r; + struct ras_fs_if fs_info = { + .sysfs_name = "umc_err_count", + }; + struct ras_ih_if ih_info = { + .cb = amdgpu_umc_process_ras_data_cb, + }; + + if (!adev->umc.ras_if) { + adev->umc.ras_if = + kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); + if (!adev->umc.ras_if) + return -ENOMEM; + adev->umc.ras_if->block = AMDGPU_RAS_BLOCK__UMC; + adev->umc.ras_if->type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; + adev->umc.ras_if->sub_block_index = 0; + } + ih_info.head = fs_info.head = *adev->umc.ras_if; + + r = amdgpu_ras_late_init(adev, adev->umc.ras_if, + &fs_info, &ih_info); + if (r) + goto free; + + if (amdgpu_ras_is_supported(adev, adev->umc.ras_if->block)) { + r = amdgpu_irq_get(adev, &adev->gmc.ecc_irq, 0); + if (r) + goto late_fini; + } else { + r = 0; + goto free; + } + + /* ras init of specific umc version */ + if (adev->umc.ras_funcs && + adev->umc.ras_funcs->err_cnt_init) + adev->umc.ras_funcs->err_cnt_init(adev); + + return 0; + +late_fini: + amdgpu_ras_late_fini(adev, adev->umc.ras_if, &ih_info); +free: + kfree(adev->umc.ras_if); + adev->umc.ras_if = NULL; + return r; +} + +void amdgpu_umc_ras_fini(struct amdgpu_device *adev) +{ + if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC) && + adev->umc.ras_if) { + struct ras_common_if *ras_if = adev->umc.ras_if; + struct ras_ih_if ih_info = { + .head = *ras_if, + .cb = amdgpu_umc_process_ras_data_cb, + }; + + amdgpu_ras_late_fini(adev, ras_if, &ih_info); + kfree(ras_if); + } +} + int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 9e40bade0a68..b72194e8bfe5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -78,9 +78,9 @@ struct amdgpu_umc { int amdgpu_umc_ras_late_init(struct amdgpu_device *adev); void amdgpu_umc_ras_fini(struct amdgpu_device *adev); -int amdgpu_umc_process_ras_data_cb(struct amdgpu_device *adev, +int amdgpu_umc_poison_handler(struct amdgpu_device *adev, void *ras_error_status, - struct amdgpu_iv_entry *entry); + bool reset); int amdgpu_umc_process_ecc_irq(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 3fc49823f527..894444ab0032 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -553,7 +553,6 @@ static void amdgpu_virt_populate_vf2pf_ucode_info(struct amdgpu_device *adev) static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev) { struct amd_sriov_msg_vf2pf_info *vf2pf_info; - struct ttm_resource_manager *vram_man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); vf2pf_info = (struct amd_sriov_msg_vf2pf_info *) adev->virt.fw_reserve.p_vf2pf; @@ -576,8 +575,8 @@ static int amdgpu_virt_write_vf2pf_data(struct amdgpu_device *adev) vf2pf_info->driver_cert = 0; vf2pf_info->os_info.all = 0; - vf2pf_info->fb_usage = amdgpu_vram_mgr_usage(vram_man) >> 20; - vf2pf_info->fb_vis_usage = amdgpu_vram_mgr_vis_usage(vram_man) >> 20; + vf2pf_info->fb_usage = amdgpu_vram_mgr_usage(&adev->mman.vram_mgr) >> 20; + vf2pf_info->fb_vis_usage = amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr) >> 20; vf2pf_info->fb_size = adev->gmc.real_vram_size >> 20; vf2pf_info->fb_vis_size = adev->gmc.visible_vram_size >> 20; @@ -622,19 +621,37 @@ void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev) void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) { - uint64_t bp_block_offset = 0; - uint32_t bp_block_size = 0; - struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL; - adev->virt.fw_reserve.p_pf2vf = NULL; adev->virt.fw_reserve.p_vf2pf = NULL; adev->virt.vf2pf_update_interval_ms = 0; - if (adev->mman.fw_vram_usage_va != NULL) { + if (adev->bios != NULL) { adev->virt.vf2pf_update_interval_ms = 2000; adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) + (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); + + amdgpu_virt_read_pf2vf_data(adev); + } + + if (adev->virt.vf2pf_update_interval_ms != 0) { + INIT_DELAYED_WORK(&adev->virt.vf2pf_work, amdgpu_virt_update_vf2pf_work_item); + schedule_delayed_work(&(adev->virt.vf2pf_work), msecs_to_jiffies(adev->virt.vf2pf_update_interval_ms)); + } +} + + +void amdgpu_virt_exchange_data(struct amdgpu_device *adev) +{ + uint64_t bp_block_offset = 0; + uint32_t bp_block_size = 0; + struct amd_sriov_msg_pf2vf_info *pf2vf_v2 = NULL; + + if (adev->mman.fw_vram_usage_va != NULL) { + + adev->virt.fw_reserve.p_pf2vf = + (struct amd_sriov_msg_pf2vf_info_header *) (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) @@ -663,16 +680,10 @@ void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev) (adev->bios + (AMD_SRIOV_MSG_PF2VF_OFFSET_KB << 10)); amdgpu_virt_read_pf2vf_data(adev); - - return; - } - - if (adev->virt.vf2pf_update_interval_ms != 0) { - INIT_DELAYED_WORK(&adev->virt.vf2pf_work, amdgpu_virt_update_vf2pf_work_item); - schedule_delayed_work(&(adev->virt.vf2pf_work), adev->virt.vf2pf_update_interval_ms); } } + void amdgpu_detect_virtualization(struct amdgpu_device *adev) { uint32_t reg; @@ -715,6 +726,10 @@ void amdgpu_detect_virtualization(struct amdgpu_device *adev) vi_set_virt_ops(adev); break; case CHIP_VEGA10: + soc15_set_virt_ops(adev); + /* send a dummy GPU_INIT_DATA request to host on vega10 */ + amdgpu_virt_request_init_data(adev); + break; case CHIP_VEGA20: case CHIP_ARCTURUS: case CHIP_ALDEBARAN: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index 8d4c20bb71c5..9adfb8d63280 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -308,6 +308,7 @@ int amdgpu_virt_alloc_mm_table(struct amdgpu_device *adev); void amdgpu_virt_free_mm_table(struct amdgpu_device *adev); void amdgpu_virt_release_ras_err_handler_data(struct amdgpu_device *adev); void amdgpu_virt_init_data_exchange(struct amdgpu_device *adev); +void amdgpu_virt_exchange_data(struct amdgpu_device *adev); void amdgpu_virt_fini_data_exchange(struct amdgpu_device *adev); void amdgpu_detect_virtualization(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index 2dcc68e04e84..d99c8779b51e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -144,15 +144,16 @@ static void amdgpu_vkms_crtc_atomic_disable(struct drm_crtc *crtc, static void amdgpu_vkms_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) { + unsigned long flags; if (crtc->state->event) { - spin_lock(&crtc->dev->event_lock); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (drm_crtc_vblank_get(crtc) != 0) drm_crtc_send_vblank_event(crtc, crtc->state->event); else drm_crtc_arm_vblank_event(crtc, crtc->state->event); - spin_unlock(&crtc->dev->event_lock); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); crtc->state->event = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 7b2b0980ec41..7a2b487db57c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -96,10 +96,9 @@ static ssize_t amdgpu_mem_info_vram_used_show(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - struct ttm_resource_manager *man; - man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); - return sysfs_emit(buf, "%llu\n", amdgpu_vram_mgr_usage(man)); + return sysfs_emit(buf, "%llu\n", + amdgpu_vram_mgr_usage(&adev->mman.vram_mgr)); } /** @@ -116,10 +115,9 @@ static ssize_t amdgpu_mem_info_vis_vram_used_show(struct device *dev, { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - struct ttm_resource_manager *man; - man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM); - return sysfs_emit(buf, "%llu\n", amdgpu_vram_mgr_vis_usage(man)); + return sysfs_emit(buf, "%llu\n", + amdgpu_vram_mgr_vis_usage(&adev->mman.vram_mgr)); } /** @@ -263,16 +261,15 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man) /** * amdgpu_vram_mgr_reserve_range - Reserve a range from VRAM * - * @man: TTM memory type manager + * @mgr: amdgpu_vram_mgr pointer * @start: start address of the range in VRAM * @size: size of the range * - * Reserve memory from start addess with the specified size in VRAM + * Reserve memory from start address with the specified size in VRAM */ -int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man, +int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr, uint64_t start, uint64_t size) { - struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); struct amdgpu_vram_reservation *rsv; rsv = kzalloc(sizeof(*rsv), GFP_KERNEL); @@ -285,7 +282,7 @@ int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man, spin_lock(&mgr->lock); list_add_tail(&mgr->reservations_pending, &rsv->node); - amdgpu_vram_mgr_do_reserve(man); + amdgpu_vram_mgr_do_reserve(&mgr->manager); spin_unlock(&mgr->lock); return 0; @@ -294,7 +291,7 @@ int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man, /** * amdgpu_vram_mgr_query_page_status - query the reservation status * - * @man: TTM memory type manager + * @mgr: amdgpu_vram_mgr pointer * @start: start address of a page in VRAM * * Returns: @@ -302,10 +299,9 @@ int amdgpu_vram_mgr_reserve_range(struct ttm_resource_manager *man, * 0: the page has been reserved * -ENOENT: the input page is not a reservation */ -int amdgpu_vram_mgr_query_page_status(struct ttm_resource_manager *man, +int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr, uint64_t start) { - struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); struct amdgpu_vram_reservation *rsv; int ret; @@ -632,28 +628,24 @@ void amdgpu_vram_mgr_free_sgt(struct device *dev, /** * amdgpu_vram_mgr_usage - how many bytes are used in this domain * - * @man: TTM memory type manager + * @mgr: amdgpu_vram_mgr pointer * * Returns how many bytes are used in this domain. */ -uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man) +uint64_t amdgpu_vram_mgr_usage(struct amdgpu_vram_mgr *mgr) { - struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); - return atomic64_read(&mgr->usage); } /** * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part * - * @man: TTM memory type manager + * @mgr: amdgpu_vram_mgr pointer * * Returns how many bytes are used in the visible part of VRAM */ -uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_resource_manager *man) +uint64_t amdgpu_vram_mgr_vis_usage(struct amdgpu_vram_mgr *mgr) { - struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); - return atomic64_read(&mgr->vis_usage); } @@ -675,8 +667,8 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man, spin_unlock(&mgr->lock); drm_printf(printer, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n", - man->size, amdgpu_vram_mgr_usage(man) >> 20, - amdgpu_vram_mgr_vis_usage(man) >> 20); + man->size, amdgpu_vram_mgr_usage(mgr) >> 20, + amdgpu_vram_mgr_vis_usage(mgr) >> 20); } static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index a38c6a747fa4..e8b8f28c2f72 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -208,6 +208,7 @@ static struct attribute *amdgpu_xgmi_hive_attrs[] = { &amdgpu_xgmi_hive_id, NULL }; +ATTRIBUTE_GROUPS(amdgpu_xgmi_hive); static ssize_t amdgpu_xgmi_show_attrs(struct kobject *kobj, struct attribute *attr, char *buf) @@ -237,7 +238,7 @@ static const struct sysfs_ops amdgpu_xgmi_hive_ops = { struct kobj_type amdgpu_xgmi_hive_type = { .release = amdgpu_xgmi_hive_release, .sysfs_ops = &amdgpu_xgmi_hive_ops, - .default_attrs = amdgpu_xgmi_hive_attrs, + .default_groups = amdgpu_xgmi_hive_groups, }; static ssize_t amdgpu_xgmi_show_device_id(struct device *dev, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index edb3e3b08eed..9189fb85a4dd 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -63,6 +63,13 @@ #define mmGCEA_PROBE_MAP 0x070c #define mmGCEA_PROBE_MAP_BASE_IDX 0 +#define GFX9_RLCG_GC_WRITE_OLD (0x8 << 28) +#define GFX9_RLCG_GC_WRITE (0x0 << 28) +#define GFX9_RLCG_GC_READ (0x1 << 28) +#define GFX9_RLCG_VFGATE_DISABLED 0x4000000 +#define GFX9_RLCG_WRONG_OPERATION_TYPE 0x2000000 +#define GFX9_RLCG_NOT_IN_RANGE 0x1000000 + MODULE_FIRMWARE("amdgpu/vega10_ce.bin"); MODULE_FIRMWARE("amdgpu/vega10_pfp.bin"); MODULE_FIRMWARE("amdgpu/vega10_me.bin"); @@ -739,7 +746,7 @@ static const u32 GFX_RLC_SRM_INDEX_CNTL_DATA_OFFSETS[] = mmRLC_SRM_INDEX_CNTL_DATA_7 - mmRLC_SRM_INDEX_CNTL_DATA_0, }; -static void gfx_v9_0_rlcg_w(struct amdgpu_device *adev, u32 offset, u32 v, u32 flag) +static u32 gfx_v9_0_rlcg_rw(struct amdgpu_device *adev, u32 offset, u32 v, uint32_t flag) { static void *scratch_reg0; static void *scratch_reg1; @@ -748,21 +755,20 @@ static void gfx_v9_0_rlcg_w(struct amdgpu_device *adev, u32 offset, u32 v, u32 f static void *spare_int; static uint32_t grbm_cntl; static uint32_t grbm_idx; + uint32_t i = 0; + uint32_t retries = 50000; + u32 ret = 0; + u32 tmp; scratch_reg0 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG0_BASE_IDX] + mmSCRATCH_REG0)*4; scratch_reg1 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG1)*4; - scratch_reg2 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG2)*4; - scratch_reg3 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG1_BASE_IDX] + mmSCRATCH_REG3)*4; + scratch_reg2 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG2_BASE_IDX] + mmSCRATCH_REG2)*4; + scratch_reg3 = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmSCRATCH_REG3_BASE_IDX] + mmSCRATCH_REG3)*4; spare_int = adev->rmmio + (adev->reg_offset[GC_HWIP][0][mmRLC_SPARE_INT_BASE_IDX] + mmRLC_SPARE_INT)*4; grbm_cntl = adev->reg_offset[GC_HWIP][0][mmGRBM_GFX_CNTL_BASE_IDX] + mmGRBM_GFX_CNTL; grbm_idx = adev->reg_offset[GC_HWIP][0][mmGRBM_GFX_INDEX_BASE_IDX] + mmGRBM_GFX_INDEX; - if (amdgpu_sriov_runtime(adev)) { - pr_err("shouldn't call rlcg write register during runtime\n"); - return; - } - if (offset == grbm_cntl || offset == grbm_idx) { if (offset == grbm_cntl) writel(v, scratch_reg2); @@ -771,41 +777,95 @@ static void gfx_v9_0_rlcg_w(struct amdgpu_device *adev, u32 offset, u32 v, u32 f writel(v, ((void __iomem *)adev->rmmio) + (offset * 4)); } else { - uint32_t i = 0; - uint32_t retries = 50000; - + /* + * SCRATCH_REG0 = read/write value + * SCRATCH_REG1[30:28] = command + * SCRATCH_REG1[19:0] = address in dword + * SCRATCH_REG1[26:24] = Error reporting + */ writel(v, scratch_reg0); - writel(offset | 0x80000000, scratch_reg1); + writel(offset | flag, scratch_reg1); writel(1, spare_int); - for (i = 0; i < retries; i++) { - u32 tmp; + for (i = 0; i < retries; i++) { tmp = readl(scratch_reg1); - if (!(tmp & 0x80000000)) + if (!(tmp & flag)) break; udelay(10); } - if (i >= retries) - pr_err("timeout: rlcg program reg:0x%05x failed !\n", offset); + + if (i >= retries) { + if (amdgpu_sriov_reg_indirect_gc(adev)) { + if (tmp & GFX9_RLCG_VFGATE_DISABLED) + pr_err("The vfgate is disabled, program reg:0x%05x failed!\n", offset); + else if (tmp & GFX9_RLCG_WRONG_OPERATION_TYPE) + pr_err("Wrong operation type, program reg:0x%05x failed!\n", offset); + else if (tmp & GFX9_RLCG_NOT_IN_RANGE) + pr_err("The register is not in range, program reg:0x%05x failed!\n", offset); + else + pr_err("Unknown error type, program reg:0x%05x failed!\n", offset); + } else + pr_err("timeout: rlcg program reg:0x%05x failed!\n", offset); + } } + ret = readl(scratch_reg0); + + return ret; +} + +static bool gfx_v9_0_get_rlcg_flag(struct amdgpu_device *adev, u32 acc_flags, u32 hwip, + int write, u32 *rlcg_flag) +{ + + switch (hwip) { + case GC_HWIP: + if (amdgpu_sriov_reg_indirect_gc(adev)) { + *rlcg_flag = write ? GFX9_RLCG_GC_WRITE : GFX9_RLCG_GC_READ; + + return true; + /* only in new version, AMDGPU_REGS_NO_KIQ and AMDGPU_REGS_RLC enabled simultaneously */ + } else if ((acc_flags & AMDGPU_REGS_RLC) && !(acc_flags & AMDGPU_REGS_NO_KIQ) && write) { + *rlcg_flag = GFX9_RLCG_GC_WRITE_OLD; + return true; + } + + break; + default: + return false; + } + + return false; +} + +static u32 gfx_v9_0_sriov_rreg(struct amdgpu_device *adev, u32 offset, u32 acc_flags, u32 hwip) +{ + u32 rlcg_flag; + + if (!amdgpu_sriov_runtime(adev) && gfx_v9_0_get_rlcg_flag(adev, acc_flags, hwip, 0, &rlcg_flag)) + return gfx_v9_0_rlcg_rw(adev, offset, 0, rlcg_flag); + + if (acc_flags & AMDGPU_REGS_NO_KIQ) + return RREG32_NO_KIQ(offset); + else + return RREG32(offset); } static void gfx_v9_0_sriov_wreg(struct amdgpu_device *adev, u32 offset, - u32 v, u32 acc_flags, u32 hwip) + u32 value, u32 acc_flags, u32 hwip) { - if ((acc_flags & AMDGPU_REGS_RLC) && - amdgpu_sriov_fullaccess(adev)) { - gfx_v9_0_rlcg_w(adev, offset, v, acc_flags); + u32 rlcg_flag; + if (!amdgpu_sriov_runtime(adev) && gfx_v9_0_get_rlcg_flag(adev, acc_flags, hwip, 1, &rlcg_flag)) { + gfx_v9_0_rlcg_rw(adev, offset, value, rlcg_flag); return; } if (acc_flags & AMDGPU_REGS_NO_KIQ) - WREG32_NO_KIQ(offset, v); + WREG32_NO_KIQ(offset, value); else - WREG32(offset, v); + WREG32(offset, value); } #define VEGA10_GB_ADDR_CONFIG_GOLDEN 0x2a114042 @@ -5135,7 +5195,7 @@ static void gfx_v9_0_update_spm_vmid(struct amdgpu_device *adev, unsigned vmid) if (amdgpu_sriov_is_pp_one_vf(adev)) data = RREG32_NO_KIQ(reg); else - data = RREG32(reg); + data = RREG32_SOC15(GC, 0, mmRLC_SPM_MC_CNTL); data &= ~RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK; data |= (vmid & RLC_SPM_MC_CNTL__RLC_SPM_VMID_MASK) << RLC_SPM_MC_CNTL__RLC_SPM_VMID__SHIFT; @@ -5191,6 +5251,7 @@ static const struct amdgpu_rlc_funcs gfx_v9_0_rlc_funcs = { .start = gfx_v9_0_rlc_start, .update_spm_vmid = gfx_v9_0_update_spm_vmid, .sriov_wreg = gfx_v9_0_sriov_wreg, + .sriov_rreg = gfx_v9_0_sriov_rreg, .is_rlcg_access_range = gfx_v9_0_is_rlcg_access_range, }; @@ -5796,16 +5857,16 @@ static void gfx_v9_0_set_compute_eop_interrupt_state(struct amdgpu_device *adev, switch (state) { case AMDGPU_IRQ_STATE_DISABLE: - mec_int_cntl = RREG32(mec_int_cntl_reg); + mec_int_cntl = RREG32_SOC15_IP(GC,mec_int_cntl_reg); mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL, TIME_STAMP_INT_ENABLE, 0); - WREG32(mec_int_cntl_reg, mec_int_cntl); + WREG32_SOC15_IP(GC, mec_int_cntl_reg, mec_int_cntl); break; case AMDGPU_IRQ_STATE_ENABLE: - mec_int_cntl = RREG32(mec_int_cntl_reg); + mec_int_cntl = RREG32_SOC15_IP(GC, mec_int_cntl_reg); mec_int_cntl = REG_SET_FIELD(mec_int_cntl, CP_ME1_PIPE0_INT_CNTL, TIME_STAMP_INT_ENABLE, 1); - WREG32(mec_int_cntl_reg, mec_int_cntl); + WREG32_SOC15_IP(GC, mec_int_cntl_reg, mec_int_cntl); break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index ae46eb35b3d7..38bb42727715 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -914,12 +914,6 @@ static int gmc_v10_0_sw_init(void *handle) return r; } - if (adev->gmc.xgmi.supported) { - r = adev->gfxhub.funcs->get_xgmi_info(adev); - if (r) - return r; - } - r = gmc_v10_0_mc_init(adev); if (r) return r; @@ -995,7 +989,7 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) goto skip_pin_bo; - r = amdgpu_gart_table_vram_pin(adev); + r = amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); if (r) return r; @@ -1066,7 +1060,6 @@ static void gmc_v10_0_gart_disable(struct amdgpu_device *adev) { adev->gfxhub.funcs->gart_disable(adev); adev->mmhub.funcs->gart_disable(adev); - amdgpu_gart_table_vram_unpin(adev); } static int gmc_v10_0_hw_fini(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 0fe714f54cca..cd6c38e083d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -476,7 +476,7 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } - r = amdgpu_gart_table_vram_pin(adev); + r = amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); if (r) return r; @@ -608,7 +608,6 @@ static void gmc_v6_0_gart_disable(struct amdgpu_device *adev) WREG32(mmVM_L2_CNTL3, VM_L2_CNTL3__L2_CACHE_BIGK_ASSOCIATIVITY_MASK | (0UL << VM_L2_CNTL3__L2_CACHE_BIGK_FRAGMENT_SIZE__SHIFT)); - amdgpu_gart_table_vram_unpin(adev); } static void gmc_v6_0_vm_decode_fault(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 0a50fdaced7e..ab8adbff9e2d 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -620,7 +620,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } - r = amdgpu_gart_table_vram_pin(adev); + r = amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); if (r) return r; @@ -758,7 +758,6 @@ static void gmc_v7_0_gart_disable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_CACHE, 0); WREG32(mmVM_L2_CNTL, tmp); WREG32(mmVM_L2_CNTL2, 0); - amdgpu_gart_table_vram_unpin(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 492ebed2915b..054733838292 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -515,10 +515,10 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) static int gmc_v8_0_mc_init(struct amdgpu_device *adev) { int r; + u32 tmp; adev->gmc.vram_width = amdgpu_atombios_get_vram_width(adev); if (!adev->gmc.vram_width) { - u32 tmp; int chansize, numchan; /* Get VRAM informations */ @@ -562,8 +562,15 @@ static int gmc_v8_0_mc_init(struct amdgpu_device *adev) adev->gmc.vram_width = numchan * chansize; } /* size in MB on si */ - adev->gmc.mc_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; - adev->gmc.real_vram_size = RREG32(mmCONFIG_MEMSIZE) * 1024ULL * 1024ULL; + tmp = RREG32(mmCONFIG_MEMSIZE); + /* some boards may have garbage in the upper 16 bits */ + if (tmp & 0xffff0000) { + DRM_INFO("Probable bad vram size: 0x%08x\n", tmp); + if (tmp & 0xffff) + tmp &= 0xffff; + } + adev->gmc.mc_vram_size = tmp * 1024ULL * 1024ULL; + adev->gmc.real_vram_size = adev->gmc.mc_vram_size; if (!(adev->flags & AMD_IS_APU)) { r = amdgpu_device_resize_fb_bar(adev); @@ -837,7 +844,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) dev_err(adev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } - r = amdgpu_gart_table_vram_pin(adev); + r = amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); if (r) return r; @@ -992,7 +999,6 @@ static void gmc_v8_0_gart_disable(struct amdgpu_device *adev) tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_CACHE, 0); WREG32(mmVM_L2_CNTL, tmp); WREG32(mmVM_L2_CNTL2, 0); - amdgpu_gart_table_vram_unpin(adev); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index a5471923b3f6..88c1eb9ad068 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -72,6 +72,9 @@ #define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0 0x049d #define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX 2 +#define mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_DCN2 0x05ea +#define mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_DCN2_BASE_IDX 2 + static const char *gfxhub_client_ids[] = { "CB", @@ -478,9 +481,18 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev, hub = &adev->vmhub[j]; for (i = 0; i < 16; i++) { reg = hub->vm_context0_cntl + i; - tmp = RREG32(reg); + + if (j == AMDGPU_GFXHUB_0) + tmp = RREG32_SOC15_IP(GC, reg); + else + tmp = RREG32_SOC15_IP(MMHUB, reg); + tmp &= ~bits; - WREG32(reg, tmp); + + if (j == AMDGPU_GFXHUB_0) + WREG32_SOC15_IP(GC, reg, tmp); + else + WREG32_SOC15_IP(MMHUB, reg, tmp); } } break; @@ -489,9 +501,18 @@ static int gmc_v9_0_vm_fault_interrupt_state(struct amdgpu_device *adev, hub = &adev->vmhub[j]; for (i = 0; i < 16; i++) { reg = hub->vm_context0_cntl + i; - tmp = RREG32(reg); + + if (j == AMDGPU_GFXHUB_0) + tmp = RREG32_SOC15_IP(GC, reg); + else + tmp = RREG32_SOC15_IP(MMHUB, reg); + tmp |= bits; - WREG32(reg, tmp); + + if (j == AMDGPU_GFXHUB_0) + WREG32_SOC15_IP(GC, reg, tmp); + else + WREG32_SOC15_IP(MMHUB, reg, tmp); } } break; @@ -788,9 +809,12 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ if (use_semaphore) { for (j = 0; j < adev->usec_timeout; j++) { - /* a read return value of 1 means semaphore acuqire */ - tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_sem + - hub->eng_distance * eng); + /* a read return value of 1 means semaphore acquire */ + if (vmhub == AMDGPU_GFXHUB_0) + tmp = RREG32_SOC15_IP_NO_KIQ(GC, hub->vm_inv_eng0_sem + hub->eng_distance * eng); + else + tmp = RREG32_SOC15_IP_NO_KIQ(MMHUB, hub->vm_inv_eng0_sem + hub->eng_distance * eng); + if (tmp & 0x1) break; udelay(1); @@ -801,8 +825,10 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, } do { - WREG32_NO_KIQ(hub->vm_inv_eng0_req + - hub->eng_distance * eng, inv_req); + if (vmhub == AMDGPU_GFXHUB_0) + WREG32_SOC15_IP_NO_KIQ(GC, hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req); + else + WREG32_SOC15_IP_NO_KIQ(MMHUB, hub->vm_inv_eng0_req + hub->eng_distance * eng, inv_req); /* * Issue a dummy read to wait for the ACK register to @@ -815,8 +841,11 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, hub->eng_distance * eng); for (j = 0; j < adev->usec_timeout; j++) { - tmp = RREG32_NO_KIQ(hub->vm_inv_eng0_ack + - hub->eng_distance * eng); + if (vmhub == AMDGPU_GFXHUB_0) + tmp = RREG32_SOC15_IP_NO_KIQ(GC, hub->vm_inv_eng0_ack + hub->eng_distance * eng); + else + tmp = RREG32_SOC15_IP_NO_KIQ(MMHUB, hub->vm_inv_eng0_ack + hub->eng_distance * eng); + if (tmp & (1 << vmid)) break; udelay(1); @@ -827,13 +856,16 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, } while (inv_req); /* TODO: It needs to continue working on debugging with semaphore for GFXHUB as well. */ - if (use_semaphore) + if (use_semaphore) { /* * add semaphore release after invalidation, * write with 0 means semaphore release */ - WREG32_NO_KIQ(hub->vm_inv_eng0_sem + - hub->eng_distance * eng, 0); + if (vmhub == AMDGPU_GFXHUB_0) + WREG32_SOC15_IP_NO_KIQ(GC, hub->vm_inv_eng0_sem + hub->eng_distance * eng, 0); + else + WREG32_SOC15_IP_NO_KIQ(MMHUB, hub->vm_inv_eng0_sem + hub->eng_distance * eng, 0); + } spin_unlock(&adev->gmc.invalidate_lock); @@ -1105,6 +1137,8 @@ static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev) u32 d1vga_control = RREG32_SOC15(DCE, 0, mmD1VGA_CONTROL); unsigned size; + /* TODO move to DC so GMC doesn't need to hard-code DCN registers */ + if (REG_GET_FIELD(d1vga_control, D1VGA_CONTROL, D1VGA_MODE_ENABLE)) { size = AMDGPU_VBIOS_VGA_ALLOCATION; } else { @@ -1113,7 +1147,6 @@ static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev) switch (adev->ip_versions[DCE_HWIP][0]) { case IP_VERSION(1, 0, 0): case IP_VERSION(1, 0, 1): - case IP_VERSION(2, 1, 0): viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION); size = (REG_GET_FIELD(viewport, HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * @@ -1121,6 +1154,14 @@ static unsigned gmc_v9_0_get_vbios_fb_size(struct amdgpu_device *adev) HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH) * 4); break; + case IP_VERSION(2, 1, 0): + viewport = RREG32_SOC15(DCE, 0, mmHUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_DCN2); + size = (REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT) * + REG_GET_FIELD(viewport, + HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH) * + 4); + break; default: viewport = RREG32_SOC15(DCE, 0, mmSCL0_VIEWPORT_SIZE); size = (REG_GET_FIELD(viewport, SCL0_VIEWPORT_SIZE, VIEWPORT_HEIGHT) * @@ -1599,12 +1640,6 @@ static int gmc_v9_0_sw_init(void *handle) } adev->need_swiotlb = drm_need_swiotlb(44); - if (adev->gmc.xgmi.supported) { - r = adev->gfxhub.funcs->get_xgmi_info(adev); - if (r) - return r; - } - r = gmc_v9_0_mc_init(adev); if (r) return r; @@ -1720,7 +1755,7 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) goto skip_pin_bo; - r = amdgpu_gart_table_vram_pin(adev); + r = amdgpu_gtt_mgr_recover(&adev->mman.gtt_mgr); if (r) return r; @@ -1798,7 +1833,6 @@ static void gmc_v9_0_gart_disable(struct amdgpu_device *adev) { adev->gfxhub.funcs->gart_disable(adev); adev->mmhub.funcs->gart_disable(adev); - amdgpu_gart_table_vram_unpin(adev); } static int gmc_v9_0_hw_fini(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c index 0077e738db31..56da5ab82987 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c @@ -180,6 +180,11 @@ static int xgpu_ai_send_access_requests(struct amdgpu_device *adev, RREG32_NO_KIQ(SOC15_REG_OFFSET(NBIO, 0, mmBIF_BX_PF0_MAILBOX_MSGBUF_RCV_DW2)); } + } else if (req == IDH_REQ_GPU_INIT_DATA){ + /* Dummy REQ_GPU_INIT_DATA handling */ + r = xgpu_ai_poll_msg(adev, IDH_REQ_GPU_INIT_DATA_READY); + /* version set to 0 since dummy */ + adev->virt.req_init_data_ver = 0; } return 0; @@ -381,10 +386,16 @@ void xgpu_ai_mailbox_put_irq(struct amdgpu_device *adev) amdgpu_irq_put(adev, &adev->virt.rcv_irq, 0); } +static int xgpu_ai_request_init_data(struct amdgpu_device *adev) +{ + return xgpu_ai_send_access_requests(adev, IDH_REQ_GPU_INIT_DATA); +} + const struct amdgpu_virt_ops xgpu_ai_virt_ops = { .req_full_gpu = xgpu_ai_request_full_gpu_access, .rel_full_gpu = xgpu_ai_release_full_gpu_access, .reset_gpu = xgpu_ai_request_reset, .wait_reset = NULL, .trans_msg = xgpu_ai_mailbox_trans_msg, + .req_init_data = xgpu_ai_request_init_data, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h index f9aa4d0bb638..fa7e13e0459e 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.h @@ -35,6 +35,7 @@ enum idh_request { IDH_REQ_GPU_FINI_ACCESS, IDH_REL_GPU_FINI_ACCESS, IDH_REQ_GPU_RESET_ACCESS, + IDH_REQ_GPU_INIT_DATA, IDH_LOG_VF_ERROR = 200, IDH_READY_TO_RESET = 201, @@ -48,6 +49,7 @@ enum idh_event { IDH_SUCCESS, IDH_FAIL, IDH_QUERY_ALIVE, + IDH_REQ_GPU_INIT_DATA_READY, IDH_TEXT_MESSAGE = 255, }; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index 2176ef85f137..d0e76b36d4ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -277,13 +277,15 @@ static bool psp_v11_0_is_sos_alive(struct psp_context *psp) return sol_reg != 0x0; } -static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp) +static int psp_v11_0_bootloader_load_component(struct psp_context *psp, + struct psp_bin_desc *bin_desc, + enum psp_bootloader_cmd bl_cmd) { int ret; uint32_t psp_gfxdrv_command_reg = 0; struct amdgpu_device *adev = psp->adev; - /* Check tOS sign of life register to confirm sys driver and sOS + /* Check sOS sign of life register to confirm sys driver and sOS * are already been loaded. */ if (psp_v11_0_is_sos_alive(psp)) @@ -293,13 +295,13 @@ static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp) if (ret) return ret; - /* Copy PSP KDB binary to memory */ - psp_copy_fw(psp, psp->kdb.start_addr, psp->kdb.size_bytes); + /* Copy PSP System Driver binary to memory */ + psp_copy_fw(psp, bin_desc->start_addr, bin_desc->size_bytes); - /* Provide the PSP KDB to bootloader */ + /* Provide the sys driver to bootloader */ WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, (uint32_t)(psp->fw_pri_mc_addr >> 20)); - psp_gfxdrv_command_reg = PSP_BL__LOAD_KEY_DATABASE; + psp_gfxdrv_command_reg = bl_cmd; WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, psp_gfxdrv_command_reg); @@ -308,69 +310,19 @@ static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp) return ret; } -static int psp_v11_0_bootloader_load_spl(struct psp_context *psp) +static int psp_v11_0_bootloader_load_kdb(struct psp_context *psp) { - int ret; - uint32_t psp_gfxdrv_command_reg = 0; - struct amdgpu_device *adev = psp->adev; - - /* Check tOS sign of life register to confirm sys driver and sOS - * are already been loaded. - */ - if (psp_v11_0_is_sos_alive(psp)) - return 0; - - ret = psp_v11_0_wait_for_bootloader(psp); - if (ret) - return ret; - - /* Copy PSP SPL binary to memory */ - psp_copy_fw(psp, psp->spl.start_addr, psp->spl.size_bytes); - - /* Provide the PSP SPL to bootloader */ - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, - (uint32_t)(psp->fw_pri_mc_addr >> 20)); - psp_gfxdrv_command_reg = PSP_BL__LOAD_TOS_SPL_TABLE; - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, - psp_gfxdrv_command_reg); - - ret = psp_v11_0_wait_for_bootloader(psp); + return psp_v11_0_bootloader_load_component(psp, &psp->kdb, PSP_BL__LOAD_KEY_DATABASE); +} - return ret; +static int psp_v11_0_bootloader_load_spl(struct psp_context *psp) +{ + return psp_v11_0_bootloader_load_component(psp, &psp->spl, PSP_BL__LOAD_TOS_SPL_TABLE); } static int psp_v11_0_bootloader_load_sysdrv(struct psp_context *psp) { - int ret; - uint32_t psp_gfxdrv_command_reg = 0; - struct amdgpu_device *adev = psp->adev; - - /* Check sOS sign of life register to confirm sys driver and sOS - * are already been loaded. - */ - if (psp_v11_0_is_sos_alive(psp)) - return 0; - - ret = psp_v11_0_wait_for_bootloader(psp); - if (ret) - return ret; - - /* Copy PSP System Driver binary to memory */ - psp_copy_fw(psp, psp->sys.start_addr, psp->sys.size_bytes); - - /* Provide the sys driver to bootloader */ - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_36, - (uint32_t)(psp->fw_pri_mc_addr >> 20)); - psp_gfxdrv_command_reg = PSP_BL__LOAD_SYSDRV; - WREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_35, - psp_gfxdrv_command_reg); - - /* there might be handshake issue with hardware which needs delay */ - mdelay(20); - - ret = psp_v11_0_wait_for_bootloader(psp); - - return ret; + return psp_v11_0_bootloader_load_component(psp, &psp->sys, PSP_BL__LOAD_SYSDRV); } static int psp_v11_0_bootloader_load_sos(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index 4f546f632223..d3d6d5b045b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -542,9 +542,6 @@ static void sdma_v5_2_ctx_switch_enable(struct amdgpu_device *adev, bool enable) } for (i = 0; i < adev->sdma.num_instances; i++) { - f32_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); - f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, - AUTO_CTXSW_ENABLE, enable ? 1 : 0); if (enable && amdgpu_sdma_phase_quantum) { WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_PHASE0_QUANTUM), phase_quantum); @@ -553,7 +550,13 @@ static void sdma_v5_2_ctx_switch_enable(struct amdgpu_device *adev, bool enable) WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_PHASE2_QUANTUM), phase_quantum); } - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), f32_cntl); + + if (!amdgpu_sriov_vf(adev)) { + f32_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + AUTO_CTXSW_ENABLE, enable ? 1 : 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), f32_cntl); + } } } @@ -576,10 +579,12 @@ static void sdma_v5_2_enable(struct amdgpu_device *adev, bool enable) sdma_v5_2_rlc_stop(adev); } - for (i = 0; i < adev->sdma.num_instances; i++) { - f32_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); - f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1); - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl); + if (!amdgpu_sriov_vf(adev)) { + for (i = 0; i < adev->sdma.num_instances; i++) { + f32_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, enable ? 0 : 1); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl); + } } } @@ -608,7 +613,8 @@ static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev) ring = &adev->sdma.instance[i].ring; wb_offset = (ring->rptr_offs * 4); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); + if (!amdgpu_sriov_vf(adev)) + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); /* Set ring buffer size in dwords */ rb_bufsz = order_base_2(ring->ring_size / 4); @@ -683,32 +689,34 @@ static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev) sdma_v5_2_ring_set_wptr(ring); /* set minor_ptr_update to 0 after wptr programed */ - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); - /* set utc l1 enable flag always to 1 */ - temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); - - /* enable MCBP */ - temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); - - /* Set up RESP_MODE to non-copy addresses */ - temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); - - /* program default cache read and write policy */ - temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); - /* clean read policy and write policy bits */ - temp &= 0xFF0FFF; - temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | - (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | - SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); + /* SRIOV VF has no control of any of registers below */ if (!amdgpu_sriov_vf(adev)) { + /* set utc l1 enable flag always to 1 */ + temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); + + /* enable MCBP */ + temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); + + /* Set up RESP_MODE to non-copy addresses */ + temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); + + /* program default cache read and write policy */ + temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); + /* clean read policy and write policy bits */ + temp &= 0xFF0FFF; + temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | + (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | + SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); + /* unhalt engine */ temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); @@ -1436,13 +1444,14 @@ static int sdma_v5_2_set_trap_irq_state(struct amdgpu_device *adev, enum amdgpu_interrupt_state state) { u32 sdma_cntl; - u32 reg_offset = sdma_v5_2_get_reg_offset(adev, type, mmSDMA0_CNTL); - sdma_cntl = RREG32(reg_offset); - sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE, - state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); - WREG32(reg_offset, sdma_cntl); + if (!amdgpu_sriov_vf(adev)) { + sdma_cntl = RREG32(reg_offset); + sdma_cntl = REG_SET_FIELD(sdma_cntl, SDMA0_CNTL, TRAP_ENABLE, + state == AMDGPU_IRQ_STATE_ENABLE ? 1 : 0); + WREG32(reg_offset, sdma_cntl); + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/soc15_common.h b/drivers/gpu/drm/amd/amdgpu/soc15_common.h index 8a9ca87d8663..473767e03676 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15_common.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15_common.h @@ -51,6 +51,8 @@ #define RREG32_SOC15_IP(ip, reg) __RREG32_SOC15_RLC__(reg, 0, ip##_HWIP) +#define RREG32_SOC15_IP_NO_KIQ(ip, reg) __RREG32_SOC15_RLC__(reg, AMDGPU_REGS_NO_KIQ, ip##_HWIP) + #define RREG32_SOC15_NO_KIQ(ip, inst, reg) \ __RREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg, \ AMDGPU_REGS_NO_KIQ, ip##_HWIP) @@ -65,6 +67,9 @@ #define WREG32_SOC15_IP(ip, reg, value) \ __WREG32_SOC15_RLC__(reg, value, 0, ip##_HWIP) +#define WREG32_SOC15_IP_NO_KIQ(ip, reg, value) \ + __WREG32_SOC15_RLC__(reg, value, AMDGPU_REGS_NO_KIQ, ip##_HWIP) + #define WREG32_SOC15_NO_KIQ(ip, inst, reg, value) \ __WREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg, \ value, AMDGPU_REGS_NO_KIQ, ip##_HWIP) diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index d54d720b3cf6..3799226defc0 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -246,6 +246,13 @@ static int vcn_v1_0_suspend(void *handle) { int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; + bool idle_work_unexecuted; + + idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work); + if (idle_work_unexecuted) { + if (adev->pm.dpm_enabled) + amdgpu_dpm_enable_uvd(adev, false); + } r = vcn_v1_0_hw_fini(adev); if (r) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index f187596faf66..9624bbe8b501 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1060,6 +1060,9 @@ static int kfd_parse_subtype_iolink(struct crat_subtype_iolink *iolink, return -ENODEV; /* same everything but the other direction */ props2 = kmemdup(props, sizeof(*props2), GFP_KERNEL); + if (!props2) + return -ENOMEM; + props2->node_from = id_to; props2->node_to = id_from; props2->kobj = NULL; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index facc28f58c1f..2b65d0acae2c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -59,11 +59,78 @@ static void kfd_gtt_sa_fini(struct kfd_dev *kfd); static int kfd_resume(struct kfd_dev *kfd); +static void kfd_device_info_set_sdma_queue_num(struct kfd_dev *kfd) +{ + uint32_t sdma_version = kfd->adev->ip_versions[SDMA0_HWIP][0]; + + switch (sdma_version) { + case IP_VERSION(4, 0, 0):/* VEGA10 */ + case IP_VERSION(4, 0, 1):/* VEGA12 */ + case IP_VERSION(4, 1, 0):/* RAVEN */ + case IP_VERSION(4, 1, 1):/* RAVEN */ + case IP_VERSION(4, 1, 2):/* RENOIR */ + case IP_VERSION(5, 2, 1):/* VANGOGH */ + case IP_VERSION(5, 2, 3):/* YELLOW_CARP */ + kfd->device_info.num_sdma_queues_per_engine = 2; + break; + case IP_VERSION(4, 2, 0):/* VEGA20 */ + case IP_VERSION(4, 2, 2):/* ARCTURUS */ + case IP_VERSION(4, 4, 0):/* ALDEBARAN */ + case IP_VERSION(5, 0, 0):/* NAVI10 */ + case IP_VERSION(5, 0, 1):/* CYAN_SKILLFISH */ + case IP_VERSION(5, 0, 2):/* NAVI14 */ + case IP_VERSION(5, 0, 5):/* NAVI12 */ + case IP_VERSION(5, 2, 0):/* SIENNA_CICHLID */ + case IP_VERSION(5, 2, 2):/* NAVY_FLOUNDER */ + case IP_VERSION(5, 2, 4):/* DIMGREY_CAVEFISH */ + case IP_VERSION(5, 2, 5):/* BEIGE_GOBY */ + kfd->device_info.num_sdma_queues_per_engine = 8; + break; + default: + dev_warn(kfd_device, + "Default sdma queue per engine(8) is set due to " + "mismatch of sdma ip block(SDMA_HWIP:0x%x).\n", + sdma_version); + kfd->device_info.num_sdma_queues_per_engine = 8; + } +} + +static void kfd_device_info_set_event_interrupt_class(struct kfd_dev *kfd) +{ + uint32_t gc_version = KFD_GC_VERSION(kfd); + + switch (gc_version) { + case IP_VERSION(9, 0, 1): /* VEGA10 */ + case IP_VERSION(9, 1, 0): /* RAVEN */ + case IP_VERSION(9, 2, 1): /* VEGA12 */ + case IP_VERSION(9, 2, 2): /* RAVEN */ + case IP_VERSION(9, 3, 0): /* RENOIR */ + case IP_VERSION(9, 4, 0): /* VEGA20 */ + case IP_VERSION(9, 4, 1): /* ARCTURUS */ + case IP_VERSION(9, 4, 2): /* ALDEBARAN */ + case IP_VERSION(10, 3, 1): /* VANGOGH */ + case IP_VERSION(10, 3, 3): /* YELLOW_CARP */ + case IP_VERSION(10, 1, 3): /* CYAN_SKILLFISH */ + case IP_VERSION(10, 1, 10): /* NAVI10 */ + case IP_VERSION(10, 1, 2): /* NAVI12 */ + case IP_VERSION(10, 1, 1): /* NAVI14 */ + case IP_VERSION(10, 3, 0): /* SIENNA_CICHLID */ + case IP_VERSION(10, 3, 2): /* NAVY_FLOUNDER */ + case IP_VERSION(10, 3, 4): /* DIMGREY_CAVEFISH */ + case IP_VERSION(10, 3, 5): /* BEIGE_GOBY */ + kfd->device_info.event_interrupt_class = &event_interrupt_class_v9; + break; + default: + dev_warn(kfd_device, "v9 event interrupt handler is set due to " + "mismatch of gc ip block(GC_HWIP:0x%x).\n", gc_version); + kfd->device_info.event_interrupt_class = &event_interrupt_class_v9; + } +} + static void kfd_device_info_init(struct kfd_dev *kfd, bool vf, uint32_t gfx_target_version) { uint32_t gc_version = KFD_GC_VERSION(kfd); - uint32_t sdma_version = kfd->adev->ip_versions[SDMA0_HWIP][0]; uint32_t asic_type = kfd->adev->asic_type; kfd->device_info.max_pasid_bits = 16; @@ -75,16 +142,11 @@ static void kfd_device_info_init(struct kfd_dev *kfd, if (KFD_IS_SOC15(kfd)) { kfd->device_info.doorbell_size = 8; kfd->device_info.ih_ring_entry_size = 8 * sizeof(uint32_t); - kfd->device_info.event_interrupt_class = &event_interrupt_class_v9; kfd->device_info.supports_cwsr = true; - if ((sdma_version >= IP_VERSION(4, 0, 0) && - sdma_version <= IP_VERSION(4, 2, 0)) || - sdma_version == IP_VERSION(5, 2, 1) || - sdma_version == IP_VERSION(5, 2, 3)) - kfd->device_info.num_sdma_queues_per_engine = 2; - else - kfd->device_info.num_sdma_queues_per_engine = 8; + kfd_device_info_set_sdma_queue_num(kfd); + + kfd_device_info_set_event_interrupt_class(kfd); /* Raven */ if (gc_version == IP_VERSION(9, 1, 0) || diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index dd0b952f0173..4b6814949aad 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -47,7 +47,7 @@ static int execute_queues_cpsch(struct device_queue_manager *dqm, uint32_t filter_param); static int unmap_queues_cpsch(struct device_queue_manager *dqm, enum kfd_unmap_queues_filter filter, - uint32_t filter_param); + uint32_t filter_param, bool reset); static int map_queues_cpsch(struct device_queue_manager *dqm); @@ -570,7 +570,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q, /* Make sure the queue is unmapped before updating the MQD */ if (dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) { retval = unmap_queues_cpsch(dqm, - KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0); + KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, false); if (retval) { pr_err("unmap queue failed\n"); goto out_unlock; @@ -1004,14 +1004,17 @@ static void uninitialize(struct device_queue_manager *dqm) static int start_nocpsch(struct device_queue_manager *dqm) { + int r = 0; + pr_info("SW scheduler is used"); init_interrupts(dqm); if (dqm->dev->adev->asic_type == CHIP_HAWAII) - return pm_init(&dqm->packet_mgr, dqm); - dqm->sched_running = true; + r = pm_init(&dqm->packet_mgr, dqm); + if (!r) + dqm->sched_running = true; - return 0; + return r; } static int stop_nocpsch(struct device_queue_manager *dqm) @@ -1223,7 +1226,7 @@ static int stop_cpsch(struct device_queue_manager *dqm) } if (!dqm->is_hws_hang) - unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0); + unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, false); hanging = dqm->is_hws_hang || dqm->is_resetting; dqm->sched_running = false; @@ -1419,7 +1422,7 @@ static int map_queues_cpsch(struct device_queue_manager *dqm) /* dqm->lock mutex has to be locked before calling this function */ static int unmap_queues_cpsch(struct device_queue_manager *dqm, enum kfd_unmap_queues_filter filter, - uint32_t filter_param) + uint32_t filter_param, bool reset) { int retval = 0; struct mqd_manager *mqd_mgr; @@ -1432,7 +1435,7 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm, return retval; retval = pm_send_unmap_queue(&dqm->packet_mgr, KFD_QUEUE_TYPE_COMPUTE, - filter, filter_param, false, 0); + filter, filter_param, reset, 0); if (retval) return retval; @@ -1476,6 +1479,21 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm, return retval; } +/* only for compute queue */ +static int reset_queues_cpsch(struct device_queue_manager *dqm, + uint16_t pasid) +{ + int retval; + + dqm_lock(dqm); + + retval = unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_BY_PASID, + pasid, true); + + dqm_unlock(dqm); + return retval; +} + /* dqm->lock mutex has to be locked before calling this function */ static int execute_queues_cpsch(struct device_queue_manager *dqm, enum kfd_unmap_queues_filter filter, @@ -1485,7 +1503,7 @@ static int execute_queues_cpsch(struct device_queue_manager *dqm, if (dqm->is_hws_hang) return -EIO; - retval = unmap_queues_cpsch(dqm, filter, filter_param); + retval = unmap_queues_cpsch(dqm, filter, filter_param, false); if (retval) return retval; @@ -1896,6 +1914,7 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev) dqm->ops.evict_process_queues = evict_process_queues_cpsch; dqm->ops.restore_process_queues = restore_process_queues_cpsch; dqm->ops.get_wave_state = get_wave_state; + dqm->ops.reset_queues = reset_queues_cpsch; break; case KFD_SCHED_POLICY_NO_HWS: /* initialize dqm for no cp scheduling */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index 499fc0ea387f..e145e4deb53a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -81,6 +81,8 @@ struct device_process_node { * * @get_wave_state: Retrieves context save state and optionally copies the * control stack, if kept in the MQD, to the given userspace address. + * + * @reset_queues: reset queues which consume RAS poison */ struct device_queue_manager_ops { @@ -134,6 +136,9 @@ struct device_queue_manager_ops { void __user *ctl_stack, u32 *ctl_stack_used_size, u32 *save_area_used_size); + + int (*reset_queues)(struct device_queue_manager *dqm, + uint16_t pasid); }; struct device_queue_manager_asic_ops { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c index deb64168c9e8..e8bc28009c22 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c @@ -89,6 +89,44 @@ enum SQ_INTERRUPT_ERROR_TYPE { #define KFD_SQ_INT_DATA__ERR_TYPE_MASK 0xF00000 #define KFD_SQ_INT_DATA__ERR_TYPE__SHIFT 20 +static void event_interrupt_poison_consumption(struct kfd_dev *dev, + uint16_t pasid, uint16_t source_id) +{ + int ret = -EINVAL; + struct kfd_process *p = kfd_lookup_process_by_pasid(pasid); + + if (!p) + return; + + /* all queues of a process will be unmapped in one time */ + if (atomic_read(&p->poison)) { + kfd_unref_process(p); + return; + } + + atomic_set(&p->poison, 1); + kfd_unref_process(p); + + switch (source_id) { + case SOC15_INTSRC_SQ_INTERRUPT_MSG: + if (dev->dqm->ops.reset_queues) + ret = dev->dqm->ops.reset_queues(dev->dqm, pasid); + break; + case SOC15_INTSRC_SDMA_ECC: + default: + break; + } + + kfd_signal_poison_consumed_event(dev, pasid); + + /* resetting queue passes, do page retirement without gpu reset + resetting queue fails, fallback to gpu reset solution */ + if (!ret) + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, false); + else + amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev, true); +} + static bool event_interrupt_isr_v9(struct kfd_dev *dev, const uint32_t *ih_ring_entry, uint32_t *patched_ihre, @@ -159,6 +197,7 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev, */ return source_id == SOC15_INTSRC_CP_END_OF_PIPE || source_id == SOC15_INTSRC_SDMA_TRAP || + source_id == SOC15_INTSRC_SDMA_ECC || source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG || source_id == SOC15_INTSRC_CP_BAD_OPCODE || ((client_id == SOC15_IH_CLIENTID_VMC || @@ -230,8 +269,7 @@ static void event_interrupt_wq_v9(struct kfd_dev *dev, sq_intr_err); if (sq_intr_err != SQ_INTERRUPT_ERROR_TYPE_ILLEGAL_INST && sq_intr_err != SQ_INTERRUPT_ERROR_TYPE_MEMVIOL) { - kfd_signal_poison_consumed_event(dev, pasid); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev); + event_interrupt_poison_consumption(dev, pasid, source_id); return; } break; @@ -252,8 +290,7 @@ static void event_interrupt_wq_v9(struct kfd_dev *dev, if (source_id == SOC15_INTSRC_SDMA_TRAP) { kfd_signal_event_interrupt(pasid, context_id0 & 0xfffffff, 28); } else if (source_id == SOC15_INTSRC_SDMA_ECC) { - kfd_signal_poison_consumed_event(dev, pasid); - amdgpu_amdkfd_ras_poison_consumption_handler(dev->adev); + event_interrupt_poison_consumption(dev, pasid, source_id); return; } } else if (client_id == SOC15_IH_CLIENTID_VMC || diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 48c2f2b6e217..ed5385137f48 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -549,7 +549,7 @@ static void svm_migrate_page_free(struct page *page) if (svm_bo) { pr_debug_ratelimited("ref: %d\n", kref_read(&svm_bo->kref)); - svm_range_bo_unref(svm_bo); + svm_range_bo_unref_async(svm_bo); } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 0c3f911e3bf4..ea68f3b3a4e9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -856,6 +856,8 @@ struct kfd_process { struct svm_range_list svms; bool xnack_enabled; + + atomic_t poison; }; #define KFD_PROCESS_TABLE_SIZE 5 /* bits: 32 entries */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index f1930ff2c74a..d1145da5348f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -461,6 +461,7 @@ static struct attribute *procfs_queue_attrs[] = { &attr_queue_gpuid, NULL }; +ATTRIBUTE_GROUPS(procfs_queue); static const struct sysfs_ops procfs_queue_ops = { .show = kfd_procfs_queue_show, @@ -468,7 +469,7 @@ static const struct sysfs_ops procfs_queue_ops = { static struct kobj_type procfs_queue_type = { .sysfs_ops = &procfs_queue_ops, - .default_attrs = procfs_queue_attrs, + .default_groups = procfs_queue_groups, }; static const struct sysfs_ops procfs_stats_ops = { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 7e92dcea4ce8..f2805ba74c80 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -107,7 +107,7 @@ static void svm_range_add_to_svms(struct svm_range *prange) pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx]\n", prange->svms, prange, prange->start, prange->last); - list_add_tail(&prange->list, &prange->svms->list); + list_move_tail(&prange->list, &prange->svms->list); prange->it_node.start = prange->start; prange->it_node.last = prange->last; interval_tree_insert(&prange->it_node, &prange->svms->objects); @@ -295,8 +295,6 @@ svm_range *svm_range_new(struct svm_range_list *svms, uint64_t start, prange->last = last; INIT_LIST_HEAD(&prange->list); INIT_LIST_HEAD(&prange->update_list); - INIT_LIST_HEAD(&prange->remove_list); - INIT_LIST_HEAD(&prange->insert_list); INIT_LIST_HEAD(&prange->svm_bo_list); INIT_LIST_HEAD(&prange->deferred_list); INIT_LIST_HEAD(&prange->child_list); @@ -332,6 +330,8 @@ static void svm_range_bo_release(struct kref *kref) struct svm_range_bo *svm_bo; svm_bo = container_of(kref, struct svm_range_bo, kref); + pr_debug("svm_bo 0x%p\n", svm_bo); + spin_lock(&svm_bo->list_lock); while (!list_empty(&svm_bo->range_list)) { struct svm_range *prange = @@ -365,12 +365,33 @@ static void svm_range_bo_release(struct kref *kref) kfree(svm_bo); } -void svm_range_bo_unref(struct svm_range_bo *svm_bo) +static void svm_range_bo_wq_release(struct work_struct *work) { - if (!svm_bo) - return; + struct svm_range_bo *svm_bo; + + svm_bo = container_of(work, struct svm_range_bo, release_work); + svm_range_bo_release(&svm_bo->kref); +} + +static void svm_range_bo_release_async(struct kref *kref) +{ + struct svm_range_bo *svm_bo; + + svm_bo = container_of(kref, struct svm_range_bo, kref); + pr_debug("svm_bo 0x%p\n", svm_bo); + INIT_WORK(&svm_bo->release_work, svm_range_bo_wq_release); + schedule_work(&svm_bo->release_work); +} - kref_put(&svm_bo->kref, svm_range_bo_release); +void svm_range_bo_unref_async(struct svm_range_bo *svm_bo) +{ + kref_put(&svm_bo->kref, svm_range_bo_release_async); +} + +static void svm_range_bo_unref(struct svm_range_bo *svm_bo) +{ + if (svm_bo) + kref_put(&svm_bo->kref, svm_range_bo_release); } static bool @@ -995,7 +1016,7 @@ svm_range_split_tail(struct svm_range *prange, int r = svm_range_split(prange, prange->start, new_last, &tail); if (!r) - list_add(&tail->insert_list, insert_list); + list_add(&tail->list, insert_list); return r; } @@ -1007,7 +1028,7 @@ svm_range_split_head(struct svm_range *prange, int r = svm_range_split(prange, new_start, prange->last, &head); if (!r) - list_add(&head->insert_list, insert_list); + list_add(&head->list, insert_list); return r; } @@ -1875,8 +1896,8 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size, goto out; } - list_add(&old->remove_list, remove_list); - list_add(&prange->insert_list, insert_list); + list_add(&old->update_list, remove_list); + list_add(&prange->list, insert_list); list_add(&prange->update_list, update_list); if (node->start < start) { @@ -1908,7 +1929,7 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size, goto out; } - list_add(&prange->insert_list, insert_list); + list_add(&prange->list, insert_list); list_add(&prange->update_list, update_list); } @@ -1923,13 +1944,13 @@ svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size, r = -ENOMEM; goto out; } - list_add(&prange->insert_list, insert_list); + list_add(&prange->list, insert_list); list_add(&prange->update_list, update_list); } out: if (r) - list_for_each_entry_safe(prange, tmp, insert_list, insert_list) + list_for_each_entry_safe(prange, tmp, insert_list, list) svm_range_free(prange); return r; @@ -2254,8 +2275,8 @@ svm_range_cpu_invalidate_pagetables(struct mmu_interval_notifier *mni, start = mni->interval_tree.start; last = mni->interval_tree.last; - start = (start > range->start ? start : range->start) >> PAGE_SHIFT; - last = (last < (range->end - 1) ? last : range->end - 1) >> PAGE_SHIFT; + start = max(start, range->start) >> PAGE_SHIFT; + last = min(last, range->end - 1) >> PAGE_SHIFT; pr_debug("[0x%lx 0x%lx] range[0x%lx 0x%lx] notifier[0x%lx 0x%lx] %d\n", start, last, range->start >> PAGE_SHIFT, (range->end - 1) >> PAGE_SHIFT, @@ -3213,7 +3234,7 @@ svm_range_set_attr(struct kfd_process *p, uint64_t start, uint64_t size, goto out; } /* Apply changes as a transaction */ - list_for_each_entry_safe(prange, next, &insert_list, insert_list) { + list_for_each_entry_safe(prange, next, &insert_list, list) { svm_range_add_to_svms(prange); svm_range_add_notifier_locked(mm, prange); } @@ -3221,8 +3242,7 @@ svm_range_set_attr(struct kfd_process *p, uint64_t start, uint64_t size, svm_range_apply_attrs(p, prange, nattr, attrs); /* TODO: unmap ranges from GPU that lost access */ } - list_for_each_entry_safe(prange, next, &remove_list, - remove_list) { + list_for_each_entry_safe(prange, next, &remove_list, update_list) { pr_debug("unlink old 0x%p prange 0x%p [0x%lx 0x%lx]\n", prange->svms, prange, prange->start, prange->last); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index 6dc91c33e80f..949b477e2f4c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -48,6 +48,7 @@ struct svm_range_bo { struct work_struct eviction_work; struct svm_range_list *svms; uint32_t evicting; + struct work_struct release_work; }; enum svm_work_list_ops { @@ -75,8 +76,6 @@ struct svm_work_list_item { * aligned, page size is (last - start + 1) * @list: link list node, used to scan all ranges of svms * @update_list:link list node used to add to update_list - * @remove_list:link list node used to add to remove list - * @insert_list:link list node used to add to insert list * @mapping: bo_va mapping structure to create and update GPU page table * @npages: number of pages * @dma_addr: dma mapping address on each GPU for system memory physical page @@ -112,8 +111,6 @@ struct svm_range { struct interval_tree_node it_node; struct list_head list; struct list_head update_list; - struct list_head remove_list; - struct list_head insert_list; uint64_t npages; dma_addr_t *dma_addr[MAX_GPU_INSTANCE]; struct ttm_resource *ttm_res; @@ -195,7 +192,7 @@ void svm_range_list_lock_and_flush_work(struct svm_range_list *svms, struct mm_s */ #define KFD_IS_SVM_API_SUPPORTED(dev) ((dev)->pgmap.type != 0) -void svm_range_bo_unref(struct svm_range_bo *svm_bo); +void svm_range_bo_unref_async(struct svm_range_bo *svm_bo); #else struct kfd_process; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 2f0b14f8f833..7f9773f8dab6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -658,7 +658,7 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, struct drm_connector_list_iter iter; struct dc_link *link; uint8_t link_index = 0; - struct drm_device *dev = adev->dm.ddev; + struct drm_device *dev; if (adev == NULL) return; @@ -675,6 +675,7 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, link_index = notify->link_index; link = adev->dm.dc->links[link_index]; + dev = adev->dm.ddev; drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { @@ -1161,6 +1162,32 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) return 0; } +static void dm_dmub_hw_resume(struct amdgpu_device *adev) +{ + struct dmub_srv *dmub_srv = adev->dm.dmub_srv; + enum dmub_status status; + bool init; + + if (!dmub_srv) { + /* DMUB isn't supported on the ASIC. */ + return; + } + + status = dmub_srv_is_hw_init(dmub_srv, &init); + if (status != DMUB_STATUS_OK) + DRM_WARN("DMUB hardware init check failed: %d\n", status); + + if (status == DMUB_STATUS_OK && init) { + /* Wait for firmware load to finish. */ + status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); + if (status != DMUB_STATUS_OK) + DRM_WARN("Wait for DMUB auto-load failed: %d\n", status); + } else { + /* Perform the full hardware initialization. */ + dm_dmub_hw_init(adev); + } +} + #if defined(CONFIG_DRM_AMD_DC_DCN) static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config) { @@ -2637,9 +2664,7 @@ static int dm_resume(void *handle) amdgpu_dm_outbox_init(adev); /* Before powering on DC we need to re-initialize DMUB. */ - r = dm_dmub_hw_init(adev); - if (r) - DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r); + dm_dmub_hw_resume(adev); /* power on hardware */ dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); @@ -6073,6 +6098,7 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, struct dsc_dec_dpcd_caps *dsc_caps) { stream->timing.flags.DSC = 0; + dsc_caps->is_dsc_supported = false; if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || sink->sink_signal == SIGNAL_TYPE_EDP)) { @@ -10737,6 +10763,8 @@ static int dm_update_plane_state(struct dc *dc, dm_new_plane_state->dc_state = dc_new_plane_state; + dm_new_crtc_state->mpo_requested |= (plane->type == DRM_PLANE_TYPE_OVERLAY); + /* Tell DC to do a full surface update every time there * is a plane change. Inefficient, but works for now. */ @@ -10889,7 +10917,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, enum dc_status status; int ret, i; bool lock_and_validation_needed = false; - struct dm_crtc_state *dm_old_crtc_state; + struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; #if defined(CONFIG_DRM_AMD_DC_DCN) struct dsc_mst_fairness_vars vars[MAX_PIPES]; struct drm_dp_mst_topology_state *mst_state; @@ -11071,6 +11099,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, goto fail; } + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + if (dm_new_crtc_state->mpo_requested) + DRM_DEBUG_DRIVER("MPO enablement requested on crtc:[%p]\n", crtc); + } + /* Check cursor planes scaling */ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) { ret = dm_check_crtc_cursor(state, crtc, new_crtc_state); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index c98e402eab0c..b9a69b0cef23 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -626,6 +626,8 @@ struct dm_crtc_state { bool cm_has_degamma; bool cm_is_degamma_srgb; + bool mpo_requested; + int update_type; int active_planes; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c index 8f78e62b28b7..48005def1164 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c @@ -741,7 +741,7 @@ void vg_clk_mgr_construct( sizeof(struct watermarks), &clk_mgr->smu_wm_set.mc_address.quad_part); - if (clk_mgr->smu_wm_set.wm_set == 0) { + if (!clk_mgr->smu_wm_set.wm_set) { clk_mgr->smu_wm_set.wm_set = &dummy_wms; clk_mgr->smu_wm_set.mc_address.quad_part = 0; } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index 412cc6a716f7..4162ce40089b 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -158,6 +158,7 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base, union display_idle_optimization_u idle_info = { 0 }; idle_info.idle_info.df_request_disabled = 1; idle_info.idle_info.phy_ref_clk_off = 1; + idle_info.idle_info.s0i2_rdy = 1; dcn31_smu_set_display_idle_optimization(clk_mgr, idle_info.data); /* update power state */ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c index b7ace235a2d5..a1011f3273f3 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c @@ -119,6 +119,12 @@ static int dcn31_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, result = dcn31_smu_wait_for_response(clk_mgr, 10, 200000); + if (result == VBIOSSMC_Result_Failed) { + ASSERT(0); + REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Result_OK); + return -1; + } + if (IS_SMU_TIMEOUT(result)) { ASSERT(0); dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index c250f6de5136..91c4874473d6 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -274,24 +274,6 @@ static bool create_links( goto failed_alloc; } -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) && - dc->caps.dp_hpo && - link->dc->res_pool->res_cap->num_hpo_dp_link_encoder > 0) { - /* FPGA case - Allocate HPO DP link encoder */ - if (i < link->dc->res_pool->res_cap->num_hpo_dp_link_encoder) { - link->hpo_dp_link_enc = link->dc->res_pool->hpo_dp_link_enc[i]; - - if (link->hpo_dp_link_enc == NULL) { - BREAK_TO_DEBUGGER(); - goto failed_alloc; - } - link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source; - link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter; - } - } -#endif - link->link_status.dpcd_caps = &link->dpcd_caps; enc_init.ctx = dc->ctx; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 21be2a684393..643762542e4d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -422,6 +422,8 @@ char *dc_status_to_str(enum dc_status status) return "The operation is not supported."; case DC_UNSUPPORTED_VALUE: return "The value specified is not supported."; + case DC_NO_LINK_ENC_RESOURCE: + return "No link encoder resource"; case DC_ERROR_UNEXPECTED: return "Unexpected error"; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 3d75f56a939c..b5e570d33ca9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -66,31 +66,6 @@ /******************************************************************************* * Private functions ******************************************************************************/ -#if defined(CONFIG_DRM_AMD_DC_DCN) -static bool add_dp_hpo_link_encoder_to_link(struct dc_link *link) -{ - struct hpo_dp_link_encoder *enc = resource_get_unused_hpo_dp_link_encoder( - link->dc->res_pool); - - if (!link->hpo_dp_link_enc && enc) { - link->hpo_dp_link_enc = enc; - link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter; - link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source; - } - - return (link->hpo_dp_link_enc != NULL); -} - -static void remove_dp_hpo_link_encoder_from_link(struct dc_link *link) -{ - if (link->hpo_dp_link_enc) { - link->hpo_dp_link_enc->hpd_source = HPD_SOURCEID_UNKNOWN; - link->hpo_dp_link_enc->transmitter = TRANSMITTER_UNKNOWN; - link->hpo_dp_link_enc = NULL; - } -} -#endif - static void dc_link_destruct(struct dc_link *link) { int i; @@ -118,12 +93,6 @@ static void dc_link_destruct(struct dc_link *link) link->link_enc->funcs->destroy(&link->link_enc); } -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (link->hpo_dp_link_enc) { - remove_dp_hpo_link_encoder_from_link(link); - } -#endif - if (link->local_sink) dc_sink_release(link->local_sink); @@ -881,6 +850,7 @@ static bool dc_link_detect_helper(struct dc_link *link, enum dc_connection_type pre_connection_type = dc_connection_none; bool perform_dp_seamless_boot = false; const uint32_t post_oui_delay = 30; // 30ms + struct link_resource link_res = { 0 }; DC_LOGGER_INIT(link->ctx->logger); @@ -975,7 +945,10 @@ static bool dc_link_detect_helper(struct dc_link *link, #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING) - add_dp_hpo_link_encoder_to_link(link); + link_res.hpo_dp_link_enc = resource_get_hpo_dp_link_enc_for_det_lt( + &link->dc->current_state->res_ctx, + link->dc->res_pool, + link); #endif if (link->type == dc_connection_mst_branch) { @@ -986,7 +959,7 @@ static bool dc_link_detect_helper(struct dc_link *link, * empty which leads to allocate_mst_payload() has "0" * pbn_per_slot value leading to exception on dc_fixpt_div() */ - dp_verify_mst_link_cap(link); + dp_verify_mst_link_cap(link, &link_res); /* * This call will initiate MST topology discovery. Which @@ -1150,6 +1123,7 @@ static bool dc_link_detect_helper(struct dc_link *link, // verify link cap for SST non-seamless boot if (!perform_dp_seamless_boot) dp_verify_link_cap_with_retries(link, + &link_res, &link->reported_link_cap, LINK_TRAINING_MAX_VERIFY_RETRY); } else { @@ -1844,6 +1818,8 @@ static void enable_stream_features(struct pipe_ctx *pipe_ctx) union down_spread_ctrl old_downspread; union down_spread_ctrl new_downspread; + memset(&old_downspread, 0, sizeof(old_downspread)); + core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL, &old_downspread.raw, sizeof(old_downspread)); @@ -2503,7 +2479,8 @@ static void write_i2c_redriver_setting( DC_LOG_DEBUG("Set redriver failed"); } -static void disable_link(struct dc_link *link, enum signal_type signal) +static void disable_link(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal) { /* * TODO: implement call for dp_set_hw_test_pattern @@ -2522,20 +2499,20 @@ static void disable_link(struct dc_link *link, enum signal_type signal) struct dc_link_settings link_settings = link->cur_link_settings; #endif if (dc_is_dp_sst_signal(signal)) - dp_disable_link_phy(link, signal); + dp_disable_link_phy(link, link_res, signal); else - dp_disable_link_phy_mst(link, signal); + dp_disable_link_phy_mst(link, link_res, signal); if (dc_is_dp_sst_signal(signal) || link->mst_stream_alloc_table.stream_count == 0) { #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) { dp_set_fec_enable(link, false); - dp_set_fec_ready(link, false); + dp_set_fec_ready(link, link_res, false); } #else dp_set_fec_enable(link, false); - dp_set_fec_ready(link, false); + dp_set_fec_ready(link, link_res, false); #endif } } else { @@ -2646,7 +2623,7 @@ static enum dc_status enable_link( * new link settings. */ if (link->link_status.link_active) { - disable_link(link, pipe_ctx->stream->signal); + disable_link(link, &pipe_ctx->link_res, pipe_ctx->stream->signal); } switch (pipe_ctx->stream->signal) { @@ -3421,7 +3398,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx, { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; struct link_mst_stream_allocation_table proposed_table = {0}; struct fixed31_32 avg_time_slots_per_mtp; @@ -3503,7 +3480,7 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; #if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; #endif struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -3833,7 +3810,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; #if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; #endif struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -3994,104 +3971,73 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) { struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp; -#if defined(CONFIG_DRM_AMD_DC_DCN) struct link_encoder *link_enc = NULL; -#endif + struct cp_psp_stream_config config = {0}; + enum dp_panel_mode panel_mode = + dp_get_panel_mode(pipe_ctx->stream->link); - if (cp_psp && cp_psp->funcs.update_stream_config) { - struct cp_psp_stream_config config = {0}; - enum dp_panel_mode panel_mode = - dp_get_panel_mode(pipe_ctx->stream->link); + if (cp_psp == NULL || cp_psp->funcs.update_stream_config == NULL) + return; - config.otg_inst = (uint8_t) pipe_ctx->stream_res.tg->inst; - /*stream_enc_inst*/ - config.dig_fe = (uint8_t) pipe_ctx->stream_res.stream_enc->stream_enc_inst; - config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst; -#if defined(CONFIG_DRM_AMD_DC_DCN) - config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; - - if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY || - pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - link_enc = pipe_ctx->stream->link->link_enc; - config.dio_output_type = pipe_ctx->stream->link->ep_type; - config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; - if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) - link_enc = pipe_ctx->stream->link->link_enc; - else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) - if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_stream( - pipe_ctx->stream->ctx->dc, - pipe_ctx->stream); - } - ASSERT(link_enc); + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) + link_enc = pipe_ctx->stream->link->link_enc; + else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && + pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) + link_enc = link_enc_cfg_get_link_enc_used_by_stream( + pipe_ctx->stream->ctx->dc, + pipe_ctx->stream); + ASSERT(link_enc); + if (link_enc == NULL) + return; - // Initialize PHY ID with ABCDE - 01234 mapping except when it is B0 - config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + /* otg instance */ + config.otg_inst = (uint8_t) pipe_ctx->stream_res.tg->inst; - // Add flag to guard new A0 DIG mapping - if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 == true && - pipe_ctx->stream->link->dc->ctx->dce_version == DCN_VERSION_3_1) { - config.dig_be = link_enc->preferred_engine; - config.dio_output_type = pipe_ctx->stream->link->ep_type; - config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; - } else { - config.dio_output_type = 0; - config.dio_output_idx = 0; - } + /* dig front end */ + config.dig_fe = (uint8_t) pipe_ctx->stream_res.stream_enc->stream_enc_inst; - // Add flag to guard B0 implementation - if (pipe_ctx->stream->ctx->dc->enable_c20_dtm_b0 == true && - link_enc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { - if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - // enum ID 1-4 maps to DPIA PHY ID 0-3 - config.phy_idx = pipe_ctx->stream->link->link_id.enum_id - ENUM_ID_1; - } else { // for non DPIA mode over B0, ABCDE maps to 01564 - - switch (link_enc->transmitter) { - case TRANSMITTER_UNIPHY_A: - config.phy_idx = 0; - break; - case TRANSMITTER_UNIPHY_B: - config.phy_idx = 1; - break; - case TRANSMITTER_UNIPHY_C: - config.phy_idx = 5; - break; - case TRANSMITTER_UNIPHY_D: - config.phy_idx = 6; - break; - case TRANSMITTER_UNIPHY_E: - config.phy_idx = 4; - break; - default: - config.phy_idx = 0; - break; - } + /* stream encoder index */ + config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (is_dp_128b_132b_signal(pipe_ctx)) + config.stream_enc_idx = + pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0; +#endif - } - } - } else if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_stream( - pipe_ctx->stream->ctx->dc, - pipe_ctx->stream); - config.phy_idx = 0; /* Clear phy_idx for non-physical display endpoints. */ - } - ASSERT(link_enc); - if (link_enc) - config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; - if (is_dp_128b_132b_signal(pipe_ctx)) { - config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0; - config.link_enc_idx = pipe_ctx->stream->link->hpo_dp_link_enc->inst; - config.dp2_enabled = 1; - } + /* dig back end */ + config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst; + + /* link encoder index */ + config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (is_dp_128b_132b_signal(pipe_ctx)) + config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst; #endif - config.dpms_off = dpms_off; - config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context; - config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP); - config.mst_enabled = (pipe_ctx->stream->signal == - SIGNAL_TYPE_DISPLAY_PORT_MST); - cp_psp->funcs.update_stream_config(cp_psp->handle, &config); - } + /* dio output index */ + config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; + + /* phy index */ + config.phy_idx = resource_transmitter_to_phy_idx( + pipe_ctx->stream->link->dc, link_enc->transmitter); + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + /* USB4 DPIA doesn't use PHY in our soc, initialize it to 0 */ + config.phy_idx = 0; + + /* stream properties */ + config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0; + config.mst_enabled = (pipe_ctx->stream->signal == + SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0; +#if defined(CONFIG_DRM_AMD_DC_DCN) + config.dp2_enabled = is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0; +#endif + config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ? + 1 : 0; + config.dpms_off = dpms_off; + + /* dm stream context */ + config.dm_stream_ctx = pipe_ctx->stream->dm_stream_context; + + cp_psp->funcs.update_stream_config(cp_psp->handle, &config); } #endif @@ -4112,7 +4058,7 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi stream->link->cur_link_settings = link_settings; /* Enable clock, Configure lane count, and Enable Link Encoder*/ - enable_dp_hpo_output(stream->link, &stream->link->cur_link_settings); + enable_dp_hpo_output(stream->link, &pipe_ctx->link_res, &stream->link->cur_link_settings); #ifdef DIAGS_BUILD /* Workaround for FPGA HPO capture DP link data: @@ -4162,12 +4108,12 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc; } - stream->link->hpo_dp_link_enc->funcs->update_stream_allocation_table( - stream->link->hpo_dp_link_enc, + pipe_ctx->link_res.hpo_dp_link_enc->funcs->update_stream_allocation_table( + pipe_ctx->link_res.hpo_dp_link_enc, &proposed_table); - stream->link->hpo_dp_link_enc->funcs->set_throttled_vcp_size( - stream->link->hpo_dp_link_enc, + pipe_ctx->link_res.hpo_dp_link_enc->funcs->set_throttled_vcp_size( + pipe_ctx->link_res.hpo_dp_link_enc, pipe_ctx->stream_res.hpo_dp_stream_enc->inst, avg_time_slots_per_mtp); @@ -4356,7 +4302,8 @@ void core_link_enable_stream( if (status != DC_FAIL_DP_LINK_TRAINING || pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { if (false == stream->link->link_status.link_active) - disable_link(stream->link, pipe_ctx->stream->signal); + disable_link(stream->link, &pipe_ctx->link_res, + pipe_ctx->stream->signal); BREAK_TO_DEBUGGER(); return; } @@ -4505,14 +4452,14 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) * state machine. * In DP2 or MST mode, our encoder will stay video active */ - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); dc->hwss.disable_stream(pipe_ctx); } else { dc->hwss.disable_stream(pipe_ctx); - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); } #else - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); dc->hwss.disable_stream(pipe_ctx); #endif @@ -4595,16 +4542,22 @@ void dc_link_set_drive_settings(struct dc *dc, { int i; + struct pipe_ctx *pipe = NULL; + const struct link_resource *link_res; - for (i = 0; i < dc->link_count; i++) { - if (dc->links[i] == link) - break; - } + link_res = dc_link_get_cur_link_res(link); - if (i >= dc->link_count) + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->stream->link) { + if (pipe->stream->link == link) + break; + } + } + if (pipe && link_res) + dc_link_dp_set_drive_settings(pipe->stream->link, link_res, lt_settings); + else ASSERT_CRITICAL(false); - - dc_link_dp_set_drive_settings(dc->links[i], lt_settings); } void dc_link_set_preferred_link_settings(struct dc *dc, @@ -4665,11 +4618,9 @@ void dc_link_set_preferred_training_settings(struct dc *dc, if (link_setting != NULL) { link->preferred_link_setting = *link_setting; #if defined(CONFIG_DRM_AMD_DC_DCN) - if (dp_get_link_encoding_format(link_setting) == - DP_128b_132b_ENCODING && !link->hpo_dp_link_enc) { - if (!add_dp_hpo_link_encoder_to_link(link)) - memset(&link->preferred_link_setting, 0, sizeof(link->preferred_link_setting)); - } + if (dp_get_link_encoding_format(link_setting) == DP_128b_132b_ENCODING) + /* TODO: add dc update for acquiring link res */ + skip_immediate_retrain = true; #endif } else { link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; @@ -4796,6 +4747,9 @@ void dc_link_overwrite_extended_receiver_cap( bool dc_link_is_fec_supported(const struct dc_link *link) { + /* TODO - use asic cap instead of link_enc->features + * we no longer know which link enc to use for this link before commit + */ struct link_encoder *link_enc = NULL; /* Links supporting dynamically assigned link encoder will be assigned next @@ -4890,3 +4844,125 @@ uint32_t dc_bandwidth_in_kbps_from_timing( return kbps; } + +const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link) +{ + int i; + struct pipe_ctx *pipe = NULL; + const struct link_resource *link_res = NULL; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) { + if (pipe->stream->link == link) { + link_res = &pipe->link_res; + break; + } + } + } + + return link_res; +} + +/** + * dc_get_cur_link_res_map() - take a snapshot of current link resource allocation state + * @dc: pointer to dc of the dm calling this + * @map: a dc link resource snapshot defined internally to dc. + * + * DM needs to capture a snapshot of current link resource allocation mapping + * and store it in its persistent storage. + * + * Some of the link resource is using first come first serve policy. + * The allocation mapping depends on original hotplug order. This information + * is lost after driver is loaded next time. The snapshot is used in order to + * restore link resource to its previous state so user will get consistent + * link capability allocation across reboot. + * + * Return: none (void function) + * + */ +void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map) +{ +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct dc_link *link; + uint8_t i; + uint32_t hpo_dp_recycle_map = 0; + + *map = 0; + + if (dc->caps.dp_hpo) { + for (i = 0; i < dc->caps.max_links; i++) { + link = dc->links[i]; + if (link->link_status.link_active && + dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING && + dp_get_link_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING) + /* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability + * but current link doesn't use it. + */ + hpo_dp_recycle_map |= (1 << i); + } + *map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT); + } +#endif +} + +/** + * dc_restore_link_res_map() - restore link resource allocation state from a snapshot + * @dc: pointer to dc of the dm calling this + * @map: a dc link resource snapshot defined internally to dc. + * + * DM needs to call this function after initial link detection on boot and + * before first commit streams to restore link resource allocation state + * from previous boot session. + * + * Some of the link resource is using first come first serve policy. + * The allocation mapping depends on original hotplug order. This information + * is lost after driver is loaded next time. The snapshot is used in order to + * restore link resource to its previous state so user will get consistent + * link capability allocation across reboot. + * + * Return: none (void function) + * + */ +void dc_restore_link_res_map(const struct dc *dc, uint32_t *map) +{ +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct dc_link *link; + uint8_t i; + unsigned int available_hpo_dp_count; + uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK) + >> LINK_RES_HPO_DP_REC_MAP__SHIFT; + + if (dc->caps.dp_hpo) { + available_hpo_dp_count = dc->res_pool->hpo_dp_link_enc_count; + /* remove excess 128b/132b encoding support for not recycled links */ + for (i = 0; i < dc->caps.max_links; i++) { + if ((hpo_dp_recycle_map & (1 << i)) == 0) { + link = dc->links[i]; + if (link->type != dc_connection_none && + dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + if (available_hpo_dp_count > 0) + available_hpo_dp_count--; + else + /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */ + link->verified_link_cap.link_rate = LINK_RATE_HIGH3; + } + } + } + /* remove excess 128b/132b encoding support for recycled links */ + for (i = 0; i < dc->caps.max_links; i++) { + if ((hpo_dp_recycle_map & (1 << i)) != 0) { + link = dc->links[i]; + if (link->type != dc_connection_none && + dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + if (available_hpo_dp_count > 0) + available_hpo_dp_count--; + else + /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */ + link->verified_link_cap.link_rate = LINK_RATE_HIGH3; + } + } + } + } +#endif +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 8a35370da867..05e216524370 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -1251,6 +1251,7 @@ bool dp_is_max_vs_reached( static bool perform_post_lt_adj_req_sequence( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { enum dc_lane_count lane_count = @@ -1314,6 +1315,7 @@ static bool perform_post_lt_adj_req_sequence( lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); dc_link_dp_set_drive_settings(link, + link_res, lt_settings); break; } @@ -1388,6 +1390,7 @@ enum link_training_result dp_get_cr_failure(enum dc_lane_count ln_count, static enum link_training_result perform_channel_equalization_sequence( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t offset) { @@ -1410,12 +1413,12 @@ static enum link_training_result perform_channel_equalization_sequence( tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4; #endif - dp_set_hw_training_pattern(link, tr_pattern, offset); + dp_set_hw_training_pattern(link, link_res, tr_pattern, offset); for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; retries_ch_eq++) { - dp_set_hw_lane_settings(link, lt_settings, offset); + dp_set_hw_lane_settings(link, link_res, lt_settings, offset); /* 2. update DPCD*/ if (!retries_ch_eq) @@ -1479,18 +1482,20 @@ static enum link_training_result perform_channel_equalization_sequence( } static void start_clock_recovery_pattern_early(struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t offset) { DC_LOG_HW_LINK_TRAINING("%s\n GPU sends TPS1. Wait 400us.\n", __func__); - dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, offset); - dp_set_hw_lane_settings(link, lt_settings, offset); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); + dp_set_hw_lane_settings(link, link_res, lt_settings, offset); udelay(400); } static enum link_training_result perform_clock_recovery_sequence( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t offset) { @@ -1506,7 +1511,7 @@ static enum link_training_result perform_clock_recovery_sequence( retry_count = 0; if (!link->ctx->dc->work_arounds.lt_early_cr_pattern) - dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, offset); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset); /* najeeb - The synaptics MST hub can put the LT in * infinite loop by switching the VS @@ -1523,6 +1528,7 @@ static enum link_training_result perform_clock_recovery_sequence( /* 1. call HWSS to set lane settings*/ dp_set_hw_lane_settings( link, + link_res, lt_settings, offset); @@ -1544,9 +1550,6 @@ static enum link_training_result perform_clock_recovery_sequence( /* 3. wait receiver to lock-on*/ wait_time_microsec = lt_settings->cr_pattern_time; - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - wait_time_microsec = TRAINING_AUX_RD_INTERVAL; - if (link->dc->debug.apply_vendor_specific_lttpr_wa && (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN)) { wait_time_microsec = 16000; @@ -1624,13 +1627,14 @@ static enum link_training_result perform_clock_recovery_sequence( static inline enum link_training_result dp_transition_to_video_idle( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, enum link_training_result status) { union lane_count_set lane_count_set = {0}; /* 4. mainlink output idle pattern*/ - dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); /* * 5. post training adjust if required @@ -1654,7 +1658,7 @@ static inline enum link_training_result dp_transition_to_video_idle( } if (status == LINK_TRAINING_SUCCESS && - perform_post_lt_adj_req_sequence(link, lt_settings) == false) + perform_post_lt_adj_req_sequence(link, link_res, lt_settings) == false) status = LINK_TRAINING_LQA_FAIL; lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; @@ -2097,10 +2101,11 @@ static void print_status_message( void dc_link_dp_set_drive_settings( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { /* program ASIC PHY settings*/ - dp_set_hw_lane_settings(link, lt_settings, DPRX); + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); @@ -2111,6 +2116,7 @@ void dc_link_dp_set_drive_settings( bool dc_link_dp_perform_link_training_skip_aux( struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_setting) { struct link_training_settings lt_settings = {0}; @@ -2127,10 +2133,10 @@ bool dc_link_dp_perform_link_training_skip_aux( /* 1. Perform_clock_recovery_sequence. */ /* transmit training pattern for clock recovery */ - dp_set_hw_training_pattern(link, lt_settings.pattern_for_cr, DPRX); + dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_cr, DPRX); /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, <_settings, DPRX); + dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); /* wait receiver to lock-on*/ dp_wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); @@ -2138,10 +2144,10 @@ bool dc_link_dp_perform_link_training_skip_aux( /* 2. Perform_channel_equalization_sequence. */ /* transmit training pattern for channel equalization. */ - dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq, DPRX); + dp_set_hw_training_pattern(link, link_res, lt_settings.pattern_for_eq, DPRX); /* call HWSS to set lane settings*/ - dp_set_hw_lane_settings(link, <_settings, DPRX); + dp_set_hw_lane_settings(link, link_res, <_settings, DPRX); /* wait receiver to lock-on. */ dp_wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); @@ -2149,7 +2155,7 @@ bool dc_link_dp_perform_link_training_skip_aux( /* 3. Perform_link_training_int. */ /* Mainlink output idle pattern. */ - dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + dp_set_hw_test_pattern(link, link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); print_status_message(link, <_settings, LINK_TRAINING_SUCCESS); @@ -2230,6 +2236,7 @@ static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link, static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { uint8_t loop_count; @@ -2241,7 +2248,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; /* Transmit 128b/132b_TPS1 over Main-Link */ - dp_set_hw_training_pattern(link, lt_settings->pattern_for_cr, DPRX); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, DPRX); /* Set TRAINING_PATTERN_SET to 01h */ dpcd_set_training_pattern(link, lt_settings->pattern_for_cr); @@ -2251,8 +2258,8 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( &dpcd_lane_status_updated, dpcd_lane_adjust, DPRX); dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); - dp_set_hw_lane_settings(link, lt_settings, DPRX); - dp_set_hw_training_pattern(link, lt_settings->pattern_for_eq, DPRX); + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); + dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, DPRX); /* Set loop counter to start from 1 */ loop_count = 1; @@ -2279,7 +2286,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) { status = DP_128b_132b_LT_FAILED; } else { - dp_set_hw_lane_settings(link, lt_settings, DPRX); + dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX); dpcd_set_lane_settings(link, lt_settings, DPRX); } loop_count++; @@ -2308,6 +2315,7 @@ static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence( static enum link_training_result dp_perform_128b_132b_cds_done_sequence( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { /* Assumption: assume hardware has transmitted eq pattern */ @@ -2344,6 +2352,7 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence( static enum link_training_result dp_perform_8b_10b_link_training( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { enum link_training_result status = LINK_TRAINING_SUCCESS; @@ -2353,7 +2362,7 @@ static enum link_training_result dp_perform_8b_10b_link_training( uint8_t lane = 0; if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, lt_settings, DPRX); + start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX); /* 1. set link rate, lane count and spread. */ dpcd_set_link_settings(link, lt_settings); @@ -2367,12 +2376,13 @@ static enum link_training_result dp_perform_8b_10b_link_training( for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS); repeater_id--) { - status = perform_clock_recovery_sequence(link, lt_settings, repeater_id); + status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id); if (status != LINK_TRAINING_SUCCESS) break; status = perform_channel_equalization_sequence(link, + link_res, lt_settings, repeater_id); @@ -2387,9 +2397,10 @@ static enum link_training_result dp_perform_8b_10b_link_training( } if (status == LINK_TRAINING_SUCCESS) { - status = perform_clock_recovery_sequence(link, lt_settings, DPRX); + status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX); if (status == LINK_TRAINING_SUCCESS) { status = perform_channel_equalization_sequence(link, + link_res, lt_settings, DPRX); } @@ -2401,6 +2412,7 @@ static enum link_training_result dp_perform_8b_10b_link_training( #if defined(CONFIG_DRM_AMD_DC_DCN) static enum link_training_result dp_perform_128b_132b_link_training( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { enum link_training_result result = LINK_TRAINING_SUCCESS; @@ -2412,23 +2424,358 @@ static enum link_training_result dp_perform_128b_132b_link_training( decide_8b_10b_training_settings(link, <_settings->link_settings, &legacy_settings); - return dp_perform_8b_10b_link_training(link, &legacy_settings); + return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings); } dpcd_set_link_settings(link, lt_settings); if (result == LINK_TRAINING_SUCCESS) - result = dp_perform_128b_132b_channel_eq_done_sequence(link, lt_settings); + result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings); if (result == LINK_TRAINING_SUCCESS) - result = dp_perform_128b_132b_cds_done_sequence(link, lt_settings); + result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings); return result; } #endif +static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; + const uint8_t offset = dp_convert_to_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; + const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68}; + uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; + uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; + uint32_t vendor_lttpr_write_address = 0xF004F; + enum link_training_result status = LINK_TRAINING_SUCCESS; + uint8_t lane = 0; + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; + uint8_t toggle_rate; + uint8_t rate; + + /* Only 8b/10b is supported */ + ASSERT(dp_get_link_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING); + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + } + + /* Vendor specific: Reset lane settings */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_reset[0], + sizeof(vendor_lttpr_write_data_reset)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* Vendor specific: Enable intercept */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + + /* 1. set link rate, lane count and spread. */ + + downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); + + lane_count_set.bits.LANE_COUNT_SET = + lt_settings->link_settings.lane_count; + + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + + if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } + + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + + core_link_write_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, 1); + +#if defined(CONFIG_DRM_AMD_DC_DCN) + rate = get_dpcd_link_rate(<_settings->link_settings); +#else + rate = (uint8_t) (lt_settings->link_settings.link_rate); +#endif + + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + + if (link->vendor_specific_lttpr_link_rate_wa == rate) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &toggle_rate, + 1); + } + + link->vendor_specific_lttpr_link_rate_wa = rate; + + core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_BW_SET, + lt_settings->link_settings.link_rate, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + + /* 2. Perform link training */ + + /* Perform Clock Recovery Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + uint32_t retries_cr; + uint32_t retry_count; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; + union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + retries_cr = 0; + retry_count = 0; + + while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + + memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); + memset(&dpcd_lane_status_updated, '\0', + sizeof(dpcd_lane_status_updated)); + + /* 1. call HWSS to set lane settings */ + dp_set_hw_lane_settings( + link, + link_res, + lt_settings, + 0); + + /* 2. update DPCD of the receiver */ + if (!retry_count) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration. + */ + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + lt_settings->pattern_for_cr, + 0); + /* Vendor specific: Disable intercept */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_dis[0], + sizeof(vendor_lttpr_write_data_intercept_dis)); + } else { + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + dpcd_set_lane_settings( + link, + lt_settings, + 0); + } + + /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested drive + * settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 6. max VS reached*/ + if (dp_is_max_vs_reached(lt_settings)) + break; + + /* 7. same lane settings */ + /* Note: settings are the same for all lanes, + * so comparing first lane is sufficient + */ + if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + retries_cr++; + else + retries_cr = 0; + + /* 8. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + retry_count++; + } + + if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { + ASSERT(0); + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + __func__, + LINK_TRAINING_MAX_CR_RETRY); + + } + + status = dp_get_cr_failure(lane_count, dpcd_lane_status); + } + + /* Perform Channel EQ Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + enum dc_dp_training_pattern tr_pattern; + uint32_t retries_ch_eq; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; + + dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); + + status = LINK_TRAINING_EQ_FAIL_EQ; + + for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; + retries_ch_eq++) { + + dp_set_hw_lane_settings(link, link_res, lt_settings, 0); + + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* 2. update DPCD*/ + if (!retries_ch_eq) + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration + */ + + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + tr_pattern, 0); + else + dpcd_set_lane_settings(link, lt_settings, 0); + + /* 3. wait for receiver to lock-on*/ + wait_time_microsec = lt_settings->eq_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested + * drive settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_EQ_FAIL_CR; + break; + } + + /* 6. check CHEQ done*/ + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 7. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + } + + return status; +} + + enum link_training_result dc_link_dp_perform_link_training( struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_settings, bool skip_video_pattern) { @@ -2459,18 +2806,22 @@ enum link_training_result dc_link_dp_perform_link_training( /* configure link prior to entering training mode */ dpcd_configure_lttpr_mode(link, <_settings); - dp_set_fec_ready(link, lt_settings.should_set_fec_ready); + dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready); dpcd_configure_channel_coding(link, <_settings); /* enter training mode: * Per DP specs starting from here, DPTX device shall not issue * Non-LT AUX transactions inside training mode. */ - if (encoding == DP_8b_10b_ENCODING) - status = dp_perform_8b_10b_link_training(link, <_settings); + if (!link->dc->debug.apply_vendor_specific_lttpr_wa && + (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + link->lttpr_mode == LTTPR_MODE_TRANSPARENT) + status = dc_link_dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); + else if (encoding == DP_8b_10b_ENCODING) + status = dp_perform_8b_10b_link_training(link, link_res, <_settings); #if defined(CONFIG_DRM_AMD_DC_DCN) else if (encoding == DP_128b_132b_ENCODING) - status = dp_perform_128b_132b_link_training(link, <_settings); + status = dp_perform_128b_132b_link_training(link, link_res, <_settings); #endif else ASSERT(0); @@ -2488,6 +2839,7 @@ enum link_training_result dc_link_dp_perform_link_training( /* switch to video idle */ if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) status = dp_transition_to_video_idle(link, + link_res, <_settings, status); @@ -2539,6 +2891,7 @@ bool perform_link_training_with_retries( dp_enable_link_phy( link, + &pipe_ctx->link_res, signal, pipe_ctx->clock_source->id, ¤t_setting); @@ -2566,23 +2919,24 @@ bool perform_link_training_with_retries( dp_set_panel_mode(link, panel_mode); if (link->aux_access_disabled) { - dc_link_dp_perform_link_training_skip_aux(link, ¤t_setting); + dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, ¤t_setting); return true; } else { /** @todo Consolidate USB4 DP and DPx.x training. */ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { status = dc_link_dpia_perform_link_training(link, - ¤t_setting, - skip_video_pattern); + &pipe_ctx->link_res, + ¤t_setting, + skip_video_pattern); /* Transmit idle pattern once training successful. */ if (status == LINK_TRAINING_SUCCESS) - dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, - NULL, 0); + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); } else { status = dc_link_dp_perform_link_training(link, - ¤t_setting, - skip_video_pattern); + &pipe_ctx->link_res, + ¤t_setting, + skip_video_pattern); } if (status == LINK_TRAINING_SUCCESS) @@ -2597,7 +2951,7 @@ bool perform_link_training_with_retries( DC_LOG_WARNING("%s: Link training attempt %u of %d failed\n", __func__, (unsigned int)j + 1, attempts); - dp_disable_link_phy(link, signal); + dp_disable_link_phy(link, &pipe_ctx->link_res, signal); /* Abort link training if failure due to sink being unplugged. */ if (status == LINK_TRAINING_ABORT) { @@ -2646,12 +3000,13 @@ static enum clock_source_id get_clock_source_id(struct dc_link *link) return dp_cs_id; } -static void set_dp_mst_mode(struct dc_link *link, bool mst_enable) +static void set_dp_mst_mode(struct dc_link *link, const struct link_resource *link_res, + bool mst_enable) { if (mst_enable == false && link->type == dc_connection_mst_branch) { /* Disable MST on link. Use only local sink. */ - dp_disable_link_phy_mst(link, link->connector_signal); + dp_disable_link_phy_mst(link, link_res, link->connector_signal); link->type = dc_connection_single; link->local_sink = link->remote_sinks[0]; @@ -2662,7 +3017,7 @@ static void set_dp_mst_mode(struct dc_link *link, bool mst_enable) link->type == dc_connection_single && link->remote_sinks[0] != NULL) { /* Re-enable MST on link. */ - dp_disable_link_phy(link, link->connector_signal); + dp_disable_link_phy(link, link_res, link->connector_signal); dp_enable_mst_on_sink(link, true); link->type = dc_connection_mst_branch; @@ -2688,6 +3043,7 @@ bool dc_link_dp_sync_lt_begin(struct dc_link *link) enum link_training_result dc_link_dp_sync_lt_attempt( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *link_settings, struct dc_link_training_overrides *lt_overrides) { @@ -2707,14 +3063,14 @@ enum link_training_result dc_link_dp_sync_lt_attempt( <_settings); /* Setup MST Mode */ if (lt_overrides->mst_enable) - set_dp_mst_mode(link, *lt_overrides->mst_enable); + set_dp_mst_mode(link, link_res, *lt_overrides->mst_enable); /* Disable link */ - dp_disable_link_phy(link, link->connector_signal); + dp_disable_link_phy(link, link_res, link->connector_signal); /* Enable link */ dp_cs_id = get_clock_source_id(link); - dp_enable_link_phy(link, link->connector_signal, + dp_enable_link_phy(link, link_res, link->connector_signal, dp_cs_id, link_settings); /* Set FEC enable */ @@ -2722,7 +3078,7 @@ enum link_training_result dc_link_dp_sync_lt_attempt( if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { #endif fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable; - dp_set_fec_ready(link, fec_enable); + dp_set_fec_ready(link, NULL, fec_enable); #if defined(CONFIG_DRM_AMD_DC_DCN) } #endif @@ -2739,7 +3095,7 @@ enum link_training_result dc_link_dp_sync_lt_attempt( /* Attempt to train with given link training settings */ if (link->ctx->dc->work_arounds.lt_early_cr_pattern) - start_clock_recovery_pattern_early(link, <_settings, DPRX); + start_clock_recovery_pattern_early(link, link_res, <_settings, DPRX); /* Set link rate, lane count and spread. */ dpcd_set_link_settings(link, <_settings); @@ -2747,9 +3103,10 @@ enum link_training_result dc_link_dp_sync_lt_attempt( /* 2. perform link training (set link training done * to false is done as well) */ - lt_status = perform_clock_recovery_sequence(link, <_settings, DPRX); + lt_status = perform_clock_recovery_sequence(link, link_res, <_settings, DPRX); if (lt_status == LINK_TRAINING_SUCCESS) { lt_status = perform_channel_equalization_sequence(link, + link_res, <_settings, DPRX); } @@ -2770,11 +3127,11 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) #if defined(CONFIG_DRM_AMD_DC_DCN) struct dc_link_settings link_settings = link->cur_link_settings; #endif - dp_disable_link_phy(link, link->connector_signal); + dp_disable_link_phy(link, NULL, link->connector_signal); #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) #endif - dp_set_fec_ready(link, false); + dp_set_fec_ready(link, NULL, false); } link->sync_lt_in_progress = false; @@ -2829,7 +3186,8 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_ return false; } -static struct dc_link_settings get_max_link_cap(struct dc_link *link) +static struct dc_link_settings get_max_link_cap(struct dc_link *link, + const struct link_resource *link_res) { struct dc_link_settings max_link_cap = {0}; #if defined(CONFIG_DRM_AMD_DC_DCN) @@ -2853,9 +3211,11 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) if (link_enc) link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap); #if defined(CONFIG_DRM_AMD_DC_DCN) - if (max_link_cap.link_rate >= LINK_RATE_UHBR10 && - !link->hpo_dp_link_enc) - max_link_cap.link_rate = LINK_RATE_HIGH3; + if (max_link_cap.link_rate >= LINK_RATE_UHBR10) { + if (!link_res->hpo_dp_link_enc || + link->dc->debug.disable_uhbr) + max_link_cap.link_rate = LINK_RATE_HIGH3; + } #endif /* Lower link settings based on sink's link cap */ @@ -2873,7 +3233,7 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) * account for lttpr repeaters cap * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). */ - if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + if (link->lttpr_mode != LTTPR_MODE_NON_LTTPR) { if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count) max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count; @@ -3012,6 +3372,7 @@ bool hpd_rx_irq_check_link_loss_status( bool dp_verify_link_cap( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *known_limit_link_setting, int *fail_count) { @@ -3029,7 +3390,7 @@ bool dp_verify_link_cap( /* link training starts with the maximum common settings * supported by both sink and ASIC. */ - max_link_cap = get_max_link_cap(link); + max_link_cap = get_max_link_cap(link, link_res); initial_link_settings = get_common_supported_link_settings( *known_limit_link_setting, max_link_cap); @@ -3069,7 +3430,7 @@ bool dp_verify_link_cap( * find the physical link capability */ /* disable PHY done possible by BIOS, will be done by driver itself */ - dp_disable_link_phy(link, link->connector_signal); + dp_disable_link_phy(link, link_res, link->connector_signal); dp_cs_id = get_clock_source_id(link); @@ -3081,8 +3442,8 @@ bool dp_verify_link_cap( */ if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C && link->dc->debug.usbc_combo_phy_reset_wa) { - dp_enable_link_phy(link, link->connector_signal, dp_cs_id, cur); - dp_disable_link_phy(link, link->connector_signal); + dp_enable_link_phy(link, link_res, link->connector_signal, dp_cs_id, cur); + dp_disable_link_phy(link, link_res, link->connector_signal); } do { @@ -3093,6 +3454,7 @@ bool dp_verify_link_cap( dp_enable_link_phy( link, + link_res, link->connector_signal, dp_cs_id, cur); @@ -3103,6 +3465,7 @@ bool dp_verify_link_cap( else { status = dc_link_dp_perform_link_training( link, + link_res, cur, skip_video_pattern); if (status == LINK_TRAINING_SUCCESS) @@ -3124,7 +3487,7 @@ bool dp_verify_link_cap( * setting or before returning we'll enable it later * based on the actual mode we're driving */ - dp_disable_link_phy(link, link->connector_signal); + dp_disable_link_phy(link, link_res, link->connector_signal); } while (!success && decide_fallback_link_setting(link, initial_link_settings, cur, status)); @@ -3148,6 +3511,7 @@ bool dp_verify_link_cap( bool dp_verify_link_cap_with_retries( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *known_limit_link_setting, int attempts) { @@ -3165,7 +3529,7 @@ bool dp_verify_link_cap_with_retries( link->verified_link_cap.link_rate = LINK_RATE_LOW; link->verified_link_cap.link_spread = LINK_SPREAD_DISABLED; break; - } else if (dp_verify_link_cap(link, + } else if (dp_verify_link_cap(link, link_res, known_limit_link_setting, &fail_count) && fail_count == 0) { success = true; @@ -3177,13 +3541,13 @@ bool dp_verify_link_cap_with_retries( } bool dp_verify_mst_link_cap( - struct dc_link *link) + struct dc_link *link, const struct link_resource *link_res) { struct dc_link_settings max_link_cap = {0}; if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_8b_10b_ENCODING) { - max_link_cap = get_max_link_cap(link); + max_link_cap = get_max_link_cap(link, link_res); link->verified_link_cap = get_common_supported_link_settings( link->reported_link_cap, max_link_cap); @@ -3192,6 +3556,7 @@ bool dp_verify_mst_link_cap( else if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING) { dp_verify_link_cap_with_retries(link, + link_res, &link->reported_link_cap, LINK_TRAINING_MAX_VERIFY_RETRY); } @@ -5720,7 +6085,7 @@ bool dc_link_dp_set_test_pattern( DP_TEST_PATTERN_VIDEO_MODE) { /* Set CRTC Test Pattern */ set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); - dp_set_hw_test_pattern(link, test_pattern, + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, (uint8_t *)p_custom_pattern, (uint32_t)cust_pattern_size); @@ -5751,7 +6116,7 @@ bool dc_link_dp_set_test_pattern( p_link_settings->dpcd_lane_settings, p_link_settings->link_settings.lane_count); } else { - dp_set_hw_lane_settings(link, p_link_settings, DPRX); + dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX); dpcd_set_lane_settings(link, p_link_settings, DPRX); } } @@ -5766,7 +6131,7 @@ bool dc_link_dp_set_test_pattern( pipes->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc); } - dp_set_hw_test_pattern(link, test_pattern, + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, (uint8_t *)p_custom_pattern, (uint32_t)cust_pattern_size); @@ -6086,7 +6451,7 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) return DP_PANEL_MODE_DEFAULT; } -enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready) +enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready) { /* FEC has to be "set ready" before the link training. * The policy is to always train with FEC @@ -6653,8 +7018,10 @@ struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) { + /* If this assert is hit then we have a link encoder dynamic management issue */ + ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); return (pipe_ctx->stream_res.hpo_dp_stream_enc && - pipe_ctx->stream->link->hpo_dp_link_enc && + pipe_ctx->link_res.hpo_dp_link_enc && dc_is_dp_signal(pipe_ctx->stream->signal)); } #endif diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c index d72122593959..0e95bc5df4e7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c @@ -77,7 +77,9 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) * @param[in] link_setting Lane count, link rate and downspread control. * @param[out] lt_settings Link settings and drive settings (voltage swing and pre-emphasis). */ -static enum link_training_result dpia_configure_link(struct dc_link *link, +static enum link_training_result dpia_configure_link( + struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_setting, struct link_training_settings *lt_settings) { @@ -111,7 +113,7 @@ static enum link_training_result dpia_configure_link(struct dc_link *link, fec_enable = *link->preferred_training_settings.fec_enable; else fec_enable = true; - status = dp_set_fec_ready(link, fec_enable); + status = dp_set_fec_ready(link, link_res, fec_enable); if (status != DC_OK && link->is_hpd_pending) return LINK_TRAINING_ABORT; @@ -252,7 +254,9 @@ static enum dc_status dpcd_set_lt_pattern(struct dc_link *link, * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). * @param hop The Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_cr_non_transparent(struct dc_link *link, +static enum link_training_result dpia_training_cr_non_transparent( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t hop) { @@ -411,7 +415,9 @@ static enum link_training_result dpia_training_cr_non_transparent(struct dc_link * @param link DPIA link being trained. * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). */ -static enum link_training_result dpia_training_cr_transparent(struct dc_link *link, +static enum link_training_result dpia_training_cr_transparent( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0; @@ -511,16 +517,18 @@ static enum link_training_result dpia_training_cr_transparent(struct dc_link *li * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). * @param hop The Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_cr_phase(struct dc_link *link, +static enum link_training_result dpia_training_cr_phase( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t hop) { enum link_training_result result = LINK_TRAINING_CR_FAIL_LANE0; if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - result = dpia_training_cr_non_transparent(link, lt_settings, hop); + result = dpia_training_cr_non_transparent(link, link_res, lt_settings, hop); else - result = dpia_training_cr_transparent(link, lt_settings); + result = dpia_training_cr_transparent(link, link_res, lt_settings); return result; } @@ -561,7 +569,9 @@ static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link, * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). * @param hop The Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_eq_non_transparent(struct dc_link *link, +static enum link_training_result dpia_training_eq_non_transparent( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t hop) { @@ -700,7 +710,9 @@ static enum link_training_result dpia_training_eq_non_transparent(struct dc_link * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). * @param hop The Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_eq_transparent(struct dc_link *link, +static enum link_training_result dpia_training_eq_transparent( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings) { enum link_training_result result = LINK_TRAINING_EQ_FAIL_EQ; @@ -779,16 +791,18 @@ static enum link_training_result dpia_training_eq_transparent(struct dc_link *li * @param lt_settings link_setting and drive settings (voltage swing and pre-emphasis). * @param hop The Hop in display path. DPRX = 0. */ -static enum link_training_result dpia_training_eq_phase(struct dc_link *link, +static enum link_training_result dpia_training_eq_phase( + struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings, uint32_t hop) { enum link_training_result result; if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) - result = dpia_training_eq_non_transparent(link, lt_settings, hop); + result = dpia_training_eq_non_transparent(link, link_res, lt_settings, hop); else - result = dpia_training_eq_transparent(link, lt_settings); + result = dpia_training_eq_transparent(link, link_res, lt_settings); return result; } @@ -908,7 +922,9 @@ static void dpia_training_abort(struct dc_link *link, uint32_t hop) core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data); } -enum link_training_result dc_link_dpia_perform_link_training(struct dc_link *link, +enum link_training_result dc_link_dpia_perform_link_training( + struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_setting, bool skip_video_pattern) { @@ -918,7 +934,7 @@ enum link_training_result dc_link_dpia_perform_link_training(struct dc_link *lin int8_t repeater_id; /* Current hop. */ /* Configure link as prescribed in link_setting and set LTTPR mode. */ - result = dpia_configure_link(link, link_setting, <_settings); + result = dpia_configure_link(link, link_res, link_setting, <_settings); if (result != LINK_TRAINING_SUCCESS) return result; @@ -930,12 +946,12 @@ enum link_training_result dc_link_dpia_perform_link_training(struct dc_link *lin */ for (repeater_id = repeater_cnt; repeater_id >= 0; repeater_id--) { /* Clock recovery. */ - result = dpia_training_cr_phase(link, <_settings, repeater_id); + result = dpia_training_cr_phase(link, link_res, <_settings, repeater_id); if (result != LINK_TRAINING_SUCCESS) break; /* Equalization. */ - result = dpia_training_eq_phase(link, <_settings, repeater_id); + result = dpia_training_eq_phase(link, link_res, <_settings, repeater_id); if (result != LINK_TRAINING_SUCCESS) break; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 368e834c6809..45d03d3a95c3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -71,6 +71,7 @@ void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) void dp_enable_link_phy( struct dc_link *link, + const struct link_resource *link_res, enum signal_type signal, enum clock_source_id clock_source, const struct dc_link_settings *link_settings) @@ -135,7 +136,7 @@ void dp_enable_link_phy( #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) { - enable_dp_hpo_output(link, link_settings); + enable_dp_hpo_output(link, link_res, link_settings); } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) { if (dc_is_dp_sst_signal(signal)) { link_enc->funcs->enable_dp_output( @@ -236,12 +237,13 @@ bool edp_receiver_ready_T7(struct dc_link *link) return result; } -void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) +void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal) { struct dc *dc = link->ctx->dc; struct dmcu *dmcu = dc->res_pool->dmcu; #if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_link_enc = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_link_enc = link_res->hpo_dp_link_enc; #endif struct link_encoder *link_enc; @@ -260,7 +262,7 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) link->dc->hwss.edp_backlight_control(link, false); #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING) - disable_dp_hpo_output(link, signal); + disable_dp_hpo_output(link, link_res, signal); else link_enc->funcs->disable_output(link_enc, signal); #else @@ -274,7 +276,7 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING && hpo_link_enc) - disable_dp_hpo_output(link, signal); + disable_dp_hpo_output(link, link_res, signal); else link_enc->funcs->disable_output(link_enc, signal); #else @@ -294,13 +296,14 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link); } -void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) +void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal) { /* MST disable link only when no stream use the link */ if (link->mst_stream_alloc_table.stream_count > 0) return; - dp_disable_link_phy(link, signal); + dp_disable_link_phy(link, link_res, signal); /* set the sink to SST mode after disabling the link */ dp_enable_mst_on_sink(link, false); @@ -308,6 +311,7 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) bool dp_set_hw_training_pattern( struct dc_link *link, + const struct link_resource *link_res, enum dc_dp_training_pattern pattern, uint32_t offset) { @@ -338,7 +342,7 @@ bool dp_set_hw_training_pattern( break; } - dp_set_hw_test_pattern(link, test_pattern, NULL, 0); + dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0); return true; } @@ -349,6 +353,7 @@ bool dp_set_hw_training_pattern( #endif void dp_set_hw_lane_settings( struct dc_link *link, + const struct link_resource *link_res, const struct link_training_settings *link_settings, uint32_t offset) { @@ -361,8 +366,8 @@ void dp_set_hw_lane_settings( #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link_settings->link_settings) == DP_128b_132b_ENCODING) { - link->hpo_dp_link_enc->funcs->set_ffe( - link->hpo_dp_link_enc, + link_res->hpo_dp_link_enc->funcs->set_ffe( + link_res->hpo_dp_link_enc, &link_settings->link_settings, link_settings->lane_settings[0].FFE_PRESET.raw); } else if (dp_get_link_encoding_format(&link_settings->link_settings) @@ -379,6 +384,7 @@ void dp_set_hw_lane_settings( void dp_set_hw_test_pattern( struct dc_link *link, + const struct link_resource *link_res, enum dp_test_pattern test_pattern, uint8_t *custom_pattern, uint32_t custom_pattern_size) @@ -406,8 +412,8 @@ void dp_set_hw_test_pattern( #if defined(CONFIG_DRM_AMD_DC_DCN) switch (link_encoding_format) { case DP_128b_132b_ENCODING: - link->hpo_dp_link_enc->funcs->set_link_test_pattern( - link->hpo_dp_link_enc, &pattern_param); + link_res->hpo_dp_link_enc->funcs->set_link_test_pattern( + link_res->hpo_dp_link_enc, &pattern_param); break; case DP_8b_10b_ENCODING: ASSERT(encoder); @@ -446,7 +452,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, pipes[i].stream_res.stream_enc); /* disable any test pattern that might be active */ - dp_set_hw_test_pattern(link, + dp_set_hw_test_pattern(link, &pipes[i].link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); dp_receiver_power_ctrl(link, false); @@ -763,7 +769,9 @@ static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link) } } -void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *link_settings) +void enable_dp_hpo_output(struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_settings) { const struct dc *dc = link->dc; enum phyd32clk_clock_source phyd32clk; @@ -789,10 +797,11 @@ void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *l } } else { /* DP2.0 HW: call transmitter control to enable PHY */ - link->hpo_dp_link_enc->funcs->enable_link_phy( - link->hpo_dp_link_enc, + link_res->hpo_dp_link_enc->funcs->enable_link_phy( + link_res->hpo_dp_link_enc, link_settings, - link->link_enc->transmitter); + link->link_enc->transmitter, + link->link_enc->hpd_source); } /* DCCG muxing and DTBCLK DTO */ @@ -806,24 +815,26 @@ void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *l phyd32clk = get_phyd32clk_src(link); dc->res_pool->dccg->funcs->enable_symclk32_le( dc->res_pool->dccg, - link->hpo_dp_link_enc->inst, + link_res->hpo_dp_link_enc->inst, phyd32clk); - link->hpo_dp_link_enc->funcs->link_enable( - link->hpo_dp_link_enc, - link_settings->lane_count); + link_res->hpo_dp_link_enc->funcs->link_enable( + link_res->hpo_dp_link_enc, + link_settings->lane_count); } } -void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal) +void disable_dp_hpo_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal) { const struct dc *dc = link->dc; - link->hpo_dp_link_enc->funcs->link_disable(link->hpo_dp_link_enc); + link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc); if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { dc->res_pool->dccg->funcs->disable_symclk32_le( dc->res_pool->dccg, - link->hpo_dp_link_enc->inst); + link_res->hpo_dp_link_enc->inst); dc->res_pool->dccg->funcs->set_physymclk( dc->res_pool->dccg, @@ -834,8 +845,8 @@ void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal) dm_set_phyd32clk(dc->ctx, 0); } else { /* DP2.0 HW: call transmitter control to disable PHY */ - link->hpo_dp_link_enc->funcs->disable_link_phy( - link->hpo_dp_link_enc, + link_res->hpo_dp_link_enc->funcs->disable_link_phy( + link_res->hpo_dp_link_enc, signal); } } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 8b6b035bfa9c..b3912ff9dc91 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -734,10 +734,6 @@ static void calculate_split_count_and_index(struct pipe_ctx *pipe_ctx, int *spli (*split_idx)++; split_pipe = split_pipe->top_pipe; } - - /* MPO window on right side of ODM split */ - if (split_pipe && split_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) - (*split_idx)++; } else { /*Get odm split index*/ struct pipe_ctx *split_pipe = pipe_ctx->prev_odm_pipe; @@ -784,11 +780,7 @@ static void calculate_recout(struct pipe_ctx *pipe_ctx) /* * Only the leftmost ODM pipe should be offset by a nonzero distance */ - if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe && !pipe_ctx->prev_odm_pipe) { - /* MPO window on right side of ODM split */ - data->recout.x = stream->dst.x + (surf_clip.x - stream->dst.width/2) * - stream->dst.width / stream->src.width; - } else if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { + if (!pipe_ctx->prev_odm_pipe || split_idx == split_count) { data->recout.x = stream->dst.x; if (stream->src.x < surf_clip.x) data->recout.x += (surf_clip.x - stream->src.x) * stream->dst.width @@ -986,8 +978,6 @@ static void calculate_inits_and_viewports(struct pipe_ctx *pipe_ctx) * stream->dst.height / stream->src.height; if (pipe_ctx->prev_odm_pipe && split_idx) ro_lb = data->h_active * split_idx - recout_full_x; - else if (pipe_ctx->top_pipe && pipe_ctx->top_pipe->prev_odm_pipe) - ro_lb = data->h_active * split_idx - recout_full_x + data->recout.x; else ro_lb = data->recout.x - recout_full_x; ro_tb = data->recout.y - recout_full_y; @@ -1086,9 +1076,6 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) timing->v_border_top + timing->v_border_bottom; if (pipe_ctx->next_odm_pipe || pipe_ctx->prev_odm_pipe) pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx) + 1; - /* ODM + windows MPO, where window is on either right or left ODM half */ - else if (pipe_ctx->top_pipe && (pipe_ctx->top_pipe->next_odm_pipe || pipe_ctx->top_pipe->prev_odm_pipe)) - pipe_ctx->plane_res.scl_data.h_active /= get_num_odm_splits(pipe_ctx->top_pipe) + 1; /* depends on h_active */ calculate_recout(pipe_ctx); @@ -1097,6 +1084,11 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) /* depends on scaling ratios and recout, does not calculate offset yet */ calculate_viewport_size(pipe_ctx); + /* Stopgap for validation of ODM + MPO on one side of screen case */ + if (pipe_ctx->plane_res.scl_data.viewport.height < 1 || + pipe_ctx->plane_res.scl_data.viewport.width < 1) + return false; + /* * LB calculations depend on vp size, h/v_active and scaling ratios * Setting line buffer pixel depth to 24bpp yields banding @@ -1445,54 +1437,23 @@ bool dc_add_plane_to_context( if (head_pipe != free_pipe) { tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); ASSERT(tail_pipe); - - /* ODM + window MPO, where MPO window is on right half only */ - if (free_pipe->plane_state && - (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.width/2) && - tail_pipe->next_odm_pipe) { - free_pipe->stream_res.tg = tail_pipe->next_odm_pipe->stream_res.tg; - free_pipe->stream_res.abm = tail_pipe->next_odm_pipe->stream_res.abm; - free_pipe->stream_res.opp = tail_pipe->next_odm_pipe->stream_res.opp; - free_pipe->stream_res.stream_enc = tail_pipe->next_odm_pipe->stream_res.stream_enc; - free_pipe->stream_res.audio = tail_pipe->next_odm_pipe->stream_res.audio; - free_pipe->clock_source = tail_pipe->next_odm_pipe->clock_source; - - free_pipe->top_pipe = tail_pipe->next_odm_pipe; - tail_pipe->next_odm_pipe->bottom_pipe = free_pipe; - } else { - free_pipe->stream_res.tg = tail_pipe->stream_res.tg; - free_pipe->stream_res.abm = tail_pipe->stream_res.abm; - free_pipe->stream_res.opp = tail_pipe->stream_res.opp; - free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; - free_pipe->stream_res.audio = tail_pipe->stream_res.audio; - free_pipe->clock_source = tail_pipe->clock_source; - - free_pipe->top_pipe = tail_pipe; - tail_pipe->bottom_pipe = free_pipe; - - if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { - free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe; - tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe; - } - if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) { - free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; - tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; - } + free_pipe->stream_res.tg = tail_pipe->stream_res.tg; + free_pipe->stream_res.abm = tail_pipe->stream_res.abm; + free_pipe->stream_res.opp = tail_pipe->stream_res.opp; + free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; + free_pipe->stream_res.audio = tail_pipe->stream_res.audio; + free_pipe->clock_source = tail_pipe->clock_source; + free_pipe->top_pipe = tail_pipe; + tail_pipe->bottom_pipe = free_pipe; + if (!free_pipe->next_odm_pipe && tail_pipe->next_odm_pipe && tail_pipe->next_odm_pipe->bottom_pipe) { + free_pipe->next_odm_pipe = tail_pipe->next_odm_pipe->bottom_pipe; + tail_pipe->next_odm_pipe->bottom_pipe->prev_odm_pipe = free_pipe; + } + if (!free_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe && tail_pipe->prev_odm_pipe->bottom_pipe) { + free_pipe->prev_odm_pipe = tail_pipe->prev_odm_pipe->bottom_pipe; + tail_pipe->prev_odm_pipe->bottom_pipe->next_odm_pipe = free_pipe; } } - - /* ODM + window MPO, where MPO window is on left half only */ - if (free_pipe->plane_state && - (free_pipe->plane_state->clip_rect.x + free_pipe->plane_state->clip_rect.width <= - free_pipe->stream->src.x + free_pipe->stream->src.width/2)) { - break; - } - /* ODM + window MPO, where MPO window is on right half only */ - if (free_pipe->plane_state && - (free_pipe->plane_state->clip_rect.x >= free_pipe->stream->src.width/2)) { - break; - } - head_pipe = head_pipe->next_odm_pipe; } /* assign new surfaces*/ @@ -1763,6 +1724,94 @@ static void update_hpo_dp_stream_engine_usage( res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired; } } + +static inline int find_acquired_hpo_dp_link_enc_for_link( + const struct resource_context *res_ctx, + const struct dc_link *link) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++) + if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 && + res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index) + return i; + + return -1; +} + +static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx, + const struct resource_pool *pool) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++) + if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0) + break; + + return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) && + i < pool->hpo_dp_link_enc_count) ? i : -1; +} + +static inline void acquire_hpo_dp_link_enc( + struct resource_context *res_ctx, + unsigned int link_index, + int enc_index) +{ + res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index; + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1; +} + +static inline void retain_hpo_dp_link_enc( + struct resource_context *res_ctx, + int enc_index) +{ + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++; +} + +static inline void release_hpo_dp_link_enc( + struct resource_context *res_ctx, + int enc_index) +{ + ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0); + res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--; +} + +static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *pipe_ctx, + struct dc_stream_state *stream) +{ + int enc_index; + + enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); + + if (enc_index >= 0) { + retain_hpo_dp_link_enc(res_ctx, enc_index); + } else { + enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); + if (enc_index >= 0) + acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index); + } + + if (enc_index >= 0) + pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; + + return pipe_ctx->link_res.hpo_dp_link_enc != NULL; +} + +static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx, + struct pipe_ctx *pipe_ctx, + struct dc_stream_state *stream) +{ + int enc_index; + + enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link); + + if (enc_index >= 0) { + release_hpo_dp_link_enc(res_ctx, enc_index); + pipe_ctx->link_res.hpo_dp_link_enc = NULL; + } +} #endif /* TODO: release audio object */ @@ -1925,6 +1974,7 @@ enum dc_status dc_remove_stream_from_ctx( &new_ctx->res_ctx, dc->res_pool, del_pipe->stream_res.hpo_dp_stream_enc, false); + remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream); } #endif @@ -2200,6 +2250,8 @@ enum dc_status resource_map_pool_resources( &context->res_ctx, pool, pipe_ctx->stream_res.hpo_dp_stream_enc, true); + if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream)) + return DC_NO_LINK_ENC_RESOURCE; } } #endif @@ -2875,6 +2927,8 @@ bool pipe_need_reprogram( #if defined(CONFIG_DRM_AMD_DC_DCN) if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc) return true; + if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc) + return true; #endif /* DIG link encoder resource assignment for stream changed. */ @@ -3143,22 +3197,23 @@ void get_audio_check(struct audio_info *aud_modes, } #if defined(CONFIG_DRM_AMD_DC_DCN) -struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder( - const struct resource_pool *pool) +struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt( + const struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct dc_link *link) { - uint8_t i; - struct hpo_dp_link_encoder *enc = NULL; + struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL; + int enc_index; - ASSERT(pool->hpo_dp_link_enc_count <= MAX_HPO_DP2_LINK_ENCODERS); + enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link); - for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { - if (pool->hpo_dp_link_enc[i]->transmitter == TRANSMITTER_UNKNOWN) { - enc = pool->hpo_dp_link_enc[i]; - break; - } - } + if (enc_index < 0) + enc_index = find_free_hpo_dp_link_enc(res_ctx, pool); + + if (enc_index >= 0) + hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index]; - return enc; + return hpo_dp_link_enc; } #endif @@ -3215,3 +3270,36 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, i, disabled_master_pipe_idx); } } + +uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter) +{ + /* TODO - get transmitter to phy idx mapping from DMUB */ + uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A; + +#if defined(CONFIG_DRM_AMD_DC_DCN) + if (dc->ctx->dce_version == DCN_VERSION_3_1 && + dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + phy_idx = 0; + break; + case TRANSMITTER_UNIPHY_B: + phy_idx = 1; + break; + case TRANSMITTER_UNIPHY_C: + phy_idx = 5; + break; + case TRANSMITTER_UNIPHY_D: + phy_idx = 6; + break; + case TRANSMITTER_UNIPHY_E: + phy_idx = 4; + break; + default: + phy_idx = 0; + break; + } + } +#endif + return phy_idx; +} diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 18e59d635ca2..288e7b01f561 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -47,7 +47,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.166" +#define DC_VER "3.2.167" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -691,6 +691,7 @@ struct dc_debug_options { /* TODO - remove once tested */ bool legacy_dp2_lt; bool set_mst_en_for_sst; + bool disable_uhbr; bool force_dp2_lt_fallback_method; #endif union mem_low_power_enable_options enable_mem_low_power; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 4ebba641538b..c0e37ad0e26c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -30,6 +30,8 @@ #include "dc_types.h" #include "grph_object_defs.h" +struct link_resource; + enum dc_link_fec_state { dc_link_fec_not_ready, dc_link_fec_ready, @@ -160,9 +162,6 @@ struct dc_link { struct panel_cntl *panel_cntl; struct link_encoder *link_enc; -#if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_dp_link_enc; -#endif struct graphics_object_id link_id; /* Endpoint type distinguishes display endpoints which do not have entries * in the BIOS connector table from those that do. Helps when tracking link @@ -359,14 +358,17 @@ void dc_link_remove_remote_sink( void dc_link_dp_set_drive_settings( struct dc_link *link, + const struct link_resource *link_res, struct link_training_settings *lt_settings); bool dc_link_dp_perform_link_training_skip_aux( struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_setting); enum link_training_result dc_link_dp_perform_link_training( struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_settings, bool skip_video_pattern); @@ -374,6 +376,7 @@ bool dc_link_dp_sync_lt_begin(struct dc_link *link); enum link_training_result dc_link_dp_sync_lt_attempt( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *link_setting, struct dc_link_training_overrides *lt_settings); @@ -454,4 +457,10 @@ bool dc_link_should_enable_fec(const struct dc_link *link); uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw); enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link); #endif + +const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link); +/* take a snapshot of current link resource allocation state */ +void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map); +/* restore link resource allocation state from a snapshot */ +void dc_restore_link_res_map(const struct dc *dc, uint32_t *map); #endif /* DC_LINK_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 2d470f524367..530a72e3eefe 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -468,8 +468,6 @@ void dcn10_log_hw_state(struct dc *dc, log_mpc_crc(dc, log_ctx); { - int hpo_dp_link_enc_count = 0; - if (pool->hpo_dp_stream_enc_count > 0) { DTN_INFO("DP HPO S_ENC: Enabled OTG Format Depth Vid SDP Compressed Link\n"); for (i = 0; i < pool->hpo_dp_stream_enc_count; i++) { @@ -500,18 +498,14 @@ void dcn10_log_hw_state(struct dc *dc, } /* log DP HPO L_ENC section if any hpo_dp_link_enc exists */ - for (i = 0; i < dc->link_count; i++) - if (dc->links[i]->hpo_dp_link_enc) - hpo_dp_link_enc_count++; - - if (hpo_dp_link_enc_count) { + if (pool->hpo_dp_link_enc_count) { DTN_INFO("DP HPO L_ENC: Enabled Mode Lanes Stream Slots VC Rate X VC Rate Y\n"); - for (i = 0; i < dc->link_count; i++) { - struct hpo_dp_link_encoder *hpo_dp_link_enc = dc->links[i]->hpo_dp_link_enc; + for (i = 0; i < pool->hpo_dp_link_enc_count; i++) { + struct hpo_dp_link_encoder *hpo_dp_link_enc = pool->hpo_dp_link_enc[i]; struct hpo_dp_link_enc_state hpo_dp_le_state = {0}; - if (hpo_dp_link_enc && hpo_dp_link_enc->funcs->read_state) { + if (hpo_dp_link_enc->funcs->read_state) { hpo_dp_link_enc->funcs->read_state(hpo_dp_link_enc, &hpo_dp_le_state); DTN_INFO("[%d]: %d %6s %d %d %d %d %d\n", hpo_dp_link_enc->inst, @@ -1371,7 +1365,12 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context) uint32_t opp_id_src1 = OPP_ID_INVALID; // Step 1: To find out which OPTC is running & OPTC DSC is ON - for (i = 0; i < dc->res_pool->res_cap->num_timing_generator; i++) { + // We can't use res_pool->res_cap->num_timing_generator to check + // Because it records display pipes default setting built in driver, + // not display pipes of the current chip. + // Some ASICs would be fused display pipes less than the default setting. + // In dcnxx_resource_construct function, driver would obatin real information. + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { uint32_t optc_dsc_state = 0; struct timing_generator *tg = dc->res_pool->timing_generators[i]; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c index 34001a30d449..10e613ec7d24 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c @@ -78,6 +78,7 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .get_clock = dcn10_get_clock, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, .set_backlight_level = dce110_set_backlight_level, .set_abm_immediate_disable = dce110_set_abm_immediate_disable, .set_pipe = dce110_set_pipe, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index a17fe8ab2904..4991e93e5308 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2414,7 +2414,7 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->map_stream_to_link( pipe_ctx->stream_res.hpo_dp_stream_enc, pipe_ctx->stream_res.hpo_dp_stream_enc->inst, - link->hpo_dp_link_enc->inst); + pipe_ctx->link_res.hpo_dp_link_enc->inst); } if (!is_dp_128b_132b_signal(pipe_ctx) && link_enc) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 40b122a708ef..2bc93df023ad 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1069,7 +1069,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -3093,8 +3093,7 @@ static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struc else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) { struct dc_link *link = context->streams[0]->sink->link; - if ((link->link_index == 0 && link->psr_settings.psr_feature_enabled) - || context->bw_ctx.dml.vba.StutterPeriod > 5000.0) + if (link->link_index == 0 && context->bw_ctx.dml.vba.StutterPeriod > 5000.0) return DCN_ZSTATE_SUPPORT_ALLOW; else return DCN_ZSTATE_SUPPORT_DISALLOW; diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c index cfd09b3f705e..fe22530242d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c @@ -134,11 +134,12 @@ void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) PHYSICAL_ADDRESS_LOC addr; struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dce_hwseq *hws = dc->hwseq; - struct dc_plane_address uma = plane_state->address; + struct dc_plane_address uma; if (plane_state == NULL) return; + uma = plane_state->address; addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); plane_address_in_gpu_space_to_uma(hws, &uma); diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c index d6acf9a8590a..0bb7d3dd53fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c @@ -603,7 +603,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c index ca1bbc942fd4..e5cc6bf45743 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -873,7 +873,7 @@ static const struct dc_debug_options debug_defaults_drv = { .clock_trace = true, .disable_pplib_clock_request = true, .min_disp_clk_khz = 100000, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c index 369ceeeddc7e..602ec9a08549 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c @@ -840,7 +840,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -1761,17 +1761,6 @@ static bool dcn30_split_stream_for_mpc_or_odm( int pipe_idx = sec_pipe->pipe_idx; const struct resource_pool *pool = dc->res_pool; - if (pri_pipe->plane_state) { - /* ODM + window MPO, where MPO window is on left half only */ - if (pri_pipe->plane_state->clip_rect.x + pri_pipe->plane_state->clip_rect.width <= - pri_pipe->stream->src.x + pri_pipe->stream->src.width/2) - return true; - - /* ODM + window MPO, where MPO window is on right half only */ - if (pri_pipe->plane_state->clip_rect.x >= pri_pipe->stream->src.width/2) - return true; - } - *sec_pipe = *pri_pipe; sec_pipe->pipe_idx = pipe_idx; diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index b4001233867c..c1c6e602b06c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -686,7 +686,7 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_clock_gate = true, .disable_pplib_clock_request = true, .disable_pplib_wm_range = true, - .pipe_split_policy = MPC_SPLIT_AVOID, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c index 003e95368672..2e9cbfa7663b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c @@ -211,7 +211,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_dccg.h index a79c54bbc899..294bd757bcb5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_dccg.h @@ -15,7 +15,11 @@ SR(DPPCLK_DTO_CTRL),\ DCCG_SRII(DTO_PARAM, DPPCLK, 0),\ DCCG_SRII(DTO_PARAM, DPPCLK, 1),\ - SR(REFCLK_CNTL) + SR(REFCLK_CNTL),\ + SR(DISPCLK_FREQ_CHANGE_CNTL),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0),\ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1) + #define DCCG_MASK_SH_LIST_DCN3_03(mask_sh) \ DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ @@ -25,6 +29,18 @@ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(REFCLK_CNTL, REFCLK_CLOCK_EN, mask_sh),\ - DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh) + DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_STEP_DELAY, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_STEP_SIZE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_FREQ_RAMP_DONE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_MAX_ERRDET_CYCLES, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_RESET, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_STATE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_OVR_EN, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_CHG_FWD_CORR_DISABLE, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, ADD_PIXEL, 1, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 0, mask_sh),\ + DCCG_SFII(OTG, PIXEL_RATE_CNTL, OTG, DROP_PIXEL, 1, mask_sh) #endif //__DCN303_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c index 01ba9d656c72..2de687f64cf6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c @@ -193,7 +193,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index 71c359f9cdd2..8b9b1a5309ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -100,6 +100,35 @@ static uint8_t phy_id_from_transmitter(enum transmitter t) return phy_id; } +static bool has_query_dp_alt(struct link_encoder *enc) +{ + struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; + + /* Supports development firmware and firmware >= 4.0.11 */ + return dc_dmub_srv && + !(dc_dmub_srv->dmub->fw_version >= DMUB_FW_VERSION(4, 0, 0) && + dc_dmub_srv->dmub->fw_version <= DMUB_FW_VERSION(4, 0, 10)); +} + +static bool query_dp_alt_from_dmub(struct link_encoder *enc, + union dmub_rb_cmd *cmd) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; + + memset(cmd, 0, sizeof(*cmd)); + cmd->query_dp_alt.header.type = DMUB_CMD__VBIOS; + cmd->query_dp_alt.header.sub_type = + DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT; + cmd->query_dp_alt.header.payload_bytes = sizeof(cmd->query_dp_alt.data); + cmd->query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter); + + if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, cmd)) + return false; + + return true; +} + void dcn31_link_encoder_set_dio_phy_mux( struct link_encoder *enc, enum encoder_type_select sel, @@ -569,45 +598,90 @@ void dcn31_link_encoder_disable_output( bool dcn31_link_encoder_is_in_alt_mode(struct link_encoder *enc) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); - struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; union dmub_rb_cmd cmd; - bool is_usb_c_alt_mode = false; + uint32_t dp_alt_mode_disable; - if (enc->features.flags.bits.DP_IS_USB_C && dc_dmub_srv) { - memset(&cmd, 0, sizeof(cmd)); - cmd.query_dp_alt.header.type = DMUB_CMD__VBIOS; - cmd.query_dp_alt.header.sub_type = DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT; - cmd.query_dp_alt.header.payload_bytes = sizeof(cmd.panel_cntl.data); - cmd.query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter); + /* Only applicable to USB-C PHY. */ + if (!enc->features.flags.bits.DP_IS_USB_C) + return false; - if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd)) + /* + * Use the new interface from DMCUB if available. + * Avoids hanging the RDCPSPIPE if DMCUB wasn't already running. + */ + if (has_query_dp_alt(enc)) { + if (!query_dp_alt_from_dmub(enc, &cmd)) return false; - is_usb_c_alt_mode = (cmd.query_dp_alt.data.is_dp_alt_disable == 0); + return (cmd.query_dp_alt.data.is_dp_alt_disable == 0); } - return is_usb_c_alt_mode; + /* Legacy path, avoid if possible. */ + if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); + } else { + /* + * B0 phys use a new set of registers to check whether alt mode is disabled. + * if value == 1 alt mode is disabled, otherwise it is enabled. + */ + if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); + } else { + REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); + } + } + + return (dp_alt_mode_disable == 0); } void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc, struct dc_link_settings *link_settings) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); - struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; union dmub_rb_cmd cmd; + uint32_t is_in_usb_c_dp4_mode = 0; dcn10_link_encoder_get_max_link_cap(enc, link_settings); - if (enc->features.flags.bits.DP_IS_USB_C && dc_dmub_srv) { - memset(&cmd, 0, sizeof(cmd)); - cmd.query_dp_alt.header.type = DMUB_CMD__VBIOS; - cmd.query_dp_alt.header.sub_type = DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT; - cmd.query_dp_alt.header.payload_bytes = sizeof(cmd.panel_cntl.data); - cmd.query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter); + /* Take the link cap directly if not USB */ + if (!enc->features.flags.bits.DP_IS_USB_C) + return; - if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd)) + /* + * Use the new interface from DMCUB if available. + * Avoids hanging the RDCPSPIPE if DMCUB wasn't already running. + */ + if (has_query_dp_alt(enc)) { + if (!query_dp_alt_from_dmub(enc, &cmd)) return; - if (cmd.query_dp_alt.data.is_usb && cmd.query_dp_alt.data.is_dp4 == 0) + if (cmd.query_dp_alt.data.is_usb && + cmd.query_dp_alt.data.is_dp4 == 0) link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); + + return; } + + /* Legacy path, avoid if possible. */ + if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); + } else { + if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); + } else { + REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); + } + } + + if (!is_in_usb_c_dp4_mode) + link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c index 6c08e21bb708..80dfaa4d4d81 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c @@ -499,7 +499,8 @@ static enum bp_result link_transmitter_control( void dcn31_hpo_dp_link_enc_enable_dp_output( struct hpo_dp_link_encoder *enc, const struct dc_link_settings *link_settings, - enum transmitter transmitter) + enum transmitter transmitter, + enum hpd_source_id hpd_source) { struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc); struct bp_transmitter_control cntl = { 0 }; @@ -508,6 +509,9 @@ void dcn31_hpo_dp_link_enc_enable_dp_output( /* Set the transmitter */ enc3->base.transmitter = transmitter; + /* Set the hpd source */ + enc3->base.hpd_source = hpd_source; + /* Enable the PHY */ cntl.action = TRANSMITTER_CONTROL_ENABLE; cntl.engine_id = ENGINE_ID_UNKNOWN; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h index 0706ccaf6fec..e324e9b83136 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h @@ -184,7 +184,8 @@ void hpo_dp_link_encoder31_construct(struct dcn31_hpo_dp_link_encoder *enc31, void dcn31_hpo_dp_link_enc_enable_dp_output( struct hpo_dp_link_encoder *enc, const struct dc_link_settings *link_settings, - enum transmitter transmitter); + enum transmitter transmitter, + enum hpd_source_id hpd_source); void dcn31_hpo_dp_link_enc_disable_output( struct hpo_dp_link_encoder *enc, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c index 7a7a8c5edabd..d7559e5a99ce 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -103,6 +103,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .z10_restore = dcn31_z10_restore, .z10_save_init = dcn31_z10_save_init, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .optimize_pwr_state = dcn21_optimize_pwr_state, .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, .update_visual_confirm_color = dcn20_update_visual_confirm_color, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c index 29ee3c22b0ab..8d64187478e4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -355,6 +355,14 @@ static const struct dce110_clk_src_regs clk_src_regs[] = { clk_src_regs(3, D), clk_src_regs(4, E) }; +/*pll_id being rempped in dmub, in driver it is logical instance*/ +static const struct dce110_clk_src_regs clk_src_regs_b0[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, F), + clk_src_regs(3, G), + clk_src_regs(4, E) +}; static const struct dce110_clk_src_shift cs_shift = { CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) @@ -995,7 +1003,7 @@ static const struct dc_debug_options debug_defaults_drv = { .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_AVOID, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, .force_single_disp_pipe_split = false, .disable_dcc = DCC_ENABLE, .vsr_support = true, @@ -1976,7 +1984,7 @@ static void dcn31_calculate_wm_and_dlg_fp( pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); - if (dc->config.forced_clocks) { + if (dc->config.forced_clocks || dc->debug.max_disp_clk) { pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; } @@ -2294,14 +2302,27 @@ static bool dcn31_resource_construct( dcn30_clock_source_create(ctx, ctx->dc_bios, CLOCK_SOURCE_COMBO_PHY_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + /*move phypllx_pixclk_resync to dmub next*/ + if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs_b0[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs_b0[3], false); + } else { + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = dcn30_clock_source_create(ctx, ctx->dc_bios, CLOCK_SOURCE_COMBO_PHY_PLL2, &clk_src_regs[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = dcn30_clock_source_create(ctx, ctx->dc_bios, CLOCK_SOURCE_COMBO_PHY_PLL3, &clk_src_regs[3], false); + } + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = dcn30_clock_source_create(ctx, ctx->dc_bios, CLOCK_SOURCE_COMBO_PHY_PLL4, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h index 416fe7a721d8..a513363b3326 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h @@ -49,4 +49,35 @@ struct resource_pool *dcn31_create_resource_pool( const struct dc_init_data *init_data, struct dc *dc); +/*temp: B0 specific before switch to dcn313 headers*/ +#ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL +#define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e +#define regPHYPLLF_PIXCLK_RESYNC_CNTL_BASE_IDX 1 +#define regPHYPLLG_PIXCLK_RESYNC_CNTL 0x005f +#define regPHYPLLG_PIXCLK_RESYNC_CNTL_BASE_IDX 1 + +//PHYPLLF_PIXCLK_RESYNC_CNTL +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE__SHIFT 0x8 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE_MASK 0x00000100L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L + +//PHYPLLG_PIXCLK_RESYNC_CNTL +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE__SHIFT 0x8 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE_MASK 0x00000100L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L +#endif #endif /* _DCN31_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h index 511f9e1159c7..4229369c57f4 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h +++ b/drivers/gpu/drm/amd/display/dc/dm_cp_psp.h @@ -34,12 +34,12 @@ struct cp_psp_stream_config { uint8_t dig_fe; uint8_t link_enc_idx; uint8_t stream_enc_idx; - uint8_t phy_idx; uint8_t dio_output_idx; - uint8_t dio_output_type; + uint8_t phy_idx; uint8_t assr_enabled; uint8_t mst_enabled; uint8_t dp2_enabled; + uint8_t usb4_enabled; void *dm_stream_ctx; bool dpms_off; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c index 91810aaee5a3..789f7562cdc7 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c @@ -1274,7 +1274,7 @@ static void dcn20_adjust_adaptive_sync_v_startup( static bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) { return (pipe_ctx->stream_res.hpo_dp_stream_enc && - pipe_ctx->stream->link->hpo_dp_link_enc && + pipe_ctx->link_res.hpo_dp_link_enc && dc_is_dp_signal(pipe_ctx->stream->signal)); } diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h index d34b0b0eea65..444182a97e6e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -53,6 +53,8 @@ enum dc_status { DC_NOT_SUPPORTED = 24, DC_UNSUPPORTED_VALUE = 25, + DC_NO_LINK_ENC_RESOURCE = 26, + DC_ERROR_UNEXPECTED = -1 }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index f3c0e70073da..943240e2809e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -334,6 +334,20 @@ struct plane_resource { struct dcn_fe_bandwidth bw; }; +#if defined(CONFIG_DRM_AMD_DC_DCN) +#define LINK_RES_HPO_DP_REC_MAP__MASK 0xFFFF +#define LINK_RES_HPO_DP_REC_MAP__SHIFT 0 +#endif + +/* all mappable hardware resources used to enable a link */ +struct link_resource { +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct hpo_dp_link_encoder *hpo_dp_link_enc; +#else + void *dummy; +#endif +}; + union pipe_update_flags { struct { uint32_t enable : 1; @@ -361,6 +375,7 @@ struct pipe_ctx { struct plane_resource plane_res; struct stream_resource stream_res; + struct link_resource link_res; struct clock_source *clock_source; @@ -412,6 +427,8 @@ struct resource_context { struct link_enc_cfg_context link_enc_cfg_ctx; #if defined(CONFIG_DRM_AMD_DC_DCN) bool is_hpo_dp_stream_enc_acquired[MAX_HPO_DP2_ENCODERS]; + unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS]; + int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS]; #endif #if defined(CONFIG_DRM_AMD_DC_DCN) bool is_mpc_3dlut_acquired[MAX_PIPES]; diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 52bdfea7897b..cd52813a8432 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -56,16 +56,19 @@ enum { bool dp_verify_link_cap( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *known_limit_link_setting, int *fail_count); bool dp_verify_link_cap_with_retries( struct dc_link *link, + const struct link_resource *link_res, struct dc_link_settings *known_limit_link_setting, int attempts); bool dp_verify_mst_link_cap( - struct dc_link *link); + struct dc_link *link, + const struct link_resource *link_res); bool dp_validate_mode_timing( struct dc_link *link, @@ -168,7 +171,7 @@ uint8_t dc_dp_initialize_scrambling_data_symbols( struct dc_link *link, enum dc_dp_training_pattern pattern); -enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready); +enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready); void dp_set_fec_enable(struct dc_link *link, bool enable); struct link_encoder *dp_get_link_enc(struct dc_link *link); bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); @@ -211,8 +214,12 @@ bool dpcd_poll_for_allocation_change_trigger(struct dc_link *link); struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( const struct dc_stream_state *stream, const struct dc_link *link); -void enable_dp_hpo_output(struct dc_link *link, const struct dc_link_settings *link_settings); -void disable_dp_hpo_output(struct dc_link *link, enum signal_type signal); +void enable_dp_hpo_output(struct dc_link *link, + const struct link_resource *link_res, + const struct dc_link_settings *link_settings); +void disable_dp_hpo_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable); bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx); void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link); diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h index 974d703e3771..74dafd0f9d3d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h @@ -91,8 +91,9 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link); * DPIA equivalent of dc_link_dp_perfrorm_link_training. * Aborts link training upon detection of sink unplug. */ -enum link_training_result -dc_link_dpia_perform_link_training(struct dc_link *link, +enum link_training_result dc_link_dpia_perform_link_training( + struct dc_link *link, + const struct link_resource *link_res, const struct dc_link_settings *link_setting, bool skip_video_pattern); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index bb0e91756ddd..2ce15cd10d80 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -268,7 +268,8 @@ struct hpo_dp_link_encoder_funcs { void (*enable_link_phy)(struct hpo_dp_link_encoder *enc, const struct dc_link_settings *link_settings, - enum transmitter transmitter); + enum transmitter transmitter, + enum hpd_source_id hpd_source); void (*disable_link_phy)(struct hpo_dp_link_encoder *link_enc, enum signal_type signal); diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index ba664bc49595..69d63763a10e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -32,6 +32,7 @@ struct gpio *get_hpd_gpio(struct dc_bios *dcb, void dp_enable_link_phy( struct dc_link *link, + const struct link_resource *link_res, enum signal_type signal, enum clock_source_id clock_source, const struct dc_link_settings *link_settings); @@ -42,22 +43,27 @@ void edp_add_delay_for_T9(struct dc_link *link); bool edp_receiver_ready_T9(struct dc_link *link); bool edp_receiver_ready_T7(struct dc_link *link); -void dp_disable_link_phy(struct dc_link *link, enum signal_type signal); +void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal); -void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal); +void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal); bool dp_set_hw_training_pattern( struct dc_link *link, + const struct link_resource *link_res, enum dc_dp_training_pattern pattern, uint32_t offset); void dp_set_hw_lane_settings( struct dc_link *link, + const struct link_resource *link_res, const struct link_training_settings *link_settings, uint32_t offset); void dp_set_hw_test_pattern( struct dc_link *link, + const struct link_resource *link_res, enum dp_test_pattern test_pattern, uint8_t *custom_pattern, uint32_t custom_pattern_size); diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index c208925f8247..028180f58f71 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -206,8 +206,10 @@ int get_num_mpc_splits(struct pipe_ctx *pipe); int get_num_odm_splits(struct pipe_ctx *pipe); #if defined(CONFIG_DRM_AMD_DC_DCN) -struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder( - const struct resource_pool *pool); +struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt( + const struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct dc_link *link); #endif void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, @@ -216,5 +218,6 @@ void reset_syncd_pipes_from_disabled_pipes(struct dc *dc, void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc, struct dc_state *context, uint8_t disabled_master_pipe_idx); +uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter); #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index afe9bc839b45..873ecd04e01d 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -46,10 +46,10 @@ /* Firmware versioning. */ #ifdef DMUB_EXPOSE_VERSION -#define DMUB_FW_VERSION_GIT_HASH 0xc99a4517 +#define DMUB_FW_VERSION_GIT_HASH 0xbaf06b95 #define DMUB_FW_VERSION_MAJOR 0 #define DMUB_FW_VERSION_MINOR 0 -#define DMUB_FW_VERSION_REVISION 97 +#define DMUB_FW_VERSION_REVISION 98 #define DMUB_FW_VERSION_TEST 0 #define DMUB_FW_VERSION_VBIOS 0 #define DMUB_FW_VERSION_HOTFIX 0 diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index f673a1c1777a..9280f2abd973 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -852,7 +852,7 @@ bool dmub_srv_should_detect(struct dmub_srv *dmub) enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub) { - if (!dmub->hw_init || dmub->hw_funcs.clear_inbox0_ack_register) + if (!dmub->hw_init || !dmub->hw_funcs.clear_inbox0_ack_register) return DMUB_STATUS_INVALID; dmub->hw_funcs.clear_inbox0_ack_register(dmub); @@ -878,7 +878,7 @@ enum dmub_status dmub_srv_wait_for_inbox0_ack(struct dmub_srv *dmub, uint32_t ti enum dmub_status dmub_srv_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data) { - if (!dmub->hw_init || dmub->hw_funcs.send_inbox0_cmd) + if (!dmub->hw_init || !dmub->hw_funcs.send_inbox0_cmd) return DMUB_STATUS_INVALID; dmub->hw_funcs.send_inbox0_cmd(dmub, data); diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h index 6d648c889866..f7420c3f5672 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h @@ -104,6 +104,7 @@ struct mod_hdcp_displayport { uint8_t rev; uint8_t assr_enabled; uint8_t mst_enabled; + uint8_t usb4_enabled; }; struct mod_hdcp_hdmi { @@ -249,7 +250,6 @@ struct mod_hdcp_link { uint8_t ddc_line; uint8_t link_enc_idx; uint8_t phy_idx; - uint8_t dio_output_type; uint8_t dio_output_id; uint8_t hdcp_supported_informational; union { diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_offset.h index 79eae0256dbd..8072b0a6376d 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_offset.h @@ -20753,8 +20753,6 @@ // addressBlock: nbio_nbif0_gdc_GDCDEC // base address: 0xd0000000 -#define regGDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL 0x2ffc0eda -#define regGDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL_BASE_IDX 5 #define regGDC1_NGDC_SDP_PORT_CTRL 0x2ffc0ee2 #define regGDC1_NGDC_SDP_PORT_CTRL_BASE_IDX 5 #define regGDC1_SHUB_REGS_IF_CTL 0x2ffc0ee3 diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_sh_mask.h index e27fdc0c643c..54b0e4623971 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_2_0_sh_mask.h @@ -1,4 +1,3 @@ - /* * Copyright (C) 2020 Advanced Micro Devices, Inc. * @@ -108541,17 +108540,6 @@ // addressBlock: nbio_nbif0_gdc_GDCDEC -//GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN0_FAST_WRITE_RESPONSE_EN__SHIFT 0x0 -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN1_FAST_WRITE_RESPONSE_EN__SHIFT 0x1 -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN2_FAST_WRITE_RESPONSE_EN__SHIFT 0x2 -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN3_FAST_WRITE_RESPONSE_EN__SHIFT 0x3 -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__FWR_NORMAL_ARB_MODE__SHIFT 0x10 -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN0_FAST_WRITE_RESPONSE_EN_MASK 0x00000001L -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN1_FAST_WRITE_RESPONSE_EN_MASK 0x00000002L -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN2_FAST_WRITE_RESPONSE_EN_MASK 0x00000004L -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__LOGAN3_FAST_WRITE_RESPONSE_EN_MASK 0x00000008L -#define GDC1_LOGAN_FAST_WRITE_RESPONSE_CNTL__FWR_NORMAL_ARB_MODE_MASK 0x00010000L //GDC1_NGDC_SDP_PORT_CTRL #define GDC1_NGDC_SDP_PORT_CTRL__SDP_DISCON_HYSTERESIS__SHIFT 0x0 #define GDC1_NGDC_SDP_PORT_CTRL__NGDC_OBFF_HW_URGENT_EARLY_WAKEUP_EN__SHIFT 0xf diff --git a/drivers/gpu/drm/amd/include/discovery.h b/drivers/gpu/drm/amd/include/discovery.h index 7ec4331e67f2..a486769b66c6 100644 --- a/drivers/gpu/drm/amd/include/discovery.h +++ b/drivers/gpu/drm/amd/include/discovery.h @@ -143,6 +143,55 @@ struct gc_info_v1_0 { uint32_t gc_num_gl2a; }; +struct gc_info_v1_1 { + struct gpu_info_header header; + + uint32_t gc_num_se; + uint32_t gc_num_wgp0_per_sa; + uint32_t gc_num_wgp1_per_sa; + uint32_t gc_num_rb_per_se; + uint32_t gc_num_gl2c; + uint32_t gc_num_gprs; + uint32_t gc_num_max_gs_thds; + uint32_t gc_gs_table_depth; + uint32_t gc_gsprim_buff_depth; + uint32_t gc_parameter_cache_depth; + uint32_t gc_double_offchip_lds_buffer; + uint32_t gc_wave_size; + uint32_t gc_max_waves_per_simd; + uint32_t gc_max_scratch_slots_per_cu; + uint32_t gc_lds_size; + uint32_t gc_num_sc_per_se; + uint32_t gc_num_sa_per_se; + uint32_t gc_num_packer_per_sc; + uint32_t gc_num_gl2a; + uint32_t gc_num_tcp_per_sa; + uint32_t gc_num_sdp_interface; + uint32_t gc_num_tcps; +}; + +struct gc_info_v2_0 { + struct gpu_info_header header; + + uint32_t gc_num_se; + uint32_t gc_num_cu_per_sh; + uint32_t gc_num_sh_per_se; + uint32_t gc_num_rb_per_se; + uint32_t gc_num_tccs; + uint32_t gc_num_gprs; + uint32_t gc_num_max_gs_thds; + uint32_t gc_gs_table_depth; + uint32_t gc_gsprim_buff_depth; + uint32_t gc_parameter_cache_depth; + uint32_t gc_double_offchip_lds_buffer; + uint32_t gc_wave_size; + uint32_t gc_max_waves_per_simd; + uint32_t gc_max_scratch_slots_per_cu; + uint32_t gc_lds_size; + uint32_t gc_num_sc_per_se; + uint32_t gc_num_packer_per_sc; +}; + typedef struct harvest_info_header { uint32_t signature; /* Table Signature */ uint32_t version; /* Table Version */ diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 082539c70fd4..e2cae97f4ff1 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -2090,7 +2090,8 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } else if (DEVICE_ATTR_IS(unique_id)) { if (asic_type != CHIP_VEGA10 && asic_type != CHIP_VEGA20 && - asic_type != CHIP_ARCTURUS) + asic_type != CHIP_ARCTURUS && + asic_type != CHIP_ALDEBARAN) *states = ATTR_STATE_UNSUPPORTED; } else if (DEVICE_ATTR_IS(pp_features)) { if (adev->flags & AMD_IS_APU || asic_type < CHIP_VEGA10) @@ -2133,6 +2134,12 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ } } + /* setting should not be allowed from VF */ + if (amdgpu_sriov_vf(adev)) { + dev_attr->attr.mode &= ~S_IWUGO; + dev_attr->store = NULL; + } + #undef DEVICE_ATTR_IS return 0; diff --git a/drivers/gpu/drm/amd/pm/inc/aldebaran_ppsmc.h b/drivers/gpu/drm/amd/pm/inc/aldebaran_ppsmc.h index 35fa0d8e92dd..ab66a4b9e438 100644 --- a/drivers/gpu/drm/amd/pm/inc/aldebaran_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/inc/aldebaran_ppsmc.h @@ -102,7 +102,9 @@ #define PPSMC_MSG_GfxDriverResetRecovery 0x42 #define PPSMC_MSG_BoardPowerCalibration 0x43 -#define PPSMC_Message_Count 0x44 +#define PPSMC_MSG_HeavySBR 0x45 +#define PPSMC_Message_Count 0x46 + //PPSMC Reset Types #define PPSMC_RESET_TYPE_WARM_RESET 0x00 diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h index 2b9b9a7ba97a..ba7565bc8104 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h @@ -1257,9 +1257,9 @@ struct pptable_funcs { int (*set_fine_grain_gfx_freq_parameters)(struct smu_context *smu); /** - * @set_light_sbr: Set light sbr mode for the SMU. + * @smu_handle_passthrough_sbr: Send message to SMU about special handling for SBR. */ - int (*set_light_sbr)(struct smu_context *smu, bool enable); + int (*smu_handle_passthrough_sbr)(struct smu_context *smu, bool enable); /** * @wait_for_event: Wait for events from SMU. @@ -1415,7 +1415,7 @@ int smu_allow_xgmi_power_down(struct smu_context *smu, bool en); int smu_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value); -int smu_set_light_sbr(struct smu_context *smu, bool enable); +int smu_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_wait_for_event(struct amdgpu_device *adev, enum smu_event_type event, uint64_t event_arg); diff --git a/drivers/gpu/drm/amd/pm/inc/smu_types.h b/drivers/gpu/drm/amd/pm/inc/smu_types.h index 18b862a90fbe..ff8a0bcbd290 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_types.h @@ -229,7 +229,8 @@ __SMU_DUMMY_MAP(BoardPowerCalibration), \ __SMU_DUMMY_MAP(RequestGfxclk), \ __SMU_DUMMY_MAP(ForceGfxVid), \ - __SMU_DUMMY_MAP(UnforceGfxVid), + __SMU_DUMMY_MAP(UnforceGfxVid), \ + __SMU_DUMMY_MAP(HeavySBR), #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type diff --git a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h index 2d422e6a9feb..acb3be292096 100644 --- a/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/inc/smu_v11_0.h @@ -312,7 +312,7 @@ int smu_v11_0_deep_sleep_control(struct smu_context *smu, void smu_v11_0_interrupt_work(struct smu_context *smu); -int smu_v11_0_set_light_sbr(struct smu_context *smu, bool enable); +int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable); int smu_v11_0_restore_user_od_settings(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 2d718c30c8eb..d93d28c1af95 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -1405,8 +1405,14 @@ static int smu_disable_dpms(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; + /* + * TODO: (adev->in_suspend && !adev->in_s0ix) is added to pair + * the workaround which always reset the asic in suspend. + * It's likely that workaround will be dropped in the future. + * Then the change here should be dropped together. + */ bool use_baco = !smu->is_apu && - ((amdgpu_in_reset(adev) && + (((amdgpu_in_reset(adev) || (adev->in_suspend && !adev->in_s0ix)) && (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || ((adev->in_runpm || adev->in_s4) && amdgpu_asic_supports_baco(adev))); @@ -1569,9 +1575,7 @@ static int smu_suspend(void *handle) smu->watermarks_bitmap &= ~(WATERMARKS_LOADED); - /* skip CGPG when in S0ix */ - if (smu->is_apu && !adev->in_s0ix) - smu_set_gfx_cgpg(&adev->smu, false); + smu_set_gfx_cgpg(&adev->smu, false); return 0; } @@ -1602,8 +1606,7 @@ static int smu_resume(void *handle) return ret; } - if (smu->is_apu) - smu_set_gfx_cgpg(&adev->smu, true); + smu_set_gfx_cgpg(&adev->smu, true); smu->disable_uclk_switch = 0; @@ -3061,13 +3064,13 @@ static int smu_gfx_state_change_set(void *handle, return ret; } -int smu_set_light_sbr(struct smu_context *smu, bool enable) +int smu_handle_passthrough_sbr(struct smu_context *smu, bool enable) { int ret = 0; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_light_sbr) - ret = smu->ppt_funcs->set_light_sbr(smu, enable); + if (smu->ppt_funcs->smu_handle_passthrough_sbr) + ret = smu->ppt_funcs->smu_handle_passthrough_sbr(smu, enable); mutex_unlock(&smu->mutex); return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 58bc387fb279..505d2fb94fd9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2472,7 +2472,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .deep_sleep_control = smu_v11_0_deep_sleep_control, .get_fan_parameters = arcturus_get_fan_parameters, .interrupt_work = smu_v11_0_interrupt_work, - .set_light_sbr = smu_v11_0_set_light_sbr, + .smu_handle_passthrough_sbr = smu_v11_0_handle_passthrough_sbr, .set_mp1_state = smu_cmn_set_mp1_state, }; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 28b7c0562b99..4e9e2cf39859 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -1724,7 +1724,7 @@ int smu_v11_0_mode1_reset(struct smu_context *smu) return ret; } -int smu_v11_0_set_light_sbr(struct smu_context *smu, bool enable) +int smu_v11_0_handle_passthrough_sbr(struct smu_context *smu, bool enable) { int ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 43028f2cd28b..9c91e79c955f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -120,7 +120,8 @@ int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate) int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable) { - if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) + /* Until now the SMU12 only implemented for Renoir series so here neen't do APU check. */ + if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) || smu->adev->in_s0ix) return 0; return smu_cmn_send_smc_msg_with_param(smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 0907da022197..4885c4ae78b7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -141,6 +141,7 @@ static const struct cmn2asic_msg_mapping aldebaran_message_map[SMU_MSG_MAX_COUNT MSG_MAP(SetUclkDpmMode, PPSMC_MSG_SetUclkDpmMode, 0), MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), MSG_MAP(BoardPowerCalibration, PPSMC_MSG_BoardPowerCalibration, 0), + MSG_MAP(HeavySBR, PPSMC_MSG_HeavySBR, 0), }; static const struct cmn2asic_mapping aldebaran_clk_map[SMU_CLK_COUNT] = { @@ -1605,7 +1606,8 @@ out_unlock: mutex_unlock(&smu->metrics_lock); adev->unique_id = ((uint64_t)upper32 << 32) | lower32; - sprintf(adev->serial, "%016llx", adev->unique_id); + if (adev->serial[0] == '\0') + sprintf(adev->serial, "%016llx", adev->unique_id); } static bool aldebaran_is_baco_supported(struct smu_context *smu) @@ -1623,10 +1625,18 @@ static int aldebaran_set_df_cstate(struct smu_context *smu, static int aldebaran_allow_xgmi_power_down(struct smu_context *smu, bool en) { - return smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_GmiPwrDnControl, - en ? 1 : 0, - NULL); + struct amdgpu_device *adev = smu->adev; + + /* The message only works on master die and NACK will be sent + back for other dies, only send it on master die */ + if (!adev->smuio.funcs->get_socket_id(adev) && + !adev->smuio.funcs->get_die_id(adev)) + return smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GmiPwrDnControl, + en ? 0 : 1, + NULL); + else + return 0; } static const struct throttling_logging_label { @@ -1912,6 +1922,14 @@ out: return ret; } +static int aldebaran_smu_handle_passthrough_sbr(struct smu_context *smu, bool enable) +{ + int ret = 0; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_HeavySBR, enable ? 1 : 0, NULL); + + return ret; +} + static bool aldebaran_is_mode1_reset_supported(struct smu_context *smu) { #if 0 @@ -2021,6 +2039,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .get_gpu_metrics = aldebaran_get_gpu_metrics, .mode1_reset_is_support = aldebaran_is_mode1_reset_supported, .mode2_reset_is_support = aldebaran_is_mode2_reset_supported, + .smu_handle_passthrough_sbr = aldebaran_smu_handle_passthrough_sbr, .mode1_reset = aldebaran_mode1_reset, .set_mp1_state = aldebaran_set_mp1_state, .mode2_reset = aldebaran_mode2_reset, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index 677a246212f9..b54790d3483e 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -212,7 +212,7 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) if (smu->is_apu) adev->pm.fw_version = smu_version; - switch (smu->adev->ip_versions[MP1_HWIP][0]) { + switch (adev->ip_versions[MP1_HWIP][0]) { case IP_VERSION(13, 0, 2): smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_ALDE; break; @@ -221,12 +221,17 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_YELLOW_CARP; break; default: - dev_err(smu->adev->dev, "smu unsupported IP version: 0x%x.\n", - smu->adev->ip_versions[MP1_HWIP][0]); + dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", + adev->ip_versions[MP1_HWIP][0]); smu->smc_driver_if_version = SMU13_DRIVER_IF_VERSION_INV; break; } + /* only for dGPU w/ SMU13*/ + if (adev->pm.fw) + dev_dbg(adev->dev, "smu fw reported version = 0x%08x (%d.%d.%d)\n", + smu_version, smu_major, smu_minor, smu_debug); + /* * 1. if_version mismatch is not critical as our fw is designed * to be backward compatible. @@ -236,11 +241,11 @@ int smu_v13_0_check_fw_version(struct smu_context *smu) * of halt driver loading. */ if (if_version != smu->smc_driver_if_version) { - dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + dev_info(adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " "smu fw version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_version, smu_major, smu_minor, smu_debug); - dev_warn(smu->adev->dev, "SMU driver if version not matched\n"); + dev_warn(adev->dev, "SMU driver if version not matched\n"); } return ret; diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 44c2aafcb7c2..956c8982192b 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1118,7 +1118,10 @@ static void ast_crtc_reset(struct drm_crtc *crtc) if (crtc->state) crtc->funcs->atomic_destroy_state(crtc, crtc->state); - __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); + if (ast_state) + __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); + else + __drm_atomic_helper_crtc_reset(crtc, NULL); } static struct drm_crtc_state * diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aef2fbd676e5..9603193d2fa1 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -828,8 +828,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, } if (!crtc_state->enable && !can_update_disabled) { - drm_dbg_kms(plane_state->crtc->dev, - "Cannot update plane of a disabled CRTC.\n"); + drm_dbg_kms(plane_state->plane->dev, + "Cannot update plane of a disabled CRTC.\n"); return -EINVAL; } @@ -839,8 +839,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); if (hscale < 0 || vscale < 0) { - drm_dbg_kms(plane_state->crtc->dev, - "Invalid scaling of plane\n"); + drm_dbg_kms(plane_state->plane->dev, + "Invalid scaling of plane\n"); drm_rect_debug_print("src: ", &plane_state->src, true); drm_rect_debug_print("dst: ", &plane_state->dst, false); return -ERANGE; @@ -864,8 +864,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, return 0; if (!can_position && !drm_rect_equals(dst, &clip)) { - drm_dbg_kms(plane_state->crtc->dev, - "Plane must cover entire CRTC\n"); + drm_dbg_kms(plane_state->plane->dev, + "Plane must cover entire CRTC\n"); drm_rect_debug_print("dst: ", dst, false); drm_rect_debug_print("clip: ", &clip, false); return -EINVAL; @@ -1016,7 +1016,7 @@ crtc_needs_disable(struct drm_crtc_state *old_state, * it's in self refresh mode and needs to be fully disabled. */ return old_state->active || - (old_state->self_refresh_active && !new_state->enable) || + (old_state->self_refresh_active && !new_state->active) || new_state->self_refresh_active; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9727a59d35fd..ed43b987d306 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1743,7 +1743,13 @@ void drm_fb_helper_fill_info(struct fb_info *info, sizes->fb_width, sizes->fb_height); info->par = fb_helper; - snprintf(info->fix.id, sizeof(info->fix.id), "%s", + /* + * The DRM drivers fbdev emulation device name can be confusing if the + * driver name also has a "drm" suffix on it. Leading to names such as + * "simpledrmdrmfb" in /proc/fb. Unfortunately, it's an uAPI and can't + * be changed due user-space tools (e.g: pm-utils) matching against it. + */ + snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb", fb_helper->dev->driver->name); } diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index ded8968b3e8a..0327d595e028 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -209,11 +209,11 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); if (ret) return ret; - src = data[0].vaddr; /* TODO: Use mapping abstraction properly */ ret = drm_gem_fb_vmap(fb, map, data); if (ret) goto out_drm_gem_fb_end_cpu_access; + src = data[0].vaddr; /* TODO: Use mapping abstraction properly */ switch (fb->format->format) { case DRM_FORMAT_RGB565: diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 39197b4beea7..1eae5a9645f4 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -65,6 +65,7 @@ config DRM_MSM_HDMI_HDCP config DRM_MSM_DP bool "Enable DisplayPort support in MSM DRM driver" depends on DRM_MSM + select RATIONAL default y help Compile in support for DP driver in MSM DRM driver. DP external diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 093454457545..03ab55c37beb 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -19,7 +19,7 @@ msm-y := \ hdmi/hdmi.o \ hdmi/hdmi_audio.o \ hdmi/hdmi_bridge.o \ - hdmi/hdmi_connector.o \ + hdmi/hdmi_hpd.o \ hdmi/hdmi_i2c.o \ hdmi/hdmi_phy.o \ hdmi/hdmi_phy_8960.o \ @@ -27,12 +27,6 @@ msm-y := \ hdmi/hdmi_phy_8x60.o \ hdmi/hdmi_phy_8x74.o \ hdmi/hdmi_pll_8960.o \ - edp/edp.o \ - edp/edp_aux.o \ - edp/edp_bridge.o \ - edp/edp_connector.o \ - edp/edp_ctrl.o \ - edp/edp_phy.o \ disp/mdp_format.o \ disp/mdp_kms.o \ disp/mdp4/mdp4_crtc.o \ diff --git a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c index bdc989183c64..22e8295a5e2b 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a2xx_gpu.c @@ -12,7 +12,6 @@ static bool a2xx_idle(struct msm_gpu *gpu); static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { - struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = submit->ring; unsigned int i; @@ -23,7 +22,7 @@ static void a2xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: /* ignore if there has not been a ctx switch: */ - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 8fb847c174ff..2e481e2692ba 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -30,7 +30,6 @@ static bool a3xx_idle(struct msm_gpu *gpu); static void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { - struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = submit->ring; unsigned int i; @@ -41,7 +40,7 @@ static void a3xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: /* ignore if there has not been a ctx switch: */ - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index a96ee79cc5e0..c5524d6e8705 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -24,7 +24,6 @@ static bool a4xx_idle(struct msm_gpu *gpu); static void a4xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { - struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = submit->ring; unsigned int i; @@ -35,7 +34,7 @@ static void a4xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: /* ignore if there has not been a ctx switch: */ - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: diff --git a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c index dd593ec2bc56..6bd397a85834 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_debugfs.c @@ -107,7 +107,7 @@ reset_set(void *data, u64 val) * try to reset an active GPU. */ - mutex_lock(&dev->struct_mutex); + mutex_lock(&gpu->lock); release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]); adreno_gpu->fw[ADRENO_FW_PM4] = NULL; @@ -133,7 +133,7 @@ reset_set(void *data, u64 val) gpu->funcs->recover(gpu); pm_runtime_put_sync(&gpu->pdev->dev); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); return 0; } diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 5e2750eb3810..3d28fcf841a6 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -65,7 +65,6 @@ void a5xx_flush(struct msm_gpu *gpu, struct msm_ringbuffer *ring, static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit) { - struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = submit->ring; struct msm_gem_object *obj; uint32_t *ptr, dwords; @@ -76,7 +75,7 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit case MSM_SUBMIT_CMD_IB_TARGET_BUF: break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: @@ -126,12 +125,11 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); - struct msm_drm_private *priv = gpu->dev->dev_private; struct msm_ringbuffer *ring = submit->ring; unsigned int i, ibs = 0; if (IS_ENABLED(CONFIG_DRM_MSM_GPU_SUDO) && submit->in_rb) { - priv->lastctx = NULL; + gpu->cur_ctx_seqno = 0; a5xx_submit_in_rb(gpu, submit); return; } @@ -166,7 +164,7 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) case MSM_SUBMIT_CMD_IB_TARGET_BUF: break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: @@ -441,7 +439,7 @@ void a5xx_set_hwcg(struct msm_gpu *gpu, bool state) const struct adreno_five_hwcg_regs *regs; unsigned int i, sz; - if (adreno_is_a508(adreno_gpu)) { + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) { regs = a50x_hwcg; sz = ARRAY_SIZE(a50x_hwcg); } else if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu)) { @@ -485,7 +483,7 @@ static int a5xx_me_init(struct msm_gpu *gpu) OUT_RING(ring, 0x00000000); /* Specify workarounds for various microcode issues */ - if (adreno_is_a530(adreno_gpu)) { + if (adreno_is_a506(adreno_gpu) || adreno_is_a530(adreno_gpu)) { /* Workaround for token end syncs * Force a WFI after every direct-render 3D mode draw and every * 2D mode 3 draw @@ -620,8 +618,16 @@ static int a5xx_ucode_init(struct msm_gpu *gpu) static int a5xx_zap_shader_resume(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int ret; + /* + * Adreno 506 have CPZ Retention feature and doesn't require + * to resume zap shader + */ + if (adreno_is_a506(adreno_gpu)) + return 0; + ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); if (ret) DRM_ERROR("%s: zap-shader resume failed: %d\n", @@ -733,9 +739,10 @@ static int a5xx_hw_init(struct msm_gpu *gpu) 0x00100000 + adreno_gpu->gmem - 1); gpu_write(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_HI, 0x00000000); - if (adreno_is_a508(adreno_gpu) || adreno_is_a510(adreno_gpu)) { + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || + adreno_is_a510(adreno_gpu)) { gpu_write(gpu, REG_A5XX_CP_MEQ_THRESHOLDS, 0x20); - if (adreno_is_a508(adreno_gpu)) + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x400); else gpu_write(gpu, REG_A5XX_CP_MERCIU_SIZE, 0x20); @@ -751,7 +758,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A5XX_CP_ROQ_THRESHOLDS_1, 0x40201B16); } - if (adreno_is_a508(adreno_gpu)) + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu)) gpu_write(gpu, REG_A5XX_PC_DBG_ECO_CNTL, (0x100 << 11 | 0x100 << 22)); else if (adreno_is_a509(adreno_gpu) || adreno_is_a510(adreno_gpu) || @@ -769,8 +776,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) * Disable the RB sampler datapath DP2 clock gating optimization * for 1-SP GPUs, as it is enabled by default. */ - if (adreno_is_a508(adreno_gpu) || adreno_is_a509(adreno_gpu) || - adreno_is_a512(adreno_gpu)) + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || + adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu)) gpu_rmw(gpu, REG_A5XX_RB_DBG_ECO_CNTL, 0, (1 << 9)); /* Disable UCHE global filter as SP can invalidate/flush independently */ @@ -851,10 +858,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) /* UCHE */ gpu_write(gpu, REG_A5XX_CP_PROTECT(16), ADRENO_PROTECT_RW(0xE80, 16)); - if (adreno_is_a508(adreno_gpu) || adreno_is_a509(adreno_gpu) || - adreno_is_a510(adreno_gpu) || adreno_is_a512(adreno_gpu) || - adreno_is_a530(adreno_gpu)) - gpu_write(gpu, REG_A5XX_CP_PROTECT(17), + /* SMMU */ + gpu_write(gpu, REG_A5XX_CP_PROTECT(17), ADRENO_PROTECT_RW(0x10000, 0x8000)); gpu_write(gpu, REG_A5XX_RBBM_SECVID_TSB_CNTL, 0); @@ -895,8 +900,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) if (ret) return ret; - if (!(adreno_is_a508(adreno_gpu) || adreno_is_a509(adreno_gpu) || - adreno_is_a510(adreno_gpu) || adreno_is_a512(adreno_gpu))) + if (adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu)) a5xx_gpmu_ucode_init(gpu); ret = a5xx_ucode_init(gpu); @@ -927,6 +931,8 @@ static int a5xx_hw_init(struct msm_gpu *gpu) if (IS_ERR(a5xx_gpu->shadow)) return PTR_ERR(a5xx_gpu->shadow); + + msm_gem_object_set_name(a5xx_gpu->shadow_bo, "shadow"); } gpu_write64(gpu, REG_A5XX_CP_RB_RPTR_ADDR, @@ -1254,6 +1260,7 @@ static void a5xx_fault_detect_irq(struct msm_gpu *gpu) static irqreturn_t a5xx_irq(struct msm_gpu *gpu) { + struct msm_drm_private *priv = gpu->dev->dev_private; u32 status = gpu_read(gpu, REG_A5XX_RBBM_INT_0_STATUS); /* @@ -1263,6 +1270,11 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu) gpu_write(gpu, REG_A5XX_RBBM_INT_CLEAR_CMD, status & ~A5XX_RBBM_INT_0_MASK_RBBM_AHB_ERROR); + if (priv->disable_err_irq) { + status &= A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS | + A5XX_RBBM_INT_0_MASK_CP_SW; + } + /* Pass status to a5xx_rbbm_err_irq because we've already cleared it */ if (status & RBBM_ERROR_MASK) a5xx_rbbm_err_irq(gpu, status); @@ -1338,7 +1350,7 @@ static int a5xx_pm_resume(struct msm_gpu *gpu) if (ret) return ret; - /* Adreno 508, 509, 510, 512 needs manual RBBM sus/res control */ + /* Adreno 506, 508, 509, 510, 512 needs manual RBBM sus/res control */ if (!(adreno_is_a530(adreno_gpu) || adreno_is_a540(adreno_gpu))) { /* Halt the sp_input_clk at HM level */ gpu_write(gpu, REG_A5XX_RBBM_CLOCK_CNTL, 0x00000055); @@ -1381,8 +1393,9 @@ static int a5xx_pm_suspend(struct msm_gpu *gpu) u32 mask = 0xf; int i, ret; - /* A508, A510 have 3 XIN ports in VBIF */ - if (adreno_is_a508(adreno_gpu) || adreno_is_a510(adreno_gpu)) + /* A506, A508, A510 have 3 XIN ports in VBIF */ + if (adreno_is_a506(adreno_gpu) || adreno_is_a508(adreno_gpu) || + adreno_is_a510(adreno_gpu)) mask = 0x7; /* Clear the VBIF pipe before shutting down */ diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 71e52b2b2025..3e325e2a2b1b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1146,7 +1146,7 @@ static void a6xx_gmu_memory_free(struct a6xx_gmu *gmu) } static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, - size_t size, u64 iova) + size_t size, u64 iova, const char *name) { struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct drm_device *dev = a6xx_gpu->base.base.dev; @@ -1181,6 +1181,8 @@ static int a6xx_gmu_memory_alloc(struct a6xx_gmu *gmu, struct a6xx_gmu_bo *bo, bo->virt = msm_gem_get_vaddr(bo->obj); bo->size = size; + msm_gem_object_set_name(bo->obj, name); + return 0; } @@ -1515,7 +1517,8 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) */ gmu->dummy.size = SZ_4K; if (adreno_is_a660_family(adreno_gpu)) { - ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_4K * 7, 0x60400000); + ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_4K * 7, + 0x60400000, "debug"); if (ret) goto err_memory; @@ -1523,42 +1526,46 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node) } /* Allocate memory for the GMU dummy page */ - ret = a6xx_gmu_memory_alloc(gmu, &gmu->dummy, gmu->dummy.size, 0x60000000); + ret = a6xx_gmu_memory_alloc(gmu, &gmu->dummy, gmu->dummy.size, + 0x60000000, "dummy"); if (ret) goto err_memory; + /* Note that a650 family also includes a660 family: */ if (adreno_is_a650_family(adreno_gpu)) { ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache, - SZ_16M - SZ_16K, 0x04000); + SZ_16M - SZ_16K, 0x04000, "icache"); if (ret) goto err_memory; } else if (adreno_is_a640_family(adreno_gpu)) { ret = a6xx_gmu_memory_alloc(gmu, &gmu->icache, - SZ_256K - SZ_16K, 0x04000); + SZ_256K - SZ_16K, 0x04000, "icache"); if (ret) goto err_memory; ret = a6xx_gmu_memory_alloc(gmu, &gmu->dcache, - SZ_256K - SZ_16K, 0x44000); + SZ_256K - SZ_16K, 0x44000, "dcache"); if (ret) goto err_memory; } else { + BUG_ON(adreno_is_a660_family(adreno_gpu)); + /* HFI v1, has sptprac */ gmu->legacy = true; /* Allocate memory for the GMU debug region */ - ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_16K, 0); + ret = a6xx_gmu_memory_alloc(gmu, &gmu->debug, SZ_16K, 0, "debug"); if (ret) goto err_memory; } /* Allocate memory for for the HFI queues */ - ret = a6xx_gmu_memory_alloc(gmu, &gmu->hfi, SZ_16K, 0); + ret = a6xx_gmu_memory_alloc(gmu, &gmu->hfi, SZ_16K, 0, "hfi"); if (ret) goto err_memory; /* Allocate memory for the GMU log region */ - ret = a6xx_gmu_memory_alloc(gmu, &gmu->log, SZ_4K, 0); + ret = a6xx_gmu_memory_alloc(gmu, &gmu->log, SZ_4K, 0, "log"); if (ret) goto err_memory; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 78aad5216a61..51b83776951b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -106,7 +106,7 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, u32 asid; u64 memptr = rbmemptr(ring, ttbr0); - if (ctx->seqno == a6xx_gpu->cur_ctx_seqno) + if (ctx->seqno == a6xx_gpu->base.base.cur_ctx_seqno) return; if (msm_iommu_pagetable_params(ctx->aspace->mmu, &ttbr, &asid)) @@ -138,14 +138,11 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu, OUT_PKT7(ring, CP_EVENT_WRITE, 1); OUT_RING(ring, 0x31); - - a6xx_gpu->cur_ctx_seqno = ctx->seqno; } static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) { unsigned int index = submit->seqno % MSM_GPU_SUBMIT_STATS_COUNT; - struct msm_drm_private *priv = gpu->dev->dev_private; struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = submit->ring; @@ -177,7 +174,7 @@ static void a6xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) case MSM_SUBMIT_CMD_IB_TARGET_BUF: break; case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: - if (priv->lastctx == submit->queue->ctx) + if (gpu->cur_ctx_seqno == submit->queue->ctx->seqno) break; fallthrough; case MSM_SUBMIT_CMD_BUF: @@ -1071,6 +1068,8 @@ static int hw_init(struct msm_gpu *gpu) if (IS_ERR(a6xx_gpu->shadow)) return PTR_ERR(a6xx_gpu->shadow); + + msm_gem_object_set_name(a6xx_gpu->shadow_bo, "shadow"); } gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR_LO, @@ -1081,7 +1080,7 @@ static int hw_init(struct msm_gpu *gpu) /* Always come up on rb 0 */ a6xx_gpu->cur_ring = gpu->rb[0]; - a6xx_gpu->cur_ctx_seqno = 0; + gpu->cur_ctx_seqno = 0; /* Enable the SQE_to start the CP engine */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 1); @@ -1376,10 +1375,14 @@ static void a6xx_fault_detect_irq(struct msm_gpu *gpu) static irqreturn_t a6xx_irq(struct msm_gpu *gpu) { + struct msm_drm_private *priv = gpu->dev->dev_private; u32 status = gpu_read(gpu, REG_A6XX_RBBM_INT_0_STATUS); gpu_write(gpu, REG_A6XX_RBBM_INT_CLEAR_CMD, status); + if (priv->disable_err_irq) + status &= A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS; + if (status & A6XX_RBBM_INT_0_MASK_RBBM_HANG_DETECT) a6xx_fault_detect_irq(gpu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 8e5527c881b1..86e0a7c3fe6d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -20,16 +20,6 @@ struct a6xx_gpu { struct msm_ringbuffer *cur_ring; - /** - * cur_ctx_seqno: - * - * The ctx->seqno value of the context with current pgtables - * installed. Tracked by seqno rather than pointer value to - * avoid dangling pointers, and cases where a ctx can be freed - * and a new one created with the same address. - */ - int cur_ctx_seqno; - struct a6xx_gmu gmu; struct drm_gem_object *shadow_bo; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c index 6e90209cd543..55f443328d8e 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c @@ -42,7 +42,15 @@ struct a6xx_gpu_state { struct a6xx_gpu_state_obj *cx_debugbus; int nr_cx_debugbus; + struct msm_gpu_state_bo *gmu_log; + struct msm_gpu_state_bo *gmu_hfi; + struct msm_gpu_state_bo *gmu_debug; + + s32 hfi_queue_history[2][HFI_HISTORY_SZ]; + struct list_head objs; + + bool gpu_initialized; }; static inline int CRASHDUMP_WRITE(u64 *in, u32 reg, u32 val) @@ -800,6 +808,45 @@ static void a6xx_get_gmu_registers(struct msm_gpu *gpu, &a6xx_state->gmu_registers[2], false); } +static struct msm_gpu_state_bo *a6xx_snapshot_gmu_bo( + struct a6xx_gpu_state *a6xx_state, struct a6xx_gmu_bo *bo) +{ + struct msm_gpu_state_bo *snapshot; + + snapshot = state_kcalloc(a6xx_state, 1, sizeof(*snapshot)); + if (!snapshot) + return NULL; + + snapshot->iova = bo->iova; + snapshot->size = bo->size; + snapshot->data = kvzalloc(snapshot->size, GFP_KERNEL); + if (!snapshot->data) + return NULL; + + memcpy(snapshot->data, bo->virt, bo->size); + + return snapshot; +} + +static void a6xx_snapshot_gmu_hfi_history(struct msm_gpu *gpu, + struct a6xx_gpu_state *a6xx_state) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct a6xx_gmu *gmu = &a6xx_gpu->gmu; + unsigned i, j; + + BUILD_BUG_ON(ARRAY_SIZE(gmu->queues) != ARRAY_SIZE(a6xx_state->hfi_queue_history)); + + for (i = 0; i < ARRAY_SIZE(gmu->queues); i++) { + struct a6xx_hfi_queue *queue = &gmu->queues[i]; + for (j = 0; j < HFI_HISTORY_SZ; j++) { + unsigned idx = (j + queue->history_idx) % HFI_HISTORY_SZ; + a6xx_state->hfi_queue_history[i][j] = queue->history[idx]; + } + } +} + #define A6XX_GBIF_REGLIST_SIZE 1 static void a6xx_get_registers(struct msm_gpu *gpu, struct a6xx_gpu_state *a6xx_state, @@ -937,6 +984,12 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) a6xx_get_gmu_registers(gpu, a6xx_state); + a6xx_state->gmu_log = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.log); + a6xx_state->gmu_hfi = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.hfi); + a6xx_state->gmu_debug = a6xx_snapshot_gmu_bo(a6xx_state, &a6xx_gpu->gmu.debug); + + a6xx_snapshot_gmu_hfi_history(gpu, a6xx_state); + /* If GX isn't on the rest of the data isn't going to be accessible */ if (!a6xx_gmu_gx_is_on(&a6xx_gpu->gmu)) return &a6xx_state->base; @@ -950,7 +1003,8 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) * write out GPU state, so we need to skip this when the SMMU is * stalled in response to an iova fault */ - if (!stalled && !a6xx_crashdumper_init(gpu, &_dumper)) { + if (!stalled && !gpu->needs_hw_init && + !a6xx_crashdumper_init(gpu, &_dumper)) { dumper = &_dumper; } @@ -967,6 +1021,8 @@ struct msm_gpu_state *a6xx_gpu_state_get(struct msm_gpu *gpu) if (snapshot_debugbus) a6xx_get_debugbus(gpu, a6xx_state); + a6xx_state->gpu_initialized = !gpu->needs_hw_init; + return &a6xx_state->base; } @@ -978,6 +1034,12 @@ static void a6xx_gpu_state_destroy(struct kref *kref) struct a6xx_gpu_state *a6xx_state = container_of(state, struct a6xx_gpu_state, base); + if (a6xx_state->gmu_log) + kvfree(a6xx_state->gmu_log->data); + + if (a6xx_state->gmu_hfi) + kvfree(a6xx_state->gmu_hfi->data); + list_for_each_entry_safe(obj, tmp, &a6xx_state->objs, node) kfree(obj); @@ -1189,8 +1251,48 @@ void a6xx_show(struct msm_gpu *gpu, struct msm_gpu_state *state, if (IS_ERR_OR_NULL(state)) return; + drm_printf(p, "gpu-initialized: %d\n", a6xx_state->gpu_initialized); + adreno_show(gpu, state, p); + drm_puts(p, "gmu-log:\n"); + if (a6xx_state->gmu_log) { + struct msm_gpu_state_bo *gmu_log = a6xx_state->gmu_log; + + drm_printf(p, " iova: 0x%016llx\n", gmu_log->iova); + drm_printf(p, " size: %zu\n", gmu_log->size); + adreno_show_object(p, &gmu_log->data, gmu_log->size, + &gmu_log->encoded); + } + + drm_puts(p, "gmu-hfi:\n"); + if (a6xx_state->gmu_hfi) { + struct msm_gpu_state_bo *gmu_hfi = a6xx_state->gmu_hfi; + unsigned i, j; + + drm_printf(p, " iova: 0x%016llx\n", gmu_hfi->iova); + drm_printf(p, " size: %zu\n", gmu_hfi->size); + for (i = 0; i < ARRAY_SIZE(a6xx_state->hfi_queue_history); i++) { + drm_printf(p, " queue-history[%u]:", i); + for (j = 0; j < HFI_HISTORY_SZ; j++) { + drm_printf(p, " %d", a6xx_state->hfi_queue_history[i][j]); + } + drm_printf(p, "\n"); + } + adreno_show_object(p, &gmu_hfi->data, gmu_hfi->size, + &gmu_hfi->encoded); + } + + drm_puts(p, "gmu-debug:\n"); + if (a6xx_state->gmu_debug) { + struct msm_gpu_state_bo *gmu_debug = a6xx_state->gmu_debug; + + drm_printf(p, " iova: 0x%016llx\n", gmu_debug->iova); + drm_printf(p, " size: %zu\n", gmu_debug->size); + adreno_show_object(p, &gmu_debug->data, gmu_debug->size, + &gmu_debug->encoded); + } + drm_puts(p, "registers:\n"); for (i = 0; i < a6xx_state->nr_registers; i++) { struct a6xx_gpu_state_obj *obj = &a6xx_state->registers[i]; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c index d4c65bf0a1b7..d73fce5fdf1f 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c @@ -36,6 +36,8 @@ static int a6xx_hfi_queue_read(struct a6xx_gmu *gmu, hdr = queue->data[index]; + queue->history[(queue->history_idx++) % HFI_HISTORY_SZ] = index; + /* * If we are to assume that the GMU firmware is in fact a rational actor * and is programmed to not send us a larger response than we expect @@ -75,6 +77,8 @@ static int a6xx_hfi_queue_write(struct a6xx_gmu *gmu, return -ENOSPC; } + queue->history[(queue->history_idx++) % HFI_HISTORY_SZ] = index; + for (i = 0; i < dwords; i++) { queue->data[index] = data[i]; index = (index + 1) % header->size; @@ -600,6 +604,9 @@ void a6xx_hfi_stop(struct a6xx_gmu *gmu) queue->header->read_index = 0; queue->header->write_index = 0; + + memset(&queue->history, 0xff, sizeof(queue->history)); + queue->history_idx = 0; } } @@ -612,6 +619,9 @@ static void a6xx_hfi_queue_init(struct a6xx_hfi_queue *queue, queue->data = virt; atomic_set(&queue->seqnum, 0); + memset(&queue->history, 0xff, sizeof(queue->history)); + queue->history_idx = 0; + /* Set up the shared memory header */ header->iova = iova; header->type = 10 << 8 | id; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h index 2bd670ca42d6..528110169398 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.h @@ -33,6 +33,17 @@ struct a6xx_hfi_queue { spinlock_t lock; u32 *data; atomic_t seqnum; + + /* + * Tracking for the start index of the last N messages in the + * queue, for the benefit of devcore dump / crashdec (since + * parsing in the reverse direction to decode the last N + * messages is difficult to do and would rely on heuristics + * which are not guaranteed to be correct) + */ +#define HFI_HISTORY_SZ 8 + s32 history[HFI_HISTORY_SZ]; + u8 history_idx; }; /* This is the outgoing queue to the GMU */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 2a6ce76656aa..93005839b5da 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -132,6 +132,24 @@ static const struct adreno_info gpulist[] = { .inactive_period = DRM_MSM_INACTIVE_PERIOD, .init = a4xx_gpu_init, }, { + .rev = ADRENO_REV(5, 0, 6, ANY_ID), + .revn = 506, + .name = "A506", + .fw = { + [ADRENO_FW_PM4] = "a530_pm4.fw", + [ADRENO_FW_PFP] = "a530_pfp.fw", + }, + .gmem = (SZ_128K + SZ_8K), + /* + * Increase inactive period to 250 to avoid bouncing + * the GDSC which appears to make it grumpy + */ + .inactive_period = 250, + .quirks = ADRENO_QUIRK_TWO_PASS_USE_WFI | + ADRENO_QUIRK_LMLOADKILL_DISABLE, + .init = a5xx_gpu_init, + .zapfw = "a506_zap.mdt", + }, { .rev = ADRENO_REV(5, 0, 8, ANY_ID), .revn = 508, .name = "A508", @@ -408,9 +426,9 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) return NULL; } - mutex_lock(&dev->struct_mutex); + mutex_lock(&gpu->lock); ret = msm_gpu_hw_init(gpu); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); pm_runtime_put_autosuspend(&pdev->dev); if (ret) { DRM_DEV_ERROR(dev->dev, "gpu hw init failed: %d\n", ret); @@ -427,13 +445,6 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev) return gpu; } -static void set_gpu_pdev(struct drm_device *dev, - struct platform_device *pdev) -{ - struct msm_drm_private *priv = dev->dev_private; - priv->gpu_pdev = pdev; -} - static int find_chipid(struct device *dev, struct adreno_rev *rev) { struct device_node *node = dev->of_node; @@ -482,8 +493,8 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) { static struct adreno_platform_config config = {}; const struct adreno_info *info; - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); + struct drm_device *drm = priv->dev; struct msm_gpu *gpu; int ret; @@ -492,7 +503,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) return ret; dev->platform_data = &config; - set_gpu_pdev(drm, to_platform_device(dev)); + priv->gpu_pdev = to_platform_device(dev); info = adreno_info(config.rev); @@ -521,12 +532,13 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) static void adreno_unbind(struct device *dev, struct device *master, void *data) { + struct msm_drm_private *priv = dev_get_drvdata(master); struct msm_gpu *gpu = dev_to_gpu(dev); pm_runtime_force_suspend(dev); gpu->funcs->destroy(gpu); - set_gpu_pdev(dev_get_drvdata(master), NULL); + priv->gpu_pdev = NULL; } static const struct component_ops a3xx_ops = { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 748665232d29..f33cfa4ef1c8 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -504,6 +504,8 @@ int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i, count = 0; + WARN_ON(!mutex_is_locked(&gpu->lock)); + kref_init(&state->ref); ktime_get_real_ts64(&state->time); @@ -630,7 +632,7 @@ static char *adreno_gpu_ascii85_encode(u32 *src, size_t len) } /* len is expected to be in bytes */ -static void adreno_show_object(struct drm_printer *p, void **ptr, int len, +void adreno_show_object(struct drm_printer *p, void **ptr, int len, bool *encoded) { if (!*ptr || !len) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 225c277a6223..cffabe7d33c1 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -201,6 +201,11 @@ static inline int adreno_is_a430(struct adreno_gpu *gpu) return gpu->revn == 430; } +static inline int adreno_is_a506(struct adreno_gpu *gpu) +{ + return gpu->revn == 506; +} + static inline int adreno_is_a508(struct adreno_gpu *gpu) { return gpu->revn == 508; @@ -306,6 +311,8 @@ void adreno_gpu_state_destroy(struct msm_gpu_state *state); int adreno_gpu_state_get(struct msm_gpu *gpu, struct msm_gpu_state *state); int adreno_gpu_state_put(struct msm_gpu_state *state); +void adreno_show_object(struct drm_printer *p, void **ptr, int len, + bool *encoded); /* * Common helper function to initialize the default address space for arm-smmu diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 967245b8cc02..e7c9fe1a250f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -337,7 +337,8 @@ static void _dpu_crtc_program_lm_output_roi(struct drm_crtc *crtc) } static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, - struct dpu_crtc *dpu_crtc, struct dpu_crtc_mixer *mixer) + struct dpu_crtc *dpu_crtc, struct dpu_crtc_mixer *mixer, + struct dpu_hw_stage_cfg *stage_cfg) { struct drm_plane *plane; struct drm_framebuffer *fb; @@ -346,7 +347,6 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, struct dpu_plane_state *pstate = NULL; struct dpu_format *format; struct dpu_hw_ctl *ctl = mixer->lm_ctl; - struct dpu_hw_stage_cfg *stage_cfg = &dpu_crtc->stage_cfg; u32 flush_mask; uint32_t stage_idx, lm_idx; @@ -422,6 +422,7 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) struct dpu_crtc_mixer *mixer = cstate->mixers; struct dpu_hw_ctl *ctl; struct dpu_hw_mixer *lm; + struct dpu_hw_stage_cfg stage_cfg; int i; DRM_DEBUG_ATOMIC("%s\n", dpu_crtc->name); @@ -435,9 +436,9 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) } /* initialize stage cfg */ - memset(&dpu_crtc->stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); + memset(&stage_cfg, 0, sizeof(struct dpu_hw_stage_cfg)); - _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer); + _dpu_crtc_blend_setup_mixer(crtc, dpu_crtc, mixer, &stage_cfg); for (i = 0; i < cstate->num_mixers; i++) { ctl = mixer[i].lm_ctl; @@ -458,7 +459,7 @@ static void _dpu_crtc_blend_setup(struct drm_crtc *crtc) mixer[i].flush_mask); ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, - &dpu_crtc->stage_cfg); + &stage_cfg); } } @@ -923,6 +924,20 @@ static struct drm_crtc_state *dpu_crtc_duplicate_state(struct drm_crtc *crtc) return &cstate->base; } +static void dpu_crtc_atomic_print_state(struct drm_printer *p, + const struct drm_crtc_state *state) +{ + const struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); + int i; + + for (i = 0; i < cstate->num_mixers; i++) { + drm_printf(p, "\tlm[%d]=%d\n", i, cstate->mixers[i].hw_lm->idx - LM_0); + drm_printf(p, "\tctl[%d]=%d\n", i, cstate->mixers[i].lm_ctl->idx - CTL_0); + if (cstate->mixers[i].hw_dspp) + drm_printf(p, "\tdspp[%d]=%d\n", i, cstate->mixers[i].hw_dspp->idx - DSPP_0); + } +} + static void dpu_crtc_disable(struct drm_crtc *crtc, struct drm_atomic_state *state) { @@ -1423,15 +1438,16 @@ DEFINE_SHOW_ATTRIBUTE(dpu_crtc_debugfs_state); static int _dpu_crtc_init_debugfs(struct drm_crtc *crtc) { struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); + struct dentry *debugfs_root; - dpu_crtc->debugfs_root = debugfs_create_dir(dpu_crtc->name, + debugfs_root = debugfs_create_dir(dpu_crtc->name, crtc->dev->primary->debugfs_root); debugfs_create_file("status", 0400, - dpu_crtc->debugfs_root, + debugfs_root, dpu_crtc, &_dpu_debugfs_status_fops); debugfs_create_file("state", 0600, - dpu_crtc->debugfs_root, + debugfs_root, &dpu_crtc->base, &dpu_crtc_debugfs_state_fops); @@ -1449,13 +1465,6 @@ static int dpu_crtc_late_register(struct drm_crtc *crtc) return _dpu_crtc_init_debugfs(crtc); } -static void dpu_crtc_early_unregister(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - - debugfs_remove_recursive(dpu_crtc->debugfs_root); -} - static const struct drm_crtc_funcs dpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = dpu_crtc_destroy, @@ -1463,8 +1472,8 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = { .reset = dpu_crtc_reset, .atomic_duplicate_state = dpu_crtc_duplicate_state, .atomic_destroy_state = dpu_crtc_destroy_state, + .atomic_print_state = dpu_crtc_atomic_print_state, .late_register = dpu_crtc_late_register, - .early_unregister = dpu_crtc_early_unregister, .verify_crc_source = dpu_crtc_verify_crc_source, .set_crc_source = dpu_crtc_set_crc_source, .enable_vblank = msm_crtc_enable_vblank, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index ae9546ca1359..b8785c394fcc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -129,8 +129,6 @@ struct dpu_crtc_frame_event { * @drm_requested_vblank : Whether vblanks have been enabled in the encoder * @property_info : Opaque structure for generic property support * @property_defaults : Array of default values for generic property support - * @stage_cfg : H/w mixer stage configuration - * @debugfs_root : Parent of debugfs node * @vblank_cb_count : count of vblank callback since last reset * @play_count : frame count between crtc enable and disable * @vblank_cb_time : ktime at vblank count reset @@ -161,9 +159,6 @@ struct dpu_crtc { struct drm_pending_vblank_event *event; u32 vsync_count; - struct dpu_hw_stage_cfg stage_cfg; - struct dentry *debugfs_root; - u32 vblank_cb_count; u64 play_count; ktime_t vblank_cb_time; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index e7ee4cfb8461..1e648db439f9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -995,9 +995,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, trace_dpu_enc_mode_set(DRMID(drm_enc)); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) - msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode); - list_for_each_entry(conn_iter, connector_list, head) if (conn_iter->encoder == drm_enc) conn = conn_iter; @@ -1148,10 +1145,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) struct msm_drm_private *priv; struct drm_display_mode *cur_mode = NULL; - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); mutex_lock(&dpu_enc->enc_lock); @@ -1177,14 +1170,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) _dpu_encoder_virt_enable_helper(drm_enc); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - ret = msm_dp_display_enable(dpu_enc->dp, drm_enc); - if (ret) { - DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", - ret); - goto out; - } - } dpu_enc->enabled = true; out: @@ -1197,14 +1182,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) struct msm_drm_private *priv; int i = 0; - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } else if (!drm_enc->dev) { - DPU_ERROR("invalid dev\n"); - return; - } - dpu_enc = to_dpu_encoder_virt(drm_enc); DPU_DEBUG_ENC(dpu_enc, "\n"); @@ -1218,11 +1195,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) /* wait for idle */ dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); - } - dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); for (i = 0; i < dpu_enc->num_phys_encs; i++) { @@ -1247,11 +1219,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); - if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { - if (msm_dp_display_disable(dpu_enc->dp, drm_enc)) - DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); - } - mutex_unlock(&dpu_enc->enc_lock); } @@ -2128,11 +2095,8 @@ static void dpu_encoder_frame_done_timeout(struct timer_list *t) static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { .mode_set = dpu_encoder_virt_mode_set, .disable = dpu_encoder_virt_disable, - .enable = dpu_kms_encoder_enable, + .enable = dpu_encoder_virt_enable, .atomic_check = dpu_encoder_virt_atomic_check, - - /* This is called by dpu_kms_encoder_enable */ - .commit = dpu_encoder_virt_enable, }; static const struct drm_encoder_funcs dpu_encoder_funcs = { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 185379b18572..ddd9d89cd456 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -698,17 +698,17 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( { struct dpu_encoder_phys *phys_enc = NULL; struct dpu_encoder_irq *irq; - int i, ret = 0; + int i; if (!p) { - ret = -EINVAL; - goto fail; + DPU_ERROR("failed to create encoder due to invalid parameter\n"); + return ERR_PTR(-EINVAL); } phys_enc = kzalloc(sizeof(*phys_enc), GFP_KERNEL); if (!phys_enc) { - ret = -ENOMEM; - goto fail; + DPU_ERROR("failed to create encoder due to memory allocation error\n"); + return ERR_PTR(-ENOMEM); } phys_enc->hw_mdptop = p->dpu_kms->hw_mdp; @@ -748,11 +748,4 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( DPU_DEBUG_VIDENC(phys_enc, "created intf idx:%d\n", p->intf_idx); return phys_enc; - -fail: - DPU_ERROR("failed to create encoder\n"); - if (phys_enc) - dpu_encoder_phys_vid_destroy(phys_enc); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c index ce6f32a919e5..aa75991903a6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -45,7 +45,7 @@ (PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2)) #define CTL_SC7280_MASK \ - (BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_FETCH_ACTIVE)) + (BIT(DPU_CTL_ACTIVE_CFG) | BIT(DPU_CTL_FETCH_ACTIVE) | BIT(DPU_CTL_VM_CFG)) #define MERGE_3D_SM8150_MASK (0) @@ -856,9 +856,9 @@ static const struct dpu_intf_cfg sm8150_intf[] = { }; static const struct dpu_intf_cfg sc7280_intf[] = { - INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), + INTF_BLK("intf_0", INTF_0, 0x34000, INTF_DP, MSM_DP_CONTROLLER_0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 24, 25), INTF_BLK("intf_1", INTF_1, 0x35000, INTF_DSI, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 26, 27), - INTF_BLK("intf_5", INTF_5, 0x39000, INTF_EDP, 0, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23), + INTF_BLK("intf_5", INTF_5, 0x39000, INTF_DP, MSM_DP_CONTROLLER_1, 24, INTF_SC7280_MASK, MDP_SSPP_TOP0_INTR, 22, 23), }; /************************************************************* diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 4ade44bbd37e..31af04afda7d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -179,13 +179,16 @@ enum { /** * CTL sub-blocks - * @DPU_CTL_SPLIT_DISPLAY CTL supports video mode split display + * @DPU_CTL_SPLIT_DISPLAY: CTL supports video mode split display + * @DPU_CTL_FETCH_ACTIVE: Active CTL for fetch HW (SSPPs) + * @DPU_CTL_VM_CFG: CTL config to support multiple VMs * @DPU_CTL_MAX */ enum { DPU_CTL_SPLIT_DISPLAY = 0x1, DPU_CTL_ACTIVE_CFG, DPU_CTL_FETCH_ACTIVE, + DPU_CTL_VM_CFG, DPU_CTL_MAX }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 64740ddb983e..02da9ecf71f1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -36,6 +36,7 @@ #define MERGE_3D_IDX 23 #define INTF_IDX 31 #define CTL_INVALID_BIT 0xffff +#define CTL_DEFAULT_GROUP_ID 0xf static const u32 fetch_tbl[SSPP_MAX] = {CTL_INVALID_BIT, 16, 17, 18, 19, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, CTL_INVALID_BIT, 0, @@ -498,6 +499,13 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, u32 intf_active = 0; u32 mode_sel = 0; + /* CTL_TOP[31:28] carries group_id to collate CTL paths + * per VM. Explicitly disable it until VM support is + * added in SW. Power on reset value is not disable. + */ + if ((test_bit(DPU_CTL_VM_CFG, &ctx->caps->features))) + mode_sel = CTL_DEFAULT_GROUP_ID << 28; + if (cfg->intf_mode_sel == DPU_CTL_MODE_SEL_CMD) mode_sel |= BIT(17); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c index d2b6dca487e3..a77a5eaa78ad 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -30,6 +30,9 @@ #define MDP_AD4_INTR_STATUS_OFF 0x420 #define MDP_INTF_0_OFF_REV_7xxx 0x34000 #define MDP_INTF_1_OFF_REV_7xxx 0x35000 +#define MDP_INTF_2_OFF_REV_7xxx 0x36000 +#define MDP_INTF_3_OFF_REV_7xxx 0x37000 +#define MDP_INTF_4_OFF_REV_7xxx 0x38000 #define MDP_INTF_5_OFF_REV_7xxx 0x39000 /** @@ -111,6 +114,21 @@ static const struct dpu_intr_reg dpu_intr_set[] = { MDP_INTF_1_OFF_REV_7xxx+INTF_INTR_STATUS }, { + MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_2_OFF_REV_7xxx+INTF_INTR_STATUS + }, + { + MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_3_OFF_REV_7xxx+INTF_INTR_STATUS + }, + { + MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_CLEAR, + MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_EN, + MDP_INTF_4_OFF_REV_7xxx+INTF_INTR_STATUS + }, + { MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_CLEAR, MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_EN, MDP_INTF_5_OFF_REV_7xxx+INTF_INTR_STATUS diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index d50e78c9f148..1ab75cccd145 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -26,6 +26,9 @@ enum dpu_hw_intr_reg { MDP_AD4_1_INTR, MDP_INTF0_7xxx_INTR, MDP_INTF1_7xxx_INTR, + MDP_INTF2_7xxx_INTR, + MDP_INTF3_7xxx_INTR, + MDP_INTF4_7xxx_INTR, MDP_INTF5_7xxx_INTR, MDP_INTR_MAX, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index f9460672176a..09cdc3576653 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -8,6 +8,8 @@ #include "dpu_hw_sspp.h" #include "dpu_kms.h" +#include <drm/drm_file.h> + #define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087 /* DPU_SSPP_SRC */ @@ -75,6 +77,7 @@ #define SSPP_TRAFFIC_SHAPER 0x130 #define SSPP_CDP_CNTL 0x134 #define SSPP_UBWC_ERROR_STATUS 0x138 +#define SSPP_CDP_CNTL_REC1 0x13c #define SSPP_TRAFFIC_SHAPER_PREFILL 0x150 #define SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154 #define SSPP_TRAFFIC_SHAPER_REC1 0x158 @@ -413,13 +416,11 @@ static void dpu_hw_sspp_setup_pe_config(struct dpu_hw_pipe *ctx, static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_pipe *ctx, struct dpu_hw_pipe_cfg *sspp, - struct dpu_hw_pixel_ext *pe, void *scaler_cfg) { u32 idx; struct dpu_hw_scaler3_cfg *scaler3_cfg = scaler_cfg; - (void)pe; if (_sspp_subblk_offset(ctx, DPU_SSPP_SCALER_QSEED3, &idx) || !sspp || !scaler3_cfg) return; @@ -539,7 +540,7 @@ static void dpu_hw_sspp_setup_sourceaddress(struct dpu_hw_pipe *ctx, } static void dpu_hw_sspp_setup_csc(struct dpu_hw_pipe *ctx, - struct dpu_csc_cfg *data) + const struct dpu_csc_cfg *data) { u32 idx; bool csc10 = false; @@ -571,19 +572,20 @@ static void dpu_hw_sspp_setup_solidfill(struct dpu_hw_pipe *ctx, u32 color, enum } static void dpu_hw_sspp_setup_danger_safe_lut(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_qos_cfg *cfg) + u32 danger_lut, + u32 safe_lut) { u32 idx; if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) return; - DPU_REG_WRITE(&ctx->hw, SSPP_DANGER_LUT + idx, cfg->danger_lut); - DPU_REG_WRITE(&ctx->hw, SSPP_SAFE_LUT + idx, cfg->safe_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_DANGER_LUT + idx, danger_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_SAFE_LUT + idx, safe_lut); } static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_qos_cfg *cfg) + u64 creq_lut) { u32 idx; @@ -591,11 +593,11 @@ static void dpu_hw_sspp_setup_creq_lut(struct dpu_hw_pipe *ctx, return; if (ctx->cap && test_bit(DPU_SSPP_QOS_8LVL, &ctx->cap->features)) { - DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_0 + idx, cfg->creq_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_0 + idx, creq_lut); DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_1 + idx, - cfg->creq_lut >> 32); + creq_lut >> 32); } else { - DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT + idx, cfg->creq_lut); + DPU_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT + idx, creq_lut); } } @@ -625,10 +627,12 @@ static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe *ctx, } static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_cdp_cfg *cfg) + struct dpu_hw_pipe_cdp_cfg *cfg, + enum dpu_sspp_multirect_index index) { u32 idx; u32 cdp_cntl = 0; + u32 cdp_cntl_offset = 0; if (!ctx || !cfg) return; @@ -636,6 +640,11 @@ static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx, if (_sspp_subblk_offset(ctx, DPU_SSPP_SRC, &idx)) return; + if (index == DPU_SSPP_RECT_SOLO || index == DPU_SSPP_RECT_0) + cdp_cntl_offset = SSPP_CDP_CNTL; + else + cdp_cntl_offset = SSPP_CDP_CNTL_REC1; + if (cfg->enable) cdp_cntl |= BIT(0); if (cfg->ubwc_meta_enable) @@ -645,7 +654,7 @@ static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx, if (cfg->preload_ahead == DPU_SSPP_CDP_PRELOAD_AHEAD_64) cdp_cntl |= BIT(3); - DPU_REG_WRITE(&ctx->hw, SSPP_CDP_CNTL, cdp_cntl); + DPU_REG_WRITE(&ctx->hw, cdp_cntl_offset, cdp_cntl); } static void _setup_layer_ops(struct dpu_hw_pipe *c, @@ -685,6 +694,71 @@ static void _setup_layer_ops(struct dpu_hw_pipe *c, c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; } +#ifdef CONFIG_DEBUG_FS +int _dpu_hw_sspp_init_debugfs(struct dpu_hw_pipe *hw_pipe, struct dpu_kms *kms, struct dentry *entry) +{ + const struct dpu_sspp_cfg *cfg = hw_pipe->cap; + const struct dpu_sspp_sub_blks *sblk = cfg->sblk; + struct dentry *debugfs_root; + char sspp_name[32]; + + snprintf(sspp_name, sizeof(sspp_name), "%d", hw_pipe->idx); + + /* create overall sub-directory for the pipe */ + debugfs_root = + debugfs_create_dir(sspp_name, entry); + + /* don't error check these */ + debugfs_create_xul("features", 0600, + debugfs_root, (unsigned long *)&hw_pipe->cap->features); + + /* add register dump support */ + dpu_debugfs_create_regset32("src_blk", 0400, + debugfs_root, + sblk->src_blk.base + cfg->base, + sblk->src_blk.len, + kms); + + if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || + cfg->features & BIT(DPU_SSPP_SCALER_QSEED3LITE) || + cfg->features & BIT(DPU_SSPP_SCALER_QSEED2) || + cfg->features & BIT(DPU_SSPP_SCALER_QSEED4)) + dpu_debugfs_create_regset32("scaler_blk", 0400, + debugfs_root, + sblk->scaler_blk.base + cfg->base, + sblk->scaler_blk.len, + kms); + + if (cfg->features & BIT(DPU_SSPP_CSC) || + cfg->features & BIT(DPU_SSPP_CSC_10BIT)) + dpu_debugfs_create_regset32("csc_blk", 0400, + debugfs_root, + sblk->csc_blk.base + cfg->base, + sblk->csc_blk.len, + kms); + + debugfs_create_u32("xin_id", + 0400, + debugfs_root, + (u32 *) &cfg->xin_id); + debugfs_create_u32("clk_ctrl", + 0400, + debugfs_root, + (u32 *) &cfg->clk_ctrl); + debugfs_create_x32("creq_vblank", + 0600, + debugfs_root, + (u32 *) &sblk->creq_vblank); + debugfs_create_x32("danger_vblank", + 0600, + debugfs_root, + (u32 *) &sblk->danger_vblank); + + return 0; +} +#endif + + static const struct dpu_sspp_cfg *_sspp_offset(enum dpu_sspp sspp, void __iomem *addr, struct dpu_mdss_cfg *catalog, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index fdfd4b46e2c6..92b071b78fdb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -25,11 +25,17 @@ struct dpu_hw_pipe; /** * Define all scaler feature bits in catalog */ -#define DPU_SSPP_SCALER ((1UL << DPU_SSPP_SCALER_RGB) | \ - (1UL << DPU_SSPP_SCALER_QSEED2) | \ - (1UL << DPU_SSPP_SCALER_QSEED3) | \ - (1UL << DPU_SSPP_SCALER_QSEED3LITE) | \ - (1UL << DPU_SSPP_SCALER_QSEED4)) +#define DPU_SSPP_SCALER (BIT(DPU_SSPP_SCALER_RGB) | \ + BIT(DPU_SSPP_SCALER_QSEED2) | \ + BIT(DPU_SSPP_SCALER_QSEED3) | \ + BIT(DPU_SSPP_SCALER_QSEED3LITE) | \ + BIT(DPU_SSPP_SCALER_QSEED4)) + +/* + * Define all CSC feature bits in catalog + */ +#define DPU_SSPP_CSC_ANY (BIT(DPU_SSPP_CSC) | \ + BIT(DPU_SSPP_CSC_10BIT)) /** * Component indices @@ -166,18 +172,12 @@ struct dpu_hw_pipe_cfg { /** * struct dpu_hw_pipe_qos_cfg : Source pipe QoS configuration - * @danger_lut: LUT for generate danger level based on fill level - * @safe_lut: LUT for generate safe level based on fill level - * @creq_lut: LUT for generate creq level based on fill level * @creq_vblank: creq value generated to vbif during vertical blanking * @danger_vblank: danger value generated during vertical blanking * @vblank_en: enable creq_vblank and danger_vblank during vblank * @danger_safe_en: enable danger safe generation */ struct dpu_hw_pipe_qos_cfg { - u32 danger_lut; - u32 safe_lut; - u64 creq_lut; u32 creq_vblank; u32 danger_vblank; bool vblank_en; @@ -268,7 +268,7 @@ struct dpu_hw_sspp_ops { * @ctx: Pointer to pipe context * @data: Pointer to config structure */ - void (*setup_csc)(struct dpu_hw_pipe *ctx, struct dpu_csc_cfg *data); + void (*setup_csc)(struct dpu_hw_pipe *ctx, const struct dpu_csc_cfg *data); /** * setup_solidfill - enable/disable colorfill @@ -302,20 +302,22 @@ struct dpu_hw_sspp_ops { /** * setup_danger_safe_lut - setup danger safe LUTs * @ctx: Pointer to pipe context - * @cfg: Pointer to pipe QoS configuration + * @danger_lut: LUT for generate danger level based on fill level + * @safe_lut: LUT for generate safe level based on fill level * */ void (*setup_danger_safe_lut)(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_qos_cfg *cfg); + u32 danger_lut, + u32 safe_lut); /** * setup_creq_lut - setup CREQ LUT * @ctx: Pointer to pipe context - * @cfg: Pointer to pipe QoS configuration + * @creq_lut: LUT for generate creq level based on fill level * */ void (*setup_creq_lut)(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_qos_cfg *cfg); + u64 creq_lut); /** * setup_qos_ctrl - setup QoS control @@ -338,12 +340,10 @@ struct dpu_hw_sspp_ops { * setup_scaler - setup scaler * @ctx: Pointer to pipe context * @pipe_cfg: Pointer to pipe configuration - * @pe_cfg: Pointer to pixel extension configuration * @scaler_cfg: Pointer to scaler configuration */ void (*setup_scaler)(struct dpu_hw_pipe *ctx, struct dpu_hw_pipe_cfg *pipe_cfg, - struct dpu_hw_pixel_ext *pe_cfg, void *scaler_cfg); /** @@ -356,9 +356,11 @@ struct dpu_hw_sspp_ops { * setup_cdp - setup client driven prefetch * @ctx: Pointer to pipe context * @cfg: Pointer to cdp configuration + * @index: rectangle index in multirect */ void (*setup_cdp)(struct dpu_hw_pipe *ctx, - struct dpu_hw_pipe_cdp_cfg *cfg); + struct dpu_hw_pipe_cdp_cfg *cfg, + enum dpu_sspp_multirect_index index); }; /** @@ -385,6 +387,7 @@ struct dpu_hw_pipe { struct dpu_hw_sspp_ops ops; }; +struct dpu_kms; /** * dpu_hw_sspp_init - initializes the sspp hw driver object. * Should be called once before accessing every pipe. @@ -404,5 +407,8 @@ struct dpu_hw_pipe *dpu_hw_sspp_init(enum dpu_sspp idx, */ void dpu_hw_sspp_destroy(struct dpu_hw_pipe *ctx); +void dpu_debugfs_sspp_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root); +int _dpu_hw_sspp_init_debugfs(struct dpu_hw_pipe *hw_pipe, struct dpu_kms *kms, struct dentry *entry); + #endif /*_DPU_HW_SSPP_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index f94584c982cd..aad85116b0a0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -374,7 +374,7 @@ u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, - struct dpu_csc_cfg *data, bool csc10) + const struct dpu_csc_cfg *data, bool csc10) { static const u32 matrix_shift = 7; u32 clamp_shift = csc10 ? 16 : 8; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index 6d4911957e33..39134754579e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -322,6 +322,6 @@ u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, - struct dpu_csc_cfg *data, bool csc10); + const struct dpu_csc_cfg *data, bool csc10); #endif /* _DPU_HW_UTIL_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index a15b26428280..47fe11a84a77 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -21,14 +21,14 @@ #include "msm_gem.h" #include "disp/msm_disp_snapshot.h" -#include "dpu_kms.h" #include "dpu_core_irq.h" +#include "dpu_crtc.h" +#include "dpu_encoder.h" #include "dpu_formats.h" #include "dpu_hw_vbif.h" -#include "dpu_vbif.h" -#include "dpu_encoder.h" +#include "dpu_kms.h" #include "dpu_plane.h" -#include "dpu_crtc.h" +#include "dpu_vbif.h" #define CREATE_TRACE_POINTS #include "dpu_trace.h" @@ -73,8 +73,8 @@ static int _dpu_danger_signal_status(struct seq_file *s, &status); } else { seq_puts(s, "\nSafe signal status:\n"); - if (kms->hw_mdp->ops.get_danger_status) - kms->hw_mdp->ops.get_danger_status(kms->hw_mdp, + if (kms->hw_mdp->ops.get_safe_status) + kms->hw_mdp->ops.get_safe_status(kms->hw_mdp, &status); } pm_runtime_put_sync(&kms->pdev->dev); @@ -82,7 +82,7 @@ static int _dpu_danger_signal_status(struct seq_file *s, seq_printf(s, "MDP : 0x%x\n", status.mdp); for (i = SSPP_VIG0; i < SSPP_MAX; i++) - seq_printf(s, "SSPP%d : 0x%x \t", i - SSPP_VIG0, + seq_printf(s, "SSPP%d : 0x%x \n", i - SSPP_VIG0, status.sspp[i]); seq_puts(s, "\n"); @@ -101,6 +101,73 @@ static int dpu_debugfs_safe_stats_show(struct seq_file *s, void *v) } DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_safe_stats); +static ssize_t _dpu_plane_danger_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct dpu_kms *kms = file->private_data; + int len; + char buf[40]; + + len = scnprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl); + + return simple_read_from_buffer(buff, count, ppos, buf, len); +} + +static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, kms->dev) { + if (plane->fb && plane->state) { + dpu_plane_danger_signal_ctrl(plane, enable); + DPU_DEBUG("plane:%d img:%dx%d ", + plane->base.id, plane->fb->width, + plane->fb->height); + DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n", + plane->state->src_x >> 16, + plane->state->src_y >> 16, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->crtc_w, plane->state->crtc_h); + } else { + DPU_DEBUG("Inactive plane:%d\n", plane->base.id); + } + } +} + +static ssize_t _dpu_plane_danger_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct dpu_kms *kms = file->private_data; + int disable_panic; + int ret; + + ret = kstrtouint_from_user(user_buf, count, 0, &disable_panic); + if (ret) + return ret; + + if (disable_panic) { + /* Disable panic signal for all active pipes */ + DPU_DEBUG("Disabling danger:\n"); + _dpu_plane_set_danger_state(kms, false); + kms->has_danger_ctrl = false; + } else { + /* Enable panic signal for all active pipes */ + DPU_DEBUG("Enabling danger:\n"); + kms->has_danger_ctrl = true; + _dpu_plane_set_danger_state(kms, true); + } + + return count; +} + +static const struct file_operations dpu_plane_danger_enable = { + .open = simple_open, + .read = _dpu_plane_danger_read, + .write = _dpu_plane_danger_write, +}; + static void dpu_debugfs_danger_init(struct dpu_kms *dpu_kms, struct dentry *parent) { @@ -110,8 +177,20 @@ static void dpu_debugfs_danger_init(struct dpu_kms *dpu_kms, dpu_kms, &dpu_debugfs_danger_stats_fops); debugfs_create_file("safe_status", 0600, entry, dpu_kms, &dpu_debugfs_safe_stats_fops); + debugfs_create_file("disable_danger", 0600, entry, + dpu_kms, &dpu_plane_danger_enable); + } +/* + * Companion structure for dpu_debugfs_create_regset32. + */ +struct dpu_debugfs_regset32 { + uint32_t offset; + uint32_t blk_len; + struct dpu_kms *dpu_kms; +}; + static int _dpu_debugfs_show_regset32(struct seq_file *s, void *data) { struct dpu_debugfs_regset32 *regset = s->private; @@ -159,24 +238,23 @@ static const struct file_operations dpu_fops_regset32 = { .release = single_release, }; -void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset, +void dpu_debugfs_create_regset32(const char *name, umode_t mode, + void *parent, uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms) { - if (regset) { - regset->offset = offset; - regset->blk_len = length; - regset->dpu_kms = dpu_kms; - } -} + struct dpu_debugfs_regset32 *regset; -void dpu_debugfs_create_regset32(const char *name, umode_t mode, - void *parent, struct dpu_debugfs_regset32 *regset) -{ - if (!name || !regset || !regset->dpu_kms || !regset->blk_len) + if (WARN_ON(!name || !dpu_kms || !length)) + return; + + regset = devm_kzalloc(&dpu_kms->pdev->dev, sizeof(*regset), GFP_KERNEL); + if (!regset) return; /* make sure offset is a multiple of 4 */ - regset->offset = round_down(regset->offset, 4); + regset->offset = round_down(offset, 4); + regset->blk_len = length; + regset->dpu_kms = dpu_kms; debugfs_create_file(name, mode, parent, regset, &dpu_fops_regset32); } @@ -203,6 +281,7 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) dpu_debugfs_danger_init(dpu_kms, entry); dpu_debugfs_vbif_init(dpu_kms, entry); dpu_debugfs_core_irq_init(dpu_kms, entry); + dpu_debugfs_sspp_init(dpu_kms, entry); for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { if (priv->dp[i]) @@ -384,28 +463,6 @@ static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask) } } -/* - * Override the encoder enable since we need to setup the inline rotator and do - * some crtc magic before enabling any bridge that might be present. - */ -void dpu_kms_encoder_enable(struct drm_encoder *encoder) -{ - const struct drm_encoder_helper_funcs *funcs = encoder->helper_private; - struct drm_device *dev = encoder->dev; - struct drm_crtc *crtc; - - /* Forward this enable call to the commit hook */ - if (funcs && funcs->commit) - funcs->commit(encoder); - - drm_for_each_crtc(crtc, dev) { - if (!(crtc->state->encoder_mask & drm_encoder_mask(encoder))) - continue; - - trace_dpu_kms_enc_enable(DRMID(crtc)); - } -} - static void dpu_kms_complete_commit(struct msm_kms *kms, unsigned crtc_mask) { struct dpu_kms *dpu_kms = to_dpu_kms(kms); @@ -863,6 +920,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k msm_disp_snapshot_add_block(disp_state, cat->sspp[i].len, dpu_kms->mmio + cat->sspp[i].base, "sspp_%d", i); + /* dump LM sub-blocks HW regs info */ + for (i = 0; i < cat->mixer_count; i++) + msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len, + dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i); + msm_disp_snapshot_add_block(disp_state, top->hw.length, dpu_kms->mmio + top->hw.blk_off, "top"); @@ -1153,9 +1215,9 @@ struct msm_kms *dpu_kms_init(struct drm_device *dev) static int dpu_bind(struct device *dev, struct device *master, void *data) { - struct drm_device *ddev = dev_get_drvdata(master); + struct msm_drm_private *priv = dev_get_drvdata(master); struct platform_device *pdev = to_platform_device(dev); - struct msm_drm_private *priv = ddev->dev_private; + struct drm_device *ddev = priv->dev; struct dpu_kms *dpu_kms; struct dss_module_power *mp; int ret = 0; @@ -1285,7 +1347,7 @@ static const struct dev_pm_ops dpu_pm_ops = { pm_runtime_force_resume) }; -static const struct of_device_id dpu_dt_match[] = { +const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sdm845-dpu", }, { .compatible = "qcom,sc7180-dpu", }, { .compatible = "qcom,sc7280-dpu", }, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 775bcbda860f..2d385b4b7f5e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -160,34 +160,10 @@ struct dpu_global_state * * Documentation/filesystems/debugfs.rst * - * @dpu_debugfs_setup_regset32: Initialize data for dpu_debugfs_create_regset32 * @dpu_debugfs_create_regset32: Create 32-bit register dump file - * @dpu_debugfs_get_root: Get root dentry for DPU_KMS's debugfs node */ /** - * Companion structure for dpu_debugfs_create_regset32. Do not initialize the - * members of this structure explicitly; use dpu_debugfs_setup_regset32 instead. - */ -struct dpu_debugfs_regset32 { - uint32_t offset; - uint32_t blk_len; - struct dpu_kms *dpu_kms; -}; - -/** - * dpu_debugfs_setup_regset32 - Initialize register block definition for debugfs - * This function is meant to initialize dpu_debugfs_regset32 structures for use - * with dpu_debugfs_create_regset32. - * @regset: opaque register definition structure - * @offset: sub-block offset - * @length: sub-block length, in bytes - * @dpu_kms: pointer to dpu kms structure - */ -void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset, - uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms); - -/** * dpu_debugfs_create_regset32 - Create register read back file for debugfs * * This function is almost identical to the standard debugfs_create_regset32() @@ -195,20 +171,16 @@ void dpu_debugfs_setup_regset32(struct dpu_debugfs_regset32 *regset, * names/offsets do not need to be provided. The 'read' function simply outputs * sequential register values over a specified range. * - * Similar to the related debugfs_create_regset32 API, the structure pointed to - * by regset needs to persist for the lifetime of the created file. The calling - * code is responsible for initialization/management of this structure. - * - * The structure pointed to by regset is meant to be opaque. Please use - * dpu_debugfs_setup_regset32 to initialize it. - * * @name: File name within debugfs * @mode: File mode within debugfs * @parent: Parent directory entry within debugfs, can be NULL - * @regset: Pointer to persistent register block definition + * @offset: sub-block offset + * @length: sub-block length, in bytes + * @dpu_kms: pointer to dpu kms structure */ void dpu_debugfs_create_regset32(const char *name, umode_t mode, - void *parent, struct dpu_debugfs_regset32 *regset); + void *parent, + uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms); /** * dpu_debugfs_get_root - Return root directory entry for KMS's debugfs @@ -235,8 +207,6 @@ void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms); int dpu_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); void dpu_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); -void dpu_kms_encoder_enable(struct drm_encoder *encoder); - /** * dpu_kms_get_clk_rate() - get the clock rate * @dpu_kms: pointer to dpu_kms structure diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index b466784d9822..131c1f1a869c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -111,7 +111,7 @@ static int _dpu_mdss_irq_domain_add(struct dpu_mdss *dpu_mdss) struct device *dev; struct irq_domain *domain; - dev = dpu_mdss->base.dev->dev; + dev = dpu_mdss->base.dev; domain = irq_domain_add_linear(dev->of_node, 32, &dpu_mdss_irqdomain_ops, dpu_mdss); @@ -184,16 +184,15 @@ static int dpu_mdss_disable(struct msm_mdss *mdss) return ret; } -static void dpu_mdss_destroy(struct drm_device *dev) +static void dpu_mdss_destroy(struct msm_mdss *mdss) { - struct platform_device *pdev = to_platform_device(dev->dev); - struct msm_drm_private *priv = dev->dev_private; - struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); + struct platform_device *pdev = to_platform_device(mdss->dev); + struct dpu_mdss *dpu_mdss = to_dpu_mdss(mdss); struct dss_module_power *mp = &dpu_mdss->mp; int irq; - pm_runtime_suspend(dev->dev); - pm_runtime_disable(dev->dev); + pm_runtime_suspend(mdss->dev); + pm_runtime_disable(mdss->dev); _dpu_mdss_irq_domain_fini(dpu_mdss); irq = platform_get_irq(pdev, 0); irq_set_chained_handler_and_data(irq, NULL, NULL); @@ -203,7 +202,6 @@ static void dpu_mdss_destroy(struct drm_device *dev) if (dpu_mdss->mmio) devm_iounmap(&pdev->dev, dpu_mdss->mmio); dpu_mdss->mmio = NULL; - priv->mdss = NULL; } static const struct msm_mdss_funcs mdss_funcs = { @@ -212,16 +210,15 @@ static const struct msm_mdss_funcs mdss_funcs = { .destroy = dpu_mdss_destroy, }; -int dpu_mdss_init(struct drm_device *dev) +int dpu_mdss_init(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev->dev); - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = platform_get_drvdata(pdev); struct dpu_mdss *dpu_mdss; struct dss_module_power *mp; int ret; int irq; - dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL); + dpu_mdss = devm_kzalloc(&pdev->dev, sizeof(*dpu_mdss), GFP_KERNEL); if (!dpu_mdss) return -ENOMEM; @@ -238,7 +235,7 @@ int dpu_mdss_init(struct drm_device *dev) goto clk_parse_err; } - dpu_mdss->base.dev = dev; + dpu_mdss->base.dev = &pdev->dev; dpu_mdss->base.funcs = &mdss_funcs; ret = _dpu_mdss_irq_domain_add(dpu_mdss); @@ -256,7 +253,7 @@ int dpu_mdss_init(struct drm_device *dev) priv->mdss = &dpu_mdss->base; - pm_runtime_enable(dev->dev); + pm_runtime_enable(&pdev->dev); return 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index a3e3b9d1b82e..ca75089c9d61 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -13,7 +13,6 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_uapi.h> #include <drm/drm_damage_helper.h> -#include <drm/drm_file.h> #include <drm/drm_gem_atomic_helper.h> #include "msm_drv.h" @@ -90,7 +89,6 @@ enum dpu_plane_qos { /* * struct dpu_plane - local dpu plane structure * @aspace: address space pointer - * @csc_ptr: Points to dpu_csc_cfg structure to use for current * @mplane_list: List of multirect planes of the same pipe * @catalog: Points to dpu catalog structure * @revalidate: force revalidation of all the plane properties @@ -101,29 +99,14 @@ struct dpu_plane { struct mutex lock; enum dpu_sspp pipe; - uint32_t features; /* capabilities from catalog */ struct dpu_hw_pipe *pipe_hw; - struct dpu_hw_pipe_cfg pipe_cfg; - struct dpu_hw_pipe_qos_cfg pipe_qos_cfg; uint32_t color_fill; bool is_error; bool is_rt_pipe; bool is_virtual; struct list_head mplane_list; struct dpu_mdss_cfg *catalog; - - struct dpu_csc_cfg *csc_ptr; - - const struct dpu_sspp_sub_blks *pipe_sblk; - char pipe_name[DPU_NAME_SIZE]; - - /* debugfs related stuff */ - struct dentry *debugfs_root; - struct dpu_debugfs_regset32 debugfs_src; - struct dpu_debugfs_regset32 debugfs_scaler; - struct dpu_debugfs_regset32 debugfs_csc; - bool debugfs_default_scale; }; static const uint64_t supported_format_modifiers[] = { @@ -145,14 +128,15 @@ static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane) * _dpu_plane_calc_bw - calculate bandwidth required for a plane * @plane: Pointer to drm plane. * @fb: Pointer to framebuffer associated with the given plane + * @pipe_cfg: Pointer to pipe configuration * Result: Updates calculated bandwidth in the plane state. * BW Equation: src_w * src_h * bpp * fps * (v_total / v_dest) * Prefill BW Equation: line src bytes * line_time */ static void _dpu_plane_calc_bw(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, + struct dpu_hw_pipe_cfg *pipe_cfg) { - struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate; struct drm_display_mode *mode; const struct dpu_format *fmt = NULL; @@ -169,9 +153,9 @@ static void _dpu_plane_calc_bw(struct drm_plane *plane, fmt = dpu_get_dpu_format_ext(fb->format->format, fb->modifier); - src_width = drm_rect_width(&pdpu->pipe_cfg.src_rect); - src_height = drm_rect_height(&pdpu->pipe_cfg.src_rect); - dst_height = drm_rect_height(&pdpu->pipe_cfg.dst_rect); + src_width = drm_rect_width(&pipe_cfg->src_rect); + src_height = drm_rect_height(&pipe_cfg->src_rect); + dst_height = drm_rect_height(&pipe_cfg->dst_rect); fps = drm_mode_vrefresh(mode); vbp = mode->vtotal - mode->vsync_end; vpw = mode->vsync_end - mode->vsync_start; @@ -202,12 +186,12 @@ static void _dpu_plane_calc_bw(struct drm_plane *plane, /** * _dpu_plane_calc_clk - calculate clock required for a plane * @plane: Pointer to drm plane. + * @pipe_cfg: Pointer to pipe configuration * Result: Updates calculated clock in the plane state. * Clock equation: dst_w * v_total * fps * (src_h / dst_h) */ -static void _dpu_plane_calc_clk(struct drm_plane *plane) +static void _dpu_plane_calc_clk(struct drm_plane *plane, struct dpu_hw_pipe_cfg *pipe_cfg) { - struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate; struct drm_display_mode *mode; int dst_width, src_height, dst_height, fps; @@ -215,9 +199,9 @@ static void _dpu_plane_calc_clk(struct drm_plane *plane) pstate = to_dpu_plane_state(plane->state); mode = &plane->state->crtc->mode; - src_height = drm_rect_height(&pdpu->pipe_cfg.src_rect); - dst_width = drm_rect_width(&pdpu->pipe_cfg.dst_rect); - dst_height = drm_rect_height(&pdpu->pipe_cfg.dst_rect); + src_height = drm_rect_height(&pipe_cfg->src_rect); + dst_width = drm_rect_width(&pipe_cfg->dst_rect); + dst_height = drm_rect_height(&pipe_cfg->dst_rect); fps = drm_mode_vrefresh(mode); pstate->plane_clk = @@ -254,14 +238,17 @@ static int _dpu_plane_calc_fill_level(struct drm_plane *plane, fixed_buff_size = pdpu->catalog->caps->pixel_ram_size; list_for_each_entry(tmp, &pdpu->mplane_list, mplane_list) { + u32 tmp_width; + if (!tmp->base.state->visible) continue; + tmp_width = drm_rect_width(&tmp->base.state->src) >> 16; DPU_DEBUG("plane%d/%d src_width:%d/%d\n", pdpu->base.base.id, tmp->base.base.id, src_width, - drm_rect_width(&tmp->pipe_cfg.src_rect)); + tmp_width); src_width = max_t(u32, src_width, - drm_rect_width(&tmp->pipe_cfg.src_rect)); + tmp_width); } if (fmt->fetch_planes == DPU_PLANE_PSEUDO_PLANAR) { @@ -321,9 +308,10 @@ static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, * _dpu_plane_set_qos_lut - set QoS LUT of the given plane * @plane: Pointer to drm plane * @fb: Pointer to framebuffer associated with the given plane + * @pipe_cfg: Pointer to pipe configuration */ static void _dpu_plane_set_qos_lut(struct drm_plane *plane, - struct drm_framebuffer *fb) + struct drm_framebuffer *fb, struct dpu_hw_pipe_cfg *pipe_cfg) { struct dpu_plane *pdpu = to_dpu_plane(plane); const struct dpu_format *fmt = NULL; @@ -337,7 +325,7 @@ static void _dpu_plane_set_qos_lut(struct drm_plane *plane, fb->format->format, fb->modifier); total_fl = _dpu_plane_calc_fill_level(plane, fmt, - drm_rect_width(&pdpu->pipe_cfg.src_rect)); + drm_rect_width(&pipe_cfg->src_rect)); if (fmt && DPU_FORMAT_IS_LINEAR(fmt)) lut_usage = DPU_QOS_LUT_USAGE_LINEAR; @@ -348,8 +336,6 @@ static void _dpu_plane_set_qos_lut(struct drm_plane *plane, qos_lut = _dpu_plane_get_qos_lut( &pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl); - pdpu->pipe_qos_cfg.creq_lut = qos_lut; - trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0, (fmt) ? fmt->base.pixel_format : 0, pdpu->is_rt_pipe, total_fl, qos_lut, lut_usage); @@ -359,7 +345,7 @@ static void _dpu_plane_set_qos_lut(struct drm_plane *plane, fmt ? (char *)&fmt->base.pixel_format : NULL, pdpu->is_rt_pipe, total_fl, qos_lut); - pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, &pdpu->pipe_qos_cfg); + pdpu->pipe_hw->ops.setup_creq_lut(pdpu->pipe_hw, qos_lut); } /** @@ -397,24 +383,21 @@ static void _dpu_plane_set_danger_lut(struct drm_plane *plane, } } - pdpu->pipe_qos_cfg.danger_lut = danger_lut; - pdpu->pipe_qos_cfg.safe_lut = safe_lut; - trace_dpu_perf_set_danger_luts(pdpu->pipe - SSPP_VIG0, (fmt) ? fmt->base.pixel_format : 0, (fmt) ? fmt->fetch_mode : 0, - pdpu->pipe_qos_cfg.danger_lut, - pdpu->pipe_qos_cfg.safe_lut); + danger_lut, + safe_lut); DPU_DEBUG_PLANE(pdpu, "pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n", pdpu->pipe - SSPP_VIG0, fmt ? (char *)&fmt->base.pixel_format : NULL, fmt ? fmt->fetch_mode : -1, - pdpu->pipe_qos_cfg.danger_lut, - pdpu->pipe_qos_cfg.safe_lut); + danger_lut, + safe_lut); pdpu->pipe_hw->ops.setup_danger_safe_lut(pdpu->pipe_hw, - &pdpu->pipe_qos_cfg); + danger_lut, safe_lut); } /** @@ -427,47 +410,51 @@ static void _dpu_plane_set_qos_ctrl(struct drm_plane *plane, bool enable, u32 flags) { struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_hw_pipe_qos_cfg pipe_qos_cfg; + + memset(&pipe_qos_cfg, 0, sizeof(pipe_qos_cfg)); if (flags & DPU_PLANE_QOS_VBLANK_CTRL) { - pdpu->pipe_qos_cfg.creq_vblank = pdpu->pipe_sblk->creq_vblank; - pdpu->pipe_qos_cfg.danger_vblank = - pdpu->pipe_sblk->danger_vblank; - pdpu->pipe_qos_cfg.vblank_en = enable; + pipe_qos_cfg.creq_vblank = pdpu->pipe_hw->cap->sblk->creq_vblank; + pipe_qos_cfg.danger_vblank = + pdpu->pipe_hw->cap->sblk->danger_vblank; + pipe_qos_cfg.vblank_en = enable; } if (flags & DPU_PLANE_QOS_VBLANK_AMORTIZE) { /* this feature overrules previous VBLANK_CTRL */ - pdpu->pipe_qos_cfg.vblank_en = false; - pdpu->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */ + pipe_qos_cfg.vblank_en = false; + pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */ } if (flags & DPU_PLANE_QOS_PANIC_CTRL) - pdpu->pipe_qos_cfg.danger_safe_en = enable; + pipe_qos_cfg.danger_safe_en = enable; if (!pdpu->is_rt_pipe) { - pdpu->pipe_qos_cfg.vblank_en = false; - pdpu->pipe_qos_cfg.danger_safe_en = false; + pipe_qos_cfg.vblank_en = false; + pipe_qos_cfg.danger_safe_en = false; } DPU_DEBUG_PLANE(pdpu, "pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n", pdpu->pipe - SSPP_VIG0, - pdpu->pipe_qos_cfg.danger_safe_en, - pdpu->pipe_qos_cfg.vblank_en, - pdpu->pipe_qos_cfg.creq_vblank, - pdpu->pipe_qos_cfg.danger_vblank, + pipe_qos_cfg.danger_safe_en, + pipe_qos_cfg.vblank_en, + pipe_qos_cfg.creq_vblank, + pipe_qos_cfg.danger_vblank, pdpu->is_rt_pipe); pdpu->pipe_hw->ops.setup_qos_ctrl(pdpu->pipe_hw, - &pdpu->pipe_qos_cfg); + &pipe_qos_cfg); } /** * _dpu_plane_set_ot_limit - set OT limit for the given plane * @plane: Pointer to drm plane * @crtc: Pointer to drm crtc + * @pipe_cfg: Pointer to pipe configuration */ static void _dpu_plane_set_ot_limit(struct drm_plane *plane, - struct drm_crtc *crtc) + struct drm_crtc *crtc, struct dpu_hw_pipe_cfg *pipe_cfg) { struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_vbif_set_ot_params ot_params; @@ -476,8 +463,8 @@ static void _dpu_plane_set_ot_limit(struct drm_plane *plane, memset(&ot_params, 0, sizeof(ot_params)); ot_params.xin_id = pdpu->pipe_hw->cap->xin_id; ot_params.num = pdpu->pipe_hw->idx - SSPP_NONE; - ot_params.width = drm_rect_width(&pdpu->pipe_cfg.src_rect); - ot_params.height = drm_rect_height(&pdpu->pipe_cfg.src_rect); + ot_params.width = drm_rect_width(&pipe_cfg->src_rect); + ot_params.height = drm_rect_height(&pipe_cfg->src_rect); ot_params.is_wfd = !pdpu->is_rt_pipe; ot_params.frame_rate = drm_mode_vrefresh(&crtc->mode); ot_params.vbif_idx = VBIF_RT; @@ -541,14 +528,12 @@ static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, struct dpu_plane_state *pstate, uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h, struct dpu_hw_scaler3_cfg *scale_cfg, + struct dpu_hw_pixel_ext *pixel_ext, const struct dpu_format *fmt, uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v) { uint32_t i; - memset(scale_cfg, 0, sizeof(*scale_cfg)); - memset(&pstate->pixel_ext, 0, sizeof(struct dpu_hw_pixel_ext)); - scale_cfg->phase_step_x[DPU_SSPP_COMP_0] = mult_frac((1 << PHASE_STEP_SHIFT), src_w, dst_w); scale_cfg->phase_step_y[DPU_SSPP_COMP_0] = @@ -587,9 +572,9 @@ static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, scale_cfg->preload_y[i] = DPU_QSEED3_DEFAULT_PRELOAD_V; } - pstate->pixel_ext.num_ext_pxls_top[i] = + pixel_ext->num_ext_pxls_top[i] = scale_cfg->src_height[i]; - pstate->pixel_ext.num_ext_pxls_left[i] = + pixel_ext->num_ext_pxls_left[i] = scale_cfg->src_width[i]; } if (!(DPU_FORMAT_IS_YUV(fmt)) && (src_h == dst_h) @@ -606,68 +591,97 @@ static void _dpu_plane_setup_scaler3(struct dpu_plane *pdpu, scale_cfg->enable = 1; } -static void _dpu_plane_setup_csc(struct dpu_plane *pdpu) -{ - static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { - { - /* S15.16 format */ - 0x00012A00, 0x00000000, 0x00019880, - 0x00012A00, 0xFFFF9B80, 0xFFFF3000, - 0x00012A00, 0x00020480, 0x00000000, +static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xfff0, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, + { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, +}; + +static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, }, - /* signed bias */ - { 0xfff0, 0xff80, 0xff80,}, - { 0x0, 0x0, 0x0,}, - /* unsigned clamp */ - { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, - { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, - }; - static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { - { - /* S15.16 format */ - 0x00012A00, 0x00000000, 0x00019880, - 0x00012A00, 0xFFFF9B80, 0xFFFF3000, - 0x00012A00, 0x00020480, 0x00000000, - }, - /* signed bias */ - { 0xffc0, 0xfe00, 0xfe00,}, - { 0x0, 0x0, 0x0,}, - /* unsigned clamp */ - { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, - { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, - }; + /* signed bias */ + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, +}; + +static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_plane *pdpu, const struct dpu_format *fmt) +{ + const struct dpu_csc_cfg *csc_ptr; if (!pdpu) { DPU_ERROR("invalid plane\n"); - return; + return NULL; } - if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->features) - pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc10_YUV2RGB_601L; + if (!DPU_FORMAT_IS_YUV(fmt)) + return NULL; + + if (BIT(DPU_SSPP_CSC_10BIT) & pdpu->pipe_hw->cap->features) + csc_ptr = &dpu_csc10_YUV2RGB_601L; else - pdpu->csc_ptr = (struct dpu_csc_cfg *)&dpu_csc_YUV2RGB_601L; + csc_ptr = &dpu_csc_YUV2RGB_601L; DPU_DEBUG_PLANE(pdpu, "using 0x%X 0x%X 0x%X...\n", - pdpu->csc_ptr->csc_mv[0], - pdpu->csc_ptr->csc_mv[1], - pdpu->csc_ptr->csc_mv[2]); + csc_ptr->csc_mv[0], + csc_ptr->csc_mv[1], + csc_ptr->csc_mv[2]); + + return csc_ptr; } static void _dpu_plane_setup_scaler(struct dpu_plane *pdpu, struct dpu_plane_state *pstate, - const struct dpu_format *fmt, bool color_fill) + const struct dpu_format *fmt, bool color_fill, + struct dpu_hw_pipe_cfg *pipe_cfg) { const struct drm_format_info *info = drm_format_info(fmt->base.pixel_format); + struct dpu_hw_scaler3_cfg scaler3_cfg; + struct dpu_hw_pixel_ext pixel_ext; + + memset(&scaler3_cfg, 0, sizeof(scaler3_cfg)); + memset(&pixel_ext, 0, sizeof(pixel_ext)); /* don't chroma subsample if decimating */ /* update scaler. calculate default config for QSEED3 */ _dpu_plane_setup_scaler3(pdpu, pstate, - drm_rect_width(&pdpu->pipe_cfg.src_rect), - drm_rect_height(&pdpu->pipe_cfg.src_rect), - drm_rect_width(&pdpu->pipe_cfg.dst_rect), - drm_rect_height(&pdpu->pipe_cfg.dst_rect), - &pstate->scaler3_cfg, fmt, + drm_rect_width(&pipe_cfg->src_rect), + drm_rect_height(&pipe_cfg->src_rect), + drm_rect_width(&pipe_cfg->dst_rect), + drm_rect_height(&pipe_cfg->dst_rect), + &scaler3_cfg, &pixel_ext, fmt, info->hsub, info->vsub); + + if (pdpu->pipe_hw->ops.setup_pe) + pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, + &pixel_ext); + + /** + * when programmed in multirect mode, scalar block will be + * bypassed. Still we need to update alpha and bitwidth + * ONLY for RECT0 + */ + if (pdpu->pipe_hw->ops.setup_scaler && + pstate->multirect_index != DPU_SSPP_RECT_1) + pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, + pipe_cfg, + &scaler3_cfg); } /** @@ -683,6 +697,7 @@ static int _dpu_plane_color_fill(struct dpu_plane *pdpu, const struct dpu_format *fmt; const struct drm_plane *plane = &pdpu->base; struct dpu_plane_state *pstate = to_dpu_plane_state(plane->state); + struct dpu_hw_pipe_cfg pipe_cfg; DPU_DEBUG_PLANE(pdpu, "\n"); @@ -699,13 +714,14 @@ static int _dpu_plane_color_fill(struct dpu_plane *pdpu, pstate->multirect_index); /* override scaler/decimation if solid fill */ - pdpu->pipe_cfg.src_rect.x1 = 0; - pdpu->pipe_cfg.src_rect.y1 = 0; - pdpu->pipe_cfg.src_rect.x2 = - drm_rect_width(&pdpu->pipe_cfg.dst_rect); - pdpu->pipe_cfg.src_rect.y2 = - drm_rect_height(&pdpu->pipe_cfg.dst_rect); - _dpu_plane_setup_scaler(pdpu, pstate, fmt, true); + pipe_cfg.dst_rect = pstate->base.dst; + + pipe_cfg.src_rect.x1 = 0; + pipe_cfg.src_rect.y1 = 0; + pipe_cfg.src_rect.x2 = + drm_rect_width(&pipe_cfg.dst_rect); + pipe_cfg.src_rect.y2 = + drm_rect_height(&pipe_cfg.dst_rect); if (pdpu->pipe_hw->ops.setup_format) pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, @@ -714,18 +730,10 @@ static int _dpu_plane_color_fill(struct dpu_plane *pdpu, if (pdpu->pipe_hw->ops.setup_rects) pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, - &pdpu->pipe_cfg, + &pipe_cfg, pstate->multirect_index); - if (pdpu->pipe_hw->ops.setup_pe) - pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, - &pstate->pixel_ext); - - if (pdpu->pipe_hw->ops.setup_scaler && - pstate->multirect_index != DPU_SSPP_RECT_1) - pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, - &pdpu->pipe_cfg, &pstate->pixel_ext, - &pstate->scaler3_cfg); + _dpu_plane_setup_scaler(pdpu, pstate, fmt, true, &pipe_cfg); } return 0; @@ -964,10 +972,10 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); - min_scale = FRAC_16_16(1, pdpu->pipe_sblk->maxupscale); + min_scale = FRAC_16_16(1, pdpu->pipe_hw->cap->sblk->maxupscale); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, min_scale, - pdpu->pipe_sblk->maxdwnscale << 16, + pdpu->pipe_hw->cap->sblk->maxdwnscale << 16, true, true); if (ret) { DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret); @@ -993,9 +1001,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1; if (DPU_FORMAT_IS_YUV(fmt) && - (!(pdpu->features & DPU_SSPP_SCALER) || - !(pdpu->features & (BIT(DPU_SSPP_CSC) - | BIT(DPU_SSPP_CSC_10BIT))))) { + (!(pdpu->pipe_hw->cap->features & DPU_SSPP_SCALER) || + !(pdpu->pipe_hw->cap->features & DPU_SSPP_CSC_ANY))) { DPU_DEBUG_PLANE(pdpu, "plane doesn't have scaler/csc for yuv\n"); return -EINVAL; @@ -1056,8 +1063,13 @@ void dpu_plane_flush(struct drm_plane *plane) else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) /* force 100% alpha */ _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF); - else if (pdpu->pipe_hw && pdpu->csc_ptr && pdpu->pipe_hw->ops.setup_csc) - pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, pdpu->csc_ptr); + else if (pdpu->pipe_hw && pdpu->pipe_hw->ops.setup_csc) { + const struct dpu_format *fmt = to_dpu_format(msm_framebuffer_format(plane->state->fb)); + const struct dpu_csc_cfg *csc_ptr = _dpu_plane_get_csc(pdpu, fmt); + + if (csc_ptr) + pdpu->pipe_hw->ops.setup_csc(pdpu->pipe_hw, csc_ptr); + } /* flag h/w flush complete */ if (plane->state) @@ -1091,10 +1103,11 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) bool is_rt_pipe, update_qos_remap; const struct dpu_format *fmt = to_dpu_format(msm_framebuffer_format(fb)); + struct dpu_hw_pipe_cfg pipe_cfg; - memset(&(pdpu->pipe_cfg), 0, sizeof(struct dpu_hw_pipe_cfg)); + memset(&pipe_cfg, 0, sizeof(struct dpu_hw_pipe_cfg)); - _dpu_plane_set_scanout(plane, pstate, &pdpu->pipe_cfg, fb); + _dpu_plane_set_scanout(plane, pstate, &pipe_cfg, fb); pstate->pending = true; @@ -1106,17 +1119,15 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) crtc->base.id, DRM_RECT_ARG(&state->dst), (char *)&fmt->base.pixel_format, DPU_FORMAT_IS_UBWC(fmt)); - pdpu->pipe_cfg.src_rect = state->src; + pipe_cfg.src_rect = state->src; /* state->src is 16.16, src_rect is not */ - pdpu->pipe_cfg.src_rect.x1 >>= 16; - pdpu->pipe_cfg.src_rect.x2 >>= 16; - pdpu->pipe_cfg.src_rect.y1 >>= 16; - pdpu->pipe_cfg.src_rect.y2 >>= 16; - - pdpu->pipe_cfg.dst_rect = state->dst; + pipe_cfg.src_rect.x1 >>= 16; + pipe_cfg.src_rect.x2 >>= 16; + pipe_cfg.src_rect.y1 >>= 16; + pipe_cfg.src_rect.y2 >>= 16; - _dpu_plane_setup_scaler(pdpu, pstate, fmt, false); + pipe_cfg.dst_rect = state->dst; /* override for color fill */ if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) { @@ -1126,25 +1137,11 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) if (pdpu->pipe_hw->ops.setup_rects) { pdpu->pipe_hw->ops.setup_rects(pdpu->pipe_hw, - &pdpu->pipe_cfg, + &pipe_cfg, pstate->multirect_index); } - if (pdpu->pipe_hw->ops.setup_pe && - (pstate->multirect_index != DPU_SSPP_RECT_1)) - pdpu->pipe_hw->ops.setup_pe(pdpu->pipe_hw, - &pstate->pixel_ext); - - /** - * when programmed in multirect mode, scalar block will be - * bypassed. Still we need to update alpha and bitwidth - * ONLY for RECT0 - */ - if (pdpu->pipe_hw->ops.setup_scaler && - pstate->multirect_index != DPU_SSPP_RECT_1) - pdpu->pipe_hw->ops.setup_scaler(pdpu->pipe_hw, - &pdpu->pipe_cfg, &pstate->pixel_ext, - &pstate->scaler3_cfg); + _dpu_plane_setup_scaler(pdpu, pstate, fmt, false, &pipe_cfg); if (pdpu->pipe_hw->ops.setup_multirect) pdpu->pipe_hw->ops.setup_multirect( @@ -1173,35 +1170,29 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) pstate->multirect_index); if (pdpu->pipe_hw->ops.setup_cdp) { - struct dpu_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg; + struct dpu_hw_pipe_cdp_cfg cdp_cfg; - memset(cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg)); + memset(&cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg)); - cdp_cfg->enable = pdpu->catalog->perf.cdp_cfg + cdp_cfg.enable = pdpu->catalog->perf.cdp_cfg [DPU_PERF_CDP_USAGE_RT].rd_enable; - cdp_cfg->ubwc_meta_enable = + cdp_cfg.ubwc_meta_enable = DPU_FORMAT_IS_UBWC(fmt); - cdp_cfg->tile_amortize_enable = + cdp_cfg.tile_amortize_enable = DPU_FORMAT_IS_UBWC(fmt) || DPU_FORMAT_IS_TILE(fmt); - cdp_cfg->preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64; + cdp_cfg.preload_ahead = DPU_SSPP_CDP_PRELOAD_AHEAD_64; - pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, cdp_cfg); + pdpu->pipe_hw->ops.setup_cdp(pdpu->pipe_hw, &cdp_cfg, pstate->multirect_index); } - - /* update csc */ - if (DPU_FORMAT_IS_YUV(fmt)) - _dpu_plane_setup_csc(pdpu); - else - pdpu->csc_ptr = NULL; } - _dpu_plane_set_qos_lut(plane, fb); + _dpu_plane_set_qos_lut(plane, fb, &pipe_cfg); _dpu_plane_set_danger_lut(plane, fb); if (plane->type != DRM_PLANE_TYPE_CURSOR) { _dpu_plane_set_qos_ctrl(plane, true, DPU_PLANE_QOS_PANIC_CTRL); - _dpu_plane_set_ot_limit(plane, crtc); + _dpu_plane_set_ot_limit(plane, crtc, &pipe_cfg); } update_qos_remap = (is_rt_pipe != pdpu->is_rt_pipe) || @@ -1215,9 +1206,9 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) _dpu_plane_set_qos_remap(plane); } - _dpu_plane_calc_bw(plane, fb); + _dpu_plane_calc_bw(plane, fb, &pipe_cfg); - _dpu_plane_calc_clk(plane); + _dpu_plane_calc_clk(plane, &pipe_cfg); } static void _dpu_plane_atomic_disable(struct drm_plane *plane) @@ -1314,6 +1305,46 @@ dpu_plane_duplicate_state(struct drm_plane *plane) return &pstate->base; } +static const char * const multirect_mode_name[] = { + [DPU_SSPP_MULTIRECT_NONE] = "none", + [DPU_SSPP_MULTIRECT_PARALLEL] = "parallel", + [DPU_SSPP_MULTIRECT_TIME_MX] = "time_mx", +}; + +static const char * const multirect_index_name[] = { + [DPU_SSPP_RECT_SOLO] = "solo", + [DPU_SSPP_RECT_0] = "rect_0", + [DPU_SSPP_RECT_1] = "rect_1", +}; + +static const char *dpu_get_multirect_mode(enum dpu_sspp_multirect_mode mode) +{ + if (WARN_ON(mode >= ARRAY_SIZE(multirect_mode_name))) + return "unknown"; + + return multirect_mode_name[mode]; +} + +static const char *dpu_get_multirect_index(enum dpu_sspp_multirect_index index) +{ + if (WARN_ON(index >= ARRAY_SIZE(multirect_index_name))) + return "unknown"; + + return multirect_index_name[index]; +} + +static void dpu_plane_atomic_print_state(struct drm_printer *p, + const struct drm_plane_state *state) +{ + const struct dpu_plane_state *pstate = to_dpu_plane_state(state); + const struct dpu_plane *pdpu = to_dpu_plane(state->plane); + + drm_printf(p, "\tstage=%d\n", pstate->stage); + drm_printf(p, "\tsspp=%s\n", pdpu->pipe_hw->cap->name); + drm_printf(p, "\tmultirect_mode=%s\n", dpu_get_multirect_mode(pstate->multirect_mode)); + drm_printf(p, "\tmultirect_index=%s\n", dpu_get_multirect_index(pstate->multirect_index)); +} + static void dpu_plane_reset(struct drm_plane *plane) { struct dpu_plane *pdpu; @@ -1343,7 +1374,7 @@ static void dpu_plane_reset(struct drm_plane *plane) } #ifdef CONFIG_DEBUG_FS -static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) +void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) { struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); @@ -1356,167 +1387,23 @@ static void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) pm_runtime_put_sync(&dpu_kms->pdev->dev); } -static ssize_t _dpu_plane_danger_read(struct file *file, - char __user *buff, size_t count, loff_t *ppos) -{ - struct dpu_kms *kms = file->private_data; - int len; - char buf[40]; - - len = scnprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl); - - return simple_read_from_buffer(buff, count, ppos, buf, len); -} - -static void _dpu_plane_set_danger_state(struct dpu_kms *kms, bool enable) +/* SSPP live inside dpu_plane private data only. Enumerate them here. */ +void dpu_debugfs_sspp_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root) { struct drm_plane *plane; + struct dentry *entry = debugfs_create_dir("sspp", debugfs_root); - drm_for_each_plane(plane, kms->dev) { - if (plane->fb && plane->state) { - dpu_plane_danger_signal_ctrl(plane, enable); - DPU_DEBUG("plane:%d img:%dx%d ", - plane->base.id, plane->fb->width, - plane->fb->height); - DPU_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n", - plane->state->src_x >> 16, - plane->state->src_y >> 16, - plane->state->src_w >> 16, - plane->state->src_h >> 16, - plane->state->crtc_x, plane->state->crtc_y, - plane->state->crtc_w, plane->state->crtc_h); - } else { - DPU_DEBUG("Inactive plane:%d\n", plane->base.id); - } - } -} - -static ssize_t _dpu_plane_danger_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct dpu_kms *kms = file->private_data; - int disable_panic; - int ret; - - ret = kstrtouint_from_user(user_buf, count, 0, &disable_panic); - if (ret) - return ret; - - if (disable_panic) { - /* Disable panic signal for all active pipes */ - DPU_DEBUG("Disabling danger:\n"); - _dpu_plane_set_danger_state(kms, false); - kms->has_danger_ctrl = false; - } else { - /* Enable panic signal for all active pipes */ - DPU_DEBUG("Enabling danger:\n"); - kms->has_danger_ctrl = true; - _dpu_plane_set_danger_state(kms, true); - } - - return count; -} + if (IS_ERR(entry)) + return; -static const struct file_operations dpu_plane_danger_enable = { - .open = simple_open, - .read = _dpu_plane_danger_read, - .write = _dpu_plane_danger_write, -}; + drm_for_each_plane(plane, dpu_kms->dev) { + struct dpu_plane *pdpu = to_dpu_plane(plane); -static int _dpu_plane_init_debugfs(struct drm_plane *plane) -{ - struct dpu_plane *pdpu = to_dpu_plane(plane); - struct dpu_kms *kms = _dpu_plane_get_kms(plane); - const struct dpu_sspp_cfg *cfg = pdpu->pipe_hw->cap; - const struct dpu_sspp_sub_blks *sblk = cfg->sblk; - - /* create overall sub-directory for the pipe */ - pdpu->debugfs_root = - debugfs_create_dir(pdpu->pipe_name, - plane->dev->primary->debugfs_root); - - /* don't error check these */ - debugfs_create_x32("features", 0600, - pdpu->debugfs_root, &pdpu->features); - - /* add register dump support */ - dpu_debugfs_setup_regset32(&pdpu->debugfs_src, - sblk->src_blk.base + cfg->base, - sblk->src_blk.len, - kms); - dpu_debugfs_create_regset32("src_blk", 0400, - pdpu->debugfs_root, &pdpu->debugfs_src); - - if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED3LITE) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED2) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED4)) { - dpu_debugfs_setup_regset32(&pdpu->debugfs_scaler, - sblk->scaler_blk.base + cfg->base, - sblk->scaler_blk.len, - kms); - dpu_debugfs_create_regset32("scaler_blk", 0400, - pdpu->debugfs_root, - &pdpu->debugfs_scaler); - debugfs_create_bool("default_scaling", - 0600, - pdpu->debugfs_root, - &pdpu->debugfs_default_scale); - } - - if (cfg->features & BIT(DPU_SSPP_CSC) || - cfg->features & BIT(DPU_SSPP_CSC_10BIT)) { - dpu_debugfs_setup_regset32(&pdpu->debugfs_csc, - sblk->csc_blk.base + cfg->base, - sblk->csc_blk.len, - kms); - dpu_debugfs_create_regset32("csc_blk", 0400, - pdpu->debugfs_root, &pdpu->debugfs_csc); + _dpu_hw_sspp_init_debugfs(pdpu->pipe_hw, dpu_kms, entry); } - - debugfs_create_u32("xin_id", - 0400, - pdpu->debugfs_root, - (u32 *) &cfg->xin_id); - debugfs_create_u32("clk_ctrl", - 0400, - pdpu->debugfs_root, - (u32 *) &cfg->clk_ctrl); - debugfs_create_x32("creq_vblank", - 0600, - pdpu->debugfs_root, - (u32 *) &sblk->creq_vblank); - debugfs_create_x32("danger_vblank", - 0600, - pdpu->debugfs_root, - (u32 *) &sblk->danger_vblank); - - debugfs_create_file("disable_danger", - 0600, - pdpu->debugfs_root, - kms, &dpu_plane_danger_enable); - - return 0; -} -#else -static int _dpu_plane_init_debugfs(struct drm_plane *plane) -{ - return 0; } #endif -static int dpu_plane_late_register(struct drm_plane *plane) -{ - return _dpu_plane_init_debugfs(plane); -} - -static void dpu_plane_early_unregister(struct drm_plane *plane) -{ - struct dpu_plane *pdpu = to_dpu_plane(plane); - - debugfs_remove_recursive(pdpu->debugfs_root); -} - static bool dpu_plane_format_mod_supported(struct drm_plane *plane, uint32_t format, uint64_t modifier) { @@ -1541,8 +1428,7 @@ static const struct drm_plane_funcs dpu_plane_funcs = { .reset = dpu_plane_reset, .atomic_duplicate_state = dpu_plane_duplicate_state, .atomic_destroy_state = dpu_plane_destroy_state, - .late_register = dpu_plane_late_register, - .early_unregister = dpu_plane_early_unregister, + .atomic_print_state = dpu_plane_atomic_print_state, .format_mod_supported = dpu_plane_format_mod_supported, }; @@ -1609,21 +1495,13 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, goto clean_sspp; } - /* cache features mask for later */ - pdpu->features = pdpu->pipe_hw->cap->features; - pdpu->pipe_sblk = pdpu->pipe_hw->cap->sblk; - if (!pdpu->pipe_sblk) { - DPU_ERROR("[%u]invalid sblk\n", pipe); - goto clean_sspp; - } - if (pdpu->is_virtual) { - format_list = pdpu->pipe_sblk->virt_format_list; - num_formats = pdpu->pipe_sblk->virt_num_formats; + format_list = pdpu->pipe_hw->cap->sblk->virt_format_list; + num_formats = pdpu->pipe_hw->cap->sblk->virt_num_formats; } else { - format_list = pdpu->pipe_sblk->format_list; - num_formats = pdpu->pipe_sblk->num_formats; + format_list = pdpu->pipe_hw->cap->sblk->format_list; + num_formats = pdpu->pipe_hw->cap->sblk->num_formats; } ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, @@ -1663,12 +1541,9 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, /* success! finalize initialization */ drm_plane_helper_add(plane, &dpu_plane_helper_funcs); - /* save user friendly pipe name for later */ - snprintf(pdpu->pipe_name, DPU_NAME_SIZE, "plane%u", plane->base.id); - mutex_init(&pdpu->lock); - DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", pdpu->pipe_name, + DPU_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", plane->name, pipe, plane->base.id, master_plane_id); return plane; @@ -1676,6 +1551,7 @@ clean_sspp: if (pdpu && pdpu->pipe_hw) dpu_hw_sspp_destroy(pdpu->pipe_hw); clean_plane: + list_del(&pdpu->mplane_list); kfree(pdpu); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index 34e03ac05f4a..9d51dad5c6a5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -23,9 +23,6 @@ * @multirect_index: index of the rectangle of SSPP * @multirect_mode: parallel or time multiplex multirect mode * @pending: whether the current update is still pending - * @scaler3_cfg: configuration data for scaler3 - * @pixel_ext: configuration data for pixel extensions - * @cdp_cfg: CDP configuration * @plane_fetch_bw: calculated BW per plane * @plane_clk: calculated clk per plane */ @@ -38,11 +35,6 @@ struct dpu_plane_state { uint32_t multirect_mode; bool pending; - /* scaler configuration */ - struct dpu_hw_scaler3_cfg scaler3_cfg; - struct dpu_hw_pixel_ext pixel_ext; - - struct dpu_hw_pipe_cdp_cfg cdp_cfg; u64 plane_fetch_bw; u64 plane_clk; }; @@ -134,4 +126,10 @@ void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state); int dpu_plane_color_fill(struct drm_plane *plane, uint32_t color, uint32_t alpha); +#ifdef CONFIG_DEBUG_FS +void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable); +#else +static inline void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) {} +#endif + #endif /* _DPU_PLANE_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 37bba57675a8..54d74341e690 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -266,10 +266,6 @@ DEFINE_EVENT(dpu_drm_obj_template, dpu_crtc_complete_commit, TP_PROTO(uint32_t drm_id), TP_ARGS(drm_id) ); -DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_enc_enable, - TP_PROTO(uint32_t drm_id), - TP_ARGS(drm_id) -); DEFINE_EVENT(dpu_drm_obj_template, dpu_kms_commit, TP_PROTO(uint32_t drm_id), TP_ARGS(drm_id) diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 7b242246d4e7..12a5f81e402b 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -370,22 +370,7 @@ static int modeset_init_intf(struct mdp5_kms *mdp5_kms, switch (intf->type) { case INTF_eDP: - if (!priv->edp) - break; - - ctl = mdp5_ctlm_request(ctlm, intf->num); - if (!ctl) { - ret = -EINVAL; - break; - } - - encoder = construct_encoder(mdp5_kms, intf, ctl); - if (IS_ERR(encoder)) { - ret = PTR_ERR(encoder); - break; - } - - ret = msm_edp_modeset_init(priv->edp, dev, encoder); + DRM_DEV_INFO(dev->dev, "Skipping eDP interface %d\n", intf->num); break; case INTF_HDMI: if (!priv->hdmi) @@ -936,7 +921,8 @@ fail: static int mdp5_bind(struct device *dev, struct device *master, void *data) { - struct drm_device *ddev = dev_get_drvdata(master); + struct msm_drm_private *priv = dev_get_drvdata(master); + struct drm_device *ddev = priv->dev; struct platform_device *pdev = to_platform_device(dev); DBG(""); @@ -1031,7 +1017,7 @@ static const struct dev_pm_ops mdp5_pm_ops = { SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL) }; -static const struct of_device_id mdp5_dt_match[] = { +const struct of_device_id mdp5_dt_match[] = { { .compatible = "qcom,mdp5", }, /* to support downstream DT files */ { .compatible = "qcom,mdss_mdp", }, diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c index 0ea53420bc40..b3f79c2277e9 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mdss.c @@ -16,8 +16,6 @@ struct mdp5_mdss { void __iomem *mmio, *vbif; - struct regulator *vdd; - struct clk *ahb_clk; struct clk *axi_clk; struct clk *vsync_clk; @@ -114,7 +112,7 @@ static const struct irq_domain_ops mdss_hw_irqdomain_ops = { static int mdss_irq_domain_init(struct mdp5_mdss *mdp5_mdss) { - struct device *dev = mdp5_mdss->base.dev->dev; + struct device *dev = mdp5_mdss->base.dev; struct irq_domain *d; d = irq_domain_add_linear(dev->of_node, 32, &mdss_hw_irqdomain_ops, @@ -157,7 +155,7 @@ static int mdp5_mdss_disable(struct msm_mdss *mdss) static int msm_mdss_get_clocks(struct mdp5_mdss *mdp5_mdss) { struct platform_device *pdev = - to_platform_device(mdp5_mdss->base.dev->dev); + to_platform_device(mdp5_mdss->base.dev); mdp5_mdss->ahb_clk = msm_clk_get(pdev, "iface"); if (IS_ERR(mdp5_mdss->ahb_clk)) @@ -174,10 +172,9 @@ static int msm_mdss_get_clocks(struct mdp5_mdss *mdp5_mdss) return 0; } -static void mdp5_mdss_destroy(struct drm_device *dev) +static void mdp5_mdss_destroy(struct msm_mdss *mdss) { - struct msm_drm_private *priv = dev->dev_private; - struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(priv->mdss); + struct mdp5_mdss *mdp5_mdss = to_mdp5_mdss(mdss); if (!mdp5_mdss) return; @@ -185,9 +182,7 @@ static void mdp5_mdss_destroy(struct drm_device *dev) irq_domain_remove(mdp5_mdss->irqcontroller.domain); mdp5_mdss->irqcontroller.domain = NULL; - regulator_disable(mdp5_mdss->vdd); - - pm_runtime_disable(dev->dev); + pm_runtime_disable(mdss->dev); } static const struct msm_mdss_funcs mdss_funcs = { @@ -196,25 +191,24 @@ static const struct msm_mdss_funcs mdss_funcs = { .destroy = mdp5_mdss_destroy, }; -int mdp5_mdss_init(struct drm_device *dev) +int mdp5_mdss_init(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev->dev); - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = platform_get_drvdata(pdev); struct mdp5_mdss *mdp5_mdss; int ret; DBG(""); - if (!of_device_is_compatible(dev->dev->of_node, "qcom,mdss")) + if (!of_device_is_compatible(pdev->dev.of_node, "qcom,mdss")) return 0; - mdp5_mdss = devm_kzalloc(dev->dev, sizeof(*mdp5_mdss), GFP_KERNEL); + mdp5_mdss = devm_kzalloc(&pdev->dev, sizeof(*mdp5_mdss), GFP_KERNEL); if (!mdp5_mdss) { ret = -ENOMEM; goto fail; } - mdp5_mdss->base.dev = dev; + mdp5_mdss->base.dev = &pdev->dev; mdp5_mdss->mmio = msm_ioremap(pdev, "mdss_phys", "MDSS"); if (IS_ERR(mdp5_mdss->mmio)) { @@ -230,45 +224,29 @@ int mdp5_mdss_init(struct drm_device *dev) ret = msm_mdss_get_clocks(mdp5_mdss); if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to get clocks: %d\n", ret); - goto fail; - } - - /* Regulator to enable GDSCs in downstream kernels */ - mdp5_mdss->vdd = devm_regulator_get(dev->dev, "vdd"); - if (IS_ERR(mdp5_mdss->vdd)) { - ret = PTR_ERR(mdp5_mdss->vdd); - goto fail; - } - - ret = regulator_enable(mdp5_mdss->vdd); - if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to enable regulator vdd: %d\n", - ret); + DRM_DEV_ERROR(&pdev->dev, "failed to get clocks: %d\n", ret); goto fail; } - ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0), + ret = devm_request_irq(&pdev->dev, platform_get_irq(pdev, 0), mdss_irq, 0, "mdss_isr", mdp5_mdss); if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to init irq: %d\n", ret); - goto fail_irq; + DRM_DEV_ERROR(&pdev->dev, "failed to init irq: %d\n", ret); + goto fail; } ret = mdss_irq_domain_init(mdp5_mdss); if (ret) { - DRM_DEV_ERROR(dev->dev, "failed to init sub-block irqs: %d\n", ret); - goto fail_irq; + DRM_DEV_ERROR(&pdev->dev, "failed to init sub-block irqs: %d\n", ret); + goto fail; } mdp5_mdss->base.funcs = &mdss_funcs; priv->mdss = &mdp5_mdss->base; - pm_runtime_enable(dev->dev); + pm_runtime_enable(&pdev->dev); return 0; -fail_irq: - regulator_disable(mdp5_mdss->vdd); fail: return ret; } diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c index a4a7cb06bc87..e75b97127c0d 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c @@ -28,29 +28,42 @@ static ssize_t __maybe_unused disp_devcoredump_read(char *buffer, loff_t offset, return count - iter.remain; } -static void _msm_disp_snapshot_work(struct kthread_work *work) +struct msm_disp_state * +msm_disp_snapshot_state_sync(struct msm_kms *kms) { - struct msm_kms *kms = container_of(work, struct msm_kms, dump_work); struct drm_device *drm_dev = kms->dev; struct msm_disp_state *disp_state; - struct drm_printer p; + + WARN_ON(!mutex_is_locked(&kms->dump_mutex)); disp_state = kzalloc(sizeof(struct msm_disp_state), GFP_KERNEL); if (!disp_state) - return; + return ERR_PTR(-ENOMEM); disp_state->dev = drm_dev->dev; disp_state->drm_dev = drm_dev; INIT_LIST_HEAD(&disp_state->blocks); - /* Serialize dumping here */ - mutex_lock(&kms->dump_mutex); - msm_disp_snapshot_capture_state(disp_state); + return disp_state; +} + +static void _msm_disp_snapshot_work(struct kthread_work *work) +{ + struct msm_kms *kms = container_of(work, struct msm_kms, dump_work); + struct msm_disp_state *disp_state; + struct drm_printer p; + + /* Serialize dumping here */ + mutex_lock(&kms->dump_mutex); + disp_state = msm_disp_snapshot_state_sync(kms); mutex_unlock(&kms->dump_mutex); + if (IS_ERR(disp_state)) + return; + if (MSM_DISP_SNAPSHOT_DUMP_IN_CONSOLE) { p = drm_info_printer(disp_state->drm_dev->dev); msm_disp_state_print(disp_state, &p); diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h index 4c619307612c..b5f452bd7ada 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.h @@ -39,7 +39,7 @@ * @dev: device pointer * @drm_dev: drm device pointer * @atomic_state: atomic state duplicated at the time of the error - * @timestamp: timestamp at which the coredump was captured + * @time: timestamp at which the coredump was captured */ struct msm_disp_state { struct device *dev; @@ -49,7 +49,7 @@ struct msm_disp_state { struct drm_atomic_state *atomic_state; - ktime_t timestamp; + struct timespec64 time; }; /** @@ -85,6 +85,16 @@ int msm_disp_snapshot_init(struct drm_device *drm_dev); void msm_disp_snapshot_destroy(struct drm_device *drm_dev); /** + * msm_disp_snapshot_state_sync - synchronously snapshot display state + * @kms: the kms object + * + * Returns state or error + * + * Must be called with &kms->dump_mutex held + */ +struct msm_disp_state *msm_disp_snapshot_state_sync(struct msm_kms *kms); + +/** * msm_disp_snapshot_state - trigger to dump the display snapshot * @drm_dev: handle to drm device diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index 2e1acb1bc390..5d2ff6791058 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -5,6 +5,8 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <generated/utsrelease.h> + #include "msm_disp_snapshot.h" static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *base_addr) @@ -79,10 +81,11 @@ void msm_disp_state_print(struct msm_disp_state *state, struct drm_printer *p) } drm_printf(p, "---\n"); - + drm_printf(p, "kernel: " UTS_RELEASE "\n"); drm_printf(p, "module: " KBUILD_MODNAME "\n"); drm_printf(p, "dpu devcoredump\n"); - drm_printf(p, "timestamp %lld\n", ktime_to_ns(state->timestamp)); + drm_printf(p, "time: %lld.%09ld\n", + state->time.tv_sec, state->time.tv_nsec); list_for_each_entry_safe(block, tmp, &state->blocks, node) { drm_printf(p, "====================%s================\n", block->name); @@ -100,7 +103,7 @@ static void msm_disp_capture_atomic_state(struct msm_disp_state *disp_state) struct drm_device *ddev; struct drm_modeset_acquire_ctx ctx; - disp_state->timestamp = ktime_get(); + ktime_get_real_ts64(&disp_state->time); ddev = disp_state->drm_dev; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 62e75dc8afc6..c724cb0bde9d 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -119,13 +119,13 @@ void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) { u32 config = 0, tbd; - u8 *dpcd = ctrl->panel->dpcd; + const u8 *dpcd = ctrl->panel->dpcd; /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT); /* Scrambler reset enable */ - if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) + if (drm_dp_alternate_scrambler_reset_cap(dpcd)) config |= DP_CONFIGURATION_CTRL_ASSR; tbd = dp_link_get_test_bits_depth(ctrl->link, @@ -1228,7 +1228,10 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, int *training_step) { int ret = 0; + const u8 *dpcd = ctrl->panel->dpcd; u8 encoding = DP_SET_ANSI_8B10B; + u8 ssc; + u8 assr; struct dp_link_info link_info = {0}; dp_ctrl_config_ctrl(ctrl); @@ -1238,9 +1241,21 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING; dp_aux_link_configure(ctrl->aux, &link_info); + + if (drm_dp_max_downspread(dpcd)) { + ssc = DP_SPREAD_AMP_0_5; + drm_dp_dpcd_write(ctrl->aux, DP_DOWNSPREAD_CTRL, &ssc, 1); + } + drm_dp_dpcd_write(ctrl->aux, DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1); + if (drm_dp_alternate_scrambler_reset_cap(dpcd)) { + assr = DP_ALTERNATE_SCRAMBLER_RESET_ENABLE; + drm_dp_dpcd_write(ctrl->aux, DP_EDP_CONFIGURATION_SET, + &assr, 1); + } + ret = dp_ctrl_link_train_1(ctrl, training_step); if (ret) { DRM_ERROR("link training #1 failed. ret=%d\n", ret); @@ -1312,9 +1327,11 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) struct dp_io *dp_io = &ctrl->parser->io; struct phy *phy = dp_io->phy; struct phy_configure_opts_dp *opts_dp = &dp_io->phy_opts.dp; + const u8 *dpcd = ctrl->panel->dpcd; opts_dp->lanes = ctrl->link->link_params.num_lanes; opts_dp->link_rate = ctrl->link->link_params.rate / 100; + opts_dp->ssc = drm_dp_max_downspread(dpcd); dp_ctrl_set_clock_rate(ctrl, DP_CTRL_PM, "ctrl_link", ctrl->link->link_params.rate * 1000); @@ -1406,7 +1423,7 @@ void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) { - u8 *dpcd = ctrl->panel->dpcd; + const u8 *dpcd = ctrl->panel->dpcd; /* * For better interop experience, used a fixed NVID=0x8000 diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index aba8aa47ed76..7cc4d21f2091 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -135,8 +135,18 @@ static const struct msm_dp_config sc7180_dp_cfg = { .num_descs = 1, }; +static const struct msm_dp_config sc7280_dp_cfg = { + .descs = (const struct msm_dp_desc[]) { + [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort }, + [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP }, + }, + .num_descs = 2, +}; + static const struct of_device_id dp_dt_match[] = { { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg }, + { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_cfg }, + { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_cfg }, {} }; @@ -224,13 +234,10 @@ static int dp_display_bind(struct device *dev, struct device *master, { int rc = 0; struct dp_display_private *dp = dev_get_dp_display_private(dev); - struct msm_drm_private *priv; - struct drm_device *drm; - - drm = dev_get_drvdata(master); + struct msm_drm_private *priv = dev_get_drvdata(master); + struct drm_device *drm = priv->dev; dp->dp_display.drm_dev = drm; - priv = drm->dev_private; priv->dp[dp->id] = &dp->dp_display; rc = dp->parser->parse(dp->parser, dp->dp_display.connector_type); @@ -266,8 +273,7 @@ static void dp_display_unbind(struct device *dev, struct device *master, void *data) { struct dp_display_private *dp = dev_get_dp_display_private(dev); - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); dp_power_client_deinit(dp->power); dp_aux_unregister(dp->aux); @@ -410,12 +416,11 @@ static int dp_display_usbpd_configure_cb(struct device *dev) static int dp_display_usbpd_disconnect_cb(struct device *dev) { - int rc = 0; struct dp_display_private *dp = dev_get_dp_display_private(dev); dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); - return rc; + return 0; } static void dp_display_handle_video_request(struct dp_display_private *dp) @@ -522,11 +527,8 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) dp->hpd_state = ST_CONNECT_PENDING; - hpd->hpd_high = 1; - ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); if (ret) { /* link train failed */ - hpd->hpd_high = 0; dp->hpd_state = ST_DISCONNECTED; if (ret == -ECONNRESET) { /* cable unplugged */ @@ -603,7 +605,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) /* triggered by irq_hdp with sink_count = 0 */ if (dp->link->sink_count == 0) { dp_ctrl_off_phy(dp->ctrl); - hpd->hpd_high = 0; dp->core_initialized = false; } mutex_unlock(&dp->event_mutex); @@ -627,8 +628,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) /* disable HPD plug interrupts */ dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false); - hpd->hpd_high = 0; - /* * We don't need separate work for disconnect as * connect/attention interrupts are disabled @@ -693,9 +692,15 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) return 0; } - ret = dp_display_usbpd_attention_cb(&dp->pdev->dev); - if (ret == -ECONNRESET) { /* cable unplugged */ - dp->core_initialized = false; + /* + * dp core (ahb/aux clks) must be initialized before + * irq_hpd be handled + */ + if (dp->core_initialized) { + ret = dp_display_usbpd_attention_cb(&dp->pdev->dev); + if (ret == -ECONNRESET) { /* cable unplugged */ + dp->core_initialized = false; + } } DRM_DEBUG_DP("hpd_state=%d\n", state); @@ -707,9 +712,9 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) static void dp_display_deinit_sub_modules(struct dp_display_private *dp) { dp_debug_put(dp->debug); + dp_audio_put(dp->audio); dp_panel_put(dp->panel); dp_aux_put(dp->aux); - dp_audio_put(dp->audio); } static int dp_init_sub_modules(struct dp_display_private *dp) @@ -1481,6 +1486,18 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, } priv->connectors[priv->num_connectors++] = dp_display->connector; + + dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder); + if (IS_ERR(dp_display->bridge)) { + ret = PTR_ERR(dp_display->bridge); + DRM_DEV_ERROR(dev->dev, + "failed to create dp bridge: %d\n", ret); + dp_display->bridge = NULL; + return ret; + } + + priv->bridges[priv->num_bridges++] = dp_display->bridge; + return 0; } @@ -1584,8 +1601,8 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) } void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { struct dp_display_private *dp_display; diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 8e80e3bac394..e3adcd578a90 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -13,6 +13,7 @@ struct msm_dp { struct drm_device *drm_dev; struct device *codec_dev; + struct drm_bridge *bridge; struct drm_connector *connector; struct drm_encoder *encoder; struct drm_bridge *panel_bridge; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 76856c4ee1d6..d4d360d19eba 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -12,6 +12,14 @@ #include "msm_kms.h" #include "dp_drm.h" + +struct msm_dp_bridge { + struct drm_bridge bridge; + struct msm_dp *dp_display; +}; + +#define to_dp_display(x) container_of((x), struct msm_dp_bridge, bridge) + struct dp_connector { struct drm_connector base; struct msm_dp *dp_display; @@ -173,3 +181,70 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display) return connector; } + +static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_mode_set(dp_display, drm_bridge->encoder, mode, adjusted_mode); +} + +static void dp_bridge_enable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_enable(dp_display, drm_bridge->encoder); +} + +static void dp_bridge_disable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_pre_disable(dp_display, drm_bridge->encoder); +} + +static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) +{ + struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); + struct msm_dp *dp_display = dp_bridge->dp_display; + + msm_dp_display_disable(dp_display, drm_bridge->encoder); +} + +static const struct drm_bridge_funcs dp_bridge_ops = { + .enable = dp_bridge_enable, + .disable = dp_bridge_disable, + .post_disable = dp_bridge_post_disable, + .mode_set = dp_bridge_mode_set, +}; + +struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, + struct drm_encoder *encoder) +{ + int rc; + struct msm_dp_bridge *dp_bridge; + struct drm_bridge *bridge; + + dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL); + if (!dp_bridge) + return ERR_PTR(-ENOMEM); + + dp_bridge->dp_display = dp_display; + + bridge = &dp_bridge->bridge; + bridge->funcs = &dp_bridge_ops; + bridge->encoder = encoder; + + rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (rc) { + DRM_ERROR("failed to attach bridge, rc=%d\n", rc); + return ERR_PTR(rc); + } + + return bridge; +} diff --git a/drivers/gpu/drm/msm/dp/dp_hpd.c b/drivers/gpu/drm/msm/dp/dp_hpd.c index e1c90fa47411..db98a1d431eb 100644 --- a/drivers/gpu/drm/msm/dp/dp_hpd.c +++ b/drivers/gpu/drm/msm/dp/dp_hpd.c @@ -32,8 +32,6 @@ int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd) hpd_priv = container_of(dp_usbpd, struct dp_hpd_private, dp_usbpd); - dp_usbpd->hpd_high = hpd; - if (!hpd_priv->dp_cb || !hpd_priv->dp_cb->configure || !hpd_priv->dp_cb->disconnect) { pr_err("hpd dp_cb not initialized\n"); diff --git a/drivers/gpu/drm/msm/dp/dp_hpd.h b/drivers/gpu/drm/msm/dp/dp_hpd.h index 5bc5bb64680f..8feec5aa5027 100644 --- a/drivers/gpu/drm/msm/dp/dp_hpd.h +++ b/drivers/gpu/drm/msm/dp/dp_hpd.h @@ -26,7 +26,6 @@ enum plug_orientation { * @multi_func: multi-function preferred * @usb_config_req: request to switch to usb * @exit_dp_mode: request exit from displayport mode - * @hpd_high: Hot Plug Detect signal is high. * @hpd_irq: Change in the status since last message * @alt_mode_cfg_done: bool to specify alt mode status * @debug_en: bool to specify debug mode @@ -39,7 +38,6 @@ struct dp_usbpd { bool multi_func; bool usb_config_req; bool exit_dp_mode; - bool hpd_high; bool hpd_irq; bool alt_mode_cfg_done; bool debug_en; diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index a5bdfc5029de..d4d31e5bda07 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -737,18 +737,25 @@ static int dp_link_parse_sink_count(struct dp_link *dp_link) return 0; } -static void dp_link_parse_sink_status_field(struct dp_link_private *link) +static int dp_link_parse_sink_status_field(struct dp_link_private *link) { int len = 0; link->prev_sink_count = link->dp_link.sink_count; - dp_link_parse_sink_count(&link->dp_link); + len = dp_link_parse_sink_count(&link->dp_link); + if (len < 0) { + DRM_ERROR("DP parse sink count failed\n"); + return len; + } len = drm_dp_dpcd_read_link_status(link->aux, link->link_status); - if (len < DP_LINK_STATUS_SIZE) + if (len < DP_LINK_STATUS_SIZE) { DRM_ERROR("DP link status read failed\n"); - dp_link_parse_request(link); + return len; + } + + return dp_link_parse_request(link); } /** @@ -1023,7 +1030,9 @@ int dp_link_process_request(struct dp_link *dp_link) dp_link_reset_data(link); - dp_link_parse_sink_status_field(link); + ret = dp_link_parse_sink_status_field(link); + if (ret) + return ret; if (link->request.test_requested == DP_TEST_LINK_EDID_READ) { dp_link->sink_request |= DP_TEST_LINK_EDID_READ; diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index 5cd230a5d5d3..052548883d27 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -110,8 +110,7 @@ destroy_dsi: static int dsi_bind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); struct msm_dsi *msm_dsi = dev_get_drvdata(dev); priv->dsi[msm_dsi->id] = msm_dsi; @@ -122,8 +121,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) static void dsi_unbind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); struct msm_dsi *msm_dsi = dev_get_drvdata(dev); priv->dsi[msm_dsi->id] = NULL; @@ -225,9 +223,13 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, goto fail; } - if (!msm_dsi_manager_validate_current_config(msm_dsi->id)) { - ret = -EINVAL; - goto fail; + if (msm_dsi_is_bonded_dsi(msm_dsi) && + !msm_dsi_is_master_dsi(msm_dsi)) { + /* + * Do not return an eror here, + * Just skip creating encoder/connector for the slave-DSI. + */ + return 0; } msm_dsi->encoder = encoder; diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index bb39e7ca802d..c8dedc95428c 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -82,7 +82,6 @@ int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len); int msm_dsi_manager_register(struct msm_dsi *msm_dsi); void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); -bool msm_dsi_manager_validate_current_config(u8 id); void msm_dsi_manager_tpg_enable(void); /* msm dsi */ @@ -120,6 +119,8 @@ unsigned long msm_dsi_host_get_mode_flags(struct mipi_dsi_host *host); struct drm_bridge *msm_dsi_host_get_bridge(struct mipi_dsi_host *host); int msm_dsi_host_register(struct mipi_dsi_host *host); void msm_dsi_host_unregister(struct mipi_dsi_host *host); +void msm_dsi_host_set_phy_mode(struct mipi_dsi_host *host, + struct msm_dsi_phy *src_phy); int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, struct msm_dsi_phy *src_phy); void msm_dsi_host_reset_phy(struct mipi_dsi_host *host); @@ -173,8 +174,6 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, void msm_dsi_phy_disable(struct msm_dsi_phy *phy); void msm_dsi_phy_set_usecase(struct msm_dsi_phy *phy, enum msm_dsi_phy_usecase uc); -int msm_dsi_phy_get_clk_provider(struct msm_dsi_phy *phy, - struct clk **byte_clk_provider, struct clk **pixel_clk_provider); void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy); int msm_dsi_phy_pll_restore_state(struct msm_dsi_phy *phy); void msm_dsi_phy_snapshot(struct msm_disp_state *disp_state, struct msm_dsi_phy *phy); diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index a6893cc45fe4..6b3ced4aaaf5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -2020,7 +2020,7 @@ void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host, /* TODO: unvote for bus bandwidth */ cfg_hnd->ops->link_clk_disable(msm_host); - pm_runtime_put_autosuspend(&msm_host->pdev->dev); + pm_runtime_put(&msm_host->pdev->dev); } int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, @@ -2179,57 +2179,12 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 dma_base, wmb(); } -int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, +void msm_dsi_host_set_phy_mode(struct mipi_dsi_host *host, struct msm_dsi_phy *src_phy) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); - struct clk *byte_clk_provider, *pixel_clk_provider; - int ret; msm_host->cphy_mode = src_phy->cphy_mode; - - ret = msm_dsi_phy_get_clk_provider(src_phy, - &byte_clk_provider, &pixel_clk_provider); - if (ret) { - pr_info("%s: can't get provider from pll, don't set parent\n", - __func__); - return 0; - } - - ret = clk_set_parent(msm_host->byte_clk_src, byte_clk_provider); - if (ret) { - pr_err("%s: can't set parent to byte_clk_src. ret=%d\n", - __func__, ret); - goto exit; - } - - ret = clk_set_parent(msm_host->pixel_clk_src, pixel_clk_provider); - if (ret) { - pr_err("%s: can't set parent to pixel_clk_src. ret=%d\n", - __func__, ret); - goto exit; - } - - if (msm_host->dsi_clk_src) { - ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider); - if (ret) { - pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n", - __func__, ret); - goto exit; - } - } - - if (msm_host->esc_clk_src) { - ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider); - if (ret) { - pr_err("%s: can't set parent to esc_clk_src. ret=%d\n", - __func__, ret); - goto exit; - } - } - -exit: - return ret; } void msm_dsi_host_reset_phy(struct mipi_dsi_host *host) @@ -2297,7 +2252,7 @@ int msm_dsi_host_enable(struct mipi_dsi_host *host) */ /* if (msm_panel->mode == MSM_DSI_CMD_MODE) { * dsi_link_clk_disable(msm_host); - * pm_runtime_put_autosuspend(&msm_host->pdev->dev); + * pm_runtime_put(&msm_host->pdev->dev); * } */ msm_host->enabled = true; @@ -2389,7 +2344,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, fail_disable_clk: cfg_hnd->ops->link_clk_disable(msm_host); - pm_runtime_put_autosuspend(&msm_host->pdev->dev); + pm_runtime_put(&msm_host->pdev->dev); fail_disable_reg: dsi_host_regulator_disable(msm_host); unlock_ret: @@ -2416,7 +2371,7 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host) pinctrl_pm_select_sleep_state(&msm_host->pdev->dev); cfg_hnd->ops->link_clk_disable(msm_host); - pm_runtime_put_autosuspend(&msm_host->pdev->dev); + pm_runtime_put(&msm_host->pdev->dev); dsi_host_regulator_disable(msm_host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 01bf8d907933..f19bae475c96 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -79,10 +79,8 @@ static int dsi_mgr_setup_components(int id) return ret; msm_dsi_phy_set_usecase(msm_dsi->phy, MSM_DSI_PHY_STANDALONE); - ret = msm_dsi_host_set_src_pll(msm_dsi->host, msm_dsi->phy); - } else if (!other_dsi) { - ret = 0; - } else { + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); + } else if (other_dsi) { struct msm_dsi *master_link_dsi = IS_MASTER_DSI_LINK(id) ? msm_dsi : other_dsi; struct msm_dsi *slave_link_dsi = IS_MASTER_DSI_LINK(id) ? @@ -106,13 +104,11 @@ static int dsi_mgr_setup_components(int id) MSM_DSI_PHY_MASTER); msm_dsi_phy_set_usecase(clk_slave_dsi->phy, MSM_DSI_PHY_SLAVE); - ret = msm_dsi_host_set_src_pll(msm_dsi->host, clk_master_dsi->phy); - if (ret) - return ret; - ret = msm_dsi_host_set_src_pll(other_dsi->host, clk_master_dsi->phy); + msm_dsi_host_set_phy_mode(msm_dsi->host, msm_dsi->phy); + msm_dsi_host_set_phy_mode(other_dsi->host, other_dsi->phy); } - return ret; + return 0; } static int enable_phy(struct msm_dsi *msm_dsi, @@ -649,23 +645,6 @@ fail: return ERR_PTR(ret); } -bool msm_dsi_manager_validate_current_config(u8 id) -{ - bool is_bonded_dsi = IS_BONDED_DSI(); - - /* - * For bonded DSI, we only have one drm panel. For this - * use case, we register only one bridge/connector. - * Skip bridge/connector initialisation if it is - * slave-DSI for bonded DSI configuration. - */ - if (is_bonded_dsi && !IS_MASTER_DSI_LINK(id)) { - DBG("Skip bridge registration for slave DSI->id: %d\n", id); - return false; - } - return true; -} - /* initialize bridge */ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 9842e04b5858..c2ed177717c7 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -602,7 +602,7 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) static void dsi_phy_disable_resource(struct msm_dsi_phy *phy) { clk_disable_unprepare(phy->ahb_clk); - pm_runtime_put_autosuspend(&phy->pdev->dev); + pm_runtime_put(&phy->pdev->dev); } static const struct of_device_id dsi_phy_dt_match[] = { @@ -892,17 +892,6 @@ bool msm_dsi_phy_set_continuous_clock(struct msm_dsi_phy *phy, bool enable) return phy->cfg->ops.set_continuous_clock(phy, enable); } -int msm_dsi_phy_get_clk_provider(struct msm_dsi_phy *phy, - struct clk **byte_clk_provider, struct clk **pixel_clk_provider) -{ - if (byte_clk_provider) - *byte_clk_provider = phy->provided_clocks->hws[DSI_BYTE_PLL_CLK]->clk; - if (pixel_clk_provider) - *pixel_clk_provider = phy->provided_clocks->hws[DSI_PIXEL_PLL_CLK]->clk; - - return 0; -} - void msm_dsi_phy_pll_save_state(struct msm_dsi_phy *phy) { if (phy->cfg->ops.save_pll_state) { diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c deleted file mode 100644 index 106a67473af5..000000000000 --- a/drivers/gpu/drm/msm/edp/edp.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include <linux/of_irq.h> -#include "edp.h" - -static irqreturn_t edp_irq(int irq, void *dev_id) -{ - struct msm_edp *edp = dev_id; - - /* Process eDP irq */ - return msm_edp_ctrl_irq(edp->ctrl); -} - -static void edp_destroy(struct platform_device *pdev) -{ - struct msm_edp *edp = platform_get_drvdata(pdev); - - if (!edp) - return; - - if (edp->ctrl) { - msm_edp_ctrl_destroy(edp->ctrl); - edp->ctrl = NULL; - } - - platform_set_drvdata(pdev, NULL); -} - -/* construct eDP at bind/probe time, grab all the resources. */ -static struct msm_edp *edp_init(struct platform_device *pdev) -{ - struct msm_edp *edp = NULL; - int ret; - - if (!pdev) { - pr_err("no eDP device\n"); - ret = -ENXIO; - goto fail; - } - - edp = devm_kzalloc(&pdev->dev, sizeof(*edp), GFP_KERNEL); - if (!edp) { - ret = -ENOMEM; - goto fail; - } - DBG("eDP probed=%p", edp); - - edp->pdev = pdev; - platform_set_drvdata(pdev, edp); - - ret = msm_edp_ctrl_init(edp); - if (ret) - goto fail; - - return edp; - -fail: - if (edp) - edp_destroy(pdev); - - return ERR_PTR(ret); -} - -static int edp_bind(struct device *dev, struct device *master, void *data) -{ - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; - struct msm_edp *edp; - - DBG(""); - edp = edp_init(to_platform_device(dev)); - if (IS_ERR(edp)) - return PTR_ERR(edp); - priv->edp = edp; - - return 0; -} - -static void edp_unbind(struct device *dev, struct device *master, void *data) -{ - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; - - DBG(""); - if (priv->edp) { - edp_destroy(to_platform_device(dev)); - priv->edp = NULL; - } -} - -static const struct component_ops edp_ops = { - .bind = edp_bind, - .unbind = edp_unbind, -}; - -static int edp_dev_probe(struct platform_device *pdev) -{ - DBG(""); - return component_add(&pdev->dev, &edp_ops); -} - -static int edp_dev_remove(struct platform_device *pdev) -{ - DBG(""); - component_del(&pdev->dev, &edp_ops); - return 0; -} - -static const struct of_device_id dt_match[] = { - { .compatible = "qcom,mdss-edp" }, - {} -}; - -static struct platform_driver edp_driver = { - .probe = edp_dev_probe, - .remove = edp_dev_remove, - .driver = { - .name = "msm_edp", - .of_match_table = dt_match, - }, -}; - -void __init msm_edp_register(void) -{ - DBG(""); - platform_driver_register(&edp_driver); -} - -void __exit msm_edp_unregister(void) -{ - DBG(""); - platform_driver_unregister(&edp_driver); -} - -/* Second part of initialization, the drm/kms level modeset_init */ -int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev, - struct drm_encoder *encoder) -{ - struct platform_device *pdev = edp->pdev; - struct msm_drm_private *priv = dev->dev_private; - int ret; - - edp->encoder = encoder; - edp->dev = dev; - - edp->bridge = msm_edp_bridge_init(edp); - if (IS_ERR(edp->bridge)) { - ret = PTR_ERR(edp->bridge); - DRM_DEV_ERROR(dev->dev, "failed to create eDP bridge: %d\n", ret); - edp->bridge = NULL; - goto fail; - } - - edp->connector = msm_edp_connector_init(edp); - if (IS_ERR(edp->connector)) { - ret = PTR_ERR(edp->connector); - DRM_DEV_ERROR(dev->dev, "failed to create eDP connector: %d\n", ret); - edp->connector = NULL; - goto fail; - } - - edp->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); - if (edp->irq < 0) { - ret = edp->irq; - DRM_DEV_ERROR(dev->dev, "failed to get IRQ: %d\n", ret); - goto fail; - } - - ret = devm_request_irq(&pdev->dev, edp->irq, - edp_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "edp_isr", edp); - if (ret < 0) { - DRM_DEV_ERROR(dev->dev, "failed to request IRQ%u: %d\n", - edp->irq, ret); - goto fail; - } - - priv->bridges[priv->num_bridges++] = edp->bridge; - priv->connectors[priv->num_connectors++] = edp->connector; - - return 0; - -fail: - /* bridge/connector are normally destroyed by drm */ - if (edp->bridge) { - edp_bridge_destroy(edp->bridge); - edp->bridge = NULL; - } - if (edp->connector) { - edp->connector->funcs->destroy(edp->connector); - edp->connector = NULL; - } - - return ret; -} diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h deleted file mode 100644 index 8590f2ce274d..000000000000 --- a/drivers/gpu/drm/msm/edp/edp.h +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#ifndef __EDP_CONNECTOR_H__ -#define __EDP_CONNECTOR_H__ - -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <drm/drm_bridge.h> -#include <drm/drm_crtc.h> -#include <drm/drm_dp_helper.h> - -#include "msm_drv.h" - -#define edp_read(offset) msm_readl((offset)) -#define edp_write(offset, data) msm_writel((data), (offset)) - -struct edp_ctrl; -struct edp_aux; -struct edp_phy; - -struct msm_edp { - struct drm_device *dev; - struct platform_device *pdev; - - struct drm_connector *connector; - struct drm_bridge *bridge; - - /* the encoder we are hooked to (outside of eDP block) */ - struct drm_encoder *encoder; - - struct edp_ctrl *ctrl; - - int irq; -}; - -/* eDP bridge */ -struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp); -void edp_bridge_destroy(struct drm_bridge *bridge); - -/* eDP connector */ -struct drm_connector *msm_edp_connector_init(struct msm_edp *edp); - -/* AUX */ -void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux); -void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux); -irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr); -void msm_edp_aux_ctrl(struct edp_aux *aux, int enable); - -/* Phy */ -bool msm_edp_phy_ready(struct edp_phy *phy); -void msm_edp_phy_ctrl(struct edp_phy *phy, int enable); -void msm_edp_phy_vm_pe_init(struct edp_phy *phy); -void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1); -void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane); -void *msm_edp_phy_init(struct device *dev, void __iomem *regbase); - -/* Ctrl */ -irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl); -void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on); -int msm_edp_ctrl_init(struct msm_edp *edp); -void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl); -bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl); -int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, - struct drm_connector *connector, struct edid **edid); -int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, - const struct drm_display_mode *mode, - const struct drm_display_info *info); -/* @pixel_rate is in kHz */ -bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, - u32 pixel_rate, u32 *pm, u32 *pn); - -#endif /* __EDP_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/msm/edp/edp.xml.h b/drivers/gpu/drm/msm/edp/edp.xml.h deleted file mode 100644 index 7907e0f5988f..000000000000 --- a/drivers/gpu/drm/msm/edp/edp.xml.h +++ /dev/null @@ -1,388 +0,0 @@ -#ifndef EDP_XML -#define EDP_XML - -/* Autogenerated file, DO NOT EDIT manually! - -This file was generated by the rules-ng-ng headergen tool in this git repository: -http://github.com/freedreno/envytools/ -git clone https://github.com/freedreno/envytools.git - -The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/mesa/mesa/src/freedreno/registers/msm.xml ( 981 bytes, from 2021-06-05 21:37:42) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/freedreno_copyright.xml ( 1572 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/mdp/mdp4.xml ( 20912 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/mdp/mdp_common.xml ( 2849 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/mdp/mdp5.xml ( 37461 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi.xml ( 15291 bytes, from 2021-06-15 22:36:13) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_v2.xml ( 3236 bytes, from 2021-06-05 21:37:42) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_28nm_8960.xml ( 4935 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_28nm.xml ( 7004 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_20nm.xml ( 3712 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_14nm.xml ( 5381 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_10nm.xml ( 4499 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_7nm.xml ( 10953 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/dsi_phy_5nm.xml ( 10900 bytes, from 2021-05-21 19:18:08) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/sfpb.xml ( 602 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/dsi/mmss_cc.xml ( 1686 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/hdmi/qfprom.xml ( 600 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/hdmi/hdmi.xml ( 41874 bytes, from 2021-02-18 16:45:44) -- /home/robclark/src/mesa/mesa/src/freedreno/registers/edp/edp.xml ( 10416 bytes, from 2021-02-18 16:45:44) - -Copyright (C) 2013-2021 by the following authors: -- Rob Clark <robdclark@gmail.com> (robclark) -- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice (including the -next paragraph) shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -enum edp_color_depth { - EDP_6BIT = 0, - EDP_8BIT = 1, - EDP_10BIT = 2, - EDP_12BIT = 3, - EDP_16BIT = 4, -}; - -enum edp_component_format { - EDP_RGB = 0, - EDP_YUV422 = 1, - EDP_YUV444 = 2, -}; - -#define REG_EDP_MAINLINK_CTRL 0x00000004 -#define EDP_MAINLINK_CTRL_ENABLE 0x00000001 -#define EDP_MAINLINK_CTRL_RESET 0x00000002 - -#define REG_EDP_STATE_CTRL 0x00000008 -#define EDP_STATE_CTRL_TRAIN_PATTERN_1 0x00000001 -#define EDP_STATE_CTRL_TRAIN_PATTERN_2 0x00000002 -#define EDP_STATE_CTRL_TRAIN_PATTERN_3 0x00000004 -#define EDP_STATE_CTRL_SYMBOL_ERR_RATE_MEAS 0x00000008 -#define EDP_STATE_CTRL_PRBS7 0x00000010 -#define EDP_STATE_CTRL_CUSTOM_80_BIT_PATTERN 0x00000020 -#define EDP_STATE_CTRL_SEND_VIDEO 0x00000040 -#define EDP_STATE_CTRL_PUSH_IDLE 0x00000080 - -#define REG_EDP_CONFIGURATION_CTRL 0x0000000c -#define EDP_CONFIGURATION_CTRL_SYNC_CLK 0x00000001 -#define EDP_CONFIGURATION_CTRL_STATIC_MVID 0x00000002 -#define EDP_CONFIGURATION_CTRL_PROGRESSIVE 0x00000004 -#define EDP_CONFIGURATION_CTRL_LANES__MASK 0x00000030 -#define EDP_CONFIGURATION_CTRL_LANES__SHIFT 4 -static inline uint32_t EDP_CONFIGURATION_CTRL_LANES(uint32_t val) -{ - return ((val) << EDP_CONFIGURATION_CTRL_LANES__SHIFT) & EDP_CONFIGURATION_CTRL_LANES__MASK; -} -#define EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING 0x00000040 -#define EDP_CONFIGURATION_CTRL_COLOR__MASK 0x00000100 -#define EDP_CONFIGURATION_CTRL_COLOR__SHIFT 8 -static inline uint32_t EDP_CONFIGURATION_CTRL_COLOR(enum edp_color_depth val) -{ - return ((val) << EDP_CONFIGURATION_CTRL_COLOR__SHIFT) & EDP_CONFIGURATION_CTRL_COLOR__MASK; -} - -#define REG_EDP_SOFTWARE_MVID 0x00000014 - -#define REG_EDP_SOFTWARE_NVID 0x00000018 - -#define REG_EDP_TOTAL_HOR_VER 0x0000001c -#define EDP_TOTAL_HOR_VER_HORIZ__MASK 0x0000ffff -#define EDP_TOTAL_HOR_VER_HORIZ__SHIFT 0 -static inline uint32_t EDP_TOTAL_HOR_VER_HORIZ(uint32_t val) -{ - return ((val) << EDP_TOTAL_HOR_VER_HORIZ__SHIFT) & EDP_TOTAL_HOR_VER_HORIZ__MASK; -} -#define EDP_TOTAL_HOR_VER_VERT__MASK 0xffff0000 -#define EDP_TOTAL_HOR_VER_VERT__SHIFT 16 -static inline uint32_t EDP_TOTAL_HOR_VER_VERT(uint32_t val) -{ - return ((val) << EDP_TOTAL_HOR_VER_VERT__SHIFT) & EDP_TOTAL_HOR_VER_VERT__MASK; -} - -#define REG_EDP_START_HOR_VER_FROM_SYNC 0x00000020 -#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK 0x0000ffff -#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT 0 -static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_HORIZ(uint32_t val) -{ - return ((val) << EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK; -} -#define EDP_START_HOR_VER_FROM_SYNC_VERT__MASK 0xffff0000 -#define EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT 16 -static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_VERT(uint32_t val) -{ - return ((val) << EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_VERT__MASK; -} - -#define REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY 0x00000024 -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK 0x00007fff -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT 0 -static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ(uint32_t val) -{ - return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK; -} -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC 0x00008000 -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK 0x7fff0000 -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT 16 -static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT(uint32_t val) -{ - return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK; -} -#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC 0x80000000 - -#define REG_EDP_ACTIVE_HOR_VER 0x00000028 -#define EDP_ACTIVE_HOR_VER_HORIZ__MASK 0x0000ffff -#define EDP_ACTIVE_HOR_VER_HORIZ__SHIFT 0 -static inline uint32_t EDP_ACTIVE_HOR_VER_HORIZ(uint32_t val) -{ - return ((val) << EDP_ACTIVE_HOR_VER_HORIZ__SHIFT) & EDP_ACTIVE_HOR_VER_HORIZ__MASK; -} -#define EDP_ACTIVE_HOR_VER_VERT__MASK 0xffff0000 -#define EDP_ACTIVE_HOR_VER_VERT__SHIFT 16 -static inline uint32_t EDP_ACTIVE_HOR_VER_VERT(uint32_t val) -{ - return ((val) << EDP_ACTIVE_HOR_VER_VERT__SHIFT) & EDP_ACTIVE_HOR_VER_VERT__MASK; -} - -#define REG_EDP_MISC1_MISC0 0x0000002c -#define EDP_MISC1_MISC0_MISC0__MASK 0x000000ff -#define EDP_MISC1_MISC0_MISC0__SHIFT 0 -static inline uint32_t EDP_MISC1_MISC0_MISC0(uint32_t val) -{ - return ((val) << EDP_MISC1_MISC0_MISC0__SHIFT) & EDP_MISC1_MISC0_MISC0__MASK; -} -#define EDP_MISC1_MISC0_SYNC 0x00000001 -#define EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK 0x00000006 -#define EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT 1 -static inline uint32_t EDP_MISC1_MISC0_COMPONENT_FORMAT(enum edp_component_format val) -{ - return ((val) << EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT) & EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK; -} -#define EDP_MISC1_MISC0_CEA 0x00000008 -#define EDP_MISC1_MISC0_BT709_5 0x00000010 -#define EDP_MISC1_MISC0_COLOR__MASK 0x000000e0 -#define EDP_MISC1_MISC0_COLOR__SHIFT 5 -static inline uint32_t EDP_MISC1_MISC0_COLOR(enum edp_color_depth val) -{ - return ((val) << EDP_MISC1_MISC0_COLOR__SHIFT) & EDP_MISC1_MISC0_COLOR__MASK; -} -#define EDP_MISC1_MISC0_MISC1__MASK 0x0000ff00 -#define EDP_MISC1_MISC0_MISC1__SHIFT 8 -static inline uint32_t EDP_MISC1_MISC0_MISC1(uint32_t val) -{ - return ((val) << EDP_MISC1_MISC0_MISC1__SHIFT) & EDP_MISC1_MISC0_MISC1__MASK; -} -#define EDP_MISC1_MISC0_INTERLACED_ODD 0x00000100 -#define EDP_MISC1_MISC0_STEREO__MASK 0x00000600 -#define EDP_MISC1_MISC0_STEREO__SHIFT 9 -static inline uint32_t EDP_MISC1_MISC0_STEREO(uint32_t val) -{ - return ((val) << EDP_MISC1_MISC0_STEREO__SHIFT) & EDP_MISC1_MISC0_STEREO__MASK; -} - -#define REG_EDP_PHY_CTRL 0x00000074 -#define EDP_PHY_CTRL_SW_RESET_PLL 0x00000001 -#define EDP_PHY_CTRL_SW_RESET 0x00000004 - -#define REG_EDP_MAINLINK_READY 0x00000084 -#define EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY 0x00000008 -#define EDP_MAINLINK_READY_TRAIN_PATTERN_2_READY 0x00000010 -#define EDP_MAINLINK_READY_TRAIN_PATTERN_3_READY 0x00000020 - -#define REG_EDP_AUX_CTRL 0x00000300 -#define EDP_AUX_CTRL_ENABLE 0x00000001 -#define EDP_AUX_CTRL_RESET 0x00000002 - -#define REG_EDP_INTERRUPT_REG_1 0x00000308 -#define EDP_INTERRUPT_REG_1_HPD 0x00000001 -#define EDP_INTERRUPT_REG_1_HPD_ACK 0x00000002 -#define EDP_INTERRUPT_REG_1_HPD_EN 0x00000004 -#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE 0x00000008 -#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_ACK 0x00000010 -#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_EN 0x00000020 -#define EDP_INTERRUPT_REG_1_WRONG_ADDR 0x00000040 -#define EDP_INTERRUPT_REG_1_WRONG_ADDR_ACK 0x00000080 -#define EDP_INTERRUPT_REG_1_WRONG_ADDR_EN 0x00000100 -#define EDP_INTERRUPT_REG_1_TIMEOUT 0x00000200 -#define EDP_INTERRUPT_REG_1_TIMEOUT_ACK 0x00000400 -#define EDP_INTERRUPT_REG_1_TIMEOUT_EN 0x00000800 -#define EDP_INTERRUPT_REG_1_NACK_DEFER 0x00001000 -#define EDP_INTERRUPT_REG_1_NACK_DEFER_ACK 0x00002000 -#define EDP_INTERRUPT_REG_1_NACK_DEFER_EN 0x00004000 -#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT 0x00008000 -#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_ACK 0x00010000 -#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_EN 0x00020000 -#define EDP_INTERRUPT_REG_1_I2C_NACK 0x00040000 -#define EDP_INTERRUPT_REG_1_I2C_NACK_ACK 0x00080000 -#define EDP_INTERRUPT_REG_1_I2C_NACK_EN 0x00100000 -#define EDP_INTERRUPT_REG_1_I2C_DEFER 0x00200000 -#define EDP_INTERRUPT_REG_1_I2C_DEFER_ACK 0x00400000 -#define EDP_INTERRUPT_REG_1_I2C_DEFER_EN 0x00800000 -#define EDP_INTERRUPT_REG_1_PLL_UNLOCK 0x01000000 -#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_ACK 0x02000000 -#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_EN 0x04000000 -#define EDP_INTERRUPT_REG_1_AUX_ERROR 0x08000000 -#define EDP_INTERRUPT_REG_1_AUX_ERROR_ACK 0x10000000 -#define EDP_INTERRUPT_REG_1_AUX_ERROR_EN 0x20000000 - -#define REG_EDP_INTERRUPT_REG_2 0x0000030c -#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO 0x00000001 -#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_ACK 0x00000002 -#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_EN 0x00000004 -#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT 0x00000008 -#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_ACK 0x00000010 -#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_EN 0x00000020 -#define EDP_INTERRUPT_REG_2_FRAME_END 0x00000200 -#define EDP_INTERRUPT_REG_2_FRAME_END_ACK 0x00000080 -#define EDP_INTERRUPT_REG_2_FRAME_END_EN 0x00000100 -#define EDP_INTERRUPT_REG_2_CRC_UPDATED 0x00000200 -#define EDP_INTERRUPT_REG_2_CRC_UPDATED_ACK 0x00000400 -#define EDP_INTERRUPT_REG_2_CRC_UPDATED_EN 0x00000800 - -#define REG_EDP_INTERRUPT_TRANS_NUM 0x00000310 - -#define REG_EDP_AUX_DATA 0x00000314 -#define EDP_AUX_DATA_READ 0x00000001 -#define EDP_AUX_DATA_DATA__MASK 0x0000ff00 -#define EDP_AUX_DATA_DATA__SHIFT 8 -static inline uint32_t EDP_AUX_DATA_DATA(uint32_t val) -{ - return ((val) << EDP_AUX_DATA_DATA__SHIFT) & EDP_AUX_DATA_DATA__MASK; -} -#define EDP_AUX_DATA_INDEX__MASK 0x00ff0000 -#define EDP_AUX_DATA_INDEX__SHIFT 16 -static inline uint32_t EDP_AUX_DATA_INDEX(uint32_t val) -{ - return ((val) << EDP_AUX_DATA_INDEX__SHIFT) & EDP_AUX_DATA_INDEX__MASK; -} -#define EDP_AUX_DATA_INDEX_WRITE 0x80000000 - -#define REG_EDP_AUX_TRANS_CTRL 0x00000318 -#define EDP_AUX_TRANS_CTRL_I2C 0x00000100 -#define EDP_AUX_TRANS_CTRL_GO 0x00000200 - -#define REG_EDP_AUX_STATUS 0x00000324 - -static inline uint32_t REG_EDP_PHY_LN(uint32_t i0) { return 0x00000400 + 0x40*i0; } - -static inline uint32_t REG_EDP_PHY_LN_PD_CTL(uint32_t i0) { return 0x00000404 + 0x40*i0; } - -#define REG_EDP_PHY_GLB_VM_CFG0 0x00000510 - -#define REG_EDP_PHY_GLB_VM_CFG1 0x00000514 - -#define REG_EDP_PHY_GLB_MISC9 0x00000518 - -#define REG_EDP_PHY_GLB_CFG 0x00000528 - -#define REG_EDP_PHY_GLB_PD_CTL 0x0000052c - -#define REG_EDP_PHY_GLB_PHY_STATUS 0x00000598 - -#define REG_EDP_28nm_PHY_PLL_REFCLK_CFG 0x00000000 - -#define REG_EDP_28nm_PHY_PLL_POSTDIV1_CFG 0x00000004 - -#define REG_EDP_28nm_PHY_PLL_CHGPUMP_CFG 0x00000008 - -#define REG_EDP_28nm_PHY_PLL_VCOLPF_CFG 0x0000000c - -#define REG_EDP_28nm_PHY_PLL_VREG_CFG 0x00000010 - -#define REG_EDP_28nm_PHY_PLL_PWRGEN_CFG 0x00000014 - -#define REG_EDP_28nm_PHY_PLL_DMUX_CFG 0x00000018 - -#define REG_EDP_28nm_PHY_PLL_AMUX_CFG 0x0000001c - -#define REG_EDP_28nm_PHY_PLL_GLB_CFG 0x00000020 -#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B 0x00000001 -#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B 0x00000002 -#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B 0x00000004 -#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE 0x00000008 - -#define REG_EDP_28nm_PHY_PLL_POSTDIV2_CFG 0x00000024 - -#define REG_EDP_28nm_PHY_PLL_POSTDIV3_CFG 0x00000028 - -#define REG_EDP_28nm_PHY_PLL_LPFR_CFG 0x0000002c - -#define REG_EDP_28nm_PHY_PLL_LPFC1_CFG 0x00000030 - -#define REG_EDP_28nm_PHY_PLL_LPFC2_CFG 0x00000034 - -#define REG_EDP_28nm_PHY_PLL_SDM_CFG0 0x00000038 - -#define REG_EDP_28nm_PHY_PLL_SDM_CFG1 0x0000003c - -#define REG_EDP_28nm_PHY_PLL_SDM_CFG2 0x00000040 - -#define REG_EDP_28nm_PHY_PLL_SDM_CFG3 0x00000044 - -#define REG_EDP_28nm_PHY_PLL_SDM_CFG4 0x00000048 - -#define REG_EDP_28nm_PHY_PLL_SSC_CFG0 0x0000004c - -#define REG_EDP_28nm_PHY_PLL_SSC_CFG1 0x00000050 - -#define REG_EDP_28nm_PHY_PLL_SSC_CFG2 0x00000054 - -#define REG_EDP_28nm_PHY_PLL_SSC_CFG3 0x00000058 - -#define REG_EDP_28nm_PHY_PLL_LKDET_CFG0 0x0000005c - -#define REG_EDP_28nm_PHY_PLL_LKDET_CFG1 0x00000060 - -#define REG_EDP_28nm_PHY_PLL_LKDET_CFG2 0x00000064 - -#define REG_EDP_28nm_PHY_PLL_TEST_CFG 0x00000068 -#define EDP_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET 0x00000001 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG0 0x0000006c - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG1 0x00000070 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG2 0x00000074 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG3 0x00000078 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG4 0x0000007c - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG5 0x00000080 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG6 0x00000084 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG7 0x00000088 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG8 0x0000008c - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG9 0x00000090 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG10 0x00000094 - -#define REG_EDP_28nm_PHY_PLL_CAL_CFG11 0x00000098 - -#define REG_EDP_28nm_PHY_PLL_EFUSE_CFG 0x0000009c - -#define REG_EDP_28nm_PHY_PLL_DEBUG_BUS_SEL 0x000000a0 - - -#endif /* EDP_XML */ diff --git a/drivers/gpu/drm/msm/edp/edp_aux.c b/drivers/gpu/drm/msm/edp/edp_aux.c deleted file mode 100644 index e3d85c622cfb..000000000000 --- a/drivers/gpu/drm/msm/edp/edp_aux.c +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include "edp.h" -#include "edp.xml.h" - -#define AUX_CMD_FIFO_LEN 144 -#define AUX_CMD_NATIVE_MAX 16 -#define AUX_CMD_I2C_MAX 128 - -#define EDP_INTR_AUX_I2C_ERR \ - (EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \ - EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \ - EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER) -#define EDP_INTR_TRANS_STATUS \ - (EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR) - -struct edp_aux { - void __iomem *base; - bool msg_err; - - struct completion msg_comp; - - /* To prevent the message transaction routine from reentry. */ - struct mutex msg_mutex; - - struct drm_dp_aux drm_aux; -}; -#define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux) - -static int edp_msg_fifo_tx(struct edp_aux *aux, struct drm_dp_aux_msg *msg) -{ - u32 data[4]; - u32 reg, len; - bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); - bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); - u8 *msgdata = msg->buffer; - int i; - - if (read) - len = 4; - else - len = msg->size + 4; - - /* - * cmd fifo only has depth of 144 bytes - */ - if (len > AUX_CMD_FIFO_LEN) - return -EINVAL; - - /* Pack cmd and write to HW */ - data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ - if (read) - data[0] |= BIT(4); /* R/W */ - - data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ - data[2] = msg->address & 0xff; /* addr[7:0] */ - data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ - - for (i = 0; i < len; i++) { - reg = (i < 4) ? data[i] : msgdata[i - 4]; - reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */ - if (i == 0) - reg |= EDP_AUX_DATA_INDEX_WRITE; - edp_write(aux->base + REG_EDP_AUX_DATA, reg); - } - - reg = 0; /* Transaction number is always 1 */ - if (!native) /* i2c */ - reg |= EDP_AUX_TRANS_CTRL_I2C; - - reg |= EDP_AUX_TRANS_CTRL_GO; - edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, reg); - - return 0; -} - -static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg) -{ - u32 data; - u8 *dp; - int i; - u32 len = msg->size; - - edp_write(aux->base + REG_EDP_AUX_DATA, - EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */ - - dp = msg->buffer; - - /* discard first byte */ - data = edp_read(aux->base + REG_EDP_AUX_DATA); - for (i = 0; i < len; i++) { - data = edp_read(aux->base + REG_EDP_AUX_DATA); - dp[i] = (u8)((data >> 8) & 0xff); - } - - return 0; -} - -/* - * This function does the real job to process an AUX transaction. - * It will call msm_edp_aux_ctrl() function to reset the AUX channel, - * if the waiting is timeout. - * The caller who triggers the transaction should avoid the - * msm_edp_aux_ctrl() running concurrently in other threads, i.e. - * start transaction only when AUX channel is fully enabled. - */ -static ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, - struct drm_dp_aux_msg *msg) -{ - struct edp_aux *aux = to_edp_aux(drm_aux); - ssize_t ret; - unsigned long time_left; - bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); - bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); - - /* Ignore address only message */ - if ((msg->size == 0) || (msg->buffer == NULL)) { - msg->reply = native ? - DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; - return msg->size; - } - - /* msg sanity check */ - if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) || - (msg->size > AUX_CMD_I2C_MAX)) { - pr_err("%s: invalid msg: size(%zu), request(%x)\n", - __func__, msg->size, msg->request); - return -EINVAL; - } - - mutex_lock(&aux->msg_mutex); - - aux->msg_err = false; - reinit_completion(&aux->msg_comp); - - ret = edp_msg_fifo_tx(aux, msg); - if (ret < 0) - goto unlock_exit; - - DBG("wait_for_completion"); - time_left = wait_for_completion_timeout(&aux->msg_comp, - msecs_to_jiffies(300)); - if (!time_left) { - /* - * Clear GO and reset AUX channel - * to cancel the current transaction. - */ - edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0); - msm_edp_aux_ctrl(aux, 1); - pr_err("%s: aux timeout,\n", __func__); - ret = -ETIMEDOUT; - goto unlock_exit; - } - DBG("completion"); - - if (!aux->msg_err) { - if (read) { - ret = edp_msg_fifo_rx(aux, msg); - if (ret < 0) - goto unlock_exit; - } - - msg->reply = native ? - DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; - } else { - /* Reply defer to retry */ - msg->reply = native ? - DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; - /* - * The sleep time in caller is not long enough to make sure - * our H/W completes transactions. Add more defer time here. - */ - msleep(100); - } - - /* Return requested size for success or retry */ - ret = msg->size; - -unlock_exit: - mutex_unlock(&aux->msg_mutex); - return ret; -} - -void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux) -{ - struct device *dev = &edp->pdev->dev; - struct edp_aux *aux = NULL; - int ret; - - DBG(""); - aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL); - if (!aux) - return NULL; - - aux->base = regbase; - mutex_init(&aux->msg_mutex); - init_completion(&aux->msg_comp); - - aux->drm_aux.name = "msm_edp_aux"; - aux->drm_aux.dev = dev; - aux->drm_aux.drm_dev = edp->dev; - aux->drm_aux.transfer = edp_aux_transfer; - ret = drm_dp_aux_register(&aux->drm_aux); - if (ret) { - pr_err("%s: failed to register drm aux: %d\n", __func__, ret); - mutex_destroy(&aux->msg_mutex); - } - - if (drm_aux && aux) - *drm_aux = &aux->drm_aux; - - return aux; -} - -void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux) -{ - if (aux) { - drm_dp_aux_unregister(&aux->drm_aux); - mutex_destroy(&aux->msg_mutex); - } -} - -irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr) -{ - if (isr & EDP_INTR_TRANS_STATUS) { - DBG("isr=%x", isr); - edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0); - - if (isr & EDP_INTR_AUX_I2C_ERR) - aux->msg_err = true; - else - aux->msg_err = false; - - complete(&aux->msg_comp); - } - - return IRQ_HANDLED; -} - -void msm_edp_aux_ctrl(struct edp_aux *aux, int enable) -{ - u32 data; - - DBG("enable=%d", enable); - data = edp_read(aux->base + REG_EDP_AUX_CTRL); - - if (enable) { - data |= EDP_AUX_CTRL_RESET; - edp_write(aux->base + REG_EDP_AUX_CTRL, data); - /* Make sure full reset */ - wmb(); - usleep_range(500, 1000); - - data &= ~EDP_AUX_CTRL_RESET; - data |= EDP_AUX_CTRL_ENABLE; - edp_write(aux->base + REG_EDP_AUX_CTRL, data); - } else { - data &= ~EDP_AUX_CTRL_ENABLE; - edp_write(aux->base + REG_EDP_AUX_CTRL, data); - } -} - diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c deleted file mode 100644 index c69a37e0c708..000000000000 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include "edp.h" - -struct edp_bridge { - struct drm_bridge base; - struct msm_edp *edp; -}; -#define to_edp_bridge(x) container_of(x, struct edp_bridge, base) - -void edp_bridge_destroy(struct drm_bridge *bridge) -{ -} - -static void edp_bridge_pre_enable(struct drm_bridge *bridge) -{ - struct edp_bridge *edp_bridge = to_edp_bridge(bridge); - struct msm_edp *edp = edp_bridge->edp; - - DBG(""); - msm_edp_ctrl_power(edp->ctrl, true); -} - -static void edp_bridge_enable(struct drm_bridge *bridge) -{ - DBG(""); -} - -static void edp_bridge_disable(struct drm_bridge *bridge) -{ - DBG(""); -} - -static void edp_bridge_post_disable(struct drm_bridge *bridge) -{ - struct edp_bridge *edp_bridge = to_edp_bridge(bridge); - struct msm_edp *edp = edp_bridge->edp; - - DBG(""); - msm_edp_ctrl_power(edp->ctrl, false); -} - -static void edp_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = bridge->dev; - struct drm_connector *connector; - struct edp_bridge *edp_bridge = to_edp_bridge(bridge); - struct msm_edp *edp = edp_bridge->edp; - - DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_encoder *encoder = connector->encoder; - struct drm_bridge *first_bridge; - - if (!connector->encoder) - continue; - - first_bridge = drm_bridge_chain_get_first_bridge(encoder); - if (bridge == first_bridge) { - msm_edp_ctrl_timing_cfg(edp->ctrl, - adjusted_mode, &connector->display_info); - break; - } - } -} - -static const struct drm_bridge_funcs edp_bridge_funcs = { - .pre_enable = edp_bridge_pre_enable, - .enable = edp_bridge_enable, - .disable = edp_bridge_disable, - .post_disable = edp_bridge_post_disable, - .mode_set = edp_bridge_mode_set, -}; - -/* initialize bridge */ -struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp) -{ - struct drm_bridge *bridge = NULL; - struct edp_bridge *edp_bridge; - int ret; - - edp_bridge = devm_kzalloc(edp->dev->dev, - sizeof(*edp_bridge), GFP_KERNEL); - if (!edp_bridge) { - ret = -ENOMEM; - goto fail; - } - - edp_bridge->edp = edp; - - bridge = &edp_bridge->base; - bridge->funcs = &edp_bridge_funcs; - - ret = drm_bridge_attach(edp->encoder, bridge, NULL, 0); - if (ret) - goto fail; - - return bridge; - -fail: - if (bridge) - edp_bridge_destroy(bridge); - - return ERR_PTR(ret); -} diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c deleted file mode 100644 index 73cb5fd97a5a..000000000000 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include "drm/drm_edid.h" -#include "msm_kms.h" -#include "edp.h" - -struct edp_connector { - struct drm_connector base; - struct msm_edp *edp; -}; -#define to_edp_connector(x) container_of(x, struct edp_connector, base) - -static enum drm_connector_status edp_connector_detect( - struct drm_connector *connector, bool force) -{ - struct edp_connector *edp_connector = to_edp_connector(connector); - struct msm_edp *edp = edp_connector->edp; - - DBG(""); - return msm_edp_ctrl_panel_connected(edp->ctrl) ? - connector_status_connected : connector_status_disconnected; -} - -static void edp_connector_destroy(struct drm_connector *connector) -{ - struct edp_connector *edp_connector = to_edp_connector(connector); - - DBG(""); - - drm_connector_cleanup(connector); - - kfree(edp_connector); -} - -static int edp_connector_get_modes(struct drm_connector *connector) -{ - struct edp_connector *edp_connector = to_edp_connector(connector); - struct msm_edp *edp = edp_connector->edp; - - struct edid *drm_edid = NULL; - int ret = 0; - - DBG(""); - ret = msm_edp_ctrl_get_panel_info(edp->ctrl, connector, &drm_edid); - if (ret) - return ret; - - drm_connector_update_edid_property(connector, drm_edid); - if (drm_edid) - ret = drm_add_edid_modes(connector, drm_edid); - - return ret; -} - -static int edp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct edp_connector *edp_connector = to_edp_connector(connector); - struct msm_edp *edp = edp_connector->edp; - struct msm_drm_private *priv = connector->dev->dev_private; - struct msm_kms *kms = priv->kms; - long actual, requested; - - requested = 1000 * mode->clock; - actual = kms->funcs->round_pixclk(kms, - requested, edp_connector->edp->encoder); - - DBG("requested=%ld, actual=%ld", requested, actual); - if (actual != requested) - return MODE_CLOCK_RANGE; - - if (!msm_edp_ctrl_pixel_clock_valid( - edp->ctrl, mode->clock, NULL, NULL)) - return MODE_CLOCK_RANGE; - - /* Invalidate all modes if color format is not supported */ - if (connector->display_info.bpc > 8) - return MODE_BAD; - - return MODE_OK; -} - -static const struct drm_connector_funcs edp_connector_funcs = { - .detect = edp_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = edp_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs edp_connector_helper_funcs = { - .get_modes = edp_connector_get_modes, - .mode_valid = edp_connector_mode_valid, -}; - -/* initialize connector */ -struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) -{ - struct drm_connector *connector = NULL; - struct edp_connector *edp_connector; - int ret; - - edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL); - if (!edp_connector) - return ERR_PTR(-ENOMEM); - - edp_connector->edp = edp; - - connector = &edp_connector->base; - - ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs, - DRM_MODE_CONNECTOR_eDP); - if (ret) - return ERR_PTR(ret); - - drm_connector_helper_add(connector, &edp_connector_helper_funcs); - - /* We don't support HPD, so only poll status until connected. */ - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - - /* Display driver doesn't support interlace now. */ - connector->interlace_allowed = false; - connector->doublescan_allowed = false; - - drm_connector_attach_encoder(connector, edp->encoder); - - return connector; -} diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c deleted file mode 100644 index a68a4a1867c1..000000000000 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ /dev/null @@ -1,1373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include <linux/clk.h> -#include <linux/gpio/consumer.h> -#include <linux/regulator/consumer.h> -#include <drm/drm_crtc.h> -#include <drm/drm_dp_helper.h> -#include <drm/drm_edid.h> - -#include "edp.h" -#include "edp.xml.h" - -#define VDDA_UA_ON_LOAD 100000 /* uA units */ -#define VDDA_UA_OFF_LOAD 100 /* uA units */ - -#define DPCD_LINK_VOLTAGE_MAX 4 -#define DPCD_LINK_PRE_EMPHASIS_MAX 4 - -#define EDP_LINK_BW_MAX DP_LINK_BW_2_7 - -/* Link training return value */ -#define EDP_TRAIN_FAIL -1 -#define EDP_TRAIN_SUCCESS 0 -#define EDP_TRAIN_RECONFIG 1 - -#define EDP_CLK_MASK_AHB BIT(0) -#define EDP_CLK_MASK_AUX BIT(1) -#define EDP_CLK_MASK_LINK BIT(2) -#define EDP_CLK_MASK_PIXEL BIT(3) -#define EDP_CLK_MASK_MDP_CORE BIT(4) -#define EDP_CLK_MASK_LINK_CHAN (EDP_CLK_MASK_LINK | EDP_CLK_MASK_PIXEL) -#define EDP_CLK_MASK_AUX_CHAN \ - (EDP_CLK_MASK_AHB | EDP_CLK_MASK_AUX | EDP_CLK_MASK_MDP_CORE) -#define EDP_CLK_MASK_ALL (EDP_CLK_MASK_AUX_CHAN | EDP_CLK_MASK_LINK_CHAN) - -#define EDP_BACKLIGHT_MAX 255 - -#define EDP_INTR_STATUS1 \ - (EDP_INTERRUPT_REG_1_HPD | EDP_INTERRUPT_REG_1_AUX_I2C_DONE | \ - EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \ - EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \ - EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER | \ - EDP_INTERRUPT_REG_1_PLL_UNLOCK | EDP_INTERRUPT_REG_1_AUX_ERROR) -#define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2) -#define EDP_INTR_STATUS2 \ - (EDP_INTERRUPT_REG_2_READY_FOR_VIDEO | \ - EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT | \ - EDP_INTERRUPT_REG_2_FRAME_END | EDP_INTERRUPT_REG_2_CRC_UPDATED) -#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2) - -struct edp_ctrl { - struct platform_device *pdev; - - void __iomem *base; - - /* regulators */ - struct regulator *vdda_vreg; /* 1.8 V */ - struct regulator *lvl_vreg; - - /* clocks */ - struct clk *aux_clk; - struct clk *pixel_clk; - struct clk *ahb_clk; - struct clk *link_clk; - struct clk *mdp_core_clk; - - /* gpios */ - struct gpio_desc *panel_en_gpio; - struct gpio_desc *panel_hpd_gpio; - - /* completion and mutex */ - struct completion idle_comp; - struct mutex dev_mutex; /* To protect device power status */ - - /* work queue */ - struct work_struct on_work; - struct work_struct off_work; - struct workqueue_struct *workqueue; - - /* Interrupt register lock */ - spinlock_t irq_lock; - - bool edp_connected; - bool power_on; - - /* edid raw data */ - struct edid *edid; - - struct drm_dp_aux *drm_aux; - - /* dpcd raw data */ - u8 dpcd[DP_RECEIVER_CAP_SIZE]; - - /* Link status */ - u8 link_rate; - u8 lane_cnt; - u8 v_level; - u8 p_level; - - /* Timing status */ - u8 interlaced; - u32 pixel_rate; /* in kHz */ - u32 color_depth; - - struct edp_aux *aux; - struct edp_phy *phy; -}; - -struct edp_pixel_clk_div { - u32 rate; /* in kHz */ - u32 m; - u32 n; -}; - -#define EDP_PIXEL_CLK_NUM 8 -static const struct edp_pixel_clk_div clk_divs[2][EDP_PIXEL_CLK_NUM] = { - { /* Link clock = 162MHz, source clock = 810MHz */ - {119000, 31, 211}, /* WSXGA+ 1680x1050@60Hz CVT */ - {130250, 32, 199}, /* UXGA 1600x1200@60Hz CVT */ - {148500, 11, 60}, /* FHD 1920x1080@60Hz */ - {154000, 50, 263}, /* WUXGA 1920x1200@60Hz CVT */ - {209250, 31, 120}, /* QXGA 2048x1536@60Hz CVT */ - {268500, 119, 359}, /* WQXGA 2560x1600@60Hz CVT */ - {138530, 33, 193}, /* AUO B116HAN03.0 Panel */ - {141400, 48, 275}, /* AUO B133HTN01.2 Panel */ - }, - { /* Link clock = 270MHz, source clock = 675MHz */ - {119000, 52, 295}, /* WSXGA+ 1680x1050@60Hz CVT */ - {130250, 11, 57}, /* UXGA 1600x1200@60Hz CVT */ - {148500, 11, 50}, /* FHD 1920x1080@60Hz */ - {154000, 47, 206}, /* WUXGA 1920x1200@60Hz CVT */ - {209250, 31, 100}, /* QXGA 2048x1536@60Hz CVT */ - {268500, 107, 269}, /* WQXGA 2560x1600@60Hz CVT */ - {138530, 63, 307}, /* AUO B116HAN03.0 Panel */ - {141400, 53, 253}, /* AUO B133HTN01.2 Panel */ - }, -}; - -static int edp_clk_init(struct edp_ctrl *ctrl) -{ - struct platform_device *pdev = ctrl->pdev; - int ret; - - ctrl->aux_clk = msm_clk_get(pdev, "core"); - if (IS_ERR(ctrl->aux_clk)) { - ret = PTR_ERR(ctrl->aux_clk); - pr_err("%s: Can't find core clock, %d\n", __func__, ret); - ctrl->aux_clk = NULL; - return ret; - } - - ctrl->pixel_clk = msm_clk_get(pdev, "pixel"); - if (IS_ERR(ctrl->pixel_clk)) { - ret = PTR_ERR(ctrl->pixel_clk); - pr_err("%s: Can't find pixel clock, %d\n", __func__, ret); - ctrl->pixel_clk = NULL; - return ret; - } - - ctrl->ahb_clk = msm_clk_get(pdev, "iface"); - if (IS_ERR(ctrl->ahb_clk)) { - ret = PTR_ERR(ctrl->ahb_clk); - pr_err("%s: Can't find iface clock, %d\n", __func__, ret); - ctrl->ahb_clk = NULL; - return ret; - } - - ctrl->link_clk = msm_clk_get(pdev, "link"); - if (IS_ERR(ctrl->link_clk)) { - ret = PTR_ERR(ctrl->link_clk); - pr_err("%s: Can't find link clock, %d\n", __func__, ret); - ctrl->link_clk = NULL; - return ret; - } - - /* need mdp core clock to receive irq */ - ctrl->mdp_core_clk = msm_clk_get(pdev, "mdp_core"); - if (IS_ERR(ctrl->mdp_core_clk)) { - ret = PTR_ERR(ctrl->mdp_core_clk); - pr_err("%s: Can't find mdp_core clock, %d\n", __func__, ret); - ctrl->mdp_core_clk = NULL; - return ret; - } - - return 0; -} - -static int edp_clk_enable(struct edp_ctrl *ctrl, u32 clk_mask) -{ - int ret; - - DBG("mask=%x", clk_mask); - /* ahb_clk should be enabled first */ - if (clk_mask & EDP_CLK_MASK_AHB) { - ret = clk_prepare_enable(ctrl->ahb_clk); - if (ret) { - pr_err("%s: Failed to enable ahb clk\n", __func__); - goto f0; - } - } - if (clk_mask & EDP_CLK_MASK_AUX) { - ret = clk_set_rate(ctrl->aux_clk, 19200000); - if (ret) { - pr_err("%s: Failed to set rate aux clk\n", __func__); - goto f1; - } - ret = clk_prepare_enable(ctrl->aux_clk); - if (ret) { - pr_err("%s: Failed to enable aux clk\n", __func__); - goto f1; - } - } - /* Need to set rate and enable link_clk prior to pixel_clk */ - if (clk_mask & EDP_CLK_MASK_LINK) { - DBG("edp->link_clk, set_rate %ld", - (unsigned long)ctrl->link_rate * 27000000); - ret = clk_set_rate(ctrl->link_clk, - (unsigned long)ctrl->link_rate * 27000000); - if (ret) { - pr_err("%s: Failed to set rate to link clk\n", - __func__); - goto f2; - } - - ret = clk_prepare_enable(ctrl->link_clk); - if (ret) { - pr_err("%s: Failed to enable link clk\n", __func__); - goto f2; - } - } - if (clk_mask & EDP_CLK_MASK_PIXEL) { - DBG("edp->pixel_clk, set_rate %ld", - (unsigned long)ctrl->pixel_rate * 1000); - ret = clk_set_rate(ctrl->pixel_clk, - (unsigned long)ctrl->pixel_rate * 1000); - if (ret) { - pr_err("%s: Failed to set rate to pixel clk\n", - __func__); - goto f3; - } - - ret = clk_prepare_enable(ctrl->pixel_clk); - if (ret) { - pr_err("%s: Failed to enable pixel clk\n", __func__); - goto f3; - } - } - if (clk_mask & EDP_CLK_MASK_MDP_CORE) { - ret = clk_prepare_enable(ctrl->mdp_core_clk); - if (ret) { - pr_err("%s: Failed to enable mdp core clk\n", __func__); - goto f4; - } - } - - return 0; - -f4: - if (clk_mask & EDP_CLK_MASK_PIXEL) - clk_disable_unprepare(ctrl->pixel_clk); -f3: - if (clk_mask & EDP_CLK_MASK_LINK) - clk_disable_unprepare(ctrl->link_clk); -f2: - if (clk_mask & EDP_CLK_MASK_AUX) - clk_disable_unprepare(ctrl->aux_clk); -f1: - if (clk_mask & EDP_CLK_MASK_AHB) - clk_disable_unprepare(ctrl->ahb_clk); -f0: - return ret; -} - -static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask) -{ - if (clk_mask & EDP_CLK_MASK_MDP_CORE) - clk_disable_unprepare(ctrl->mdp_core_clk); - if (clk_mask & EDP_CLK_MASK_PIXEL) - clk_disable_unprepare(ctrl->pixel_clk); - if (clk_mask & EDP_CLK_MASK_LINK) - clk_disable_unprepare(ctrl->link_clk); - if (clk_mask & EDP_CLK_MASK_AUX) - clk_disable_unprepare(ctrl->aux_clk); - if (clk_mask & EDP_CLK_MASK_AHB) - clk_disable_unprepare(ctrl->ahb_clk); -} - -static int edp_regulator_init(struct edp_ctrl *ctrl) -{ - struct device *dev = &ctrl->pdev->dev; - int ret; - - DBG(""); - ctrl->vdda_vreg = devm_regulator_get(dev, "vdda"); - ret = PTR_ERR_OR_ZERO(ctrl->vdda_vreg); - if (ret) { - pr_err("%s: Could not get vdda reg, ret = %d\n", __func__, - ret); - ctrl->vdda_vreg = NULL; - return ret; - } - ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd"); - ret = PTR_ERR_OR_ZERO(ctrl->lvl_vreg); - if (ret) { - pr_err("%s: Could not get lvl-vdd reg, ret = %d\n", __func__, - ret); - ctrl->lvl_vreg = NULL; - return ret; - } - - return 0; -} - -static int edp_regulator_enable(struct edp_ctrl *ctrl) -{ - int ret; - - ret = regulator_set_load(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); - if (ret < 0) { - pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__); - goto vdda_set_fail; - } - - ret = regulator_enable(ctrl->vdda_vreg); - if (ret) { - pr_err("%s: Failed to enable vdda_vreg regulator.\n", __func__); - goto vdda_enable_fail; - } - - ret = regulator_enable(ctrl->lvl_vreg); - if (ret) { - pr_err("Failed to enable lvl-vdd reg regulator, %d", ret); - goto lvl_enable_fail; - } - - DBG("exit"); - return 0; - -lvl_enable_fail: - regulator_disable(ctrl->vdda_vreg); -vdda_enable_fail: - regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); -vdda_set_fail: - return ret; -} - -static void edp_regulator_disable(struct edp_ctrl *ctrl) -{ - regulator_disable(ctrl->lvl_vreg); - regulator_disable(ctrl->vdda_vreg); - regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); -} - -static int edp_gpio_config(struct edp_ctrl *ctrl) -{ - struct device *dev = &ctrl->pdev->dev; - int ret; - - ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN); - if (IS_ERR(ctrl->panel_hpd_gpio)) { - ret = PTR_ERR(ctrl->panel_hpd_gpio); - ctrl->panel_hpd_gpio = NULL; - pr_err("%s: cannot get panel-hpd-gpios, %d\n", __func__, ret); - return ret; - } - - ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW); - if (IS_ERR(ctrl->panel_en_gpio)) { - ret = PTR_ERR(ctrl->panel_en_gpio); - ctrl->panel_en_gpio = NULL; - pr_err("%s: cannot get panel-en-gpios, %d\n", __func__, ret); - return ret; - } - - DBG("gpio on"); - - return 0; -} - -static void edp_ctrl_irq_enable(struct edp_ctrl *ctrl, int enable) -{ - unsigned long flags; - - DBG("%d", enable); - spin_lock_irqsave(&ctrl->irq_lock, flags); - if (enable) { - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, EDP_INTR_MASK1); - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, EDP_INTR_MASK2); - } else { - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, 0x0); - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, 0x0); - } - spin_unlock_irqrestore(&ctrl->irq_lock, flags); - DBG("exit"); -} - -static void edp_fill_link_cfg(struct edp_ctrl *ctrl) -{ - u32 prate; - u32 lrate; - u32 bpp; - u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); - u8 lane; - - prate = ctrl->pixel_rate; - bpp = ctrl->color_depth * 3; - - /* - * By default, use the maximum link rate and minimum lane count, - * so that we can do rate down shift during link training. - */ - ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; - - prate *= bpp; - prate /= 8; /* in kByte */ - - lrate = 270000; /* in kHz */ - lrate *= ctrl->link_rate; - lrate /= 10; /* in kByte, 10 bits --> 8 bits */ - - for (lane = 1; lane <= max_lane; lane <<= 1) { - if (lrate >= prate) - break; - lrate <<= 1; - } - - ctrl->lane_cnt = lane; - DBG("rate=%d lane=%d", ctrl->link_rate, ctrl->lane_cnt); -} - -static void edp_config_ctrl(struct edp_ctrl *ctrl) -{ - u32 data; - enum edp_color_depth depth; - - data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1); - - if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) - data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING; - - depth = EDP_6BIT; - if (ctrl->color_depth == 8) - depth = EDP_8BIT; - - data |= EDP_CONFIGURATION_CTRL_COLOR(depth); - - if (!ctrl->interlaced) /* progressive */ - data |= EDP_CONFIGURATION_CTRL_PROGRESSIVE; - - data |= (EDP_CONFIGURATION_CTRL_SYNC_CLK | - EDP_CONFIGURATION_CTRL_STATIC_MVID); - - edp_write(ctrl->base + REG_EDP_CONFIGURATION_CTRL, data); -} - -static void edp_state_ctrl(struct edp_ctrl *ctrl, u32 state) -{ - edp_write(ctrl->base + REG_EDP_STATE_CTRL, state); - /* Make sure H/W status is set */ - wmb(); -} - -static int edp_lane_set_write(struct edp_ctrl *ctrl, - u8 voltage_level, u8 pre_emphasis_level) -{ - int i; - u8 buf[4]; - - if (voltage_level >= DPCD_LINK_VOLTAGE_MAX) - voltage_level |= 0x04; - - if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX) - pre_emphasis_level |= 0x04; - - pre_emphasis_level <<= 3; - - for (i = 0; i < 4; i++) - buf[i] = voltage_level | pre_emphasis_level; - - DBG("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level); - if (drm_dp_dpcd_write(ctrl->drm_aux, 0x103, buf, 4) < 4) { - pr_err("%s: Set sw/pe to panel failed\n", __func__); - return -ENOLINK; - } - - return 0; -} - -static int edp_train_pattern_set_write(struct edp_ctrl *ctrl, u8 pattern) -{ - u8 p = pattern; - - DBG("pattern=%x", p); - if (drm_dp_dpcd_write(ctrl->drm_aux, - DP_TRAINING_PATTERN_SET, &p, 1) < 1) { - pr_err("%s: Set training pattern to panel failed\n", __func__); - return -ENOLINK; - } - - return 0; -} - -static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl, - const u8 *link_status) -{ - int i; - u8 max = 0; - u8 data; - - /* use the max level across lanes */ - for (i = 0; i < ctrl->lane_cnt; i++) { - data = drm_dp_get_adjust_request_voltage(link_status, i); - DBG("lane=%d req_voltage_swing=0x%x", i, data); - if (max < data) - max = data; - } - - ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; - - /* use the max level across lanes */ - max = 0; - for (i = 0; i < ctrl->lane_cnt; i++) { - data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); - DBG("lane=%d req_pre_emphasis=0x%x", i, data); - if (max < data) - max = data; - } - - ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; - DBG("v_level=%d, p_level=%d", ctrl->v_level, ctrl->p_level); -} - -static void edp_host_train_set(struct edp_ctrl *ctrl, u32 train) -{ - int cnt = 10; - u32 data; - u32 shift = train - 1; - - DBG("train=%d", train); - - edp_state_ctrl(ctrl, EDP_STATE_CTRL_TRAIN_PATTERN_1 << shift); - while (--cnt) { - data = edp_read(ctrl->base + REG_EDP_MAINLINK_READY); - if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift)) - break; - } - - if (cnt == 0) - pr_err("%s: set link_train=%d failed\n", __func__, train); -} - -static const u8 vm_pre_emphasis[4][4] = { - {0x03, 0x06, 0x09, 0x0C}, /* pe0, 0 db */ - {0x03, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */ - {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ -}; - -/* voltage swing, 0.2v and 1.0v are not support */ -static const u8 vm_voltage_swing[4][4] = { - {0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */ - {0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */ - {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */ - {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ -}; - -static int edp_voltage_pre_emphasise_set(struct edp_ctrl *ctrl) -{ - u32 value0; - u32 value1; - - DBG("v=%d p=%d", ctrl->v_level, ctrl->p_level); - - value0 = vm_pre_emphasis[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; - value1 = vm_voltage_swing[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; - - /* Configure host and panel only if both values are allowed */ - if (value0 != 0xFF && value1 != 0xFF) { - msm_edp_phy_vm_pe_cfg(ctrl->phy, value0, value1); - return edp_lane_set_write(ctrl, ctrl->v_level, ctrl->p_level); - } - - return -EINVAL; -} - -static int edp_start_link_train_1(struct edp_ctrl *ctrl) -{ - u8 link_status[DP_LINK_STATUS_SIZE]; - u8 old_v_level; - int tries; - int ret; - int rlen; - - DBG(""); - - edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1); - ret = edp_voltage_pre_emphasise_set(ctrl); - if (ret) - return ret; - ret = edp_train_pattern_set_write(ctrl, - DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); - if (ret) - return ret; - - tries = 0; - old_v_level = ctrl->v_level; - while (1) { - drm_dp_link_train_clock_recovery_delay(ctrl->drm_aux, ctrl->dpcd); - - rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); - if (rlen < DP_LINK_STATUS_SIZE) { - pr_err("%s: read link status failed\n", __func__); - return -ENOLINK; - } - if (drm_dp_clock_recovery_ok(link_status, ctrl->lane_cnt)) { - ret = 0; - break; - } - - if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) { - ret = -1; - break; - } - - if (old_v_level == ctrl->v_level) { - tries++; - if (tries >= 5) { - ret = -1; - break; - } - } else { - tries = 0; - old_v_level = ctrl->v_level; - } - - edp_sink_train_set_adjust(ctrl, link_status); - ret = edp_voltage_pre_emphasise_set(ctrl); - if (ret) - return ret; - } - - return ret; -} - -static int edp_start_link_train_2(struct edp_ctrl *ctrl) -{ - u8 link_status[DP_LINK_STATUS_SIZE]; - int tries = 0; - int ret; - int rlen; - - DBG(""); - - edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2); - ret = edp_voltage_pre_emphasise_set(ctrl); - if (ret) - return ret; - - ret = edp_train_pattern_set_write(ctrl, - DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN); - if (ret) - return ret; - - while (1) { - drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); - - rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); - if (rlen < DP_LINK_STATUS_SIZE) { - pr_err("%s: read link status failed\n", __func__); - return -ENOLINK; - } - if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) { - ret = 0; - break; - } - - tries++; - if (tries > 10) { - ret = -1; - break; - } - - edp_sink_train_set_adjust(ctrl, link_status); - ret = edp_voltage_pre_emphasise_set(ctrl); - if (ret) - return ret; - } - - return ret; -} - -static int edp_link_rate_down_shift(struct edp_ctrl *ctrl) -{ - u32 prate, lrate, bpp; - u8 rate, lane, max_lane; - int changed = 0; - - rate = ctrl->link_rate; - lane = ctrl->lane_cnt; - max_lane = drm_dp_max_lane_count(ctrl->dpcd); - - bpp = ctrl->color_depth * 3; - prate = ctrl->pixel_rate; - prate *= bpp; - prate /= 8; /* in kByte */ - - if (rate > DP_LINK_BW_1_62 && rate <= EDP_LINK_BW_MAX) { - rate -= 4; /* reduce rate */ - changed++; - } - - if (changed) { - if (lane >= 1 && lane < max_lane) - lane <<= 1; /* increase lane */ - - lrate = 270000; /* in kHz */ - lrate *= rate; - lrate /= 10; /* kByte, 10 bits --> 8 bits */ - lrate *= lane; - - DBG("new lrate=%u prate=%u(kHz) rate=%d lane=%d p=%u b=%d", - lrate, prate, rate, lane, - ctrl->pixel_rate, - bpp); - - if (lrate > prate) { - ctrl->link_rate = rate; - ctrl->lane_cnt = lane; - DBG("new rate=%d %d", rate, lane); - return 0; - } - } - - return -EINVAL; -} - -static int edp_clear_training_pattern(struct edp_ctrl *ctrl) -{ - int ret; - - ret = edp_train_pattern_set_write(ctrl, 0); - - drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); - - return ret; -} - -static int edp_do_link_train(struct edp_ctrl *ctrl) -{ - u8 values[2]; - int ret; - - DBG(""); - /* - * Set the current link rate and lane cnt to panel. They may have been - * adjusted and the values are different from them in DPCD CAP - */ - values[0] = ctrl->lane_cnt; - values[1] = ctrl->link_rate; - - if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) - values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - - if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, - sizeof(values)) < 0) - return EDP_TRAIN_FAIL; - - ctrl->v_level = 0; /* start from default level */ - ctrl->p_level = 0; - - edp_state_ctrl(ctrl, 0); - if (edp_clear_training_pattern(ctrl)) - return EDP_TRAIN_FAIL; - - ret = edp_start_link_train_1(ctrl); - if (ret < 0) { - if (edp_link_rate_down_shift(ctrl) == 0) { - DBG("link reconfig"); - ret = EDP_TRAIN_RECONFIG; - goto clear; - } else { - pr_err("%s: Training 1 failed", __func__); - ret = EDP_TRAIN_FAIL; - goto clear; - } - } - DBG("Training 1 completed successfully"); - - edp_state_ctrl(ctrl, 0); - if (edp_clear_training_pattern(ctrl)) - return EDP_TRAIN_FAIL; - - ret = edp_start_link_train_2(ctrl); - if (ret < 0) { - if (edp_link_rate_down_shift(ctrl) == 0) { - DBG("link reconfig"); - ret = EDP_TRAIN_RECONFIG; - goto clear; - } else { - pr_err("%s: Training 2 failed", __func__); - ret = EDP_TRAIN_FAIL; - goto clear; - } - } - DBG("Training 2 completed successfully"); - - edp_state_ctrl(ctrl, EDP_STATE_CTRL_SEND_VIDEO); -clear: - edp_clear_training_pattern(ctrl); - - return ret; -} - -static void edp_clock_synchrous(struct edp_ctrl *ctrl, int sync) -{ - u32 data; - enum edp_color_depth depth; - - data = edp_read(ctrl->base + REG_EDP_MISC1_MISC0); - - if (sync) - data |= EDP_MISC1_MISC0_SYNC; - else - data &= ~EDP_MISC1_MISC0_SYNC; - - /* only legacy rgb mode supported */ - depth = EDP_6BIT; /* Default */ - if (ctrl->color_depth == 8) - depth = EDP_8BIT; - else if (ctrl->color_depth == 10) - depth = EDP_10BIT; - else if (ctrl->color_depth == 12) - depth = EDP_12BIT; - else if (ctrl->color_depth == 16) - depth = EDP_16BIT; - - data |= EDP_MISC1_MISC0_COLOR(depth); - - edp_write(ctrl->base + REG_EDP_MISC1_MISC0, data); -} - -static int edp_sw_mvid_nvid(struct edp_ctrl *ctrl, u32 m, u32 n) -{ - u32 n_multi, m_multi = 5; - - if (ctrl->link_rate == DP_LINK_BW_1_62) { - n_multi = 1; - } else if (ctrl->link_rate == DP_LINK_BW_2_7) { - n_multi = 2; - } else { - pr_err("%s: Invalid link rate, %d\n", __func__, - ctrl->link_rate); - return -EINVAL; - } - - edp_write(ctrl->base + REG_EDP_SOFTWARE_MVID, m * m_multi); - edp_write(ctrl->base + REG_EDP_SOFTWARE_NVID, n * n_multi); - - return 0; -} - -static void edp_mainlink_ctrl(struct edp_ctrl *ctrl, int enable) -{ - u32 data = 0; - - edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, EDP_MAINLINK_CTRL_RESET); - /* Make sure fully reset */ - wmb(); - usleep_range(500, 1000); - - if (enable) - data |= EDP_MAINLINK_CTRL_ENABLE; - - edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, data); -} - -static void edp_ctrl_phy_aux_enable(struct edp_ctrl *ctrl, int enable) -{ - if (enable) { - edp_regulator_enable(ctrl); - edp_clk_enable(ctrl, EDP_CLK_MASK_AUX_CHAN); - msm_edp_phy_ctrl(ctrl->phy, 1); - msm_edp_aux_ctrl(ctrl->aux, 1); - gpiod_set_value(ctrl->panel_en_gpio, 1); - } else { - gpiod_set_value(ctrl->panel_en_gpio, 0); - msm_edp_aux_ctrl(ctrl->aux, 0); - msm_edp_phy_ctrl(ctrl->phy, 0); - edp_clk_disable(ctrl, EDP_CLK_MASK_AUX_CHAN); - edp_regulator_disable(ctrl); - } -} - -static void edp_ctrl_link_enable(struct edp_ctrl *ctrl, int enable) -{ - u32 m, n; - - if (enable) { - /* Enable link channel clocks */ - edp_clk_enable(ctrl, EDP_CLK_MASK_LINK_CHAN); - - msm_edp_phy_lane_power_ctrl(ctrl->phy, true, ctrl->lane_cnt); - - msm_edp_phy_vm_pe_init(ctrl->phy); - - /* Make sure phy is programed */ - wmb(); - msm_edp_phy_ready(ctrl->phy); - - edp_config_ctrl(ctrl); - msm_edp_ctrl_pixel_clock_valid(ctrl, ctrl->pixel_rate, &m, &n); - edp_sw_mvid_nvid(ctrl, m, n); - edp_mainlink_ctrl(ctrl, 1); - } else { - edp_mainlink_ctrl(ctrl, 0); - - msm_edp_phy_lane_power_ctrl(ctrl->phy, false, 0); - edp_clk_disable(ctrl, EDP_CLK_MASK_LINK_CHAN); - } -} - -static int edp_ctrl_training(struct edp_ctrl *ctrl) -{ - int ret; - - /* Do link training only when power is on */ - if (!ctrl->power_on) - return -EINVAL; - -train_start: - ret = edp_do_link_train(ctrl); - if (ret == EDP_TRAIN_RECONFIG) { - /* Re-configure main link */ - edp_ctrl_irq_enable(ctrl, 0); - edp_ctrl_link_enable(ctrl, 0); - msm_edp_phy_ctrl(ctrl->phy, 0); - - /* Make sure link is fully disabled */ - wmb(); - usleep_range(500, 1000); - - msm_edp_phy_ctrl(ctrl->phy, 1); - edp_ctrl_link_enable(ctrl, 1); - edp_ctrl_irq_enable(ctrl, 1); - goto train_start; - } - - return ret; -} - -static void edp_ctrl_on_worker(struct work_struct *work) -{ - struct edp_ctrl *ctrl = container_of( - work, struct edp_ctrl, on_work); - u8 value; - int ret; - - mutex_lock(&ctrl->dev_mutex); - - if (ctrl->power_on) { - DBG("already on"); - goto unlock_ret; - } - - edp_ctrl_phy_aux_enable(ctrl, 1); - edp_ctrl_link_enable(ctrl, 1); - - edp_ctrl_irq_enable(ctrl, 1); - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { - ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); - if (ret < 0) - goto fail; - - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D0; - - ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); - if (ret < 0) - goto fail; - - /* - * According to the DP 1.1 specification, a "Sink Device must - * exit the power saving state within 1 ms" (Section 2.5.3.1, - * Table 5-52, "Sink Control Field" (register 0x600). - */ - usleep_range(1000, 2000); - } - - ctrl->power_on = true; - - /* Start link training */ - ret = edp_ctrl_training(ctrl); - if (ret != EDP_TRAIN_SUCCESS) - goto fail; - - DBG("DONE"); - goto unlock_ret; - -fail: - edp_ctrl_irq_enable(ctrl, 0); - edp_ctrl_link_enable(ctrl, 0); - edp_ctrl_phy_aux_enable(ctrl, 0); - ctrl->power_on = false; -unlock_ret: - mutex_unlock(&ctrl->dev_mutex); -} - -static void edp_ctrl_off_worker(struct work_struct *work) -{ - struct edp_ctrl *ctrl = container_of( - work, struct edp_ctrl, off_work); - unsigned long time_left; - - mutex_lock(&ctrl->dev_mutex); - - if (!ctrl->power_on) { - DBG("already off"); - goto unlock_ret; - } - - reinit_completion(&ctrl->idle_comp); - edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); - - time_left = wait_for_completion_timeout(&ctrl->idle_comp, - msecs_to_jiffies(500)); - if (!time_left) - DBG("%s: idle pattern timedout\n", __func__); - - edp_state_ctrl(ctrl, 0); - - /* DP_SET_POWER register is only available on DPCD v1.1 and later */ - if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { - u8 value; - int ret; - - ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); - if (ret > 0) { - value &= ~DP_SET_POWER_MASK; - value |= DP_SET_POWER_D3; - - drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); - } - } - - edp_ctrl_irq_enable(ctrl, 0); - - edp_ctrl_link_enable(ctrl, 0); - - edp_ctrl_phy_aux_enable(ctrl, 0); - - ctrl->power_on = false; - -unlock_ret: - mutex_unlock(&ctrl->dev_mutex); -} - -irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl) -{ - u32 isr1, isr2, mask1, mask2; - u32 ack; - - DBG(""); - spin_lock(&ctrl->irq_lock); - isr1 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_1); - isr2 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_2); - - mask1 = isr1 & EDP_INTR_MASK1; - mask2 = isr2 & EDP_INTR_MASK2; - - isr1 &= ~mask1; /* remove masks bit */ - isr2 &= ~mask2; - - DBG("isr=%x mask=%x isr2=%x mask2=%x", - isr1, mask1, isr2, mask2); - - ack = isr1 & EDP_INTR_STATUS1; - ack <<= 1; /* ack bits */ - ack |= mask1; - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, ack); - - ack = isr2 & EDP_INTR_STATUS2; - ack <<= 1; /* ack bits */ - ack |= mask2; - edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, ack); - spin_unlock(&ctrl->irq_lock); - - if (isr1 & EDP_INTERRUPT_REG_1_HPD) - DBG("edp_hpd"); - - if (isr2 & EDP_INTERRUPT_REG_2_READY_FOR_VIDEO) - DBG("edp_video_ready"); - - if (isr2 & EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT) { - DBG("idle_patterns_sent"); - complete(&ctrl->idle_comp); - } - - msm_edp_aux_irq(ctrl->aux, isr1); - - return IRQ_HANDLED; -} - -void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on) -{ - if (on) - queue_work(ctrl->workqueue, &ctrl->on_work); - else - queue_work(ctrl->workqueue, &ctrl->off_work); -} - -int msm_edp_ctrl_init(struct msm_edp *edp) -{ - struct edp_ctrl *ctrl = NULL; - struct device *dev; - int ret; - - if (!edp) { - pr_err("%s: edp is NULL!\n", __func__); - return -EINVAL; - } - - dev = &edp->pdev->dev; - ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) - return -ENOMEM; - - edp->ctrl = ctrl; - ctrl->pdev = edp->pdev; - - ctrl->base = msm_ioremap(ctrl->pdev, "edp", "eDP"); - if (IS_ERR(ctrl->base)) - return PTR_ERR(ctrl->base); - - /* Get regulator, clock, gpio, pwm */ - ret = edp_regulator_init(ctrl); - if (ret) { - pr_err("%s:regulator init fail\n", __func__); - return ret; - } - ret = edp_clk_init(ctrl); - if (ret) { - pr_err("%s:clk init fail\n", __func__); - return ret; - } - ret = edp_gpio_config(ctrl); - if (ret) { - pr_err("%s:failed to configure GPIOs: %d", __func__, ret); - return ret; - } - - /* Init aux and phy */ - ctrl->aux = msm_edp_aux_init(edp, ctrl->base, &ctrl->drm_aux); - if (!ctrl->aux || !ctrl->drm_aux) { - pr_err("%s:failed to init aux\n", __func__); - return -ENOMEM; - } - - ctrl->phy = msm_edp_phy_init(dev, ctrl->base); - if (!ctrl->phy) { - pr_err("%s:failed to init phy\n", __func__); - ret = -ENOMEM; - goto err_destory_aux; - } - - spin_lock_init(&ctrl->irq_lock); - mutex_init(&ctrl->dev_mutex); - init_completion(&ctrl->idle_comp); - - /* setup workqueue */ - ctrl->workqueue = alloc_ordered_workqueue("edp_drm_work", 0); - INIT_WORK(&ctrl->on_work, edp_ctrl_on_worker); - INIT_WORK(&ctrl->off_work, edp_ctrl_off_worker); - - return 0; - -err_destory_aux: - msm_edp_aux_destroy(dev, ctrl->aux); - ctrl->aux = NULL; - return ret; -} - -void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl) -{ - if (!ctrl) - return; - - if (ctrl->workqueue) { - destroy_workqueue(ctrl->workqueue); - ctrl->workqueue = NULL; - } - - if (ctrl->aux) { - msm_edp_aux_destroy(&ctrl->pdev->dev, ctrl->aux); - ctrl->aux = NULL; - } - - kfree(ctrl->edid); - ctrl->edid = NULL; - - mutex_destroy(&ctrl->dev_mutex); -} - -bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) -{ - mutex_lock(&ctrl->dev_mutex); - DBG("connect status = %d", ctrl->edp_connected); - if (ctrl->edp_connected) { - mutex_unlock(&ctrl->dev_mutex); - return true; - } - - if (!ctrl->power_on) { - edp_ctrl_phy_aux_enable(ctrl, 1); - edp_ctrl_irq_enable(ctrl, 1); - } - - if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd, - DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) { - pr_err("%s: AUX channel is NOT ready\n", __func__); - memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE); - } else { - ctrl->edp_connected = true; - } - - if (!ctrl->power_on) { - edp_ctrl_irq_enable(ctrl, 0); - edp_ctrl_phy_aux_enable(ctrl, 0); - } - - DBG("exit: connect status=%d", ctrl->edp_connected); - - mutex_unlock(&ctrl->dev_mutex); - - return ctrl->edp_connected; -} - -int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, - struct drm_connector *connector, struct edid **edid) -{ - mutex_lock(&ctrl->dev_mutex); - - if (ctrl->edid) { - if (edid) { - DBG("Just return edid buffer"); - *edid = ctrl->edid; - } - goto unlock_ret; - } - - if (!ctrl->power_on) { - edp_ctrl_phy_aux_enable(ctrl, 1); - edp_ctrl_irq_enable(ctrl, 1); - } - - /* Initialize link rate as panel max link rate */ - ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; - - ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); - if (!ctrl->edid) { - pr_err("%s: edid read fail\n", __func__); - goto disable_ret; - } - - if (edid) - *edid = ctrl->edid; - -disable_ret: - if (!ctrl->power_on) { - edp_ctrl_irq_enable(ctrl, 0); - edp_ctrl_phy_aux_enable(ctrl, 0); - } -unlock_ret: - mutex_unlock(&ctrl->dev_mutex); - return 0; -} - -int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, - const struct drm_display_mode *mode, - const struct drm_display_info *info) -{ - u32 hstart_from_sync, vstart_from_sync; - u32 data; - int ret = 0; - - mutex_lock(&ctrl->dev_mutex); - /* - * Need to keep color depth, pixel rate and - * interlaced information in ctrl context - */ - ctrl->color_depth = info->bpc; - ctrl->pixel_rate = mode->clock; - ctrl->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); - - /* Fill initial link config based on passed in timing */ - edp_fill_link_cfg(ctrl); - - if (edp_clk_enable(ctrl, EDP_CLK_MASK_AHB)) { - pr_err("%s, fail to prepare enable ahb clk\n", __func__); - ret = -EINVAL; - goto unlock_ret; - } - edp_clock_synchrous(ctrl, 1); - - /* Configure eDP timing to HW */ - edp_write(ctrl->base + REG_EDP_TOTAL_HOR_VER, - EDP_TOTAL_HOR_VER_HORIZ(mode->htotal) | - EDP_TOTAL_HOR_VER_VERT(mode->vtotal)); - - vstart_from_sync = mode->vtotal - mode->vsync_start; - hstart_from_sync = mode->htotal - mode->hsync_start; - edp_write(ctrl->base + REG_EDP_START_HOR_VER_FROM_SYNC, - EDP_START_HOR_VER_FROM_SYNC_HORIZ(hstart_from_sync) | - EDP_START_HOR_VER_FROM_SYNC_VERT(vstart_from_sync)); - - data = EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT( - mode->vsync_end - mode->vsync_start); - data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ( - mode->hsync_end - mode->hsync_start); - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC; - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC; - edp_write(ctrl->base + REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY, data); - - edp_write(ctrl->base + REG_EDP_ACTIVE_HOR_VER, - EDP_ACTIVE_HOR_VER_HORIZ(mode->hdisplay) | - EDP_ACTIVE_HOR_VER_VERT(mode->vdisplay)); - - edp_clk_disable(ctrl, EDP_CLK_MASK_AHB); - -unlock_ret: - mutex_unlock(&ctrl->dev_mutex); - return ret; -} - -bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, - u32 pixel_rate, u32 *pm, u32 *pn) -{ - const struct edp_pixel_clk_div *divs; - u32 err = 1; /* 1% error tolerance */ - u32 clk_err; - int i; - - if (ctrl->link_rate == DP_LINK_BW_1_62) { - divs = clk_divs[0]; - } else if (ctrl->link_rate == DP_LINK_BW_2_7) { - divs = clk_divs[1]; - } else { - pr_err("%s: Invalid link rate,%d\n", __func__, ctrl->link_rate); - return false; - } - - for (i = 0; i < EDP_PIXEL_CLK_NUM; i++) { - clk_err = abs(divs[i].rate - pixel_rate); - if ((divs[i].rate * err / 100) >= clk_err) { - if (pm) - *pm = divs[i].m; - if (pn) - *pn = divs[i].n; - return true; - } - } - - DBG("pixel clock %d(kHz) not supported", pixel_rate); - - return false; -} - diff --git a/drivers/gpu/drm/msm/edp/edp_phy.c b/drivers/gpu/drm/msm/edp/edp_phy.c deleted file mode 100644 index fcaf7b7ecdd2..000000000000 --- a/drivers/gpu/drm/msm/edp/edp_phy.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. - */ - -#include "edp.h" -#include "edp.xml.h" - -#define EDP_MAX_LANE 4 - -struct edp_phy { - void __iomem *base; -}; - -bool msm_edp_phy_ready(struct edp_phy *phy) -{ - u32 status; - int cnt = 100; - - while (--cnt) { - status = edp_read(phy->base + - REG_EDP_PHY_GLB_PHY_STATUS); - if (status & 0x01) - break; - usleep_range(500, 1000); - } - - if (cnt == 0) { - pr_err("%s: PHY NOT ready\n", __func__); - return false; - } else { - return true; - } -} - -void msm_edp_phy_ctrl(struct edp_phy *phy, int enable) -{ - DBG("enable=%d", enable); - if (enable) { - /* Reset */ - edp_write(phy->base + REG_EDP_PHY_CTRL, - EDP_PHY_CTRL_SW_RESET | EDP_PHY_CTRL_SW_RESET_PLL); - /* Make sure fully reset */ - wmb(); - usleep_range(500, 1000); - edp_write(phy->base + REG_EDP_PHY_CTRL, 0x000); - edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0x3f); - edp_write(phy->base + REG_EDP_PHY_GLB_CFG, 0x1); - } else { - edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0xc0); - } -} - -/* voltage mode and pre emphasis cfg */ -void msm_edp_phy_vm_pe_init(struct edp_phy *phy) -{ - edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, 0x3); - edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, 0x64); - edp_write(phy->base + REG_EDP_PHY_GLB_MISC9, 0x6c); -} - -void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1) -{ - edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, v0); - edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, v1); -} - -void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane) -{ - u32 i; - u32 data; - - if (up) - data = 0; /* power up */ - else - data = 0x7; /* power down */ - - for (i = 0; i < max_lane; i++) - edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data); - - /* power down unused lane */ - data = 0x7; /* power down */ - for (i = max_lane; i < EDP_MAX_LANE; i++) - edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data); -} - -void *msm_edp_phy_init(struct device *dev, void __iomem *regbase) -{ - struct edp_phy *phy = NULL; - - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return NULL; - - phy->base = regbase; - return phy; -} - diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 75b64e6ae035..3acdeae25caf 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -8,6 +8,8 @@ #include <linux/of_irq.h> #include <linux/of_gpio.h> +#include <drm/drm_bridge_connector.h> + #include <sound/hdmi-codec.h> #include "hdmi.h" @@ -41,7 +43,7 @@ static irqreturn_t msm_hdmi_irq(int irq, void *dev_id) struct hdmi *hdmi = dev_id; /* Process HPD: */ - msm_hdmi_connector_irq(hdmi->connector); + msm_hdmi_hpd_irq(hdmi->bridge); /* Process DDC: */ msm_hdmi_i2c_irq(hdmi->i2c); @@ -281,7 +283,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - hdmi->connector = msm_hdmi_connector_init(hdmi); + hdmi->connector = drm_bridge_connector_init(hdmi->dev, encoder); if (IS_ERR(hdmi->connector)) { ret = PTR_ERR(hdmi->connector); DRM_DEV_ERROR(dev->dev, "failed to create HDMI connector: %d\n", ret); @@ -289,6 +291,8 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } + drm_connector_attach_encoder(hdmi->connector, hdmi->encoder); + hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); if (hdmi->irq < 0) { ret = hdmi->irq; @@ -305,7 +309,9 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, goto fail; } - ret = msm_hdmi_hpd_enable(hdmi->connector); + drm_bridge_connector_enable_hpd(hdmi->connector); + + ret = msm_hdmi_hpd_enable(hdmi->bridge); if (ret < 0) { DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret); goto fail; @@ -514,8 +520,7 @@ static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); struct hdmi_platform_config *hdmi_cfg; struct hdmi *hdmi; struct device_node *of_node = dev->of_node; @@ -586,8 +591,8 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) static void msm_hdmi_unbind(struct device *dev, struct device *master, void *data) { - struct drm_device *drm = dev_get_drvdata(master); - struct msm_drm_private *priv = drm->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(master); + if (priv->hdmi) { if (priv->hdmi->audio_pdev) platform_device_unregister(priv->hdmi->audio_pdev); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 82261078c6b1..736f348befb3 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -114,6 +114,13 @@ struct hdmi_platform_config { struct hdmi_gpio_data gpios[HDMI_MAX_NUM_GPIO]; }; +struct hdmi_bridge { + struct drm_bridge base; + struct hdmi *hdmi; + struct work_struct hpd_work; +}; +#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) + void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on); static inline void hdmi_write(struct hdmi *hdmi, u32 reg, u32 data) @@ -230,13 +237,11 @@ void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi); void msm_hdmi_bridge_destroy(struct drm_bridge *bridge); -/* - * hdmi connector: - */ - -void msm_hdmi_connector_irq(struct drm_connector *connector); -struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi); -int msm_hdmi_hpd_enable(struct drm_connector *connector); +void msm_hdmi_hpd_irq(struct drm_bridge *bridge); +enum drm_connector_status msm_hdmi_bridge_detect( + struct drm_bridge *bridge); +int msm_hdmi_hpd_enable(struct drm_bridge *bridge); +void msm_hdmi_hpd_disable(struct hdmi_bridge *hdmi_bridge); /* * i2c adapter for ddc: diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index f04eb4a70f0d..68fba4bf7212 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -5,17 +5,16 @@ */ #include <linux/delay.h> +#include <drm/drm_bridge_connector.h> +#include "msm_kms.h" #include "hdmi.h" -struct hdmi_bridge { - struct drm_bridge base; - struct hdmi *hdmi; -}; -#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) - void msm_hdmi_bridge_destroy(struct drm_bridge *bridge) { + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + + msm_hdmi_hpd_disable(hdmi_bridge); } static void msm_hdmi_power_on(struct drm_bridge *bridge) @@ -70,7 +69,7 @@ static void power_off(struct drm_bridge *bridge) if (ret) DRM_DEV_ERROR(dev->dev, "failed to disable pwr regulator: %d\n", ret); - pm_runtime_put_autosuspend(&hdmi->pdev->dev); + pm_runtime_put(&hdmi->pdev->dev); } #define AVI_IFRAME_LINE_NUMBER 1 @@ -251,14 +250,76 @@ static void msm_hdmi_bridge_mode_set(struct drm_bridge *bridge, msm_hdmi_audio_update(hdmi); } +static struct edid *msm_hdmi_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + struct edid *edid; + uint32_t hdmi_ctrl; + + hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); + hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); + + edid = drm_get_edid(connector, hdmi->i2c); + + hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); + + hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); + + return edid; +} + +static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + const struct hdmi_platform_config *config = hdmi->config; + struct msm_drm_private *priv = bridge->dev->dev_private; + struct msm_kms *kms = priv->kms; + long actual, requested; + + requested = 1000 * mode->clock; + actual = kms->funcs->round_pixclk(kms, + requested, hdmi_bridge->hdmi->encoder); + + /* for mdp5/apq8074, we manage our own pixel clk (as opposed to + * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder + * instead): + */ + if (config->pwr_clk_cnt > 0) + actual = clk_round_rate(hdmi->pwr_clks[0], actual); + + DBG("requested=%ld, actual=%ld", requested, actual); + + if (actual != requested) + return MODE_CLOCK_RANGE; + + return 0; +} + static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = { .pre_enable = msm_hdmi_bridge_pre_enable, .enable = msm_hdmi_bridge_enable, .disable = msm_hdmi_bridge_disable, .post_disable = msm_hdmi_bridge_post_disable, .mode_set = msm_hdmi_bridge_mode_set, + .mode_valid = msm_hdmi_bridge_mode_valid, + .get_edid = msm_hdmi_bridge_get_edid, + .detect = msm_hdmi_bridge_detect, }; +static void +msm_hdmi_hotplug_work(struct work_struct *work) +{ + struct hdmi_bridge *hdmi_bridge = + container_of(work, struct hdmi_bridge, hpd_work); + struct drm_bridge *bridge = &hdmi_bridge->base; + + drm_bridge_hpd_notify(bridge, drm_bridge_detect(bridge)); +} /* initialize bridge */ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi) @@ -275,11 +336,17 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi) } hdmi_bridge->hdmi = hdmi; + INIT_WORK(&hdmi_bridge->hpd_work, msm_hdmi_hotplug_work); bridge = &hdmi_bridge->base; bridge->funcs = &msm_hdmi_bridge_funcs; + bridge->ddc = hdmi->i2c; + bridge->type = DRM_MODE_CONNECTOR_HDMIA; + bridge->ops = DRM_BRIDGE_OP_HPD | + DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID; - ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, 0); + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c index a7f729cdec7b..75605ddac7c4 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_hpd.c @@ -11,13 +11,6 @@ #include "msm_kms.h" #include "hdmi.h" -struct hdmi_connector { - struct drm_connector base; - struct hdmi *hdmi; - struct work_struct hpd_work; -}; -#define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) - static void msm_hdmi_phy_reset(struct hdmi *hdmi) { unsigned int val; @@ -139,10 +132,10 @@ static void enable_hpd_clocks(struct hdmi *hdmi, bool enable) } } -int msm_hdmi_hpd_enable(struct drm_connector *connector) +int msm_hdmi_hpd_enable(struct drm_bridge *bridge) { - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - struct hdmi *hdmi = hdmi_connector->hdmi; + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; struct device *dev = &hdmi->pdev->dev; uint32_t hpd_ctrl; @@ -199,9 +192,9 @@ fail: return ret; } -static void hdp_disable(struct hdmi_connector *hdmi_connector) +void msm_hdmi_hpd_disable(struct hdmi_bridge *hdmi_bridge) { - struct hdmi *hdmi = hdmi_connector->hdmi; + struct hdmi *hdmi = hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; struct device *dev = &hdmi->pdev->dev; int ret; @@ -212,7 +205,7 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) msm_hdmi_set_mode(hdmi, false); enable_hpd_clocks(hdmi, false); - pm_runtime_put_autosuspend(dev); + pm_runtime_put(dev); ret = gpio_config(hdmi, false); if (ret) @@ -227,19 +220,10 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) dev_warn(dev, "failed to disable hpd regulator: %d\n", ret); } -static void -msm_hdmi_hotplug_work(struct work_struct *work) -{ - struct hdmi_connector *hdmi_connector = - container_of(work, struct hdmi_connector, hpd_work); - struct drm_connector *connector = &hdmi_connector->base; - drm_helper_hpd_irq_event(connector->dev); -} - -void msm_hdmi_connector_irq(struct drm_connector *connector) +void msm_hdmi_hpd_irq(struct drm_bridge *bridge) { - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - struct hdmi *hdmi = hdmi_connector->hdmi; + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; uint32_t hpd_int_status, hpd_int_ctrl; /* Process HPD: */ @@ -262,7 +246,7 @@ void msm_hdmi_connector_irq(struct drm_connector *connector) hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); - queue_work(hdmi->workq, &hdmi_connector->hpd_work); + queue_work(hdmi->workq, &hdmi_bridge->hpd_work); } } @@ -276,7 +260,7 @@ static enum drm_connector_status detect_reg(struct hdmi *hdmi) hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); enable_hpd_clocks(hdmi, false); - pm_runtime_put_autosuspend(&hdmi->pdev->dev); + pm_runtime_put(&hdmi->pdev->dev); return (hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED) ? connector_status_connected : connector_status_disconnected; @@ -293,11 +277,11 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi) connector_status_disconnected; } -static enum drm_connector_status hdmi_connector_detect( - struct drm_connector *connector, bool force) +enum drm_connector_status msm_hdmi_bridge_detect( + struct drm_bridge *bridge) { - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - struct hdmi *hdmi = hdmi_connector->hdmi; + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; const struct hdmi_platform_config *config = hdmi->config; struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX]; enum drm_connector_status stat_gpio, stat_reg; @@ -331,115 +315,3 @@ static enum drm_connector_status hdmi_connector_detect( return stat_gpio; } - -static void hdmi_connector_destroy(struct drm_connector *connector) -{ - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - - hdp_disable(hdmi_connector); - - drm_connector_cleanup(connector); - - kfree(hdmi_connector); -} - -static int msm_hdmi_connector_get_modes(struct drm_connector *connector) -{ - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - struct hdmi *hdmi = hdmi_connector->hdmi; - struct edid *edid; - uint32_t hdmi_ctrl; - int ret = 0; - - hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL); - hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE); - - edid = drm_get_edid(connector, hdmi->i2c); - - hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl); - - hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid); - drm_connector_update_edid_property(connector, edid); - - if (edid) { - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } - - return ret; -} - -static int msm_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); - struct hdmi *hdmi = hdmi_connector->hdmi; - const struct hdmi_platform_config *config = hdmi->config; - struct msm_drm_private *priv = connector->dev->dev_private; - struct msm_kms *kms = priv->kms; - long actual, requested; - - requested = 1000 * mode->clock; - actual = kms->funcs->round_pixclk(kms, - requested, hdmi_connector->hdmi->encoder); - - /* for mdp5/apq8074, we manage our own pixel clk (as opposed to - * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder - * instead): - */ - if (config->pwr_clk_cnt > 0) - actual = clk_round_rate(hdmi->pwr_clks[0], actual); - - DBG("requested=%ld, actual=%ld", requested, actual); - - if (actual != requested) - return MODE_CLOCK_RANGE; - - return 0; -} - -static const struct drm_connector_funcs hdmi_connector_funcs = { - .detect = hdmi_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = hdmi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs msm_hdmi_connector_helper_funcs = { - .get_modes = msm_hdmi_connector_get_modes, - .mode_valid = msm_hdmi_connector_mode_valid, -}; - -/* initialize connector */ -struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) -{ - struct drm_connector *connector = NULL; - struct hdmi_connector *hdmi_connector; - - hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL); - if (!hdmi_connector) - return ERR_PTR(-ENOMEM); - - hdmi_connector->hdmi = hdmi; - INIT_WORK(&hdmi_connector->hpd_work, msm_hdmi_hotplug_work); - - connector = &hdmi_connector->base; - - drm_connector_init_with_ddc(hdmi->dev, connector, - &hdmi_connector_funcs, - DRM_MODE_CONNECTOR_HDMIA, - hdmi->i2c); - drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs); - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT; - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - drm_connector_attach_encoder(connector, hdmi->encoder); - - return connector; -} diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index dee13fedee3b..0804c31e8962 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -15,6 +15,11 @@ #include "msm_gpu.h" #include "msm_kms.h" #include "msm_debugfs.h" +#include "disp/msm_disp_snapshot.h" + +/* + * GPU Snapshot: + */ struct msm_gpu_show_priv { struct msm_gpu_state *state; @@ -29,14 +34,14 @@ static int msm_gpu_show(struct seq_file *m, void *arg) struct msm_gpu *gpu = priv->gpu; int ret; - ret = mutex_lock_interruptible(&show_priv->dev->struct_mutex); + ret = mutex_lock_interruptible(&gpu->lock); if (ret) return ret; drm_printf(&p, "%s Status:\n", gpu->name); gpu->funcs->show(gpu, show_priv->state, &p); - mutex_unlock(&show_priv->dev->struct_mutex); + mutex_unlock(&gpu->lock); return 0; } @@ -48,9 +53,9 @@ static int msm_gpu_release(struct inode *inode, struct file *file) struct msm_drm_private *priv = show_priv->dev->dev_private; struct msm_gpu *gpu = priv->gpu; - mutex_lock(&show_priv->dev->struct_mutex); + mutex_lock(&gpu->lock); gpu->funcs->gpu_state_put(show_priv->state); - mutex_unlock(&show_priv->dev->struct_mutex); + mutex_unlock(&gpu->lock); kfree(show_priv); @@ -72,7 +77,7 @@ static int msm_gpu_open(struct inode *inode, struct file *file) if (!show_priv) return -ENOMEM; - ret = mutex_lock_interruptible(&dev->struct_mutex); + ret = mutex_lock_interruptible(&gpu->lock); if (ret) goto free_priv; @@ -81,7 +86,7 @@ static int msm_gpu_open(struct inode *inode, struct file *file) show_priv->state = gpu->funcs->gpu_state_get(gpu); pm_runtime_put_sync(&gpu->pdev->dev); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); if (IS_ERR(show_priv->state)) { ret = PTR_ERR(show_priv->state); @@ -109,6 +114,73 @@ static const struct file_operations msm_gpu_fops = { .release = msm_gpu_release, }; +/* + * Display Snapshot: + */ + +static int msm_kms_show(struct seq_file *m, void *arg) +{ + struct drm_printer p = drm_seq_file_printer(m); + struct msm_disp_state *state = m->private; + + msm_disp_state_print(state, &p); + + return 0; +} + +static int msm_kms_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = file->private_data; + struct msm_disp_state *state = m->private; + + msm_disp_state_free(state); + + return single_release(inode, file); +} + +static int msm_kms_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + struct msm_drm_private *priv = dev->dev_private; + struct msm_disp_state *state; + int ret; + + if (!priv->kms) + return -ENODEV; + + ret = mutex_lock_interruptible(&priv->kms->dump_mutex); + if (ret) + return ret; + + state = msm_disp_snapshot_state_sync(priv->kms); + + mutex_unlock(&priv->kms->dump_mutex); + + if (IS_ERR(state)) { + return PTR_ERR(state); + } + + ret = single_open(file, msm_kms_show, state); + if (ret) { + msm_disp_state_free(state); + return ret; + } + + return 0; +} + +static const struct file_operations msm_kms_fops = { + .owner = THIS_MODULE, + .open = msm_kms_open, + .read = seq_read, + .llseek = seq_lseek, + .release = msm_kms_release, +}; + +/* + * Other debugfs: + */ + static unsigned long last_shrink_freed; static int @@ -134,8 +206,10 @@ DEFINE_SIMPLE_ATTRIBUTE(shrink_fops, "0x%08llx\n"); -static int msm_gem_show(struct drm_device *dev, struct seq_file *m) +static int msm_gem_show(struct seq_file *m, void *arg) { + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; struct msm_drm_private *priv = dev->dev_private; int ret; @@ -150,8 +224,10 @@ static int msm_gem_show(struct drm_device *dev, struct seq_file *m) return 0; } -static int msm_mm_show(struct drm_device *dev, struct seq_file *m) +static int msm_mm_show(struct seq_file *m, void *arg) { + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; struct drm_printer p = drm_seq_file_printer(m); drm_mm_print(&dev->vma_offset_manager->vm_addr_space_mm, &p); @@ -159,8 +235,10 @@ static int msm_mm_show(struct drm_device *dev, struct seq_file *m) return 0; } -static int msm_fb_show(struct drm_device *dev, struct seq_file *m) +static int msm_fb_show(struct seq_file *m, void *arg) { + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; struct msm_drm_private *priv = dev->dev_private; struct drm_framebuffer *fb, *fbdev_fb = NULL; @@ -183,29 +261,10 @@ static int msm_fb_show(struct drm_device *dev, struct seq_file *m) return 0; } -static int show_locked(struct seq_file *m, void *arg) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - int (*show)(struct drm_device *dev, struct seq_file *m) = - node->info_ent->data; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; - - ret = show(dev, m); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - static struct drm_info_list msm_debugfs_list[] = { - {"gem", show_locked, 0, msm_gem_show}, - { "mm", show_locked, 0, msm_mm_show }, - { "fb", show_locked, 0, msm_fb_show }, + {"gem", msm_gem_show}, + { "mm", msm_mm_show }, + { "fb", msm_fb_show }, }; static int late_init_minor(struct drm_minor *minor) @@ -252,9 +311,15 @@ void msm_debugfs_init(struct drm_minor *minor) debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, dev, &msm_gpu_fops); + debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, + dev, &msm_kms_fops); + debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root, &priv->hangcheck_period); + debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root, + &priv->disable_err_irq); + debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, dev, &shrink_fops); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 892c04365239..ad35a5d94053 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -339,10 +339,9 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, static int msm_drm_uninit(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); - struct drm_device *ddev = platform_get_drvdata(pdev); - struct msm_drm_private *priv = ddev->dev_private; + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct drm_device *ddev = priv->dev; struct msm_kms *kms = priv->kms; - struct msm_mdss *mdss = priv->mdss; int i; /* @@ -402,14 +401,10 @@ static int msm_drm_uninit(struct device *dev) component_unbind_all(dev, ddev); - if (mdss && mdss->funcs) - mdss->funcs->destroy(ddev); - ddev->dev_private = NULL; drm_dev_put(ddev); destroy_workqueue(priv->wq); - kfree(priv); return 0; } @@ -512,8 +507,8 @@ static int msm_init_vram(struct drm_device *dev) static int msm_drm_init(struct device *dev, const struct drm_driver *drv) { struct platform_device *pdev = to_platform_device(dev); + struct msm_drm_private *priv = dev_get_drvdata(dev); struct drm_device *ddev; - struct msm_drm_private *priv; struct msm_kms *kms; struct msm_mdss *mdss; int ret, i; @@ -523,32 +518,9 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) DRM_DEV_ERROR(dev, "failed to allocate drm_device\n"); return PTR_ERR(ddev); } - - platform_set_drvdata(pdev, ddev); - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_put_drm_dev; - } - ddev->dev_private = priv; priv->dev = ddev; - switch (get_mdp_ver(pdev)) { - case KMS_MDP5: - ret = mdp5_mdss_init(ddev); - break; - case KMS_DPU: - ret = dpu_mdss_init(ddev); - break; - default: - ret = 0; - break; - } - if (ret) - goto err_free_priv; - mdss = priv->mdss; priv->wq = alloc_ordered_workqueue("msm", 0); @@ -571,12 +543,12 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) ret = msm_init_vram(ddev); if (ret) - goto err_destroy_mdss; + return ret; /* Bind all our sub-components: */ ret = component_bind_all(dev, ddev); if (ret) - goto err_destroy_mdss; + return ret; dma_set_max_seg_size(dev, UINT_MAX); @@ -682,15 +654,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) err_msm_uninit: msm_drm_uninit(dev); return ret; -err_destroy_mdss: - if (mdss && mdss->funcs) - mdss->funcs->destroy(ddev); -err_free_priv: - kfree(priv); -err_put_drm_dev: - drm_dev_put(ddev); - platform_set_drvdata(pdev, NULL); - return ret; } /* @@ -752,14 +715,8 @@ static void context_close(struct msm_file_private *ctx) static void msm_postclose(struct drm_device *dev, struct drm_file *file) { - struct msm_drm_private *priv = dev->dev_private; struct msm_file_private *ctx = file->driver_priv; - mutex_lock(&dev->struct_mutex); - if (ctx == priv->lastctx) - priv->lastctx = NULL; - mutex_unlock(&dev->struct_mutex); - context_close(ctx); } @@ -973,7 +930,7 @@ static int wait_fence(struct msm_gpu_submitqueue *queue, uint32_t fence_id, struct dma_fence *fence; int ret; - if (fence_id > queue->last_fence) { + if (fence_after(fence_id, queue->last_fence)) { DRM_ERROR_RATELIMITED("waiting on invalid fence: %u (of %u)\n", fence_id, queue->last_fence); return -EINVAL; @@ -1142,8 +1099,7 @@ static const struct drm_driver msm_driver = { static int __maybe_unused msm_runtime_suspend(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); - struct msm_drm_private *priv = ddev->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(dev); struct msm_mdss *mdss = priv->mdss; DBG(""); @@ -1156,8 +1112,7 @@ static int __maybe_unused msm_runtime_suspend(struct device *dev) static int __maybe_unused msm_runtime_resume(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); - struct msm_drm_private *priv = ddev->dev_private; + struct msm_drm_private *priv = dev_get_drvdata(dev); struct msm_mdss *mdss = priv->mdss; DBG(""); @@ -1187,8 +1142,8 @@ static int __maybe_unused msm_pm_resume(struct device *dev) static int __maybe_unused msm_pm_prepare(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); - struct msm_drm_private *priv = ddev ? ddev->dev_private : NULL; + struct msm_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *ddev = priv ? priv->dev : NULL; if (!priv || !priv->kms) return 0; @@ -1198,8 +1153,8 @@ static int __maybe_unused msm_pm_prepare(struct device *dev) static void __maybe_unused msm_pm_complete(struct device *dev) { - struct drm_device *ddev = dev_get_drvdata(dev); - struct msm_drm_private *priv = ddev ? ddev->dev_private : NULL; + struct msm_drm_private *priv = dev_get_drvdata(dev); + struct drm_device *ddev = priv ? priv->dev : NULL; if (!priv || !priv->kms) return; @@ -1292,9 +1247,10 @@ static int add_components_mdp(struct device *mdp_dev, return 0; } -static int compare_name_mdp(struct device *dev, void *data) +static int find_mdp_node(struct device *dev, void *data) { - return (strstr(dev_name(dev), "mdp") != NULL); + return of_match_node(dpu_dt_match, dev->of_node) || + of_match_node(mdp5_dt_match, dev->of_node); } static int add_display_components(struct platform_device *pdev, @@ -1319,7 +1275,7 @@ static int add_display_components(struct platform_device *pdev, return ret; } - mdp_dev = device_find_child(dev, NULL, compare_name_mdp); + mdp_dev = device_find_child(dev, NULL, find_mdp_node); if (!mdp_dev) { DRM_DEV_ERROR(dev, "failed to find MDSS MDP node\n"); of_platform_depopulate(dev); @@ -1397,12 +1353,35 @@ static const struct component_master_ops msm_drm_ops = { static int msm_pdev_probe(struct platform_device *pdev) { struct component_match *match = NULL; + struct msm_drm_private *priv; int ret; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + switch (get_mdp_ver(pdev)) { + case KMS_MDP5: + ret = mdp5_mdss_init(pdev); + break; + case KMS_DPU: + ret = dpu_mdss_init(pdev); + break; + default: + ret = 0; + break; + } + if (ret) { + platform_set_drvdata(pdev, NULL); + return ret; + } + if (get_mdp_ver(pdev)) { ret = add_display_components(pdev, &match); if (ret) - return ret; + goto fail; } ret = add_gpu_components(&pdev->dev, &match); @@ -1424,21 +1403,31 @@ static int msm_pdev_probe(struct platform_device *pdev) fail: of_platform_depopulate(&pdev->dev); + + if (priv->mdss && priv->mdss->funcs) + priv->mdss->funcs->destroy(priv->mdss); + return ret; } static int msm_pdev_remove(struct platform_device *pdev) { + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct msm_mdss *mdss = priv->mdss; + component_master_del(&pdev->dev, &msm_drm_ops); of_platform_depopulate(&pdev->dev); + if (mdss && mdss->funcs) + mdss->funcs->destroy(mdss); + return 0; } static void msm_pdev_shutdown(struct platform_device *pdev) { - struct drm_device *drm = platform_get_drvdata(pdev); - struct msm_drm_private *priv = drm ? drm->dev_private : NULL; + struct msm_drm_private *priv = platform_get_drvdata(pdev); + struct drm_device *drm = priv ? priv->dev : NULL; if (!priv || !priv->kms) return; @@ -1478,7 +1467,6 @@ static int __init msm_drm_register(void) msm_mdp_register(); msm_dpu_register(); msm_dsi_register(); - msm_edp_register(); msm_hdmi_register(); msm_dp_register(); adreno_register(); @@ -1492,7 +1480,6 @@ static void __exit msm_drm_unregister(void) msm_dp_unregister(); msm_hdmi_unregister(); adreno_unregister(); - msm_edp_unregister(); msm_dsi_unregister(); msm_mdp_unregister(); msm_dpu_unregister(); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index eb984d925f4d..d7574e6bd4e4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -151,12 +151,6 @@ struct msm_drm_private { */ struct hdmi *hdmi; - /* eDP is for mdp5 only, but kms has not been created - * when edp_bind() and edp_init() are called. Here is the only - * place to keep the edp instance. - */ - struct msm_edp *edp; - /* DSI is shared by mdp4 and mdp5 */ struct msm_dsi *dsi[2]; @@ -164,7 +158,7 @@ struct msm_drm_private { /* when we have more than one 'msm_gpu' these need to be an array: */ struct msm_gpu *gpu; - struct msm_file_private *lastctx; + /* gpu is only set on open(), but we need this info earlier */ bool is_a2xx; bool has_cached_coherent; @@ -246,6 +240,15 @@ struct msm_drm_private { /* For hang detection, in ms */ unsigned int hangcheck_period; + + /** + * disable_err_irq: + * + * Disable handling of GPU hw error interrupts, to force fallback to + * sw hangcheck timer. Written (via debugfs) by igt tests to test + * the sw hangcheck mechanism. + */ + bool disable_err_irq; }; struct msm_format { @@ -335,12 +338,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev, void __init msm_hdmi_register(void); void __exit msm_hdmi_unregister(void); -struct msm_edp; -void __init msm_edp_register(void); -void __exit msm_edp_unregister(void); -int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev, - struct drm_encoder *encoder); - struct msm_dsi; #ifdef CONFIG_DRM_MSM_DSI int dsi_dev_attach(struct platform_device *pdev); @@ -392,8 +389,12 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder); int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder); int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder); void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); + +struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, + struct drm_device *dev, + struct drm_encoder *encoder); void msm_dp_irq_postinstall(struct msm_dp *dp_display); void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display); @@ -430,8 +431,8 @@ static inline int msm_dp_display_pre_disable(struct msm_dp *dp, } static inline void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { } diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 0daaeb54ff6f..4c39ef9dd75d 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -81,8 +81,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, bo = msm_framebuffer_bo(fb, 0); - mutex_lock(&dev->struct_mutex); - /* * NOTE: if we can be guaranteed to be able to map buffer * in panic (ie. lock-safe, etc) we could avoid pinning the @@ -91,14 +89,14 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, ret = msm_gem_get_and_pin_iova(bo, priv->kms->aspace, &paddr); if (ret) { DRM_DEV_ERROR(dev->dev, "failed to get buffer obj iova: %d\n", ret); - goto fail_unlock; + goto fail; } fbi = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(fbi)) { DRM_DEV_ERROR(dev->dev, "failed to allocate fb info\n"); ret = PTR_ERR(fbi); - goto fail_unlock; + goto fail; } DBG("fbi=%p, dev=%p", fbi, dev); @@ -115,7 +113,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fbi->screen_base = msm_gem_get_vaddr(bo); if (IS_ERR(fbi->screen_base)) { ret = PTR_ERR(fbi->screen_base); - goto fail_unlock; + goto fail; } fbi->screen_size = bo->size; fbi->fix.smem_start = paddr; @@ -124,12 +122,9 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); - mutex_unlock(&dev->struct_mutex); - return 0; -fail_unlock: - mutex_unlock(&dev->struct_mutex); +fail: drm_framebuffer_remove(fb); return ret; } diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 4783db528bcc..17ee3822b423 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -60,4 +60,16 @@ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); struct dma_fence * msm_fence_alloc(struct msm_fence_context *fctx); +static inline bool +fence_before(uint32_t a, uint32_t b) +{ + return (int32_t)(a - b) < 0; +} + +static inline bool +fence_after(uint32_t a, uint32_t b) +{ + return (int32_t)(a - b) > 0; +} + #endif diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 282628d6b72c..6cfa984dee6a 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -881,7 +881,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, * to the underlying fence. */ submit->fence_id = idr_alloc_cyclic(&queue->fence_idr, - submit->user_fence, 0, INT_MAX, GFP_KERNEL); + submit->user_fence, 1, INT_MAX, GFP_KERNEL); if (submit->fence_id < 0) { ret = submit->fence_id = 0; submit->fence_id = 0; diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 2c46cd968ac4..0f78c2615272 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -150,7 +150,7 @@ int msm_gpu_hw_init(struct msm_gpu *gpu) { int ret; - WARN_ON(!mutex_is_locked(&gpu->dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&gpu->lock)); if (!gpu->needs_hw_init) return 0; @@ -172,7 +172,7 @@ static void update_fences(struct msm_gpu *gpu, struct msm_ringbuffer *ring, spin_lock_irqsave(&ring->submit_lock, flags); list_for_each_entry(submit, &ring->submits, node) { - if (submit->seqno > fence) + if (fence_after(submit->seqno, fence)) break; msm_update_fence(submit->ring->fctx, @@ -361,7 +361,7 @@ static void recover_worker(struct kthread_work *work) char *comm = NULL, *cmd = NULL; int i; - mutex_lock(&dev->struct_mutex); + mutex_lock(&gpu->lock); DRM_DEV_ERROR(dev->dev, "%s: hangcheck recover!\n", gpu->name); @@ -442,7 +442,7 @@ static void recover_worker(struct kthread_work *work) } } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); msm_gpu_retire(gpu); } @@ -450,12 +450,11 @@ static void recover_worker(struct kthread_work *work) static void fault_worker(struct kthread_work *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, fault_work); - struct drm_device *dev = gpu->dev; struct msm_gem_submit *submit; struct msm_ringbuffer *cur_ring = gpu->funcs->active_ring(gpu); char *comm = NULL, *cmd = NULL; - mutex_lock(&dev->struct_mutex); + mutex_lock(&gpu->lock); submit = find_submit(cur_ring, cur_ring->memptrs->fence + 1); if (submit && submit->fault_dumped) @@ -490,7 +489,7 @@ resume_smmu: memset(&gpu->fault_info, 0, sizeof(gpu->fault_info)); gpu->aspace->mmu->funcs->resume_translation(gpu->aspace->mmu); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); } static void hangcheck_timer_reset(struct msm_gpu *gpu) @@ -510,7 +509,7 @@ static void hangcheck_handler(struct timer_list *t) if (fence != ring->hangcheck_fence) { /* some progress has been made.. ya! */ ring->hangcheck_fence = fence; - } else if (fence < ring->seqno) { + } else if (fence_before(fence, ring->seqno)) { /* no progress and not done.. hung! */ ring->hangcheck_fence = fence; DRM_DEV_ERROR(dev->dev, "%s: hangcheck detected gpu lockup rb %d!\n", @@ -524,7 +523,7 @@ static void hangcheck_handler(struct timer_list *t) } /* if still more pending work, reset the hangcheck timer: */ - if (ring->seqno > ring->hangcheck_fence) + if (fence_after(ring->seqno, ring->hangcheck_fence)) hangcheck_timer_reset(gpu); /* workaround for missing irq: */ @@ -733,7 +732,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) struct msm_ringbuffer *ring = submit->ring; unsigned long flags; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&gpu->lock)); pm_runtime_get_sync(&gpu->pdev->dev); @@ -763,7 +762,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) mutex_unlock(&gpu->active_lock); gpu->funcs->submit(gpu, submit); - priv->lastctx = submit->queue->ctx; + gpu->cur_ctx_seqno = submit->queue->ctx->seqno; hangcheck_timer_reset(gpu); } @@ -848,6 +847,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, INIT_LIST_HEAD(&gpu->active_list); mutex_init(&gpu->active_lock); + mutex_init(&gpu->lock); kthread_init_work(&gpu->retire_work, retire_worker); kthread_init_work(&gpu->recover_work, recover_worker); kthread_init_work(&gpu->fault_work, fault_worker); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 48ea2de911f1..445c6bfd4b6b 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -88,6 +88,21 @@ struct msm_gpu_devfreq { struct devfreq *devfreq; /** + * idle_constraint: + * + * A PM QoS constraint to limit max freq while the GPU is idle. + */ + struct dev_pm_qos_request idle_freq; + + /** + * boost_constraint: + * + * A PM QoS constraint to boost min freq for a period of time + * until the boost expires. + */ + struct dev_pm_qos_request boost_freq; + + /** * busy_cycles: * * Used by implementation of gpu->gpu_busy() to track the last @@ -103,22 +118,19 @@ struct msm_gpu_devfreq { ktime_t idle_time; /** - * idle_freq: + * idle_work: * - * Shadow frequency used while the GPU is idle. From the PoV of - * the devfreq governor, we are continuing to sample busyness and - * adjust frequency while the GPU is idle, but we use this shadow - * value as the GPU is actually clamped to minimum frequency while - * it is inactive. + * Used to delay clamping to idle freq on active->idle transition. */ - unsigned long idle_freq; + struct msm_hrtimer_work idle_work; /** - * idle_work: + * boost_work: * - * Used to delay clamping to idle freq on active->idle transition. + * Used to reset the boost_constraint after the boost period has + * elapsed */ - struct msm_hrtimer_work idle_work; + struct msm_hrtimer_work boost_work; }; struct msm_gpu { @@ -144,6 +156,17 @@ struct msm_gpu { struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS]; int nr_rings; + /** + * cur_ctx_seqno: + * + * The ctx->seqno value of the last context to submit rendering, + * and the one with current pgtables installed (for generations + * that support per-context pgtables). Tracked by seqno rather + * than pointer value to avoid dangling pointers, and cases where + * a ctx can be freed and a new one created with the same address. + */ + int cur_ctx_seqno; + /* * List of GEM active objects on this gpu. Protected by * msm_drm_private::mm_lock @@ -151,12 +174,22 @@ struct msm_gpu { struct list_head active_list; /** + * lock: + * + * General lock for serializing all the gpu things. + * + * TODO move to per-ring locking where feasible (ie. submit/retire + * path, etc) + */ + struct mutex lock; + + /** * active_submits: * * The number of submitted but not yet retired submits, used to * determine transitions between active and idle. * - * Protected by lock + * Protected by active_lock */ int active_submits; @@ -241,7 +274,7 @@ static inline bool msm_gpu_active(struct msm_gpu *gpu) for (i = 0; i < gpu->nr_rings; i++) { struct msm_ringbuffer *ring = gpu->rb[i]; - if (ring->seqno > ring->memptrs->fence) + if (fence_after(ring->seqno, ring->memptrs->fence)) return true; } @@ -501,6 +534,7 @@ void msm_devfreq_init(struct msm_gpu *gpu); void msm_devfreq_cleanup(struct msm_gpu *gpu); void msm_devfreq_resume(struct msm_gpu *gpu); void msm_devfreq_suspend(struct msm_gpu *gpu); +void msm_devfreq_boost(struct msm_gpu *gpu, unsigned factor); void msm_devfreq_active(struct msm_gpu *gpu); void msm_devfreq_idle(struct msm_gpu *gpu); @@ -537,28 +571,28 @@ static inline struct msm_gpu_state *msm_gpu_crashstate_get(struct msm_gpu *gpu) { struct msm_gpu_state *state = NULL; - mutex_lock(&gpu->dev->struct_mutex); + mutex_lock(&gpu->lock); if (gpu->crashstate) { kref_get(&gpu->crashstate->ref); state = gpu->crashstate; } - mutex_unlock(&gpu->dev->struct_mutex); + mutex_unlock(&gpu->lock); return state; } static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu) { - mutex_lock(&gpu->dev->struct_mutex); + mutex_lock(&gpu->lock); if (gpu->crashstate) { if (gpu->funcs->gpu_state_put(gpu->crashstate)) gpu->crashstate = NULL; } - mutex_unlock(&gpu->dev->struct_mutex); + mutex_unlock(&gpu->lock); } /* diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index 384e90c4b2a7..62405e980925 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -9,6 +9,7 @@ #include <linux/devfreq.h> #include <linux/devfreq_cooling.h> +#include <linux/units.h> /* * Power Management: @@ -25,17 +26,6 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, * to something that actually is in the opp table: */ opp = devfreq_recommended_opp(dev, freq, flags); - - /* - * If the GPU is idle, devfreq is not aware, so just ignore - * it's requests - */ - if (gpu->devfreq.idle_freq) { - gpu->devfreq.idle_freq = *freq; - dev_pm_opp_put(opp); - return 0; - } - if (IS_ERR(opp)) return PTR_ERR(opp); @@ -53,9 +43,6 @@ static int msm_devfreq_target(struct device *dev, unsigned long *freq, static unsigned long get_freq(struct msm_gpu *gpu) { - if (gpu->devfreq.idle_freq) - return gpu->devfreq.idle_freq; - if (gpu->funcs->gpu_get_freq) return gpu->funcs->gpu_get_freq(gpu); @@ -93,6 +80,7 @@ static struct devfreq_dev_profile msm_devfreq_profile = { .get_cur_freq = msm_devfreq_get_cur_freq, }; +static void msm_devfreq_boost_work(struct kthread_work *work); static void msm_devfreq_idle_work(struct kthread_work *work); void msm_devfreq_init(struct msm_gpu *gpu) @@ -103,6 +91,12 @@ void msm_devfreq_init(struct msm_gpu *gpu) if (!gpu->funcs->gpu_busy) return; + dev_pm_qos_add_request(&gpu->pdev->dev, &df->idle_freq, + DEV_PM_QOS_MAX_FREQUENCY, + PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); + dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, + DEV_PM_QOS_MIN_FREQUENCY, 0); + msm_devfreq_profile.initial_freq = gpu->fast_rate; /* @@ -133,13 +127,19 @@ void msm_devfreq_init(struct msm_gpu *gpu) gpu->cooling = NULL; } + msm_hrtimer_work_init(&df->boost_work, gpu->worker, msm_devfreq_boost_work, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); msm_hrtimer_work_init(&df->idle_work, gpu->worker, msm_devfreq_idle_work, CLOCK_MONOTONIC, HRTIMER_MODE_REL); } void msm_devfreq_cleanup(struct msm_gpu *gpu) { + struct msm_gpu_devfreq *df = &gpu->devfreq; + devfreq_cooling_unregister(gpu->cooling); + dev_pm_qos_remove_request(&df->boost_freq); + dev_pm_qos_remove_request(&df->idle_freq); } void msm_devfreq_resume(struct msm_gpu *gpu) @@ -155,12 +155,40 @@ void msm_devfreq_suspend(struct msm_gpu *gpu) devfreq_suspend_device(gpu->devfreq.devfreq); } +static void msm_devfreq_boost_work(struct kthread_work *work) +{ + struct msm_gpu_devfreq *df = container_of(work, + struct msm_gpu_devfreq, boost_work.work); + + dev_pm_qos_update_request(&df->boost_freq, 0); +} + +void msm_devfreq_boost(struct msm_gpu *gpu, unsigned factor) +{ + struct msm_gpu_devfreq *df = &gpu->devfreq; + uint64_t freq; + + freq = get_freq(gpu); + freq *= factor; + + /* + * A nice little trap is that PM QoS operates in terms of KHz, + * while devfreq operates in terms of Hz: + */ + do_div(freq, HZ_PER_KHZ); + + dev_pm_qos_update_request(&df->boost_freq, freq); + + msm_hrtimer_queue_work(&df->boost_work, + ms_to_ktime(msm_devfreq_profile.polling_ms), + HRTIMER_MODE_REL); +} + void msm_devfreq_active(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; struct devfreq_dev_status status; unsigned int idle_time; - unsigned long target_freq = df->idle_freq; if (!df->devfreq) return; @@ -170,12 +198,6 @@ void msm_devfreq_active(struct msm_gpu *gpu) */ hrtimer_cancel(&df->idle_work.timer); - /* - * Hold devfreq lock to synchronize with get_dev_status()/ - * target() callbacks - */ - mutex_lock(&df->devfreq->lock); - idle_time = ktime_to_ms(ktime_sub(ktime_get(), df->idle_time)); /* @@ -183,21 +205,18 @@ void msm_devfreq_active(struct msm_gpu *gpu) * interval, then we won't meet the threshold of busyness for * the governor to ramp up the freq.. so give some boost */ - if (idle_time > msm_devfreq_profile.polling_ms/2) { - target_freq *= 2; + if (idle_time > msm_devfreq_profile.polling_ms) { + msm_devfreq_boost(gpu, 2); } - df->idle_freq = 0; - - msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); + dev_pm_qos_update_request(&df->idle_freq, + PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); /* * Reset the polling interval so we aren't inconsistent * about freq vs busy/total cycles */ msm_devfreq_get_dev_status(&gpu->pdev->dev, &status); - - mutex_unlock(&df->devfreq->lock); } @@ -206,23 +225,11 @@ static void msm_devfreq_idle_work(struct kthread_work *work) struct msm_gpu_devfreq *df = container_of(work, struct msm_gpu_devfreq, idle_work.work); struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq); - unsigned long idle_freq, target_freq = 0; - - /* - * Hold devfreq lock to synchronize with get_dev_status()/ - * target() callbacks - */ - mutex_lock(&df->devfreq->lock); - - idle_freq = get_freq(gpu); - - if (gpu->clamp_to_idle) - msm_devfreq_target(&gpu->pdev->dev, &target_freq, 0); df->idle_time = ktime_get(); - df->idle_freq = idle_freq; - mutex_unlock(&df->devfreq->lock); + if (gpu->clamp_to_idle) + dev_pm_qos_update_request(&df->idle_freq, 0); } void msm_devfreq_idle(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 6a42b819abc4..2a4f0526cb98 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -198,19 +198,22 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev); struct msm_kms *mdp5_kms_init(struct drm_device *dev); struct msm_kms *dpu_kms_init(struct drm_device *dev); +extern const struct of_device_id dpu_dt_match[]; +extern const struct of_device_id mdp5_dt_match[]; + struct msm_mdss_funcs { int (*enable)(struct msm_mdss *mdss); int (*disable)(struct msm_mdss *mdss); - void (*destroy)(struct drm_device *dev); + void (*destroy)(struct msm_mdss *mdss); }; struct msm_mdss { - struct drm_device *dev; + struct device *dev; const struct msm_mdss_funcs *funcs; }; -int mdp5_mdss_init(struct drm_device *dev); -int dpu_mdss_init(struct drm_device *dev); +int mdp5_mdss_init(struct platform_device *dev); +int dpu_mdss_init(struct platform_device *dev); #define for_each_crtc_mask(dev, crtc, crtc_mask) \ drm_for_each_crtc(crtc, dev) \ diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index 3a27153eef08..3d3da79fec2a 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -155,9 +155,12 @@ static int perf_open(struct inode *inode, struct file *file) struct msm_gpu *gpu = priv->gpu; int ret = 0; - mutex_lock(&dev->struct_mutex); + if (!gpu) + return -ENODEV; - if (perf->open || !gpu) { + mutex_lock(&gpu->lock); + + if (perf->open) { ret = -EBUSY; goto out; } @@ -171,7 +174,7 @@ static int perf_open(struct inode *inode, struct file *file) perf->next_jiffies = jiffies + SAMPLE_TIME; out: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); return ret; } diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index b55398a34fa4..81432ec07012 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -86,7 +86,7 @@ struct msm_rd_state { struct msm_gem_submit *submit; /* fifo access is synchronized on the producer side by - * struct_mutex held by submit code (otherwise we could + * gpu->lock held by submit code (otherwise we could * end up w/ cmds logged in different order than they * were executed). And read_lock synchronizes the reads */ @@ -181,9 +181,12 @@ static int rd_open(struct inode *inode, struct file *file) uint32_t gpu_id; int ret = 0; - mutex_lock(&dev->struct_mutex); + if (!gpu) + return -ENODEV; - if (rd->open || !gpu) { + mutex_lock(&gpu->lock); + + if (rd->open) { ret = -EBUSY; goto out; } @@ -200,7 +203,7 @@ static int rd_open(struct inode *inode, struct file *file) rd_write_section(rd, RD_GPU_ID, &gpu_id, sizeof(gpu_id)); out: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&gpu->lock); return ret; } @@ -340,11 +343,10 @@ out_unlock: msm_gem_unlock(&obj->base); } -/* called under struct_mutex */ +/* called under gpu->lock */ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, const char *fmt, ...) { - struct drm_device *dev = submit->dev; struct task_struct *task; char msg[256]; int i, n; @@ -355,7 +357,7 @@ void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, /* writing into fifo is serialized by caller, and * rd->read_lock is used to serialize the reads */ - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&submit->gpu->lock)); if (fmt) { va_list args; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 652b1dedd7c1..3bbf574c3bdc 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -21,11 +21,11 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) pm_runtime_get_sync(&gpu->pdev->dev); /* TODO move submit path over to using a per-ring lock.. */ - mutex_lock(&gpu->dev->struct_mutex); + mutex_lock(&gpu->lock); msm_gpu_submit(gpu, submit); - mutex_unlock(&gpu->dev->struct_mutex); + mutex_unlock(&gpu->lock); pm_runtime_put(&gpu->pdev->dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 26f9299df881..a3a04e0d76ec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -344,38 +344,48 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, { struct nouveau_fence_chan *fctx = chan->fence; struct dma_resv *resv = nvbo->bo.base.resv; - struct dma_resv_iter cursor; - struct dma_fence *fence; - struct nouveau_fence *f; - int ret; + int i, ret; if (!exclusive) { ret = dma_resv_reserve_shared(resv, 1); - if (ret) return ret; } - dma_resv_for_each_fence(&cursor, resv, exclusive, fence) { - struct nouveau_channel *prev = NULL; - bool must_wait = true; - - f = nouveau_local_fence(fence, chan->drm); - if (f) { - rcu_read_lock(); - prev = rcu_dereference(f->channel); - if (prev && (prev == chan || - fctx->sync(f, prev, chan) == 0)) - must_wait = false; - rcu_read_unlock(); - } + /* Waiting for the exclusive fence first causes performance regressions + * under some circumstances. So manually wait for the shared ones first. + */ + for (i = 0; i < 2; ++i) { + struct dma_resv_iter cursor; + struct dma_fence *fence; + + dma_resv_for_each_fence(&cursor, resv, exclusive, fence) { + struct nouveau_fence *f; + + if (i == 0 && dma_resv_iter_is_exclusive(&cursor)) + continue; + + f = nouveau_local_fence(fence, chan->drm); + if (f) { + struct nouveau_channel *prev; + bool must_wait = true; + + rcu_read_lock(); + prev = rcu_dereference(f->channel); + if (prev && (prev == chan || + fctx->sync(f, prev, chan) == 0)) + must_wait = false; + rcu_read_unlock(); + if (!must_wait) + continue; + } - if (must_wait) { ret = dma_fence_wait(fence, intr); if (ret) return ret; } } + return 0; } diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index b64d93da651d..5e2b0175df36 100644 --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c @@ -658,8 +658,10 @@ int sun8i_hdmi_phy_get(struct sun8i_dw_hdmi *hdmi, struct device_node *node) return -EPROBE_DEFER; phy = platform_get_drvdata(pdev); - if (!phy) + if (!phy) { + put_device(&pdev->dev); return -EPROBE_DEFER; + } hdmi->phy = phy; diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index b977f5c94562..04146da2d1d8 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -459,7 +459,7 @@ static struct drm_display_mode simpledrm_mode(unsigned int width, { struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; - mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay; + mode.clock = mode.hdisplay * mode.vdisplay * 60 / 1000 /* kHz */; drm_mode_set_name(&mode); return mode; diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c index 0037eefe3239..a3ad7c9736ec 100644 --- a/drivers/gpu/drm/ttm/ttm_module.c +++ b/drivers/gpu/drm/ttm/ttm_module.c @@ -68,9 +68,11 @@ pgprot_t ttm_prot_from_caching(enum ttm_caching caching, pgprot_t tmp) #if defined(__i386__) || defined(__x86_64__) if (caching == ttm_write_combined) tmp = pgprot_writecombine(tmp); +#ifndef CONFIG_UML else if (boot_cpu_data.x86 > 3) tmp = pgprot_noncached(tmp); -#endif +#endif /* CONFIG_UML */ +#endif /* __i386__ || __x86_64__ */ #if defined(__ia64__) || defined(__arm__) || defined(__aarch64__) || \ defined(__powerpc__) || defined(__mips__) if (caching == ttm_write_combined) diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c index e2757ff1c23d..96e312a3eac7 100644 --- a/drivers/video/fbdev/vga16fb.c +++ b/drivers/video/fbdev/vga16fb.c @@ -184,6 +184,25 @@ static inline void setindex(int index) vga_io_w(VGA_GFX_I, index); } +/* Check if the video mode is supported by the driver */ +static inline int check_mode_supported(void) +{ + /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ +#if defined(CONFIG_X86) + /* only EGA and VGA in 16 color graphic mode are supported */ + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EGAC && + screen_info.orig_video_isVGA != VIDEO_TYPE_VGAC) + return -ENODEV; + + if (screen_info.orig_video_mode != 0x0D && /* 320x200/4 (EGA) */ + screen_info.orig_video_mode != 0x0E && /* 640x200/4 (EGA) */ + screen_info.orig_video_mode != 0x10 && /* 640x350/4 (EGA) */ + screen_info.orig_video_mode != 0x12) /* 640x480/4 (VGA) */ + return -ENODEV; +#endif + return 0; +} + static void vga16fb_pan_var(struct fb_info *info, struct fb_var_screeninfo *var) { @@ -1422,6 +1441,11 @@ static int __init vga16fb_init(void) vga16fb_setup(option); #endif + + ret = check_mode_supported(); + if (ret) + return ret; + ret = platform_driver_register(&vga16fb_driver); if (!ret) { diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 8b2ed4199284..30359e434c3f 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1784,6 +1784,13 @@ drm_dp_tps3_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) } static inline bool +drm_dp_max_downspread(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) +{ + return dpcd[DP_DPCD_REV] >= 0x11 || + dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5; +} + +static inline bool drm_dp_tps4_supported(const u8 dpcd[DP_RECEIVER_CAP_SIZE]) { return dpcd[DP_DPCD_REV] >= 0x14 && diff --git a/include/uapi/linux/kfd_sysfs.h b/include/uapi/linux/kfd_sysfs.h index e1fb78b4bf09..3e330f368917 100644 --- a/include/uapi/linux/kfd_sysfs.h +++ b/include/uapi/linux/kfd_sysfs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 OR MIT WITH Linux-syscall-note */ +/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ /* * Copyright 2021 Advanced Micro Devices, Inc. * |