Skip to content

Commit 1384cc0

Browse files
laeyraudChun-Kuang Hu
authored andcommitted
drm/mediatek: mtk_hdmi_ddc_v2: Fix multi-byte writes
Currently, the mtk_hdmi_ddc_v2 driver sends a i2c message by calling the mtk_ddc_wr_one function for each byte of the payload to setup SI2C_CTRL and DDC_CTRL registers, and perform a sequential write transfer of one byte at a time to the target device. This leads to incorrect transfers as the target address (at least) is also sent each time. So, rename mtk_ddc_wr_one function to mtk_ddcm_write_hdmi to match the read function name (mtk_ddcm_read_hdmi) and modify its behaviour to send all payload data in a single sequential write transfer by filling the transfer fifo first then starting the transfer with a size equal to the payload size and not one anymore. Fixes: 8d0f798 ("drm/mediatek: Introduce HDMI/DDC v2 for MT8195/MT8188") Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com> Link: https://patchwork.kernel.org/project/dri-devel/patch/20251205-mtk-hdmi-ddc-v2-fixes-v1-2-260dd0d320f4@collabora.com/ Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
1 parent 2788c96 commit 1384cc0

1 file changed

Lines changed: 23 additions & 25 deletions

File tree

drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,28 +66,41 @@ static int mtk_ddc_check_and_rise_low_bus(struct mtk_hdmi_ddc *ddc)
6666
return 0;
6767
}
6868

69-
static int mtk_ddc_wr_one(struct mtk_hdmi_ddc *ddc, u16 addr_id,
70-
u16 offset_id, u8 *wr_data)
69+
static int mtk_ddcm_write_hdmi(struct mtk_hdmi_ddc *ddc, u16 addr_id,
70+
u16 offset_id, u16 data_cnt, u8 *wr_data)
7171
{
7272
u32 val;
73-
int ret;
73+
int ret, i;
74+
75+
/* Don't allow transfer with a size over than the transfer fifo size
76+
* (16 byte)
77+
*/
78+
if (data_cnt > 16) {
79+
dev_err(ddc->dev, "Invalid DDCM write request\n");
80+
return -EINVAL;
81+
}
7482

7583
/* If down, rise bus for write operation */
7684
mtk_ddc_check_and_rise_low_bus(ddc);
7785

7886
regmap_update_bits(ddc->regs, HPD_DDC_CTRL, HPD_DDC_DELAY_CNT,
7987
FIELD_PREP(HPD_DDC_DELAY_CNT, DDC2_DLY_CNT));
8088

89+
/* In case there is no payload data, just do a single write for the
90+
* address only
91+
*/
8192
if (wr_data) {
82-
regmap_write(ddc->regs, SI2C_CTRL,
83-
FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
84-
FIELD_PREP(SI2C_WDATA, *wr_data) |
85-
SI2C_WR);
93+
/* Fill transfer fifo with payload data */
94+
for (i = 0; i < data_cnt; i++) {
95+
regmap_write(ddc->regs, SI2C_CTRL,
96+
FIELD_PREP(SI2C_ADDR, SI2C_ADDR_READ) |
97+
FIELD_PREP(SI2C_WDATA, wr_data[i]) |
98+
SI2C_WR);
99+
}
86100
}
87-
88101
regmap_write(ddc->regs, DDC_CTRL,
89102
FIELD_PREP(DDC_CTRL_CMD, DDC_CMD_SEQ_WRITE) |
90-
FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : 1) |
103+
FIELD_PREP(DDC_CTRL_DIN_CNT, wr_data == NULL ? 0 : data_cnt) |
91104
FIELD_PREP(DDC_CTRL_OFFSET, offset_id) |
92105
FIELD_PREP(DDC_CTRL_ADDR, addr_id));
93106
usleep_range(1000, 1250);
@@ -260,24 +273,9 @@ static int mtk_hdmi_fg_ddc_data_read(struct mtk_hdmi_ddc *ddc, u16 b_dev,
260273
static int mtk_hdmi_ddc_fg_data_write(struct mtk_hdmi_ddc *ddc, u16 b_dev,
261274
u8 data_addr, u16 data_cnt, u8 *pr_data)
262275
{
263-
int i, ret;
264-
265276
regmap_set_bits(ddc->regs, HDCP2X_POL_CTRL, HDCP2X_DIS_POLL_EN);
266-
/*
267-
* In case there is no payload data, just do a single write for the
268-
* address only
269-
*/
270-
if (data_cnt == 0)
271-
return mtk_ddc_wr_one(ddc, b_dev, data_addr, NULL);
272-
273-
i = 0;
274-
do {
275-
ret = mtk_ddc_wr_one(ddc, b_dev, data_addr + i, pr_data + i);
276-
if (ret)
277-
return ret;
278-
} while (++i < data_cnt);
279277

280-
return 0;
278+
return mtk_ddcm_write_hdmi(ddc, b_dev, data_addr, data_cnt, pr_data);
281279
}
282280

283281
static int mtk_hdmi_ddc_v2_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)

0 commit comments

Comments
 (0)