Commit e47616df authored by Kalyan Thota's avatar Kalyan Thota Committed by Rob Clark

drm/msm/dpu: add support for color processing blocks in dpu driver

This change adds support to configure dspp blocks in
the dpu driver.

Macro description of the changes coming in this patch.
1) Add dspp definitions in the hw catalog.
2) Add capability to reserve dspp blocks in the display data path.
3) Attach the reserved block to the encoder.
Signed-off-by: default avatarKalyan Thota <kalyan_t@codeaurora.org>
Tested-by: default avatarFritz Koenig <frkoenig@google.com>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent e4337877
......@@ -65,6 +65,7 @@ msm-y := \
disp/dpu1/dpu_hw_lm.o \
disp/dpu1/dpu_hw_pingpong.o \
disp/dpu1/dpu_hw_sspp.o \
disp/dpu1/dpu_hw_dspp.o \
disp/dpu1/dpu_hw_top.o \
disp/dpu1/dpu_hw_util.o \
disp/dpu1/dpu_hw_vbif.o \
......
......@@ -73,12 +73,14 @@ struct dpu_crtc_smmu_state_data {
* struct dpu_crtc_mixer: stores the map for each virtual pipeline in the CRTC
* @hw_lm: LM HW Driver context
* @lm_ctl: CTL Path HW driver context
* @lm_dspp: DSPP HW driver context
* @mixer_op_mode: mixer blending operation mode
* @flush_mask: mixer flush mask for ctl, mixer and pipe
*/
struct dpu_crtc_mixer {
struct dpu_hw_mixer *hw_lm;
struct dpu_hw_ctl *lm_ctl;
struct dpu_hw_dspp *hw_dspp;
u32 mixer_op_mode;
u32 flush_mask;
};
......
......@@ -20,6 +20,7 @@
#include "dpu_hw_catalog.h"
#include "dpu_hw_intf.h"
#include "dpu_hw_ctl.h"
#include "dpu_hw_dspp.h"
#include "dpu_formats.h"
#include "dpu_encoder_phys.h"
#include "dpu_crtc.h"
......@@ -536,6 +537,7 @@ static struct msm_display_topology dpu_encoder_get_topology(
* 1 LM, 1 INTF
* 2 LM, 1 INTF (stream merge to support high resolution interfaces)
*
* Adding color blocks only to primary interface
*/
if (intf_count == 2)
topology.num_lm = 2;
......@@ -544,6 +546,9 @@ static struct msm_display_topology dpu_encoder_get_topology(
else
topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1;
if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI)
topology.num_dspp = topology.num_lm;
topology.num_enc = 0;
topology.num_intf = intf_count;
......@@ -959,7 +964,8 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
struct dpu_hw_blk *hw_pp[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_ctl[MAX_CHANNELS_PER_ENC];
struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC];
int num_lm, num_ctl, num_pp;
struct dpu_hw_blk *hw_dspp[MAX_CHANNELS_PER_ENC] = { NULL };
int num_lm, num_ctl, num_pp, num_dspp;
int i, j;
if (!drm_enc) {
......@@ -1008,6 +1014,9 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
drm_enc->base.id, DPU_HW_BLK_CTL, hw_ctl, ARRAY_SIZE(hw_ctl));
num_lm = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
drm_enc->base.id, DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm));
num_dspp = dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state,
drm_enc->base.id, DPU_HW_BLK_DSPP, hw_dspp,
ARRAY_SIZE(hw_dspp));
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++)
dpu_enc->hw_pp[i] = i < num_pp ? to_dpu_hw_pingpong(hw_pp[i])
......@@ -1020,6 +1029,7 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc,
cstate->mixers[i].hw_lm = to_dpu_hw_mixer(hw_lm[i]);
cstate->mixers[i].lm_ctl = to_dpu_hw_ctl(hw_ctl[ctl_idx]);
cstate->mixers[i].hw_dspp = to_dpu_hw_dspp(hw_dspp[i]);
}
cstate->num_mixers = num_lm;
......
......@@ -41,6 +41,8 @@
#define PINGPONG_SDM845_SPLIT_MASK \
(PINGPONG_SDM845_MASK | BIT(DPU_PINGPONG_TE2))
#define DSPP_SC7180_MASK 0
#define DEFAULT_PIXEL_RAM_SIZE (50 * 1024)
#define DEFAULT_DPU_LINE_WIDTH 2048
#define DEFAULT_DPU_OUTPUT_LINE_WIDTH 2560
......@@ -291,29 +293,30 @@ static const struct dpu_lm_sub_blks sdm845_lm_sblk = {
},
};
#define LM_BLK(_name, _id, _base, _fmask, _sblk, _pp, _lmpair) \
#define LM_BLK(_name, _id, _base, _fmask, _sblk, _pp, _lmpair, _dspp) \
{ \
.name = _name, .id = _id, \
.base = _base, .len = 0x320, \
.features = _fmask, \
.sblk = _sblk, \
.pingpong = _pp, \
.lm_pair_mask = (1 << _lmpair) \
.lm_pair_mask = (1 << _lmpair), \
.dspp = _dspp \
}
static const struct dpu_lm_cfg sdm845_lm[] = {
LM_BLK("lm_0", LM_0, 0x44000, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_0, LM_1),
&sdm845_lm_sblk, PINGPONG_0, LM_1, 0),
LM_BLK("lm_1", LM_1, 0x45000, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_1, LM_0),
&sdm845_lm_sblk, PINGPONG_1, LM_0, 0),
LM_BLK("lm_2", LM_2, 0x46000, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_2, LM_5),
&sdm845_lm_sblk, PINGPONG_2, LM_5, 0),
LM_BLK("lm_3", LM_3, 0x0, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_MAX, 0),
&sdm845_lm_sblk, PINGPONG_MAX, 0, 0),
LM_BLK("lm_4", LM_4, 0x0, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_MAX, 0),
&sdm845_lm_sblk, PINGPONG_MAX, 0, 0),
LM_BLK("lm_5", LM_5, 0x49000, MIXER_SDM845_MASK,
&sdm845_lm_sblk, PINGPONG_3, LM_2),
&sdm845_lm_sblk, PINGPONG_3, LM_2, 0),
};
/* SC7180 */
......@@ -328,11 +331,25 @@ static const struct dpu_lm_sub_blks sc7180_lm_sblk = {
static const struct dpu_lm_cfg sc7180_lm[] = {
LM_BLK("lm_0", LM_0, 0x44000, MIXER_SC7180_MASK,
&sc7180_lm_sblk, PINGPONG_0, LM_1),
&sc7180_lm_sblk, PINGPONG_0, LM_1, DSPP_0),
LM_BLK("lm_1", LM_1, 0x45000, MIXER_SC7180_MASK,
&sc7180_lm_sblk, PINGPONG_1, LM_0),
&sc7180_lm_sblk, PINGPONG_1, LM_0, 0),
};
/*************************************************************
* DSPP sub blocks config
*************************************************************/
#define DSPP_BLK(_name, _id, _base) \
{\
.name = _name, .id = _id, \
.base = _base, .len = 0x1800, \
.features = DSPP_SC7180_MASK, \
.sblk = NULL, \
}
static const struct dpu_dspp_cfg sc7180_dspp[] = {
DSPP_BLK("dspp_0", DSPP_0, 0x54000),
};
/*************************************************************
* PINGPONG sub blocks config
*************************************************************/
......@@ -587,6 +604,8 @@ static void sc7180_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
.sspp = sc7180_sspp,
.mixer_count = ARRAY_SIZE(sc7180_lm),
.mixer = sc7180_lm,
.dspp_count = ARRAY_SIZE(sc7180_dspp),
.dspp = sc7180_dspp,
.pingpong_count = ARRAY_SIZE(sc7180_pp),
.pingpong = sc7180_pp,
.intf_count = ARRAY_SIZE(sc7180_intf),
......
......@@ -145,6 +145,17 @@ enum {
DPU_MIXER_MAX
};
/**
* DSPP sub-blocks
* @DPU_DSPP_PCC Panel color correction block
* @DPU_DSPP_GC Gamma correction block
*/
enum {
DPU_DSPP_PCC = 0x1,
DPU_DSPP_GC,
DPU_DSPP_MAX
};
/**
* PINGPONG sub-blocks
* @DPU_PINGPONG_TE Tear check block
......@@ -377,6 +388,16 @@ struct dpu_lm_sub_blks {
struct dpu_pp_blk gc;
};
/**
* struct dpu_dspp_sub_blks: Information of DSPP block
* @gc : gamma correction block
* @pcc: pixel color correction block
*/
struct dpu_dspp_sub_blks {
struct dpu_pp_blk gc;
struct dpu_pp_blk pcc;
};
struct dpu_pingpong_sub_blks {
struct dpu_pp_blk te;
struct dpu_pp_blk te2;
......@@ -471,9 +492,23 @@ struct dpu_lm_cfg {
DPU_HW_BLK_INFO;
const struct dpu_lm_sub_blks *sblk;
u32 pingpong;
u32 dspp;
unsigned long lm_pair_mask;
};
/**
* struct dpu_dspp_cfg - information of DSPP blocks
* @id enum identifying this block
* @base register offset of this block
* @features bit mask identifying sub-blocks/features
* supported by this block
* @sblk sub-blocks information
*/
struct dpu_dspp_cfg {
DPU_HW_BLK_INFO;
const struct dpu_dspp_sub_blks *sblk;
};
/**
* struct dpu_pingpong_cfg - information of PING-PONG blocks
* @id enum identifying this block
......@@ -688,6 +723,9 @@ struct dpu_mdss_cfg {
u32 ad_count;
u32 dspp_count;
const struct dpu_dspp_cfg *dspp;
/* Add additional block data structures here */
struct dpu_perf_cfg perf;
......@@ -716,6 +754,7 @@ struct dpu_mdss_hw_cfg_handler {
#define BLK_PINGPONG(s) ((s)->pingpong)
#define BLK_INTF(s) ((s)->intf)
#define BLK_AD(s) ((s)->ad)
#define BLK_DSPP(s) ((s)->dspp)
/**
* dpu_hw_catalog_init - dpu hardware catalog init API retrieves
......
......@@ -272,6 +272,31 @@ static int dpu_hw_ctl_active_get_bitmask_intf(struct dpu_hw_ctl *ctx,
return 0;
}
static uint32_t dpu_hw_ctl_get_bitmask_dspp(struct dpu_hw_ctl *ctx,
enum dpu_dspp dspp)
{
uint32_t flushbits = 0;
switch (dspp) {
case DSPP_0:
flushbits = BIT(13);
break;
case DSPP_1:
flushbits = BIT(14);
break;
case DSPP_2:
flushbits = BIT(15);
break;
case DSPP_3:
flushbits = BIT(21);
break;
default:
return 0;
}
return flushbits;
}
static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us)
{
struct dpu_hw_blk_reg_map *c = &ctx->hw;
......@@ -548,6 +573,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
ops->setup_blendstage = dpu_hw_ctl_setup_blendstage;
ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp;
ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer;
ops->get_bitmask_dspp = dpu_hw_ctl_get_bitmask_dspp;
};
static struct dpu_hw_blk_ops dpu_hw_ops;
......
......@@ -139,6 +139,9 @@ struct dpu_hw_ctl_ops {
uint32_t (*get_bitmask_mixer)(struct dpu_hw_ctl *ctx,
enum dpu_lm blk);
uint32_t (*get_bitmask_dspp)(struct dpu_hw_ctl *ctx,
enum dpu_dspp blk);
/**
* Query the value of the intf flush mask
* No effect on hardware
......
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*/
#include "dpu_hwio.h"
#include "dpu_hw_catalog.h"
#include "dpu_hw_lm.h"
#include "dpu_hw_dspp.h"
#include "dpu_kms.h"
static void _setup_dspp_ops(struct dpu_hw_dspp *c,
unsigned long features)
{
return;
}
static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp,
const struct dpu_mdss_cfg *m,
void __iomem *addr,
struct dpu_hw_blk_reg_map *b)
{
int i;
if (!m || !addr || !b)
return ERR_PTR(-EINVAL);
for (i = 0; i < m->dspp_count; i++) {
if (dspp == m->dspp[i].id) {
b->base_off = addr;
b->blk_off = m->dspp[i].base;
b->length = m->dspp[i].len;
b->hwversion = m->hwversion;
b->log_mask = DPU_DBG_MASK_DSPP;
return &m->dspp[i];
}
}
return ERR_PTR(-EINVAL);
}
static struct dpu_hw_blk_ops dpu_hw_ops;
struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx,
void __iomem *addr,
const struct dpu_mdss_cfg *m)
{
struct dpu_hw_dspp *c;
const struct dpu_dspp_cfg *cfg;
if (!addr || !m)
return ERR_PTR(-EINVAL);
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
cfg = _dspp_offset(idx, m, addr, &c->hw);
if (IS_ERR_OR_NULL(cfg)) {
kfree(c);
return ERR_PTR(-EINVAL);
}
/* Assign ops */
c->idx = idx;
c->cap = cfg;
_setup_dspp_ops(c, c->cap->features);
dpu_hw_blk_init(&c->base, DPU_HW_BLK_DSPP, idx, &dpu_hw_ops);
return c;
}
void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp)
{
if (dspp)
dpu_hw_blk_destroy(&dspp->base);
kfree(dspp);
}
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*/
#ifndef _DPU_HW_DSPP_H
#define _DPU_HW_DSPP_H
#include "dpu_hw_blk.h"
struct dpu_hw_dspp;
/**
* struct dpu_hw_dspp_ops - interface to the dspp hardware driver functions
* Caller must call the init function to get the dspp context for each dspp
* Assumption is these functions will be called after clocks are enabled
*/
struct dpu_hw_dspp_ops {
void (*dummy)(struct dpu_hw_dspp *ctx);
};
/**
* struct dpu_hw_dspp - dspp description
* @base: Hardware block base structure
* @hw: Block hardware details
* @idx: DSPP index
* @cap: Pointer to layer_cfg
* @ops: Pointer to operations possible for this DSPP
*/
struct dpu_hw_dspp {
struct dpu_hw_blk base;
struct dpu_hw_blk_reg_map hw;
/* dspp */
int idx;
const struct dpu_dspp_cfg *cap;
/* Ops */
struct dpu_hw_dspp_ops ops;
};
/**
* dpu_hw_dspp - convert base object dpu_hw_base to container
* @hw: Pointer to base hardware block
* return: Pointer to hardware block container
*/
static inline struct dpu_hw_dspp *to_dpu_hw_dspp(struct dpu_hw_blk *hw)
{
return container_of(hw, struct dpu_hw_dspp, base);
}
/**
* dpu_hw_dspp_init - initializes the dspp hw driver object.
* should be called once before accessing every dspp.
* @idx: DSPP index for which driver object is required
* @addr: Mapped register io address of MDP
* @Return: pointer to structure or ERR_PTR
*/
struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx,
void __iomem *addr, const struct dpu_mdss_cfg *m);
/**
* dpu_hw_dspp_destroy(): Destroys DSPP driver context
* @dspp: Pointer to DSPP driver context
*/
void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp);
#endif /*_DPU_HW_DSPP_H */
......@@ -95,6 +95,7 @@ enum dpu_hw_blk_type {
DPU_HW_BLK_PINGPONG,
DPU_HW_BLK_INTF,
DPU_HW_BLK_WB,
DPU_HW_BLK_DSPP,
DPU_HW_BLK_MAX,
};
......@@ -425,5 +426,6 @@ struct dpu_mdss_color {
#define DPU_DBG_MASK_TOP (1 << 7)
#define DPU_DBG_MASK_VBIF (1 << 8)
#define DPU_DBG_MASK_ROT (1 << 9)
#define DPU_DBG_MASK_DSPP (1 << 10)
#endif /* _DPU_HW_MDSS_H */
......@@ -158,6 +158,7 @@ struct dpu_global_state {
uint32_t mixer_to_enc_id[LM_MAX - LM_0];
uint32_t ctl_to_enc_id[CTL_MAX - CTL_0];
uint32_t intf_to_enc_id[INTF_MAX - INTF_0];
uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0];
};
struct dpu_global_state
......
......@@ -9,6 +9,7 @@
#include "dpu_hw_ctl.h"
#include "dpu_hw_pingpong.h"
#include "dpu_hw_intf.h"
#include "dpu_hw_dspp.h"
#include "dpu_encoder.h"
#include "dpu_trace.h"
......@@ -174,6 +175,23 @@ int dpu_rm_init(struct dpu_rm *rm,
rm->ctl_blks[ctl->id - CTL_0] = &hw->base;
}
for (i = 0; i < cat->dspp_count; i++) {
struct dpu_hw_dspp *hw;
const struct dpu_dspp_cfg *dspp = &cat->dspp[i];
if (dspp->id < DSPP_0 || dspp->id >= DSPP_MAX) {
DPU_ERROR("skip dspp %d with invalid id\n", dspp->id);
continue;
}
hw = dpu_hw_dspp_init(dspp->id, mmio, cat);
if (IS_ERR_OR_NULL(hw)) {
rc = PTR_ERR(hw);
DPU_ERROR("failed dspp object creation: err %d\n", rc);
goto fail;
}
rm->dspp_blks[dspp->id - DSPP_0] = &hw->base;
}
return 0;
fail:
......@@ -222,12 +240,17 @@ static bool _dpu_rm_check_lm_peer(struct dpu_rm *rm, int primary_idx,
* if lm, and all other hardwired blocks connected to the lm (pp) is
* available and appropriate
* @pp_idx: output parameter, index of pingpong block attached to the layer
* mixer in rm->pongpong_blks[].
* mixer in rm->pingpong_blks[].
* @dspp_idx: output parameter, index of dspp block attached to the layer
* mixer in rm->dspp_blks[].
* @reqs: input parameter, rm requirements for HW blocks needed in the
* datapath.
* @Return: true if lm matches all requirements, false otherwise
*/
static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm,
struct dpu_global_state *global_state,
uint32_t enc_id, int lm_idx, int *pp_idx)
uint32_t enc_id, int lm_idx, int *pp_idx, int *dspp_idx,
struct dpu_rm_requirements *reqs)
{
const struct dpu_lm_cfg *lm_cfg;
int idx;
......@@ -251,6 +274,23 @@ static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm,
return false;
}
*pp_idx = idx;
if (!reqs->topology.num_dspp)
return true;
idx = lm_cfg->dspp - DSPP_0;
if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks)) {
DPU_ERROR("failed to get dspp on lm %d\n", lm_cfg->dspp);
return false;
}
if (reserved_by_other(global_state->dspp_to_enc_id, idx, enc_id)) {
DPU_DEBUG("lm %d dspp %d already reserved\n", lm_cfg->id,
lm_cfg->dspp);
return false;
}
*dspp_idx = idx;
return true;
}
......@@ -262,6 +302,7 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
{
int lm_idx[MAX_BLOCKS];
int pp_idx[MAX_BLOCKS];
int dspp_idx[MAX_BLOCKS] = {0};
int i, j, lm_count = 0;
if (!reqs->topology.num_lm) {
......@@ -279,7 +320,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
lm_idx[lm_count] = i;
if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state,
enc_id, i, &pp_idx[lm_count])) {
enc_id, i, &pp_idx[lm_count],
&dspp_idx[lm_count], reqs)) {
continue;
}
......@@ -299,7 +341,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
if (!_dpu_rm_check_lm_and_get_connected_blks(rm,
global_state, enc_id, j,
&pp_idx[lm_count])) {
&pp_idx[lm_count], &dspp_idx[lm_count],
reqs)) {
continue;
}
......@@ -316,6 +359,8 @@ static int _dpu_rm_reserve_lms(struct dpu_rm *rm,
for (i = 0; i < lm_count; i++) {
global_state->mixer_to_enc_id[lm_idx[i]] = enc_id;
global_state->pingpong_to_enc_id[pp_idx[i]] = enc_id;
global_state->dspp_to_enc_id[dspp_idx[i]] =
reqs->topology.num_dspp ? enc_id : 0;
trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id,
pp_idx[i] + PINGPONG_0);
......@@ -560,6 +605,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm,
hw_to_enc_id = global_state->intf_to_enc_id;
max_blks = ARRAY_SIZE(rm->intf_blks);
break;
case DPU_HW_BLK_DSPP:
hw_blks = rm->dspp_blks;
hw_to_enc_id = global_state->dspp_to_enc_id;
max_blks = ARRAY_SIZE(rm->dspp_blks);
break;
default:
DPU_ERROR("blk type %d not managed by rm\n", type);
return 0;
......
......@@ -19,6 +19,7 @@ struct dpu_global_state;
* @mixer_blks: array of layer mixer hardware resources
* @ctl_blks: array of ctl hardware resources
* @intf_blks: array of intf hardware resources
* @dspp_blks: array of dspp hardware resources
* @lm_max_width: cached layer mixer maximum width
* @rm_lock: resource manager mutex
*/
......@@ -27,6 +28,7 @@ struct dpu_rm {
struct dpu_hw_blk *mixer_blks[LM_MAX - LM_0];
struct dpu_hw_blk *ctl_blks[CTL_MAX - CTL_0];
struct dpu_hw_blk *intf_blks[INTF_MAX - INTF_0];
struct dpu_hw_blk *dspp_blks[DSPP_MAX - DSPP_0];
uint32_t lm_max_width;
};
......
......@@ -105,6 +105,7 @@ struct msm_display_topology {
u32 num_lm;
u32 num_enc;
u32 num_intf;
u32 num_dspp;
};
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment