Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/mcde: Retry DSI read/write transactions

The vendor driver makes a few retries on read DSI
transactions, something that is needed especially in
case of read (such as reading the panel MTP ID) while
the panel is running in video mode. This happens on
the Samsung s6e63m0 panel on the Golden device.

Retry reads and writes alike three times.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Stephan Gerhold <stephan@gerhold.net>
Cc: Stephan Gerhold <stephan@gerhold.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20200814194451.3494294-1-linus.walleij@linaro.org

+92 -66
+92 -66
drivers/gpu/drm/mcde/mcde_dsi.c
··· 208 208 (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \ 209 209 (type == MIPI_DSI_DCS_READ)) 210 210 211 + static int mcde_dsi_execute_transfer(struct mcde_dsi *d, 212 + const struct mipi_dsi_msg *msg) 213 + { 214 + const u32 loop_delay_us = 10; /* us */ 215 + u32 loop_counter; 216 + size_t txlen = msg->tx_len; 217 + size_t rxlen = msg->rx_len; 218 + int i; 219 + u32 val; 220 + int ret; 221 + 222 + writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); 223 + writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); 224 + /* Send command */ 225 + writel(1, d->regs + DSI_DIRECT_CMD_SEND); 226 + 227 + loop_counter = 1000 * 1000 / loop_delay_us; 228 + if (MCDE_DSI_HOST_IS_READ(msg->type)) { 229 + /* Read command */ 230 + while (!(readl(d->regs + DSI_DIRECT_CMD_STS) & 231 + (DSI_DIRECT_CMD_STS_READ_COMPLETED | 232 + DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR)) 233 + && --loop_counter) 234 + usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); 235 + if (!loop_counter) { 236 + dev_err(d->dev, "DSI read timeout!\n"); 237 + /* Set exit code and retry */ 238 + return -ETIME; 239 + } 240 + } else { 241 + /* Writing only */ 242 + while (!(readl(d->regs + DSI_DIRECT_CMD_STS) & 243 + DSI_DIRECT_CMD_STS_WRITE_COMPLETED) 244 + && --loop_counter) 245 + usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); 246 + 247 + if (!loop_counter) { 248 + /* Set exit code and retry */ 249 + dev_err(d->dev, "DSI write timeout!\n"); 250 + return -ETIME; 251 + } 252 + } 253 + 254 + val = readl(d->regs + DSI_DIRECT_CMD_STS); 255 + if (val & DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR) { 256 + dev_err(d->dev, "read completed with error\n"); 257 + writel(1, d->regs + DSI_DIRECT_CMD_RD_INIT); 258 + return -EIO; 259 + } 260 + if (val & DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED) { 261 + val >>= DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT; 262 + dev_err(d->dev, "error during transmission: %04x\n", 263 + val); 264 + return -EIO; 265 + } 266 + 267 + if (!MCDE_DSI_HOST_IS_READ(msg->type)) { 268 + /* Return number of bytes written */ 269 + ret = txlen; 270 + } else { 271 + /* OK this is a read command, get the response */ 272 + u32 rdsz; 273 + u32 rddat; 274 + u8 *rx = msg->rx_buf; 275 + 276 + rdsz = readl(d->regs + DSI_DIRECT_CMD_RD_PROPERTY); 277 + rdsz &= DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK; 278 + rddat = readl(d->regs + DSI_DIRECT_CMD_RDDAT); 279 + if (rdsz < rxlen) { 280 + dev_err(d->dev, "read error, requested %zd got %d\n", 281 + rxlen, rdsz); 282 + return -EIO; 283 + } 284 + /* FIXME: read more than 4 bytes */ 285 + for (i = 0; i < 4 && i < rxlen; i++) 286 + rx[i] = (rddat >> (i * 8)) & 0xff; 287 + ret = rdsz; 288 + } 289 + 290 + /* Successful transmission */ 291 + return ret; 292 + } 293 + 211 294 static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host, 212 295 const struct mipi_dsi_msg *msg) 213 296 { 214 297 struct mcde_dsi *d = host_to_mcde_dsi(host); 215 - const u32 loop_delay_us = 10; /* us */ 216 298 const u8 *tx = msg->tx_buf; 217 - u32 loop_counter; 218 299 size_t txlen = msg->tx_len; 219 300 size_t rxlen = msg->rx_len; 301 + unsigned int retries = 0; 220 302 u32 val; 221 303 int ret; 222 304 int i; ··· 364 282 writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3); 365 283 } 366 284 367 - writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); 368 - writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); 369 - /* Send command */ 370 - writel(1, d->regs + DSI_DIRECT_CMD_SEND); 371 - 372 - loop_counter = 1000 * 1000 / loop_delay_us; 373 - if (MCDE_DSI_HOST_IS_READ(msg->type)) { 374 - /* Read command */ 375 - while (!(readl(d->regs + DSI_DIRECT_CMD_STS) & 376 - (DSI_DIRECT_CMD_STS_READ_COMPLETED | 377 - DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR)) 378 - && --loop_counter) 379 - usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); 380 - if (!loop_counter) { 381 - dev_err(d->dev, "DSI read timeout!\n"); 382 - return -ETIME; 383 - } 384 - } else { 385 - /* Writing only */ 386 - while (!(readl(d->regs + DSI_DIRECT_CMD_STS) & 387 - DSI_DIRECT_CMD_STS_WRITE_COMPLETED) 388 - && --loop_counter) 389 - usleep_range(loop_delay_us, (loop_delay_us * 3) / 2); 390 - 391 - if (!loop_counter) { 392 - dev_err(d->dev, "DSI write timeout!\n"); 393 - return -ETIME; 394 - } 285 + while (retries < 3) { 286 + ret = mcde_dsi_execute_transfer(d, msg); 287 + if (ret >= 0) 288 + break; 289 + retries++; 395 290 } 291 + if (ret < 0 && retries) 292 + dev_err(d->dev, "gave up after %d retries\n", retries); 396 293 397 - val = readl(d->regs + DSI_DIRECT_CMD_STS); 398 - if (val & DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR) { 399 - dev_err(d->dev, "read completed with error\n"); 400 - writel(1, d->regs + DSI_DIRECT_CMD_RD_INIT); 401 - return -EIO; 402 - } 403 - if (val & DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED) { 404 - val >>= DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT; 405 - dev_err(d->dev, "error during transmission: %04x\n", 406 - val); 407 - return -EIO; 408 - } 409 - 410 - if (!MCDE_DSI_HOST_IS_READ(msg->type)) { 411 - /* Return number of bytes written */ 412 - ret = txlen; 413 - } else { 414 - /* OK this is a read command, get the response */ 415 - u32 rdsz; 416 - u32 rddat; 417 - u8 *rx = msg->rx_buf; 418 - 419 - rdsz = readl(d->regs + DSI_DIRECT_CMD_RD_PROPERTY); 420 - rdsz &= DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK; 421 - rddat = readl(d->regs + DSI_DIRECT_CMD_RDDAT); 422 - if (rdsz < rxlen) { 423 - dev_err(d->dev, "read error, requested %zd got %d\n", 424 - rxlen, rdsz); 425 - return -EIO; 426 - } 427 - /* FIXME: read more than 4 bytes */ 428 - for (i = 0; i < 4 && i < rxlen; i++) 429 - rx[i] = (rddat >> (i * 8)) & 0xff; 430 - ret = rdsz; 431 - } 432 - 294 + /* Clear any errors */ 433 295 writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR); 434 296 writel(~0, d->regs + DSI_CMD_MODE_STS_CLR); 435 297