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

drm/msm/dsi: do not enable irq handler before powering up the host

The DSI host might be left in some state by the bootloader. If this
state generates an IRQ, it might hang the system by holding the
interrupt line before the driver sets up the DSI host to the known
state.

Move the request_irq into msm_dsi_host_init and pass IRQF_NO_AUTOEN to
it. Call enable/disable_irq after msm_dsi_host_power_on/_off()
functions, so that we can be sure that the interrupt is delivered when
the host is in the known state.

It is not possible to defer the interrupt enablement to a later point,
because drm_panel_prepare might need to communicate with the panel over
the DSI link and that requires working interrupt.

Fixes: a689554ba6ed ("drm/msm: Initial add DSI connector support")
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Abhinav Kumar <abhinavk@codeaurora.org>
Link: https://lore.kernel.org/r/20211002010830.647416-1-dmitry.baryshkov@linaro.org
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Rob Clark <robdclark@chromium.org>

authored by

Dmitry Baryshkov and committed by
Rob Clark
bf94ec09 fb25d447

+49 -17
+2
drivers/gpu/drm/msm/dsi/dsi.h
··· 107 107 u32 dma_base, u32 len); 108 108 int msm_dsi_host_enable(struct mipi_dsi_host *host); 109 109 int msm_dsi_host_disable(struct mipi_dsi_host *host); 110 + void msm_dsi_host_enable_irq(struct mipi_dsi_host *host); 111 + void msm_dsi_host_disable_irq(struct mipi_dsi_host *host); 110 112 int msm_dsi_host_power_on(struct mipi_dsi_host *host, 111 113 struct msm_dsi_phy_shared_timings *phy_shared_timings, 112 114 bool is_bonded_dsi, struct msm_dsi_phy *phy);
+31 -17
drivers/gpu/drm/msm/dsi/dsi_host.c
··· 1895 1895 return ret; 1896 1896 } 1897 1897 1898 + msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 1899 + if (msm_host->irq < 0) { 1900 + ret = msm_host->irq; 1901 + dev_err(&pdev->dev, "failed to get irq: %d\n", ret); 1902 + return ret; 1903 + } 1904 + 1905 + /* do not autoenable, will be enabled later */ 1906 + ret = devm_request_irq(&pdev->dev, msm_host->irq, dsi_host_irq, 1907 + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN, 1908 + "dsi_isr", msm_host); 1909 + if (ret < 0) { 1910 + dev_err(&pdev->dev, "failed to request IRQ%u: %d\n", 1911 + msm_host->irq, ret); 1912 + return ret; 1913 + } 1914 + 1898 1915 init_completion(&msm_host->dma_comp); 1899 1916 init_completion(&msm_host->video_comp); 1900 1917 mutex_init(&msm_host->dev_mutex); ··· 1955 1938 { 1956 1939 struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 1957 1940 const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; 1958 - struct platform_device *pdev = msm_host->pdev; 1959 1941 int ret; 1960 - 1961 - msm_host->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 1962 - if (msm_host->irq < 0) { 1963 - ret = msm_host->irq; 1964 - DRM_DEV_ERROR(dev->dev, "failed to get irq: %d\n", ret); 1965 - return ret; 1966 - } 1967 - 1968 - ret = devm_request_irq(&pdev->dev, msm_host->irq, 1969 - dsi_host_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 1970 - "dsi_isr", msm_host); 1971 - if (ret < 0) { 1972 - DRM_DEV_ERROR(&pdev->dev, "failed to request IRQ%u: %d\n", 1973 - msm_host->irq, ret); 1974 - return ret; 1975 - } 1976 1942 1977 1943 msm_host->dev = dev; 1978 1944 ret = cfg_hnd->ops->tx_buf_alloc(msm_host, SZ_4K); ··· 2310 2310 else 2311 2311 clk_req->bitclk_rate = msm_host->byte_clk_rate * 8; 2312 2312 clk_req->escclk_rate = msm_host->esc_clk_rate; 2313 + } 2314 + 2315 + void msm_dsi_host_enable_irq(struct mipi_dsi_host *host) 2316 + { 2317 + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2318 + 2319 + enable_irq(msm_host->irq); 2320 + } 2321 + 2322 + void msm_dsi_host_disable_irq(struct mipi_dsi_host *host) 2323 + { 2324 + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); 2325 + 2326 + disable_irq(msm_host->irq); 2313 2327 } 2314 2328 2315 2329 int msm_dsi_host_enable(struct mipi_dsi_host *host)
+16
drivers/gpu/drm/msm/dsi/dsi_manager.c
··· 379 379 } 380 380 } 381 381 382 + /* 383 + * Enable before preparing the panel, disable after unpreparing, so 384 + * that the panel can communicate over the DSI link. 385 + */ 386 + msm_dsi_host_enable_irq(host); 387 + if (is_bonded_dsi && msm_dsi1) 388 + msm_dsi_host_enable_irq(msm_dsi1->host); 389 + 382 390 /* Always call panel functions once, because even for dual panels, 383 391 * there is only one drm_panel instance. 384 392 */ ··· 421 413 if (panel) 422 414 drm_panel_unprepare(panel); 423 415 panel_prep_fail: 416 + msm_dsi_host_disable_irq(host); 417 + if (is_bonded_dsi && msm_dsi1) 418 + msm_dsi_host_disable_irq(msm_dsi1->host); 419 + 424 420 if (is_bonded_dsi && msm_dsi1) 425 421 msm_dsi_host_power_off(msm_dsi1->host); 426 422 host1_on_fail: ··· 536 524 pr_err("%s: Panel %d unprepare failed,%d\n", __func__, 537 525 id, ret); 538 526 } 527 + 528 + msm_dsi_host_disable_irq(host); 529 + if (is_bonded_dsi && msm_dsi1) 530 + msm_dsi_host_disable_irq(msm_dsi1->host); 539 531 540 532 /* Save PHY status if it is a clock source */ 541 533 msm_dsi_phy_pll_save_state(msm_dsi->phy);