Skip to content

Commit 28b7c8a

Browse files
AngeloGioacchino Del RegnoChun-Kuang Hu
authored andcommitted
drm/mediatek: mtk_hdmi_v2: Add debugfs ops and implement ABIST
Implement the Automated Built-In Self-Test ABIST functionality provided by the HDMIv2 IP and expose it through the "hdmi_abist" debugfs file. Write "1" to this file to activate ABIST, or "0" to deactivate. The ABIST functionality can be used to validate that the HDMI Transmitter itself works and that can output a valid image to the HDMI Display that is connected. This is especially useful when trying to rule out any possible issue that is related to the display pipeline, as the HDMI Tx is always the last component; this means that HDMI ABIST can be used even without prior display controller pipeline configuration. The expected output is a 100% color bar (rainbow) test pattern. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Reviewed-by: CK Hu <ck.hu@mediatek.com> Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com> Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20251023-mediatek-drm-hdmi-v2-v11-10-7873ec4a1edf@collabora.com/ Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
1 parent 8d0f798 commit 28b7c8a

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

drivers/gpu/drm/mediatek/mtk_hdmi_v2.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,128 @@ static int mtk_hdmi_v2_hdmi_write_infoframe(struct drm_bridge *bridge,
11901190
return 0;
11911191
}
11921192

1193+
static int mtk_hdmi_v2_set_abist(struct mtk_hdmi *hdmi, bool enable)
1194+
{
1195+
struct drm_display_mode *mode = &hdmi->mode;
1196+
int abist_format = -EINVAL;
1197+
bool interlaced;
1198+
1199+
if (!enable) {
1200+
regmap_clear_bits(hdmi->regs, TOP_CFG00, HDMI_ABIST_ENABLE);
1201+
return 0;
1202+
}
1203+
1204+
if (!mode->hdisplay || !mode->vdisplay)
1205+
return -EINVAL;
1206+
1207+
interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
1208+
1209+
switch (mode->hdisplay) {
1210+
case 720:
1211+
if (mode->vdisplay == 480)
1212+
abist_format = 2;
1213+
else if (mode->vdisplay == 576)
1214+
abist_format = 11;
1215+
break;
1216+
case 1280:
1217+
if (mode->vdisplay == 720)
1218+
abist_format = 3;
1219+
break;
1220+
case 1440:
1221+
if (mode->vdisplay == 480)
1222+
abist_format = interlaced ? 5 : 9;
1223+
else if (mode->vdisplay == 576)
1224+
abist_format = interlaced ? 14 : 18;
1225+
break;
1226+
case 1920:
1227+
if (mode->vdisplay == 1080)
1228+
abist_format = interlaced ? 4 : 10;
1229+
break;
1230+
case 3840:
1231+
if (mode->vdisplay == 2160)
1232+
abist_format = 25;
1233+
break;
1234+
case 4096:
1235+
if (mode->vdisplay == 2160)
1236+
abist_format = 26;
1237+
break;
1238+
default:
1239+
break;
1240+
}
1241+
if (abist_format < 0)
1242+
return abist_format;
1243+
1244+
regmap_update_bits(hdmi->regs, TOP_CFG00, HDMI_ABIST_VIDEO_FORMAT,
1245+
FIELD_PREP(HDMI_ABIST_VIDEO_FORMAT, abist_format));
1246+
regmap_set_bits(hdmi->regs, TOP_CFG00, HDMI_ABIST_ENABLE);
1247+
return 0;
1248+
}
1249+
1250+
static int mtk_hdmi_v2_debug_abist_show(struct seq_file *m, void *arg)
1251+
{
1252+
struct mtk_hdmi *hdmi = m->private;
1253+
bool en;
1254+
u32 val;
1255+
int ret;
1256+
1257+
if (!hdmi)
1258+
return -EINVAL;
1259+
1260+
ret = regmap_read(hdmi->regs, TOP_CFG00, &val);
1261+
if (ret)
1262+
return ret;
1263+
1264+
en = FIELD_GET(HDMI_ABIST_ENABLE, val);
1265+
1266+
seq_printf(m, "HDMI Automated Built-In Self Test: %s\n",
1267+
en ? "Enabled" : "Disabled");
1268+
1269+
return 0;
1270+
}
1271+
1272+
static ssize_t mtk_hdmi_v2_debug_abist_write(struct file *file,
1273+
const char __user *ubuf,
1274+
size_t len, loff_t *offp)
1275+
{
1276+
struct seq_file *m = file->private_data;
1277+
int ret;
1278+
u32 en;
1279+
1280+
if (!m || !m->private || *offp)
1281+
return -EINVAL;
1282+
1283+
ret = kstrtouint_from_user(ubuf, len, 0, &en);
1284+
if (ret)
1285+
return ret;
1286+
1287+
if (en < 0 || en > 1)
1288+
return -EINVAL;
1289+
1290+
mtk_hdmi_v2_set_abist((struct mtk_hdmi *)m->private, en);
1291+
return len;
1292+
}
1293+
1294+
static int mtk_hdmi_v2_debug_abist_open(struct inode *inode, struct file *file)
1295+
{
1296+
return single_open(file, mtk_hdmi_v2_debug_abist_show, inode->i_private);
1297+
}
1298+
1299+
static const struct file_operations mtk_hdmi_debug_abist_fops = {
1300+
.owner = THIS_MODULE,
1301+
.open = mtk_hdmi_v2_debug_abist_open,
1302+
.read = seq_read,
1303+
.write = mtk_hdmi_v2_debug_abist_write,
1304+
.llseek = seq_lseek,
1305+
.release = single_release,
1306+
};
1307+
1308+
static void mtk_hdmi_v2_debugfs_init(struct drm_bridge *bridge, struct dentry *root)
1309+
{
1310+
struct mtk_hdmi *dpi = hdmi_ctx_from_bridge(bridge);
1311+
1312+
debugfs_create_file("hdmi_abist", 0640, root, dpi, &mtk_hdmi_debug_abist_fops);
1313+
}
1314+
11931315
static const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs = {
11941316
.attach = mtk_hdmi_v2_bridge_attach,
11951317
.detach = mtk_hdmi_v2_bridge_detach,
@@ -1209,6 +1331,7 @@ static const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs = {
12091331
.hdmi_tmds_char_rate_valid = mtk_hdmi_v2_hdmi_tmds_char_rate_valid,
12101332
.hdmi_clear_infoframe = mtk_hdmi_v2_hdmi_clear_infoframe,
12111333
.hdmi_write_infoframe = mtk_hdmi_v2_hdmi_write_infoframe,
1334+
.debugfs_init = mtk_hdmi_v2_debugfs_init,
12121335
};
12131336

12141337
/*

0 commit comments

Comments
 (0)