Merge tag 'drm-msm-next-2024-03-07' of https://gitlab.freedesktop.org/drm/msm into drm-next
Late updates for v6.9, the main part is CDM (YUV over DP) which was waiting for drm-misc-next-2024-02-29. DPU: - Add support for YUV420 over DP - Patchset to ease debugging of vblank timeouts - Small cleanup Signed-off-by: Dave Airlie <airlied@redhat.com> From: Rob Clark <robdclark@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGvedk6OCOZ-NNtGf_pNiGuK9uvWj1MCDZLX9Jo2nHS=Zg@mail.gmail.com
This commit is contained in:
commit
b9511c6d27
@ -127,7 +127,8 @@ msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
|
||||
dp/dp_drm.o \
|
||||
dp/dp_link.o \
|
||||
dp/dp_panel.o \
|
||||
dp/dp_audio.o
|
||||
dp/dp_audio.o \
|
||||
dp/dp_utils.o
|
||||
|
||||
msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
|
||||
|
||||
|
@ -126,6 +126,8 @@ enum dpu_enc_rc_states {
|
||||
* @base: drm_encoder base class for registration with DRM
|
||||
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
|
||||
* @enabled: True if the encoder is active, protected by enc_lock
|
||||
* @commit_done_timedout: True if there has been a timeout on commit after
|
||||
* enabling the encoder.
|
||||
* @num_phys_encs: Actual number of physical encoders contained.
|
||||
* @phys_encs: Container of physical encoders managed.
|
||||
* @cur_master: Pointer to the current master in this mode. Optimization
|
||||
@ -172,6 +174,7 @@ struct dpu_encoder_virt {
|
||||
spinlock_t enc_spinlock;
|
||||
|
||||
bool enabled;
|
||||
bool commit_done_timedout;
|
||||
|
||||
unsigned int num_phys_encs;
|
||||
struct dpu_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||
@ -218,12 +221,59 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = {
|
||||
15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10
|
||||
};
|
||||
|
||||
u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct drm_encoder *drm_enc;
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
struct drm_display_info *info;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
drm_enc = phys_enc->parent;
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
info = &dpu_enc->connector->display_info;
|
||||
mode = &phys_enc->cached_mode;
|
||||
|
||||
if (drm_mode_is_420_only(info, mode))
|
||||
return DRM_FORMAT_YUV420;
|
||||
|
||||
return DRM_FORMAT_RGB888;
|
||||
}
|
||||
|
||||
bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct drm_encoder *drm_enc;
|
||||
struct dpu_encoder_virt *dpu_enc;
|
||||
struct msm_display_info *disp_info;
|
||||
struct msm_drm_private *priv;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
drm_enc = phys_enc->parent;
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
disp_info = &dpu_enc->disp_info;
|
||||
priv = drm_enc->dev->dev_private;
|
||||
mode = &phys_enc->cached_mode;
|
||||
|
||||
return phys_enc->hw_intf->cap->type == INTF_DP &&
|
||||
msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode);
|
||||
}
|
||||
|
||||
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc)
|
||||
{
|
||||
const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
const struct dpu_encoder_virt *dpu_enc;
|
||||
struct msm_drm_private *priv = drm_enc->dev->dev_private;
|
||||
const struct msm_display_info *disp_info;
|
||||
int index;
|
||||
|
||||
return dpu_enc->wide_bus_en;
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
disp_info = &dpu_enc->disp_info;
|
||||
index = disp_info->h_tile_instance[0];
|
||||
|
||||
if (disp_info->intf_type == INTF_DP)
|
||||
return msm_dp_wide_bus_available(priv->dp[index]);
|
||||
else if (disp_info->intf_type == INTF_DSI)
|
||||
return msm_dsi_wide_bus_enabled(priv->dsi[index]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc)
|
||||
@ -588,6 +638,7 @@ static int dpu_encoder_virt_atomic_check(
|
||||
struct dpu_kms *dpu_kms;
|
||||
struct drm_display_mode *adj_mode;
|
||||
struct msm_display_topology topology;
|
||||
struct msm_display_info *disp_info;
|
||||
struct dpu_global_state *global_state;
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_dsc_config *dsc;
|
||||
@ -603,6 +654,7 @@ static int dpu_encoder_virt_atomic_check(
|
||||
DPU_DEBUG_ENC(dpu_enc, "\n");
|
||||
|
||||
priv = drm_enc->dev->dev_private;
|
||||
disp_info = &dpu_enc->disp_info;
|
||||
dpu_kms = to_dpu_kms(priv->kms);
|
||||
adj_mode = &crtc_state->adjusted_mode;
|
||||
global_state = dpu_kms_get_global_state(crtc_state->state);
|
||||
@ -616,21 +668,24 @@ static int dpu_encoder_virt_atomic_check(
|
||||
topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, crtc_state, dsc);
|
||||
|
||||
/*
|
||||
* Use CDM only for writeback at the moment as other interfaces cannot handle it.
|
||||
* if writeback itself cannot handle cdm for some reason it will fail in its atomic_check()
|
||||
* Use CDM only for writeback or DP at the moment as other interfaces cannot handle it.
|
||||
* If writeback itself cannot handle cdm for some reason it will fail in its atomic_check()
|
||||
* earlier.
|
||||
*/
|
||||
if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) {
|
||||
if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) {
|
||||
fb = conn_state->writeback_job->fb;
|
||||
|
||||
if (fb && DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb))))
|
||||
topology.needs_cdm = true;
|
||||
if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
|
||||
crtc_state->mode_changed = true;
|
||||
else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
|
||||
crtc_state->mode_changed = true;
|
||||
} else if (disp_info->intf_type == INTF_DP) {
|
||||
if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode))
|
||||
topology.needs_cdm = true;
|
||||
}
|
||||
|
||||
if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm)
|
||||
crtc_state->mode_changed = true;
|
||||
else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm)
|
||||
crtc_state->mode_changed = true;
|
||||
/*
|
||||
* Release and Allocate resources on every modeset
|
||||
* Dont allocate when active is false.
|
||||
@ -1102,7 +1157,8 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
|
||||
|
||||
dpu_enc->dsc_mask = dsc_mask;
|
||||
|
||||
if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) {
|
||||
if ((dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) ||
|
||||
dpu_enc->disp_info.intf_type == INTF_DP) {
|
||||
struct dpu_hw_blk *hw_cdm = NULL;
|
||||
|
||||
dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
|
||||
@ -1209,26 +1265,20 @@ static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc,
|
||||
struct dpu_encoder_virt *dpu_enc = NULL;
|
||||
int ret = 0;
|
||||
struct drm_display_mode *cur_mode = NULL;
|
||||
struct msm_drm_private *priv = drm_enc->dev->dev_private;
|
||||
struct msm_display_info *disp_info;
|
||||
int index;
|
||||
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
disp_info = &dpu_enc->disp_info;
|
||||
index = disp_info->h_tile_instance[0];
|
||||
|
||||
dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc);
|
||||
|
||||
atomic_set(&dpu_enc->frame_done_timeout_cnt, 0);
|
||||
|
||||
if (disp_info->intf_type == INTF_DP)
|
||||
dpu_enc->wide_bus_en = msm_dp_wide_bus_available(priv->dp[index]);
|
||||
else if (disp_info->intf_type == INTF_DSI)
|
||||
dpu_enc->wide_bus_en = msm_dsi_wide_bus_enabled(priv->dsi[index]);
|
||||
|
||||
mutex_lock(&dpu_enc->enc_lock);
|
||||
|
||||
dpu_enc->commit_done_timedout = false;
|
||||
|
||||
cur_mode = &dpu_enc->base.crtc->state->adjusted_mode;
|
||||
|
||||
dpu_enc->wide_bus_en = dpu_encoder_is_widebus_enabled(drm_enc);
|
||||
|
||||
trace_dpu_enc_enable(DRMID(drm_enc), cur_mode->hdisplay,
|
||||
cur_mode->vdisplay);
|
||||
|
||||
@ -1282,7 +1332,7 @@ static void dpu_encoder_virt_atomic_disable(struct drm_encoder *drm_enc,
|
||||
trace_dpu_enc_disable(DRMID(drm_enc));
|
||||
|
||||
/* wait for idle */
|
||||
dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
|
||||
dpu_encoder_wait_for_tx_complete(drm_enc);
|
||||
|
||||
dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP);
|
||||
|
||||
@ -2133,6 +2183,84 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
|
||||
ctl->ops.clear_pending_flush(ctl);
|
||||
}
|
||||
|
||||
void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
|
||||
const struct dpu_format *dpu_fmt,
|
||||
u32 output_type)
|
||||
{
|
||||
struct dpu_hw_cdm *hw_cdm;
|
||||
struct dpu_hw_cdm_cfg *cdm_cfg;
|
||||
struct dpu_hw_pingpong *hw_pp;
|
||||
int ret;
|
||||
|
||||
if (!phys_enc)
|
||||
return;
|
||||
|
||||
cdm_cfg = &phys_enc->cdm_cfg;
|
||||
hw_pp = phys_enc->hw_pp;
|
||||
hw_cdm = phys_enc->hw_cdm;
|
||||
|
||||
if (!hw_cdm)
|
||||
return;
|
||||
|
||||
if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
|
||||
DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", DRMID(phys_enc->parent),
|
||||
dpu_fmt->base.pixel_format);
|
||||
if (hw_cdm->ops.bind_pingpong_blk)
|
||||
hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
|
||||
|
||||
cdm_cfg->output_width = phys_enc->cached_mode.hdisplay;
|
||||
cdm_cfg->output_height = phys_enc->cached_mode.vdisplay;
|
||||
cdm_cfg->output_fmt = dpu_fmt;
|
||||
cdm_cfg->output_type = output_type;
|
||||
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
|
||||
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
|
||||
cdm_cfg->csc_cfg = &dpu_csc10_rgb2yuv_601l;
|
||||
|
||||
/* enable 10 bit logic */
|
||||
switch (cdm_cfg->output_fmt->chroma_sample) {
|
||||
case DPU_CHROMA_RGB:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
case DPU_CHROMA_H2V1:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
case DPU_CHROMA_420:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
|
||||
break;
|
||||
case DPU_CHROMA_H1V2:
|
||||
default:
|
||||
DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
|
||||
DRMID(phys_enc->parent));
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
|
||||
DRMID(phys_enc->parent), cdm_cfg->output_width,
|
||||
cdm_cfg->output_height, cdm_cfg->output_fmt->base.pixel_format,
|
||||
cdm_cfg->output_type, cdm_cfg->output_bit_depth,
|
||||
cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
|
||||
|
||||
if (hw_cdm->ops.enable) {
|
||||
cdm_cfg->pp_id = hw_pp->idx;
|
||||
ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
|
||||
if (ret < 0) {
|
||||
DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
|
||||
DRMID(phys_enc->parent), ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int _dpu_encoder_status_show(struct seq_file *s, void *data)
|
||||
{
|
||||
@ -2402,10 +2530,18 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
|
||||
return &dpu_enc->base;
|
||||
}
|
||||
|
||||
int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc,
|
||||
enum msm_event_wait event)
|
||||
/**
|
||||
* dpu_encoder_wait_for_commit_done() - Wait for encoder to flush pending state
|
||||
* @drm_enc: encoder pointer
|
||||
*
|
||||
* Wait for hardware to have flushed the current pending changes to hardware at
|
||||
* a vblank or CTL_START. Physical encoders will map this differently depending
|
||||
* on the type: vid mode -> vsync_irq, cmd mode -> CTL_START.
|
||||
*
|
||||
* Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
|
||||
*/
|
||||
int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_enc)
|
||||
{
|
||||
int (*fn_wait)(struct dpu_encoder_phys *phys_enc) = NULL;
|
||||
struct dpu_encoder_virt *dpu_enc = NULL;
|
||||
int i, ret = 0;
|
||||
|
||||
@ -2419,23 +2555,51 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc,
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
|
||||
switch (event) {
|
||||
case MSM_ENC_COMMIT_DONE:
|
||||
fn_wait = phys->ops.wait_for_commit_done;
|
||||
break;
|
||||
case MSM_ENC_TX_COMPLETE:
|
||||
fn_wait = phys->ops.wait_for_tx_complete;
|
||||
break;
|
||||
default:
|
||||
DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n",
|
||||
event);
|
||||
return -EINVAL;
|
||||
if (phys->ops.wait_for_commit_done) {
|
||||
DPU_ATRACE_BEGIN("wait_for_commit_done");
|
||||
ret = phys->ops.wait_for_commit_done(phys);
|
||||
DPU_ATRACE_END("wait_for_commit_done");
|
||||
if (ret == -ETIMEDOUT && !dpu_enc->commit_done_timedout) {
|
||||
dpu_enc->commit_done_timedout = true;
|
||||
msm_disp_snapshot_state(drm_enc->dev);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_wait) {
|
||||
DPU_ATRACE_BEGIN("wait_for_completion_event");
|
||||
ret = fn_wait(phys);
|
||||
DPU_ATRACE_END("wait_for_completion_event");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_encoder_wait_for_tx_complete() - Wait for encoder to transfer pixels to panel
|
||||
* @drm_enc: encoder pointer
|
||||
*
|
||||
* Wait for the hardware to transfer all the pixels to the panel. Physical
|
||||
* encoders will map this differently depending on the type: vid mode -> vsync_irq,
|
||||
* cmd mode -> pp_done.
|
||||
*
|
||||
* Return: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
|
||||
*/
|
||||
int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct dpu_encoder_virt *dpu_enc = NULL;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!drm_enc) {
|
||||
DPU_ERROR("invalid encoder\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
dpu_enc = to_dpu_encoder_virt(drm_enc);
|
||||
DPU_DEBUG_ENC(dpu_enc, "\n");
|
||||
|
||||
for (i = 0; i < dpu_enc->num_phys_encs; i++) {
|
||||
struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
|
||||
|
||||
if (phys->ops.wait_for_tx_complete) {
|
||||
DPU_ATRACE_BEGIN("wait_for_tx_complete");
|
||||
ret = phys->ops.wait_for_tx_complete(phys);
|
||||
DPU_ATRACE_END("wait_for_tx_complete");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -93,25 +93,9 @@ void dpu_encoder_kickoff(struct drm_encoder *encoder);
|
||||
*/
|
||||
int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time);
|
||||
|
||||
/**
|
||||
* dpu_encoder_wait_for_event - Waits for encoder events
|
||||
* @encoder: encoder pointer
|
||||
* @event: event to wait for
|
||||
* MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending
|
||||
* frames to hardware at a vblank or ctl_start
|
||||
* Encoders will map this differently depending on the
|
||||
* panel type.
|
||||
* vid mode -> vsync_irq
|
||||
* cmd mode -> ctl_start
|
||||
* MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to
|
||||
* the panel. Encoders will map this differently
|
||||
* depending on the panel type.
|
||||
* vid mode -> vsync_irq
|
||||
* cmd mode -> pp_done
|
||||
* Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise
|
||||
*/
|
||||
int dpu_encoder_wait_for_event(struct drm_encoder *drm_encoder,
|
||||
enum msm_event_wait event);
|
||||
int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder);
|
||||
|
||||
int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_encoder);
|
||||
|
||||
/*
|
||||
* dpu_encoder_get_intf_mode - get interface mode of the given encoder
|
||||
@ -156,6 +140,10 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc);
|
||||
*/
|
||||
int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled
|
||||
* @drm_enc: Pointer to previously created drm encoder structure
|
||||
*/
|
||||
bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
|
||||
|
||||
/**
|
||||
|
@ -147,6 +147,7 @@ enum dpu_intr_idx {
|
||||
* @hw_wb: Hardware interface to the wb registers
|
||||
* @hw_cdm: Hardware interface to the CDM registers
|
||||
* @dpu_kms: Pointer to the dpu_kms top level
|
||||
* @cdm_cfg: CDM block config needed to store WB/DP block's CDM configuration
|
||||
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
|
||||
* @vblank_ctl_lock: Vblank ctl mutex lock to protect vblank_refcount
|
||||
* @enabled: Whether the encoder has enabled and running a mode
|
||||
@ -177,6 +178,7 @@ struct dpu_encoder_phys {
|
||||
struct dpu_hw_wb *hw_wb;
|
||||
struct dpu_hw_cdm *hw_cdm;
|
||||
struct dpu_kms *dpu_kms;
|
||||
struct dpu_hw_cdm_cfg cdm_cfg;
|
||||
struct drm_display_mode cached_mode;
|
||||
struct mutex vblank_ctl_lock;
|
||||
enum dpu_enc_split_role split_role;
|
||||
@ -206,7 +208,6 @@ static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
|
||||
* @wbirq_refcount: Reference count of writeback interrupt
|
||||
* @wb_done_timeout_cnt: number of wb done irq timeout errors
|
||||
* @wb_cfg: writeback block config to store fb related details
|
||||
* @cdm_cfg: cdm block config needed to store writeback block's CDM configuration
|
||||
* @wb_conn: backpointer to writeback connector
|
||||
* @wb_job: backpointer to current writeback job
|
||||
* @dest: dpu buffer layout for current writeback output buffer
|
||||
@ -216,7 +217,6 @@ struct dpu_encoder_phys_wb {
|
||||
atomic_t wbirq_refcount;
|
||||
int wb_done_timeout_cnt;
|
||||
struct dpu_hw_wb_cfg wb_cfg;
|
||||
struct dpu_hw_cdm_cfg cdm_cfg;
|
||||
struct drm_writeback_connector *wb_conn;
|
||||
struct drm_writeback_job *wb_job;
|
||||
struct dpu_hw_fmt_layout dest;
|
||||
@ -334,6 +334,19 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
|
||||
*/
|
||||
unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_get_drm_fmt - return DRM fourcc format
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
*/
|
||||
u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_needs_periph_flush - return true if physical encoder requires
|
||||
* peripheral flush
|
||||
* @phys_enc: Pointer to physical encoder structure
|
||||
*/
|
||||
bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_split_config - split display configuration helper function
|
||||
* This helper function may be used by physical encoders to configure
|
||||
@ -374,6 +387,15 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
|
||||
*/
|
||||
void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
|
||||
* @phys_enc: Pointer to physical encoder
|
||||
* @output_type: HDMI/WB
|
||||
*/
|
||||
void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc,
|
||||
const struct dpu_format *dpu_fmt,
|
||||
u32 output_type);
|
||||
|
||||
/**
|
||||
* dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception
|
||||
* @drm_enc: Pointer to drm encoder structure
|
||||
|
@ -236,7 +236,7 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
|
||||
struct drm_display_mode mode;
|
||||
struct dpu_hw_intf_timing_params timing_params = { 0 };
|
||||
const struct dpu_format *fmt = NULL;
|
||||
u32 fmt_fourcc = DRM_FORMAT_RGB888;
|
||||
u32 fmt_fourcc;
|
||||
unsigned long lock_flags;
|
||||
struct dpu_hw_intf_cfg intf_cfg = { 0 };
|
||||
|
||||
@ -255,17 +255,21 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
|
||||
DPU_DEBUG_VIDENC(phys_enc, "enabling mode:\n");
|
||||
drm_mode_debug_printmodeline(&mode);
|
||||
|
||||
if (phys_enc->split_role != ENC_ROLE_SOLO) {
|
||||
fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
|
||||
|
||||
if (phys_enc->split_role != ENC_ROLE_SOLO || fmt_fourcc == DRM_FORMAT_YUV420) {
|
||||
mode.hdisplay >>= 1;
|
||||
mode.htotal >>= 1;
|
||||
mode.hsync_start >>= 1;
|
||||
mode.hsync_end >>= 1;
|
||||
mode.hskew >>= 1;
|
||||
|
||||
DPU_DEBUG_VIDENC(phys_enc,
|
||||
"split_role %d, halve horizontal %d %d %d %d\n",
|
||||
"split_role %d, halve horizontal %d %d %d %d %d\n",
|
||||
phys_enc->split_role,
|
||||
mode.hdisplay, mode.htotal,
|
||||
mode.hsync_start, mode.hsync_end);
|
||||
mode.hsync_start, mode.hsync_end,
|
||||
mode.hskew);
|
||||
}
|
||||
|
||||
drm_mode_to_intf_timing_params(phys_enc, &mode, &timing_params);
|
||||
@ -273,6 +277,8 @@ static void dpu_encoder_phys_vid_setup_timing_engine(
|
||||
fmt = dpu_get_dpu_format(fmt_fourcc);
|
||||
DPU_DEBUG_VIDENC(phys_enc, "fmt_fourcc 0x%X\n", fmt_fourcc);
|
||||
|
||||
if (phys_enc->hw_cdm)
|
||||
intf_cfg.cdm = phys_enc->hw_cdm->idx;
|
||||
intf_cfg.intf = phys_enc->hw_intf->idx;
|
||||
intf_cfg.intf_mode_sel = DPU_CTL_MODE_SEL_VID;
|
||||
intf_cfg.stream_sel = 0; /* Don't care value for video mode */
|
||||
@ -403,8 +409,12 @@ end:
|
||||
static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct dpu_hw_ctl *ctl;
|
||||
const struct dpu_format *fmt;
|
||||
u32 fmt_fourcc;
|
||||
|
||||
ctl = phys_enc->hw_ctl;
|
||||
fmt_fourcc = dpu_encoder_get_drm_fmt(phys_enc);
|
||||
fmt = dpu_get_dpu_format(fmt_fourcc);
|
||||
|
||||
DPU_DEBUG_VIDENC(phys_enc, "\n");
|
||||
|
||||
@ -413,6 +423,8 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
|
||||
|
||||
dpu_encoder_helper_split_config(phys_enc, phys_enc->hw_intf->idx);
|
||||
|
||||
dpu_encoder_helper_phys_setup_cdm(phys_enc, fmt, CDM_CDWN_OUTPUT_HDMI);
|
||||
|
||||
dpu_encoder_phys_vid_setup_timing_engine(phys_enc);
|
||||
|
||||
/*
|
||||
@ -428,6 +440,16 @@ static void dpu_encoder_phys_vid_enable(struct dpu_encoder_phys *phys_enc)
|
||||
if (ctl->ops.update_pending_flush_merge_3d && phys_enc->hw_pp->merge_3d)
|
||||
ctl->ops.update_pending_flush_merge_3d(ctl, phys_enc->hw_pp->merge_3d->idx);
|
||||
|
||||
if (ctl->ops.update_pending_flush_cdm && phys_enc->hw_cdm)
|
||||
ctl->ops.update_pending_flush_cdm(ctl, phys_enc->hw_cdm->idx);
|
||||
|
||||
/*
|
||||
* Peripheral flush must be updated whenever flushing SDP packets is needed.
|
||||
* SDP packets are required for any YUV format (YUV420, YUV422, YUV444).
|
||||
*/
|
||||
if (ctl->ops.update_pending_flush_periph && dpu_encoder_needs_periph_flush(phys_enc))
|
||||
ctl->ops.update_pending_flush_periph(ctl, phys_enc->hw_intf->idx);
|
||||
|
||||
skip_flush:
|
||||
DPU_DEBUG_VIDENC(phys_enc,
|
||||
"update pending flush ctl %d intf %d\n",
|
||||
@ -480,7 +502,7 @@ static int dpu_encoder_phys_vid_wait_for_commit_done(
|
||||
(hw_ctl->ops.get_flush_register(hw_ctl) == 0),
|
||||
msecs_to_jiffies(50));
|
||||
if (ret <= 0) {
|
||||
DPU_ERROR("vblank timeout\n");
|
||||
DPU_ERROR("vblank timeout: %x\n", hw_ctl->ops.get_flush_register(hw_ctl));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -264,96 +264,6 @@ static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block
|
||||
* This API does not handle DPU_CHROMA_H1V2.
|
||||
* @phys_enc:Pointer to physical encoder
|
||||
*/
|
||||
static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc)
|
||||
{
|
||||
struct dpu_hw_cdm *hw_cdm;
|
||||
struct dpu_hw_cdm_cfg *cdm_cfg;
|
||||
struct dpu_hw_pingpong *hw_pp;
|
||||
struct dpu_encoder_phys_wb *wb_enc;
|
||||
const struct msm_format *format;
|
||||
const struct dpu_format *dpu_fmt;
|
||||
struct drm_writeback_job *wb_job;
|
||||
int ret;
|
||||
|
||||
if (!phys_enc)
|
||||
return;
|
||||
|
||||
wb_enc = to_dpu_encoder_phys_wb(phys_enc);
|
||||
cdm_cfg = &wb_enc->cdm_cfg;
|
||||
hw_pp = phys_enc->hw_pp;
|
||||
hw_cdm = phys_enc->hw_cdm;
|
||||
wb_job = wb_enc->wb_job;
|
||||
|
||||
format = msm_framebuffer_format(wb_enc->wb_job->fb);
|
||||
dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, wb_job->fb->modifier);
|
||||
|
||||
if (!hw_cdm)
|
||||
return;
|
||||
|
||||
if (!DPU_FORMAT_IS_YUV(dpu_fmt)) {
|
||||
DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", DRMID(phys_enc->parent),
|
||||
dpu_fmt->base.pixel_format);
|
||||
if (hw_cdm->ops.bind_pingpong_blk)
|
||||
hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg));
|
||||
|
||||
cdm_cfg->output_width = wb_job->fb->width;
|
||||
cdm_cfg->output_height = wb_job->fb->height;
|
||||
cdm_cfg->output_fmt = dpu_fmt;
|
||||
cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB;
|
||||
cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ?
|
||||
CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT;
|
||||
cdm_cfg->csc_cfg = &dpu_csc10_rgb2yuv_601l;
|
||||
|
||||
/* enable 10 bit logic */
|
||||
switch (cdm_cfg->output_fmt->chroma_sample) {
|
||||
case DPU_CHROMA_RGB:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
case DPU_CHROMA_H2V1:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
case DPU_CHROMA_420:
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE;
|
||||
break;
|
||||
case DPU_CHROMA_H1V2:
|
||||
default:
|
||||
DPU_ERROR("[enc:%d] unsupported chroma sampling type\n",
|
||||
DRMID(phys_enc->parent));
|
||||
cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE;
|
||||
cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n",
|
||||
DRMID(phys_enc->parent), cdm_cfg->output_width,
|
||||
cdm_cfg->output_height, cdm_cfg->output_fmt->base.pixel_format,
|
||||
cdm_cfg->output_type, cdm_cfg->output_bit_depth,
|
||||
cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type);
|
||||
|
||||
if (hw_cdm->ops.enable) {
|
||||
cdm_cfg->pp_id = hw_pp->idx;
|
||||
ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg);
|
||||
if (ret < 0) {
|
||||
DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n",
|
||||
DRMID(phys_enc->parent), ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* _dpu_encoder_phys_wb_update_flush - flush hardware update
|
||||
* @phys_enc: Pointer to physical encoder
|
||||
@ -409,6 +319,14 @@ static void dpu_encoder_phys_wb_setup(
|
||||
struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
|
||||
struct drm_display_mode mode = phys_enc->cached_mode;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
|
||||
struct drm_writeback_job *wb_job;
|
||||
const struct msm_format *format;
|
||||
const struct dpu_format *dpu_fmt;
|
||||
|
||||
wb_job = wb_enc->wb_job;
|
||||
format = msm_framebuffer_format(wb_enc->wb_job->fb);
|
||||
dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, wb_job->fb->modifier);
|
||||
|
||||
DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n",
|
||||
hw_wb->idx - WB_0, mode.name,
|
||||
@ -422,7 +340,7 @@ static void dpu_encoder_phys_wb_setup(
|
||||
|
||||
dpu_encoder_phys_wb_setup_fb(phys_enc, fb);
|
||||
|
||||
dpu_encoder_helper_phys_setup_cdm(phys_enc);
|
||||
dpu_encoder_helper_phys_setup_cdm(phys_enc, dpu_fmt, CDM_CDWN_OUTPUT_WB);
|
||||
|
||||
dpu_encoder_phys_wb_setup_ctl(phys_enc);
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm)
|
||||
dpu_hw_cdm_setup_cdwn(ctx, cdm);
|
||||
|
||||
if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) {
|
||||
if (fmt->chroma_sample != DPU_CHROMA_H1V2)
|
||||
if (fmt->chroma_sample == DPU_CHROMA_H1V2)
|
||||
return -EINVAL; /*unsupported format */
|
||||
opmode = CDM_HDMI_PACK_OP_MODE_EN;
|
||||
opmode |= (fmt->chroma_sample << 1);
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define CTL_WB_FLUSH 0x108
|
||||
#define CTL_INTF_FLUSH 0x110
|
||||
#define CTL_CDM_FLUSH 0x114
|
||||
#define CTL_PERIPH_FLUSH 0x128
|
||||
#define CTL_INTF_MASTER 0x134
|
||||
#define CTL_DSPP_n_FLUSH(n) ((0x13C) + ((n) * 4))
|
||||
|
||||
@ -49,6 +50,7 @@
|
||||
#define MERGE_3D_IDX 23
|
||||
#define DSC_IDX 22
|
||||
#define CDM_IDX 26
|
||||
#define PERIPH_IDX 30
|
||||
#define INTF_IDX 31
|
||||
#define WB_IDX 16
|
||||
#define DSPP_IDX 29 /* From DPU hw rev 7.x.x */
|
||||
@ -151,6 +153,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
|
||||
ctx->pending_dspp_flush_mask[dspp - DSPP_0]);
|
||||
}
|
||||
|
||||
if (ctx->pending_flush_mask & BIT(PERIPH_IDX))
|
||||
DPU_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH,
|
||||
ctx->pending_periph_flush_mask);
|
||||
|
||||
if (ctx->pending_flush_mask & BIT(DSC_IDX))
|
||||
DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH,
|
||||
ctx->pending_dsc_flush_mask);
|
||||
@ -311,6 +317,13 @@ static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
|
||||
ctx->pending_flush_mask |= BIT(INTF_IDX);
|
||||
}
|
||||
|
||||
static void dpu_hw_ctl_update_pending_flush_periph_v1(struct dpu_hw_ctl *ctx,
|
||||
enum dpu_intf intf)
|
||||
{
|
||||
ctx->pending_periph_flush_mask |= BIT(intf - INTF_0);
|
||||
ctx->pending_flush_mask |= BIT(PERIPH_IDX);
|
||||
}
|
||||
|
||||
static void dpu_hw_ctl_update_pending_flush_merge_3d_v1(struct dpu_hw_ctl *ctx,
|
||||
enum dpu_merge_3d merge_3d)
|
||||
{
|
||||
@ -680,6 +693,10 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
|
||||
ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
|
||||
ops->update_pending_flush_intf =
|
||||
dpu_hw_ctl_update_pending_flush_intf_v1;
|
||||
|
||||
ops->update_pending_flush_periph =
|
||||
dpu_hw_ctl_update_pending_flush_periph_v1;
|
||||
|
||||
ops->update_pending_flush_merge_3d =
|
||||
dpu_hw_ctl_update_pending_flush_merge_3d_v1;
|
||||
ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
|
||||
|
@ -122,6 +122,15 @@ struct dpu_hw_ctl_ops {
|
||||
void (*update_pending_flush_intf)(struct dpu_hw_ctl *ctx,
|
||||
enum dpu_intf blk);
|
||||
|
||||
/**
|
||||
* OR in the given flushbits to the cached pending_(periph_)flush_mask
|
||||
* No effect on hardware
|
||||
* @ctx : ctl path ctx pointer
|
||||
* @blk : interface block index
|
||||
*/
|
||||
void (*update_pending_flush_periph)(struct dpu_hw_ctl *ctx,
|
||||
enum dpu_intf blk);
|
||||
|
||||
/**
|
||||
* OR in the given flushbits to the cached pending_(merge_3d_)flush_mask
|
||||
* No effect on hardware
|
||||
@ -264,6 +273,7 @@ struct dpu_hw_ctl {
|
||||
u32 pending_flush_mask;
|
||||
u32 pending_intf_flush_mask;
|
||||
u32 pending_wb_flush_mask;
|
||||
u32 pending_periph_flush_mask;
|
||||
u32 pending_merge_3d_flush_mask;
|
||||
u32 pending_dspp_flush_mask[DSPP_MAX - DSPP_0];
|
||||
u32 pending_dsc_flush_mask;
|
||||
|
@ -476,7 +476,7 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms,
|
||||
* mode panels. This may be a no-op for command mode panels.
|
||||
*/
|
||||
trace_dpu_kms_wait_for_commit_done(DRMID(crtc));
|
||||
ret = dpu_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE);
|
||||
ret = dpu_encoder_wait_for_commit_done(encoder);
|
||||
if (ret && ret != -EWOULDBLOCK) {
|
||||
DPU_ERROR("wait for commit done returned %d\n", ret);
|
||||
break;
|
||||
@ -563,6 +563,7 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
|
||||
{
|
||||
struct drm_encoder *encoder = NULL;
|
||||
struct msm_display_info info;
|
||||
bool yuv_supported;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
@ -581,7 +582,8 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
|
||||
return PTR_ERR(encoder);
|
||||
}
|
||||
|
||||
rc = msm_dp_modeset_init(priv->dp[i], dev, encoder);
|
||||
yuv_supported = !!dpu_kms->catalog->cdm;
|
||||
rc = msm_dp_modeset_init(priv->dp[i], dev, encoder, yuv_supported);
|
||||
if (rc) {
|
||||
DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc);
|
||||
return rc;
|
||||
|
@ -15,13 +15,7 @@
|
||||
#include "dp_audio.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_display.h"
|
||||
|
||||
#define HEADER_BYTE_2_BIT 0
|
||||
#define PARITY_BYTE_2_BIT 8
|
||||
#define HEADER_BYTE_1_BIT 16
|
||||
#define PARITY_BYTE_1_BIT 24
|
||||
#define HEADER_BYTE_3_BIT 16
|
||||
#define PARITY_BYTE_3_BIT 24
|
||||
#include "dp_utils.h"
|
||||
|
||||
struct dp_audio_private {
|
||||
struct platform_device *audio_pdev;
|
||||
@ -36,71 +30,6 @@ struct dp_audio_private {
|
||||
struct dp_audio dp_audio;
|
||||
};
|
||||
|
||||
static u8 dp_audio_get_g0_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[3];
|
||||
g[1] = c[0] ^ c[3];
|
||||
g[2] = c[1];
|
||||
g[3] = c[2];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
static u8 dp_audio_get_g1_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[0] ^ c[3];
|
||||
g[1] = c[0] ^ c[1] ^ c[3];
|
||||
g[2] = c[1] ^ c[2];
|
||||
g[3] = c[2] ^ c[3];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
static u8 dp_audio_calculate_parity(u32 data)
|
||||
{
|
||||
u8 x0 = 0;
|
||||
u8 x1 = 0;
|
||||
u8 ci = 0;
|
||||
u8 iData = 0;
|
||||
u8 i = 0;
|
||||
u8 parity_byte;
|
||||
u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
|
||||
|
||||
for (i = 0; i < num_byte; i++) {
|
||||
iData = (data >> i*4) & 0xF;
|
||||
|
||||
ci = iData ^ x1;
|
||||
x1 = x0 ^ dp_audio_get_g1_value(ci);
|
||||
x0 = dp_audio_get_g0_value(ci);
|
||||
}
|
||||
|
||||
parity_byte = x1 | (x0 << 4);
|
||||
|
||||
return parity_byte;
|
||||
}
|
||||
|
||||
static u32 dp_audio_get_header(struct dp_catalog *catalog,
|
||||
enum dp_catalog_audio_sdp_type sdp,
|
||||
enum dp_catalog_audio_header_type header)
|
||||
@ -134,7 +63,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
new_value = 0x02;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -147,7 +76,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
|
||||
new_value = value;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -162,7 +91,7 @@ static void dp_audio_stream_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
|
||||
|
||||
new_value = audio->channels - 1;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -184,7 +113,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
new_value = 0x1;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -198,7 +127,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
new_value = 0x17;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -212,7 +141,7 @@ static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
|
||||
|
||||
new_value = (0x0 | (0x11 << 2));
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -233,7 +162,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
new_value = 0x84;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -247,7 +176,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
new_value = 0x1b;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -261,7 +190,7 @@ static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
|
||||
|
||||
new_value = (0x0 | (0x11 << 2));
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -282,7 +211,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
new_value = 0x05;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -296,7 +225,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
new_value = 0x0F;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -310,7 +239,7 @@ static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
|
||||
|
||||
new_value = 0x0;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -331,7 +260,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
new_value = 0x06;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
@ -345,7 +274,7 @@ static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
new_value = 0x0F;
|
||||
parity_byte = dp_audio_calculate_parity(new_value);
|
||||
parity_byte = dp_utils_calculate_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
drm_dbg_dp(audio->drm_dev,
|
||||
|
@ -450,9 +450,26 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog,
|
||||
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val);
|
||||
}
|
||||
|
||||
void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog)
|
||||
{
|
||||
u32 mainlink_ctrl, hw_revision;
|
||||
struct dp_catalog_private *catalog = container_of(dp_catalog,
|
||||
struct dp_catalog_private, dp_catalog);
|
||||
|
||||
mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
hw_revision = dp_catalog_hw_revision(dp_catalog);
|
||||
if (hw_revision >= DP_HW_VERSION_1_2)
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
|
||||
else
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
|
||||
|
||||
dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
|
||||
void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
|
||||
u32 rate, u32 stream_rate_khz,
|
||||
bool fixed_nvid)
|
||||
bool fixed_nvid, bool is_ycbcr_420)
|
||||
{
|
||||
u32 pixel_m, pixel_n;
|
||||
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
|
||||
@ -495,6 +512,9 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog,
|
||||
nvid = temp;
|
||||
}
|
||||
|
||||
if (is_ycbcr_420)
|
||||
mvid /= 2;
|
||||
|
||||
if (link_rate_hbr2 == rate)
|
||||
nvid *= 2;
|
||||
|
||||
@ -889,6 +909,99 @@ int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp)
|
||||
{
|
||||
struct dp_catalog_private *catalog;
|
||||
u32 header[2];
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
|
||||
|
||||
dp_utils_pack_sdp_header(&vsc_sdp->sdp_header, header);
|
||||
|
||||
dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]);
|
||||
dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]);
|
||||
|
||||
for (i = 0; i < sizeof(vsc_sdp->db); i += 4) {
|
||||
val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i + 2] << 16) |
|
||||
(vsc_sdp->db[i + 3] << 24));
|
||||
dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog)
|
||||
{
|
||||
struct dp_catalog_private *catalog;
|
||||
u32 hw_revision;
|
||||
|
||||
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
|
||||
|
||||
hw_revision = dp_catalog_hw_revision(dp_catalog);
|
||||
if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= DP_HW_VERSION_1_0) {
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01);
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp)
|
||||
{
|
||||
struct dp_catalog_private *catalog;
|
||||
u32 cfg, cfg2, misc;
|
||||
|
||||
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
|
||||
|
||||
cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
|
||||
cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
|
||||
misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
|
||||
|
||||
cfg |= GEN0_SDP_EN;
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
|
||||
|
||||
cfg2 |= GENERIC0_SDPSIZE_VALID;
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2);
|
||||
|
||||
dp_catalog_panel_send_vsc_sdp(dp_catalog, vsc_sdp);
|
||||
|
||||
/* indicates presence of VSC (BIT(6) of MISC1) */
|
||||
misc |= DP_MISC1_VSC_SDP;
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=1\n");
|
||||
|
||||
pr_debug("misc settings = 0x%x\n", misc);
|
||||
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc);
|
||||
|
||||
dp_catalog_panel_update_sdp(dp_catalog);
|
||||
}
|
||||
|
||||
void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog)
|
||||
{
|
||||
struct dp_catalog_private *catalog;
|
||||
u32 cfg, cfg2, misc;
|
||||
|
||||
catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog);
|
||||
|
||||
cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG);
|
||||
cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2);
|
||||
misc = dp_read_link(catalog, REG_DP_MISC1_MISC0);
|
||||
|
||||
cfg &= ~GEN0_SDP_EN;
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg);
|
||||
|
||||
cfg2 &= ~GENERIC0_SDPSIZE_VALID;
|
||||
dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2);
|
||||
|
||||
/* switch back to MSA */
|
||||
misc &= ~DP_MISC1_VSC_SDP;
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=0\n");
|
||||
|
||||
pr_debug("misc settings = 0x%x\n", misc);
|
||||
dp_write_link(catalog, REG_DP_MISC1_MISC0, misc);
|
||||
|
||||
dp_catalog_panel_update_sdp(dp_catalog);
|
||||
}
|
||||
|
||||
void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
|
||||
struct drm_display_mode *drm_mode)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
#include "dp_utils.h"
|
||||
#include "disp/msm_disp_snapshot.h"
|
||||
|
||||
/* interrupts */
|
||||
@ -29,6 +30,9 @@
|
||||
|
||||
#define DP_AUX_CFG_MAX_VALUE_CNT 3
|
||||
|
||||
#define DP_HW_VERSION_1_0 0x10000000
|
||||
#define DP_HW_VERSION_1_2 0x10020000
|
||||
|
||||
/* PHY AUX config registers */
|
||||
enum dp_phy_aux_config_type {
|
||||
PHY_AUX_CFG0,
|
||||
@ -92,9 +96,10 @@ void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);
|
||||
void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable);
|
||||
void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool enable);
|
||||
void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
|
||||
void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
|
||||
u32 stream_rate_khz, bool fixed_nvid);
|
||||
u32 stream_rate_khz, bool fixed_nvid, bool is_ycbcr_420);
|
||||
int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 pattern);
|
||||
u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
|
||||
@ -120,6 +125,8 @@ u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog);
|
||||
|
||||
/* DP Panel APIs */
|
||||
int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp);
|
||||
void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_dump_regs(struct dp_catalog *dp_catalog);
|
||||
void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
|
||||
struct drm_display_mode *drm_mode);
|
||||
|
@ -142,6 +142,9 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
|
||||
/* Default-> LSCLK DIV: 1/4 LCLK */
|
||||
config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
|
||||
|
||||
if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
|
||||
config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */
|
||||
|
||||
/* Scrambler reset enable */
|
||||
if (drm_dp_alternate_scrambler_reset_cap(dpcd))
|
||||
config |= DP_CONFIGURATION_CTRL_ASSR;
|
||||
@ -176,6 +179,7 @@ static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl)
|
||||
|
||||
dp_catalog_ctrl_lane_mapping(ctrl->catalog);
|
||||
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
|
||||
dp_catalog_setup_peripheral_flush(ctrl->catalog);
|
||||
|
||||
dp_ctrl_config_ctrl(ctrl);
|
||||
|
||||
@ -966,7 +970,7 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl,
|
||||
in.hporch = drm_mode->htotal - drm_mode->hdisplay;
|
||||
in.nlanes = ctrl->link->link_params.num_lanes;
|
||||
in.bpp = ctrl->panel->dp_mode.bpp;
|
||||
in.pixel_enc = 444;
|
||||
in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444;
|
||||
in.dsc_en = 0;
|
||||
in.async_en = 0;
|
||||
in.fec_en = 0;
|
||||
@ -1849,6 +1853,8 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
|
||||
ctrl->link->link_params.rate = rate;
|
||||
ctrl->link->link_params.num_lanes =
|
||||
ctrl->panel->link_info.num_lanes;
|
||||
if (ctrl->panel->dp_mode.out_fmt_is_yuv_420)
|
||||
pixel_rate >>= 1;
|
||||
}
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
|
||||
@ -1964,7 +1970,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
|
||||
|
||||
pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock;
|
||||
|
||||
if (dp_ctrl->wide_bus_en)
|
||||
if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420)
|
||||
pixel_rate >>= 1;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n",
|
||||
@ -2016,7 +2022,8 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train)
|
||||
|
||||
dp_catalog_ctrl_config_msa(ctrl->catalog,
|
||||
ctrl->link->link_params.rate,
|
||||
pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl));
|
||||
pixel_rate_orig, dp_ctrl_use_fixed_nvid(ctrl),
|
||||
ctrl->panel->dp_mode.out_fmt_is_yuv_420);
|
||||
|
||||
dp_ctrl_setup_tr_unit(ctrl);
|
||||
|
||||
@ -2042,6 +2049,8 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl)
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
dp_catalog_panel_disable_vsc_sdp(ctrl->catalog);
|
||||
|
||||
/* set dongle to D3 (power off) mode */
|
||||
dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
|
||||
|
||||
@ -2094,6 +2103,8 @@ void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
dp_catalog_panel_disable_vsc_sdp(ctrl->catalog);
|
||||
|
||||
dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
|
||||
dp_catalog_ctrl_reset(ctrl->catalog);
|
||||
|
@ -111,7 +111,7 @@ struct dp_display_private {
|
||||
struct dp_event event_list[DP_EVENT_Q_MAX];
|
||||
spinlock_t event_lock;
|
||||
|
||||
bool wide_bus_en;
|
||||
bool wide_bus_supported;
|
||||
|
||||
struct dp_audio *audio;
|
||||
};
|
||||
@ -120,7 +120,7 @@ struct msm_dp_desc {
|
||||
phys_addr_t io_start;
|
||||
unsigned int id;
|
||||
unsigned int connector_type;
|
||||
bool wide_bus_en;
|
||||
bool wide_bus_supported;
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc7180_dp_descs[] = {
|
||||
@ -129,8 +129,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc7280_dp_descs[] = {
|
||||
{ .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
{ .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -142,22 +142,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc8280xp_dp_descs[] = {
|
||||
{ .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
|
||||
{ .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{ .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct msm_dp_desc sc8280xp_edp_descs[] = {
|
||||
{ .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
{ .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
{ .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
|
||||
{ .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
|
||||
{ .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
|
||||
{ .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
|
||||
{ .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -766,10 +766,6 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
|
||||
goto error_ctrl;
|
||||
}
|
||||
|
||||
/* populate wide_bus_en to differernt layers */
|
||||
dp->ctrl->wide_bus_en = dp->wide_bus_en;
|
||||
dp->catalog->wide_bus_en = dp->wide_bus_en;
|
||||
|
||||
return rc;
|
||||
|
||||
error_ctrl:
|
||||
@ -790,6 +786,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
|
||||
drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode);
|
||||
dp->panel->dp_mode.bpp = mode->bpp;
|
||||
dp->panel->dp_mode.capabilities = mode->capabilities;
|
||||
dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
|
||||
dp_panel_init_panel_info(dp->panel);
|
||||
return 0;
|
||||
}
|
||||
@ -918,6 +915,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
|
||||
dp_display = container_of(dp, struct dp_display_private, dp_display);
|
||||
link_info = &dp_display->panel->link_info;
|
||||
|
||||
if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
|
||||
dp_display->panel->vsc_sdp_supported)
|
||||
mode_pclk_khz /= 2;
|
||||
|
||||
mode_bpp = dp->connector->display_info.bpc * num_components;
|
||||
if (!mode_bpp)
|
||||
mode_bpp = default_bpp;
|
||||
@ -1247,7 +1248,7 @@ static int dp_display_probe(struct platform_device *pdev)
|
||||
dp->name = "drm_dp";
|
||||
dp->id = desc->id;
|
||||
dp->dp_display.connector_type = desc->connector_type;
|
||||
dp->wide_bus_en = desc->wide_bus_en;
|
||||
dp->wide_bus_supported = desc->wide_bus_supported;
|
||||
dp->dp_display.is_edp =
|
||||
(dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP);
|
||||
|
||||
@ -1375,13 +1376,34 @@ void __exit msm_dp_unregister(void)
|
||||
platform_driver_unregister(&dp_display_driver);
|
||||
}
|
||||
|
||||
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct dp_display_private *dp;
|
||||
const struct drm_display_info *info;
|
||||
|
||||
dp = container_of(dp_display, struct dp_display_private, dp_display);
|
||||
info = &dp_display->connector->display_info;
|
||||
|
||||
return dp->panel->vsc_sdp_supported && drm_mode_is_420_only(info, mode);
|
||||
}
|
||||
|
||||
bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return msm_dp_is_yuv_420_enabled(dp_display, mode);
|
||||
}
|
||||
|
||||
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
|
||||
{
|
||||
struct dp_display_private *dp;
|
||||
|
||||
dp = container_of(dp_display, struct dp_display_private, dp_display);
|
||||
|
||||
return dp->wide_bus_en;
|
||||
if (dp->dp_mode.out_fmt_is_yuv_420)
|
||||
return false;
|
||||
|
||||
return dp->wide_bus_supported;
|
||||
}
|
||||
|
||||
void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, bool is_edp)
|
||||
@ -1404,7 +1426,7 @@ void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, boo
|
||||
}
|
||||
|
||||
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
struct drm_encoder *encoder, bool yuv_supported)
|
||||
{
|
||||
struct dp_display_private *dp_priv;
|
||||
int ret;
|
||||
@ -1420,7 +1442,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
dp_display->connector = dp_drm_connector_init(dp_display, encoder);
|
||||
dp_display->connector = dp_drm_connector_init(dp_display, encoder, yuv_supported);
|
||||
if (IS_ERR(dp_display->connector)) {
|
||||
ret = PTR_ERR(dp_display->connector);
|
||||
DRM_DEV_ERROR(dev->dev,
|
||||
@ -1550,8 +1572,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
|
||||
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
|
||||
struct msm_dp *dp = dp_bridge->dp_display;
|
||||
struct dp_display_private *dp_display;
|
||||
struct dp_panel *dp_panel;
|
||||
|
||||
dp_display = container_of(dp, struct dp_display_private, dp_display);
|
||||
dp_panel = dp_display->panel;
|
||||
|
||||
memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
|
||||
|
||||
@ -1570,6 +1594,16 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
|
||||
|
||||
dp_display->dp_mode.h_active_low =
|
||||
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
|
||||
|
||||
dp_display->dp_mode.out_fmt_is_yuv_420 =
|
||||
drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) &&
|
||||
dp_panel->vsc_sdp_supported;
|
||||
|
||||
/* populate wide_bus_support to different layers */
|
||||
dp_display->ctrl->wide_bus_en =
|
||||
dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported;
|
||||
dp_display->catalog->wide_bus_en =
|
||||
dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported;
|
||||
}
|
||||
|
||||
void dp_bridge_hpd_enable(struct drm_bridge *bridge)
|
||||
|
@ -353,7 +353,8 @@ int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
}
|
||||
|
||||
/* connector initialization */
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder)
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder,
|
||||
bool yuv_supported)
|
||||
{
|
||||
struct drm_connector *connector = NULL;
|
||||
|
||||
@ -364,6 +365,9 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct dr
|
||||
if (!dp_display->is_edp)
|
||||
drm_connector_attach_dp_subconnector_property(connector);
|
||||
|
||||
if (yuv_supported)
|
||||
connector->ycbcr_420_allowed = true;
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
return connector;
|
||||
|
@ -19,7 +19,8 @@ struct msm_dp_bridge {
|
||||
|
||||
#define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge)
|
||||
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder);
|
||||
struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder,
|
||||
bool yuv_supported);
|
||||
int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "dp_panel.h"
|
||||
#include "dp_utils.h"
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_edid.h>
|
||||
@ -57,6 +58,7 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, dpcd);
|
||||
link_info = &dp_panel->link_info;
|
||||
link_info->revision = dpcd[DP_DPCD_REV];
|
||||
major = (link_info->revision >> 4) & 0x0f;
|
||||
@ -287,6 +289,53 @@ void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable)
|
||||
dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode);
|
||||
}
|
||||
|
||||
static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel)
|
||||
{
|
||||
struct dp_catalog *catalog;
|
||||
struct dp_panel_private *panel;
|
||||
struct dp_display_mode *dp_mode;
|
||||
struct drm_dp_vsc_sdp vsc_sdp_data;
|
||||
struct dp_sdp vsc_sdp;
|
||||
ssize_t len;
|
||||
|
||||
if (!dp_panel) {
|
||||
DRM_ERROR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
catalog = panel->catalog;
|
||||
dp_mode = &dp_panel->dp_mode;
|
||||
|
||||
memset(&vsc_sdp_data, 0, sizeof(vsc_sdp_data));
|
||||
|
||||
/* VSC SDP header as per table 2-118 of DP 1.4 specification */
|
||||
vsc_sdp_data.sdp_type = DP_SDP_VSC;
|
||||
vsc_sdp_data.revision = 0x05;
|
||||
vsc_sdp_data.length = 0x13;
|
||||
|
||||
/* VSC SDP Payload for DB16 */
|
||||
vsc_sdp_data.pixelformat = DP_PIXELFORMAT_YUV420;
|
||||
vsc_sdp_data.colorimetry = DP_COLORIMETRY_DEFAULT;
|
||||
|
||||
/* VSC SDP Payload for DB17 */
|
||||
vsc_sdp_data.bpc = dp_mode->bpp / 3;
|
||||
vsc_sdp_data.dynamic_range = DP_DYNAMIC_RANGE_CTA;
|
||||
|
||||
/* VSC SDP Payload for DB18 */
|
||||
vsc_sdp_data.content_type = DP_CONTENT_TYPE_GRAPHICS;
|
||||
|
||||
len = drm_dp_vsc_sdp_pack(&vsc_sdp_data, &vsc_sdp);
|
||||
if (len < 0) {
|
||||
DRM_ERROR("unable to pack vsc sdp\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
dp_catalog_panel_enable_vsc_sdp(catalog, &vsc_sdp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dp_panel_dump_regs(struct dp_panel *dp_panel)
|
||||
{
|
||||
struct dp_catalog *catalog;
|
||||
@ -350,6 +399,10 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel)
|
||||
catalog->dp_active = data;
|
||||
|
||||
dp_catalog_panel_timing_cfg(catalog);
|
||||
|
||||
if (dp_panel->dp_mode.out_fmt_is_yuv_420)
|
||||
dp_panel_setup_vsc_sdp_yuv_420(dp_panel);
|
||||
|
||||
panel->panel_on = true;
|
||||
|
||||
return 0;
|
||||
|
@ -19,6 +19,7 @@ struct dp_display_mode {
|
||||
u32 bpp;
|
||||
u32 h_active_low;
|
||||
u32 v_active_low;
|
||||
bool out_fmt_is_yuv_420;
|
||||
};
|
||||
|
||||
struct dp_panel_in {
|
||||
@ -45,6 +46,7 @@ struct dp_panel {
|
||||
struct dp_display_mode dp_mode;
|
||||
struct dp_panel_psr psr_cap;
|
||||
bool video_test;
|
||||
bool vsc_sdp_supported;
|
||||
|
||||
u32 vic;
|
||||
u32 max_dp_lanes;
|
||||
|
@ -6,6 +6,9 @@
|
||||
#ifndef _DP_REG_H_
|
||||
#define _DP_REG_H_
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* DP_TX Registers */
|
||||
#define REG_DP_HW_VERSION (0x00000000)
|
||||
|
||||
@ -102,6 +105,9 @@
|
||||
#define DP_MAINLINK_CTRL_ENABLE (0x00000001)
|
||||
#define DP_MAINLINK_CTRL_RESET (0x00000002)
|
||||
#define DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER (0x00000010)
|
||||
#define DP_MAINLINK_CTRL_FLUSH_MODE_MASK GENMASK(24, 23)
|
||||
#define DP_MAINLINK_FLUSH_MODE_UPDATE_SDP FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 1)
|
||||
#define DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE FIELD_PREP(DP_MAINLINK_CTRL_FLUSH_MODE_MASK, 3)
|
||||
#define DP_MAINLINK_FB_BOUNDARY_SEL (0x02000000)
|
||||
|
||||
#define REG_DP_STATE_CTRL (0x00000004)
|
||||
@ -142,6 +148,7 @@
|
||||
#define DP_MISC0_SYNCHRONOUS_CLK (0x00000001)
|
||||
#define DP_MISC0_COLORIMETRY_CFG_SHIFT (0x00000001)
|
||||
#define DP_MISC0_TEST_BITS_DEPTH_SHIFT (0x00000005)
|
||||
#define DP_MISC1_VSC_SDP (0x00004000)
|
||||
|
||||
#define DP_MISC0_COLORIMERY_CFG_LEGACY_RGB (0)
|
||||
#define DP_MISC0_COLORIMERY_CFG_CEA_RGB (0x04)
|
||||
@ -204,9 +211,11 @@
|
||||
#define MMSS_DP_AUDIO_CTRL_RESET (0x00000214)
|
||||
|
||||
#define MMSS_DP_SDP_CFG (0x00000228)
|
||||
#define GEN0_SDP_EN (0x00020000)
|
||||
#define MMSS_DP_SDP_CFG2 (0x0000022C)
|
||||
#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230)
|
||||
#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234)
|
||||
#define GENERIC0_SDPSIZE_VALID (0x00010000)
|
||||
|
||||
#define MMSS_DP_AUDIO_STREAM_0 (0x00000240)
|
||||
#define MMSS_DP_AUDIO_STREAM_1 (0x00000244)
|
||||
|
96
drivers/gpu/drm/msm/dp/dp_utils.c
Normal file
96
drivers/gpu/drm/msm/dp/dp_utils.c
Normal file
@ -0,0 +1,96 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "dp_utils.h"
|
||||
|
||||
#define DP_SDP_HEADER_SIZE 8
|
||||
|
||||
u8 dp_utils_get_g0_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[3];
|
||||
g[1] = c[0] ^ c[3];
|
||||
g[2] = c[1];
|
||||
g[3] = c[2];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
u8 dp_utils_get_g1_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[0] ^ c[3];
|
||||
g[1] = c[0] ^ c[1] ^ c[3];
|
||||
g[2] = c[1] ^ c[2];
|
||||
g[3] = c[2] ^ c[3];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
u8 dp_utils_calculate_parity(u32 data)
|
||||
{
|
||||
u8 x0 = 0;
|
||||
u8 x1 = 0;
|
||||
u8 ci = 0;
|
||||
u8 iData = 0;
|
||||
u8 i = 0;
|
||||
u8 parity_byte;
|
||||
u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
|
||||
|
||||
for (i = 0; i < num_byte; i++) {
|
||||
iData = (data >> i * 4) & 0xF;
|
||||
|
||||
ci = iData ^ x1;
|
||||
x1 = x0 ^ dp_utils_get_g1_value(ci);
|
||||
x0 = dp_utils_get_g0_value(ci);
|
||||
}
|
||||
|
||||
parity_byte = x1 | (x0 << 4);
|
||||
|
||||
return parity_byte;
|
||||
}
|
||||
|
||||
ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
length = sizeof(header_buff);
|
||||
if (length < DP_SDP_HEADER_SIZE)
|
||||
return -ENOSPC;
|
||||
|
||||
header_buff[0] = FIELD_PREP(HEADER_0_MASK, sdp_header->HB0) |
|
||||
FIELD_PREP(PARITY_0_MASK, dp_utils_calculate_parity(sdp_header->HB0)) |
|
||||
FIELD_PREP(HEADER_1_MASK, sdp_header->HB1) |
|
||||
FIELD_PREP(PARITY_1_MASK, dp_utils_calculate_parity(sdp_header->HB1));
|
||||
|
||||
header_buff[1] = FIELD_PREP(HEADER_2_MASK, sdp_header->HB2) |
|
||||
FIELD_PREP(PARITY_2_MASK, dp_utils_calculate_parity(sdp_header->HB2)) |
|
||||
FIELD_PREP(HEADER_3_MASK, sdp_header->HB3) |
|
||||
FIELD_PREP(PARITY_3_MASK, dp_utils_calculate_parity(sdp_header->HB3));
|
||||
|
||||
return length;
|
||||
}
|
36
drivers/gpu/drm/msm/dp/dp_utils.h
Normal file
36
drivers/gpu/drm/msm/dp/dp_utils.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2024, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_UTILS_H_
|
||||
#define _DP_UTILS_H_
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
|
||||
#define HEADER_BYTE_0_BIT 0
|
||||
#define PARITY_BYTE_0_BIT 8
|
||||
#define HEADER_BYTE_1_BIT 16
|
||||
#define PARITY_BYTE_1_BIT 24
|
||||
#define HEADER_BYTE_2_BIT 0
|
||||
#define PARITY_BYTE_2_BIT 8
|
||||
#define HEADER_BYTE_3_BIT 16
|
||||
#define PARITY_BYTE_3_BIT 24
|
||||
|
||||
#define HEADER_0_MASK GENMASK(7, 0)
|
||||
#define PARITY_0_MASK GENMASK(15, 8)
|
||||
#define HEADER_1_MASK GENMASK(23, 16)
|
||||
#define PARITY_1_MASK GENMASK(31, 24)
|
||||
#define HEADER_2_MASK GENMASK(7, 0)
|
||||
#define PARITY_2_MASK GENMASK(15, 8)
|
||||
#define HEADER_3_MASK GENMASK(23, 16)
|
||||
#define PARITY_3_MASK GENMASK(31, 24)
|
||||
|
||||
u8 dp_utils_get_g0_value(u8 data);
|
||||
u8 dp_utils_get_g1_value(u8 data);
|
||||
u8 dp_utils_calculate_parity(u32 data);
|
||||
ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff);
|
||||
|
||||
#endif /* _DP_UTILS_H_ */
|
@ -74,16 +74,6 @@ enum msm_dsi_controller {
|
||||
#define MSM_GPU_MAX_RINGS 4
|
||||
#define MAX_H_TILES_PER_DISPLAY 2
|
||||
|
||||
/**
|
||||
* enum msm_event_wait - type of HW events to wait for
|
||||
* @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
|
||||
* @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel
|
||||
*/
|
||||
enum msm_event_wait {
|
||||
MSM_ENC_COMMIT_DONE = 0,
|
||||
MSM_ENC_TX_COMPLETE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct msm_display_topology - defines a display topology pipeline
|
||||
* @num_lm: number of layer mixers used
|
||||
@ -385,9 +375,12 @@ static inline struct drm_dsc_config *msm_dsi_get_dsc_config(struct msm_dsi *msm_
|
||||
int __init msm_dp_register(void);
|
||||
void __exit msm_dp_unregister(void);
|
||||
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
struct drm_encoder *encoder, bool yuv_supported);
|
||||
void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display);
|
||||
|
||||
bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode);
|
||||
bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode);
|
||||
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display);
|
||||
|
||||
#else
|
||||
@ -400,7 +393,8 @@ static inline void __exit msm_dp_unregister(void)
|
||||
}
|
||||
static inline int msm_dp_modeset_init(struct msm_dp *dp_display,
|
||||
struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
struct drm_encoder *encoder,
|
||||
bool yuv_supported)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -409,6 +403,18 @@ static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
|
||||
{
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user