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

drm/stm: ltdc: update hardware error management

The latest hardware version (0x40100) supports a hardware threshold
register (aka FUTR) to trigger a fifo underrun interrupt.
A software threshold has been implemented for other hardware versions.
The threshold is set to 128 by default.

Signed-off-by: Yannick Fertre <yannick.fertre@foss.st.com>
Signed-off-by: Philippe Cornu <philippe.cornu@foss.st.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220603134654.594373-1-yannick.fertre@foss.st.com

authored by

Yannick Fertre and committed by
Philippe Cornu
7d008eec c6193dc5

+77 -19
+72 -18
drivers/gpu/drm/stm/ltdc.c
··· 165 165 #define BCCR_BCWHITE GENMASK(23, 0) /* Background Color WHITE */ 166 166 167 167 #define IER_LIE BIT(0) /* Line Interrupt Enable */ 168 - #define IER_FUIE BIT(1) /* Fifo Underrun Interrupt Enable */ 168 + #define IER_FUWIE BIT(1) /* Fifo Underrun Warning Interrupt Enable */ 169 169 #define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ 170 - #define IER_RRIE BIT(3) /* Register Reload Interrupt enable */ 170 + #define IER_RRIE BIT(3) /* Register Reload Interrupt Enable */ 171 + #define IER_FUEIE BIT(6) /* Fifo Underrun Error Interrupt Enable */ 172 + #define IER_CRCIE BIT(7) /* CRC Error Interrupt Enable */ 171 173 172 174 #define CPSR_CYPOS GENMASK(15, 0) /* Current Y position */ 173 175 174 176 #define ISR_LIF BIT(0) /* Line Interrupt Flag */ 175 - #define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ 177 + #define ISR_FUWIF BIT(1) /* Fifo Underrun Warning Interrupt Flag */ 176 178 #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ 177 179 #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ 180 + #define ISR_FUEIF BIT(6) /* Fifo Underrun Error Interrupt Flag */ 181 + #define ISR_CRCIF BIT(7) /* CRC Error Interrupt Flag */ 178 182 179 183 #define EDCR_OCYEN BIT(25) /* Output Conversion to YCbCr 422: ENable */ 180 184 #define EDCR_OCYSEL BIT(26) /* Output Conversion to YCbCr 422: SELection of the CCIR */ ··· 237 233 #define BF2_1CA 0x005 /* 1 - Constant Alpha */ 238 234 239 235 #define NB_PF 8 /* Max nb of HW pixel format */ 236 + 237 + #define FUT_DFT 128 /* Default value of fifo underrun threshold */ 240 238 241 239 /* 242 240 * Skip the first value and the second in case CRC was enabled during ··· 720 714 ltdc_irq_crc_handle(ldev, crtc); 721 715 } 722 716 723 - /* Save FIFO Underrun & Transfer Error status */ 724 717 mutex_lock(&ldev->err_lock); 725 - if (ldev->irq_status & ISR_FUIF) 726 - ldev->error_status |= ISR_FUIF; 727 718 if (ldev->irq_status & ISR_TERRIF) 728 - ldev->error_status |= ISR_TERRIF; 719 + ldev->transfer_err++; 720 + if (ldev->irq_status & ISR_FUEIF) 721 + ldev->fifo_err++; 722 + if (ldev->irq_status & ISR_FUWIF) 723 + ldev->fifo_warn++; 729 724 mutex_unlock(&ldev->err_lock); 730 725 731 726 return IRQ_HANDLED; ··· 785 778 regmap_write(ldev->regmap, LTDC_BCCR, BCCR_BCBLACK); 786 779 787 780 /* Enable IRQ */ 788 - regmap_set_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); 781 + regmap_set_bits(ldev->regmap, LTDC_IER, IER_FUWIE | IER_FUEIE | IER_RRIE | IER_TERRIE); 789 782 790 783 /* Commit shadow registers = update planes at next vblank */ 791 784 if (!ldev->caps.plane_reg_shadow) ··· 811 804 LXCR_CLUTEN | LXCR_LEN, 0); 812 805 813 806 /* disable IRQ */ 814 - regmap_clear_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); 807 + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_FUWIE | IER_FUEIE | IER_RRIE | IER_TERRIE); 815 808 816 809 /* immediately commit disable of layers before switching off LTDC */ 817 810 if (!ldev->caps.plane_reg_shadow) 818 811 regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); 819 812 820 813 pm_runtime_put_sync(ddev->dev); 814 + 815 + /* clear interrupt error counters */ 816 + mutex_lock(&ldev->err_lock); 817 + ldev->transfer_err = 0; 818 + ldev->fifo_err = 0; 819 + ldev->fifo_warn = 0; 820 + mutex_unlock(&ldev->err_lock); 821 821 } 822 822 823 823 #define CLK_TOLERANCE_HZ 50 ··· 1185 1171 return 0; 1186 1172 } 1187 1173 1174 + static void ltdc_crtc_atomic_print_state(struct drm_printer *p, 1175 + const struct drm_crtc_state *state) 1176 + { 1177 + struct drm_crtc *crtc = state->crtc; 1178 + struct ltdc_device *ldev = crtc_to_ltdc(crtc); 1179 + 1180 + drm_printf(p, "\ttransfer_error=%d\n", ldev->transfer_err); 1181 + drm_printf(p, "\tfifo_underrun_error=%d\n", ldev->fifo_err); 1182 + drm_printf(p, "\tfifo_underrun_warning=%d\n", ldev->fifo_warn); 1183 + drm_printf(p, "\tfifo_underrun_threshold=%d\n", ldev->fifo_threshold); 1184 + } 1185 + 1188 1186 static const struct drm_crtc_funcs ltdc_crtc_funcs = { 1189 1187 .destroy = drm_crtc_cleanup, 1190 1188 .set_config = drm_atomic_helper_set_config, ··· 1207 1181 .enable_vblank = ltdc_crtc_enable_vblank, 1208 1182 .disable_vblank = ltdc_crtc_disable_vblank, 1209 1183 .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 1184 + .atomic_print_state = ltdc_crtc_atomic_print_state, 1210 1185 }; 1211 1186 1212 1187 static const struct drm_crtc_funcs ltdc_crtc_with_crc_support_funcs = { ··· 1222 1195 .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, 1223 1196 .set_crc_source = ltdc_crtc_set_crc_source, 1224 1197 .verify_crc_source = ltdc_crtc_verify_crc_source, 1198 + .atomic_print_state = ltdc_crtc_atomic_print_state, 1225 1199 }; 1226 1200 1227 1201 /* ··· 1483 1455 ldev->plane_fpsi[plane->index].counter++; 1484 1456 1485 1457 mutex_lock(&ldev->err_lock); 1486 - if (ldev->error_status & ISR_FUIF) { 1487 - DRM_WARN("ltdc fifo underrun: please verify display mode\n"); 1488 - ldev->error_status &= ~ISR_FUIF; 1458 + if (ldev->transfer_err) { 1459 + DRM_WARN("ltdc transfer error: %d\n", ldev->transfer_err); 1460 + ldev->transfer_err = 0; 1489 1461 } 1490 - if (ldev->error_status & ISR_TERRIF) { 1491 - DRM_WARN("ltdc transfer error\n"); 1492 - ldev->error_status &= ~ISR_TERRIF; 1462 + 1463 + if (ldev->caps.fifo_threshold) { 1464 + if (ldev->fifo_err) { 1465 + DRM_WARN("ltdc fifo underrun: please verify display mode\n"); 1466 + ldev->fifo_err = 0; 1467 + } 1468 + } else { 1469 + if (ldev->fifo_warn >= ldev->fifo_threshold) { 1470 + DRM_WARN("ltdc fifo underrun: please verify display mode\n"); 1471 + ldev->fifo_warn = 0; 1472 + } 1493 1473 } 1494 1474 mutex_unlock(&ldev->err_lock); 1495 1475 } ··· 1739 1703 1740 1704 DRM_DEBUG_DRIVER("\n"); 1741 1705 1706 + /* set fifo underrun threshold register */ 1707 + if (ldev->caps.fifo_threshold) 1708 + regmap_write(ldev->regmap, LTDC_FUT, ldev->fifo_threshold); 1709 + 1742 1710 /* Enable LTDC */ 1743 1711 regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); 1744 1712 } ··· 1844 1804 ldev->caps.crc = false; 1845 1805 ldev->caps.dynamic_zorder = false; 1846 1806 ldev->caps.plane_rotation = false; 1807 + ldev->caps.fifo_threshold = false; 1847 1808 break; 1848 1809 case HWVER_20101: 1849 1810 ldev->caps.layer_ofs = LAY_OFS_0; ··· 1862 1821 ldev->caps.crc = false; 1863 1822 ldev->caps.dynamic_zorder = false; 1864 1823 ldev->caps.plane_rotation = false; 1824 + ldev->caps.fifo_threshold = false; 1865 1825 break; 1866 1826 case HWVER_40100: 1867 1827 ldev->caps.layer_ofs = LAY_OFS_1; ··· 1880 1838 ldev->caps.crc = true; 1881 1839 ldev->caps.dynamic_zorder = true; 1882 1840 ldev->caps.plane_rotation = true; 1841 + ldev->caps.fifo_threshold = true; 1883 1842 break; 1884 1843 default: 1885 1844 return -ENODEV; ··· 2005 1962 goto err; 2006 1963 } 2007 1964 2008 - /* Disable interrupts */ 2009 - regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); 2010 - 2011 1965 ret = ltdc_get_caps(ddev); 2012 1966 if (ret) { 2013 1967 DRM_ERROR("hardware identifier (0x%08x) not supported!\n", ··· 2012 1972 goto err; 2013 1973 } 2014 1974 1975 + /* Disable interrupts */ 1976 + if (ldev->caps.fifo_threshold) 1977 + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUWIE | 1978 + IER_TERRIE); 1979 + else 1980 + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUWIE | 1981 + IER_TERRIE | IER_FUEIE); 1982 + 2015 1983 DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version); 1984 + 1985 + /* initialize default value for fifo underrun threshold & clear interrupt error counters */ 1986 + ldev->transfer_err = 0; 1987 + ldev->fifo_err = 0; 1988 + ldev->fifo_warn = 0; 1989 + ldev->fifo_threshold = FUT_DFT; 2016 1990 2017 1991 for (i = 0; i < ldev->caps.nb_irq; i++) { 2018 1992 irq = platform_get_irq(pdev, i);
+5 -1
drivers/gpu/drm/stm/ltdc.h
··· 30 30 bool crc; /* cyclic redundancy check supported */ 31 31 bool dynamic_zorder; /* dynamic z-order */ 32 32 bool plane_rotation; /* plane rotation */ 33 + bool fifo_threshold; /* fifo underrun threshold supported */ 33 34 }; 34 35 35 36 #define LTDC_MAX_LAYER 4 ··· 46 45 struct clk *pixel_clk; /* lcd pixel clock */ 47 46 struct mutex err_lock; /* protecting error_status */ 48 47 struct ltdc_caps caps; 49 - u32 error_status; 50 48 u32 irq_status; 49 + u32 fifo_err; /* fifo underrun error counter */ 50 + u32 fifo_warn; /* fifo underrun warning counter */ 51 + u32 fifo_threshold; /* fifo underrun threshold */ 52 + u32 transfer_err; /* transfer error counter */ 51 53 struct fps_info plane_fpsi[LTDC_MAX_LAYER]; 52 54 struct drm_atomic_state *suspend_state; 53 55 int crc_skip_count;