Skip to content

Commit 5306b3f

Browse files
Hsiao Chien SungChun-Kuang Hu
authored andcommitted
drm/mediatek: Filter modes according to hardware capability
We found a stability issue on MT8188 when connecting an external monitor in 2560x1440@144Hz mode. Checked with the designer, there is a function called "prefetch" which is working during VBP (triggered by VSYNC). If the duration of VBP is too short, the throughput requirement could increase more than 3 times and lead to stability issues. The mode settings that VDOSYS supports are mainly affected by clock rate and throughput, display driver should filter these settings according to the SoC's limitation to avoid unstable conditions. Since currently the mode filter is only available on MT8195 and MT8188 and they share the same compatible name, the reference number (8250) is hard coded instead of in the driver data. Signed-off-by: Hsiao Chien Sung <shawn.sung@mediatek.corp-partner.google.com> Reviewed-by: CK Hu <ck.hu@mediatek.com> Link: https://patchwork.kernel.org/project/dri-devel/patch/20240220093711.20546-2-shawn.sung@mediatek.com/ Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
1 parent e14cba9 commit 5306b3f

File tree

6 files changed

+116
-0
lines changed

6 files changed

+116
-0
lines changed

drivers/gpu/drm/mediatek/mtk_disp_drv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int
7373
struct cmdq_pkt *cmdq_pkt);
7474
void mtk_merge_start_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
7575
void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
76+
enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
77+
const struct drm_display_mode *mode);
7678

7779
void mtk_ovl_bgclr_in_on(struct device *dev);
7880
void mtk_ovl_bgclr_in_off(struct device *dev);
@@ -131,6 +133,8 @@ unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev);
131133
struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev);
132134
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev);
133135
size_t mtk_ovl_adaptor_get_num_formats(struct device *dev);
136+
enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
137+
const struct drm_display_mode *mode);
134138

135139
void mtk_rdma_bypass_shadow(struct device *dev);
136140
int mtk_rdma_clk_enable(struct device *dev);

drivers/gpu/drm/mediatek/mtk_disp_merge.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,71 @@ void mtk_merge_clk_disable(struct device *dev)
222222
clk_disable_unprepare(priv->clk);
223223
}
224224

