On the display side, cleanups and fixes to enabled modifiers (QCOM_COMPRESSED). And otherwise mostly misc fixes all around.
Unified · Split
| @@ -0,0 +1,59 @@ | |||
| 1 | Qualcomm adreno/snapdragon GMU (Graphics management unit) | ||
| 2 | |||
| 3 | The GMU is a programmable power controller for the GPU. the CPU controls the | ||
| 4 | GMU which in turn handles power controls for the GPU. | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | - compatible: "qcom,adreno-gmu-XYZ.W", "qcom,adreno-gmu" | ||
| 8 | for example: "qcom,adreno-gmu-630.2", "qcom,adreno-gmu" | ||
| 9 | Note that you need to list the less specific "qcom,adreno-gmu" | ||
| 10 | for generic matches and the more specific identifier to identify | ||
| 11 | the specific device. | ||
| 12 | - reg: Physical base address and length of the GMU registers. | ||
| 13 | - reg-names: Matching names for the register regions | ||
| 14 | * "gmu" | ||
| 15 | * "gmu_pdc" | ||
| 16 | * "gmu_pdc_seg" | ||
| 17 | - interrupts: The interrupt signals from the GMU. | ||
| 18 | - interrupt-names: Matching names for the interrupts | ||
| 19 | * "hfi" | ||
| 20 | * "gmu" | ||
| 21 | - clocks: phandles to the device clocks | ||
| 22 | - clock-names: Matching names for the clocks | ||
| 23 | * "gmu" | ||
| 24 | * "cxo" | ||
| 25 | * "axi" | ||
| 26 | * "mnoc" | ||
| 27 | - power-domains: should be <&clock_gpucc GPU_CX_GDSC> | ||
| 28 | - iommus: phandle to the adreno iommu | ||
| 29 | - operating-points-v2: phandle to the OPP operating points | ||
| 30 | |||
| 31 | Example: | ||
| 32 | |||
| 33 | / { | ||
| 34 | ... | ||
| 35 | |||
| 36 | gmu: gmu@506a000 { | ||
| 37 | compatible="qcom,adreno-gmu-630.2", "qcom,adreno-gmu"; | ||
| 38 | |||
| 39 | reg = <0x506a000 0x30000>, | ||
| 40 | <0xb280000 0x10000>, | ||
| 41 | <0xb480000 0x10000>; | ||
| 42 | reg-names = "gmu", "gmu_pdc", "gmu_pdc_seq"; | ||
| 43 | |||
| 44 | interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>, | ||
| 45 | <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>; | ||
| 46 | interrupt-names = "hfi", "gmu"; | ||
| 47 | |||
| 48 | clocks = <&gpucc GPU_CC_CX_GMU_CLK>, | ||
| 49 | <&gpucc GPU_CC_CXO_CLK>, | ||
| 50 | <&gcc GCC_DDRSS_GPU_AXI_CLK>, | ||
| 51 | <&gcc GCC_GPU_MEMNOC_GFX_CLK>; | ||
| 52 | clock-names = "gmu", "cxo", "axi", "memnoc"; | ||
| 53 | |||
| 54 | power-domains = <&gpucc GPU_CX_GDSC>; | ||
| 55 | iommus = <&adreno_smmu 5>; | ||
| 56 | |||
| 57 | operating-points-v2 = <&gmu_opp_table>; | ||
| 58 | }; | ||
| 59 | }; | ||
| @@ -10,14 +10,23 @@ Required properties: · 9 unmodified lines | |||
| 10 | If "amd,imageon" is used, there should be no top level msm device. | 10 | If "amd,imageon" is used, there should be no top level msm device. |
| 11 | - reg: Physical base address and length of the controller's registers. | 11 | - reg: Physical base address and length of the controller's registers. |
| 12 | - interrupts: The interrupt signal from the gpu. | 12 | - interrupts: The interrupt signal from the gpu. |
| 13 | - clocks: device clocks | 13 | - clocks: device clocks (if applicable) |
| 14 | See ../clocks/clock-bindings.txt for details. | 14 | See ../clocks/clock-bindings.txt for details. |
| 15 | - clock-names: the following clocks are required: | 15 | - clock-names: the following clocks are required by a3xx, a4xx and a5xx |
| 16 | cores: | ||
| 16 | * "core" | 17 | * "core" |
| 17 | * "iface" | 18 | * "iface" |
| 18 | * "mem_iface" | 19 | * "mem_iface" |
| 20 | For GMU attached devices the GPU clocks are not used and are not required. The | ||
| 21 | following devices should not list clocks: | ||
| 22 | - qcom,adreno-630.2 | ||
| 23 | - iommus: optional phandle to an adreno iommu instance | ||
| 24 | - operating-points-v2: optional phandle to the OPP operating points | ||
| 25 | - qcom,gmu: For GMU attached devices a phandle to the GMU device that will | ||
| 26 | control the power for the GPU. Applicable targets: | ||
| 27 | - qcom,adreno-630.2 | ||
| 19 | 28 | ||
| 20 | Example: | 29 | Example 3xx/4xx/a5xx: |
| 21 | 30 | ||
| 22 | / { | 31 | / { |
| 23 | ... | 32 | ... |
| @@ -37,3 +46,30 @@ Example: · 13 unmodified lines | |||
| 37 | <&mmcc MMSS_IMEM_AHB_CLK>; | 46 | <&mmcc MMSS_IMEM_AHB_CLK>; |
| 38 | }; | 47 | }; |
| 39 | }; | 48 | }; |
| 49 | |||
| 50 | Example a6xx (with GMU): | ||
| 51 | |||
| 52 | / { | ||
| 53 | ... | ||
| 54 | |||
| 55 | gpu@5000000 { | ||
| 56 | compatible = "qcom,adreno-630.2", "qcom,adreno"; | ||
| 57 | #stream-id-cells = <16>; | ||
| 58 | |||
| 59 | reg = <0x5000000 0x40000>, <0x509e000 0x10>; | ||
| 60 | reg-names = "kgsl_3d0_reg_memory", "cx_mem"; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Look ma, no clocks! The GPU clocks and power are | ||
| 64 | * controlled entirely by the GMU | ||
| 65 | */ | ||
| 66 | |||
| 67 | interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>; | ||
| 68 | |||
| 69 | iommus = <&adreno_smmu 0>; | ||
| 70 | |||
| 71 | operating-points-v2 = <&gpu_opp_table>; | ||
| 72 | |||
| 73 | qcom,gmu = <&gmu>; | ||
| 74 | }; | ||
| 75 | }; | ||
| @@ -4851,10 +4851,11 @@ F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt · 4850 unmodified lines | |||
| 4851 | 4851 | ||
| 4852 | DRM DRIVER FOR MSM ADRENO GPU | 4852 | DRM DRIVER FOR MSM ADRENO GPU |
| 4853 | M: Rob Clark <robdclark@gmail.com> | 4853 | M: Rob Clark <robdclark@gmail.com> |
| 4854 | M: Sean Paul <sean@poorly.run> | ||
| 4854 | L: linux-arm-msm@vger.kernel.org | 4855 | L: linux-arm-msm@vger.kernel.org |
| 4855 | L: dri-devel@lists.freedesktop.org | 4856 | L: dri-devel@lists.freedesktop.org |
| 4856 | L: freedreno@lists.freedesktop.org | 4857 | L: freedreno@lists.freedesktop.org |
| 4857 | T: git git://people.freedesktop.org/~robclark/linux | 4858 | T: git https://gitlab.freedesktop.org/drm/msm.git |
| 4858 | S: Maintained | 4859 | S: Maintained |
| 4859 | F: drivers/gpu/drm/msm/ | 4860 | F: drivers/gpu/drm/msm/ |
| 4860 | F: include/uapi/drm/msm_drm.h | 4861 | F: include/uapi/drm/msm_drm.h |
| @@ -465,8 +465,6 @@ static void _dpu_crtc_setup_mixer_for_encoder( · 464 unmodified lines | |||
| 465 | return; | 465 | return; |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | mixer->encoder = enc; | ||
| 469 | |||
| 470 | cstate->num_mixers++; | 468 | cstate->num_mixers++; |
| 471 | DPU_DEBUG("setup mixer %d: lm %d\n", | 469 | DPU_DEBUG("setup mixer %d: lm %d\n", |
| 472 | i, mixer->hw_lm->idx - LM_0); | 470 | i, mixer->hw_lm->idx - LM_0); |
| @@ -718,11 +716,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) · 245 unmodified lines | |||
| 718 | * may delay and flush at an irq event (e.g. ppdone) | 716 | * may delay and flush at an irq event (e.g. ppdone) |
| 719 | */ | 717 | */ |
| 720 | drm_for_each_encoder_mask(encoder, crtc->dev, | 718 | drm_for_each_encoder_mask(encoder, crtc->dev, |
| 721 | crtc->state->encoder_mask) { | 719 | crtc->state->encoder_mask) |
| 722 | struct dpu_encoder_kickoff_params params = { 0 }; | 720 | dpu_encoder_prepare_for_kickoff(encoder, async); |
| 723 | dpu_encoder_prepare_for_kickoff(encoder, ¶ms, async); | ||
| 724 | } | ||
| 725 | |||
| 726 | 721 | ||
| 727 | if (!async) { | 722 | if (!async) { |
| 728 | /* wait for frame_event_done completion */ | 723 | /* wait for frame_event_done completion */ |
| @@ -84,14 +84,12 @@ struct dpu_crtc_smmu_state_data { · 83 unmodified lines | |||
| 84 | * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC | 84 | * struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC |
| 85 | * @hw_lm: LM HW Driver context | 85 | * @hw_lm: LM HW Driver context |
| 86 | * @lm_ctl: CTL Path HW driver context | 86 | * @lm_ctl: CTL Path HW driver context |
| 87 | * @encoder: Encoder attached to this lm & ctl | ||
| 88 | * @mixer_op_mode: mixer blending operation mode | 87 | * @mixer_op_mode: mixer blending operation mode |
| 89 | * @flush_mask: mixer flush mask for ctl, mixer and pipe | 88 | * @flush_mask: mixer flush mask for ctl, mixer and pipe |
| 90 | */ | 89 | */ |
| 91 | struct dpu_crtc_mixer { | 90 | struct dpu_crtc_mixer { |
| 92 | struct dpu_hw_mixer *hw_lm; | 91 | struct dpu_hw_mixer *hw_lm; |
| 93 | struct dpu_hw_ctl *lm_ctl; | 92 | struct dpu_hw_ctl *lm_ctl; |
| 94 | struct drm_encoder *encoder; | ||
| 95 | u32 mixer_op_mode; | 93 | u32 mixer_op_mode; |
| 96 | u32 flush_mask; | 94 | u32 flush_mask; |
| 97 | }; | 95 | }; |
| @@ -205,7 +205,7 @@ struct dpu_encoder_virt { · 204 unmodified lines | |||
| 205 | bool idle_pc_supported; | 205 | bool idle_pc_supported; |
| 206 | struct mutex rc_lock; | 206 | struct mutex rc_lock; |
| 207 | enum dpu_enc_rc_states rc_state; | 207 | enum dpu_enc_rc_states rc_state; |
| 208 | struct kthread_delayed_work delayed_off_work; | 208 | struct delayed_work delayed_off_work; |
| 209 | struct kthread_work vsync_event_work; | 209 | struct kthread_work vsync_event_work; |
| 210 | struct msm_display_topology topology; | 210 | struct msm_display_topology topology; |
| 211 | bool mode_set_complete; | 211 | bool mode_set_complete; |
| @@ -742,7 +742,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, · 530 unmodified lines | |||
| 742 | { | 742 | { |
| 743 | struct dpu_encoder_virt *dpu_enc; | 743 | struct dpu_encoder_virt *dpu_enc; |
| 744 | struct msm_drm_private *priv; | 744 | struct msm_drm_private *priv; |
| 745 | struct msm_drm_thread *disp_thread; | ||
| 746 | bool is_vid_mode = false; | 745 | bool is_vid_mode = false; |
| 747 | 746 | ||
| 748 | if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || | 747 | if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private || |
| @@ -755,12 +754,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, · 6 unmodified lines | |||
| 755 | is_vid_mode = dpu_enc->disp_info.capabilities & | 754 | is_vid_mode = dpu_enc->disp_info.capabilities & |
| 756 | MSM_DISPLAY_CAP_VID_MODE; | 755 | MSM_DISPLAY_CAP_VID_MODE; |
| 757 | 756 | ||
| 758 | if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { | ||
| 759 | DPU_ERROR("invalid crtc index\n"); | ||
| 760 | return -EINVAL; | ||
| 761 | } | ||
| 762 | disp_thread = &priv->disp_thread[drm_enc->crtc->index]; | ||
| 763 | |||
| 764 | /* | 757 | /* |
| 765 | * when idle_pc is not supported, process only KICKOFF, STOP and MODESET | 758 | * when idle_pc is not supported, process only KICKOFF, STOP and MODESET |
| 766 | * events and return early for other events (ie wb display). | 759 | * events and return early for other events (ie wb display). |
| @@ -777,8 +770,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, · 10 unmodified lines | |||
| 777 | switch (sw_event) { | 770 | switch (sw_event) { |
| 778 | case DPU_ENC_RC_EVENT_KICKOFF: | 771 | case DPU_ENC_RC_EVENT_KICKOFF: |
| 779 | /* cancel delayed off work, if any */ | 772 | /* cancel delayed off work, if any */ |
| 780 | if (kthread_cancel_delayed_work_sync( | 773 | if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work)) |
| 781 | &dpu_enc->delayed_off_work)) | ||
| 782 | DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", | 774 | DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", |
| 783 | sw_event); | 775 | sw_event); |
| 784 | 776 | ||
| @@ -837,10 +829,8 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, · 52 unmodified lines | |||
| 837 | return 0; | 829 | return 0; |
| 838 | } | 830 | } |
| 839 | 831 | ||
| 840 | kthread_queue_delayed_work( | 832 | queue_delayed_work(priv->wq, &dpu_enc->delayed_off_work, |
| 841 | &disp_thread->worker, | 833 | msecs_to_jiffies(dpu_enc->idle_timeout)); |
| 842 | &dpu_enc->delayed_off_work, | ||
| 843 | msecs_to_jiffies(dpu_enc->idle_timeout)); | ||
| 844 | 834 | ||
| 845 | trace_dpu_enc_rc(DRMID(drm_enc), sw_event, | 835 | trace_dpu_enc_rc(DRMID(drm_enc), sw_event, |
| 846 | dpu_enc->idle_pc_supported, dpu_enc->rc_state, | 836 | dpu_enc->idle_pc_supported, dpu_enc->rc_state, |
| @@ -849,8 +839,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, · 2 unmodified lines | |||
| 849 | 839 | ||
| 850 | case DPU_ENC_RC_EVENT_PRE_STOP: | 840 | case DPU_ENC_RC_EVENT_PRE_STOP: |
| 851 | /* cancel delayed off work, if any */ | 841 | /* cancel delayed off work, if any */ |
| 852 | if (kthread_cancel_delayed_work_sync( | 842 | if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work)) |
| 853 | &dpu_enc->delayed_off_work)) | ||
| 854 | DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", | 843 | DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n", |
| 855 | sw_event); | 844 | sw_event); |
| 856 | 845 | ||
| @@ -1368,7 +1357,7 @@ static void dpu_encoder_frame_done_callback( · 511 unmodified lines | |||
| 1368 | } | 1357 | } |
| 1369 | } | 1358 | } |
| 1370 | 1359 | ||
| 1371 | static void dpu_encoder_off_work(struct kthread_work *work) | 1360 | static void dpu_encoder_off_work(struct work_struct *work) |
| 1372 | { | 1361 | { |
| 1373 | struct dpu_encoder_virt *dpu_enc = container_of(work, | 1362 | struct dpu_encoder_virt *dpu_enc = container_of(work, |
| 1374 | struct dpu_encoder_virt, delayed_off_work.work); | 1363 | struct dpu_encoder_virt, delayed_off_work.work); |
| @@ -1756,15 +1745,14 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) · 381 unmodified lines | |||
| 1756 | nsecs_to_jiffies(ktime_to_ns(wakeup_time))); | 1745 | nsecs_to_jiffies(ktime_to_ns(wakeup_time))); |
| 1757 | } | 1746 | } |
| 1758 | 1747 | ||
| 1759 | void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, | 1748 | void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) |
| 1760 | struct dpu_encoder_kickoff_params *params, bool async) | ||
| 1761 | { | 1749 | { |
| 1762 | struct dpu_encoder_virt *dpu_enc; | 1750 | struct dpu_encoder_virt *dpu_enc; |
| 1763 | struct dpu_encoder_phys *phys; | 1751 | struct dpu_encoder_phys *phys; |
| 1764 | bool needs_hw_reset = false; | 1752 | bool needs_hw_reset = false; |
| 1765 | unsigned int i; | 1753 | unsigned int i; |
| 1766 | 1754 | ||
| 1767 | if (!drm_enc || !params) { | 1755 | if (!drm_enc) { |
| 1768 | DPU_ERROR("invalid args\n"); | 1756 | DPU_ERROR("invalid args\n"); |
| 1769 | return; | 1757 | return; |
| 1770 | } | 1758 | } |
| @@ -1778,7 +1766,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, · 7 unmodified lines | |||
| 1778 | phys = dpu_enc->phys_encs[i]; | 1766 | phys = dpu_enc->phys_encs[i]; |
| 1779 | if (phys) { | 1767 | if (phys) { |
| 1780 | if (phys->ops.prepare_for_kickoff) | 1768 | if (phys->ops.prepare_for_kickoff) |
| 1781 | phys->ops.prepare_for_kickoff(phys, params); | 1769 | phys->ops.prepare_for_kickoff(phys); |
| 1782 | if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) | 1770 | if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET) |
| 1783 | needs_hw_reset = true; | 1771 | needs_hw_reset = true; |
| 1784 | } | 1772 | } |
| @@ -2193,7 +2181,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, · 408 unmodified lines | |||
| 2193 | 2181 | ||
| 2194 | 2182 | ||
| 2195 | mutex_init(&dpu_enc->rc_lock); | 2183 | mutex_init(&dpu_enc->rc_lock); |
| 2196 | kthread_init_delayed_work(&dpu_enc->delayed_off_work, | 2184 | INIT_DELAYED_WORK(&dpu_enc->delayed_off_work, |
| 2197 | dpu_encoder_off_work); | 2185 | dpu_encoder_off_work); |
| 2198 | dpu_enc->idle_timeout = IDLE_TIMEOUT; | 2186 | dpu_enc->idle_timeout = IDLE_TIMEOUT; |
| 2199 | 2187 | ||
| @@ -37,15 +37,6 @@ struct dpu_encoder_hw_resources { · 36 unmodified lines | |||
| 37 | enum dpu_intf_mode intfs[INTF_MAX]; | 37 | enum dpu_intf_mode intfs[INTF_MAX]; |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | /** | ||
| 41 | * dpu_encoder_kickoff_params - info encoder requires at kickoff | ||
| 42 | * @affected_displays: bitmask, bit set means the ROI of the commit lies within | ||
| 43 | * the bounds of the physical display at the bit index | ||
| 44 | */ | ||
| 45 | struct dpu_encoder_kickoff_params { | ||
| 46 | unsigned long affected_displays; | ||
| 47 | }; | ||
| 48 | |||
| 49 | /** | 40 | /** |
| 50 | * dpu_encoder_get_hw_resources - Populate table of required hardware resources | 41 | * dpu_encoder_get_hw_resources - Populate table of required hardware resources |
| 51 | * @encoder: encoder pointer | 42 | * @encoder: encoder pointer |
| @@ -88,11 +79,9 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder, · 36 unmodified lines | |||
| 88 | * Immediately: if no previous commit is outstanding. | 79 | * Immediately: if no previous commit is outstanding. |
| 89 | * Delayed: Block until next trigger can be issued. | 80 | * Delayed: Block until next trigger can be issued. |
| 90 | * @encoder: encoder pointer | 81 | * @encoder: encoder pointer |
| 91 | * @params: kickoff time parameters | ||
| 92 | * @async: true if this is an asynchronous commit | 82 | * @async: true if this is an asynchronous commit |
| 93 | */ | 83 | */ |
| 94 | void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, | 84 | void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, bool async); |
| 95 | struct dpu_encoder_kickoff_params *params, bool async); | ||
| 96 | 85 | ||
| 97 | /** | 86 | /** |
| 98 | * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous | 87 | * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous |
| @@ -144,8 +144,7 @@ struct dpu_encoder_phys_ops { · 143 unmodified lines | |||
| 144 | int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); | 144 | int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); |
| 145 | int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); | 145 | int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); |
| 146 | int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); | 146 | int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); |
| 147 | void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc, | 147 | void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc); |
| 148 | struct dpu_encoder_kickoff_params *params); | ||
| 149 | void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); | 148 | void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); |
| 150 | void (*trigger_start)(struct dpu_encoder_phys *phys_enc); | 149 | void (*trigger_start)(struct dpu_encoder_phys *phys_enc); |
| 151 | bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc); | 150 | bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc); |
| @@ -594,8 +594,7 @@ static void dpu_encoder_phys_cmd_get_hw_resources( · 593 unmodified lines | |||
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | static void dpu_encoder_phys_cmd_prepare_for_kickoff( | 596 | static void dpu_encoder_phys_cmd_prepare_for_kickoff( |
| 597 | struct dpu_encoder_phys *phys_enc, | 597 | struct dpu_encoder_phys *phys_enc) |
| 598 | struct dpu_encoder_kickoff_params *params) | ||
| 599 | { | 598 | { |
| 600 | struct dpu_encoder_phys_cmd *cmd_enc = | 599 | struct dpu_encoder_phys_cmd *cmd_enc = |
| 601 | to_dpu_encoder_phys_cmd(phys_enc); | 600 | to_dpu_encoder_phys_cmd(phys_enc); |
| @@ -693,7 +692,7 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( · 91 unmodified lines | |||
| 693 | 692 | ||
| 694 | /* required for both controllers */ | 693 | /* required for both controllers */ |
| 695 | if (!rc && cmd_enc->serialize_wait4pp) | 694 | if (!rc && cmd_enc->serialize_wait4pp) |
| 696 | dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL); | 695 | dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc); |
| 697 | 696 | ||
| 698 | return rc; | 697 | return rc; |
| 699 | } | 698 | } |
| @@ -587,14 +587,13 @@ static int dpu_encoder_phys_vid_wait_for_vblank( · 586 unmodified lines | |||
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | static void dpu_encoder_phys_vid_prepare_for_kickoff( | 589 | static void dpu_encoder_phys_vid_prepare_for_kickoff( |
| 590 | struct dpu_encoder_phys *phys_enc, | 590 | struct dpu_encoder_phys *phys_enc) |
| 591 | struct dpu_encoder_kickoff_params *params) | ||
| 592 | { | 591 | { |
| 593 | struct dpu_encoder_phys_vid *vid_enc; | 592 | struct dpu_encoder_phys_vid *vid_enc; |
| 594 | struct dpu_hw_ctl *ctl; | 593 | struct dpu_hw_ctl *ctl; |
| 595 | int rc; | 594 | int rc; |
| 596 | 595 | ||
| 597 | if (!phys_enc || !params) { | 596 | if (!phys_enc) { |
| 598 | DPU_ERROR("invalid encoder/parameters\n"); | 597 | DPU_ERROR("invalid encoder/parameters\n"); |
| 599 | return; | 598 | return; |
| 600 | } | 599 | } |
| @@ -263,13 +263,13 @@ static const struct dpu_format dpu_format_map[] = { · 262 unmodified lines | |||
| 263 | 263 | ||
| 264 | INTERLEAVED_RGB_FMT(RGB565, | 264 | INTERLEAVED_RGB_FMT(RGB565, |
| 265 | 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, | 265 | 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, |
| 266 | C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, | 266 | C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, |
| 267 | false, 2, 0, | 267 | false, 2, 0, |
| 268 | DPU_FETCH_LINEAR, 1), | 268 | DPU_FETCH_LINEAR, 1), |
| 269 | 269 | ||
| 270 | INTERLEAVED_RGB_FMT(BGR565, | 270 | INTERLEAVED_RGB_FMT(BGR565, |
| 271 | 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, | 271 | 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, |
| 272 | C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, | 272 | C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, |
| 273 | false, 2, 0, | 273 | false, 2, 0, |
| 274 | DPU_FETCH_LINEAR, 1), | 274 | DPU_FETCH_LINEAR, 1), |
| 275 | 275 | ||
| @@ -1137,36 +1137,3 @@ const struct msm_format *dpu_get_msm_format( · 861 unmodified lines | |||
| 1137 | return &fmt->base; | 1137 | return &fmt->base; |
| 1138 | return NULL; | 1138 | return NULL; |
| 1139 | } | 1139 | } |
| 1140 | |||
| 1141 | uint32_t dpu_populate_formats( | ||
| 1142 | const struct dpu_format_extended *format_list, | ||
| 1143 | uint32_t *pixel_formats, | ||
| 1144 | uint64_t *pixel_modifiers, | ||
| 1145 | uint32_t pixel_formats_max) | ||
| 1146 | { | ||
| 1147 | uint32_t i, fourcc_format; | ||
| 1148 | |||
| 1149 | if (!format_list || !pixel_formats) | ||
| 1150 | return 0; | ||
| 1151 | |||
| 1152 | for (i = 0, fourcc_format = 0; | ||
| 1153 | format_list->fourcc_format && i < pixel_formats_max; | ||
| 1154 | ++format_list) { | ||
| 1155 | /* verify if listed format is in dpu_format_map? */ | ||
| 1156 | |||
| 1157 | /* optionally return modified formats */ | ||
| 1158 | if (pixel_modifiers) { | ||
| 1159 | /* assume same modifier for all fb planes */ | ||
| 1160 | pixel_formats[i] = format_list->fourcc_format; | ||
| 1161 | pixel_modifiers[i++] = format_list->modifier; | ||
| 1162 | } else { | ||
| 1163 | /* assume base formats grouped together */ | ||
| 1164 | if (fourcc_format != format_list->fourcc_format) { | ||
| 1165 | fourcc_format = format_list->fourcc_format; | ||
| 1166 | pixel_formats[i++] = fourcc_format; | ||
| 1167 | } | ||
| 1168 | } | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | return i; | ||
| 1172 | } | ||
| @@ -40,20 +40,6 @@ const struct msm_format *dpu_get_msm_format( · 39 unmodified lines | |||
| 40 | const uint32_t format, | 40 | const uint32_t format, |
| 41 | const uint64_t modifiers); | 41 | const uint64_t modifiers); |
| 42 | 42 | ||
| 43 | /** | ||
| 44 | * dpu_populate_formats - populate the given array with fourcc codes supported | ||
| 45 | * @format_list: pointer to list of possible formats | ||
| 46 | * @pixel_formats: array to populate with fourcc codes | ||
| 47 | * @pixel_modifiers: array to populate with drm modifiers, can be NULL | ||
| 48 | * @pixel_formats_max: length of pixel formats array | ||
| 49 | * Return: number of elements populated | ||
| 50 | */ | ||
| 51 | uint32_t dpu_populate_formats( | ||
| 52 | const struct dpu_format_extended *format_list, | ||
| 53 | uint32_t *pixel_formats, | ||
| 54 | uint64_t *pixel_modifiers, | ||
| 55 | uint32_t pixel_formats_max); | ||
| 56 | |||
| 57 | /** | 43 | /** |
| 58 | * dpu_format_check_modified_format - validate format and buffers for | 44 | * dpu_format_check_modified_format - validate format and buffers for |
| 59 | * dpu non-standard, i.e. modified format | 45 | * dpu non-standard, i.e. modified format |
| @@ -151,7 +151,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = { · 150 unmodified lines | |||
| 151 | .id = DPU_SSPP_CSC_10BIT, \ | 151 | .id = DPU_SSPP_CSC_10BIT, \ |
| 152 | .base = 0x1a00, .len = 0x100,}, \ | 152 | .base = 0x1a00, .len = 0x100,}, \ |
| 153 | .format_list = plane_formats_yuv, \ | 153 | .format_list = plane_formats_yuv, \ |
| 154 | .num_formats = ARRAY_SIZE(plane_formats_yuv), \ | ||
| 154 | .virt_format_list = plane_formats, \ | 155 | .virt_format_list = plane_formats, \ |
| 156 | .virt_num_formats = ARRAY_SIZE(plane_formats), \ | ||
| 155 | } | 157 | } |
| 156 | 158 | ||
| 157 | #define _DMA_SBLK(num, sdma_pri) \ | 159 | #define _DMA_SBLK(num, sdma_pri) \ |
| @@ -163,7 +165,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = { · 5 unmodified lines | |||
| 163 | .src_blk = {.name = STRCAT("sspp_src_", num), \ | 165 | .src_blk = {.name = STRCAT("sspp_src_", num), \ |
| 164 | .id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \ | 166 | .id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \ |
| 165 | .format_list = plane_formats, \ | 167 | .format_list = plane_formats, \ |
| 168 | .num_formats = ARRAY_SIZE(plane_formats), \ | ||
| 166 | .virt_format_list = plane_formats, \ | 169 | .virt_format_list = plane_formats, \ |
| 170 | .virt_num_formats = ARRAY_SIZE(plane_formats), \ | ||
| 167 | } | 171 | } |
| 168 | 172 | ||
| 169 | static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5); | 173 | static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5); |
| @@ -251,17 +251,6 @@ struct dpu_pp_blk { · 250 unmodified lines | |||
| 251 | u32 version; | 251 | u32 version; |
| 252 | }; | 252 | }; |
| 253 | 253 | ||
| 254 | /** | ||
| 255 | * struct dpu_format_extended - define dpu specific pixel format+modifier | ||
| 256 | * @fourcc_format: Base FOURCC pixel format code | ||
| 257 | * @modifier: 64-bit drm format modifier, same modifier must be applied to all | ||
| 258 | * framebuffer planes | ||
| 259 | */ | ||
| 260 | struct dpu_format_extended { | ||
| 261 | uint32_t fourcc_format; | ||
| 262 | uint64_t modifier; | ||
| 263 | }; | ||
| 264 | |||
| 265 | /** | 254 | /** |
| 266 | * enum dpu_qos_lut_usage - define QoS LUT use cases | 255 | * enum dpu_qos_lut_usage - define QoS LUT use cases |
| 267 | */ | 256 | */ |
| @@ -348,7 +337,9 @@ struct dpu_sspp_blks_common { · 80 unmodified lines | |||
| 348 | * @pcc_blk: | 337 | * @pcc_blk: |
| 349 | * @igc_blk: | 338 | * @igc_blk: |
| 350 | * @format_list: Pointer to list of supported formats | 339 | * @format_list: Pointer to list of supported formats |
| 340 | * @num_formats: Number of supported formats | ||
| 351 | * @virt_format_list: Pointer to list of supported formats for virtual planes | 341 | * @virt_format_list: Pointer to list of supported formats for virtual planes |
| 342 | * @virt_num_formats: Number of supported formats for virtual planes | ||
| 352 | */ | 343 | */ |
| 353 | struct dpu_sspp_sub_blks { | 344 | struct dpu_sspp_sub_blks { |
| 354 | const struct dpu_sspp_blks_common *common; | 345 | const struct dpu_sspp_blks_common *common; |
| @@ -366,8 +357,10 @@ struct dpu_sspp_sub_blks { · 11 unmodified lines | |||
| 366 | struct dpu_pp_blk pcc_blk; | 357 | struct dpu_pp_blk pcc_blk; |
| 367 | struct dpu_pp_blk igc_blk; | 358 | struct dpu_pp_blk igc_blk; |
| 368 | 359 | ||
| 369 | const struct dpu_format_extended *format_list; | 360 | const u32 *format_list; |
| 370 | const struct dpu_format_extended *virt_format_list; | 361 | u32 num_formats; |
| 362 | const u32 *virt_format_list; | ||
| 363 | u32 virt_num_formats; | ||
| 371 | }; | 364 | }; |
| 372 | 365 | ||
| 373 | /** | 366 | /** |
| @@ -12,157 +12,81 @@ · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | #include "dpu_hw_mdss.h" | 13 | #include "dpu_hw_mdss.h" |
| 14 | 14 | ||
| 15 | static const struct dpu_format_extended plane_formats[] = { | 15 | static const uint32_t qcom_compressed_supported_formats[] = { |
| 16 | {DRM_FORMAT_ARGB8888, 0}, | 16 | DRM_FORMAT_ABGR8888, |
| 17 | {DRM_FORMAT_ABGR8888, 0}, | 17 | DRM_FORMAT_XBGR8888, |
| 18 | {DRM_FORMAT_RGBA8888, 0}, | 18 | DRM_FORMAT_BGR565, |
| 19 | {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | ||
| 20 | {DRM_FORMAT_BGRA8888, 0}, | ||
| 21 | {DRM_FORMAT_XRGB8888, 0}, | ||
| 22 | {DRM_FORMAT_RGBX8888, 0}, | ||
| 23 | {DRM_FORMAT_BGRX8888, 0}, | ||
| 24 | {DRM_FORMAT_XBGR8888, 0}, | ||
| 25 | {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | ||
| 26 | {DRM_FORMAT_RGB888, 0}, | ||
| 27 | {DRM_FORMAT_BGR888, 0}, | ||
| 28 | {DRM_FORMAT_RGB565, 0}, | ||
| 29 | {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | ||
| 30 | {DRM_FORMAT_BGR565, 0}, | ||
| 31 | {DRM_FORMAT_ARGB1555, 0}, | ||
| 32 | {DRM_FORMAT_ABGR1555, 0}, | ||
| 33 | {DRM_FORMAT_RGBA5551, 0}, | ||
| 34 | {DRM_FORMAT_BGRA5551, 0}, | ||
| 35 | {DRM_FORMAT_XRGB1555, 0}, | ||
| 36 | {DRM_FORMAT_XBGR1555, 0}, | ||
| 37 | {DRM_FORMAT_RGBX5551, 0}, | ||
| 38 | {DRM_FORMAT_BGRX5551, 0}, | ||
| 39 | {DRM_FORMAT_ARGB4444, 0}, | ||
| 40 | {DRM_FORMAT_ABGR4444, 0}, | ||
| 41 | {DRM_FORMAT_RGBA4444, 0}, | ||
| 42 | {DRM_FORMAT_BGRA4444, 0}, | ||
| 43 | {DRM_FORMAT_XRGB4444, 0}, | ||
| 44 | {DRM_FORMAT_XBGR4444, 0}, | ||
| 45 | {DRM_FORMAT_RGBX4444, 0}, | ||
| 46 | {DRM_FORMAT_BGRX4444, 0}, | ||
| 47 | {0, 0}, | ||
| 48 | }; | 19 | }; |
| 49 | 20 | ||
| 50 | static const struct dpu_format_extended plane_formats_yuv[] = { | 21 | static const uint32_t plane_formats[] = { |
| 51 | {DRM_FORMAT_ARGB8888, 0}, | 22 | DRM_FORMAT_ARGB8888, |
| 52 | {DRM_FORMAT_ABGR8888, 0}, | 23 | DRM_FORMAT_ABGR8888, |
| 53 | {DRM_FORMAT_RGBA8888, 0}, | 24 | DRM_FORMAT_RGBA8888, |
| 54 | {DRM_FORMAT_BGRX8888, 0}, | 25 | DRM_FORMAT_BGRA8888, |
| 55 | {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 26 | DRM_FORMAT_XRGB8888, |
| 56 | {DRM_FORMAT_BGRA8888, 0}, | 27 | DRM_FORMAT_RGBX8888, |
| 57 | {DRM_FORMAT_XRGB8888, 0}, | 28 | DRM_FORMAT_BGRX8888, |
| 58 | {DRM_FORMAT_XBGR8888, 0}, | 29 | DRM_FORMAT_XBGR8888, |
| 59 | {DRM_FORMAT_RGBX8888, 0}, | 30 | DRM_FORMAT_RGB888, |
| 60 | {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 31 | DRM_FORMAT_BGR888, |
| 61 | {DRM_FORMAT_RGB888, 0}, | 32 | DRM_FORMAT_RGB565, |
| 62 | {DRM_FORMAT_BGR888, 0}, | 33 | DRM_FORMAT_BGR565, |
| 63 | {DRM_FORMAT_RGB565, 0}, | 34 | DRM_FORMAT_ARGB1555, |
| 64 | {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 35 | DRM_FORMAT_ABGR1555, |
| 65 | {DRM_FORMAT_BGR565, 0}, | 36 | DRM_FORMAT_RGBA5551, |
| 66 | {DRM_FORMAT_ARGB1555, 0}, | 37 | DRM_FORMAT_BGRA5551, |
| 67 | {DRM_FORMAT_ABGR1555, 0}, | 38 | DRM_FORMAT_XRGB1555, |
| 68 | {DRM_FORMAT_RGBA5551, 0}, | 39 | DRM_FORMAT_XBGR1555, |
| 69 | {DRM_FORMAT_BGRA5551, 0}, | 40 | DRM_FORMAT_RGBX5551, |
| 70 | {DRM_FORMAT_XRGB1555, 0}, | 41 | DRM_FORMAT_BGRX5551, |
| 71 | {DRM_FORMAT_XBGR1555, 0}, | 42 | DRM_FORMAT_ARGB4444, |
| 72 | {DRM_FORMAT_RGBX5551, 0}, | 43 | DRM_FORMAT_ABGR4444, |
| 73 | {DRM_FORMAT_BGRX5551, 0}, | 44 | DRM_FORMAT_RGBA4444, |
| 74 | {DRM_FORMAT_ARGB4444, 0}, | 45 | DRM_FORMAT_BGRA4444, |
| 75 | {DRM_FORMAT_ABGR4444, 0}, | 46 | DRM_FORMAT_XRGB4444, |
| 76 | {DRM_FORMAT_RGBA4444, 0}, | 47 | DRM_FORMAT_XBGR4444, |
| 77 | {DRM_FORMAT_BGRA4444, 0}, | 48 | DRM_FORMAT_RGBX4444, |
| 78 | {DRM_FORMAT_XRGB4444, 0}, | 49 | DRM_FORMAT_BGRX4444, |
| 79 | {DRM_FORMAT_XBGR4444, 0}, | ||
| 80 | {DRM_FORMAT_RGBX4444, 0}, | ||
| 81 | {DRM_FORMAT_BGRX4444, 0}, | ||
| 82 | |||
| 83 | {DRM_FORMAT_NV12, 0}, | ||
| 84 | {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | ||
| 85 | {DRM_FORMAT_NV21, 0}, | ||
| 86 | {DRM_FORMAT_NV16, 0}, | ||
| 87 | {DRM_FORMAT_NV61, 0}, | ||
| 88 | {DRM_FORMAT_VYUY, 0}, | ||
| 89 | {DRM_FORMAT_UYVY, 0}, | ||
| 90 | {DRM_FORMAT_YUYV, 0}, | ||
| 91 | {DRM_FORMAT_YVYU, 0}, | ||
| 92 | {DRM_FORMAT_YUV420, 0}, | ||
| 93 | {DRM_FORMAT_YVU420, 0}, | ||
| 94 | {0, 0}, | ||
| 95 | }; | ||
| 96 | |||
| 97 | static const struct dpu_format_extended cursor_formats[] = { | ||
| 98 | {DRM_FORMAT_ARGB8888, 0}, | ||
| 99 | {DRM_FORMAT_ABGR8888, 0}, | ||
| 100 | {DRM_FORMAT_RGBA8888, 0}, | ||
| 101 | {DRM_FORMAT_BGRA8888, 0}, | ||
| 102 | {DRM_FORMAT_XRGB8888, 0}, | ||
| 103 | {DRM_FORMAT_ARGB1555, 0}, | ||
| 104 | {DRM_FORMAT_ABGR1555, 0}, | ||
| 105 | {DRM_FORMAT_RGBA5551, 0}, | ||
| 106 | {DRM_FORMAT_BGRA5551, 0}, | ||
| 107 | {DRM_FORMAT_ARGB4444, 0}, | ||
| 108 | {DRM_FORMAT_ABGR4444, 0}, | ||
| 109 | {DRM_FORMAT_RGBA4444, 0}, | ||
| 110 | {DRM_FORMAT_BGRA4444, 0}, | ||
| 111 | {0, 0}, | ||
| 112 | }; | 50 | }; |
| 113 | 51 | ||
| 114 | static const struct dpu_format_extended wb2_formats[] = { | 52 | static const uint32_t plane_formats_yuv[] = { |
| 115 | {DRM_FORMAT_RGB565, 0}, | 53 | DRM_FORMAT_ARGB8888, |
| 116 | {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 54 | DRM_FORMAT_ABGR8888, |
| 117 | {DRM_FORMAT_RGB888, 0}, | 55 | DRM_FORMAT_RGBA8888, |
| 118 | {DRM_FORMAT_ARGB8888, 0}, | 56 | DRM_FORMAT_BGRX8888, |
| 119 | {DRM_FORMAT_RGBA8888, 0}, | 57 | DRM_FORMAT_BGRA8888, |
| 120 | {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 58 | DRM_FORMAT_XRGB8888, |
| 121 | {DRM_FORMAT_XRGB8888, 0}, | 59 | DRM_FORMAT_XBGR8888, |
| 122 | {DRM_FORMAT_RGBX8888, 0}, | 60 | DRM_FORMAT_RGBX8888, |
| 123 | {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 61 | DRM_FORMAT_RGB888, |
| 124 | {DRM_FORMAT_ARGB1555, 0}, | 62 | DRM_FORMAT_BGR888, |
| 125 | {DRM_FORMAT_RGBA5551, 0}, | 63 | DRM_FORMAT_RGB565, |
| 126 | {DRM_FORMAT_XRGB1555, 0}, | 64 | DRM_FORMAT_BGR565, |
| 127 | {DRM_FORMAT_RGBX5551, 0}, | 65 | DRM_FORMAT_ARGB1555, |
| 128 | {DRM_FORMAT_ARGB4444, 0}, | 66 | DRM_FORMAT_ABGR1555, |
| 129 | {DRM_FORMAT_RGBA4444, 0}, | 67 | DRM_FORMAT_RGBA5551, |
| 130 | {DRM_FORMAT_RGBX4444, 0}, | 68 | DRM_FORMAT_BGRA5551, |
| 131 | {DRM_FORMAT_XRGB4444, 0}, | 69 | DRM_FORMAT_XRGB1555, |
| 132 | 70 | DRM_FORMAT_XBGR1555, | |
| 133 | {DRM_FORMAT_BGR565, 0}, | 71 | DRM_FORMAT_RGBX5551, |
| 134 | {DRM_FORMAT_BGR888, 0}, | 72 | DRM_FORMAT_BGRX5551, |
| 135 | {DRM_FORMAT_ABGR8888, 0}, | 73 | DRM_FORMAT_ARGB4444, |
| 136 | {DRM_FORMAT_BGRA8888, 0}, | 74 | DRM_FORMAT_ABGR4444, |
| 137 | {DRM_FORMAT_BGRX8888, 0}, | 75 | DRM_FORMAT_RGBA4444, |
| 138 | {DRM_FORMAT_XBGR8888, 0}, | 76 | DRM_FORMAT_BGRA4444, |
| 139 | {DRM_FORMAT_ABGR1555, 0}, | 77 | DRM_FORMAT_XRGB4444, |
| 140 | {DRM_FORMAT_BGRA5551, 0}, | 78 | DRM_FORMAT_XBGR4444, |
| 141 | {DRM_FORMAT_XBGR1555, 0}, | 79 | DRM_FORMAT_RGBX4444, |
| 142 | {DRM_FORMAT_BGRX5551, 0}, | 80 | DRM_FORMAT_BGRX4444, |
| 143 | {DRM_FORMAT_ABGR4444, 0}, | ||
| 144 | {DRM_FORMAT_BGRA4444, 0}, | ||
| 145 | {DRM_FORMAT_BGRX4444, 0}, | ||
| 146 | {DRM_FORMAT_XBGR4444, 0}, | ||
| 147 | |||
| 148 | {DRM_FORMAT_YUV420, 0}, | ||
| 149 | {DRM_FORMAT_NV12, 0}, | ||
| 150 | {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | ||
| 151 | {DRM_FORMAT_NV16, 0}, | ||
| 152 | {DRM_FORMAT_YUYV, 0}, | ||
| 153 | |||
| 154 | {0, 0}, | ||
| 155 | }; | ||
| 156 | 81 | ||
| 157 | static const struct dpu_format_extended rgb_10bit_formats[] = { | 82 | DRM_FORMAT_NV12, |
| 158 | {DRM_FORMAT_BGRA1010102, 0}, | 83 | DRM_FORMAT_NV21, |
| 159 | {DRM_FORMAT_BGRX1010102, 0}, | 84 | DRM_FORMAT_NV16, |
| 160 | {DRM_FORMAT_RGBA1010102, 0}, | 85 | DRM_FORMAT_NV61, |
| 161 | {DRM_FORMAT_RGBX1010102, 0}, | 86 | DRM_FORMAT_VYUY, |
| 162 | {DRM_FORMAT_ABGR2101010, 0}, | 87 | DRM_FORMAT_UYVY, |
| 163 | {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 88 | DRM_FORMAT_YUYV, |
| 164 | {DRM_FORMAT_XBGR2101010, 0}, | 89 | DRM_FORMAT_YVYU, |
| 165 | {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, | 90 | DRM_FORMAT_YUV420, |
| 166 | {DRM_FORMAT_ARGB2101010, 0}, | 91 | DRM_FORMAT_YVU420, |
| 167 | {DRM_FORMAT_XRGB2101010, 0}, | ||
| 168 | }; | 92 | }; |
| @@ -170,10 +170,6 @@ · 169 unmodified lines | |||
| 170 | /** | 170 | /** |
| 171 | * AD4 interrupt status bit definitions | 171 | * AD4 interrupt status bit definitions |
| 172 | */ | 172 | */ |
| 173 | #define DPU_INTR_BRIGHTPR_UPDATED BIT(4) | ||
| 174 | #define DPU_INTR_DARKENH_UPDATED BIT(3) | ||
| 175 | #define DPU_INTR_STREN_OUTROI_UPDATED BIT(2) | ||
| 176 | #define DPU_INTR_STREN_INROI_UPDATED BIT(1) | ||
| 177 | #define DPU_INTR_BACKLIGHT_UPDATED BIT(0) | 173 | #define DPU_INTR_BACKLIGHT_UPDATED BIT(0) |
| 178 | /** | 174 | /** |
| 179 | * struct dpu_intr_reg - array of DPU register sets | 175 | * struct dpu_intr_reg - array of DPU register sets |
| @@ -782,18 +778,6 @@ static int dpu_hw_intr_irqidx_lookup(enum dpu_intr_type intr_type, · 602 unmodified lines | |||
| 782 | return -EINVAL; | 778 | return -EINVAL; |
| 783 | } | 779 | } |
| 784 | 780 | ||
| 785 | static void dpu_hw_intr_set_mask(struct dpu_hw_intr *intr, uint32_t reg_off, | ||
| 786 | uint32_t mask) | ||
| 787 | { | ||
| 788 | if (!intr) | ||
| 789 | return; | ||
| 790 | |||
| 791 | DPU_REG_WRITE(&intr->hw, reg_off, mask); | ||
| 792 | |||
| 793 | /* ensure register writes go through */ | ||
| 794 | wmb(); | ||
| 795 | } | ||
| 796 | |||
| 797 | static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, | 781 | static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, |
| 798 | void (*cbfunc)(void *, int), | 782 | void (*cbfunc)(void *, int), |
| 799 | void *arg) | 783 | void *arg) |
| @@ -1004,18 +988,6 @@ static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr) · 204 unmodified lines | |||
| 1004 | return 0; | 988 | return 0; |
| 1005 | } | 989 | } |
| 1006 | 990 | ||
| 1007 | static int dpu_hw_intr_get_valid_interrupts(struct dpu_hw_intr *intr, | ||
| 1008 | uint32_t *mask) | ||
| 1009 | { | ||
| 1010 | if (!intr || !mask) | ||
| 1011 | return -EINVAL; | ||
| 1012 | |||
| 1013 | *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 | ||
| 1014 | | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; | ||
| 1015 | |||
| 1016 | return 0; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr) | 991 | static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr) |
| 1020 | { | 992 | { |
| 1021 | int i; | 993 | int i; |
| @@ -1065,19 +1037,6 @@ static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr, · 43 unmodified lines | |||
| 1065 | wmb(); | 1037 | wmb(); |
| 1066 | } | 1038 | } |
| 1067 | 1039 | ||
| 1068 | static void dpu_hw_intr_clear_interrupt_status(struct dpu_hw_intr *intr, | ||
| 1069 | int irq_idx) | ||
| 1070 | { | ||
| 1071 | unsigned long irq_flags; | ||
| 1072 | |||
| 1073 | if (!intr) | ||
| 1074 | return; | ||
| 1075 | |||
| 1076 | spin_lock_irqsave(&intr->irq_lock, irq_flags); | ||
| 1077 | dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx); | ||
| 1078 | spin_unlock_irqrestore(&intr->irq_lock, irq_flags); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, | 1040 | static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, |
| 1082 | int irq_idx, bool clear) | 1041 | int irq_idx, bool clear) |
| 1083 | { | 1042 | { |
| @@ -1113,16 +1072,13 @@ static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, · 29 unmodified lines | |||
| 1113 | 1072 | ||
| 1114 | static void __setup_intr_ops(struct dpu_hw_intr_ops *ops) | 1073 | static void __setup_intr_ops(struct dpu_hw_intr_ops *ops) |
| 1115 | { | 1074 | { |
| 1116 | ops->set_mask = dpu_hw_intr_set_mask; | ||
| 1117 | ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup; | 1075 | ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup; |
| 1118 | ops->enable_irq = dpu_hw_intr_enable_irq; | 1076 | ops->enable_irq = dpu_hw_intr_enable_irq; |
| 1119 | ops->disable_irq = dpu_hw_intr_disable_irq; | 1077 | ops->disable_irq = dpu_hw_intr_disable_irq; |
| 1120 | ops->dispatch_irqs = dpu_hw_intr_dispatch_irq; | 1078 | ops->dispatch_irqs = dpu_hw_intr_dispatch_irq; |
| 1121 | ops->clear_all_irqs = dpu_hw_intr_clear_irqs; | 1079 | ops->clear_all_irqs = dpu_hw_intr_clear_irqs; |
| 1122 | ops->disable_all_irqs = dpu_hw_intr_disable_irqs; | 1080 | ops->disable_all_irqs = dpu_hw_intr_disable_irqs; |
| 1123 | ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts; | ||
| 1124 | ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses; | 1081 | ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses; |
| 1125 | ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status; | ||
| 1126 | ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock; | 1082 | ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock; |
| 1127 | ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status; | 1083 | ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status; |
| 1128 | } | 1084 | } |
| @@ -20,13 +20,6 @@ · 19 unmodified lines | |||
| 20 | #include "dpu_hw_util.h" | 20 | #include "dpu_hw_util.h" |
| 21 | #include "dpu_hw_mdss.h" | 21 | #include "dpu_hw_mdss.h" |
| 22 | 22 | ||
| 23 | #define IRQ_SOURCE_MDP BIT(0) | ||
| 24 | #define IRQ_SOURCE_DSI0 BIT(4) | ||
| 25 | #define IRQ_SOURCE_DSI1 BIT(5) | ||
| 26 | #define IRQ_SOURCE_HDMI BIT(8) | ||
| 27 | #define IRQ_SOURCE_EDP BIT(12) | ||
| 28 | #define IRQ_SOURCE_MHL BIT(16) | ||
| 29 | |||
| 30 | /** | 23 | /** |
| 31 | * dpu_intr_type - HW Interrupt Type | 24 | * dpu_intr_type - HW Interrupt Type |
| 32 | * @DPU_IRQ_TYPE_WB_ROT_COMP: WB rotator done | 25 | * @DPU_IRQ_TYPE_WB_ROT_COMP: WB rotator done |
| @@ -95,18 +88,6 @@ struct dpu_hw_intr; · 62 unmodified lines | |||
| 95 | * Interrupt operations. | 88 | * Interrupt operations. |
| 96 | */ | 89 | */ |
| 97 | struct dpu_hw_intr_ops { | 90 | struct dpu_hw_intr_ops { |
| 98 | /** | ||
| 99 | * set_mask - Programs the given interrupt register with the | ||
| 100 | * given interrupt mask. Register value will get overwritten. | ||
| 101 | * @intr: HW interrupt handle | ||
| 102 | * @reg_off: MDSS HW register offset | ||
| 103 | * @irqmask: IRQ mask value | ||
| 104 | */ | ||
| 105 | void (*set_mask)( | ||
| 106 | struct dpu_hw_intr *intr, | ||
| 107 | uint32_t reg, | ||
| 108 | uint32_t irqmask); | ||
| 109 | |||
| 110 | /** | 91 | /** |
| 111 | * irq_idx_lookup - Lookup IRQ index on the HW interrupt type | 92 | * irq_idx_lookup - Lookup IRQ index on the HW interrupt type |
| 112 | * Used for all irq related ops | 93 | * Used for all irq related ops |
| @@ -176,16 +157,6 @@ struct dpu_hw_intr_ops { · 63 unmodified lines | |||
| 176 | void (*get_interrupt_statuses)( | 157 | void (*get_interrupt_statuses)( |
| 177 | struct dpu_hw_intr *intr); | 158 | struct dpu_hw_intr *intr); |
| 178 | 159 | ||
| 179 | /** | ||
| 180 | * clear_interrupt_status - Clears HW interrupt status based on given | ||
| 181 | * lookup IRQ index. | ||
| 182 | * @intr: HW interrupt handle | ||
| 183 | * @irq_idx: Lookup irq index return from irq_idx_lookup | ||
| 184 | */ | ||
| 185 | void (*clear_interrupt_status)( | ||
| 186 | struct dpu_hw_intr *intr, | ||
| 187 | int irq_idx); | ||
| 188 | |||
| 189 | /** | 160 | /** |
| 190 | * clear_intr_status_nolock() - clears the HW interrupts without lock | 161 | * clear_intr_status_nolock() - clears the HW interrupts without lock |
| 191 | * @intr: HW interrupt handle | 162 | * @intr: HW interrupt handle |
| @@ -206,21 +177,6 @@ struct dpu_hw_intr_ops { · 14 unmodified lines | |||
| 206 | struct dpu_hw_intr *intr, | 177 | struct dpu_hw_intr *intr, |
| 207 | int irq_idx, | 178 | int irq_idx, |
| 208 | bool clear); | 179 | bool clear); |
| 209 | |||
| 210 | /** | ||
| 211 | * get_valid_interrupts - Gets a mask of all valid interrupt sources | ||
| 212 | * within DPU. These are actually status bits | ||
| 213 | * within interrupt registers that specify the | ||
| 214 | * source of the interrupt in IRQs. For example, | ||
| 215 | * valid interrupt sources can be MDP, DSI, | ||
| 216 | * HDMI etc. | ||
| 217 | * @intr: HW interrupt handle | ||
| 218 | * @mask: Returning the interrupt source MASK | ||
| 219 | * @return: 0 for success, otherwise failure | ||
| 220 | */ | ||
| 221 | int (*get_valid_interrupts)( | ||
| 222 | struct dpu_hw_intr *intr, | ||
| 223 | uint32_t *mask); | ||
| 224 | }; | 180 | }; |
| 225 | 181 | ||
| 226 | /** | 182 | /** |
| @@ -258,12 +258,6 @@ enum dpu_vbif { · 257 unmodified lines | |||
| 258 | VBIF_NRT = VBIF_1 | 258 | VBIF_NRT = VBIF_1 |
| 259 | }; | 259 | }; |
| 260 | 260 | ||
| 261 | enum dpu_iommu_domain { | ||
| 262 | DPU_IOMMU_DOMAIN_UNSECURE, | ||
| 263 | DPU_IOMMU_DOMAIN_SECURE, | ||
| 264 | DPU_IOMMU_DOMAIN_MAX | ||
| 265 | }; | ||
| 266 | |||
| 267 | /** | 261 | /** |
| 268 | * DPU HW,Component order color map | 262 | * DPU HW,Component order color map |
| 269 | */ | 263 | */ |
| @@ -358,7 +352,6 @@ enum dpu_3d_blend_mode { · 88 unmodified lines | |||
| 358 | * @alpha_enable: whether the format has an alpha channel | 352 | * @alpha_enable: whether the format has an alpha channel |
| 359 | * @num_planes: number of planes (including meta data planes) | 353 | * @num_planes: number of planes (including meta data planes) |
| 360 | * @fetch_mode: linear, tiled, or ubwc hw fetch behavior | 354 | * @fetch_mode: linear, tiled, or ubwc hw fetch behavior |
| 361 | * @is_yuv: is format a yuv variant | ||
| 362 | * @flag: usage bit flags | 355 | * @flag: usage bit flags |
| 363 | * @tile_width: format tile width | 356 | * @tile_width: format tile width |
| 364 | * @tile_height: format tile height | 357 | * @tile_height: format tile height |
| @@ -18,7 +18,6 @@ · 17 unmodified lines | |||
| 18 | #include "dpu_hw_mdss.h" | 18 | #include "dpu_hw_mdss.h" |
| 19 | 19 | ||
| 20 | #define REG_MASK(n) ((BIT(n)) - 1) | 20 | #define REG_MASK(n) ((BIT(n)) - 1) |
| 21 | struct dpu_format_extended; | ||
| 22 | 21 | ||
| 23 | /* | 22 | /* |
| 24 | * This is the common struct maintained by each sub block | 23 | * This is the common struct maintained by each sub block |
| @@ -405,35 +405,38 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, · 404 unmodified lines | |||
| 405 | } | 405 | } |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | static void _dpu_kms_initialize_dsi(struct drm_device *dev, | 408 | static int _dpu_kms_initialize_dsi(struct drm_device *dev, |
| 409 | struct msm_drm_private *priv, | 409 | struct msm_drm_private *priv, |
| 410 | struct dpu_kms *dpu_kms) | 410 | struct dpu_kms *dpu_kms) |
| 411 | { | 411 | { |
| 412 | struct drm_encoder *encoder = NULL; | 412 | struct drm_encoder *encoder = NULL; |
| 413 | int i, rc; | 413 | int i, rc = 0; |
| 414 | |||
| 415 | if (!(priv->dsi[0] || priv->dsi[1])) | ||
| 416 | return rc; | ||
| 414 | 417 | ||
| 415 | /*TODO: Support two independent DSI connectors */ | 418 | /*TODO: Support two independent DSI connectors */ |
| 416 | encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI); | 419 | encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI); |
| 417 | if (IS_ERR_OR_NULL(encoder)) { | 420 | if (IS_ERR(encoder)) { |
| 418 | DPU_ERROR("encoder init failed for dsi display\n"); | 421 | DPU_ERROR("encoder init failed for dsi display\n"); |
| 419 | return; | 422 | return PTR_ERR(encoder); |
| 420 | } | 423 | } |
| 421 | 424 | ||
| 422 | priv->encoders[priv->num_encoders++] = encoder; | 425 | priv->encoders[priv->num_encoders++] = encoder; |
| 423 | 426 | ||
| 424 | for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { | 427 | for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) { |
| 425 | if (!priv->dsi[i]) { | 428 | if (!priv->dsi[i]) |
| 426 | DPU_DEBUG("invalid msm_dsi for ctrl %d\n", i); | 429 | continue; |
| 427 | return; | ||
| 428 | } | ||
| 429 | 430 | ||
| 430 | rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder); | 431 | rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder); |
| 431 | if (rc) { | 432 | if (rc) { |
| 432 | DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n", | 433 | DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n", |
| 433 | i, rc); | 434 | i, rc); |
| 434 | continue; | 435 | break; |
| 435 | } | 436 | } |
| 436 | } | 437 | } |
| 438 | |||
| 439 | return rc; | ||
| 437 | } | 440 | } |
| 438 | 441 | ||
| 439 | /** | 442 | /** |
| @@ -444,16 +447,16 @@ static void _dpu_kms_initialize_dsi(struct drm_device *dev, · 4 unmodified lines | |||
| 444 | * @dpu_kms: Pointer to dpu kms structure | 447 | * @dpu_kms: Pointer to dpu kms structure |
| 445 | * Returns: Zero on success | 448 | * Returns: Zero on success |
| 446 | */ | 449 | */ |
| 447 | static void _dpu_kms_setup_displays(struct drm_device *dev, | 450 | static int _dpu_kms_setup_displays(struct drm_device *dev, |
| 448 | struct msm_drm_private *priv, | 451 | struct msm_drm_private *priv, |
| 449 | struct dpu_kms *dpu_kms) | 452 | struct dpu_kms *dpu_kms) |
| 450 | { | 453 | { |
| 451 | _dpu_kms_initialize_dsi(dev, priv, dpu_kms); | ||
| 452 | |||
| 453 | /** | 454 | /** |
| 454 | * Extend this function to initialize other | 455 | * Extend this function to initialize other |
| 455 | * types of displays | 456 | * types of displays |
| 456 | */ | 457 | */ |
| 458 | |||
| 459 | return _dpu_kms_initialize_dsi(dev, priv, dpu_kms); | ||
| 457 | } | 460 | } |
| 458 | 461 | ||
| 459 | static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms) | 462 | static void _dpu_kms_drm_obj_destroy(struct dpu_kms *dpu_kms) |
| @@ -516,7 +519,9 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) · 56 unmodified lines | |||
| 516 | * Create encoder and query display drivers to create | 519 | * Create encoder and query display drivers to create |
| 517 | * bridges and connectors | 520 | * bridges and connectors |
| 518 | */ | 521 | */ |
| 519 | _dpu_kms_setup_displays(dev, priv, dpu_kms); | 522 | ret = _dpu_kms_setup_displays(dev, priv, dpu_kms); |
| 523 | if (ret) | ||
| 524 | goto fail; | ||
| 520 | 525 | ||
| 521 | max_crtc_count = min(catalog->mixer_count, priv->num_encoders); | 526 | max_crtc_count = min(catalog->mixer_count, priv->num_encoders); |
| 522 | 527 | ||
| @@ -627,6 +632,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) · 104 unmodified lines | |||
| 627 | devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]); | 632 | devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]); |
| 628 | dpu_kms->vbif[VBIF_RT] = NULL; | 633 | dpu_kms->vbif[VBIF_RT] = NULL; |
| 629 | 634 | ||
| 635 | if (dpu_kms->hw_mdp) | ||
| 636 | dpu_hw_mdp_destroy(dpu_kms->hw_mdp); | ||
| 637 | dpu_kms->hw_mdp = NULL; | ||
| 638 | |||
| 630 | if (dpu_kms->mmio) | 639 | if (dpu_kms->mmio) |
| 631 | devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio); | 640 | devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio); |
| 632 | dpu_kms->mmio = NULL; | 641 | dpu_kms->mmio = NULL; |
| @@ -877,8 +886,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) · 244 unmodified lines | |||
| 877 | goto power_error; | 886 | goto power_error; |
| 878 | } | 887 | } |
| 879 | 888 | ||
| 880 | rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio, | 889 | rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio); |
| 881 | dpu_kms->dev); | ||
| 882 | if (rc) { | 890 | if (rc) { |
| 883 | DPU_ERROR("rm init failed: %d\n", rc); | 891 | DPU_ERROR("rm init failed: %d\n", rc); |
| 884 | goto power_error; | 892 | goto power_error; |
| @@ -886,11 +894,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms) · 1 unmodified line | |||
| 886 | 894 | ||
| 887 | dpu_kms->rm_init = true; | 895 | dpu_kms->rm_init = true; |
| 888 | 896 | ||
| 889 | dpu_kms->hw_mdp = dpu_rm_get_mdp(&dpu_kms->rm); | 897 | dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio, |
| 890 | if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) { | 898 | dpu_kms->catalog); |
| 899 | if (IS_ERR(dpu_kms->hw_mdp)) { | ||
| 891 | rc = PTR_ERR(dpu_kms->hw_mdp); | 900 | rc = PTR_ERR(dpu_kms->hw_mdp); |
| 892 | if (!dpu_kms->hw_mdp) | ||
| 893 | rc = -EINVAL; | ||
| 894 | DPU_ERROR("failed to get hw_mdp: %d\n", rc); | 901 | DPU_ERROR("failed to get hw_mdp: %d\n", rc); |
| 895 | dpu_kms->hw_mdp = NULL; | 902 | dpu_kms->hw_mdp = NULL; |
| 896 | goto power_error; | 903 | goto power_error; |
| @@ -926,16 +933,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms) · 29 unmodified lines | |||
| 926 | goto hw_intr_init_err; | 933 | goto hw_intr_init_err; |
| 927 | } | 934 | } |
| 928 | 935 | ||
| 929 | /* | ||
| 930 | * _dpu_kms_drm_obj_init should create the DRM related objects | ||
| 931 | * i.e. CRTCs, planes, encoders, connectors and so forth | ||
| 932 | */ | ||
| 933 | rc = _dpu_kms_drm_obj_init(dpu_kms); | ||
| 934 | if (rc) { | ||
| 935 | DPU_ERROR("modeset init failed: %d\n", rc); | ||
| 936 | goto drm_obj_init_err; | ||
| 937 | } | ||
| 938 | |||
| 939 | dev->mode_config.min_width = 0; | 936 | dev->mode_config.min_width = 0; |
| 940 | dev->mode_config.min_height = 0; | 937 | dev->mode_config.min_height = 0; |
| 941 | 938 | ||
| @@ -952,6 +949,16 @@ static int dpu_kms_hw_init(struct msm_kms *kms) · 10 unmodified lines | |||
| 952 | */ | 949 | */ |
| 953 | dev->mode_config.allow_fb_modifiers = true; | 950 | dev->mode_config.allow_fb_modifiers = true; |
| 954 | 951 | ||
| 952 | /* | ||
| 953 | * _dpu_kms_drm_obj_init should create the DRM related objects | ||
| 954 | * i.e. CRTCs, planes, encoders, connectors and so forth | ||
| 955 | */ | ||
| 956 | rc = _dpu_kms_drm_obj_init(dpu_kms); | ||
| 957 | if (rc) { | ||
| 958 | DPU_ERROR("modeset init failed: %d\n", rc); | ||
| 959 | goto drm_obj_init_err; | ||
| 960 | } | ||
| 961 | |||
| 955 | dpu_vbif_init_memtypes(dpu_kms); | 962 | dpu_vbif_init_memtypes(dpu_kms); |
| 956 | 963 | ||
| 957 | pm_runtime_put_sync(&dpu_kms->pdev->dev); | 964 | pm_runtime_put_sync(&dpu_kms->pdev->dev); |
| @@ -23,11 +23,14 @@ struct dpu_mdss { · 22 unmodified lines | |||
| 23 | struct dpu_irq_controller irq_controller; | 23 | struct dpu_irq_controller irq_controller; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | static irqreturn_t dpu_mdss_irq(int irq, void *arg) | 26 | static void dpu_mdss_irq(struct irq_desc *desc) |
| 27 | { | 27 | { |
| 28 | struct dpu_mdss *dpu_mdss = arg; | 28 | struct dpu_mdss *dpu_mdss = irq_desc_get_handler_data(desc); |
| 29 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
| 29 | u32 interrupts; | 30 | u32 interrupts; |
| 30 | 31 | ||
| 32 | chained_irq_enter(chip, desc); | ||
| 33 | |||
| 31 | interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS); | 34 | interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS); |
| 32 | 35 | ||
| 33 | while (interrupts) { | 36 | while (interrupts) { |
| @@ -39,20 +42,20 @@ static irqreturn_t dpu_mdss_irq(int irq, void *arg) · 5 unmodified lines | |||
| 39 | hwirq); | 42 | hwirq); |
| 40 | if (mapping == 0) { | 43 | if (mapping == 0) { |
| 41 | DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq); | 44 | DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq); |
| 42 | return IRQ_NONE; | 45 | break; |
| 43 | } | 46 | } |
| 44 | 47 | ||
| 45 | rc = generic_handle_irq(mapping); | 48 | rc = generic_handle_irq(mapping); |
| 46 | if (rc < 0) { | 49 | if (rc < 0) { |
| 47 | DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n", | 50 | DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n", |
| 48 | hwirq, mapping, rc); | 51 | hwirq, mapping, rc); |
| 49 | return IRQ_NONE; | 52 | break; |
| 50 | } | 53 | } |
| 51 | 54 | ||
| 52 | interrupts &= ~(1 << hwirq); | 55 | interrupts &= ~(1 << hwirq); |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | return IRQ_HANDLED; | 58 | chained_irq_exit(chip, desc); |
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | static void dpu_mdss_irq_mask(struct irq_data *irqd) | 61 | static void dpu_mdss_irq_mask(struct irq_data *irqd) |
| @@ -83,16 +86,16 @@ static struct irq_chip dpu_mdss_irq_chip = { · 24 unmodified lines | |||
| 83 | .irq_unmask = dpu_mdss_irq_unmask, | 86 | .irq_unmask = dpu_mdss_irq_unmask, |
| 84 | }; | 87 | }; |
| 85 | 88 | ||
| 89 | static struct lock_class_key dpu_mdss_lock_key, dpu_mdss_request_key; | ||
| 90 | |||
| 86 | static int dpu_mdss_irqdomain_map(struct irq_domain *domain, | 91 | static int dpu_mdss_irqdomain_map(struct irq_domain *domain, |
| 87 | unsigned int irq, irq_hw_number_t hwirq) | 92 | unsigned int irq, irq_hw_number_t hwirq) |
| 88 | { | 93 | { |
| 89 | struct dpu_mdss *dpu_mdss = domain->host_data; | 94 | struct dpu_mdss *dpu_mdss = domain->host_data; |
| 90 | int ret; | ||
| 91 | 95 | ||
| 96 | irq_set_lockdep_class(irq, &dpu_mdss_lock_key, &dpu_mdss_request_key); | ||
| 92 | irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq); | 97 | irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq); |
| 93 | ret = irq_set_chip_data(irq, dpu_mdss); | 98 | return irq_set_chip_data(irq, dpu_mdss); |
| 94 | |||
| 95 | return ret; | ||
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | static const struct irq_domain_ops dpu_mdss_irqdomain_ops = { | 101 | static const struct irq_domain_ops dpu_mdss_irqdomain_ops = { |
| @@ -159,11 +162,13 @@ static void dpu_mdss_destroy(struct drm_device *dev) · 60 unmodified lines | |||
| 159 | struct msm_drm_private *priv = dev->dev_private; | 162 | struct msm_drm_private *priv = dev->dev_private; |
| 160 | struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); | 163 | struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); |
| 161 | struct dss_module_power *mp = &dpu_mdss->mp; | 164 | struct dss_module_power *mp = &dpu_mdss->mp; |
| 165 | int irq; | ||
| 162 | 166 | ||
| 163 | pm_runtime_suspend(dev->dev); | 167 | pm_runtime_suspend(dev->dev); |
| 164 | pm_runtime_disable(dev->dev); | 168 | pm_runtime_disable(dev->dev); |
| 165 | _dpu_mdss_irq_domain_fini(dpu_mdss); | 169 | _dpu_mdss_irq_domain_fini(dpu_mdss); |
| 166 | free_irq(platform_get_irq(pdev, 0), dpu_mdss); | 170 | irq = platform_get_irq(pdev, 0); |
| 171 | irq_set_chained_handler_and_data(irq, NULL, NULL); | ||
| 167 | msm_dss_put_clk(mp->clk_config, mp->num_clk); | 172 | msm_dss_put_clk(mp->clk_config, mp->num_clk); |
| 168 | devm_kfree(&pdev->dev, mp->clk_config); | 173 | devm_kfree(&pdev->dev, mp->clk_config); |
| 169 | 174 | ||
| @@ -187,6 +192,7 @@ int dpu_mdss_init(struct drm_device *dev) · 17 unmodified lines | |||
| 187 | struct dpu_mdss *dpu_mdss; | 192 | struct dpu_mdss *dpu_mdss; |
| 188 | struct dss_module_power *mp; | 193 | struct dss_module_power *mp; |
| 189 | int ret = 0; | 194 | int ret = 0; |
| 195 | int irq; | ||
| 190 | 196 | ||
| 191 | dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL); | 197 | dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL); |
| 192 | if (!dpu_mdss) | 198 | if (!dpu_mdss) |
| @@ -219,12 +225,12 @@ int dpu_mdss_init(struct drm_device *dev) · 26 unmodified lines | |||
| 219 | if (ret) | 225 | if (ret) |
| 220 | goto irq_domain_error; | 226 | goto irq_domain_error; |
| 221 | 227 | ||
| 222 | ret = request_irq(platform_get_irq(pdev, 0), | 228 | irq = platform_get_irq(pdev, 0); |
| 223 | dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss); | 229 | if (irq < 0) |
| 224 | if (ret) { | ||
| 225 | DPU_ERROR("failed to init irq: %d\n", ret); | ||
| 226 | goto irq_error; | 230 | goto irq_error; |
| 227 | } | 231 | |
| 232 | irq_set_chained_handler_and_data(irq, dpu_mdss_irq, | ||
| 233 | dpu_mdss); | ||
| 228 | 234 | ||
| 229 | pm_runtime_enable(dev->dev); | 235 | pm_runtime_enable(dev->dev); |
| 230 | 236 | ||
| @@ -95,8 +95,6 @@ struct dpu_plane { · 94 unmodified lines | |||
| 95 | 95 | ||
| 96 | enum dpu_sspp pipe; | 96 | enum dpu_sspp pipe; |
| 97 | uint32_t features; /* capabilities from catalog */ | 97 | uint32_t features; /* capabilities from catalog */ |
| 98 | uint32_t nformats; | ||
| 99 | uint32_t formats[64]; | ||
| 100 | 98 | ||
| 101 | struct dpu_hw_pipe *pipe_hw; | 99 | struct dpu_hw_pipe *pipe_hw; |
| 102 | struct dpu_hw_pipe_cfg pipe_cfg; | 100 | struct dpu_hw_pipe_cfg pipe_cfg; |
| @@ -121,6 +119,12 @@ struct dpu_plane { · 18 unmodified lines | |||
| 121 | bool debugfs_default_scale; | 119 | bool debugfs_default_scale; |
| 122 | }; | 120 | }; |
| 123 | 121 | ||
| 122 | static const uint64_t supported_format_modifiers[] = { | ||
| 123 | DRM_FORMAT_MOD_QCOM_COMPRESSED, | ||
| 124 | DRM_FORMAT_MOD_LINEAR, | ||
| 125 | DRM_FORMAT_MOD_INVALID | ||
| 126 | }; | ||
| 127 | |||
| 124 | #define to_dpu_plane(x) container_of(x, struct dpu_plane, base) | 128 | #define to_dpu_plane(x) container_of(x, struct dpu_plane, base) |
| 125 | 129 | ||
| 126 | static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane) | 130 | static struct dpu_kms *_dpu_plane_get_kms(struct drm_plane *plane) |
| @@ -1410,6 +1414,23 @@ static void dpu_plane_early_unregister(struct drm_plane *plane) · 1283 unmodified lines | |||
| 1410 | debugfs_remove_recursive(pdpu->debugfs_root); | 1414 | debugfs_remove_recursive(pdpu->debugfs_root); |
| 1411 | } | 1415 | } |
| 1412 | 1416 | ||
| 1417 | static bool dpu_plane_format_mod_supported(struct drm_plane *plane, | ||
| 1418 | uint32_t format, uint64_t modifier) | ||
| 1419 | { | ||
| 1420 | if (modifier == DRM_FORMAT_MOD_LINEAR) | ||
| 1421 | return true; | ||
| 1422 | |||
| 1423 | if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) { | ||
| 1424 | int i; | ||
| 1425 | for (i = 0; i < ARRAY_SIZE(qcom_compressed_supported_formats); i++) { | ||
| 1426 | if (format == qcom_compressed_supported_formats[i]) | ||
| 1427 | return true; | ||
| 1428 | } | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | return false; | ||
| 1432 | } | ||
| 1433 | |||
| 1413 | static const struct drm_plane_funcs dpu_plane_funcs = { | 1434 | static const struct drm_plane_funcs dpu_plane_funcs = { |
| 1414 | .update_plane = drm_atomic_helper_update_plane, | 1435 | .update_plane = drm_atomic_helper_update_plane, |
| 1415 | .disable_plane = drm_atomic_helper_disable_plane, | 1436 | .disable_plane = drm_atomic_helper_disable_plane, |
| @@ -1419,6 +1440,7 @@ static const struct drm_plane_funcs dpu_plane_funcs = { · 3 unmodified lines | |||
| 1419 | .atomic_destroy_state = dpu_plane_destroy_state, | 1440 | .atomic_destroy_state = dpu_plane_destroy_state, |
| 1420 | .late_register = dpu_plane_late_register, | 1441 | .late_register = dpu_plane_late_register, |
| 1421 | .early_unregister = dpu_plane_early_unregister, | 1442 | .early_unregister = dpu_plane_early_unregister, |
| 1443 | .format_mod_supported = dpu_plane_format_mod_supported, | ||
| 1422 | }; | 1444 | }; |
| 1423 | 1445 | ||
| 1424 | static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { | 1446 | static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { |
| @@ -1444,11 +1466,12 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, · 19 unmodified lines | |||
| 1444 | unsigned long possible_crtcs, u32 master_plane_id) | 1466 | unsigned long possible_crtcs, u32 master_plane_id) |
| 1445 | { | 1467 | { |
| 1446 | struct drm_plane *plane = NULL, *master_plane = NULL; | 1468 | struct drm_plane *plane = NULL, *master_plane = NULL; |
| 1447 | const struct dpu_format_extended *format_list; | 1469 | const uint32_t *format_list; |
| 1448 | struct dpu_plane *pdpu; | 1470 | struct dpu_plane *pdpu; |
| 1449 | struct msm_drm_private *priv = dev->dev_private; | 1471 | struct msm_drm_private *priv = dev->dev_private; |
| 1450 | struct dpu_kms *kms = to_dpu_kms(priv->kms); | 1472 | struct dpu_kms *kms = to_dpu_kms(priv->kms); |
| 1451 | int zpos_max = DPU_ZPOS_MAX; | 1473 | int zpos_max = DPU_ZPOS_MAX; |
| 1474 | uint32_t num_formats; | ||
| 1452 | int ret = -EINVAL; | 1475 | int ret = -EINVAL; |
| 1453 | 1476 | ||
| 1454 | /* create and zero local structure */ | 1477 | /* create and zero local structure */ |
| @@ -1491,24 +1514,18 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, · 36 unmodified lines | |||
| 1491 | goto clean_sspp; | 1514 | goto clean_sspp; |
| 1492 | } | 1515 | } |
| 1493 | 1516 | ||
| 1494 | if (!master_plane_id) | 1517 | if (pdpu->is_virtual) { |
| 1495 | format_list = pdpu->pipe_sblk->format_list; | ||
| 1496 | else | ||
| 1497 | format_list = pdpu->pipe_sblk->virt_format_list; | 1518 | format_list = pdpu->pipe_sblk->virt_format_list; |
| 1498 | 1519 | num_formats = pdpu->pipe_sblk->virt_num_formats; | |
| 1499 | pdpu->nformats = dpu_populate_formats(format_list, | 1520 | } |
| 1500 | pdpu->formats, | 1521 | else { |
| 1501 | 0, | 1522 | format_list = pdpu->pipe_sblk->format_list; |
| 1502 | ARRAY_SIZE(pdpu->formats)); | 1523 | num_formats = pdpu->pipe_sblk->num_formats; |
| 1503 | |||
| 1504 | if (!pdpu->nformats) { | ||
| 1505 | DPU_ERROR("[%u]no valid formats for plane\n", pipe); | ||
| 1506 | goto clean_sspp; | ||
| 1507 | } | 1524 | } |
| 1508 | 1525 | ||
| 1509 | ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, | 1526 | ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, |
| 1510 | pdpu->formats, pdpu->nformats, | 1527 | format_list, num_formats, |
| 1511 | NULL, type, NULL); | 1528 | supported_format_modifiers, type, NULL); |
| 1512 | if (ret) | 1529 | if (ret) |
| 1513 | goto clean_sspp; | 1530 | goto clean_sspp; |
| 1514 | 1531 | ||
| @@ -28,23 +28,18 @@ · 27 unmodified lines | |||
| 28 | /** | 28 | /** |
| 29 | * struct dpu_plane_state: Define dpu extension of drm plane state object | 29 | * struct dpu_plane_state: Define dpu extension of drm plane state object |
| 30 | * @base: base drm plane state object | 30 | * @base: base drm plane state object |
| 31 | * @property_state: Local storage for msm_prop properties | ||
| 32 | * @property_values: cached plane property values | ||
| 33 | * @aspace: pointer to address space for input/output buffers | 31 | * @aspace: pointer to address space for input/output buffers |
| 34 | * @input_fence: dereferenced input fence pointer | ||
| 35 | * @stage: assigned by crtc blender | 32 | * @stage: assigned by crtc blender |
| 36 | * @multirect_index: index of the rectangle of SSPP | 33 | * @multirect_index: index of the rectangle of SSPP |
| 37 | * @multirect_mode: parallel or time multiplex multirect mode | 34 | * @multirect_mode: parallel or time multiplex multirect mode |
| 38 | * @pending: whether the current update is still pending | 35 | * @pending: whether the current update is still pending |
| 39 | * @scaler3_cfg: configuration data for scaler3 | 36 | * @scaler3_cfg: configuration data for scaler3 |
| 40 | * @pixel_ext: configuration data for pixel extensions | 37 | * @pixel_ext: configuration data for pixel extensions |
| 41 | * @scaler_check_state: indicates status of user provided pixel extension data | ||
| 42 | * @cdp_cfg: CDP configuration | 38 | * @cdp_cfg: CDP configuration |
| 43 | */ | 39 | */ |
| 44 | struct dpu_plane_state { | 40 | struct dpu_plane_state { |
| 45 | struct drm_plane_state base; | 41 | struct drm_plane_state base; |
| 46 | struct msm_gem_address_space *aspace; | 42 | struct msm_gem_address_space *aspace; |
| 47 | void *input_fence; | ||
| 48 | enum dpu_stage stage; | 43 | enum dpu_stage stage; |
| 49 | uint32_t multirect_index; | 44 | uint32_t multirect_index; |
| 50 | uint32_t multirect_mode; | 45 | uint32_t multirect_mode; |
| @@ -106,12 +101,6 @@ void dpu_plane_restore(struct drm_plane *plane); · 55 unmodified lines | |||
| 106 | */ | 101 | */ |
| 107 | void dpu_plane_flush(struct drm_plane *plane); | 102 | void dpu_plane_flush(struct drm_plane *plane); |
| 108 | 103 | ||
| 109 | /** | ||
| 110 | * dpu_plane_kickoff - final plane operations before commit kickoff | ||
| 111 | * @plane: Pointer to drm plane structure | ||
| 112 | */ | ||
| 113 | void dpu_plane_kickoff(struct drm_plane *plane); | ||
| 114 | |||
| 115 | /** | 104 | /** |
| 116 | * dpu_plane_set_error: enable/disable error condition | 105 | * dpu_plane_set_error: enable/disable error condition |
| 117 | * @plane: pointer to drm_plane structure | 106 | * @plane: pointer to drm_plane structure |
| @@ -146,14 +135,6 @@ int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane); · 28 unmodified lines | |||
| 146 | */ | 135 | */ |
| 147 | void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state); | 136 | void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state); |
| 148 | 137 | ||
| 149 | /** | ||
| 150 | * dpu_plane_wait_input_fence - wait for input fence object | ||
| 151 | * @plane: Pointer to DRM plane object | ||
| 152 | * @wait_ms: Wait timeout value | ||
| 153 | * Returns: Zero on success | ||
| 154 | */ | ||
| 155 | int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms); | ||
| 156 | |||
| 157 | /** | 138 | /** |
| 158 | * dpu_plane_color_fill - enables color fill on plane | 139 | * dpu_plane_color_fill - enables color fill on plane |
| 159 | * @plane: Pointer to DRM plane object | 140 | * @plane: Pointer to DRM plane object |
| @@ -164,12 +145,4 @@ int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms); · 4 unmodified lines | |||
| 164 | int dpu_plane_color_fill(struct drm_plane *plane, | 145 | int dpu_plane_color_fill(struct drm_plane *plane, |
| 165 | uint32_t color, uint32_t alpha); | 146 | uint32_t color, uint32_t alpha); |
| 166 | 147 | ||
| 167 | /** | ||
| 168 | * dpu_plane_set_revalidate - sets revalidate flag which forces a full | ||
| 169 | * validation of the plane properties in the next atomic check | ||
| 170 | * @plane: Pointer to DRM plane object | ||
| 171 | * @enable: Boolean to set/unset the flag | ||
| 172 | */ | ||
| 173 | void dpu_plane_set_revalidate(struct drm_plane *plane, bool enable); | ||
| 174 | |||
| 175 | #endif /* _DPU_PLANE_H_ */ | 148 | #endif /* _DPU_PLANE_H_ */ |
| @@ -21,8 +21,8 @@ · 20 unmodified lines | |||
| 21 | #include "dpu_encoder.h" | 21 | #include "dpu_encoder.h" |
| 22 | #include "dpu_trace.h" | 22 | #include "dpu_trace.h" |
| 23 | 23 | ||
| 24 | #define RESERVED_BY_OTHER(h, r) \ | 24 | #define RESERVED_BY_OTHER(h, r) \ |
| 25 | ((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) | 25 | ((h)->enc_id && (h)->enc_id != r) |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * struct dpu_rm_requirements - Reservation requirements parameter bundle | 28 | * struct dpu_rm_requirements - Reservation requirements parameter bundle |
| @@ -34,90 +34,21 @@ struct dpu_rm_requirements { · 5 unmodified lines | |||
| 34 | struct dpu_encoder_hw_resources hw_res; | 34 | struct dpu_encoder_hw_resources hw_res; |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | /** | ||
| 38 | * struct dpu_rm_rsvp - Use Case Reservation tagging structure | ||
| 39 | * Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain | ||
| 40 | * By using as a tag, rather than lists of pointers to HW blocks used | ||
| 41 | * we can avoid some list management since we don't know how many blocks | ||
| 42 | * of each type a given use case may require. | ||
| 43 | * @list: List head for list of all reservations | ||
| 44 | * @seq: Global RSVP sequence number for debugging, especially for | ||
| 45 | * differentiating differenct allocations for same encoder. | ||
| 46 | * @enc_id: Reservations are tracked by Encoder DRM object ID. | ||
| 47 | * CRTCs may be connected to multiple Encoders. | ||
| 48 | * An encoder or connector id identifies the display path. | ||
| 49 | */ | ||
| 50 | struct dpu_rm_rsvp { | ||
| 51 | struct list_head list; | ||
| 52 | uint32_t seq; | ||
| 53 | uint32_t enc_id; | ||
| 54 | }; | ||
| 55 | 37 | ||
| 56 | /** | 38 | /** |
| 57 | * struct dpu_rm_hw_blk - hardware block tracking list member | 39 | * struct dpu_rm_hw_blk - hardware block tracking list member |
| 58 | * @list: List head for list of all hardware blocks tracking items | 40 | * @list: List head for list of all hardware blocks tracking items |
| 59 | * @rsvp: Pointer to use case reservation if reserved by a client | ||
| 60 | * @rsvp_nxt: Temporary pointer used during reservation to the incoming | ||
| 61 | * request. Will be swapped into rsvp if proposal is accepted | ||
| 62 | * @type: Type of hardware block this structure tracks | ||
| 63 | * @id: Hardware ID number, within it's own space, ie. LM_X | 41 | * @id: Hardware ID number, within it's own space, ie. LM_X |
| 64 | * @catalog: Pointer to the hardware catalog entry for this block | 42 | * @enc_id: Encoder id to which this blk is binded |
| 65 | * @hw: Pointer to the hardware register access object for this block | 43 | * @hw: Pointer to the hardware register access object for this block |
| 66 | */ | 44 | */ |
| 67 | struct dpu_rm_hw_blk { | 45 | struct dpu_rm_hw_blk { |
| 68 | struct list_head list; | 46 | struct list_head list; |
| 69 | struct dpu_rm_rsvp *rsvp; | ||
| 70 | struct dpu_rm_rsvp *rsvp_nxt; | ||
| 71 | enum dpu_hw_blk_type type; | ||
| 72 | uint32_t id; | 47 | uint32_t id; |
| 48 | uint32_t enc_id; | ||
| 73 | struct dpu_hw_blk *hw; | 49 | struct dpu_hw_blk *hw; |
| 74 | }; | 50 | }; |
| 75 | 51 | ||
| 76 | /** | ||
| 77 | * dpu_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging | ||
| 78 | */ | ||
| 79 | enum dpu_rm_dbg_rsvp_stage { | ||
| 80 | DPU_RM_STAGE_BEGIN, | ||
| 81 | DPU_RM_STAGE_AFTER_CLEAR, | ||
| 82 | DPU_RM_STAGE_AFTER_RSVPNEXT, | ||
| 83 | DPU_RM_STAGE_FINAL | ||
| 84 | }; | ||
| 85 | |||
| 86 | static void _dpu_rm_print_rsvps( | ||
| 87 | struct dpu_rm *rm, | ||
| 88 | enum dpu_rm_dbg_rsvp_stage stage) | ||
| 89 | { | ||
| 90 | struct dpu_rm_rsvp *rsvp; | ||
| 91 | struct dpu_rm_hw_blk *blk; | ||
| 92 | enum dpu_hw_blk_type type; | ||
| 93 | |||
| 94 | DPU_DEBUG("%d\n", stage); | ||
| 95 | |||
| 96 | list_for_each_entry(rsvp, &rm->rsvps, list) { | ||
| 97 | DRM_DEBUG_KMS("%d rsvp[s%ue%u]\n", stage, rsvp->seq, | ||
| 98 | rsvp->enc_id); | ||
| 99 | } | ||
| 100 | |||
| 101 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { | ||
| 102 | list_for_each_entry(blk, &rm->hw_blks[type], list) { | ||
| 103 | if (!blk->rsvp && !blk->rsvp_nxt) | ||
| 104 | continue; | ||
| 105 | |||
| 106 | DRM_DEBUG_KMS("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage, | ||
| 107 | (blk->rsvp) ? blk->rsvp->seq : 0, | ||
| 108 | (blk->rsvp) ? blk->rsvp->enc_id : 0, | ||
| 109 | (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, | ||
| 110 | (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, | ||
| 111 | blk->type, blk->id); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm) | ||
| 117 | { | ||
| 118 | return rm->hw_mdp; | ||
| 119 | } | ||
| 120 | |||
| 121 | void dpu_rm_init_hw_iter( | 52 | void dpu_rm_init_hw_iter( |
| 122 | struct dpu_rm_hw_iter *iter, | 53 | struct dpu_rm_hw_iter *iter, |
| 123 | uint32_t enc_id, | 54 | uint32_t enc_id, |
| @@ -148,15 +79,7 @@ static bool _dpu_rm_get_hw_locked(struct dpu_rm *rm, struct dpu_rm_hw_iter *i) · 24 unmodified lines | |||
| 148 | i->blk = list_prepare_entry(i->blk, blk_list, list); | 79 | i->blk = list_prepare_entry(i->blk, blk_list, list); |
| 149 | 80 | ||
| 150 | list_for_each_entry_continue(i->blk, blk_list, list) { | 81 | list_for_each_entry_continue(i->blk, blk_list, list) { |
| 151 | struct dpu_rm_rsvp *rsvp = i->blk->rsvp; | 82 | if (i->enc_id == i->blk->enc_id) { |
| 152 | |||
| 153 | if (i->blk->type != i->type) { | ||
| 154 | DPU_ERROR("found incorrect block type %d on %d list\n", | ||
| 155 | i->blk->type, i->type); | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | |||
| 159 | if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) { | ||
| 160 | i->hw = i->blk->hw; | 83 | i->hw = i->blk->hw; |
| 161 | DPU_DEBUG("found type %d id %d for enc %d\n", | 84 | DPU_DEBUG("found type %d id %d for enc %d\n", |
| 162 | i->type, i->blk->id, i->enc_id); | 85 | i->type, i->blk->id, i->enc_id); |
| @@ -208,34 +131,18 @@ static void _dpu_rm_hw_destroy(enum dpu_hw_blk_type type, void *hw) · 45 unmodified lines | |||
| 208 | 131 | ||
| 209 | int dpu_rm_destroy(struct dpu_rm *rm) | 132 | int dpu_rm_destroy(struct dpu_rm *rm) |
| 210 | { | 133 | { |
| 211 | |||
| 212 | struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt; | ||
| 213 | struct dpu_rm_hw_blk *hw_cur, *hw_nxt; | 134 | struct dpu_rm_hw_blk *hw_cur, *hw_nxt; |
| 214 | enum dpu_hw_blk_type type; | 135 | enum dpu_hw_blk_type type; |
| 215 | 136 | ||
| 216 | if (!rm) { | ||
| 217 | DPU_ERROR("invalid rm\n"); | ||
| 218 | return -EINVAL; | ||
| 219 | } | ||
| 220 | |||
| 221 | list_for_each_entry_safe(rsvp_cur, rsvp_nxt, &rm->rsvps, list) { | ||
| 222 | list_del(&rsvp_cur->list); | ||
| 223 | kfree(rsvp_cur); | ||
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { | 137 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { |
| 228 | list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type], | 138 | list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type], |
| 229 | list) { | 139 | list) { |
| 230 | list_del(&hw_cur->list); | 140 | list_del(&hw_cur->list); |
| 231 | _dpu_rm_hw_destroy(hw_cur->type, hw_cur->hw); | 141 | _dpu_rm_hw_destroy(type, hw_cur->hw); |
| 232 | kfree(hw_cur); | 142 | kfree(hw_cur); |
| 233 | } | 143 | } |
| 234 | } | 144 | } |
| 235 | 145 | ||
| 236 | dpu_hw_mdp_destroy(rm->hw_mdp); | ||
| 237 | rm->hw_mdp = NULL; | ||
| 238 | |||
| 239 | mutex_destroy(&rm->rm_lock); | 146 | mutex_destroy(&rm->rm_lock); |
| 240 | 147 | ||
| 241 | return 0; | 148 | return 0; |
| @@ -250,11 +157,8 @@ static int _dpu_rm_hw_blk_create( · 8 unmodified lines | |||
| 250 | void *hw_catalog_info) | 157 | void *hw_catalog_info) |
| 251 | { | 158 | { |
| 252 | struct dpu_rm_hw_blk *blk; | 159 | struct dpu_rm_hw_blk *blk; |
| 253 | struct dpu_hw_mdp *hw_mdp; | ||
| 254 | void *hw; | 160 | void *hw; |
| 255 | 161 | ||
| 256 | hw_mdp = rm->hw_mdp; | ||
| 257 | |||
| 258 | switch (type) { | 162 | switch (type) { |
| 259 | case DPU_HW_BLK_LM: | 163 | case DPU_HW_BLK_LM: |
| 260 | hw = dpu_hw_lm_init(id, mmio, cat); | 164 | hw = dpu_hw_lm_init(id, mmio, cat); |
| @@ -290,9 +194,9 @@ static int _dpu_rm_hw_blk_create( · 29 unmodified lines | |||
| 290 | return -ENOMEM; | 194 | return -ENOMEM; |
| 291 | } | 195 | } |
| 292 | 196 | ||
| 293 | blk->type = type; | ||
| 294 | blk->id = id; | 197 | blk->id = id; |
| 295 | blk->hw = hw; | 198 | blk->hw = hw; |
| 199 | blk->enc_id = 0; | ||
| 296 | list_add_tail(&blk->list, &rm->hw_blks[type]); | 200 | list_add_tail(&blk->list, &rm->hw_blks[type]); |
| 297 | 201 | ||
| 298 | return 0; | 202 | return 0; |
| @@ -300,13 +204,12 @@ static int _dpu_rm_hw_blk_create( · 1 unmodified line | |||
| 300 | 204 | ||
| 301 | int dpu_rm_init(struct dpu_rm *rm, | 205 | int dpu_rm_init(struct dpu_rm *rm, |
| 302 | struct dpu_mdss_cfg *cat, | 206 | struct dpu_mdss_cfg *cat, |
| 303 | void __iomem *mmio, | 207 | void __iomem *mmio) |
| 304 | struct drm_device *dev) | ||
| 305 | { | 208 | { |
| 306 | int rc, i; | 209 | int rc, i; |
| 307 | enum dpu_hw_blk_type type; | 210 | enum dpu_hw_blk_type type; |
| 308 | 211 | ||
| 309 | if (!rm || !cat || !mmio || !dev) { | 212 | if (!rm || !cat || !mmio) { |
| 310 | DPU_ERROR("invalid kms\n"); | 213 | DPU_ERROR("invalid kms\n"); |
| 311 | return -EINVAL; | 214 | return -EINVAL; |
| 312 | } | 215 | } |
| @@ -316,21 +219,9 @@ int dpu_rm_init(struct dpu_rm *rm, · 3 unmodified lines | |||
| 316 | 219 | ||
| 317 | mutex_init(&rm->rm_lock); | 220 | mutex_init(&rm->rm_lock); |
| 318 | 221 | ||
| 319 | INIT_LIST_HEAD(&rm->rsvps); | ||
| 320 | for (type = 0; type < DPU_HW_BLK_MAX; type++) | 222 | for (type = 0; type < DPU_HW_BLK_MAX; type++) |
| 321 | INIT_LIST_HEAD(&rm->hw_blks[type]); | 223 | INIT_LIST_HEAD(&rm->hw_blks[type]); |
| 322 | 224 | ||
| 323 | rm->dev = dev; | ||
| 324 | |||
| 325 | /* Some of the sub-blocks require an mdptop to be created */ | ||
| 326 | rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat); | ||
| 327 | if (IS_ERR_OR_NULL(rm->hw_mdp)) { | ||
| 328 | rc = PTR_ERR(rm->hw_mdp); | ||
| 329 | rm->hw_mdp = NULL; | ||
| 330 | DPU_ERROR("failed: mdp hw not available\n"); | ||
| 331 | goto fail; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* Interrogate HW catalog and create tracking items for hw blocks */ | 225 | /* Interrogate HW catalog and create tracking items for hw blocks */ |
| 335 | for (i = 0; i < cat->mixer_count; i++) { | 226 | for (i = 0; i < cat->mixer_count; i++) { |
| 336 | struct dpu_lm_cfg *lm = &cat->mixer[i]; | 227 | struct dpu_lm_cfg *lm = &cat->mixer[i]; |
| @@ -410,7 +301,7 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) · 73 unmodified lines | |||
| 410 | * proposed use case requirements, incl. hardwired dependent blocks like | 301 | * proposed use case requirements, incl. hardwired dependent blocks like |
| 411 | * pingpong | 302 | * pingpong |
| 412 | * @rm: dpu resource manager handle | 303 | * @rm: dpu resource manager handle |
| 413 | * @rsvp: reservation currently being created | 304 | * @enc_id: encoder id requesting for allocation |
| 414 | * @reqs: proposed use case requirements | 305 | * @reqs: proposed use case requirements |
| 415 | * @lm: proposed layer mixer, function checks if lm, and all other hardwired | 306 | * @lm: proposed layer mixer, function checks if lm, and all other hardwired |
| 416 | * blocks connected to the lm (pp) is available and appropriate | 307 | * blocks connected to the lm (pp) is available and appropriate |
| @@ -422,7 +313,7 @@ static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) · 5 unmodified lines | |||
| 422 | */ | 313 | */ |
| 423 | static bool _dpu_rm_check_lm_and_get_connected_blks( | 314 | static bool _dpu_rm_check_lm_and_get_connected_blks( |
| 424 | struct dpu_rm *rm, | 315 | struct dpu_rm *rm, |
| 425 | struct dpu_rm_rsvp *rsvp, | 316 | uint32_t enc_id, |
| 426 | struct dpu_rm_requirements *reqs, | 317 | struct dpu_rm_requirements *reqs, |
| 427 | struct dpu_rm_hw_blk *lm, | 318 | struct dpu_rm_hw_blk *lm, |
| 428 | struct dpu_rm_hw_blk **pp, | 319 | struct dpu_rm_hw_blk **pp, |
| @@ -449,7 +340,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( · 20 unmodified lines | |||
| 449 | } | 340 | } |
| 450 | 341 | ||
| 451 | /* Already reserved? */ | 342 | /* Already reserved? */ |
| 452 | if (RESERVED_BY_OTHER(lm, rsvp)) { | 343 | if (RESERVED_BY_OTHER(lm, enc_id)) { |
| 453 | DPU_DEBUG("lm %d already reserved\n", lm_cfg->id); | 344 | DPU_DEBUG("lm %d already reserved\n", lm_cfg->id); |
| 454 | return false; | 345 | return false; |
| 455 | } | 346 | } |
| @@ -467,7 +358,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( · 11 unmodified lines | |||
| 467 | return false; | 358 | return false; |
| 468 | } | 359 | } |
| 469 | 360 | ||
| 470 | if (RESERVED_BY_OTHER(*pp, rsvp)) { | 361 | if (RESERVED_BY_OTHER(*pp, enc_id)) { |
| 471 | DPU_DEBUG("lm %d pp %d already reserved\n", lm->id, | 362 | DPU_DEBUG("lm %d pp %d already reserved\n", lm->id, |
| 472 | (*pp)->id); | 363 | (*pp)->id); |
| 473 | return false; | 364 | return false; |
| @@ -476,10 +367,8 @@ static bool _dpu_rm_check_lm_and_get_connected_blks( · 2 unmodified lines | |||
| 476 | return true; | 367 | return true; |
| 477 | } | 368 | } |
| 478 | 369 | ||
| 479 | static int _dpu_rm_reserve_lms( | 370 | static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id, |
| 480 | struct dpu_rm *rm, | 371 | struct dpu_rm_requirements *reqs) |
| 481 | struct dpu_rm_rsvp *rsvp, | ||
| 482 | struct dpu_rm_requirements *reqs) | ||
| 483 | 372 | ||
| 484 | { | 373 | { |
| 485 | struct dpu_rm_hw_blk *lm[MAX_BLOCKS]; | 374 | struct dpu_rm_hw_blk *lm[MAX_BLOCKS]; |
| @@ -504,7 +393,7 @@ static int _dpu_rm_reserve_lms( · 18 unmodified lines | |||
| 504 | lm[lm_count] = iter_i.blk; | 393 | lm[lm_count] = iter_i.blk; |
| 505 | 394 | ||
| 506 | if (!_dpu_rm_check_lm_and_get_connected_blks( | 395 | if (!_dpu_rm_check_lm_and_get_connected_blks( |
| 507 | rm, rsvp, reqs, lm[lm_count], | 396 | rm, enc_id, reqs, lm[lm_count], |
| 508 | &pp[lm_count], NULL)) | 397 | &pp[lm_count], NULL)) |
| 509 | continue; | 398 | continue; |
| 510 | 399 | ||
| @@ -519,7 +408,7 @@ static int _dpu_rm_reserve_lms( · 8 unmodified lines | |||
| 519 | continue; | 408 | continue; |
| 520 | 409 | ||
| 521 | if (!_dpu_rm_check_lm_and_get_connected_blks( | 410 | if (!_dpu_rm_check_lm_and_get_connected_blks( |
| 522 | rm, rsvp, reqs, iter_j.blk, | 411 | rm, enc_id, reqs, iter_j.blk, |
| 523 | &pp[lm_count], iter_i.blk)) | 412 | &pp[lm_count], iter_i.blk)) |
| 524 | continue; | 413 | continue; |
| 525 | 414 | ||
| @@ -537,11 +426,10 @@ static int _dpu_rm_reserve_lms( · 11 unmodified lines | |||
| 537 | if (!lm[i]) | 426 | if (!lm[i]) |
| 538 | break; | 427 | break; |
| 539 | 428 | ||
| 540 | lm[i]->rsvp_nxt = rsvp; | 429 | lm[i]->enc_id = enc_id; |
| 541 | pp[i]->rsvp_nxt = rsvp; | 430 | pp[i]->enc_id = enc_id; |
| 542 | 431 | ||
| 543 | trace_dpu_rm_reserve_lms(lm[i]->id, lm[i]->type, rsvp->enc_id, | 432 | trace_dpu_rm_reserve_lms(lm[i]->id, enc_id, pp[i]->id); |
| 544 | pp[i]->id); | ||
| 545 | } | 433 | } |
| 546 | 434 | ||
| 547 | return rc; | 435 | return rc; |
| @@ -549,7 +437,7 @@ static int _dpu_rm_reserve_lms( · 1 unmodified line | |||
| 549 | 437 | ||
| 550 | static int _dpu_rm_reserve_ctls( | 438 | static int _dpu_rm_reserve_ctls( |
| 551 | struct dpu_rm *rm, | 439 | struct dpu_rm *rm, |
| 552 | struct dpu_rm_rsvp *rsvp, | 440 | uint32_t enc_id, |
| 553 | const struct msm_display_topology *top) | 441 | const struct msm_display_topology *top) |
| 554 | { | 442 | { |
| 555 | struct dpu_rm_hw_blk *ctls[MAX_BLOCKS]; | 443 | struct dpu_rm_hw_blk *ctls[MAX_BLOCKS]; |
| @@ -570,7 +458,7 @@ static int _dpu_rm_reserve_ctls( · 14 unmodified lines | |||
| 570 | unsigned long features = ctl->caps->features; | 458 | unsigned long features = ctl->caps->features; |
| 571 | bool has_split_display; | 459 | bool has_split_display; |
| 572 | 460 | ||
| 573 | if (RESERVED_BY_OTHER(iter.blk, rsvp)) | 461 | if (RESERVED_BY_OTHER(iter.blk, enc_id)) |
| 574 | continue; | 462 | continue; |
| 575 | 463 | ||
| 576 | has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; | 464 | has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; |
| @@ -591,9 +479,8 @@ static int _dpu_rm_reserve_ctls( · 14 unmodified lines | |||
| 591 | return -ENAVAIL; | 479 | return -ENAVAIL; |
| 592 | 480 | ||
| 593 | for (i = 0; i < ARRAY_SIZE(ctls) && i < num_ctls; i++) { | 481 | for (i = 0; i < ARRAY_SIZE(ctls) && i < num_ctls; i++) { |
| 594 | ctls[i]->rsvp_nxt = rsvp; | 482 | ctls[i]->enc_id = enc_id; |
| 595 | trace_dpu_rm_reserve_ctls(ctls[i]->id, ctls[i]->type, | 483 | trace_dpu_rm_reserve_ctls(ctls[i]->id, enc_id); |
| 596 | rsvp->enc_id); | ||
| 597 | } | 484 | } |
| 598 | 485 | ||
| 599 | return 0; | 486 | return 0; |
| @@ -601,7 +488,7 @@ static int _dpu_rm_reserve_ctls( · 1 unmodified line | |||
| 601 | 488 | ||
| 602 | static int _dpu_rm_reserve_intf( | 489 | static int _dpu_rm_reserve_intf( |
| 603 | struct dpu_rm *rm, | 490 | struct dpu_rm *rm, |
| 604 | struct dpu_rm_rsvp *rsvp, | 491 | uint32_t enc_id, |
| 605 | uint32_t id, | 492 | uint32_t id, |
| 606 | enum dpu_hw_blk_type type) | 493 | enum dpu_hw_blk_type type) |
| 607 | { | 494 | { |
| @@ -614,14 +501,13 @@ static int _dpu_rm_reserve_intf( · 6 unmodified lines | |||
| 614 | if (iter.blk->id != id) | 501 | if (iter.blk->id != id) |
| 615 | continue; | 502 | continue; |
| 616 | 503 | ||
| 617 | if (RESERVED_BY_OTHER(iter.blk, rsvp)) { | 504 | if (RESERVED_BY_OTHER(iter.blk, enc_id)) { |
| 618 | DPU_ERROR("type %d id %d already reserved\n", type, id); | 505 | DPU_ERROR("type %d id %d already reserved\n", type, id); |
| 619 | return -ENAVAIL; | 506 | return -ENAVAIL; |
| 620 | } | 507 | } |
| 621 | 508 | ||
| 622 | iter.blk->rsvp_nxt = rsvp; | 509 | iter.blk->enc_id = enc_id; |
| 623 | trace_dpu_rm_reserve_intf(iter.blk->id, iter.blk->type, | 510 | trace_dpu_rm_reserve_intf(iter.blk->id, enc_id); |
| 624 | rsvp->enc_id); | ||
| 625 | break; | 511 | break; |
| 626 | } | 512 | } |
| 627 | 513 | ||
| @@ -636,7 +522,7 @@ static int _dpu_rm_reserve_intf( · 8 unmodified lines | |||
| 636 | 522 | ||
| 637 | static int _dpu_rm_reserve_intf_related_hw( | 523 | static int _dpu_rm_reserve_intf_related_hw( |
| 638 | struct dpu_rm *rm, | 524 | struct dpu_rm *rm, |
| 639 | struct dpu_rm_rsvp *rsvp, | 525 | uint32_t enc_id, |
| 640 | struct dpu_encoder_hw_resources *hw_res) | 526 | struct dpu_encoder_hw_resources *hw_res) |
| 641 | { | 527 | { |
| 642 | int i, ret = 0; | 528 | int i, ret = 0; |
| @@ -646,7 +532,7 @@ static int _dpu_rm_reserve_intf_related_hw( · 3 unmodified lines | |||
| 646 | if (hw_res->intfs[i] == INTF_MODE_NONE) | 532 | if (hw_res->intfs[i] == INTF_MODE_NONE) |
| 647 | continue; | 533 | continue; |
| 648 | id = i + INTF_0; | 534 | id = i + INTF_0; |
| 649 | ret = _dpu_rm_reserve_intf(rm, rsvp, id, | 535 | ret = _dpu_rm_reserve_intf(rm, enc_id, id, |
| 650 | DPU_HW_BLK_INTF); | 536 | DPU_HW_BLK_INTF); |
| 651 | if (ret) | 537 | if (ret) |
| 652 | return ret; | 538 | return ret; |
| @@ -655,33 +541,27 @@ static int _dpu_rm_reserve_intf_related_hw( · 2 unmodified lines | |||
| 655 | return ret; | 541 | return ret; |
| 656 | } | 542 | } |
| 657 | 543 | ||
| 658 | static int _dpu_rm_make_next_rsvp( | 544 | static int _dpu_rm_make_reservation( |
| 659 | struct dpu_rm *rm, | 545 | struct dpu_rm *rm, |
| 660 | struct drm_encoder *enc, | 546 | struct drm_encoder *enc, |
| 661 | struct drm_crtc_state *crtc_state, | 547 | struct drm_crtc_state *crtc_state, |
| 662 | struct dpu_rm_rsvp *rsvp, | ||
| 663 | struct dpu_rm_requirements *reqs) | 548 | struct dpu_rm_requirements *reqs) |
| 664 | { | 549 | { |
| 665 | int ret; | 550 | int ret; |
| 666 | 551 | ||
| 667 | /* Create reservation info, tag reserved blocks with it as we go */ | 552 | ret = _dpu_rm_reserve_lms(rm, enc->base.id, reqs); |
| 668 | rsvp->seq = ++rm->rsvp_next_seq; | ||
| 669 | rsvp->enc_id = enc->base.id; | ||
| 670 | list_add_tail(&rsvp->list, &rm->rsvps); | ||
| 671 | |||
| 672 | ret = _dpu_rm_reserve_lms(rm, rsvp, reqs); | ||
| 673 | if (ret) { | 553 | if (ret) { |
| 674 | DPU_ERROR("unable to find appropriate mixers\n"); | 554 | DPU_ERROR("unable to find appropriate mixers\n"); |
| 675 | return ret; | 555 | return ret; |
| 676 | } | 556 | } |
| 677 | 557 | ||
| 678 | ret = _dpu_rm_reserve_ctls(rm, rsvp, &reqs->topology); | 558 | ret = _dpu_rm_reserve_ctls(rm, enc->base.id, &reqs->topology); |
| 679 | if (ret) { | 559 | if (ret) { |
| 680 | DPU_ERROR("unable to find appropriate CTL\n"); | 560 | DPU_ERROR("unable to find appropriate CTL\n"); |
| 681 | return ret; | 561 | return ret; |
| 682 | } | 562 | } |
| 683 | 563 | ||
| 684 | ret = _dpu_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res); | 564 | ret = _dpu_rm_reserve_intf_related_hw(rm, enc->base.id, &reqs->hw_res); |
| 685 | if (ret) | 565 | if (ret) |
| 686 | return ret; | 566 | return ret; |
| 687 | 567 | ||
| @@ -706,108 +586,31 @@ static int _dpu_rm_populate_requirements( · 18 unmodified lines | |||
| 706 | return 0; | 586 | return 0; |
| 707 | } | 587 | } |
| 708 | 588 | ||
| 709 | static struct dpu_rm_rsvp *_dpu_rm_get_rsvp( | 589 | static void _dpu_rm_release_reservation(struct dpu_rm *rm, uint32_t enc_id) |
| 710 | struct dpu_rm *rm, | ||
| 711 | struct drm_encoder *enc) | ||
| 712 | { | 590 | { |
| 713 | struct dpu_rm_rsvp *i; | ||
| 714 | |||
| 715 | if (!rm || !enc) { | ||
| 716 | DPU_ERROR("invalid params\n"); | ||
| 717 | return NULL; | ||
| 718 | } | ||
| 719 | |||
| 720 | if (list_empty(&rm->rsvps)) | ||
| 721 | return NULL; | ||
| 722 | |||
| 723 | list_for_each_entry(i, &rm->rsvps, list) | ||
| 724 | if (i->enc_id == enc->base.id) | ||
| 725 | return i; | ||
| 726 | |||
| 727 | return NULL; | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * _dpu_rm_release_rsvp - release resources and release a reservation | ||
| 732 | * @rm: KMS handle | ||
| 733 | * @rsvp: RSVP pointer to release and release resources for | ||
| 734 | */ | ||
| 735 | static void _dpu_rm_release_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp) | ||
| 736 | { | ||
| 737 | struct dpu_rm_rsvp *rsvp_c, *rsvp_n; | ||
| 738 | struct dpu_rm_hw_blk *blk; | 591 | struct dpu_rm_hw_blk *blk; |
| 739 | enum dpu_hw_blk_type type; | 592 | enum dpu_hw_blk_type type; |
| 740 | 593 | ||
| 741 | if (!rsvp) | ||
| 742 | return; | ||
| 743 | |||
| 744 | DPU_DEBUG("rel rsvp %d enc %d\n", rsvp->seq, rsvp->enc_id); | ||
| 745 | |||
| 746 | list_for_each_entry_safe(rsvp_c, rsvp_n, &rm->rsvps, list) { | ||
| 747 | if (rsvp == rsvp_c) { | ||
| 748 | list_del(&rsvp_c->list); | ||
| 749 | break; | ||
| 750 | } | ||
| 751 | } | ||
| 752 | |||
| 753 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { | 594 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { |
| 754 | list_for_each_entry(blk, &rm->hw_blks[type], list) { | 595 | list_for_each_entry(blk, &rm->hw_blks[type], list) { |
| 755 | if (blk->rsvp == rsvp) { | 596 | if (blk->enc_id == enc_id) { |
| 756 | blk->rsvp = NULL; | 597 | blk->enc_id = 0; |
| 757 | DPU_DEBUG("rel rsvp %d enc %d %d %d\n", | 598 | DPU_DEBUG("rel enc %d %d %d\n", enc_id, |
| 758 | rsvp->seq, rsvp->enc_id, | 599 | type, blk->id); |
| 759 | blk->type, blk->id); | ||
| 760 | } | ||
| 761 | if (blk->rsvp_nxt == rsvp) { | ||
| 762 | blk->rsvp_nxt = NULL; | ||
| 763 | DPU_DEBUG("rel rsvp_nxt %d enc %d %d %d\n", | ||
| 764 | rsvp->seq, rsvp->enc_id, | ||
| 765 | blk->type, blk->id); | ||
| 766 | } | 600 | } |
| 767 | } | 601 | } |
| 768 | } | 602 | } |
| 769 | |||
| 770 | kfree(rsvp); | ||
| 771 | } | 603 | } |
| 772 | 604 | ||
| 773 | void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc) | 605 | void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc) |
| 774 | { | 606 | { |
| 775 | struct dpu_rm_rsvp *rsvp; | ||
| 776 | |||
| 777 | if (!rm || !enc) { | ||
| 778 | DPU_ERROR("invalid params\n"); | ||
| 779 | return; | ||
| 780 | } | ||
| 781 | |||
| 782 | mutex_lock(&rm->rm_lock); | 607 | mutex_lock(&rm->rm_lock); |
| 783 | 608 | ||
| 784 | rsvp = _dpu_rm_get_rsvp(rm, enc); | 609 | _dpu_rm_release_reservation(rm, enc->base.id); |
| 785 | if (!rsvp) { | ||
| 786 | DPU_ERROR("failed to find rsvp for enc %d\n", enc->base.id); | ||
| 787 | goto end; | ||
| 788 | } | ||
| 789 | 610 | ||
| 790 | _dpu_rm_release_rsvp(rm, rsvp); | ||
| 791 | end: | ||
| 792 | mutex_unlock(&rm->rm_lock); | 611 | mutex_unlock(&rm->rm_lock); |
| 793 | } | 612 | } |
| 794 | 613 | ||
| 795 | static void _dpu_rm_commit_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp) | ||
| 796 | { | ||
| 797 | struct dpu_rm_hw_blk *blk; | ||
| 798 | enum dpu_hw_blk_type type; | ||
| 799 | |||
| 800 | /* Swap next rsvp to be the active */ | ||
| 801 | for (type = 0; type < DPU_HW_BLK_MAX; type++) { | ||
| 802 | list_for_each_entry(blk, &rm->hw_blks[type], list) { | ||
| 803 | if (blk->rsvp_nxt) { | ||
| 804 | blk->rsvp = blk->rsvp_nxt; | ||
| 805 | blk->rsvp_nxt = NULL; | ||
| 806 | } | ||
| 807 | } | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | int dpu_rm_reserve( | 614 | int dpu_rm_reserve( |
| 812 | struct dpu_rm *rm, | 615 | struct dpu_rm *rm, |
| 813 | struct drm_encoder *enc, | 616 | struct drm_encoder *enc, |
| @@ -815,7 +618,6 @@ int dpu_rm_reserve( · 1 unmodified line | |||
| 815 | struct msm_display_topology topology, | 618 | struct msm_display_topology topology, |
| 816 | bool test_only) | 619 | bool test_only) |
| 817 | { | 620 | { |
| 818 | struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt; | ||
| 819 | struct dpu_rm_requirements reqs; | 621 | struct dpu_rm_requirements reqs; |
| 820 | int ret; | 622 | int ret; |
| 821 | 623 | ||
| @@ -828,8 +630,6 @@ int dpu_rm_reserve( · 6 unmodified lines | |||
| 828 | 630 | ||
| 829 | mutex_lock(&rm->rm_lock); | 631 | mutex_lock(&rm->rm_lock); |
| 830 | 632 | ||
| 831 | _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_BEGIN); | ||
| 832 | |||
| 833 | ret = _dpu_rm_populate_requirements(rm, enc, crtc_state, &reqs, | 633 | ret = _dpu_rm_populate_requirements(rm, enc, crtc_state, &reqs, |
| 834 | topology); | 634 | topology); |
| 835 | if (ret) { | 635 | if (ret) { |
| @@ -837,50 +637,17 @@ int dpu_rm_reserve( · 1 unmodified line | |||
| 837 | goto end; | 637 | goto end; |
| 838 | } | 638 | } |
| 839 | 639 | ||
| 840 | /* | 640 | ret = _dpu_rm_make_reservation(rm, enc, crtc_state, &reqs); |
| 841 | * We only support one active reservation per-hw-block. But to implement | ||
| 842 | * transactional semantics for test-only, and for allowing failure while | ||
| 843 | * modifying your existing reservation, over the course of this | ||
| 844 | * function we can have two reservations: | ||
| 845 | * Current: Existing reservation | ||
| 846 | * Next: Proposed reservation. The proposed reservation may fail, or may | ||
| 847 | * be discarded if in test-only mode. | ||
| 848 | * If reservation is successful, and we're not in test-only, then we | ||
| 849 | * replace the current with the next. | ||
| 850 | */ | ||
| 851 | rsvp_nxt = kzalloc(sizeof(*rsvp_nxt), GFP_KERNEL); | ||
| 852 | if (!rsvp_nxt) { | ||
| 853 | ret = -ENOMEM; | ||
| 854 | goto end; | ||
| 855 | } | ||
| 856 | |||
| 857 | rsvp_cur = _dpu_rm_get_rsvp(rm, enc); | ||
| 858 | |||
| 859 | /* Check the proposed reservation, store it in hw's "next" field */ | ||
| 860 | ret = _dpu_rm_make_next_rsvp(rm, enc, crtc_state, rsvp_nxt, &reqs); | ||
| 861 | |||
| 862 | _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_AFTER_RSVPNEXT); | ||
| 863 | |||
| 864 | if (ret) { | 641 | if (ret) { |
| 865 | DPU_ERROR("failed to reserve hw resources: %d\n", ret); | 642 | DPU_ERROR("failed to reserve hw resources: %d\n", ret); |
| 866 | _dpu_rm_release_rsvp(rm, rsvp_nxt); | 643 | _dpu_rm_release_reservation(rm, enc->base.id); |
| 867 | } else if (test_only) { | 644 | } else if (test_only) { |
| 868 | /* | 645 | /* test_only: test the reservation and then undo */ |
| 869 | * Normally, if test_only, test the reservation and then undo | 646 | DPU_DEBUG("test_only: discard test [enc: %d]\n", |
| 870 | * However, if the user requests LOCK, then keep the reservation | 647 | enc->base.id); |
| 871 | * made during the atomic_check phase. | 648 | _dpu_rm_release_reservation(rm, enc->base.id); |
| 872 | */ | ||
| 873 | DPU_DEBUG("test_only: discard test rsvp[s%de%d]\n", | ||
| 874 | rsvp_nxt->seq, rsvp_nxt->enc_id); | ||
| 875 | _dpu_rm_release_rsvp(rm, rsvp_nxt); | ||
| 876 | } else { | ||
| 877 | _dpu_rm_release_rsvp(rm, rsvp_cur); | ||
| 878 | |||
| 879 | _dpu_rm_commit_rsvp(rm, rsvp_nxt); | ||
| 880 | } | 649 | } |
| 881 | 650 | ||
| 882 | _dpu_rm_print_rsvps(rm, DPU_RM_STAGE_FINAL); | ||
| 883 | |||
| 884 | end: | 651 | end: |
| 885 | mutex_unlock(&rm->rm_lock); | 652 | mutex_unlock(&rm->rm_lock); |
| 886 | 653 | ||
| @@ -22,22 +22,14 @@ · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | /** | 23 | /** |
| 24 | * struct dpu_rm - DPU dynamic hardware resource manager | 24 | * struct dpu_rm - DPU dynamic hardware resource manager |
| 25 | * @dev: device handle for event logging purposes | ||
| 26 | * @rsvps: list of hardware reservations by each crtc->encoder->connector | ||
| 27 | * @hw_blks: array of lists of hardware resources present in the system, one | 25 | * @hw_blks: array of lists of hardware resources present in the system, one |
| 28 | * list per type of hardware block | 26 | * list per type of hardware block |
| 29 | * @hw_mdp: hardware object for mdp_top | ||
| 30 | * @lm_max_width: cached layer mixer maximum width | 27 | * @lm_max_width: cached layer mixer maximum width |
| 31 | * @rsvp_next_seq: sequence number for next reservation for debugging purposes | ||
| 32 | * @rm_lock: resource manager mutex | 28 | * @rm_lock: resource manager mutex |
| 33 | */ | 29 | */ |
| 34 | struct dpu_rm { | 30 | struct dpu_rm { |
| 35 | struct drm_device *dev; | ||
| 36 | struct list_head rsvps; | ||
| 37 | struct list_head hw_blks[DPU_HW_BLK_MAX]; | 31 | struct list_head hw_blks[DPU_HW_BLK_MAX]; |
| 38 | struct dpu_hw_mdp *hw_mdp; | ||
| 39 | uint32_t lm_max_width; | 32 | uint32_t lm_max_width; |
| 40 | uint32_t rsvp_next_seq; | ||
| 41 | struct mutex rm_lock; | 33 | struct mutex rm_lock; |
| 42 | }; | 34 | }; |
| 43 | 35 | ||
| @@ -67,13 +59,11 @@ struct dpu_rm_hw_iter { · 23 unmodified lines | |||
| 67 | * @rm: DPU Resource Manager handle | 59 | * @rm: DPU Resource Manager handle |
| 68 | * @cat: Pointer to hardware catalog | 60 | * @cat: Pointer to hardware catalog |
| 69 | * @mmio: mapped register io address of MDP | 61 | * @mmio: mapped register io address of MDP |
| 70 | * @dev: device handle for event logging purposes | ||
| 71 | * @Return: 0 on Success otherwise -ERROR | 62 | * @Return: 0 on Success otherwise -ERROR |
| 72 | */ | 63 | */ |
| 73 | int dpu_rm_init(struct dpu_rm *rm, | 64 | int dpu_rm_init(struct dpu_rm *rm, |
| 74 | struct dpu_mdss_cfg *cat, | 65 | struct dpu_mdss_cfg *cat, |
| 75 | void __iomem *mmio, | 66 | void __iomem *mmio); |
| 76 | struct drm_device *dev); | ||
| 77 | 67 | ||
| 78 | /** | 68 | /** |
| 79 | * dpu_rm_destroy - Free all memory allocated by dpu_rm_init | 69 | * dpu_rm_destroy - Free all memory allocated by dpu_rm_init |
| @@ -111,14 +101,6 @@ int dpu_rm_reserve(struct dpu_rm *rm, · 31 unmodified lines | |||
| 111 | */ | 101 | */ |
| 112 | void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc); | 102 | void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc); |
| 113 | 103 | ||
| 114 | /** | ||
| 115 | * dpu_rm_get_mdp - Retrieve HW block for MDP TOP. | ||
| 116 | * This is never reserved, and is usable by any display. | ||
| 117 | * @rm: DPU Resource Manager handle | ||
| 118 | * @Return: Pointer to hw block or NULL | ||
| 119 | */ | ||
| 120 | struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm); | ||
| 121 | |||
| 122 | /** | 104 | /** |
| 123 | * dpu_rm_init_hw_iter - setup given iterator for new iteration over hw list | 105 | * dpu_rm_init_hw_iter - setup given iterator for new iteration over hw list |
| 124 | * using dpu_rm_get_hw | 106 | * using dpu_rm_get_hw |
| @@ -144,12 +126,4 @@ void dpu_rm_init_hw_iter( · 19 unmodified lines | |||
| 144 | * @Return: true on match found, false on no match found | 126 | * @Return: true on match found, false on no match found |
| 145 | */ | 127 | */ |
| 146 | bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter); | 128 | bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter); |
| 147 | |||
| 148 | /** | ||
| 149 | * dpu_rm_check_property_topctl - validate property bitmask before it is set | ||
| 150 | * @val: user's proposed topology control bitmask | ||
| 151 | * @Return: 0 on success or error | ||
| 152 | */ | ||
| 153 | int dpu_rm_check_property_topctl(uint64_t val); | ||
| 154 | |||
| 155 | #endif /* __DPU_RM_H__ */ | 129 | #endif /* __DPU_RM_H__ */ |
| @@ -831,48 +831,42 @@ TRACE_EVENT(dpu_plane_disable, · 830 unmodified lines | |||
| 831 | ); | 831 | ); |
| 832 | 832 | ||
| 833 | DECLARE_EVENT_CLASS(dpu_rm_iter_template, | 833 | DECLARE_EVENT_CLASS(dpu_rm_iter_template, |
| 834 | TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), | 834 | TP_PROTO(uint32_t id, uint32_t enc_id), |
| 835 | TP_ARGS(id, type, enc_id), | 835 | TP_ARGS(id, enc_id), |
| 836 | TP_STRUCT__entry( | 836 | TP_STRUCT__entry( |
| 837 | __field( uint32_t, id ) | 837 | __field( uint32_t, id ) |
| 838 | __field( enum dpu_hw_blk_type, type ) | ||
| 839 | __field( uint32_t, enc_id ) | 838 | __field( uint32_t, enc_id ) |
| 840 | ), | 839 | ), |
| 841 | TP_fast_assign( | 840 | TP_fast_assign( |
| 842 | __entry->id = id; | 841 | __entry->id = id; |
| 843 | __entry->type = type; | ||
| 844 | __entry->enc_id = enc_id; | 842 | __entry->enc_id = enc_id; |
| 845 | ), | 843 | ), |
| 846 | TP_printk("id:%d type:%d enc_id:%u", __entry->id, __entry->type, | 844 | TP_printk("id:%d enc_id:%u", __entry->id, __entry->enc_id) |
| 847 | __entry->enc_id) | ||
| 848 | ); | 845 | ); |
| 849 | DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_intf, | 846 | DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_intf, |
| 850 | TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), | 847 | TP_PROTO(uint32_t id, uint32_t enc_id), |
| 851 | TP_ARGS(id, type, enc_id) | 848 | TP_ARGS(id, enc_id) |
| 852 | ); | 849 | ); |
| 853 | DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_ctls, | 850 | DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_ctls, |
| 854 | TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id), | 851 | TP_PROTO(uint32_t id, uint32_t enc_id), |
| 855 | TP_ARGS(id, type, enc_id) | 852 | TP_ARGS(id, enc_id) |
| 856 | ); | 853 | ); |
| 857 | 854 | ||
| 858 | TRACE_EVENT(dpu_rm_reserve_lms, | 855 | TRACE_EVENT(dpu_rm_reserve_lms, |
| 859 | TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id, | 856 | TP_PROTO(uint32_t id, uint32_t enc_id, uint32_t pp_id), |
| 860 | uint32_t pp_id), | 857 | TP_ARGS(id, enc_id, pp_id), |
| 861 | TP_ARGS(id, type, enc_id, pp_id), | ||
| 862 | TP_STRUCT__entry( | 858 | TP_STRUCT__entry( |
| 863 | __field( uint32_t, id ) | 859 | __field( uint32_t, id ) |
| 864 | __field( enum dpu_hw_blk_type, type ) | ||
| 865 | __field( uint32_t, enc_id ) | 860 | __field( uint32_t, enc_id ) |
| 866 | __field( uint32_t, pp_id ) | 861 | __field( uint32_t, pp_id ) |
| 867 | ), | 862 | ), |
| 868 | TP_fast_assign( | 863 | TP_fast_assign( |
| 869 | __entry->id = id; | 864 | __entry->id = id; |
| 870 | __entry->type = type; | ||
| 871 | __entry->enc_id = enc_id; | 865 | __entry->enc_id = enc_id; |
| 872 | __entry->pp_id = pp_id; | 866 | __entry->pp_id = pp_id; |
| 873 | ), | 867 | ), |
| 874 | TP_printk("id:%d type:%d enc_id:%u pp_id:%u", __entry->id, | 868 | TP_printk("id:%d enc_id:%u pp_id:%u", __entry->id, |
| 875 | __entry->type, __entry->enc_id, __entry->pp_id) | 869 | __entry->enc_id, __entry->pp_id) |
| 876 | ); | 870 | ); |
| 877 | 871 | ||
| 878 | TRACE_EVENT(dpu_vbif_wait_xin_halt_fail, | 872 | TRACE_EVENT(dpu_vbif_wait_xin_halt_fail, |
| @@ -207,62 +207,44 @@ u32 msm_readl(const void __iomem *addr) · 206 unmodified lines | |||
| 207 | return val; | 207 | return val; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | struct vblank_event { | 210 | struct msm_vblank_work { |
| 211 | struct list_head node; | 211 | struct work_struct work; |
| 212 | int crtc_id; | 212 | int crtc_id; |
| 213 | bool enable; | 213 | bool enable; |
| 214 | struct msm_drm_private *priv; | ||
| 214 | }; | 215 | }; |
| 215 | 216 | ||
| 216 | static void vblank_ctrl_worker(struct kthread_work *work) | 217 | static void vblank_ctrl_worker(struct work_struct *work) |
| 217 | { | 218 | { |
| 218 | struct msm_vblank_ctrl *vbl_ctrl = container_of(work, | 219 | struct msm_vblank_work *vbl_work = container_of(work, |
| 219 | struct msm_vblank_ctrl, work); | 220 | struct msm_vblank_work, work); |
| 220 | struct msm_drm_private *priv = container_of(vbl_ctrl, | 221 | struct msm_drm_private *priv = vbl_work->priv; |
| 221 | struct msm_drm_private, vblank_ctrl); | ||
| 222 | struct msm_kms *kms = priv->kms; | 222 | struct msm_kms *kms = priv->kms; |
| 223 | struct vblank_event *vbl_ev, *tmp; | ||
| 224 | unsigned long flags; | ||
| 225 | |||
| 226 | spin_lock_irqsave(&vbl_ctrl->lock, flags); | ||
| 227 | list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) { | ||
| 228 | list_del(&vbl_ev->node); | ||
| 229 | spin_unlock_irqrestore(&vbl_ctrl->lock, flags); | ||
| 230 | |||
| 231 | if (vbl_ev->enable) | ||
| 232 | kms->funcs->enable_vblank(kms, | ||
| 233 | priv->crtcs[vbl_ev->crtc_id]); | ||
| 234 | else | ||
| 235 | kms->funcs->disable_vblank(kms, | ||
| 236 | priv->crtcs[vbl_ev->crtc_id]); | ||
| 237 | |||
| 238 | kfree(vbl_ev); | ||
| 239 | 223 | ||
| 240 | spin_lock_irqsave(&vbl_ctrl->lock, flags); | 224 | if (vbl_work->enable) |
| 241 | } | 225 | kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); |
| 226 | else | ||
| 227 | kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]); | ||
| 242 | 228 | ||
| 243 | spin_unlock_irqrestore(&vbl_ctrl->lock, flags); | 229 | kfree(vbl_work); |
| 244 | } | 230 | } |
| 245 | 231 | ||
| 246 | static int vblank_ctrl_queue_work(struct msm_drm_private *priv, | 232 | static int vblank_ctrl_queue_work(struct msm_drm_private *priv, |
| 247 | int crtc_id, bool enable) | 233 | int crtc_id, bool enable) |
| 248 | { | 234 | { |
| 249 | struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; | 235 | struct msm_vblank_work *vbl_work; |
| 250 | struct vblank_event *vbl_ev; | ||
| 251 | unsigned long flags; | ||
| 252 | 236 | ||
| 253 | vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC); | 237 | vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC); |
| 254 | if (!vbl_ev) | 238 | if (!vbl_work) |
| 255 | return -ENOMEM; | 239 | return -ENOMEM; |
| 256 | 240 | ||
| 257 | vbl_ev->crtc_id = crtc_id; | 241 | INIT_WORK(&vbl_work->work, vblank_ctrl_worker); |
| 258 | vbl_ev->enable = enable; | ||
| 259 | 242 | ||
| 260 | spin_lock_irqsave(&vbl_ctrl->lock, flags); | 243 | vbl_work->crtc_id = crtc_id; |
| 261 | list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list); | 244 | vbl_work->enable = enable; |
| 262 | spin_unlock_irqrestore(&vbl_ctrl->lock, flags); | 245 | vbl_work->priv = priv; |
| 263 | 246 | ||
| 264 | kthread_queue_work(&priv->disp_thread[crtc_id].worker, | 247 | queue_work(priv->wq, &vbl_work->work); |
| 265 | &vbl_ctrl->work); | ||
| 266 | 248 | ||
| 267 | return 0; | 249 | return 0; |
| 268 | } | 250 | } |
| @@ -274,31 +256,20 @@ static int msm_drm_uninit(struct device *dev) · 5 unmodified lines | |||
| 274 | struct msm_drm_private *priv = ddev->dev_private; | 256 | struct msm_drm_private *priv = ddev->dev_private; |
| 275 | struct msm_kms *kms = priv->kms; | 257 | struct msm_kms *kms = priv->kms; |
| 276 | struct msm_mdss *mdss = priv->mdss; | 258 | struct msm_mdss *mdss = priv->mdss; |
| 277 | struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; | ||
| 278 | struct vblank_event *vbl_ev, *tmp; | ||
| 279 | int i; | 259 | int i; |
| 280 | 260 | ||
| 281 | /* We must cancel and cleanup any pending vblank enable/disable | 261 | /* We must cancel and cleanup any pending vblank enable/disable |
| 282 | * work before drm_irq_uninstall() to avoid work re-enabling an | 262 | * work before drm_irq_uninstall() to avoid work re-enabling an |
| 283 | * irq after uninstall has disabled it. | 263 | * irq after uninstall has disabled it. |
| 284 | */ | 264 | */ |
| 285 | kthread_flush_work(&vbl_ctrl->work); | ||
| 286 | list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) { | ||
| 287 | list_del(&vbl_ev->node); | ||
| 288 | kfree(vbl_ev); | ||
| 289 | } | ||
| 290 | 265 | ||
| 291 | /* clean up display commit/event worker threads */ | 266 | flush_workqueue(priv->wq); |
| 292 | for (i = 0; i < priv->num_crtcs; i++) { | 267 | destroy_workqueue(priv->wq); |
| 293 | if (priv->disp_thread[i].thread) { | ||
| 294 | kthread_flush_worker(&priv->disp_thread[i].worker); | ||
| 295 | kthread_stop(priv->disp_thread[i].thread); | ||
| 296 | priv->disp_thread[i].thread = NULL; | ||
| 297 | } | ||
| 298 | 268 | ||
| 269 | /* clean up event worker threads */ | ||
| 270 | for (i = 0; i < priv->num_crtcs; i++) { | ||
| 299 | if (priv->event_thread[i].thread) { | 271 | if (priv->event_thread[i].thread) { |
| 300 | kthread_flush_worker(&priv->event_thread[i].worker); | 272 | kthread_destroy_worker(&priv->event_thread[i].worker); |
| 301 | kthread_stop(priv->event_thread[i].thread); | ||
| 302 | priv->event_thread[i].thread = NULL; | 273 | priv->event_thread[i].thread = NULL; |
| 303 | } | 274 | } |
| 304 | } | 275 | } |
| @@ -323,9 +294,6 @@ static int msm_drm_uninit(struct device *dev) · 18 unmodified lines | |||
| 323 | drm_irq_uninstall(ddev); | 294 | drm_irq_uninstall(ddev); |
| 324 | pm_runtime_put_sync(dev); | 295 | pm_runtime_put_sync(dev); |
| 325 | 296 | ||
| 326 | flush_workqueue(priv->wq); | ||
| 327 | destroy_workqueue(priv->wq); | ||
| 328 | |||
| 329 | if (kms && kms->funcs) | 297 | if (kms && kms->funcs) |
| 330 | kms->funcs->destroy(kms); | 298 | kms->funcs->destroy(kms); |
| 331 | 299 | ||
| @@ -490,9 +458,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) · 158 unmodified lines | |||
| 490 | priv->wq = alloc_ordered_workqueue("msm", 0); | 458 | priv->wq = alloc_ordered_workqueue("msm", 0); |
| 491 | 459 | ||
| 492 | INIT_LIST_HEAD(&priv->inactive_list); | 460 | INIT_LIST_HEAD(&priv->inactive_list); |
| 493 | INIT_LIST_HEAD(&priv->vblank_ctrl.event_list); | ||
| 494 | kthread_init_work(&priv->vblank_ctrl.work, vblank_ctrl_worker); | ||
| 495 | spin_lock_init(&priv->vblank_ctrl.lock); | ||
| 496 | 461 | ||
| 497 | drm_mode_config_init(ddev); | 462 | drm_mode_config_init(ddev); |
| 498 | 463 | ||
| @@ -554,27 +519,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) · 55 unmodified lines | |||
| 554 | */ | 519 | */ |
| 555 | param.sched_priority = 16; | 520 | param.sched_priority = 16; |
| 556 | for (i = 0; i < priv->num_crtcs; i++) { | 521 | for (i = 0; i < priv->num_crtcs; i++) { |
| 557 | |||
| 558 | /* initialize display thread */ | ||
| 559 | priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; | ||
| 560 | kthread_init_worker(&priv->disp_thread[i].worker); | ||
| 561 | priv->disp_thread[i].dev = ddev; | ||
| 562 | priv->disp_thread[i].thread = | ||
| 563 | kthread_run(kthread_worker_fn, | ||
| 564 | &priv->disp_thread[i].worker, | ||
| 565 | "crtc_commit:%d", priv->disp_thread[i].crtc_id); | ||
| 566 | if (IS_ERR(priv->disp_thread[i].thread)) { | ||
| 567 | DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n"); | ||
| 568 | priv->disp_thread[i].thread = NULL; | ||
| 569 | goto err_msm_uninit; | ||
| 570 | } | ||
| 571 | |||
| 572 | ret = sched_setscheduler(priv->disp_thread[i].thread, | ||
| 573 | SCHED_FIFO, ¶m); | ||
| 574 | if (ret) | ||
| 575 | dev_warn(dev, "disp_thread set priority failed: %d\n", | ||
| 576 | ret); | ||
| 577 | |||
| 578 | /* initialize event thread */ | 522 | /* initialize event thread */ |
| 579 | priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; | 523 | priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; |
| 580 | kthread_init_worker(&priv->event_thread[i].worker); | 524 | kthread_init_worker(&priv->event_thread[i].worker); |
| @@ -589,13 +533,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) · 8 unmodified lines | |||
| 589 | goto err_msm_uninit; | 533 | goto err_msm_uninit; |
| 590 | } | 534 | } |
| 591 | 535 | ||
| 592 | /** | ||
| 593 | * event thread should also run at same priority as disp_thread | ||
| 594 | * because it is handling frame_done events. A lower priority | ||
| 595 | * event thread and higher priority disp_thread can causes | ||
| 596 | * frame_pending counters beyond 2. This can lead to commit | ||
| 597 | * failure at crtc commit level. | ||
| 598 | */ | ||
| 599 | ret = sched_setscheduler(priv->event_thread[i].thread, | 536 | ret = sched_setscheduler(priv->event_thread[i].thread, |
| 600 | SCHED_FIFO, ¶m); | 537 | SCHED_FIFO, ¶m); |
| 601 | if (ret) | 538 | if (ret) |
| @@ -914,8 +851,12 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, · 312 unmodified lines | |||
| 914 | ret = -EINVAL; | 851 | ret = -EINVAL; |
| 915 | break; | 852 | break; |
| 916 | } | 853 | } |
| 917 | ret = copy_from_user(msm_obj->name, | 854 | if (copy_from_user(msm_obj->name, u64_to_user_ptr(args->value), |
| 918 | u64_to_user_ptr(args->value), args->len); | 855 | args->len)) { |
| 856 | msm_obj->name[0] = '\0'; | ||
| 857 | ret = -EFAULT; | ||
| 858 | break; | ||
| 859 | } | ||
| 919 | msm_obj->name[args->len] = '\0'; | 860 | msm_obj->name[args->len] = '\0'; |
| 920 | for (i = 0; i < args->len; i++) { | 861 | for (i = 0; i < args->len; i++) { |
| 921 | if (!isprint(msm_obj->name[i])) { | 862 | if (!isprint(msm_obj->name[i])) { |
| @@ -931,8 +872,9 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, · 9 unmodified lines | |||
| 931 | } | 872 | } |
| 932 | args->len = strlen(msm_obj->name); | 873 | args->len = strlen(msm_obj->name); |
| 933 | if (args->value) { | 874 | if (args->value) { |
| 934 | ret = copy_to_user(u64_to_user_ptr(args->value), | 875 | if (copy_to_user(u64_to_user_ptr(args->value), |
| 935 | msm_obj->name, args->len); | 876 | msm_obj->name, args->len)) |
| 877 | ret = -EFAULT; | ||
| 936 | } | 878 | } |
| 937 | break; | 879 | break; |
| 938 | } | 880 | } |
| @@ -77,12 +77,6 @@ enum msm_mdp_plane_property { · 76 unmodified lines | |||
| 77 | PLANE_PROP_MAX_NUM | 77 | PLANE_PROP_MAX_NUM |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | struct msm_vblank_ctrl { | ||
| 81 | struct kthread_work work; | ||
| 82 | struct list_head event_list; | ||
| 83 | spinlock_t lock; | ||
| 84 | }; | ||
| 85 | |||
| 86 | #define MSM_GPU_MAX_RINGS 4 | 80 | #define MSM_GPU_MAX_RINGS 4 |
| 87 | #define MAX_H_TILES_PER_DISPLAY 2 | 81 | #define MAX_H_TILES_PER_DISPLAY 2 |
| 88 | 82 | ||
| @@ -126,7 +120,7 @@ struct msm_display_topology { · 37 unmodified lines | |||
| 126 | 120 | ||
| 127 | /** | 121 | /** |
| 128 | * struct msm_display_info - defines display properties | 122 | * struct msm_display_info - defines display properties |
| 129 | * @intf_type: DRM_MODE_CONNECTOR_ display type | 123 | * @intf_type: DRM_MODE_ENCODER_ type |
| 130 | * @capabilities: Bitmask of display flags | 124 | * @capabilities: Bitmask of display flags |
| 131 | * @num_of_h_tiles: Number of horizontal tiles in case of split interface | 125 | * @num_of_h_tiles: Number of horizontal tiles in case of split interface |
| 132 | * @h_tile_instance: Controller instance used per tile. Number of elements is | 126 | * @h_tile_instance: Controller instance used per tile. Number of elements is |
| @@ -199,7 +193,6 @@ struct msm_drm_private { · 66 unmodified lines | |||
| 199 | unsigned int num_crtcs; | 193 | unsigned int num_crtcs; |
| 200 | struct drm_crtc *crtcs[MAX_CRTCS]; | 194 | struct drm_crtc *crtcs[MAX_CRTCS]; |
| 201 | 195 | ||
| 202 | struct msm_drm_thread disp_thread[MAX_CRTCS]; | ||
| 203 | struct msm_drm_thread event_thread[MAX_CRTCS]; | 196 | struct msm_drm_thread event_thread[MAX_CRTCS]; |
| 204 | 197 | ||
| 205 | unsigned int num_encoders; | 198 | unsigned int num_encoders; |
| @@ -228,7 +221,6 @@ struct msm_drm_private { · 22 unmodified lines | |||
| 228 | struct notifier_block vmap_notifier; | 221 | struct notifier_block vmap_notifier; |
| 229 | struct shrinker shrinker; | 222 | struct shrinker shrinker; |
| 230 | 223 | ||
| 231 | struct msm_vblank_ctrl vblank_ctrl; | ||
| 232 | struct drm_atomic_state *pm_state; | 224 | struct drm_atomic_state *pm_state; |
| 233 | }; | 225 | }; |
| 234 | 226 | ||
| @@ -560,6 +560,8 @@ · 559 unmodified lines | |||
| 560 | # define DP_TEST_LINK_EDID_READ (1 << 2) | 560 | # define DP_TEST_LINK_EDID_READ (1 << 2) |
| 561 | # define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ | 561 | # define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ |
| 562 | # define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ | 562 | # define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ |
| 563 | # define DP_TEST_LINK_AUDIO_PATTERN (1 << 5) /* DPCD >= 1.2 */ | ||
| 564 | # define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6) /* DPCD >= 1.2 */ | ||
| 563 | 565 | ||
| 564 | #define DP_TEST_LINK_RATE 0x219 | 566 | #define DP_TEST_LINK_RATE 0x219 |
| 565 | # define DP_LINK_RATE_162 (0x6) | 567 | # define DP_LINK_RATE_162 (0x6) |
| @@ -608,6 +610,7 @@ · 42 unmodified lines | |||
| 608 | # define DP_COLOR_FORMAT_RGB (0 << 1) | 610 | # define DP_COLOR_FORMAT_RGB (0 << 1) |
| 609 | # define DP_COLOR_FORMAT_YCbCr422 (1 << 1) | 611 | # define DP_COLOR_FORMAT_YCbCr422 (1 << 1) |
| 610 | # define DP_COLOR_FORMAT_YCbCr444 (2 << 1) | 612 | # define DP_COLOR_FORMAT_YCbCr444 (2 << 1) |
| 613 | # define DP_TEST_DYNAMIC_RANGE_VESA (0 << 3) | ||
| 611 | # define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3) | 614 | # define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3) |
| 612 | # define DP_TEST_YCBCR_COEFFICIENTS (1 << 4) | 615 | # define DP_TEST_YCBCR_COEFFICIENTS (1 << 4) |
| 613 | # define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4) | 616 | # define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4) |
| @@ -657,6 +660,16 @@ · 43 unmodified lines | |||
| 657 | 660 | ||
| 658 | #define DP_TEST_SINK 0x270 | 661 | #define DP_TEST_SINK 0x270 |
| 659 | # define DP_TEST_SINK_START (1 << 0) | 662 | # define DP_TEST_SINK_START (1 << 0) |
| 663 | #define DP_TEST_AUDIO_MODE 0x271 | ||
| 664 | #define DP_TEST_AUDIO_PATTERN_TYPE 0x272 | ||
| 665 | #define DP_TEST_AUDIO_PERIOD_CH1 0x273 | ||
| 666 | #define DP_TEST_AUDIO_PERIOD_CH2 0x274 | ||
| 667 | #define DP_TEST_AUDIO_PERIOD_CH3 0x275 | ||
| 668 | #define DP_TEST_AUDIO_PERIOD_CH4 0x276 | ||
| 669 | #define DP_TEST_AUDIO_PERIOD_CH5 0x277 | ||
| 670 | #define DP_TEST_AUDIO_PERIOD_CH6 0x278 | ||
| 671 | #define DP_TEST_AUDIO_PERIOD_CH7 0x279 | ||
| 672 | #define DP_TEST_AUDIO_PERIOD_CH8 0x27A | ||
| 660 | 673 | ||
| 661 | #define DP_FEC_STATUS 0x280 /* 1.4 */ | 674 | #define DP_FEC_STATUS 0x280 /* 1.4 */ |
| 662 | # define DP_FEC_DECODE_EN_DETECTED (1 << 0) | 675 | # define DP_FEC_DECODE_EN_DETECTED (1 << 0) |