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

drm/meson: venc: add ENCL encoder setup for MIPI-DSI output

This adds supports for the ENCL encoder connected to a MIPI-DSI transceiver on the
Amlogic AXG, G12A, G12B & SM1 SoCs.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Nicolas Belin <nbelin@baylibre.com>
Tested-by: Nicolas Belin <nbelin@baylibre.com> # on Khadas VIM3 + TS050 Panel
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230512-amlogic-v6-4-upstream-dsi-ccf-vim3-v5-10-56eb7a4d5b8e@linaro.org

+242 -2
+25
drivers/gpu/drm/meson/meson_registers.h
··· 812 812 #define VENC_STATA 0x1b6d 813 813 #define VENC_INTCTRL 0x1b6e 814 814 #define VENC_INTCTRL_ENCI_LNRST_INT_EN BIT(1) 815 + #define VENC_INTCTRL_ENCP_LNRST_INT_EN BIT(9) 815 816 #define VENC_INTFLAG 0x1b6f 816 817 #define VENC_VIDEO_TST_EN 0x1b70 817 818 #define VENC_VIDEO_TST_MDSEL 0x1b71 ··· 1193 1192 #define ENCL_VIDEO_PB_OFFST 0x1ca5 1194 1193 #define ENCL_VIDEO_PR_OFFST 0x1ca6 1195 1194 #define ENCL_VIDEO_MODE 0x1ca7 1195 + #define ENCL_PX_LN_CNT_SHADOW_EN BIT(15) 1196 1196 #define ENCL_VIDEO_MODE_ADV 0x1ca8 1197 + #define ENCL_VIDEO_MODE_ADV_VFIFO_EN BIT(3) 1198 + #define ENCL_VIDEO_MODE_ADV_GAIN_HDTV BIT(4) 1199 + #define ENCL_SEL_GAMMA_RGB_IN BIT(10) 1197 1200 #define ENCL_DBG_PX_RST 0x1ca9 1198 1201 #define ENCL_DBG_LN_RST 0x1caa 1199 1202 #define ENCL_DBG_PX_INT 0x1cab ··· 1224 1219 #define ENCL_VIDEO_VOFFST 0x1cc0 1225 1220 #define ENCL_VIDEO_RGB_CTRL 0x1cc1 1226 1221 #define ENCL_VIDEO_FILT_CTRL 0x1cc2 1222 + #define ENCL_VIDEO_FILT_CTRL_BYPASS_FILTER BIT(12) 1227 1223 #define ENCL_VIDEO_OFLD_VPEQ_OFST 0x1cc3 1228 1224 #define ENCL_VIDEO_OFLD_VOAV_OFST 0x1cc4 1229 1225 #define ENCL_VIDEO_MATRIX_CB 0x1cc5 1230 1226 #define ENCL_VIDEO_MATRIX_CR 0x1cc6 1231 1227 #define ENCL_VIDEO_RGBIN_CTRL 0x1cc7 1228 + #define ENCL_VIDEO_RGBIN_RGB BIT(0) 1229 + #define ENCL_VIDEO_RGBIN_ZBLK BIT(1) 1232 1230 #define ENCL_MAX_LINE_SWITCH_POINT 0x1cc8 1233 1231 #define ENCL_DACSEL_0 0x1cc9 1234 1232 #define ENCL_DACSEL_1 0x1cca ··· 1308 1300 #define RDMA_STATUS2 0x1116 1309 1301 #define RDMA_STATUS3 0x1117 1310 1302 #define L_GAMMA_CNTL_PORT 0x1400 1303 + #define L_GAMMA_CNTL_PORT_VCOM_POL BIT(7) /* RW */ 1304 + #define L_GAMMA_CNTL_PORT_RVS_OUT BIT(6) /* RW */ 1305 + #define L_GAMMA_CNTL_PORT_ADR_RDY BIT(5) /* Read Only */ 1306 + #define L_GAMMA_CNTL_PORT_WR_RDY BIT(4) /* Read Only */ 1307 + #define L_GAMMA_CNTL_PORT_RD_RDY BIT(3) /* Read Only */ 1308 + #define L_GAMMA_CNTL_PORT_TR BIT(2) /* RW */ 1309 + #define L_GAMMA_CNTL_PORT_SET BIT(1) /* RW */ 1310 + #define L_GAMMA_CNTL_PORT_EN BIT(0) /* RW */ 1311 1311 #define L_GAMMA_DATA_PORT 0x1401 1312 1312 #define L_GAMMA_ADDR_PORT 0x1402 1313 + #define L_GAMMA_ADDR_PORT_RD BIT(12) 1314 + #define L_GAMMA_ADDR_PORT_AUTO_INC BIT(11) 1315 + #define L_GAMMA_ADDR_PORT_SEL_R BIT(10) 1316 + #define L_GAMMA_ADDR_PORT_SEL_G BIT(9) 1317 + #define L_GAMMA_ADDR_PORT_SEL_B BIT(8) 1318 + #define L_GAMMA_ADDR_PORT_ADDR GENMASK(7, 0) 1313 1319 #define L_GAMMA_VCOM_HSWITCH_ADDR 0x1403 1314 1320 #define L_RGB_BASE_ADDR 0x1405 1315 1321 #define L_RGB_COEFF_ADDR 0x1406 1316 1322 #define L_POL_CNTL_ADDR 0x1407 1317 1323 #define L_DITH_CNTL_ADDR 0x1408 1324 + #define L_DITH_CNTL_DITH10_EN BIT(10) 1318 1325 #define L_GAMMA_PROBE_CTRL 0x1409 1319 1326 #define L_GAMMA_PROBE_COLOR_L 0x140a 1320 1327 #define L_GAMMA_PROBE_COLOR_H 0x140b ··· 1386 1363 #define L_LCD_PWM1_HI_ADDR 0x143f 1387 1364 #define L_INV_CNT_ADDR 0x1440 1388 1365 #define L_TCON_MISC_SEL_ADDR 0x1441 1366 + #define L_TCON_MISC_SEL_STV1 BIT(4) 1367 + #define L_TCON_MISC_SEL_STV2 BIT(5) 1389 1368 #define L_DUAL_PORT_CNTL_ADDR 0x1442 1390 1369 #define MLVDS_CLK_CTL1_HI 0x1443 1391 1370 #define MLVDS_CLK_CTL1_LO 0x1444
+209 -2
drivers/gpu/drm/meson/meson_venc.c
··· 6 6 */ 7 7 8 8 #include <linux/export.h> 9 + #include <linux/iopoll.h> 9 10 10 11 #include <drm/drm_modes.h> 11 12 ··· 1558 1557 } 1559 1558 EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set); 1560 1559 1560 + static unsigned short meson_encl_gamma_table[256] = { 1561 + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 1562 + 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 1563 + 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 1564 + 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 1565 + 256, 260, 264, 268, 272, 276, 280, 284, 288, 292, 296, 300, 304, 308, 312, 316, 1566 + 320, 324, 328, 332, 336, 340, 344, 348, 352, 356, 360, 364, 368, 372, 376, 380, 1567 + 384, 388, 392, 396, 400, 404, 408, 412, 416, 420, 424, 428, 432, 436, 440, 444, 1568 + 448, 452, 456, 460, 464, 468, 472, 476, 480, 484, 488, 492, 496, 500, 504, 508, 1569 + 512, 516, 520, 524, 528, 532, 536, 540, 544, 548, 552, 556, 560, 564, 568, 572, 1570 + 576, 580, 584, 588, 592, 596, 600, 604, 608, 612, 616, 620, 624, 628, 632, 636, 1571 + 640, 644, 648, 652, 656, 660, 664, 668, 672, 676, 680, 684, 688, 692, 696, 700, 1572 + 704, 708, 712, 716, 720, 724, 728, 732, 736, 740, 744, 748, 752, 756, 760, 764, 1573 + 768, 772, 776, 780, 784, 788, 792, 796, 800, 804, 808, 812, 816, 820, 824, 828, 1574 + 832, 836, 840, 844, 848, 852, 856, 860, 864, 868, 872, 876, 880, 884, 888, 892, 1575 + 896, 900, 904, 908, 912, 916, 920, 924, 928, 932, 936, 940, 944, 948, 952, 956, 1576 + 960, 964, 968, 972, 976, 980, 984, 988, 992, 996, 1000, 1004, 1008, 1012, 1016, 1020, 1577 + }; 1578 + 1579 + static void meson_encl_set_gamma_table(struct meson_drm *priv, u16 *data, 1580 + u32 rgb_mask) 1581 + { 1582 + int i, ret; 1583 + u32 reg; 1584 + 1585 + writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, 0, 1586 + priv->io_base + _REG(L_GAMMA_CNTL_PORT)); 1587 + 1588 + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), 1589 + reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10, 10000); 1590 + if (ret) 1591 + pr_warn("%s: GAMMA ADR_RDY timeout\n", __func__); 1592 + 1593 + writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask | 1594 + FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0), 1595 + priv->io_base + _REG(L_GAMMA_ADDR_PORT)); 1596 + 1597 + for (i = 0; i < 256; i++) { 1598 + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), 1599 + reg, reg & L_GAMMA_CNTL_PORT_WR_RDY, 1600 + 10, 10000); 1601 + if (ret) 1602 + pr_warn_once("%s: GAMMA WR_RDY timeout\n", __func__); 1603 + 1604 + writel_relaxed(data[i], priv->io_base + _REG(L_GAMMA_DATA_PORT)); 1605 + } 1606 + 1607 + ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT), 1608 + reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10, 10000); 1609 + if (ret) 1610 + pr_warn("%s: GAMMA ADR_RDY timeout\n", __func__); 1611 + 1612 + writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask | 1613 + FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0x23), 1614 + priv->io_base + _REG(L_GAMMA_ADDR_PORT)); 1615 + } 1616 + 1617 + void meson_encl_load_gamma(struct meson_drm *priv) 1618 + { 1619 + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_R); 1620 + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_G); 1621 + meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_B); 1622 + 1623 + writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, L_GAMMA_CNTL_PORT_EN, 1624 + priv->io_base + _REG(L_GAMMA_CNTL_PORT)); 1625 + } 1626 + 1627 + void meson_venc_mipi_dsi_mode_set(struct meson_drm *priv, 1628 + const struct drm_display_mode *mode) 1629 + { 1630 + unsigned int max_pxcnt; 1631 + unsigned int max_lncnt; 1632 + unsigned int havon_begin; 1633 + unsigned int havon_end; 1634 + unsigned int vavon_bline; 1635 + unsigned int vavon_eline; 1636 + unsigned int hso_begin; 1637 + unsigned int hso_end; 1638 + unsigned int vso_begin; 1639 + unsigned int vso_end; 1640 + unsigned int vso_bline; 1641 + unsigned int vso_eline; 1642 + 1643 + max_pxcnt = mode->htotal - 1; 1644 + max_lncnt = mode->vtotal - 1; 1645 + havon_begin = mode->htotal - mode->hsync_start; 1646 + havon_end = havon_begin + mode->hdisplay - 1; 1647 + vavon_bline = mode->vtotal - mode->vsync_start; 1648 + vavon_eline = vavon_bline + mode->vdisplay - 1; 1649 + hso_begin = 0; 1650 + hso_end = mode->hsync_end - mode->hsync_start; 1651 + vso_begin = 0; 1652 + vso_end = 0; 1653 + vso_bline = 0; 1654 + vso_eline = mode->vsync_end - mode->vsync_start; 1655 + 1656 + meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCL); 1657 + 1658 + writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN)); 1659 + 1660 + writel_relaxed(ENCL_PX_LN_CNT_SHADOW_EN, priv->io_base + _REG(ENCL_VIDEO_MODE)); 1661 + writel_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN | 1662 + ENCL_VIDEO_MODE_ADV_GAIN_HDTV | 1663 + ENCL_SEL_GAMMA_RGB_IN, priv->io_base + _REG(ENCL_VIDEO_MODE_ADV)); 1664 + 1665 + writel_relaxed(ENCL_VIDEO_FILT_CTRL_BYPASS_FILTER, 1666 + priv->io_base + _REG(ENCL_VIDEO_FILT_CTRL)); 1667 + writel_relaxed(max_pxcnt, priv->io_base + _REG(ENCL_VIDEO_MAX_PXCNT)); 1668 + writel_relaxed(max_lncnt, priv->io_base + _REG(ENCL_VIDEO_MAX_LNCNT)); 1669 + writel_relaxed(havon_begin, priv->io_base + _REG(ENCL_VIDEO_HAVON_BEGIN)); 1670 + writel_relaxed(havon_end, priv->io_base + _REG(ENCL_VIDEO_HAVON_END)); 1671 + writel_relaxed(vavon_bline, priv->io_base + _REG(ENCL_VIDEO_VAVON_BLINE)); 1672 + writel_relaxed(vavon_eline, priv->io_base + _REG(ENCL_VIDEO_VAVON_ELINE)); 1673 + 1674 + writel_relaxed(hso_begin, priv->io_base + _REG(ENCL_VIDEO_HSO_BEGIN)); 1675 + writel_relaxed(hso_end, priv->io_base + _REG(ENCL_VIDEO_HSO_END)); 1676 + writel_relaxed(vso_begin, priv->io_base + _REG(ENCL_VIDEO_VSO_BEGIN)); 1677 + writel_relaxed(vso_end, priv->io_base + _REG(ENCL_VIDEO_VSO_END)); 1678 + writel_relaxed(vso_bline, priv->io_base + _REG(ENCL_VIDEO_VSO_BLINE)); 1679 + writel_relaxed(vso_eline, priv->io_base + _REG(ENCL_VIDEO_VSO_ELINE)); 1680 + writel_relaxed(ENCL_VIDEO_RGBIN_RGB | ENCL_VIDEO_RGBIN_ZBLK, 1681 + priv->io_base + _REG(ENCL_VIDEO_RGBIN_CTRL)); 1682 + 1683 + /* default black pattern */ 1684 + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_MDSEL)); 1685 + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_Y)); 1686 + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_CB)); 1687 + writel_relaxed(0, priv->io_base + _REG(ENCL_TST_CR)); 1688 + writel_relaxed(1, priv->io_base + _REG(ENCL_TST_EN)); 1689 + writel_bits_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN, 0, 1690 + priv->io_base + _REG(ENCL_VIDEO_MODE_ADV)); 1691 + 1692 + writel_relaxed(1, priv->io_base + _REG(ENCL_VIDEO_EN)); 1693 + 1694 + writel_relaxed(0, priv->io_base + _REG(L_RGB_BASE_ADDR)); 1695 + writel_relaxed(0x400, priv->io_base + _REG(L_RGB_COEFF_ADDR)); /* Magic value */ 1696 + 1697 + writel_relaxed(L_DITH_CNTL_DITH10_EN, priv->io_base + _REG(L_DITH_CNTL_ADDR)); 1698 + 1699 + /* DE signal for TTL */ 1700 + writel_relaxed(havon_begin, priv->io_base + _REG(L_OEH_HS_ADDR)); 1701 + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_OEH_HE_ADDR)); 1702 + writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEH_VS_ADDR)); 1703 + writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEH_VE_ADDR)); 1704 + 1705 + /* DE signal for TTL */ 1706 + writel_relaxed(havon_begin, priv->io_base + _REG(L_OEV1_HS_ADDR)); 1707 + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_OEV1_HE_ADDR)); 1708 + writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEV1_VS_ADDR)); 1709 + writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEV1_VE_ADDR)); 1710 + 1711 + /* Hsync signal for TTL */ 1712 + if (mode->flags & DRM_MODE_FLAG_PHSYNC) { 1713 + writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HS_ADDR)); 1714 + writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HE_ADDR)); 1715 + } else { 1716 + writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HS_ADDR)); 1717 + writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HE_ADDR)); 1718 + } 1719 + writel_relaxed(0, priv->io_base + _REG(L_STH1_VS_ADDR)); 1720 + writel_relaxed(max_lncnt, priv->io_base + _REG(L_STH1_VE_ADDR)); 1721 + 1722 + /* Vsync signal for TTL */ 1723 + writel_relaxed(vso_begin, priv->io_base + _REG(L_STV1_HS_ADDR)); 1724 + writel_relaxed(vso_end, priv->io_base + _REG(L_STV1_HE_ADDR)); 1725 + if (mode->flags & DRM_MODE_FLAG_PVSYNC) { 1726 + writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VS_ADDR)); 1727 + writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VE_ADDR)); 1728 + } else { 1729 + writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VS_ADDR)); 1730 + writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VE_ADDR)); 1731 + } 1732 + 1733 + /* DE signal */ 1734 + writel_relaxed(havon_begin, priv->io_base + _REG(L_DE_HS_ADDR)); 1735 + writel_relaxed(havon_end + 1, priv->io_base + _REG(L_DE_HE_ADDR)); 1736 + writel_relaxed(vavon_bline, priv->io_base + _REG(L_DE_VS_ADDR)); 1737 + writel_relaxed(vavon_eline, priv->io_base + _REG(L_DE_VE_ADDR)); 1738 + 1739 + /* Hsync signal */ 1740 + writel_relaxed(hso_begin, priv->io_base + _REG(L_HSYNC_HS_ADDR)); 1741 + writel_relaxed(hso_end, priv->io_base + _REG(L_HSYNC_HE_ADDR)); 1742 + writel_relaxed(0, priv->io_base + _REG(L_HSYNC_VS_ADDR)); 1743 + writel_relaxed(max_lncnt, priv->io_base + _REG(L_HSYNC_VE_ADDR)); 1744 + 1745 + /* Vsync signal */ 1746 + writel_relaxed(vso_begin, priv->io_base + _REG(L_VSYNC_HS_ADDR)); 1747 + writel_relaxed(vso_end, priv->io_base + _REG(L_VSYNC_HE_ADDR)); 1748 + writel_relaxed(vso_bline, priv->io_base + _REG(L_VSYNC_VS_ADDR)); 1749 + writel_relaxed(vso_eline, priv->io_base + _REG(L_VSYNC_VE_ADDR)); 1750 + 1751 + writel_relaxed(0, priv->io_base + _REG(L_INV_CNT_ADDR)); 1752 + writel_relaxed(L_TCON_MISC_SEL_STV1 | L_TCON_MISC_SEL_STV2, 1753 + priv->io_base + _REG(L_TCON_MISC_SEL_ADDR)); 1754 + 1755 + priv->venc.current_mode = MESON_VENC_MODE_MIPI_DSI; 1756 + } 1757 + EXPORT_SYMBOL_GPL(meson_venc_mipi_dsi_mode_set); 1758 + 1561 1759 void meson_venci_cvbs_mode_set(struct meson_drm *priv, 1562 1760 struct meson_cvbs_enci_mode *mode) 1563 1761 { ··· 1947 1747 1948 1748 void meson_venc_enable_vsync(struct meson_drm *priv) 1949 1749 { 1950 - writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, 1951 - priv->io_base + _REG(VENC_INTCTRL)); 1750 + switch (priv->venc.current_mode) { 1751 + case MESON_VENC_MODE_MIPI_DSI: 1752 + writel_relaxed(VENC_INTCTRL_ENCP_LNRST_INT_EN, 1753 + priv->io_base + _REG(VENC_INTCTRL)); 1754 + break; 1755 + default: 1756 + writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN, 1757 + priv->io_base + _REG(VENC_INTCTRL)); 1758 + } 1952 1759 regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25)); 1953 1760 } 1954 1761
+6
drivers/gpu/drm/meson/meson_venc.h
··· 21 21 MESON_VENC_MODE_CVBS_PAL, 22 22 MESON_VENC_MODE_CVBS_NTSC, 23 23 MESON_VENC_MODE_HDMI, 24 + MESON_VENC_MODE_MIPI_DSI, 24 25 }; 25 26 26 27 struct meson_cvbs_enci_mode { ··· 48 47 unsigned int analog_sync_adj; 49 48 }; 50 49 50 + /* LCD Encoder gamma setup */ 51 + void meson_encl_load_gamma(struct meson_drm *priv); 52 + 51 53 /* HDMI Clock parameters */ 52 54 enum drm_mode_status 53 55 meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode); ··· 67 63 unsigned int ycrcb_map, 68 64 bool yuv420_mode, 69 65 const struct drm_display_mode *mode); 66 + void meson_venc_mipi_dsi_mode_set(struct meson_drm *priv, 67 + const struct drm_display_mode *mode); 70 68 unsigned int meson_venci_get_field(struct meson_drm *priv); 71 69 72 70 void meson_venc_enable_vsync(struct meson_drm *priv);
+2
drivers/gpu/drm/meson/meson_vpp.h
··· 12 12 struct drm_rect; 13 13 struct meson_drm; 14 14 15 + /* Mux VIU/VPP to ENCL */ 16 + #define MESON_VIU_VPP_MUX_ENCL 0x0 15 17 /* Mux VIU/VPP to ENCI */ 16 18 #define MESON_VIU_VPP_MUX_ENCI 0x5 17 19 /* Mux VIU/VPP to ENCP */