225+
enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
226+
const struct drm_display_mode *mode)
227+
{
228+
struct mtk_disp_merge *priv = dev_get_drvdata(dev);
229+
unsigned long rate;
230+
231+
rate = clk_get_rate(priv->clk);
232+
233+
/* Convert to KHz and round the number */
234+
rate = (rate + 500) / 1000;
235+
236+
if (rate && mode->clock > rate) {
237+
dev_dbg(dev, "invalid clock: %d (>%lu)\n", mode->clock, rate);
238+
return MODE_CLOCK_HIGH;
239+
}
240+
241+
/*
242+
* Measure the bandwidth requirement of hardware prefetch (per frame)
243+
*
244+
* let N = prefetch buffer size in lines
245+
* (ex. N=3, then prefetch buffer size = 3 lines)
246+
*
247+
* prefetch size = htotal * N (pixels)
248+
* time per line = 1 / fps / vtotal (seconds)
249+
* duration = vbp * time per line
250+
* = vbp / fps / vtotal
251+
*
252+
* data rate = prefetch size / duration
253+
* = htotal * N / (vbp / fps / vtotal)
254+
* = htotal * vtotal * fps * N / vbp
255+
* = clk * N / vbp (pixels per second)
256+
*
257+
* Say 4K60 (CEA-861) is the maximum mode supported by the SoC
258+
* data rate = 594000K * N / 72 = 8250 (standard)
259+
* (remove K * N due to the same unit)
260+
*
261+
* For 2560x1440@144 (clk=583600K, vbp=17):
262+
* data rate = 583600 / 17 ~= 34329 > 8250 (NG)
263+
*
264+
* For 2560x1440@120 (clk=497760K, vbp=77):
265+
* data rate = 497760 / 77 ~= 6464 < 8250 (OK)
266+
*
267+
* A non-standard 4K60 timing (clk=521280K, vbp=54)
268+
* data rate = 521280 / 54 ~= 9653 > 8250 (NG)
269+
*
270+
* Bandwidth requirement of hardware prefetch increases significantly
271+
* when the VBP decreases (more than 4x in this example).
272+
*
273+
* The proposed formula is only one way to estimate whether our SoC
274+
* supports the mode setting. The basic idea behind it is just to check
275+
* if the data rate requirement is too high (directly proportional to
276+
* pixel clock, inversely proportional to vbp). Please adjust the
277+
* function if it doesn't fit your situation in the future.
278+
*/
279+
rate = mode->clock / (mode->vtotal - mode->vsync_end);
280+
281+
if (rate > 8250) {
282+
dev_dbg(dev, "invalid rate: %lu (>8250): " DRM_MODE_FMT "\n",
283+
rate, DRM_MODE_ARG(mode));
284+
return MODE_BAD;
285+
}
286+
287+
return MODE_OK;
288+
}
289+
225290
static int mtk_disp_merge_bind(struct device *dev, struct device *master,
226291
void *data)
227292
{

drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static const struct mtk_ddp_comp_funcs ethdr = {
8989
static const struct mtk_ddp_comp_funcs merge = {
9090
.clk_enable = mtk_merge_clk_enable,
9191
.clk_disable = mtk_merge_clk_disable,
92+
.mode_valid = mtk_merge_mode_valid,
9293
};
9394

9495
static const struct mtk_ddp_comp_funcs padding = {
@@ -342,6 +343,22 @@ void mtk_ovl_adaptor_clk_disable(struct device *dev)
342343
}
343344
}
344345

346+
enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
347+
const struct drm_display_mode *mode)
348+
349+
{
350+
int i;
351+
struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
352+
353+
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
354+
dev = ovl_adaptor->ovl_adaptor_comp[i];
355+
if (!dev || !comp_matches[i].funcs->mode_valid)
356+
continue;
357+
return comp_matches[i].funcs->mode_valid(dev, mode);
358+
}
359+
return MODE_OK;
360+
}
361+
345362
unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev)
346363
{
347364
return MTK_OVL_ADAPTOR_LAYER_NUM;

drivers/gpu/drm/mediatek/mtk_drm_crtc.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,22 @@ static void mtk_drm_crtc_destroy_state(struct drm_crtc *crtc,
213213
kfree(to_mtk_crtc_state(state));
214214
}
215215

216+
static enum drm_mode_status
217+
mtk_drm_crtc_mode_valid(struct drm_crtc *crtc,
218+
const struct drm_display_mode *mode)
219+
{
220+
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
221+
enum drm_mode_status status = MODE_OK;
222+
int i;
223+
224+
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
225+
status = mtk_ddp_comp_mode_valid(mtk_crtc->ddp_comp[i], mode);
226+
if (status != MODE_OK)
227+
break;
228+
}
229+
return status;
230+
}
231+
216232
static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc,
217233
const struct drm_display_mode *mode,
218234
struct drm_display_mode *adjusted_mode)
@@ -831,6 +847,7 @@ static const struct drm_crtc_funcs mtk_crtc_funcs = {
831847
static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
832848
.mode_fixup = mtk_drm_crtc_mode_fixup,
833849
.mode_set_nofb = mtk_drm_crtc_mode_set_nofb,
850+
.mode_valid = mtk_drm_crtc_mode_valid,
834851
.atomic_begin = mtk_drm_crtc_atomic_begin,
835852
.atomic_flush = mtk_drm_crtc_atomic_flush,
836853
.atomic_enable = mtk_drm_crtc_atomic_enable,

drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
418418
.remove = mtk_ovl_adaptor_remove_comp,
419419
.get_formats = mtk_ovl_adaptor_get_formats,
420420
.get_num_formats = mtk_ovl_adaptor_get_num_formats,
421+
.mode_valid = mtk_ovl_adaptor_mode_valid,
421422
};
422423

423424
static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {

drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <linux/soc/mediatek/mtk-mmsys.h>
1313
#include <linux/soc/mediatek/mtk-mutex.h>
1414

15+
#include <drm/drm_modes.h>
16+
1517
struct device;
1618
struct device_node;
1719
struct drm_crtc;
@@ -85,6 +87,7 @@ struct mtk_ddp_comp_funcs {
8587
void (*add)(struct device *dev, struct mtk_mutex *mutex);
8688
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
8789
unsigned int (*encoder_index)(struct device *dev);
90+
enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode);
8891
};
8992

9093
struct mtk_ddp_comp {
@@ -126,6 +129,15 @@ static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp)
126129
comp->funcs->clk_disable(comp->dev);
127130
}
128131

132+
static inline
133+
enum drm_mode_status mtk_ddp_comp_mode_valid(struct mtk_ddp_comp *comp,
134+
const struct drm_display_mode *mode)
135+
{
136+
if (comp && comp->funcs && comp->funcs->mode_valid)
137+
return comp->funcs->mode_valid(comp->dev, mode);
138+
return MODE_OK;
139+
}
140+
129141
static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
130142
unsigned int w, unsigned int h,
131143
unsigned int vrefresh, unsigned int bpc,

0 commit comments

Comments
 (0)