drm/msm/sde: programmable pre-fetch support for video encoders
Add support in encoder for programming early fetch in the vertical front porch. Change-Id: I60fcf4a4e6aea80292b590ee14506579123f372d Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org> Signed-off-by: Krishna Srinivas Kundurthi <kskund@codeaurora.org>
This commit is contained in:
parent
a142ec80ca
commit
fe03524bee
4 changed files with 314 additions and 119 deletions
|
@ -101,37 +101,46 @@ static void bs_set(struct sde_encoder_virt *sde_enc, int idx)
|
|||
void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
|
||||
struct sde_encoder_hw_resources *hw_res)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!hw_res) {
|
||||
if (!hw_res || !drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
/* Query resources used by phys encs, expected to be without overlap */
|
||||
memset(hw_res, 0, sizeof(*hw_res));
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys)
|
||||
if (phys && phys->phys_ops.get_hw_resources)
|
||||
phys->phys_ops.get_hw_resources(phys, hw_res);
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_destroy(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sde_enc->phys_encs); i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys) {
|
||||
if (phys && phys->phys_ops.destroy) {
|
||||
phys->phys_ops.destroy(phys);
|
||||
--sde_enc->num_phys_encs;
|
||||
sde_enc->phys_encs[i] = NULL;
|
||||
|
@ -152,70 +161,103 @@ static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc,
|
|||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
bool ret = true;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys) {
|
||||
phys->phys_ops.mode_fixup(phys, mode, adjusted_mode);
|
||||
if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0) {
|
||||
DRM_ERROR("adjusted modes not supported\n");
|
||||
return false;
|
||||
if (phys && phys->phys_ops.mode_fixup) {
|
||||
ret =
|
||||
phys->phys_ops.mode_fixup(phys, mode,
|
||||
adjusted_mode);
|
||||
if (!ret) {
|
||||
DBG("Mode unsupported by phys_enc %d", i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sde_enc->num_phys_encs > 1) {
|
||||
DBG("ModeFix only checking 1 phys_enc");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys) {
|
||||
if (phys && phys->phys_ops.mode_set)
|
||||
phys->phys_ops.mode_set(phys, mode, adjusted_mode);
|
||||
if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0)
|
||||
DRM_ERROR("adjusted modes not supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
bs_set(sde_enc, 1);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys)
|
||||
if (phys && phys->phys_ops.enable)
|
||||
phys->phys_ops.enable(phys);
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
|
@ -256,11 +298,18 @@ static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
|
|||
|
||||
static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!drm_enc) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
|
||||
if (sde_enc->kms_vblank_callback)
|
||||
sde_enc->kms_vblank_callback(sde_enc->kms_vblank_callback_data);
|
||||
|
@ -286,7 +335,8 @@ static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc,
|
|||
};
|
||||
struct sde_encoder_phys *enc =
|
||||
sde_encoder_phys_vid_init(sde_kms, intf_idx, ctl_idx,
|
||||
&sde_enc->base, parent_ops);
|
||||
&sde_enc->base,
|
||||
parent_ops);
|
||||
if (IS_ERR(enc))
|
||||
ret = PTR_ERR(enc);
|
||||
|
||||
|
@ -304,6 +354,7 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
|
|||
{
|
||||
int ret = 0;
|
||||
enum sde_intf intf_idx = INTF_MAX;
|
||||
enum sde_ctl ctl_idx = CTL_2;
|
||||
|
||||
DBG("");
|
||||
|
||||
|
@ -314,8 +365,7 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
|
|||
if (!ret)
|
||||
ret =
|
||||
sde_encoder_virt_add_phys_vid_enc(sde_enc, sde_kms,
|
||||
intf_idx,
|
||||
CTL_2);
|
||||
intf_idx, ctl_idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -343,13 +393,14 @@ static int sde_encoder_setup_dsi(struct sde_encoder_virt *sde_enc,
|
|||
enum sde_ctl ctl_idx = CTL_0;
|
||||
|
||||
intf_idx = sde_encoder_get_intf(sde_kms->catalog,
|
||||
INTF_DSI, dsi_info->h_tile_ids[i]);
|
||||
INTF_DSI,
|
||||
dsi_info->h_tile_ids[i]);
|
||||
if (intf_idx == INTF_MAX) {
|
||||
DBG("Error: could not get the interface id");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* Create both VID and CMD Phys Encoders here */
|
||||
/* Create both VID and CMD Phys Encoders here */
|
||||
if (!ret)
|
||||
ret =
|
||||
sde_encoder_virt_add_phys_vid_enc(sde_enc, sde_kms,
|
||||
|
@ -511,12 +562,22 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
|
|||
*/
|
||||
void sde_encoders_init(struct drm_device *dev)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_drm_private *priv = NULL;
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
/* Start num_encoders at 0, probe functions will increment */
|
||||
if (!dev || !dev->dev_private) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
priv = dev->dev_private;
|
||||
if (!priv->kms) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
/* Start num_encoders at 0, probe functions will increment */
|
||||
priv->num_encoders = 0;
|
||||
ret = sde_encoder_probe_dsi(dev);
|
||||
if (ret)
|
||||
|
|
|
@ -20,59 +20,44 @@
|
|||
#include "sde_encoder_phys.h"
|
||||
#include "sde_mdp_formats.h"
|
||||
|
||||
|
||||
#define to_sde_encoder_phys_vid(x) \
|
||||
container_of(x, struct sde_encoder_phys_vid, base)
|
||||
|
||||
static bool sde_encoder_phys_vid_mode_fixup(struct sde_encoder_phys *drm_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode
|
||||
*adjusted_mode)
|
||||
static void drm_mode_to_intf_timing_params(
|
||||
const struct sde_encoder_phys *phys_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct intf_timing_params *timing)
|
||||
{
|
||||
DBG("");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode
|
||||
*adjusted_mode)
|
||||
{
|
||||
mode = adjusted_mode;
|
||||
phys_enc->cached_mode = *adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_setup_timing_engine(struct sde_encoder_phys
|
||||
*phys_enc)
|
||||
{
|
||||
struct drm_display_mode *mode = &phys_enc->cached_mode;
|
||||
struct intf_timing_params p = { 0 };
|
||||
uint32_t hsync_polarity = 0;
|
||||
uint32_t vsync_polarity = 0;
|
||||
struct sde_mdp_format_params *sde_fmt_params = NULL;
|
||||
u32 fmt_fourcc = DRM_FORMAT_RGB888;
|
||||
u32 fmt_mod = 0;
|
||||
unsigned long lock_flags;
|
||||
struct sde_hw_intf_cfg intf_cfg = {0};
|
||||
|
||||
DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
memset(timing, 0, sizeof(*timing));
|
||||
/*
|
||||
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
|
||||
* Active Region Front Porch Sync Back Porch
|
||||
* <-----------------><------------><-----><----------->
|
||||
* <- [hv]display --->
|
||||
* <--------- [hv]sync_start ------>
|
||||
* <----------------- [hv]sync_end ------->
|
||||
* <---------------------------- [hv]total ------------->
|
||||
*/
|
||||
timing->width = mode->hdisplay; /* active width */
|
||||
timing->height = mode->vdisplay; /* active height */
|
||||
timing->xres = timing->width;
|
||||
timing->yres = timing->height;
|
||||
timing->h_back_porch = mode->htotal - mode->hsync_end;
|
||||
timing->h_front_porch = mode->hsync_start - mode->hdisplay;
|
||||
timing->v_back_porch = mode->vtotal - mode->vsync_end;
|
||||
timing->v_front_porch = mode->vsync_start - mode->vdisplay;
|
||||
timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start;
|
||||
timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start;
|
||||
timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
|
||||
timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
|
||||
timing->border_clr = 0;
|
||||
timing->underflow_clr = 0xff;
|
||||
timing->hsync_skew = mode->hskew;
|
||||
|
||||
/* DSI controller cannot handle active-low sync signals. */
|
||||
if (phys_enc->hw_intf->cap->type != INTF_DSI) {
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
hsync_polarity = 1;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
vsync_polarity = 1;
|
||||
if (phys_enc->hw_intf->cap->type == INTF_DSI) {
|
||||
timing->hsync_polarity = 0;
|
||||
timing->vsync_polarity = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -86,47 +71,186 @@ static void sde_encoder_phys_vid_setup_timing_engine(struct sde_encoder_phys
|
|||
* display_v_end -= mode->hsync_start - mode->hdisplay;
|
||||
* }
|
||||
*/
|
||||
}
|
||||
|
||||
static inline u32 get_horizontal_total(const struct intf_timing_params *timing)
|
||||
{
|
||||
u32 active = timing->xres;
|
||||
u32 inactive =
|
||||
timing->h_back_porch + timing->h_front_porch +
|
||||
timing->hsync_pulse_width;
|
||||
return active + inactive;
|
||||
}
|
||||
|
||||
static inline u32 get_vertical_total(const struct intf_timing_params *timing)
|
||||
{
|
||||
u32 active = timing->yres;
|
||||
u32 inactive =
|
||||
timing->v_back_porch + timing->v_front_porch +
|
||||
timing->vsync_pulse_width;
|
||||
return active + inactive;
|
||||
}
|
||||
|
||||
/*
|
||||
* programmable_fetch_get_num_lines:
|
||||
* Number of fetch lines in vertical front porch
|
||||
* @timing: Pointer to the intf timing information for the requested mode
|
||||
*
|
||||
* Returns the number of fetch lines in vertical front porch at which mdp
|
||||
* can start fetching the next frame.
|
||||
*
|
||||
* Number of needed prefetch lines is anything that cannot be absorbed in the
|
||||
* start of frame time (back porch + vsync pulse width).
|
||||
*
|
||||
* Some panels have very large VFP, however we only need a total number of
|
||||
* lines based on the chip worst case latencies.
|
||||
*/
|
||||
static u32 programmable_fetch_get_num_lines(
|
||||
struct sde_encoder_phys *phys_enc,
|
||||
const struct intf_timing_params *timing)
|
||||
{
|
||||
u32 worst_case_needed_lines =
|
||||
phys_enc->hw_intf->cap->prog_fetch_lines_worst_case;
|
||||
u32 start_of_frame_lines =
|
||||
timing->v_back_porch + timing->vsync_pulse_width;
|
||||
u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines;
|
||||
u32 actual_vfp_lines = 0;
|
||||
|
||||
/* Fetch must be outside active lines, otherwise undefined. */
|
||||
|
||||
if (start_of_frame_lines >= worst_case_needed_lines) {
|
||||
DBG("Programmable fetch is not needed due to large vbp+vsw");
|
||||
actual_vfp_lines = 0;
|
||||
} else if (timing->v_front_porch < needed_vfp_lines) {
|
||||
/* Warn fetch needed, but not enough porch in panel config */
|
||||
pr_warn_once
|
||||
("low vbp+vfp may lead to perf issues in some cases\n");
|
||||
DBG("Less vfp than fetch requires, using entire vfp");
|
||||
actual_vfp_lines = timing->v_front_porch;
|
||||
} else {
|
||||
DBG("Room in vfp for needed prefetch");
|
||||
actual_vfp_lines = needed_vfp_lines;
|
||||
}
|
||||
|
||||
DBG("v_front_porch %u v_back_porch %u vsync_pulse_width %u",
|
||||
timing->v_front_porch, timing->v_back_porch,
|
||||
timing->vsync_pulse_width);
|
||||
DBG("wc_lines %u needed_vfp_lines %u actual_vfp_lines %u",
|
||||
worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines);
|
||||
|
||||
return actual_vfp_lines;
|
||||
}
|
||||
|
||||
/*
|
||||
* programmable_fetch_config: Programs HW to prefetch lines by offsetting
|
||||
* the start of fetch into the vertical front porch for cases where the
|
||||
* vsync pulse width and vertical back porch time is insufficient
|
||||
*
|
||||
* Gets # of lines to pre-fetch, then calculate VSYNC counter value.
|
||||
* HW layer requires VSYNC counter of first pixel of tgt VFP line.
|
||||
*
|
||||
* @timing: Pointer to the intf timing information for the requested mode
|
||||
*/
|
||||
static void programmable_fetch_config(struct sde_encoder_phys *phys_enc,
|
||||
const struct intf_timing_params *timing)
|
||||
{
|
||||
struct intf_prog_fetch f = { 0 };
|
||||
u32 vfp_fetch_lines = 0;
|
||||
u32 horiz_total = 0;
|
||||
u32 vert_total = 0;
|
||||
u32 vfp_fetch_start_vsync_counter = 0;
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (WARN_ON_ONCE(!phys_enc->hw_intf->ops.setup_prg_fetch))
|
||||
return;
|
||||
|
||||
vfp_fetch_lines = programmable_fetch_get_num_lines(phys_enc, timing);
|
||||
if (vfp_fetch_lines) {
|
||||
vert_total = get_vertical_total(timing);
|
||||
horiz_total = get_horizontal_total(timing);
|
||||
vfp_fetch_start_vsync_counter =
|
||||
(vert_total - vfp_fetch_lines) * horiz_total + 1;
|
||||
f.enable = 1;
|
||||
f.fetch_start = vfp_fetch_start_vsync_counter;
|
||||
}
|
||||
|
||||
DBG("vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u",
|
||||
vfp_fetch_lines, vfp_fetch_start_vsync_counter);
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.setup_prg_fetch(phys_enc->hw_intf, &f);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
}
|
||||
|
||||
static bool sde_encoder_phys_vid_mode_fixup(
|
||||
struct sde_encoder_phys *phys_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
DBG("");
|
||||
|
||||
/*
|
||||
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
|
||||
* Active Region Front Porch Sync Back Porch
|
||||
* <---------------------><----------------><---------><-------------->
|
||||
* <--- [hv]display ----->
|
||||
* <----------- [hv]sync_start ------------>
|
||||
* <------------------- [hv]sync_end ----------------->
|
||||
* <------------------------------ [hv]total ------------------------->
|
||||
* Modifying mode has consequences when the mode comes back to us
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_mode_set(
|
||||
struct sde_encoder_phys *phys_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
mode = adjusted_mode;
|
||||
phys_enc->cached_mode = *adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_setup_timing_engine(
|
||||
struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
struct drm_display_mode *mode = &phys_enc->cached_mode;
|
||||
struct intf_timing_params p = { 0 };
|
||||
struct sde_mdp_format_params *sde_fmt_params = NULL;
|
||||
u32 fmt_fourcc = DRM_FORMAT_RGB888;
|
||||
u32 fmt_mod = 0;
|
||||
unsigned long lock_flags;
|
||||
struct sde_hw_intf_cfg intf_cfg = { 0 };
|
||||
|
||||
if (WARN_ON(!phys_enc->hw_intf->ops.setup_timing_gen))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!phys_enc->hw_ctl->ops.setup_intf_cfg))
|
||||
return;
|
||||
|
||||
DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
|
||||
drm_mode_to_intf_timing_params(phys_enc, mode, &p);
|
||||
|
||||
sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
|
||||
|
||||
p.width = mode->hdisplay; /* active width */
|
||||
p.height = mode->vdisplay; /* active height */
|
||||
p.xres = p.width; /* Display panel width */
|
||||
p.yres = p.height; /* Display panel height */
|
||||
p.h_back_porch = mode->htotal - mode->hsync_end;
|
||||
p.h_front_porch = mode->hsync_start - mode->hdisplay;
|
||||
p.v_back_porch = mode->vtotal - mode->vsync_end;
|
||||
p.v_front_porch = mode->vsync_start - mode->vdisplay;
|
||||
p.hsync_pulse_width = mode->hsync_end - mode->hsync_start;
|
||||
p.vsync_pulse_width = mode->vsync_end - mode->vsync_start;
|
||||
p.hsync_polarity = hsync_polarity;
|
||||
p.vsync_polarity = vsync_polarity;
|
||||
p.border_clr = 0;
|
||||
p.underflow_clr = 0xff;
|
||||
p.hsync_skew = mode->hskew;
|
||||
|
||||
intf_cfg.intf = phys_enc->hw_intf->idx;
|
||||
intf_cfg.wb = SDE_NONE;
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &p,
|
||||
sde_fmt_params);
|
||||
sde_fmt_params);
|
||||
phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
|
||||
programmable_fetch_config(phys_enc, &p);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_wait_for_vblank(struct sde_encoder_phys_vid
|
||||
*vid_enc)
|
||||
static void sde_encoder_phys_vid_wait_for_vblank(
|
||||
struct sde_encoder_phys_vid *vid_enc)
|
||||
{
|
||||
DBG("");
|
||||
mdp_irq_wait(vid_enc->base.mdp_kms, vid_enc->vblank_irq.irqmask);
|
||||
|
@ -139,9 +263,7 @@ static void sde_encoder_phys_vid_vblank_irq(struct mdp_irq *irq,
|
|||
container_of(irq, struct sde_encoder_phys_vid,
|
||||
vblank_irq);
|
||||
struct sde_encoder_phys *phys_enc = &vid_enc->base;
|
||||
struct intf_status status = { 0 };
|
||||
|
||||
phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status);
|
||||
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent);
|
||||
}
|
||||
|
||||
|
@ -156,6 +278,9 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
|
|||
if (WARN_ON(phys_enc->enabled))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing))
|
||||
return;
|
||||
|
||||
sde_encoder_phys_vid_setup_timing_engine(phys_enc);
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
|
@ -180,6 +305,9 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
|
|||
if (WARN_ON(!phys_enc->enabled))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
|
@ -206,10 +334,9 @@ static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc)
|
|||
kfree(vid_enc);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_get_hw_resources(struct sde_encoder_phys
|
||||
*phys_enc, struct
|
||||
sde_encoder_hw_resources
|
||||
*hw_res)
|
||||
static void sde_encoder_phys_vid_get_hw_resources(
|
||||
struct sde_encoder_phys *phys_enc,
|
||||
struct sde_encoder_hw_resources *hw_res)
|
||||
{
|
||||
DBG("");
|
||||
hw_res->intfs[phys_enc->hw_intf->idx] = true;
|
||||
|
@ -225,15 +352,16 @@ static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops)
|
|||
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
|
||||
}
|
||||
|
||||
struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx,
|
||||
struct drm_encoder *parent,
|
||||
struct sde_encoder_virt_ops
|
||||
parent_ops)
|
||||
struct sde_encoder_phys *sde_encoder_phys_vid_init(
|
||||
struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx,
|
||||
struct drm_encoder *parent,
|
||||
struct sde_encoder_virt_ops parent_ops)
|
||||
{
|
||||
struct sde_encoder_phys *phys_enc = NULL;
|
||||
struct sde_encoder_phys_vid *vid_enc = NULL;
|
||||
u32 irq_mask = 0x8000000;
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
|
@ -253,7 +381,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
|
|||
}
|
||||
|
||||
phys_enc->hw_ctl = sde_hw_ctl_init(ctl_idx, sde_kms->mmio,
|
||||
sde_kms->catalog);
|
||||
sde_kms->catalog);
|
||||
if (!phys_enc->hw_ctl) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
|
@ -264,7 +392,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
|
|||
phys_enc->parent_ops = parent_ops;
|
||||
phys_enc->mdp_kms = &sde_kms->base;
|
||||
vid_enc->vblank_irq.irq = sde_encoder_phys_vid_vblank_irq;
|
||||
vid_enc->vblank_irq.irqmask = 0x8000000;
|
||||
vid_enc->vblank_irq.irqmask = irq_mask;
|
||||
spin_lock_init(&phys_enc->spin_lock);
|
||||
|
||||
DBG("Created sde_encoder_phys_vid for intf %d", phys_enc->hw_intf->idx);
|
||||
|
|
|
@ -372,11 +372,13 @@ struct sde_cdm_cfg {
|
|||
* @features bit mask identifying sub-blocks/features
|
||||
* @type: Interface type(DSI, DP, HDMI)
|
||||
* @controller_id: Controller Instance ID in case of multiple of intf type
|
||||
* @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch
|
||||
*/
|
||||
struct sde_intf_cfg {
|
||||
SDE_HW_BLK_INFO;
|
||||
u32 type; /* interface type*/
|
||||
u32 controller_id;
|
||||
u32 prog_fetch_lines_worst_case;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -244,13 +244,17 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
|
|||
.intf_count = 4,
|
||||
.intf = {
|
||||
{.id = INTF_0, .base = 0x0006B000,
|
||||
.type = INTF_NONE, .controller_id = 0},
|
||||
.type = INTF_NONE, .controller_id = 0,
|
||||
.prog_fetch_lines_worst_case = 21},
|
||||
{.id = INTF_1, .base = 0x0006B800,
|
||||
.type = INTF_DSI, .controller_id = 0},
|
||||
.type = INTF_DSI, .controller_id = 0,
|
||||
.prog_fetch_lines_worst_case = 21},
|
||||
{.id = INTF_2, .base = 0x0006C000,
|
||||
.type = INTF_DSI, .controller_id = 1},
|
||||
.type = INTF_DSI, .controller_id = 1,
|
||||
.prog_fetch_lines_worst_case = 21},
|
||||
{.id = INTF_3, .base = 0x0006C800,
|
||||
.type = INTF_HDMI, .controller_id = 0},
|
||||
.type = INTF_HDMI, .controller_id = 0,
|
||||
.prog_fetch_lines_worst_case = 21},
|
||||
},
|
||||
.wb_count = 3,
|
||||
.wb = {
|
||||
|
|
Loading…
Add table
Reference in a new issue