Skip to content

Commit ea5e704

Browse files
Mark Yaorkhuangtao
authored andcommitted
drm/rockchip: add cabc support
CABC(Content Adaptive Backlight Control) is used to increase the contrast of such LCD-screens the backlight can be (globally) dimmed when the image to be displayed is dark (i.e. not comprising high intensity image data) while the image data is numerically corrected and adapted to the reduced backlight intensity. Change-Id: I0bd84375264675943f1b601f0cac8b843567087d Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
1 parent b7bf509 commit ea5e704

5 files changed

Lines changed: 300 additions & 0 deletions

File tree

drivers/gpu/drm/rockchip/rockchip_drm_drv.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,54 @@ static void rockchip_drm_debugfs_cleanup(struct drm_minor *minor)
953953
}
954954
#endif
955955

956+
static int rockchip_drm_create_properties(struct drm_device *dev)
957+
{
958+
struct drm_property *prop;
959+
struct rockchip_drm_private *private = dev->dev_private;
960+
const struct drm_prop_enum_list cabc_mode_enum_list[] = {
961+
{ ROCKCHIP_DRM_CABC_MODE_DISABLE, "Disable" },
962+
{ ROCKCHIP_DRM_CABC_MODE_NORMAL, "Normal" },
963+
{ ROCKCHIP_DRM_CABC_MODE_LOWPOWER, "LowPower" },
964+
{ ROCKCHIP_DRM_CABC_MODE_USERSPACE, "Userspace" },
965+
};
966+
967+
prop = drm_property_create_enum(dev, 0, "CABC_MODE", cabc_mode_enum_list,
968+
ARRAY_SIZE(cabc_mode_enum_list));
969+
970+
private->cabc_mode_property = prop;
971+
972+
prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CABC_LUT", 0);
973+
if (!prop)
974+
return -ENOMEM;
975+
private->cabc_lut_property = prop;
976+
977+
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
978+
"CABC_STAGE_UP", 0, 512);
979+
if (!prop)
980+
return -ENOMEM;
981+
private->cabc_stage_up_property = prop;
982+
983+
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
984+
"CABC_STAGE_DOWN", 0, 255);
985+
if (!prop)
986+
return -ENOMEM;
987+
private->cabc_stage_down_property = prop;
988+
989+
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
990+
"CABC_GLOBAL_DN", 0, 255);
991+
if (!prop)
992+
return -ENOMEM;
993+
private->cabc_global_dn_property = prop;
994+
995+
prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
996+
"CABC_CALC_PIXEL_NUM", 0, 1000);
997+
if (!prop)
998+
return -ENOMEM;
999+
private->cabc_calc_pixel_num_property = prop;
1000+
1001+
return 0;
1002+
}
1003+
9561004
static int rockchip_drm_bind(struct device *dev)
9571005
{
9581006
struct drm_device *drm_dev;
@@ -1012,6 +1060,7 @@ static int rockchip_drm_bind(struct device *dev)
10121060
drm_mode_config_init(drm_dev);
10131061

10141062
rockchip_drm_mode_config_init(drm_dev);
1063+
rockchip_drm_create_properties(drm_dev);
10151064

10161065
ret = rockchip_drm_init_iommu(drm_dev);
10171066
if (ret)

drivers/gpu/drm/rockchip/rockchip_drm_drv.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct rockchip_dclk_pll {
7575

7676
struct rockchip_crtc_state {
7777
struct drm_crtc_state base;
78+
struct drm_property_blob *cabc_lut;
7879
struct rockchip_dclk_pll *pll;
7980
int left_margin;
8081
int right_margin;
@@ -86,6 +87,11 @@ struct rockchip_crtc_state {
8687
int afbdc_win_ptr;
8788
int afbdc_win_id;
8889
int afbdc_en;
90+
int cabc_mode;
91+
int cabc_stage_up;
92+
int cabc_stage_down;
93+
int cabc_global_dn;
94+
int cabc_calc_pixel_num;
8995
int dsp_layer_sel;
9096
int output_type;
9197
int output_mode;
@@ -126,6 +132,13 @@ struct rockchip_logo {
126132
struct rockchip_drm_private {
127133
struct rockchip_logo *logo;
128134
struct drm_property *logo_ymirror_prop;
135+
struct drm_property *cabc_mode_property;
136+
struct drm_property *cabc_lut_property;
137+
struct drm_property *cabc_stage_up_property;
138+
struct drm_property *cabc_stage_down_property;
139+
struct drm_property *cabc_global_dn_property;
140+
struct drm_property *cabc_calc_pixel_num_property;
141+
void *backlight;
129142
struct drm_fb_helper *fbdev_helper;
130143
struct drm_gem_object *fbdev_bo;
131144
const struct rockchip_crtc_funcs *crtc_funcs[ROCKCHIP_MAX_CRTC];

drivers/gpu/drm/rockchip/rockchip_drm_vop.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ struct vop {
206206
u32 *lut;
207207
u32 lut_len;
208208
bool lut_active;
209+
void __iomem *cabc_lut_regs;
210+
u32 cabc_lut_len;
209211

210212
/* one time only one process allowed to config the register */
211213
spinlock_t reg_lock;
@@ -353,6 +355,11 @@ static inline uint32_t vop_read_lut(struct vop *vop, uint32_t offset)
353355
return readl(vop->lut_regs + offset);
354356
}
355357

358+
static inline void vop_write_cabc_lut(struct vop *vop, uint32_t offset, uint32_t v)
359+
{
360+
writel(v, vop->cabc_lut_regs + offset);
361+
}
362+
356363
static bool has_rb_swapped(uint32_t format)
357364
{
358365
switch (format) {
@@ -1795,6 +1802,13 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
17951802
VOP_CTRL_SET(vop, core_dclk_div,
17961803
!!(adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK));
17971804

1805+
VOP_CTRL_SET(vop, cabc_total_num, hdisplay * vdisplay);
1806+
VOP_CTRL_SET(vop, cabc_config_mode, STAGE_BY_STAGE);
1807+
VOP_CTRL_SET(vop, cabc_stage_up_mode, MUL_MODE);
1808+
VOP_CTRL_SET(vop, cabc_scale_cfg_value, 1);
1809+
VOP_CTRL_SET(vop, cabc_scale_cfg_enable, 0);
1810+
VOP_CTRL_SET(vop, cabc_global_dn_limit_en, 1);
1811+
17981812
clk_set_rate(vop->dclk, adjusted_mode->crtc_clock * 1000);
17991813

18001814
vop_cfg_done(vop);
@@ -2041,6 +2055,86 @@ static void vop_post_config(struct drm_crtc *crtc)
20412055
}
20422056
}
20432057

2058+
static void vop_update_cabc_lut(struct drm_crtc *crtc,
2059+
struct drm_crtc_state *old_crtc_state)
2060+
{
2061+
struct rockchip_crtc_state *s =
2062+
to_rockchip_crtc_state(crtc->state);
2063+
struct rockchip_crtc_state *old_s =
2064+
to_rockchip_crtc_state(old_crtc_state);
2065+
struct drm_property_blob *cabc_lut = s->cabc_lut;
2066+
struct drm_property_blob *old_cabc_lut = old_s->cabc_lut;
2067+
struct vop *vop = to_vop(crtc);
2068+
int lut_size;
2069+
u32 *lut;
2070+
u32 lut_len = vop->cabc_lut_len;
2071+
int i, dle;
2072+
2073+
if (!cabc_lut && old_cabc_lut) {
2074+
VOP_CTRL_SET(vop, cabc_lut_en, 0);
2075+
return;
2076+
}
2077+
if (!cabc_lut)
2078+
return;
2079+
2080+
if (old_cabc_lut && old_cabc_lut->base.id == cabc_lut->base.id)
2081+
return;
2082+
2083+
lut = (u32 *)cabc_lut->data;
2084+
lut_size = cabc_lut->length / sizeof(u32);
2085+
if (WARN(lut_size != lut_len, "Unexpect cabc lut size not match\n"))
2086+
return;
2087+
2088+
#define CTRL_GET(name) VOP_CTRL_GET(vop, name)
2089+
if (CTRL_GET(cabc_lut_en)) {
2090+
VOP_CTRL_SET(vop, cabc_lut_en, 0);
2091+
vop_cfg_done(vop);
2092+
readx_poll_timeout(CTRL_GET, cabc_lut_en, dle, !dle, 5, 33333);
2093+
}
2094+
2095+
for (i = 0; i < lut_len; i++)
2096+
vop_write_cabc_lut(vop, (i << 2), lut[i]);
2097+
#undef CTRL_GET
2098+
VOP_CTRL_SET(vop, cabc_lut_en, 1);
2099+
}
2100+
2101+
static void vop_update_cabc(struct drm_crtc *crtc,
2102+
struct drm_crtc_state *old_crtc_state)
2103+
{
2104+
struct rockchip_crtc_state *s =
2105+
to_rockchip_crtc_state(crtc->state);
2106+
struct vop *vop = to_vop(crtc);
2107+
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
2108+
int pixel_total = mode->hdisplay * mode->vdisplay;
2109+
2110+
if (!vop->cabc_lut_regs)
2111+
return;
2112+
2113+
vop_update_cabc_lut(crtc, old_crtc_state);
2114+
2115+
if (s->cabc_mode != ROCKCHIP_DRM_CABC_MODE_DISABLE) {
2116+
VOP_CTRL_SET(vop, cabc_en, 1);
2117+
VOP_CTRL_SET(vop, cabc_handle_en, 1);
2118+
VOP_CTRL_SET(vop, cabc_stage_up, s->cabc_stage_up);
2119+
VOP_CTRL_SET(vop, cabc_stage_down, s->cabc_stage_down);
2120+
VOP_CTRL_SET(vop, cabc_global_dn, s->cabc_global_dn);
2121+
VOP_CTRL_SET(vop, cabc_calc_pixel_num,
2122+
s->cabc_calc_pixel_num * pixel_total / 1000);
2123+
} else {
2124+
/*
2125+
* There are some hardware issues on cabc disabling:
2126+
* 1: if cabc auto gating enable, cabc disabling will cause
2127+
* vop die
2128+
* 2: cabc disabling always would make timing several
2129+
* pixel cycle abnormal, cause some panel abnormal.
2130+
*
2131+
* So just keep cabc enable, and make it no work with max
2132+
* cabc_calc_pixel_num, it only has little power consume.
2133+
*/
2134+
VOP_CTRL_SET(vop, cabc_calc_pixel_num, pixel_total);
2135+
}
2136+
}
2137+
20442138
static void vop_cfg_update(struct drm_crtc *crtc,
20452139
struct drm_crtc_state *old_crtc_state)
20462140
{
@@ -2147,6 +2241,8 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
21472241
vop->is_iommu_enabled = true;
21482242
}
21492243

2244+
vop_update_cabc(crtc, old_crtc_state);
2245+
21502246
vop_cfg_done(vop);
21512247

21522248
/*
@@ -2262,6 +2358,7 @@ static int vop_crtc_atomic_get_property(struct drm_crtc *crtc,
22622358
uint64_t *val)
22632359
{
22642360
struct drm_device *drm_dev = crtc->dev;
2361+
struct rockchip_drm_private *private = drm_dev->dev_private;
22652362
struct drm_mode_config *mode_config = &drm_dev->mode_config;
22662363
struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
22672364

@@ -2285,6 +2382,36 @@ static int vop_crtc_atomic_get_property(struct drm_crtc *crtc,
22852382
return 0;
22862383
}
22872384

2385+
if (property == private->cabc_mode_property) {
2386+
*val = s->cabc_mode;
2387+
return 0;
2388+
}
2389+
2390+
if (property == private->cabc_stage_up_property) {
2391+
*val = s->cabc_stage_up;
2392+
return 0;
2393+
}
2394+
2395+
if (property == private->cabc_stage_down_property) {
2396+
*val = s->cabc_stage_down;
2397+
return 0;
2398+
}
2399+
2400+
if (property == private->cabc_global_dn_property) {
2401+
*val = s->cabc_global_dn;
2402+
return 0;
2403+
}
2404+
2405+
if (property == private->cabc_calc_pixel_num_property) {
2406+
*val = s->cabc_calc_pixel_num;
2407+
return 0;
2408+
}
2409+
2410+
if (property == private->cabc_lut_property) {
2411+
*val = s->cabc_lut ? s->cabc_lut->base.id : 0;
2412+
return 0;
2413+
}
2414+
22882415
DRM_ERROR("failed to get vop crtc property\n");
22892416
return -EINVAL;
22902417
}
@@ -2295,8 +2422,10 @@ static int vop_crtc_atomic_set_property(struct drm_crtc *crtc,
22952422
uint64_t val)
22962423
{
22972424
struct drm_device *drm_dev = crtc->dev;
2425+
struct rockchip_drm_private *private = drm_dev->dev_private;
22982426
struct drm_mode_config *mode_config = &drm_dev->mode_config;
22992427
struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
2428+
struct vop *vop = to_vop(crtc);
23002429

23012430
if (property == mode_config->tv_left_margin_property) {
23022431
s->left_margin = val;
@@ -2318,6 +2447,57 @@ static int vop_crtc_atomic_set_property(struct drm_crtc *crtc,
23182447
return 0;
23192448
}
23202449

2450+
if (property == private->cabc_mode_property) {
2451+
s->cabc_mode = val;
2452+
/*
2453+
* Pre-define lowpower and normal mode to make cabc
2454+
* easier to use.
2455+
*/
2456+
if (s->cabc_mode == ROCKCHIP_DRM_CABC_MODE_NORMAL) {
2457+
s->cabc_stage_up = 257;
2458+
s->cabc_stage_down = 255;
2459+
s->cabc_global_dn = 192;
2460+
s->cabc_calc_pixel_num = 995;
2461+
} else if (s->cabc_mode == ROCKCHIP_DRM_CABC_MODE_LOWPOWER) {
2462+
s->cabc_stage_up = 260;
2463+
s->cabc_stage_down = 252;
2464+
s->cabc_global_dn = 180;
2465+
s->cabc_calc_pixel_num = 992;
2466+
}
2467+
return 0;
2468+
}
2469+
2470+
if (property == private->cabc_stage_up_property) {
2471+
s->cabc_stage_up = val;
2472+
return 0;
2473+
}
2474+
2475+
if (property == private->cabc_stage_down_property) {
2476+
s->cabc_stage_down = val;
2477+
return 0;
2478+
}
2479+
2480+
if (property == private->cabc_calc_pixel_num_property) {
2481+
s->cabc_calc_pixel_num = val;
2482+
return 0;
2483+
}
2484+
2485+
if (property == private->cabc_global_dn_property) {
2486+
s->cabc_global_dn = val;
2487+
return 0;
2488+
}
2489+
2490+
if (property == private->cabc_lut_property) {
2491+
bool replaced;
2492+
ssize_t size = vop->cabc_lut_len * 4;
2493+
2494+
return drm_atomic_replace_property_blob_from_id(crtc,
2495+
&s->cabc_lut,
2496+
val,
2497+
size,
2498+
&replaced);
2499+
}
2500+
23212501
DRM_ERROR("failed to set vop crtc property\n");
23222502
return -EINVAL;
23232503
}
@@ -2502,6 +2682,7 @@ static int vop_create_crtc(struct vop *vop)
25022682
struct device *dev = vop->dev;
25032683
const struct vop_data *vop_data = vop->data;
25042684
struct drm_device *drm_dev = vop->drm_dev;
2685+
struct rockchip_drm_private *private = drm_dev->dev_private;
25052686
struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp;
25062687
struct drm_crtc *crtc = &vop->crtc;
25072688
struct device_node *port;
@@ -2582,8 +2763,16 @@ static int vop_create_crtc(struct vop *vop)
25822763
VOP_ATTACH_MODE_CONFIG_PROP(tv_right_margin_property, 100);
25832764
VOP_ATTACH_MODE_CONFIG_PROP(tv_top_margin_property, 100);
25842765
VOP_ATTACH_MODE_CONFIG_PROP(tv_bottom_margin_property, 100);
2766+
25852767
#undef VOP_ATTACH_MODE_CONFIG_PROP
25862768

2769+
drm_object_attach_property(&crtc->base, private->cabc_lut_property, 0);
2770+
drm_object_attach_property(&crtc->base, private->cabc_mode_property, 0);
2771+
drm_object_attach_property(&crtc->base, private->cabc_stage_up_property, 0);
2772+
drm_object_attach_property(&crtc->base, private->cabc_stage_down_property, 0);
2773+
drm_object_attach_property(&crtc->base, private->cabc_global_dn_property, 0);
2774+
drm_object_attach_property(&crtc->base, private->cabc_calc_pixel_num_property, 0);
2775+
25872776
if (vop_data->feature & VOP_FEATURE_AFBDC)
25882777
feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_AFBDC);
25892778
drm_object_attach_property(&crtc->base, vop->feature_prop,
@@ -2880,6 +3069,22 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
28803069
}
28813070
}
28823071

3072+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cabc_lut");
3073+
vop->cabc_lut_regs = devm_ioremap_resource(dev, res);
3074+
if (IS_ERR(vop->cabc_lut_regs)) {
3075+
dev_warn(vop->dev, "failed to get vop cabc lut registers\n");
3076+
vop->cabc_lut_regs = NULL;
3077+
}
3078+
3079+
if (vop->cabc_lut_regs) {
3080+
vop->cabc_lut_len = resource_size(res) >> 2;
3081+
if (vop->cabc_lut_len != 128) {
3082+
dev_err(vop->dev, "unsupport cabc lut sizes %d\n",
3083+
vop->cabc_lut_len);
3084+
return -EINVAL;
3085+
}
3086+
}
3087+
28833088
vop->hclk = devm_clk_get(vop->dev, "hclk_vop");
28843089
if (IS_ERR(vop->hclk)) {
28853090
dev_err(vop->dev, "failed to get hclk source\n");

0 commit comments

Comments
 (0)