Merge https://gitlab.freedesktop.org/drm/msm into drm-next
On the display side, cleanups and fixes to enabled modifiers (QCOM_COMPRESSED). And otherwise mostly misc fixes all around. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rob Clark <robdclark@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGuZ5uBKpf=fHvKpTiD10nychuEY8rnE+HeRz0QMvtY5_A@mail.gmail.com
This commit is contained in:
commit
a5f2fafece
|
@ -0,0 +1,59 @@
|
|||
Qualcomm adreno/snapdragon GMU (Graphics management unit)
|
||||
|
||||
The GMU is a programmable power controller for the GPU. the CPU controls the
|
||||
GMU which in turn handles power controls for the GPU.
|
||||
|
||||
Required properties:
|
||||
- compatible: "qcom,adreno-gmu-XYZ.W", "qcom,adreno-gmu"
|
||||
for example: "qcom,adreno-gmu-630.2", "qcom,adreno-gmu"
|
||||
Note that you need to list the less specific "qcom,adreno-gmu"
|
||||
for generic matches and the more specific identifier to identify
|
||||
the specific device.
|
||||
- reg: Physical base address and length of the GMU registers.
|
||||
- reg-names: Matching names for the register regions
|
||||
* "gmu"
|
||||
* "gmu_pdc"
|
||||
* "gmu_pdc_seg"
|
||||
- interrupts: The interrupt signals from the GMU.
|
||||
- interrupt-names: Matching names for the interrupts
|
||||
* "hfi"
|
||||
* "gmu"
|
||||
- clocks: phandles to the device clocks
|
||||
- clock-names: Matching names for the clocks
|
||||
* "gmu"
|
||||
* "cxo"
|
||||
* "axi"
|
||||
* "mnoc"
|
||||
- power-domains: should be <&clock_gpucc GPU_CX_GDSC>
|
||||
- iommus: phandle to the adreno iommu
|
||||
- operating-points-v2: phandle to the OPP operating points
|
||||
|
||||
Example:
|
||||
|
||||
/ {
|
||||
...
|
||||
|
||||
gmu: gmu@506a000 {
|
||||
compatible="qcom,adreno-gmu-630.2", "qcom,adreno-gmu";
|
||||
|
||||
reg = <0x506a000 0x30000>,
|
||||
<0xb280000 0x10000>,
|
||||
<0xb480000 0x10000>;
|
||||
reg-names = "gmu", "gmu_pdc", "gmu_pdc_seq";
|
||||
|
||||
interrupts = <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "hfi", "gmu";
|
||||
|
||||
clocks = <&gpucc GPU_CC_CX_GMU_CLK>,
|
||||
<&gpucc GPU_CC_CXO_CLK>,
|
||||
<&gcc GCC_DDRSS_GPU_AXI_CLK>,
|
||||
<&gcc GCC_GPU_MEMNOC_GFX_CLK>;
|
||||
clock-names = "gmu", "cxo", "axi", "memnoc";
|
||||
|
||||
power-domains = <&gpucc GPU_CX_GDSC>;
|
||||
iommus = <&adreno_smmu 5>;
|
||||
|
||||
operating-points-v2 = <&gmu_opp_table>;
|
||||
};
|
||||
};
|
|
@ -10,14 +10,23 @@ Required properties:
|
|||
If "amd,imageon" is used, there should be no top level msm device.
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- interrupts: The interrupt signal from the gpu.
|
||||
- clocks: device clocks
|
||||
- clocks: device clocks (if applicable)
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names: the following clocks are required:
|
||||
- clock-names: the following clocks are required by a3xx, a4xx and a5xx
|
||||
cores:
|
||||
* "core"
|
||||
* "iface"
|
||||
* "mem_iface"
|
||||
For GMU attached devices the GPU clocks are not used and are not required. The
|
||||
following devices should not list clocks:
|
||||
- qcom,adreno-630.2
|
||||
- iommus: optional phandle to an adreno iommu instance
|
||||
- operating-points-v2: optional phandle to the OPP operating points
|
||||
- qcom,gmu: For GMU attached devices a phandle to the GMU device that will
|
||||
control the power for the GPU. Applicable targets:
|
||||
- qcom,adreno-630.2
|
||||
|
||||
Example:
|
||||
Example 3xx/4xx/a5xx:
|
||||
|
||||
/ {
|
||||
...
|
||||
|
@ -37,3 +46,30 @@ Example:
|
|||
<&mmcc MMSS_IMEM_AHB_CLK>;
|
||||
};
|
||||
};
|
||||
|
||||
Example a6xx (with GMU):
|
||||
|
||||
/ {
|
||||
...
|
||||
|
||||
gpu@5000000 {
|
||||
compatible = "qcom,adreno-630.2", "qcom,adreno";
|
||||
#stream-id-cells = <16>;
|
||||
|
||||
reg = <0x5000000 0x40000>, <0x509e000 0x10>;
|
||||
reg-names = "kgsl_3d0_reg_memory", "cx_mem";
|
||||
|
||||
/*
|
||||
* Look ma, no clocks! The GPU clocks and power are
|
||||
* controlled entirely by the GMU
|
||||
*/
|
||||
|
||||
interrupts = <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
iommus = <&adreno_smmu 0>;
|
||||
|
||||
operating-points-v2 = <&gpu_opp_table>;
|
||||
|
||||
qcom,gmu = <&gmu>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4851,10 +4851,11 @@ F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt
|
|||
|
||||
DRM DRIVER FOR MSM ADRENO GPU
|
||||
M: Rob Clark <robdclark@gmail.com>
|
||||
M: Sean Paul <sean@poorly.run>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: freedreno@lists.freedesktop.org
|
||||
T: git git://people.freedesktop.org/~robclark/linux
|
||||
T: git https://gitlab.freedesktop.org/drm/msm.git
|
||||
S: Maintained
|
||||
F: drivers/gpu/drm/msm/
|
||||
F: include/uapi/drm/msm_drm.h
|
||||
|
|
|
@ -465,8 +465,6 @@ static void _dpu_crtc_setup_mixer_for_encoder(
|
|||
return;
|
||||
}
|
||||
|
||||
mixer->encoder = enc;
|
||||
|
||||
cstate->num_mixers++;
|
||||
DPU_DEBUG("setup mixer %d: lm %d\n",
|
||||
i, mixer->hw_lm->idx - LM_0);
|
||||
|
@ -718,11 +716,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async)
|
|||
* may delay and flush at an irq event (e.g. ppdone)
|
||||
*/
|
||||
drm_for_each_encoder_mask(encoder, crtc->dev,
|
||||
crtc->state->encoder_mask) {
|
||||
struct dpu_encoder_kickoff_params params = { 0 };
|
||||
dpu_encoder_prepare_for_kickoff(encoder, ¶ms, async);
|
||||
}
|
||||
|
||||
crtc->state->encoder_mask)
|
||||
dpu_encoder_prepare_for_kickoff(encoder, async);
|
||||
|
||||
if (!async) {
|
||||
/* wait for frame_event_done completion */
|
||||
|
|
|
@ -84,14 +84,12 @@ struct dpu_crtc_smmu_state_data {
|
|||
* struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC
|
||||
* @hw_lm: LM HW Driver context
|
||||
* @lm_ctl: CTL Path HW driver context
|
||||
* @encoder: Encoder attached to this lm & ctl
|
||||
* @mixer_op_mode: mixer blending operation mode
|
||||
* @flush_mask: mixer flush mask for ctl, mixer and pipe
|
||||
*/
|
||||
struct dpu_crtc_mixer {
|
||||
struct dpu_hw_mixer *hw_lm;
|
||||
struct dpu_hw_ctl *lm_ctl;
|
||||
struct drm_encoder *encoder;
|
||||
u32 mixer_op_mode;
|
||||
u32 flush_mask;
|
||||
};
|
||||
|
|
|
@ -205,7 +205,7 @@ struct dpu_encoder_virt {
|
|||
bool idle_pc_supported;
|
||||
struct mutex rc_lock;
|
||||
enum dpu_enc_rc_states rc_state;
|
||||
struct kthread_delayed_work delayed_off_work;
|
||||
struct delayed_work delayed_off_work;
|
||||
struct kthread_work vsync_event_work;
|
||||
struct msm_display_topology topology;
|
||||
bool mode_set_complete;
|
||||
|
@ -742,7 +742,6 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
|
|||
{
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
struct msm_drm_private *priv;
|
||||
struct msm_drm_thread *disp_thread;
|
||||
bool is_vid_mode = false;
|
||||
|
||||
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,
|
|||
is_vid_mode = dpu_enc->disp_info.capabilities &
|
||||
MSM_DISPLAY_CAP_VID_MODE;
|
||||
|
||||
if (drm_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
|
||||
DPU_ERROR("invalid crtc index\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
disp_thread = &priv->disp_thread[drm_enc->crtc->index];
|
||||
|
||||
/*
|
||||
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
|
||||
* 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,
|
|||
switch (sw_event) {
|
||||
case DPU_ENC_RC_EVENT_KICKOFF:
|
||||
/* cancel delayed off work, if any */
|
||||
if (kthread_cancel_delayed_work_sync(
|
||||
&dpu_enc->delayed_off_work))
|
||||
if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work))
|
||||
DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n",
|
||||
sw_event);
|
||||
|
||||
|
@ -837,9 +829,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
kthread_queue_delayed_work(
|
||||
&disp_thread->worker,
|
||||
&dpu_enc->delayed_off_work,
|
||||
queue_delayed_work(priv->wq, &dpu_enc->delayed_off_work,
|
||||
msecs_to_jiffies(dpu_enc->idle_timeout));
|
||||
|
||||
trace_dpu_enc_rc(DRMID(drm_enc), sw_event,
|
||||
|
@ -849,8 +839,7 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
|
|||
|
||||
case DPU_ENC_RC_EVENT_PRE_STOP:
|
||||
/* cancel delayed off work, if any */
|
||||
if (kthread_cancel_delayed_work_sync(
|
||||
&dpu_enc->delayed_off_work))
|
||||
if (cancel_delayed_work_sync(&dpu_enc->delayed_off_work))
|
||||
DPU_DEBUG_ENC(dpu_enc, "sw_event:%d, work cancelled\n",
|
||||
sw_event);
|
||||
|
||||
|
@ -1368,7 +1357,7 @@ static void dpu_encoder_frame_done_callback(
|
|||
}
|
||||
}
|
||||
|
||||
static void dpu_encoder_off_work(struct kthread_work *work)
|
||||
static void dpu_encoder_off_work(struct work_struct *work)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc = container_of(work,
|
||||
struct dpu_encoder_virt, delayed_off_work.work);
|
||||
|
@ -1756,15 +1745,14 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work)
|
|||
nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
|
||||
}
|
||||
|
||||
void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
||||
struct dpu_encoder_kickoff_params *params, bool async)
|
||||
void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
struct dpu_encoder_phys *phys;
|
||||
bool needs_hw_reset = false;
|
||||
unsigned int i;
|
||||
|
||||
if (!drm_enc || !params) {
|
||||
if (!drm_enc) {
|
||||
DPU_ERROR("invalid args\n");
|
||||
return;
|
||||
}
|
||||
|
@ -1778,7 +1766,7 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
|||
phys = dpu_enc->phys_encs[i];
|
||||
if (phys) {
|
||||
if (phys->ops.prepare_for_kickoff)
|
||||
phys->ops.prepare_for_kickoff(phys, params);
|
||||
phys->ops.prepare_for_kickoff(phys);
|
||||
if (phys->enable_state == DPU_ENC_ERR_NEEDS_HW_RESET)
|
||||
needs_hw_reset = true;
|
||||
}
|
||||
|
@ -2193,7 +2181,7 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc,
|
|||
|
||||
|
||||
mutex_init(&dpu_enc->rc_lock);
|
||||
kthread_init_delayed_work(&dpu_enc->delayed_off_work,
|
||||
INIT_DELAYED_WORK(&dpu_enc->delayed_off_work,
|
||||
dpu_encoder_off_work);
|
||||
dpu_enc->idle_timeout = IDLE_TIMEOUT;
|
||||
|
||||
|
|
|
@ -37,15 +37,6 @@ struct dpu_encoder_hw_resources {
|
|||
enum dpu_intf_mode intfs[INTF_MAX];
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_kickoff_params - info encoder requires at kickoff
|
||||
* @affected_displays: bitmask, bit set means the ROI of the commit lies within
|
||||
* the bounds of the physical display at the bit index
|
||||
*/
|
||||
struct dpu_encoder_kickoff_params {
|
||||
unsigned long affected_displays;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_encoder_get_hw_resources - Populate table of required hardware resources
|
||||
* @encoder: encoder pointer
|
||||
|
@ -88,11 +79,9 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder,
|
|||
* Immediately: if no previous commit is outstanding.
|
||||
* Delayed: Block until next trigger can be issued.
|
||||
* @encoder: encoder pointer
|
||||
* @params: kickoff time parameters
|
||||
* @async: true if this is an asynchronous commit
|
||||
*/
|
||||
void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder,
|
||||
struct dpu_encoder_kickoff_params *params, bool async);
|
||||
void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, bool async);
|
||||
|
||||
/**
|
||||
* dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous
|
||||
|
|
|
@ -144,8 +144,7 @@ struct dpu_encoder_phys_ops {
|
|||
int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc);
|
||||
int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc);
|
||||
int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc,
|
||||
struct dpu_encoder_kickoff_params *params);
|
||||
void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
|
||||
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
|
||||
bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
|
||||
|
|
|
@ -594,8 +594,7 @@ static void dpu_encoder_phys_cmd_get_hw_resources(
|
|||
}
|
||||
|
||||
static void dpu_encoder_phys_cmd_prepare_for_kickoff(
|
||||
struct dpu_encoder_phys *phys_enc,
|
||||
struct dpu_encoder_kickoff_params *params)
|
||||
struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct dpu_encoder_phys_cmd *cmd_enc =
|
||||
to_dpu_encoder_phys_cmd(phys_enc);
|
||||
|
@ -693,7 +692,7 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done(
|
|||
|
||||
/* required for both controllers */
|
||||
if (!rc && cmd_enc->serialize_wait4pp)
|
||||
dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL);
|
||||
dpu_encoder_phys_cmd_prepare_for_kickoff(phys_enc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -587,14 +587,13 @@ static int dpu_encoder_phys_vid_wait_for_vblank(
|
|||
}
|
||||
|
||||
static void dpu_encoder_phys_vid_prepare_for_kickoff(
|
||||
struct dpu_encoder_phys *phys_enc,
|
||||
struct dpu_encoder_kickoff_params *params)
|
||||
struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct dpu_encoder_phys_vid *vid_enc;
|
||||
struct dpu_hw_ctl *ctl;
|
||||
int rc;
|
||||
|
||||
if (!phys_enc || !params) {
|
||||
if (!phys_enc) {
|
||||
DPU_ERROR("invalid encoder/parameters\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -263,13 +263,13 @@ static const struct dpu_format dpu_format_map[] = {
|
|||
|
||||
INTERLEAVED_RGB_FMT(RGB565,
|
||||
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
|
||||
C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
|
||||
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
|
||||
false, 2, 0,
|
||||
DPU_FETCH_LINEAR, 1),
|
||||
|
||||
INTERLEAVED_RGB_FMT(BGR565,
|
||||
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
|
||||
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
|
||||
C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
|
||||
false, 2, 0,
|
||||
DPU_FETCH_LINEAR, 1),
|
||||
|
||||
|
@ -1137,36 +1137,3 @@ const struct msm_format *dpu_get_msm_format(
|
|||
return &fmt->base;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t dpu_populate_formats(
|
||||
const struct dpu_format_extended *format_list,
|
||||
uint32_t *pixel_formats,
|
||||
uint64_t *pixel_modifiers,
|
||||
uint32_t pixel_formats_max)
|
||||
{
|
||||
uint32_t i, fourcc_format;
|
||||
|
||||
if (!format_list || !pixel_formats)
|
||||
return 0;
|
||||
|
||||
for (i = 0, fourcc_format = 0;
|
||||
format_list->fourcc_format && i < pixel_formats_max;
|
||||
++format_list) {
|
||||
/* verify if listed format is in dpu_format_map? */
|
||||
|
||||
/* optionally return modified formats */
|
||||
if (pixel_modifiers) {
|
||||
/* assume same modifier for all fb planes */
|
||||
pixel_formats[i] = format_list->fourcc_format;
|
||||
pixel_modifiers[i++] = format_list->modifier;
|
||||
} else {
|
||||
/* assume base formats grouped together */
|
||||
if (fourcc_format != format_list->fourcc_format) {
|
||||
fourcc_format = format_list->fourcc_format;
|
||||
pixel_formats[i++] = fourcc_format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -40,20 +40,6 @@ const struct msm_format *dpu_get_msm_format(
|
|||
const uint32_t format,
|
||||
const uint64_t modifiers);
|
||||
|
||||
/**
|
||||
* dpu_populate_formats - populate the given array with fourcc codes supported
|
||||
* @format_list: pointer to list of possible formats
|
||||
* @pixel_formats: array to populate with fourcc codes
|
||||
* @pixel_modifiers: array to populate with drm modifiers, can be NULL
|
||||
* @pixel_formats_max: length of pixel formats array
|
||||
* Return: number of elements populated
|
||||
*/
|
||||
uint32_t dpu_populate_formats(
|
||||
const struct dpu_format_extended *format_list,
|
||||
uint32_t *pixel_formats,
|
||||
uint64_t *pixel_modifiers,
|
||||
uint32_t pixel_formats_max);
|
||||
|
||||
/**
|
||||
* dpu_format_check_modified_format - validate format and buffers for
|
||||
* dpu non-standard, i.e. modified format
|
||||
|
|
|
@ -151,7 +151,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = {
|
|||
.id = DPU_SSPP_CSC_10BIT, \
|
||||
.base = 0x1a00, .len = 0x100,}, \
|
||||
.format_list = plane_formats_yuv, \
|
||||
.num_formats = ARRAY_SIZE(plane_formats_yuv), \
|
||||
.virt_format_list = plane_formats, \
|
||||
.virt_num_formats = ARRAY_SIZE(plane_formats), \
|
||||
}
|
||||
|
||||
#define _DMA_SBLK(num, sdma_pri) \
|
||||
|
@ -163,7 +165,9 @@ static const struct dpu_sspp_blks_common sdm845_sspp_common = {
|
|||
.src_blk = {.name = STRCAT("sspp_src_", num), \
|
||||
.id = DPU_SSPP_SRC, .base = 0x00, .len = 0x150,}, \
|
||||
.format_list = plane_formats, \
|
||||
.num_formats = ARRAY_SIZE(plane_formats), \
|
||||
.virt_format_list = plane_formats, \
|
||||
.virt_num_formats = ARRAY_SIZE(plane_formats), \
|
||||
}
|
||||
|
||||
static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = _VIG_SBLK("0", 5);
|
||||
|
|
|
@ -251,17 +251,6 @@ struct dpu_pp_blk {
|
|||
u32 version;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_format_extended - define dpu specific pixel format+modifier
|
||||
* @fourcc_format: Base FOURCC pixel format code
|
||||
* @modifier: 64-bit drm format modifier, same modifier must be applied to all
|
||||
* framebuffer planes
|
||||
*/
|
||||
struct dpu_format_extended {
|
||||
uint32_t fourcc_format;
|
||||
uint64_t modifier;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dpu_qos_lut_usage - define QoS LUT use cases
|
||||
*/
|
||||
|
@ -348,7 +337,9 @@ struct dpu_sspp_blks_common {
|
|||
* @pcc_blk:
|
||||
* @igc_blk:
|
||||
* @format_list: Pointer to list of supported formats
|
||||
* @num_formats: Number of supported formats
|
||||
* @virt_format_list: Pointer to list of supported formats for virtual planes
|
||||
* @virt_num_formats: Number of supported formats for virtual planes
|
||||
*/
|
||||
struct dpu_sspp_sub_blks {
|
||||
const struct dpu_sspp_blks_common *common;
|
||||
|
@ -366,8 +357,10 @@ struct dpu_sspp_sub_blks {
|
|||
struct dpu_pp_blk pcc_blk;
|
||||
struct dpu_pp_blk igc_blk;
|
||||
|
||||
const struct dpu_format_extended *format_list;
|
||||
const struct dpu_format_extended *virt_format_list;
|
||||
const u32 *format_list;
|
||||
u32 num_formats;
|
||||
const u32 *virt_format_list;
|
||||
u32 virt_num_formats;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,157 +12,81 @@
|
|||
|
||||
#include "dpu_hw_mdss.h"
|
||||
|
||||
static const struct dpu_format_extended plane_formats[] = {
|
||||
{DRM_FORMAT_ARGB8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, 0},
|
||||
{DRM_FORMAT_RGBA8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_BGRA8888, 0},
|
||||
{DRM_FORMAT_XRGB8888, 0},
|
||||
{DRM_FORMAT_RGBX8888, 0},
|
||||
{DRM_FORMAT_BGRX8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_RGB888, 0},
|
||||
{DRM_FORMAT_BGR888, 0},
|
||||
{DRM_FORMAT_RGB565, 0},
|
||||
{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_BGR565, 0},
|
||||
{DRM_FORMAT_ARGB1555, 0},
|
||||
{DRM_FORMAT_ABGR1555, 0},
|
||||
{DRM_FORMAT_RGBA5551, 0},
|
||||
{DRM_FORMAT_BGRA5551, 0},
|
||||
{DRM_FORMAT_XRGB1555, 0},
|
||||
{DRM_FORMAT_XBGR1555, 0},
|
||||
{DRM_FORMAT_RGBX5551, 0},
|
||||
{DRM_FORMAT_BGRX5551, 0},
|
||||
{DRM_FORMAT_ARGB4444, 0},
|
||||
{DRM_FORMAT_ABGR4444, 0},
|
||||
{DRM_FORMAT_RGBA4444, 0},
|
||||
{DRM_FORMAT_BGRA4444, 0},
|
||||
{DRM_FORMAT_XRGB4444, 0},
|
||||
{DRM_FORMAT_XBGR4444, 0},
|
||||
{DRM_FORMAT_RGBX4444, 0},
|
||||
{DRM_FORMAT_BGRX4444, 0},
|
||||
{0, 0},
|
||||
static const uint32_t qcom_compressed_supported_formats[] = {
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_BGR565,
|
||||
};
|
||||
|
||||
static const struct dpu_format_extended plane_formats_yuv[] = {
|
||||
{DRM_FORMAT_ARGB8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, 0},
|
||||
{DRM_FORMAT_RGBA8888, 0},
|
||||
{DRM_FORMAT_BGRX8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_BGRA8888, 0},
|
||||
{DRM_FORMAT_XRGB8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, 0},
|
||||
{DRM_FORMAT_RGBX8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_RGB888, 0},
|
||||
{DRM_FORMAT_BGR888, 0},
|
||||
{DRM_FORMAT_RGB565, 0},
|
||||
{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_BGR565, 0},
|
||||
{DRM_FORMAT_ARGB1555, 0},
|
||||
{DRM_FORMAT_ABGR1555, 0},
|
||||
{DRM_FORMAT_RGBA5551, 0},
|
||||
{DRM_FORMAT_BGRA5551, 0},
|
||||
{DRM_FORMAT_XRGB1555, 0},
|
||||
{DRM_FORMAT_XBGR1555, 0},
|
||||
{DRM_FORMAT_RGBX5551, 0},
|
||||
{DRM_FORMAT_BGRX5551, 0},
|
||||
{DRM_FORMAT_ARGB4444, 0},
|
||||
{DRM_FORMAT_ABGR4444, 0},
|
||||
{DRM_FORMAT_RGBA4444, 0},
|
||||
{DRM_FORMAT_BGRA4444, 0},
|
||||
{DRM_FORMAT_XRGB4444, 0},
|
||||
{DRM_FORMAT_XBGR4444, 0},
|
||||
{DRM_FORMAT_RGBX4444, 0},
|
||||
{DRM_FORMAT_BGRX4444, 0},
|
||||
|
||||
{DRM_FORMAT_NV12, 0},
|
||||
{DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_NV21, 0},
|
||||
{DRM_FORMAT_NV16, 0},
|
||||
{DRM_FORMAT_NV61, 0},
|
||||
{DRM_FORMAT_VYUY, 0},
|
||||
{DRM_FORMAT_UYVY, 0},
|
||||
{DRM_FORMAT_YUYV, 0},
|
||||
{DRM_FORMAT_YVYU, 0},
|
||||
{DRM_FORMAT_YUV420, 0},
|
||||
{DRM_FORMAT_YVU420, 0},
|
||||
{0, 0},
|
||||
static const uint32_t plane_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_BGRA8888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_RGBX8888,
|
||||
DRM_FORMAT_BGRX8888,
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_BGR888,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_BGR565,
|
||||
DRM_FORMAT_ARGB1555,
|
||||
DRM_FORMAT_ABGR1555,
|
||||
DRM_FORMAT_RGBA5551,
|
||||
DRM_FORMAT_BGRA5551,
|
||||
DRM_FORMAT_XRGB1555,
|
||||
DRM_FORMAT_XBGR1555,
|
||||
DRM_FORMAT_RGBX5551,
|
||||
DRM_FORMAT_BGRX5551,
|
||||
DRM_FORMAT_ARGB4444,
|
||||
DRM_FORMAT_ABGR4444,
|
||||
DRM_FORMAT_RGBA4444,
|
||||
DRM_FORMAT_BGRA4444,
|
||||
DRM_FORMAT_XRGB4444,
|
||||
DRM_FORMAT_XBGR4444,
|
||||
DRM_FORMAT_RGBX4444,
|
||||
DRM_FORMAT_BGRX4444,
|
||||
};
|
||||
|
||||
static const struct dpu_format_extended cursor_formats[] = {
|
||||
{DRM_FORMAT_ARGB8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, 0},
|
||||
{DRM_FORMAT_RGBA8888, 0},
|
||||
{DRM_FORMAT_BGRA8888, 0},
|
||||
{DRM_FORMAT_XRGB8888, 0},
|
||||
{DRM_FORMAT_ARGB1555, 0},
|
||||
{DRM_FORMAT_ABGR1555, 0},
|
||||
{DRM_FORMAT_RGBA5551, 0},
|
||||
{DRM_FORMAT_BGRA5551, 0},
|
||||
{DRM_FORMAT_ARGB4444, 0},
|
||||
{DRM_FORMAT_ABGR4444, 0},
|
||||
{DRM_FORMAT_RGBA4444, 0},
|
||||
{DRM_FORMAT_BGRA4444, 0},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static const struct dpu_format_extended wb2_formats[] = {
|
||||
{DRM_FORMAT_RGB565, 0},
|
||||
{DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_RGB888, 0},
|
||||
{DRM_FORMAT_ARGB8888, 0},
|
||||
{DRM_FORMAT_RGBA8888, 0},
|
||||
{DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_XRGB8888, 0},
|
||||
{DRM_FORMAT_RGBX8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_ARGB1555, 0},
|
||||
{DRM_FORMAT_RGBA5551, 0},
|
||||
{DRM_FORMAT_XRGB1555, 0},
|
||||
{DRM_FORMAT_RGBX5551, 0},
|
||||
{DRM_FORMAT_ARGB4444, 0},
|
||||
{DRM_FORMAT_RGBA4444, 0},
|
||||
{DRM_FORMAT_RGBX4444, 0},
|
||||
{DRM_FORMAT_XRGB4444, 0},
|
||||
|
||||
{DRM_FORMAT_BGR565, 0},
|
||||
{DRM_FORMAT_BGR888, 0},
|
||||
{DRM_FORMAT_ABGR8888, 0},
|
||||
{DRM_FORMAT_BGRA8888, 0},
|
||||
{DRM_FORMAT_BGRX8888, 0},
|
||||
{DRM_FORMAT_XBGR8888, 0},
|
||||
{DRM_FORMAT_ABGR1555, 0},
|
||||
{DRM_FORMAT_BGRA5551, 0},
|
||||
{DRM_FORMAT_XBGR1555, 0},
|
||||
{DRM_FORMAT_BGRX5551, 0},
|
||||
{DRM_FORMAT_ABGR4444, 0},
|
||||
{DRM_FORMAT_BGRA4444, 0},
|
||||
{DRM_FORMAT_BGRX4444, 0},
|
||||
{DRM_FORMAT_XBGR4444, 0},
|
||||
|
||||
{DRM_FORMAT_YUV420, 0},
|
||||
{DRM_FORMAT_NV12, 0},
|
||||
{DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_NV16, 0},
|
||||
{DRM_FORMAT_YUYV, 0},
|
||||
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static const struct dpu_format_extended rgb_10bit_formats[] = {
|
||||
{DRM_FORMAT_BGRA1010102, 0},
|
||||
{DRM_FORMAT_BGRX1010102, 0},
|
||||
{DRM_FORMAT_RGBA1010102, 0},
|
||||
{DRM_FORMAT_RGBX1010102, 0},
|
||||
{DRM_FORMAT_ABGR2101010, 0},
|
||||
{DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_XBGR2101010, 0},
|
||||
{DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED},
|
||||
{DRM_FORMAT_ARGB2101010, 0},
|
||||
{DRM_FORMAT_XRGB2101010, 0},
|
||||
static const uint32_t plane_formats_yuv[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_BGRX8888,
|
||||
DRM_FORMAT_BGRA8888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_RGBX8888,
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_BGR888,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_BGR565,
|
||||
DRM_FORMAT_ARGB1555,
|
||||
DRM_FORMAT_ABGR1555,
|
||||
DRM_FORMAT_RGBA5551,
|
||||
DRM_FORMAT_BGRA5551,
|
||||
DRM_FORMAT_XRGB1555,
|
||||
DRM_FORMAT_XBGR1555,
|
||||
DRM_FORMAT_RGBX5551,
|
||||
DRM_FORMAT_BGRX5551,
|
||||
DRM_FORMAT_ARGB4444,
|
||||
DRM_FORMAT_ABGR4444,
|
||||
DRM_FORMAT_RGBA4444,
|
||||
DRM_FORMAT_BGRA4444,
|
||||
DRM_FORMAT_XRGB4444,
|
||||
DRM_FORMAT_XBGR4444,
|
||||
DRM_FORMAT_RGBX4444,
|
||||
DRM_FORMAT_BGRX4444,
|
||||
|
||||
DRM_FORMAT_NV12,
|
||||
DRM_FORMAT_NV21,
|
||||
DRM_FORMAT_NV16,
|
||||
DRM_FORMAT_NV61,
|
||||
DRM_FORMAT_VYUY,
|
||||
DRM_FORMAT_UYVY,
|
||||
DRM_FORMAT_YUYV,
|
||||
DRM_FORMAT_YVYU,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_YVU420,
|
||||
};
|
||||
|
|
|
@ -170,10 +170,6 @@
|
|||
/**
|
||||
* AD4 interrupt status bit definitions
|
||||
*/
|
||||
#define DPU_INTR_BRIGHTPR_UPDATED BIT(4)
|
||||
#define DPU_INTR_DARKENH_UPDATED BIT(3)
|
||||
#define DPU_INTR_STREN_OUTROI_UPDATED BIT(2)
|
||||
#define DPU_INTR_STREN_INROI_UPDATED BIT(1)
|
||||
#define DPU_INTR_BACKLIGHT_UPDATED BIT(0)
|
||||
/**
|
||||
* 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,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dpu_hw_intr_set_mask(struct dpu_hw_intr *intr, uint32_t reg_off,
|
||||
uint32_t mask)
|
||||
{
|
||||
if (!intr)
|
||||
return;
|
||||
|
||||
DPU_REG_WRITE(&intr->hw, reg_off, mask);
|
||||
|
||||
/* ensure register writes go through */
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr,
|
||||
void (*cbfunc)(void *, int),
|
||||
void *arg)
|
||||
|
@ -1004,18 +988,6 @@ static int dpu_hw_intr_disable_irqs(struct dpu_hw_intr *intr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dpu_hw_intr_get_valid_interrupts(struct dpu_hw_intr *intr,
|
||||
uint32_t *mask)
|
||||
{
|
||||
if (!intr || !mask)
|
||||
return -EINVAL;
|
||||
|
||||
*mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1
|
||||
| IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpu_hw_intr_get_interrupt_statuses(struct dpu_hw_intr *intr)
|
||||
{
|
||||
int i;
|
||||
|
@ -1065,19 +1037,6 @@ static void dpu_hw_intr_clear_intr_status_nolock(struct dpu_hw_intr *intr,
|
|||
wmb();
|
||||
}
|
||||
|
||||
static void dpu_hw_intr_clear_interrupt_status(struct dpu_hw_intr *intr,
|
||||
int irq_idx)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
|
||||
if (!intr)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&intr->irq_lock, irq_flags);
|
||||
dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx);
|
||||
spin_unlock_irqrestore(&intr->irq_lock, irq_flags);
|
||||
}
|
||||
|
||||
static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr,
|
||||
int irq_idx, bool clear)
|
||||
{
|
||||
|
@ -1113,16 +1072,13 @@ static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr,
|
|||
|
||||
static void __setup_intr_ops(struct dpu_hw_intr_ops *ops)
|
||||
{
|
||||
ops->set_mask = dpu_hw_intr_set_mask;
|
||||
ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup;
|
||||
ops->enable_irq = dpu_hw_intr_enable_irq;
|
||||
ops->disable_irq = dpu_hw_intr_disable_irq;
|
||||
ops->dispatch_irqs = dpu_hw_intr_dispatch_irq;
|
||||
ops->clear_all_irqs = dpu_hw_intr_clear_irqs;
|
||||
ops->disable_all_irqs = dpu_hw_intr_disable_irqs;
|
||||
ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts;
|
||||
ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses;
|
||||
ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status;
|
||||
ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock;
|
||||
ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,6 @@
|
|||
#include "dpu_hw_util.h"
|
||||
#include "dpu_hw_mdss.h"
|
||||
|
||||
#define IRQ_SOURCE_MDP BIT(0)
|
||||
#define IRQ_SOURCE_DSI0 BIT(4)
|
||||
#define IRQ_SOURCE_DSI1 BIT(5)
|
||||
#define IRQ_SOURCE_HDMI BIT(8)
|
||||
#define IRQ_SOURCE_EDP BIT(12)
|
||||
#define IRQ_SOURCE_MHL BIT(16)
|
||||
|
||||
/**
|
||||
* dpu_intr_type - HW Interrupt Type
|
||||
* @DPU_IRQ_TYPE_WB_ROT_COMP: WB rotator done
|
||||
|
@ -95,18 +88,6 @@ struct dpu_hw_intr;
|
|||
* Interrupt operations.
|
||||
*/
|
||||
struct dpu_hw_intr_ops {
|
||||
/**
|
||||
* set_mask - Programs the given interrupt register with the
|
||||
* given interrupt mask. Register value will get overwritten.
|
||||
* @intr: HW interrupt handle
|
||||
* @reg_off: MDSS HW register offset
|
||||
* @irqmask: IRQ mask value
|
||||
*/
|
||||
void (*set_mask)(
|
||||
struct dpu_hw_intr *intr,
|
||||
uint32_t reg,
|
||||
uint32_t irqmask);
|
||||
|
||||
/**
|
||||
* irq_idx_lookup - Lookup IRQ index on the HW interrupt type
|
||||
* Used for all irq related ops
|
||||
|
@ -176,16 +157,6 @@ struct dpu_hw_intr_ops {
|
|||
void (*get_interrupt_statuses)(
|
||||
struct dpu_hw_intr *intr);
|
||||
|
||||
/**
|
||||
* clear_interrupt_status - Clears HW interrupt status based on given
|
||||
* lookup IRQ index.
|
||||
* @intr: HW interrupt handle
|
||||
* @irq_idx: Lookup irq index return from irq_idx_lookup
|
||||
*/
|
||||
void (*clear_interrupt_status)(
|
||||
struct dpu_hw_intr *intr,
|
||||
int irq_idx);
|
||||
|
||||
/**
|
||||
* clear_intr_status_nolock() - clears the HW interrupts without lock
|
||||
* @intr: HW interrupt handle
|
||||
|
@ -206,21 +177,6 @@ struct dpu_hw_intr_ops {
|
|||
struct dpu_hw_intr *intr,
|
||||
int irq_idx,
|
||||
bool clear);
|
||||
|
||||
/**
|
||||
* get_valid_interrupts - Gets a mask of all valid interrupt sources
|
||||
* within DPU. These are actually status bits
|
||||
* within interrupt registers that specify the
|
||||
* source of the interrupt in IRQs. For example,
|
||||
* valid interrupt sources can be MDP, DSI,
|
||||
* HDMI etc.
|
||||
* @intr: HW interrupt handle
|
||||
* @mask: Returning the interrupt source MASK
|
||||
* @return: 0 for success, otherwise failure
|
||||
*/
|
||||
int (*get_valid_interrupts)(
|
||||
struct dpu_hw_intr *intr,
|
||||
uint32_t *mask);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -258,12 +258,6 @@ enum dpu_vbif {
|
|||
VBIF_NRT = VBIF_1
|
||||
};
|
||||
|
||||
enum dpu_iommu_domain {
|
||||
DPU_IOMMU_DOMAIN_UNSECURE,
|
||||
DPU_IOMMU_DOMAIN_SECURE,
|
||||
DPU_IOMMU_DOMAIN_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* DPU HW,Component order color map
|
||||
*/
|
||||
|
@ -358,7 +352,6 @@ enum dpu_3d_blend_mode {
|
|||
* @alpha_enable: whether the format has an alpha channel
|
||||
* @num_planes: number of planes (including meta data planes)
|
||||
* @fetch_mode: linear, tiled, or ubwc hw fetch behavior
|
||||
* @is_yuv: is format a yuv variant
|
||||
* @flag: usage bit flags
|
||||
* @tile_width: format tile width
|
||||
* @tile_height: format tile height
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "dpu_hw_mdss.h"
|
||||
|
||||
#define REG_MASK(n) ((BIT(n)) - 1)
|
||||
struct dpu_format_extended;
|
||||
|
||||
/*
|
||||
* 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,
|
|||
}
|
||||
}
|
||||
|
||||
static void _dpu_kms_initialize_dsi(struct drm_device *dev,
|
||||
static int _dpu_kms_initialize_dsi(struct drm_device *dev,
|
||||
struct msm_drm_private *priv,
|
||||
struct dpu_kms *dpu_kms)
|
||||
{
|
||||
struct drm_encoder *encoder = NULL;
|
||||
int i, rc;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!(priv->dsi[0] || priv->dsi[1]))
|
||||
return rc;
|
||||
|
||||
/*TODO: Support two independent DSI connectors */
|
||||
encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_DSI);
|
||||
if (IS_ERR_OR_NULL(encoder)) {
|
||||
if (IS_ERR(encoder)) {
|
||||
DPU_ERROR("encoder init failed for dsi display\n");
|
||||
return;
|
||||
return PTR_ERR(encoder);
|
||||
}
|
||||
|
||||
priv->encoders[priv->num_encoders++] = encoder;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->dsi); i++) {
|
||||
if (!priv->dsi[i]) {
|
||||
DPU_DEBUG("invalid msm_dsi for ctrl %d\n", i);
|
||||
return;
|
||||
}
|
||||
if (!priv->dsi[i])
|
||||
continue;
|
||||
|
||||
rc = msm_dsi_modeset_init(priv->dsi[i], dev, encoder);
|
||||
if (rc) {
|
||||
DPU_ERROR("modeset_init failed for dsi[%d], rc = %d\n",
|
||||
i, rc);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,16 +447,16 @@ static void _dpu_kms_initialize_dsi(struct drm_device *dev,
|
|||
* @dpu_kms: Pointer to dpu kms structure
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
static void _dpu_kms_setup_displays(struct drm_device *dev,
|
||||
static int _dpu_kms_setup_displays(struct drm_device *dev,
|
||||
struct msm_drm_private *priv,
|
||||
struct dpu_kms *dpu_kms)
|
||||
{
|
||||
_dpu_kms_initialize_dsi(dev, priv, dpu_kms);
|
||||
|
||||
/**
|
||||
* Extend this function to initialize other
|
||||
* types of displays
|
||||
*/
|
||||
|
||||
return _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
|
||||
}
|
||||
|
||||
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)
|
|||
* Create encoder and query display drivers to create
|
||||
* bridges and connectors
|
||||
*/
|
||||
_dpu_kms_setup_displays(dev, priv, dpu_kms);
|
||||
ret = _dpu_kms_setup_displays(dev, priv, dpu_kms);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
max_crtc_count = min(catalog->mixer_count, priv->num_encoders);
|
||||
|
||||
|
@ -627,6 +632,10 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms)
|
|||
devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->vbif[VBIF_RT]);
|
||||
dpu_kms->vbif[VBIF_RT] = NULL;
|
||||
|
||||
if (dpu_kms->hw_mdp)
|
||||
dpu_hw_mdp_destroy(dpu_kms->hw_mdp);
|
||||
dpu_kms->hw_mdp = NULL;
|
||||
|
||||
if (dpu_kms->mmio)
|
||||
devm_iounmap(&dpu_kms->pdev->dev, dpu_kms->mmio);
|
||||
dpu_kms->mmio = NULL;
|
||||
|
@ -877,8 +886,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
|
|||
goto power_error;
|
||||
}
|
||||
|
||||
rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio,
|
||||
dpu_kms->dev);
|
||||
rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mmio);
|
||||
if (rc) {
|
||||
DPU_ERROR("rm init failed: %d\n", rc);
|
||||
goto power_error;
|
||||
|
@ -886,11 +894,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
|
|||
|
||||
dpu_kms->rm_init = true;
|
||||
|
||||
dpu_kms->hw_mdp = dpu_rm_get_mdp(&dpu_kms->rm);
|
||||
if (IS_ERR_OR_NULL(dpu_kms->hw_mdp)) {
|
||||
dpu_kms->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, dpu_kms->mmio,
|
||||
dpu_kms->catalog);
|
||||
if (IS_ERR(dpu_kms->hw_mdp)) {
|
||||
rc = PTR_ERR(dpu_kms->hw_mdp);
|
||||
if (!dpu_kms->hw_mdp)
|
||||
rc = -EINVAL;
|
||||
DPU_ERROR("failed to get hw_mdp: %d\n", rc);
|
||||
dpu_kms->hw_mdp = NULL;
|
||||
goto power_error;
|
||||
|
@ -926,16 +933,6 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
|
|||
goto hw_intr_init_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* _dpu_kms_drm_obj_init should create the DRM related objects
|
||||
* i.e. CRTCs, planes, encoders, connectors and so forth
|
||||
*/
|
||||
rc = _dpu_kms_drm_obj_init(dpu_kms);
|
||||
if (rc) {
|
||||
DPU_ERROR("modeset init failed: %d\n", rc);
|
||||
goto drm_obj_init_err;
|
||||
}
|
||||
|
||||
dev->mode_config.min_width = 0;
|
||||
dev->mode_config.min_height = 0;
|
||||
|
||||
|
@ -952,6 +949,16 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
|
|||
*/
|
||||
dev->mode_config.allow_fb_modifiers = true;
|
||||
|
||||
/*
|
||||
* _dpu_kms_drm_obj_init should create the DRM related objects
|
||||
* i.e. CRTCs, planes, encoders, connectors and so forth
|
||||
*/
|
||||
rc = _dpu_kms_drm_obj_init(dpu_kms);
|
||||
if (rc) {
|
||||
DPU_ERROR("modeset init failed: %d\n", rc);
|
||||
goto drm_obj_init_err;
|
||||
}
|
||||
|
||||
dpu_vbif_init_memtypes(dpu_kms);
|
||||
|
||||
pm_runtime_put_sync(&dpu_kms->pdev->dev);
|
||||
|
|
|
@ -23,11 +23,14 @@ struct dpu_mdss {
|
|||
struct dpu_irq_controller irq_controller;
|
||||
};
|
||||
|
||||
static irqreturn_t dpu_mdss_irq(int irq, void *arg)
|
||||
static void dpu_mdss_irq(struct irq_desc *desc)
|
||||
{
|
||||
struct dpu_mdss *dpu_mdss = arg;
|
||||
struct dpu_mdss *dpu_mdss = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
u32 interrupts;
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS);
|
||||
|
||||
while (interrupts) {
|
||||
|
@ -39,20 +42,20 @@ static irqreturn_t dpu_mdss_irq(int irq, void *arg)
|
|||
hwirq);
|
||||
if (mapping == 0) {
|
||||
DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq);
|
||||
return IRQ_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = generic_handle_irq(mapping);
|
||||
if (rc < 0) {
|
||||
DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n",
|
||||
hwirq, mapping, rc);
|
||||
return IRQ_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
interrupts &= ~(1 << hwirq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static void dpu_mdss_irq_mask(struct irq_data *irqd)
|
||||
|
@ -83,16 +86,16 @@ static struct irq_chip dpu_mdss_irq_chip = {
|
|||
.irq_unmask = dpu_mdss_irq_unmask,
|
||||
};
|
||||
|
||||
static struct lock_class_key dpu_mdss_lock_key, dpu_mdss_request_key;
|
||||
|
||||
static int dpu_mdss_irqdomain_map(struct irq_domain *domain,
|
||||
unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
struct dpu_mdss *dpu_mdss = domain->host_data;
|
||||
int ret;
|
||||
|
||||
irq_set_lockdep_class(irq, &dpu_mdss_lock_key, &dpu_mdss_request_key);
|
||||
irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq);
|
||||
ret = irq_set_chip_data(irq, dpu_mdss);
|
||||
|
||||
return ret;
|
||||
return irq_set_chip_data(irq, dpu_mdss);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops dpu_mdss_irqdomain_ops = {
|
||||
|
@ -159,11 +162,13 @@ static void dpu_mdss_destroy(struct drm_device *dev)
|
|||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss);
|
||||
struct dss_module_power *mp = &dpu_mdss->mp;
|
||||
int irq;
|
||||
|
||||
pm_runtime_suspend(dev->dev);
|
||||
pm_runtime_disable(dev->dev);
|
||||
_dpu_mdss_irq_domain_fini(dpu_mdss);
|
||||
free_irq(platform_get_irq(pdev, 0), dpu_mdss);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
irq_set_chained_handler_and_data(irq, NULL, NULL);
|
||||
msm_dss_put_clk(mp->clk_config, mp->num_clk);
|
||||
devm_kfree(&pdev->dev, mp->clk_config);
|
||||
|
||||
|
@ -187,6 +192,7 @@ int dpu_mdss_init(struct drm_device *dev)
|
|||
struct dpu_mdss *dpu_mdss;
|
||||
struct dss_module_power *mp;
|
||||
int ret = 0;
|
||||
int irq;
|
||||
|
||||
dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL);
|
||||
if (!dpu_mdss)
|
||||
|
@ -219,12 +225,12 @@ int dpu_mdss_init(struct drm_device *dev)
|
|||
if (ret)
|
||||
goto irq_domain_error;
|
||||
|
||||
ret = request_irq(platform_get_irq(pdev, 0),
|
||||
dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss);
|
||||
if (ret) {
|
||||
DPU_ERROR("failed to init irq: %d\n", ret);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
goto irq_error;
|
||||
}
|
||||
|
||||
irq_set_chained_handler_and_data(irq, dpu_mdss_irq,
|
||||
dpu_mdss);
|
||||
|
||||
pm_runtime_enable(dev->dev);
|
||||
|
||||
|
|
|
@ -95,8 +95,6 @@ struct dpu_plane {
|
|||
|
||||
enum dpu_sspp pipe;
|
||||
uint32_t features; /* capabilities from catalog */
|
||||
uint32_t nformats;
|
||||
uint32_t formats[64];
|
||||
|
||||
struct dpu_hw_pipe *pipe_hw;
|
||||
struct dpu_hw_pipe_cfg pipe_cfg;
|
||||
|
@ -121,6 +119,12 @@ struct dpu_plane {
|
|||
bool debugfs_default_scale;
|
||||
};
|
||||
|
||||
static const uint64_t supported_format_modifiers[] = {
|
||||
DRM_FORMAT_MOD_QCOM_COMPRESSED,
|
||||
DRM_FORMAT_MOD_LINEAR,
|
||||
DRM_FORMAT_MOD_INVALID
|
||||
};
|
||||
|
||||
#define to_dpu_plane(x) container_of(x, struct dpu_plane, base)
|
||||
|
||||
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)
|
|||
debugfs_remove_recursive(pdpu->debugfs_root);
|
||||
}
|
||||
|
||||
static bool dpu_plane_format_mod_supported(struct drm_plane *plane,
|
||||
uint32_t format, uint64_t modifier)
|
||||
{
|
||||
if (modifier == DRM_FORMAT_MOD_LINEAR)
|
||||
return true;
|
||||
|
||||
if (modifier == DRM_FORMAT_MOD_QCOM_COMPRESSED) {
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(qcom_compressed_supported_formats); i++) {
|
||||
if (format == qcom_compressed_supported_formats[i])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs dpu_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
|
@ -1419,6 +1440,7 @@ static const struct drm_plane_funcs dpu_plane_funcs = {
|
|||
.atomic_destroy_state = dpu_plane_destroy_state,
|
||||
.late_register = dpu_plane_late_register,
|
||||
.early_unregister = dpu_plane_early_unregister,
|
||||
.format_mod_supported = dpu_plane_format_mod_supported,
|
||||
};
|
||||
|
||||
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,
|
|||
unsigned long possible_crtcs, u32 master_plane_id)
|
||||
{
|
||||
struct drm_plane *plane = NULL, *master_plane = NULL;
|
||||
const struct dpu_format_extended *format_list;
|
||||
const uint32_t *format_list;
|
||||
struct dpu_plane *pdpu;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct dpu_kms *kms = to_dpu_kms(priv->kms);
|
||||
int zpos_max = DPU_ZPOS_MAX;
|
||||
uint32_t num_formats;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/* create and zero local structure */
|
||||
|
@ -1491,24 +1514,18 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev,
|
|||
goto clean_sspp;
|
||||
}
|
||||
|
||||
if (!master_plane_id)
|
||||
format_list = pdpu->pipe_sblk->format_list;
|
||||
else
|
||||
if (pdpu->is_virtual) {
|
||||
format_list = pdpu->pipe_sblk->virt_format_list;
|
||||
|
||||
pdpu->nformats = dpu_populate_formats(format_list,
|
||||
pdpu->formats,
|
||||
0,
|
||||
ARRAY_SIZE(pdpu->formats));
|
||||
|
||||
if (!pdpu->nformats) {
|
||||
DPU_ERROR("[%u]no valid formats for plane\n", pipe);
|
||||
goto clean_sspp;
|
||||
num_formats = pdpu->pipe_sblk->virt_num_formats;
|
||||
}
|
||||
else {
|
||||
format_list = pdpu->pipe_sblk->format_list;
|
||||
num_formats = pdpu->pipe_sblk->num_formats;
|
||||
}
|
||||
|
||||
ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs,
|
||||
pdpu->formats, pdpu->nformats,
|
||||
NULL, type, NULL);
|
||||
format_list, num_formats,
|
||||
supported_format_modifiers, type, NULL);
|
||||
if (ret)
|
||||
goto clean_sspp;
|
||||
|
||||
|
|
|
@ -28,23 +28,18 @@
|
|||
/**
|
||||
* struct dpu_plane_state: Define dpu extension of drm plane state object
|
||||
* @base: base drm plane state object
|
||||
* @property_state: Local storage for msm_prop properties
|
||||
* @property_values: cached plane property values
|
||||
* @aspace: pointer to address space for input/output buffers
|
||||
* @input_fence: dereferenced input fence pointer
|
||||
* @stage: assigned by crtc blender
|
||||
* @multirect_index: index of the rectangle of SSPP
|
||||
* @multirect_mode: parallel or time multiplex multirect mode
|
||||
* @pending: whether the current update is still pending
|
||||
* @scaler3_cfg: configuration data for scaler3
|
||||
* @pixel_ext: configuration data for pixel extensions
|
||||
* @scaler_check_state: indicates status of user provided pixel extension data
|
||||
* @cdp_cfg: CDP configuration
|
||||
*/
|
||||
struct dpu_plane_state {
|
||||
struct drm_plane_state base;
|
||||
struct msm_gem_address_space *aspace;
|
||||
void *input_fence;
|
||||
enum dpu_stage stage;
|
||||
uint32_t multirect_index;
|
||||
uint32_t multirect_mode;
|
||||
|
@ -106,12 +101,6 @@ void dpu_plane_restore(struct drm_plane *plane);
|
|||
*/
|
||||
void dpu_plane_flush(struct drm_plane *plane);
|
||||
|
||||
/**
|
||||
* dpu_plane_kickoff - final plane operations before commit kickoff
|
||||
* @plane: Pointer to drm plane structure
|
||||
*/
|
||||
void dpu_plane_kickoff(struct drm_plane *plane);
|
||||
|
||||
/**
|
||||
* dpu_plane_set_error: enable/disable error condition
|
||||
* @plane: pointer to drm_plane structure
|
||||
|
@ -146,14 +135,6 @@ int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane);
|
|||
*/
|
||||
void dpu_plane_clear_multirect(const struct drm_plane_state *drm_state);
|
||||
|
||||
/**
|
||||
* dpu_plane_wait_input_fence - wait for input fence object
|
||||
* @plane: Pointer to DRM plane object
|
||||
* @wait_ms: Wait timeout value
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms);
|
||||
|
||||
/**
|
||||
* dpu_plane_color_fill - enables color fill on plane
|
||||
* @plane: Pointer to DRM plane object
|
||||
|
@ -164,12 +145,4 @@ int dpu_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms);
|
|||
int dpu_plane_color_fill(struct drm_plane *plane,
|
||||
uint32_t color, uint32_t alpha);
|
||||
|
||||
/**
|
||||
* dpu_plane_set_revalidate - sets revalidate flag which forces a full
|
||||
* validation of the plane properties in the next atomic check
|
||||
* @plane: Pointer to DRM plane object
|
||||
* @enable: Boolean to set/unset the flag
|
||||
*/
|
||||
void dpu_plane_set_revalidate(struct drm_plane *plane, bool enable);
|
||||
|
||||
#endif /* _DPU_PLANE_H_ */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "dpu_trace.h"
|
||||
|
||||
#define RESERVED_BY_OTHER(h, r) \
|
||||
((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id))
|
||||
((h)->enc_id && (h)->enc_id != r)
|
||||
|
||||
/**
|
||||
* struct dpu_rm_requirements - Reservation requirements parameter bundle
|
||||
|
@ -34,90 +34,21 @@ struct dpu_rm_requirements {
|
|||
struct dpu_encoder_hw_resources hw_res;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_rm_rsvp - Use Case Reservation tagging structure
|
||||
* Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain
|
||||
* By using as a tag, rather than lists of pointers to HW blocks used
|
||||
* we can avoid some list management since we don't know how many blocks
|
||||
* of each type a given use case may require.
|
||||
* @list: List head for list of all reservations
|
||||
* @seq: Global RSVP sequence number for debugging, especially for
|
||||
* differentiating differenct allocations for same encoder.
|
||||
* @enc_id: Reservations are tracked by Encoder DRM object ID.
|
||||
* CRTCs may be connected to multiple Encoders.
|
||||
* An encoder or connector id identifies the display path.
|
||||
*/
|
||||
struct dpu_rm_rsvp {
|
||||
struct list_head list;
|
||||
uint32_t seq;
|
||||
uint32_t enc_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dpu_rm_hw_blk - hardware block tracking list member
|
||||
* @list: List head for list of all hardware blocks tracking items
|
||||
* @rsvp: Pointer to use case reservation if reserved by a client
|
||||
* @rsvp_nxt: Temporary pointer used during reservation to the incoming
|
||||
* request. Will be swapped into rsvp if proposal is accepted
|
||||
* @type: Type of hardware block this structure tracks
|
||||
* @id: Hardware ID number, within it's own space, ie. LM_X
|
||||
* @catalog: Pointer to the hardware catalog entry for this block
|
||||
* @enc_id: Encoder id to which this blk is binded
|
||||
* @hw: Pointer to the hardware register access object for this block
|
||||
*/
|
||||
struct dpu_rm_hw_blk {
|
||||
struct list_head list;
|
||||
struct dpu_rm_rsvp *rsvp;
|
||||
struct dpu_rm_rsvp *rsvp_nxt;
|
||||
enum dpu_hw_blk_type type;
|
||||
uint32_t id;
|
||||
uint32_t enc_id;
|
||||
struct dpu_hw_blk *hw;
|
||||
};
|
||||
|
||||
/**
|
||||
* dpu_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging
|
||||
*/
|
||||
enum dpu_rm_dbg_rsvp_stage {
|
||||
DPU_RM_STAGE_BEGIN,
|
||||
DPU_RM_STAGE_AFTER_CLEAR,
|
||||
DPU_RM_STAGE_AFTER_RSVPNEXT,
|
||||
DPU_RM_STAGE_FINAL
|
||||
};
|
||||
|
||||
static void _dpu_rm_print_rsvps(
|
||||
struct dpu_rm *rm,
|
||||
enum dpu_rm_dbg_rsvp_stage stage)
|
||||
{
|
||||
struct dpu_rm_rsvp *rsvp;
|
||||
struct dpu_rm_hw_blk *blk;
|
||||
enum dpu_hw_blk_type type;
|
||||
|
||||
DPU_DEBUG("%d\n", stage);
|
||||
|
||||
list_for_each_entry(rsvp, &rm->rsvps, list) {
|
||||
DRM_DEBUG_KMS("%d rsvp[s%ue%u]\n", stage, rsvp->seq,
|
||||
rsvp->enc_id);
|
||||
}
|
||||
|
||||
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
|
||||
list_for_each_entry(blk, &rm->hw_blks[type], list) {
|
||||
if (!blk->rsvp && !blk->rsvp_nxt)
|
||||
continue;
|
||||
|
||||
DRM_DEBUG_KMS("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage,
|
||||
(blk->rsvp) ? blk->rsvp->seq : 0,
|
||||
(blk->rsvp) ? blk->rsvp->enc_id : 0,
|
||||
(blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0,
|
||||
(blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0,
|
||||
blk->type, blk->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm)
|
||||
{
|
||||
return rm->hw_mdp;
|
||||
}
|
||||
|
||||
void dpu_rm_init_hw_iter(
|
||||
struct dpu_rm_hw_iter *iter,
|
||||
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)
|
|||
i->blk = list_prepare_entry(i->blk, blk_list, list);
|
||||
|
||||
list_for_each_entry_continue(i->blk, blk_list, list) {
|
||||
struct dpu_rm_rsvp *rsvp = i->blk->rsvp;
|
||||
|
||||
if (i->blk->type != i->type) {
|
||||
DPU_ERROR("found incorrect block type %d on %d list\n",
|
||||
i->blk->type, i->type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) {
|
||||
if (i->enc_id == i->blk->enc_id) {
|
||||
i->hw = i->blk->hw;
|
||||
DPU_DEBUG("found type %d id %d for enc %d\n",
|
||||
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)
|
|||
|
||||
int dpu_rm_destroy(struct dpu_rm *rm)
|
||||
{
|
||||
|
||||
struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt;
|
||||
struct dpu_rm_hw_blk *hw_cur, *hw_nxt;
|
||||
enum dpu_hw_blk_type type;
|
||||
|
||||
if (!rm) {
|
||||
DPU_ERROR("invalid rm\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(rsvp_cur, rsvp_nxt, &rm->rsvps, list) {
|
||||
list_del(&rsvp_cur->list);
|
||||
kfree(rsvp_cur);
|
||||
}
|
||||
|
||||
|
||||
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
|
||||
list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type],
|
||||
list) {
|
||||
list_del(&hw_cur->list);
|
||||
_dpu_rm_hw_destroy(hw_cur->type, hw_cur->hw);
|
||||
_dpu_rm_hw_destroy(type, hw_cur->hw);
|
||||
kfree(hw_cur);
|
||||
}
|
||||
}
|
||||
|
||||
dpu_hw_mdp_destroy(rm->hw_mdp);
|
||||
rm->hw_mdp = NULL;
|
||||
|
||||
mutex_destroy(&rm->rm_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -250,11 +157,8 @@ static int _dpu_rm_hw_blk_create(
|
|||
void *hw_catalog_info)
|
||||
{
|
||||
struct dpu_rm_hw_blk *blk;
|
||||
struct dpu_hw_mdp *hw_mdp;
|
||||
void *hw;
|
||||
|
||||
hw_mdp = rm->hw_mdp;
|
||||
|
||||
switch (type) {
|
||||
case DPU_HW_BLK_LM:
|
||||
hw = dpu_hw_lm_init(id, mmio, cat);
|
||||
|
@ -290,9 +194,9 @@ static int _dpu_rm_hw_blk_create(
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
blk->type = type;
|
||||
blk->id = id;
|
||||
blk->hw = hw;
|
||||
blk->enc_id = 0;
|
||||
list_add_tail(&blk->list, &rm->hw_blks[type]);
|
||||
|
||||
return 0;
|
||||
|
@ -300,13 +204,12 @@ static int _dpu_rm_hw_blk_create(
|
|||
|
||||
int dpu_rm_init(struct dpu_rm *rm,
|
||||
struct dpu_mdss_cfg *cat,
|
||||
void __iomem *mmio,
|
||||
struct drm_device *dev)
|
||||
void __iomem *mmio)
|
||||
{
|
||||
int rc, i;
|
||||
enum dpu_hw_blk_type type;
|
||||
|
||||
if (!rm || !cat || !mmio || !dev) {
|
||||
if (!rm || !cat || !mmio) {
|
||||
DPU_ERROR("invalid kms\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -316,21 +219,9 @@ int dpu_rm_init(struct dpu_rm *rm,
|
|||
|
||||
mutex_init(&rm->rm_lock);
|
||||
|
||||
INIT_LIST_HEAD(&rm->rsvps);
|
||||
for (type = 0; type < DPU_HW_BLK_MAX; type++)
|
||||
INIT_LIST_HEAD(&rm->hw_blks[type]);
|
||||
|
||||
rm->dev = dev;
|
||||
|
||||
/* Some of the sub-blocks require an mdptop to be created */
|
||||
rm->hw_mdp = dpu_hw_mdptop_init(MDP_TOP, mmio, cat);
|
||||
if (IS_ERR_OR_NULL(rm->hw_mdp)) {
|
||||
rc = PTR_ERR(rm->hw_mdp);
|
||||
rm->hw_mdp = NULL;
|
||||
DPU_ERROR("failed: mdp hw not available\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Interrogate HW catalog and create tracking items for hw blocks */
|
||||
for (i = 0; i < cat->mixer_count; i++) {
|
||||
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)
|
|||
* proposed use case requirements, incl. hardwired dependent blocks like
|
||||
* pingpong
|
||||
* @rm: dpu resource manager handle
|
||||
* @rsvp: reservation currently being created
|
||||
* @enc_id: encoder id requesting for allocation
|
||||
* @reqs: proposed use case requirements
|
||||
* @lm: proposed layer mixer, function checks if lm, and all other hardwired
|
||||
* 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)
|
|||
*/
|
||||
static bool _dpu_rm_check_lm_and_get_connected_blks(
|
||||
struct dpu_rm *rm,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
uint32_t enc_id,
|
||||
struct dpu_rm_requirements *reqs,
|
||||
struct dpu_rm_hw_blk *lm,
|
||||
struct dpu_rm_hw_blk **pp,
|
||||
|
@ -449,7 +340,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
|
|||
}
|
||||
|
||||
/* Already reserved? */
|
||||
if (RESERVED_BY_OTHER(lm, rsvp)) {
|
||||
if (RESERVED_BY_OTHER(lm, enc_id)) {
|
||||
DPU_DEBUG("lm %d already reserved\n", lm_cfg->id);
|
||||
return false;
|
||||
}
|
||||
|
@ -467,7 +358,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
|
|||
return false;
|
||||
}
|
||||
|
||||
if (RESERVED_BY_OTHER(*pp, rsvp)) {
|
||||
if (RESERVED_BY_OTHER(*pp, enc_id)) {
|
||||
DPU_DEBUG("lm %d pp %d already reserved\n", lm->id,
|
||||
(*pp)->id);
|
||||
return false;
|
||||
|
@ -476,9 +367,7 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(
|
|||
return true;
|
||||
}
|
||||
|
||||
static int _dpu_rm_reserve_lms(
|
||||
struct dpu_rm *rm,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
static int _dpu_rm_reserve_lms(struct dpu_rm *rm, uint32_t enc_id,
|
||||
struct dpu_rm_requirements *reqs)
|
||||
|
||||
{
|
||||
|
@ -504,7 +393,7 @@ static int _dpu_rm_reserve_lms(
|
|||
lm[lm_count] = iter_i.blk;
|
||||
|
||||
if (!_dpu_rm_check_lm_and_get_connected_blks(
|
||||
rm, rsvp, reqs, lm[lm_count],
|
||||
rm, enc_id, reqs, lm[lm_count],
|
||||
&pp[lm_count], NULL))
|
||||
continue;
|
||||
|
||||
|
@ -519,7 +408,7 @@ static int _dpu_rm_reserve_lms(
|
|||
continue;
|
||||
|
||||
if (!_dpu_rm_check_lm_and_get_connected_blks(
|
||||
rm, rsvp, reqs, iter_j.blk,
|
||||
rm, enc_id, reqs, iter_j.blk,
|
||||
&pp[lm_count], iter_i.blk))
|
||||
continue;
|
||||
|
||||
|
@ -537,11 +426,10 @@ static int _dpu_rm_reserve_lms(
|
|||
if (!lm[i])
|
||||
break;
|
||||
|
||||
lm[i]->rsvp_nxt = rsvp;
|
||||
pp[i]->rsvp_nxt = rsvp;
|
||||
lm[i]->enc_id = enc_id;
|
||||
pp[i]->enc_id = enc_id;
|
||||
|
||||
trace_dpu_rm_reserve_lms(lm[i]->id, lm[i]->type, rsvp->enc_id,
|
||||
pp[i]->id);
|
||||
trace_dpu_rm_reserve_lms(lm[i]->id, enc_id, pp[i]->id);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -549,7 +437,7 @@ static int _dpu_rm_reserve_lms(
|
|||
|
||||
static int _dpu_rm_reserve_ctls(
|
||||
struct dpu_rm *rm,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
uint32_t enc_id,
|
||||
const struct msm_display_topology *top)
|
||||
{
|
||||
struct dpu_rm_hw_blk *ctls[MAX_BLOCKS];
|
||||
|
@ -570,7 +458,7 @@ static int _dpu_rm_reserve_ctls(
|
|||
unsigned long features = ctl->caps->features;
|
||||
bool has_split_display;
|
||||
|
||||
if (RESERVED_BY_OTHER(iter.blk, rsvp))
|
||||
if (RESERVED_BY_OTHER(iter.blk, enc_id))
|
||||
continue;
|
||||
|
||||
has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features;
|
||||
|
@ -591,9 +479,8 @@ static int _dpu_rm_reserve_ctls(
|
|||
return -ENAVAIL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ctls) && i < num_ctls; i++) {
|
||||
ctls[i]->rsvp_nxt = rsvp;
|
||||
trace_dpu_rm_reserve_ctls(ctls[i]->id, ctls[i]->type,
|
||||
rsvp->enc_id);
|
||||
ctls[i]->enc_id = enc_id;
|
||||
trace_dpu_rm_reserve_ctls(ctls[i]->id, enc_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -601,7 +488,7 @@ static int _dpu_rm_reserve_ctls(
|
|||
|
||||
static int _dpu_rm_reserve_intf(
|
||||
struct dpu_rm *rm,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
uint32_t enc_id,
|
||||
uint32_t id,
|
||||
enum dpu_hw_blk_type type)
|
||||
{
|
||||
|
@ -614,14 +501,13 @@ static int _dpu_rm_reserve_intf(
|
|||
if (iter.blk->id != id)
|
||||
continue;
|
||||
|
||||
if (RESERVED_BY_OTHER(iter.blk, rsvp)) {
|
||||
if (RESERVED_BY_OTHER(iter.blk, enc_id)) {
|
||||
DPU_ERROR("type %d id %d already reserved\n", type, id);
|
||||
return -ENAVAIL;
|
||||
}
|
||||
|
||||
iter.blk->rsvp_nxt = rsvp;
|
||||
trace_dpu_rm_reserve_intf(iter.blk->id, iter.blk->type,
|
||||
rsvp->enc_id);
|
||||
iter.blk->enc_id = enc_id;
|
||||
trace_dpu_rm_reserve_intf(iter.blk->id, enc_id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -636,7 +522,7 @@ static int _dpu_rm_reserve_intf(
|
|||
|
||||
static int _dpu_rm_reserve_intf_related_hw(
|
||||
struct dpu_rm *rm,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
uint32_t enc_id,
|
||||
struct dpu_encoder_hw_resources *hw_res)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
@ -646,7 +532,7 @@ static int _dpu_rm_reserve_intf_related_hw(
|
|||
if (hw_res->intfs[i] == INTF_MODE_NONE)
|
||||
continue;
|
||||
id = i + INTF_0;
|
||||
ret = _dpu_rm_reserve_intf(rm, rsvp, id,
|
||||
ret = _dpu_rm_reserve_intf(rm, enc_id, id,
|
||||
DPU_HW_BLK_INTF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -655,33 +541,27 @@ static int _dpu_rm_reserve_intf_related_hw(
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int _dpu_rm_make_next_rsvp(
|
||||
static int _dpu_rm_make_reservation(
|
||||
struct dpu_rm *rm,
|
||||
struct drm_encoder *enc,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct dpu_rm_rsvp *rsvp,
|
||||
struct dpu_rm_requirements *reqs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Create reservation info, tag reserved blocks with it as we go */
|
||||
rsvp->seq = ++rm->rsvp_next_seq;
|
||||
rsvp->enc_id = enc->base.id;
|
||||
list_add_tail(&rsvp->list, &rm->rsvps);
|
||||
|
||||
ret = _dpu_rm_reserve_lms(rm, rsvp, reqs);
|
||||
ret = _dpu_rm_reserve_lms(rm, enc->base.id, reqs);
|
||||
if (ret) {
|
||||
DPU_ERROR("unable to find appropriate mixers\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = _dpu_rm_reserve_ctls(rm, rsvp, &reqs->topology);
|
||||
ret = _dpu_rm_reserve_ctls(rm, enc->base.id, &reqs->topology);
|
||||
if (ret) {
|
||||
DPU_ERROR("unable to find appropriate CTL\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = _dpu_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res);
|
||||
ret = _dpu_rm_reserve_intf_related_hw(rm, enc->base.id, &reqs->hw_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -706,108 +586,31 @@ static int _dpu_rm_populate_requirements(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dpu_rm_rsvp *_dpu_rm_get_rsvp(
|
||||
struct dpu_rm *rm,
|
||||
struct drm_encoder *enc)
|
||||
static void _dpu_rm_release_reservation(struct dpu_rm *rm, uint32_t enc_id)
|
||||
{
|
||||
struct dpu_rm_rsvp *i;
|
||||
|
||||
if (!rm || !enc) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (list_empty(&rm->rsvps))
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(i, &rm->rsvps, list)
|
||||
if (i->enc_id == enc->base.id)
|
||||
return i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* _dpu_rm_release_rsvp - release resources and release a reservation
|
||||
* @rm: KMS handle
|
||||
* @rsvp: RSVP pointer to release and release resources for
|
||||
*/
|
||||
static void _dpu_rm_release_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp)
|
||||
{
|
||||
struct dpu_rm_rsvp *rsvp_c, *rsvp_n;
|
||||
struct dpu_rm_hw_blk *blk;
|
||||
enum dpu_hw_blk_type type;
|
||||
|
||||
if (!rsvp)
|
||||
return;
|
||||
|
||||
DPU_DEBUG("rel rsvp %d enc %d\n", rsvp->seq, rsvp->enc_id);
|
||||
|
||||
list_for_each_entry_safe(rsvp_c, rsvp_n, &rm->rsvps, list) {
|
||||
if (rsvp == rsvp_c) {
|
||||
list_del(&rsvp_c->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
|
||||
list_for_each_entry(blk, &rm->hw_blks[type], list) {
|
||||
if (blk->rsvp == rsvp) {
|
||||
blk->rsvp = NULL;
|
||||
DPU_DEBUG("rel rsvp %d enc %d %d %d\n",
|
||||
rsvp->seq, rsvp->enc_id,
|
||||
blk->type, blk->id);
|
||||
}
|
||||
if (blk->rsvp_nxt == rsvp) {
|
||||
blk->rsvp_nxt = NULL;
|
||||
DPU_DEBUG("rel rsvp_nxt %d enc %d %d %d\n",
|
||||
rsvp->seq, rsvp->enc_id,
|
||||
blk->type, blk->id);
|
||||
if (blk->enc_id == enc_id) {
|
||||
blk->enc_id = 0;
|
||||
DPU_DEBUG("rel enc %d %d %d\n", enc_id,
|
||||
type, blk->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kfree(rsvp);
|
||||
}
|
||||
|
||||
void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc)
|
||||
{
|
||||
struct dpu_rm_rsvp *rsvp;
|
||||
|
||||
if (!rm || !enc) {
|
||||
DPU_ERROR("invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&rm->rm_lock);
|
||||
|
||||
rsvp = _dpu_rm_get_rsvp(rm, enc);
|
||||
if (!rsvp) {
|
||||
DPU_ERROR("failed to find rsvp for enc %d\n", enc->base.id);
|
||||
goto end;
|
||||
}
|
||||
_dpu_rm_release_reservation(rm, enc->base.id);
|
||||
|
||||
_dpu_rm_release_rsvp(rm, rsvp);
|
||||
end:
|
||||
mutex_unlock(&rm->rm_lock);
|
||||
}
|
||||
|
||||
static void _dpu_rm_commit_rsvp(struct dpu_rm *rm, struct dpu_rm_rsvp *rsvp)
|
||||
{
|
||||
struct dpu_rm_hw_blk *blk;
|
||||
enum dpu_hw_blk_type type;
|
||||
|
||||
/* Swap next rsvp to be the active */
|
||||
for (type = 0; type < DPU_HW_BLK_MAX; type++) {
|
||||
list_for_each_entry(blk, &rm->hw_blks[type], list) {
|
||||
if (blk->rsvp_nxt) {
|
||||
blk->rsvp = blk->rsvp_nxt;
|
||||
blk->rsvp_nxt = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dpu_rm_reserve(
|
||||
struct dpu_rm *rm,
|
||||
struct drm_encoder *enc,
|
||||
|
@ -815,7 +618,6 @@ int dpu_rm_reserve(
|
|||
struct msm_display_topology topology,
|
||||
bool test_only)
|
||||
{
|
||||
struct dpu_rm_rsvp *rsvp_cur, *rsvp_nxt;
|
||||
struct dpu_rm_requirements reqs;
|
||||
int ret;
|
||||
|
||||
|
@ -828,8 +630,6 @@ int dpu_rm_reserve(
|
|||
|
||||
mutex_lock(&rm->rm_lock);
|
||||
|
||||
_dpu_rm_print_rsvps(rm, DPU_RM_STAGE_BEGIN);
|
||||
|
||||
ret = _dpu_rm_populate_requirements(rm, enc, crtc_state, &reqs,
|
||||
topology);
|
||||
if (ret) {
|
||||
|
@ -837,50 +637,17 @@ int dpu_rm_reserve(
|
|||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only support one active reservation per-hw-block. But to implement
|
||||
* transactional semantics for test-only, and for allowing failure while
|
||||
* modifying your existing reservation, over the course of this
|
||||
* function we can have two reservations:
|
||||
* Current: Existing reservation
|
||||
* Next: Proposed reservation. The proposed reservation may fail, or may
|
||||
* be discarded if in test-only mode.
|
||||
* If reservation is successful, and we're not in test-only, then we
|
||||
* replace the current with the next.
|
||||
*/
|
||||
rsvp_nxt = kzalloc(sizeof(*rsvp_nxt), GFP_KERNEL);
|
||||
if (!rsvp_nxt) {
|
||||
ret = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rsvp_cur = _dpu_rm_get_rsvp(rm, enc);
|
||||
|
||||
/* Check the proposed reservation, store it in hw's "next" field */
|
||||
ret = _dpu_rm_make_next_rsvp(rm, enc, crtc_state, rsvp_nxt, &reqs);
|
||||
|
||||
_dpu_rm_print_rsvps(rm, DPU_RM_STAGE_AFTER_RSVPNEXT);
|
||||
|
||||
ret = _dpu_rm_make_reservation(rm, enc, crtc_state, &reqs);
|
||||
if (ret) {
|
||||
DPU_ERROR("failed to reserve hw resources: %d\n", ret);
|
||||
_dpu_rm_release_rsvp(rm, rsvp_nxt);
|
||||
_dpu_rm_release_reservation(rm, enc->base.id);
|
||||
} else if (test_only) {
|
||||
/*
|
||||
* Normally, if test_only, test the reservation and then undo
|
||||
* However, if the user requests LOCK, then keep the reservation
|
||||
* made during the atomic_check phase.
|
||||
*/
|
||||
DPU_DEBUG("test_only: discard test rsvp[s%de%d]\n",
|
||||
rsvp_nxt->seq, rsvp_nxt->enc_id);
|
||||
_dpu_rm_release_rsvp(rm, rsvp_nxt);
|
||||
} else {
|
||||
_dpu_rm_release_rsvp(rm, rsvp_cur);
|
||||
|
||||
_dpu_rm_commit_rsvp(rm, rsvp_nxt);
|
||||
/* test_only: test the reservation and then undo */
|
||||
DPU_DEBUG("test_only: discard test [enc: %d]\n",
|
||||
enc->base.id);
|
||||
_dpu_rm_release_reservation(rm, enc->base.id);
|
||||
}
|
||||
|
||||
_dpu_rm_print_rsvps(rm, DPU_RM_STAGE_FINAL);
|
||||
|
||||
end:
|
||||
mutex_unlock(&rm->rm_lock);
|
||||
|
||||
|
|
|
@ -22,22 +22,14 @@
|
|||
|
||||
/**
|
||||
* struct dpu_rm - DPU dynamic hardware resource manager
|
||||
* @dev: device handle for event logging purposes
|
||||
* @rsvps: list of hardware reservations by each crtc->encoder->connector
|
||||
* @hw_blks: array of lists of hardware resources present in the system, one
|
||||
* list per type of hardware block
|
||||
* @hw_mdp: hardware object for mdp_top
|
||||
* @lm_max_width: cached layer mixer maximum width
|
||||
* @rsvp_next_seq: sequence number for next reservation for debugging purposes
|
||||
* @rm_lock: resource manager mutex
|
||||
*/
|
||||
struct dpu_rm {
|
||||
struct drm_device *dev;
|
||||
struct list_head rsvps;
|
||||
struct list_head hw_blks[DPU_HW_BLK_MAX];
|
||||
struct dpu_hw_mdp *hw_mdp;
|
||||
uint32_t lm_max_width;
|
||||
uint32_t rsvp_next_seq;
|
||||
struct mutex rm_lock;
|
||||
};
|
||||
|
||||
|
@ -67,13 +59,11 @@ struct dpu_rm_hw_iter {
|
|||
* @rm: DPU Resource Manager handle
|
||||
* @cat: Pointer to hardware catalog
|
||||
* @mmio: mapped register io address of MDP
|
||||
* @dev: device handle for event logging purposes
|
||||
* @Return: 0 on Success otherwise -ERROR
|
||||
*/
|
||||
int dpu_rm_init(struct dpu_rm *rm,
|
||||
struct dpu_mdss_cfg *cat,
|
||||
void __iomem *mmio,
|
||||
struct drm_device *dev);
|
||||
void __iomem *mmio);
|
||||
|
||||
/**
|
||||
* dpu_rm_destroy - Free all memory allocated by dpu_rm_init
|
||||
|
@ -111,14 +101,6 @@ int dpu_rm_reserve(struct dpu_rm *rm,
|
|||
*/
|
||||
void dpu_rm_release(struct dpu_rm *rm, struct drm_encoder *enc);
|
||||
|
||||
/**
|
||||
* dpu_rm_get_mdp - Retrieve HW block for MDP TOP.
|
||||
* This is never reserved, and is usable by any display.
|
||||
* @rm: DPU Resource Manager handle
|
||||
* @Return: Pointer to hw block or NULL
|
||||
*/
|
||||
struct dpu_hw_mdp *dpu_rm_get_mdp(struct dpu_rm *rm);
|
||||
|
||||
/**
|
||||
* dpu_rm_init_hw_iter - setup given iterator for new iteration over hw list
|
||||
* using dpu_rm_get_hw
|
||||
|
@ -144,12 +126,4 @@ void dpu_rm_init_hw_iter(
|
|||
* @Return: true on match found, false on no match found
|
||||
*/
|
||||
bool dpu_rm_get_hw(struct dpu_rm *rm, struct dpu_rm_hw_iter *iter);
|
||||
|
||||
/**
|
||||
* dpu_rm_check_property_topctl - validate property bitmask before it is set
|
||||
* @val: user's proposed topology control bitmask
|
||||
* @Return: 0 on success or error
|
||||
*/
|
||||
int dpu_rm_check_property_topctl(uint64_t val);
|
||||
|
||||
#endif /* __DPU_RM_H__ */
|
||||
|
|
|
@ -831,48 +831,42 @@ TRACE_EVENT(dpu_plane_disable,
|
|||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(dpu_rm_iter_template,
|
||||
TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
|
||||
TP_ARGS(id, type, enc_id),
|
||||
TP_PROTO(uint32_t id, uint32_t enc_id),
|
||||
TP_ARGS(id, enc_id),
|
||||
TP_STRUCT__entry(
|
||||
__field( uint32_t, id )
|
||||
__field( enum dpu_hw_blk_type, type )
|
||||
__field( uint32_t, enc_id )
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->id = id;
|
||||
__entry->type = type;
|
||||
__entry->enc_id = enc_id;
|
||||
),
|
||||
TP_printk("id:%d type:%d enc_id:%u", __entry->id, __entry->type,
|
||||
__entry->enc_id)
|
||||
TP_printk("id:%d enc_id:%u", __entry->id, __entry->enc_id)
|
||||
);
|
||||
DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_intf,
|
||||
TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
|
||||
TP_ARGS(id, type, enc_id)
|
||||
TP_PROTO(uint32_t id, uint32_t enc_id),
|
||||
TP_ARGS(id, enc_id)
|
||||
);
|
||||
DEFINE_EVENT(dpu_rm_iter_template, dpu_rm_reserve_ctls,
|
||||
TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id),
|
||||
TP_ARGS(id, type, enc_id)
|
||||
TP_PROTO(uint32_t id, uint32_t enc_id),
|
||||
TP_ARGS(id, enc_id)
|
||||
);
|
||||
|
||||
TRACE_EVENT(dpu_rm_reserve_lms,
|
||||
TP_PROTO(uint32_t id, enum dpu_hw_blk_type type, uint32_t enc_id,
|
||||
uint32_t pp_id),
|
||||
TP_ARGS(id, type, enc_id, pp_id),
|
||||
TP_PROTO(uint32_t id, uint32_t enc_id, uint32_t pp_id),
|
||||
TP_ARGS(id, enc_id, pp_id),
|
||||
TP_STRUCT__entry(
|
||||
__field( uint32_t, id )
|
||||
__field( enum dpu_hw_blk_type, type )
|
||||
__field( uint32_t, enc_id )
|
||||
__field( uint32_t, pp_id )
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->id = id;
|
||||
__entry->type = type;
|
||||
__entry->enc_id = enc_id;
|
||||
__entry->pp_id = pp_id;
|
||||
),
|
||||
TP_printk("id:%d type:%d enc_id:%u pp_id:%u", __entry->id,
|
||||
__entry->type, __entry->enc_id, __entry->pp_id)
|
||||
TP_printk("id:%d enc_id:%u pp_id:%u", __entry->id,
|
||||
__entry->enc_id, __entry->pp_id)
|
||||
);
|
||||
|
||||
TRACE_EVENT(dpu_vbif_wait_xin_halt_fail,
|
||||
|
|
|
@ -207,62 +207,44 @@ u32 msm_readl(const void __iomem *addr)
|
|||
return val;
|
||||
}
|
||||
|
||||
struct vblank_event {
|
||||
struct list_head node;
|
||||
struct msm_vblank_work {
|
||||
struct work_struct work;
|
||||
int crtc_id;
|
||||
bool enable;
|
||||
struct msm_drm_private *priv;
|
||||
};
|
||||
|
||||
static void vblank_ctrl_worker(struct kthread_work *work)
|
||||
static void vblank_ctrl_worker(struct work_struct *work)
|
||||
{
|
||||
struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
|
||||
struct msm_vblank_ctrl, work);
|
||||
struct msm_drm_private *priv = container_of(vbl_ctrl,
|
||||
struct msm_drm_private, vblank_ctrl);
|
||||
struct msm_vblank_work *vbl_work = container_of(work,
|
||||
struct msm_vblank_work, work);
|
||||
struct msm_drm_private *priv = vbl_work->priv;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
struct vblank_event *vbl_ev, *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&vbl_ctrl->lock, flags);
|
||||
list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
|
||||
list_del(&vbl_ev->node);
|
||||
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
|
||||
|
||||
if (vbl_ev->enable)
|
||||
kms->funcs->enable_vblank(kms,
|
||||
priv->crtcs[vbl_ev->crtc_id]);
|
||||
if (vbl_work->enable)
|
||||
kms->funcs->enable_vblank(kms, priv->crtcs[vbl_work->crtc_id]);
|
||||
else
|
||||
kms->funcs->disable_vblank(kms,
|
||||
priv->crtcs[vbl_ev->crtc_id]);
|
||||
kms->funcs->disable_vblank(kms, priv->crtcs[vbl_work->crtc_id]);
|
||||
|
||||
kfree(vbl_ev);
|
||||
|
||||
spin_lock_irqsave(&vbl_ctrl->lock, flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
|
||||
kfree(vbl_work);
|
||||
}
|
||||
|
||||
static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
|
||||
int crtc_id, bool enable)
|
||||
{
|
||||
struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
|
||||
struct vblank_event *vbl_ev;
|
||||
unsigned long flags;
|
||||
struct msm_vblank_work *vbl_work;
|
||||
|
||||
vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC);
|
||||
if (!vbl_ev)
|
||||
vbl_work = kzalloc(sizeof(*vbl_work), GFP_ATOMIC);
|
||||
if (!vbl_work)
|
||||
return -ENOMEM;
|
||||
|
||||
vbl_ev->crtc_id = crtc_id;
|
||||
vbl_ev->enable = enable;
|
||||
INIT_WORK(&vbl_work->work, vblank_ctrl_worker);
|
||||
|
||||
spin_lock_irqsave(&vbl_ctrl->lock, flags);
|
||||
list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
|
||||
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
|
||||
vbl_work->crtc_id = crtc_id;
|
||||
vbl_work->enable = enable;
|
||||
vbl_work->priv = priv;
|
||||
|
||||
kthread_queue_work(&priv->disp_thread[crtc_id].worker,
|
||||
&vbl_ctrl->work);
|
||||
queue_work(priv->wq, &vbl_work->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -274,31 +256,20 @@ static int msm_drm_uninit(struct device *dev)
|
|||
struct msm_drm_private *priv = ddev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
struct msm_mdss *mdss = priv->mdss;
|
||||
struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
|
||||
struct vblank_event *vbl_ev, *tmp;
|
||||
int i;
|
||||
|
||||
/* We must cancel and cleanup any pending vblank enable/disable
|
||||
* work before drm_irq_uninstall() to avoid work re-enabling an
|
||||
* irq after uninstall has disabled it.
|
||||
*/
|
||||
kthread_flush_work(&vbl_ctrl->work);
|
||||
list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
|
||||
list_del(&vbl_ev->node);
|
||||
kfree(vbl_ev);
|
||||
}
|
||||
|
||||
/* clean up display commit/event worker threads */
|
||||
flush_workqueue(priv->wq);
|
||||
destroy_workqueue(priv->wq);
|
||||
|
||||
/* clean up event worker threads */
|
||||
for (i = 0; i < priv->num_crtcs; i++) {
|
||||
if (priv->disp_thread[i].thread) {
|
||||
kthread_flush_worker(&priv->disp_thread[i].worker);
|
||||
kthread_stop(priv->disp_thread[i].thread);
|
||||
priv->disp_thread[i].thread = NULL;
|
||||
}
|
||||
|
||||
if (priv->event_thread[i].thread) {
|
||||
kthread_flush_worker(&priv->event_thread[i].worker);
|
||||
kthread_stop(priv->event_thread[i].thread);
|
||||
kthread_destroy_worker(&priv->event_thread[i].worker);
|
||||
priv->event_thread[i].thread = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -323,9 +294,6 @@ static int msm_drm_uninit(struct device *dev)
|
|||
drm_irq_uninstall(ddev);
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
flush_workqueue(priv->wq);
|
||||
destroy_workqueue(priv->wq);
|
||||
|
||||
if (kms && kms->funcs)
|
||||
kms->funcs->destroy(kms);
|
||||
|
||||
|
@ -490,9 +458,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
|
|||
priv->wq = alloc_ordered_workqueue("msm", 0);
|
||||
|
||||
INIT_LIST_HEAD(&priv->inactive_list);
|
||||
INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
|
||||
kthread_init_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
|
||||
spin_lock_init(&priv->vblank_ctrl.lock);
|
||||
|
||||
drm_mode_config_init(ddev);
|
||||
|
||||
|
@ -554,27 +519,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
|
|||
*/
|
||||
param.sched_priority = 16;
|
||||
for (i = 0; i < priv->num_crtcs; i++) {
|
||||
|
||||
/* initialize display thread */
|
||||
priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id;
|
||||
kthread_init_worker(&priv->disp_thread[i].worker);
|
||||
priv->disp_thread[i].dev = ddev;
|
||||
priv->disp_thread[i].thread =
|
||||
kthread_run(kthread_worker_fn,
|
||||
&priv->disp_thread[i].worker,
|
||||
"crtc_commit:%d", priv->disp_thread[i].crtc_id);
|
||||
if (IS_ERR(priv->disp_thread[i].thread)) {
|
||||
DRM_DEV_ERROR(dev, "failed to create crtc_commit kthread\n");
|
||||
priv->disp_thread[i].thread = NULL;
|
||||
goto err_msm_uninit;
|
||||
}
|
||||
|
||||
ret = sched_setscheduler(priv->disp_thread[i].thread,
|
||||
SCHED_FIFO, ¶m);
|
||||
if (ret)
|
||||
dev_warn(dev, "disp_thread set priority failed: %d\n",
|
||||
ret);
|
||||
|
||||
/* initialize event thread */
|
||||
priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id;
|
||||
kthread_init_worker(&priv->event_thread[i].worker);
|
||||
|
@ -589,13 +533,6 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
|
|||
goto err_msm_uninit;
|
||||
}
|
||||
|
||||
/**
|
||||
* event thread should also run at same priority as disp_thread
|
||||
* because it is handling frame_done events. A lower priority
|
||||
* event thread and higher priority disp_thread can causes
|
||||
* frame_pending counters beyond 2. This can lead to commit
|
||||
* failure at crtc commit level.
|
||||
*/
|
||||
ret = sched_setscheduler(priv->event_thread[i].thread,
|
||||
SCHED_FIFO, ¶m);
|
||||
if (ret)
|
||||
|
@ -914,8 +851,12 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
|
|||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = copy_from_user(msm_obj->name,
|
||||
u64_to_user_ptr(args->value), args->len);
|
||||
if (copy_from_user(msm_obj->name, u64_to_user_ptr(args->value),
|
||||
args->len)) {
|
||||
msm_obj->name[0] = '\0';
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
msm_obj->name[args->len] = '\0';
|
||||
for (i = 0; i < args->len; i++) {
|
||||
if (!isprint(msm_obj->name[i])) {
|
||||
|
@ -931,8 +872,9 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
|
|||
}
|
||||
args->len = strlen(msm_obj->name);
|
||||
if (args->value) {
|
||||
ret = copy_to_user(u64_to_user_ptr(args->value),
|
||||
msm_obj->name, args->len);
|
||||
if (copy_to_user(u64_to_user_ptr(args->value),
|
||||
msm_obj->name, args->len))
|
||||
ret = -EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -77,12 +77,6 @@ enum msm_mdp_plane_property {
|
|||
PLANE_PROP_MAX_NUM
|
||||
};
|
||||
|
||||
struct msm_vblank_ctrl {
|
||||
struct kthread_work work;
|
||||
struct list_head event_list;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define MSM_GPU_MAX_RINGS 4
|
||||
#define MAX_H_TILES_PER_DISPLAY 2
|
||||
|
||||
|
@ -126,7 +120,7 @@ struct msm_display_topology {
|
|||
|
||||
/**
|
||||
* struct msm_display_info - defines display properties
|
||||
* @intf_type: DRM_MODE_CONNECTOR_ display type
|
||||
* @intf_type: DRM_MODE_ENCODER_ type
|
||||
* @capabilities: Bitmask of display flags
|
||||
* @num_of_h_tiles: Number of horizontal tiles in case of split interface
|
||||
* @h_tile_instance: Controller instance used per tile. Number of elements is
|
||||
|
@ -199,7 +193,6 @@ struct msm_drm_private {
|
|||
unsigned int num_crtcs;
|
||||
struct drm_crtc *crtcs[MAX_CRTCS];
|
||||
|
||||
struct msm_drm_thread disp_thread[MAX_CRTCS];
|
||||
struct msm_drm_thread event_thread[MAX_CRTCS];
|
||||
|
||||
unsigned int num_encoders;
|
||||
|
@ -228,7 +221,6 @@ struct msm_drm_private {
|
|||
struct notifier_block vmap_notifier;
|
||||
struct shrinker shrinker;
|
||||
|
||||
struct msm_vblank_ctrl vblank_ctrl;
|
||||
struct drm_atomic_state *pm_state;
|
||||
};
|
||||
|
||||
|
|
|
@ -560,6 +560,8 @@
|
|||
# define DP_TEST_LINK_EDID_READ (1 << 2)
|
||||
# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */
|
||||
# define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */
|
||||
# define DP_TEST_LINK_AUDIO_PATTERN (1 << 5) /* DPCD >= 1.2 */
|
||||
# define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6) /* DPCD >= 1.2 */
|
||||
|
||||
#define DP_TEST_LINK_RATE 0x219
|
||||
# define DP_LINK_RATE_162 (0x6)
|
||||
|
@ -608,6 +610,7 @@
|
|||
# define DP_COLOR_FORMAT_RGB (0 << 1)
|
||||
# define DP_COLOR_FORMAT_YCbCr422 (1 << 1)
|
||||
# define DP_COLOR_FORMAT_YCbCr444 (2 << 1)
|
||||
# define DP_TEST_DYNAMIC_RANGE_VESA (0 << 3)
|
||||
# define DP_TEST_DYNAMIC_RANGE_CEA (1 << 3)
|
||||
# define DP_TEST_YCBCR_COEFFICIENTS (1 << 4)
|
||||
# define DP_YCBCR_COEFFICIENTS_ITU601 (0 << 4)
|
||||
|
@ -657,6 +660,16 @@
|
|||
|
||||
#define DP_TEST_SINK 0x270
|
||||
# define DP_TEST_SINK_START (1 << 0)
|
||||
#define DP_TEST_AUDIO_MODE 0x271
|
||||
#define DP_TEST_AUDIO_PATTERN_TYPE 0x272
|
||||
#define DP_TEST_AUDIO_PERIOD_CH1 0x273
|
||||
#define DP_TEST_AUDIO_PERIOD_CH2 0x274
|
||||
#define DP_TEST_AUDIO_PERIOD_CH3 0x275
|
||||
#define DP_TEST_AUDIO_PERIOD_CH4 0x276
|
||||
#define DP_TEST_AUDIO_PERIOD_CH5 0x277
|
||||
#define DP_TEST_AUDIO_PERIOD_CH6 0x278
|
||||
#define DP_TEST_AUDIO_PERIOD_CH7 0x279
|
||||
#define DP_TEST_AUDIO_PERIOD_CH8 0x27A
|
||||
|
||||
#define DP_FEC_STATUS 0x280 /* 1.4 */
|
||||
# define DP_FEC_DECODE_EN_DETECTED (1 << 0)
|
||||
|
|
Loading…
Reference in New Issue