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

drm/mcde: Support DPI output

This implements support for DPI output using the port node
in the device tree to connect a DPI LCD display to the
MCDE. The block also supports TV-out but we leave that
for another day when we have a hardware using it.

We implement parsing and handling of the "port" node,
and follow that to the DPI endpoint.

The clock divider used by the MCDE to divide down the
"lcdclk" (this has been designed for TV-like frequencies)
is represented by an ordinary clock provider internally
in the MCDE. This idea was inspired by the PL111 solution
by Eric Anholt: the divider also works very similar to
the Pl111 clock divider.

We take care to clear up some errors regarding the number
of available formatters and their type. We have 6 DSI
formatters and 2 DPI formatters.

Tested on the Samsung GT-I9070 Janice mobile phone.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Stephan Gerhold <stephan@gerhold.net>
Cc: phone-devel@vger.kernel.org
Cc: upstreaming@lists.sr.ht
Link: https://patchwork.freedesktop.org/patch/msgid/20201112142925.2571179-2-linus.walleij@linaro.org

+594 -46
+1
drivers/gpu/drm/mcde/Kconfig
··· 4 4 depends on CMA 5 5 depends on ARM || COMPILE_TEST 6 6 depends on OF 7 + depends on COMMON_CLK 7 8 select MFD_SYSCON 8 9 select DRM_MIPI_DSI 9 10 select DRM_BRIDGE
+1 -1
drivers/gpu/drm/mcde/Makefile
··· 1 - mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_display.o 1 + mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_clk_div.o mcde_display.o 2 2 3 3 obj-$(CONFIG_DRM_MCDE) += mcde_drm.o
+192
drivers/gpu/drm/mcde/mcde_clk_div.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/clk-provider.h> 3 + #include <linux/regulator/consumer.h> 4 + 5 + #include "mcde_drm.h" 6 + #include "mcde_display_regs.h" 7 + 8 + /* The MCDE internal clock dividers for FIFO A and B */ 9 + struct mcde_clk_div { 10 + struct clk_hw hw; 11 + struct mcde *mcde; 12 + u32 cr; 13 + u32 cr_div; 14 + }; 15 + 16 + static int mcde_clk_div_enable(struct clk_hw *hw) 17 + { 18 + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 19 + struct mcde *mcde = cdiv->mcde; 20 + u32 val; 21 + 22 + spin_lock(&mcde->fifo_crx1_lock); 23 + val = readl(mcde->regs + cdiv->cr); 24 + /* 25 + * Select the PLL72 (LCD) clock as parent 26 + * FIXME: implement other parents. 27 + */ 28 + val &= ~MCDE_CRX1_CLKSEL_MASK; 29 + val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT; 30 + /* Internal clock */ 31 + val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1; 32 + 33 + /* Clear then set the divider */ 34 + val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK); 35 + val |= cdiv->cr_div; 36 + 37 + writel(val, mcde->regs + cdiv->cr); 38 + spin_unlock(&mcde->fifo_crx1_lock); 39 + 40 + return 0; 41 + } 42 + 43 + static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate, 44 + unsigned long *prate, bool set_parent) 45 + { 46 + int best_div = 1, div; 47 + struct clk_hw *parent = clk_hw_get_parent(hw); 48 + unsigned long best_prate = 0; 49 + unsigned long best_diff = ~0ul; 50 + int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1; 51 + 52 + for (div = 1; div < max_div; div++) { 53 + unsigned long this_prate, div_rate, diff; 54 + 55 + if (set_parent) 56 + this_prate = clk_hw_round_rate(parent, rate * div); 57 + else 58 + this_prate = *prate; 59 + div_rate = DIV_ROUND_UP_ULL(this_prate, div); 60 + diff = abs(rate - div_rate); 61 + 62 + if (diff < best_diff) { 63 + best_div = div; 64 + best_diff = diff; 65 + best_prate = this_prate; 66 + } 67 + } 68 + 69 + *prate = best_prate; 70 + return best_div; 71 + } 72 + 73 + static long mcde_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, 74 + unsigned long *prate) 75 + { 76 + int div = mcde_clk_div_choose_div(hw, rate, prate, true); 77 + 78 + return DIV_ROUND_UP_ULL(*prate, div); 79 + } 80 + 81 + static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw, 82 + unsigned long prate) 83 + { 84 + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 85 + struct mcde *mcde = cdiv->mcde; 86 + u32 cr; 87 + int div; 88 + 89 + /* 90 + * If the MCDE is not powered we can't access registers. 91 + * It will come up with 0 in the divider register bits, which 92 + * means "divide by 2". 93 + */ 94 + if (!regulator_is_enabled(mcde->epod)) 95 + return DIV_ROUND_UP_ULL(prate, 2); 96 + 97 + cr = readl(mcde->regs + cdiv->cr); 98 + if (cr & MCDE_CRX1_BCD) 99 + return prate; 100 + 101 + /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */ 102 + div = cr & MCDE_CRX1_PCD_MASK; 103 + div += 2; 104 + 105 + return DIV_ROUND_UP_ULL(prate, div); 106 + } 107 + 108 + static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, 109 + unsigned long prate) 110 + { 111 + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); 112 + int div = mcde_clk_div_choose_div(hw, rate, &prate, false); 113 + u32 cr = 0; 114 + 115 + /* 116 + * We cache the CR bits to set the divide in the state so that 117 + * we can call this before we can even write to the hardware. 118 + */ 119 + if (div == 1) { 120 + /* Bypass clock divider */ 121 + cr |= MCDE_CRX1_BCD; 122 + } else { 123 + div -= 2; 124 + cr |= div & MCDE_CRX1_PCD_MASK; 125 + } 126 + cdiv->cr_div = cr; 127 + 128 + return 0; 129 + } 130 + 131 + static const struct clk_ops mcde_clk_div_ops = { 132 + .enable = mcde_clk_div_enable, 133 + .recalc_rate = mcde_clk_div_recalc_rate, 134 + .round_rate = mcde_clk_div_round_rate, 135 + .set_rate = mcde_clk_div_set_rate, 136 + }; 137 + 138 + int mcde_init_clock_divider(struct mcde *mcde) 139 + { 140 + struct device *dev = mcde->dev; 141 + struct mcde_clk_div *fifoa; 142 + struct mcde_clk_div *fifob; 143 + const char *parent_name; 144 + struct clk_init_data fifoa_init = { 145 + .name = "fifoa", 146 + .ops = &mcde_clk_div_ops, 147 + .parent_names = &parent_name, 148 + .num_parents = 1, 149 + .flags = CLK_SET_RATE_PARENT, 150 + }; 151 + struct clk_init_data fifob_init = { 152 + .name = "fifob", 153 + .ops = &mcde_clk_div_ops, 154 + .parent_names = &parent_name, 155 + .num_parents = 1, 156 + .flags = CLK_SET_RATE_PARENT, 157 + }; 158 + int ret; 159 + 160 + spin_lock_init(&mcde->fifo_crx1_lock); 161 + parent_name = __clk_get_name(mcde->lcd_clk); 162 + 163 + /* Allocate 2 clocks */ 164 + fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL); 165 + if (!fifoa) 166 + return -ENOMEM; 167 + fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL); 168 + if (!fifob) 169 + return -ENOMEM; 170 + 171 + fifoa->mcde = mcde; 172 + fifoa->cr = MCDE_CRA1; 173 + fifoa->hw.init = &fifoa_init; 174 + ret = devm_clk_hw_register(dev, &fifoa->hw); 175 + if (ret) { 176 + dev_err(dev, "error registering FIFO A clock divider\n"); 177 + return ret; 178 + } 179 + mcde->fifoa_clk = fifoa->hw.clk; 180 + 181 + fifob->mcde = mcde; 182 + fifob->cr = MCDE_CRB1; 183 + fifob->hw.init = &fifob_init; 184 + ret = devm_clk_hw_register(dev, &fifob->hw); 185 + if (ret) { 186 + dev_err(dev, "error registering FIFO B clock divider\n"); 187 + return ret; 188 + } 189 + mcde->fifob_clk = fifob->hw.clk; 190 + 191 + return 0; 192 + }
+269 -33
drivers/gpu/drm/mcde/mcde_display.c
··· 8 8 #include <linux/delay.h> 9 9 #include <linux/dma-buf.h> 10 10 #include <linux/regulator/consumer.h> 11 + #include <linux/media-bus-format.h> 11 12 12 13 #include <drm/drm_device.h> 13 14 #include <drm/drm_fb_cma_helper.h> ··· 17 16 #include <drm/drm_gem_framebuffer_helper.h> 18 17 #include <drm/drm_mipi_dsi.h> 19 18 #include <drm/drm_simple_kms_helper.h> 19 + #include <drm/drm_bridge.h> 20 20 #include <drm/drm_vblank.h> 21 21 #include <video/mipi_display.h> 22 22 ··· 59 57 MCDE_OVERLAY_5, 60 58 }; 61 59 62 - enum mcde_dsi_formatter { 60 + enum mcde_formatter { 63 61 MCDE_DSI_FORMATTER_0 = 0, 64 62 MCDE_DSI_FORMATTER_1, 65 63 MCDE_DSI_FORMATTER_2, 64 + MCDE_DSI_FORMATTER_3, 65 + MCDE_DSI_FORMATTER_4, 66 + MCDE_DSI_FORMATTER_5, 67 + MCDE_DPI_FORMATTER_0, 68 + MCDE_DPI_FORMATTER_1, 66 69 }; 67 70 68 71 void mcde_display_irq(struct mcde *mcde) ··· 88 81 * 89 82 * TODO: Currently only one DSI link is supported. 90 83 */ 91 - if (mcde_dsi_irq(mcde->mdsi)) { 84 + if (!mcde->dpi_output && mcde_dsi_irq(mcde->mdsi)) { 92 85 u32 val; 93 86 94 87 /* ··· 560 553 << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 561 554 break; 562 555 case MCDE_VIDEO_FORMATTER_FLOW: 556 + case MCDE_DPI_FORMATTER_FLOW: 563 557 val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 564 558 << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 565 559 val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER ··· 599 591 mcde->regs + mux); 600 592 break; 601 593 } 594 + 595 + /* 596 + * If using DPI configure the sync event. 597 + * TODO: this is for LCD only, it does not cover TV out. 598 + */ 599 + if (mcde->dpi_output) { 600 + u32 stripwidth; 601 + 602 + stripwidth = 0xF000 / (mode->vdisplay * 4); 603 + dev_info(mcde->dev, "stripwidth: %d\n", stripwidth); 604 + 605 + val = MCDE_SYNCHCONF_HWREQVEVENT_ACTIVE_VIDEO | 606 + (mode->hdisplay - 1 - stripwidth) << MCDE_SYNCHCONF_HWREQVCNT_SHIFT | 607 + MCDE_SYNCHCONF_SWINTVEVENT_ACTIVE_VIDEO | 608 + (mode->hdisplay - 1 - stripwidth) << MCDE_SYNCHCONF_SWINTVCNT_SHIFT; 609 + 610 + switch (fifo) { 611 + case MCDE_FIFO_A: 612 + writel(val, mcde->regs + MCDE_SYNCHCONFA); 613 + break; 614 + case MCDE_FIFO_B: 615 + writel(val, mcde->regs + MCDE_SYNCHCONFB); 616 + break; 617 + } 618 + } 602 619 } 603 620 604 621 static void mcde_configure_fifo(struct mcde *mcde, enum mcde_fifo fifo, 605 - enum mcde_dsi_formatter fmt, 622 + enum mcde_formatter fmt, 606 623 int fifo_wtrmrk) 607 624 { 608 625 u32 val; ··· 648 615 } 649 616 650 617 val = fifo_wtrmrk << MCDE_CTRLX_FIFOWTRMRK_SHIFT; 651 - /* We only support DSI formatting for now */ 652 - val |= MCDE_CTRLX_FORMTYPE_DSI << 653 - MCDE_CTRLX_FORMTYPE_SHIFT; 654 618 655 - /* Select the formatter to use for this FIFO */ 656 - val |= fmt << MCDE_CTRLX_FORMID_SHIFT; 619 + /* 620 + * Select the formatter to use for this FIFO 621 + * 622 + * The register definitions imply that different IDs should be used 623 + * by the DSI formatters depending on if they are in VID or CMD 624 + * mode, and the manual says they are dedicated but identical. 625 + * The vendor code uses them as it seems fit. 626 + */ 627 + switch (fmt) { 628 + case MCDE_DSI_FORMATTER_0: 629 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 630 + val |= MCDE_CTRLX_FORMID_DSI0VID << MCDE_CTRLX_FORMID_SHIFT; 631 + break; 632 + case MCDE_DSI_FORMATTER_1: 633 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 634 + val |= MCDE_CTRLX_FORMID_DSI0CMD << MCDE_CTRLX_FORMID_SHIFT; 635 + break; 636 + case MCDE_DSI_FORMATTER_2: 637 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 638 + val |= MCDE_CTRLX_FORMID_DSI1VID << MCDE_CTRLX_FORMID_SHIFT; 639 + break; 640 + case MCDE_DSI_FORMATTER_3: 641 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 642 + val |= MCDE_CTRLX_FORMID_DSI1CMD << MCDE_CTRLX_FORMID_SHIFT; 643 + break; 644 + case MCDE_DSI_FORMATTER_4: 645 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 646 + val |= MCDE_CTRLX_FORMID_DSI2VID << MCDE_CTRLX_FORMID_SHIFT; 647 + break; 648 + case MCDE_DSI_FORMATTER_5: 649 + val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 650 + val |= MCDE_CTRLX_FORMID_DSI2CMD << MCDE_CTRLX_FORMID_SHIFT; 651 + break; 652 + case MCDE_DPI_FORMATTER_0: 653 + val |= MCDE_CTRLX_FORMTYPE_DPITV << MCDE_CTRLX_FORMTYPE_SHIFT; 654 + val |= MCDE_CTRLX_FORMID_DPIA << MCDE_CTRLX_FORMID_SHIFT; 655 + break; 656 + case MCDE_DPI_FORMATTER_1: 657 + val |= MCDE_CTRLX_FORMTYPE_DPITV << MCDE_CTRLX_FORMTYPE_SHIFT; 658 + val |= MCDE_CTRLX_FORMID_DPIB << MCDE_CTRLX_FORMID_SHIFT; 659 + break; 660 + } 657 661 writel(val, mcde->regs + ctrl); 658 662 659 663 /* Blend source with Alpha 0xff on FIFO */ ··· 698 628 0xff << MCDE_CRX0_ALPHABLEND_SHIFT; 699 629 writel(val, mcde->regs + cr0); 700 630 701 - /* Set-up from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */ 631 + spin_lock(&mcde->fifo_crx1_lock); 632 + val = readl(mcde->regs + cr1); 633 + /* 634 + * Set-up from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() 635 + * FIXME: a different clock needs to be selected for TV out. 636 + */ 637 + if (mcde->dpi_output) { 638 + struct drm_connector *connector = drm_panel_bridge_connector(mcde->bridge); 639 + u32 bus_format; 702 640 703 - /* Use the MCDE clock for this FIFO */ 704 - val = MCDE_CRX1_CLKSEL_MCDECLK << MCDE_CRX1_CLKSEL_SHIFT; 641 + /* Assume RGB888 24 bit if we have no further info */ 642 + if (!connector->display_info.num_bus_formats) { 643 + dev_info(mcde->dev, "panel does not specify bus format, assume RGB888\n"); 644 + bus_format = MEDIA_BUS_FMT_RGB888_1X24; 645 + } else { 646 + bus_format = connector->display_info.bus_formats[0]; 647 + } 705 648 706 - /* TODO: when adding DPI support add OUTBPP etc here */ 649 + /* 650 + * Set up the CDWIN and OUTBPP for the LCD 651 + * 652 + * FIXME: fill this in if you know the correspondance between the MIPI 653 + * DPI specification and the media bus formats. 654 + */ 655 + val &= ~MCDE_CRX1_CDWIN_MASK; 656 + val &= ~MCDE_CRX1_OUTBPP_MASK; 657 + switch (bus_format) { 658 + case MEDIA_BUS_FMT_RGB888_1X24: 659 + val |= MCDE_CRX1_CDWIN_24BPP << MCDE_CRX1_CDWIN_SHIFT; 660 + val |= MCDE_CRX1_OUTBPP_24BPP << MCDE_CRX1_OUTBPP_SHIFT; 661 + break; 662 + default: 663 + dev_err(mcde->dev, "unknown bus format, assume RGB888\n"); 664 + val |= MCDE_CRX1_CDWIN_24BPP << MCDE_CRX1_CDWIN_SHIFT; 665 + val |= MCDE_CRX1_OUTBPP_24BPP << MCDE_CRX1_OUTBPP_SHIFT; 666 + break; 667 + } 668 + } else { 669 + /* Use the MCDE clock for DSI */ 670 + val &= ~MCDE_CRX1_CLKSEL_MASK; 671 + val = MCDE_CRX1_CLKSEL_MCDECLK << MCDE_CRX1_CLKSEL_SHIFT; 672 + } 707 673 writel(val, mcde->regs + cr1); 674 + spin_unlock(&mcde->fifo_crx1_lock); 708 675 }; 709 676 710 677 static void mcde_configure_dsi_formatter(struct mcde *mcde, 711 - enum mcde_dsi_formatter fmt, 678 + enum mcde_formatter fmt, 712 679 u32 formatter_frame, 713 680 int pkt_size) 714 681 { ··· 785 678 delay0 = MCDE_DSIVID2DELAY0; 786 679 delay1 = MCDE_DSIVID2DELAY1; 787 680 break; 681 + default: 682 + dev_err(mcde->dev, "tried to configure a non-DSI formatter as DSI\n"); 683 + return; 788 684 } 789 685 790 686 /* ··· 969 859 return 1; 970 860 } 971 861 862 + static void mcde_setup_dpi(struct mcde *mcde, const struct drm_display_mode *mode, 863 + int *fifo_wtrmrk_lvl) 864 + { 865 + struct drm_connector *connector = drm_panel_bridge_connector(mcde->bridge); 866 + u32 hsw, hfp, hbp; 867 + u32 vsw, vfp, vbp; 868 + u32 val; 869 + 870 + /* FIXME: we only support LCD, implement TV out */ 871 + hsw = mode->hsync_end - mode->hsync_start; 872 + hfp = mode->hsync_start - mode->hdisplay; 873 + hbp = mode->htotal - mode->hsync_end; 874 + vsw = mode->vsync_end - mode->vsync_start; 875 + vfp = mode->vsync_start - mode->vdisplay; 876 + vbp = mode->vtotal - mode->vsync_end; 877 + 878 + dev_info(mcde->dev, "output on DPI LCD from channel A\n"); 879 + /* Display actual values */ 880 + dev_info(mcde->dev, "HSW: %d, HFP: %d, HBP: %d, VSW: %d, VFP: %d, VBP: %d\n", 881 + hsw, hfp, hbp, vsw, vfp, vbp); 882 + 883 + /* 884 + * The pixel fetcher is 128 64-bit words deep = 1024 bytes. 885 + * One overlay of 32bpp (4 cpp) assumed, fetch 160 pixels. 886 + * 160 * 4 = 640 bytes. 887 + */ 888 + *fifo_wtrmrk_lvl = 640; 889 + 890 + /* Set up the main control, watermark level at 7 */ 891 + val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; 892 + 893 + /* 894 + * This sets up the internal silicon muxing of the DPI 895 + * lines. This is how the silicon connects out to the 896 + * external pins, then the pins need to be further 897 + * configured into "alternate functions" using pin control 898 + * to actually get the signals out. 899 + * 900 + * FIXME: this is hardcoded to the only setting found in 901 + * the wild. If we need to use different settings for 902 + * different DPI displays, make this parameterizable from 903 + * the device tree. 904 + */ 905 + /* 24 bits DPI: connect Ch A LSB to D[0:7] */ 906 + val |= 0 << MCDE_CONF0_OUTMUX0_SHIFT; 907 + /* 24 bits DPI: connect Ch A MID to D[8:15] */ 908 + val |= 1 << MCDE_CONF0_OUTMUX1_SHIFT; 909 + /* Don't care about this muxing */ 910 + val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; 911 + /* Don't care about this muxing */ 912 + val |= 0 << MCDE_CONF0_OUTMUX3_SHIFT; 913 + /* 24 bits DPI: connect Ch A MSB to D[32:39] */ 914 + val |= 2 << MCDE_CONF0_OUTMUX4_SHIFT; 915 + /* Syncmux bits zero: DPI channel A */ 916 + writel(val, mcde->regs + MCDE_CONF0); 917 + 918 + /* This hammers us into LCD mode */ 919 + writel(0, mcde->regs + MCDE_TVCRA); 920 + 921 + /* Front porch and sync width */ 922 + val = (vsw << MCDE_TVBL1_BEL1_SHIFT); 923 + val |= (vfp << MCDE_TVBL1_BSL1_SHIFT); 924 + writel(val, mcde->regs + MCDE_TVBL1A); 925 + /* The vendor driver sets the same value into TVBL2A */ 926 + writel(val, mcde->regs + MCDE_TVBL2A); 927 + 928 + /* Vertical back porch */ 929 + val = (vbp << MCDE_TVDVO_DVO1_SHIFT); 930 + /* The vendor drivers sets the same value into TVDVOA */ 931 + val |= (vbp << MCDE_TVDVO_DVO2_SHIFT); 932 + writel(val, mcde->regs + MCDE_TVDVOA); 933 + 934 + /* Horizontal back porch, as 0 = 1 cycle we need to subtract 1 */ 935 + writel((hbp - 1), mcde->regs + MCDE_TVTIM1A); 936 + 937 + /* Horizongal sync width and horizonal front porch, 0 = 1 cycle */ 938 + val = ((hsw - 1) << MCDE_TVLBALW_LBW_SHIFT); 939 + val |= ((hfp - 1) << MCDE_TVLBALW_ALW_SHIFT); 940 + writel(val, mcde->regs + MCDE_TVLBALWA); 941 + 942 + /* Blank some TV registers we don't use */ 943 + writel(0, mcde->regs + MCDE_TVISLA); 944 + writel(0, mcde->regs + MCDE_TVBLUA); 945 + 946 + /* Set up sync inversion etc */ 947 + val = 0; 948 + if (mode->flags & DRM_MODE_FLAG_NHSYNC) 949 + val |= MCDE_LCDTIM1B_IHS; 950 + if (mode->flags & DRM_MODE_FLAG_NVSYNC) 951 + val |= MCDE_LCDTIM1B_IVS; 952 + if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) 953 + val |= MCDE_LCDTIM1B_IOE; 954 + if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 955 + val |= MCDE_LCDTIM1B_IPC; 956 + writel(val, mcde->regs + MCDE_LCDTIM1A); 957 + } 958 + 972 959 static void mcde_setup_dsi(struct mcde *mcde, const struct drm_display_mode *mode, 973 960 int cpp, int *fifo_wtrmrk_lvl, int *dsi_formatter_frame, 974 961 int *dsi_pkt_size) ··· 1183 976 writel(0, mcde->regs + MCDE_IMSCERR); 1184 977 writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); 1185 978 1186 - mcde_setup_dsi(mcde, mode, cpp, &fifo_wtrmrk, 1187 - &dsi_formatter_frame, &dsi_pkt_size); 979 + if (mcde->dpi_output) 980 + mcde_setup_dpi(mcde, mode, &fifo_wtrmrk); 981 + else 982 + mcde_setup_dsi(mcde, mode, cpp, &fifo_wtrmrk, 983 + &dsi_formatter_frame, &dsi_pkt_size); 1188 984 1189 985 mcde->stride = mode->hdisplay * cpp; 1190 986 dev_dbg(drm->dev, "Overlay line stride: %u bytes\n", ··· 1219 1009 */ 1220 1010 mcde_configure_channel(mcde, MCDE_CHANNEL_0, MCDE_FIFO_A, mode); 1221 1011 1222 - /* Configure FIFO A to use DSI formatter 0 */ 1223 - mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, 1224 - fifo_wtrmrk); 1012 + if (mcde->dpi_output) { 1013 + unsigned long lcd_freq; 1225 1014 1226 - /* 1227 - * This brings up the DSI bridge which is tightly connected 1228 - * to the MCDE DSI formatter. 1229 - * 1230 - * FIXME: if we want to use another formatter, such as DPI, 1231 - * we need to be more elaborate here and select the appropriate 1232 - * bridge. 1233 - */ 1234 - mcde_dsi_enable(mcde->bridge); 1015 + /* Configure FIFO A to use DPI formatter 0 */ 1016 + mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DPI_FORMATTER_0, 1017 + fifo_wtrmrk); 1235 1018 1236 - /* Configure the DSI formatter 0 for the DSI panel output */ 1237 - mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, 1238 - dsi_formatter_frame, dsi_pkt_size); 1019 + /* Set up and enable the LCD clock */ 1020 + lcd_freq = clk_round_rate(mcde->fifoa_clk, mode->clock * 1000); 1021 + ret = clk_set_rate(mcde->fifoa_clk, lcd_freq); 1022 + if (ret) 1023 + dev_err(mcde->dev, "failed to set LCD clock rate %lu Hz\n", 1024 + lcd_freq); 1025 + ret = clk_prepare_enable(mcde->fifoa_clk); 1026 + if (ret) { 1027 + dev_err(mcde->dev, "failed to enable FIFO A DPI clock\n"); 1028 + return; 1029 + } 1030 + dev_info(mcde->dev, "LCD FIFO A clk rate %lu Hz\n", 1031 + clk_get_rate(mcde->fifoa_clk)); 1032 + } else { 1033 + /* Configure FIFO A to use DSI formatter 0 */ 1034 + mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, 1035 + fifo_wtrmrk); 1036 + 1037 + /* 1038 + * This brings up the DSI bridge which is tightly connected 1039 + * to the MCDE DSI formatter. 1040 + */ 1041 + mcde_dsi_enable(mcde->bridge); 1042 + 1043 + /* Configure the DSI formatter 0 for the DSI panel output */ 1044 + mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, 1045 + dsi_formatter_frame, dsi_pkt_size); 1046 + } 1239 1047 1240 1048 switch (mcde->flow_mode) { 1241 1049 case MCDE_COMMAND_TE_FLOW: 1242 1050 case MCDE_COMMAND_BTA_TE_FLOW: 1243 1051 case MCDE_VIDEO_TE_FLOW: 1244 - /* We are using TE in some comination */ 1052 + /* We are using TE in some combination */ 1245 1053 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 1246 1054 val = MCDE_VSCRC_VSPOL; 1247 1055 else ··· 1311 1083 /* Disable FIFO A flow */ 1312 1084 mcde_disable_fifo(mcde, MCDE_FIFO_A, true); 1313 1085 1314 - /* This disables the DSI bridge */ 1315 - mcde_dsi_disable(mcde->bridge); 1086 + if (mcde->dpi_output) { 1087 + clk_disable_unprepare(mcde->fifoa_clk); 1088 + } else { 1089 + /* This disables the DSI bridge */ 1090 + mcde_dsi_disable(mcde->bridge); 1091 + } 1316 1092 1317 1093 event = crtc->state->event; 1318 1094 if (event) { ··· 1506 1274 DRM_FORMAT_BGR565, 1507 1275 DRM_FORMAT_YUV422, 1508 1276 }; 1277 + 1278 + ret = mcde_init_clock_divider(mcde); 1279 + if (ret) 1280 + return ret; 1509 1281 1510 1282 ret = drm_simple_display_pipe_init(drm, &mcde->pipe, 1511 1283 &mcde_display_funcs,
+87
drivers/gpu/drm/mcde/mcde_display_regs.h
··· 215 215 #define MCDE_OVLXCOMP_Z_SHIFT 27 216 216 #define MCDE_OVLXCOMP_Z_MASK 0x78000000 217 217 218 + /* DPI/TV configuration registers, channel A and B */ 219 + #define MCDE_TVCRA 0x00000838 220 + #define MCDE_TVCRB 0x00000A38 221 + #define MCDE_TVCR_MOD_TV BIT(0) /* 0 = LCD mode */ 222 + #define MCDE_TVCR_INTEREN BIT(1) 223 + #define MCDE_TVCR_IFIELD BIT(2) 224 + #define MCDE_TVCR_TVMODE_SDTV_656P (0 << 3) 225 + #define MCDE_TVCR_TVMODE_SDTV_656P_LE (3 << 3) 226 + #define MCDE_TVCR_TVMODE_SDTV_656P_BE (4 << 3) 227 + #define MCDE_TVCR_SDTVMODE_Y0CBY1CR (0 << 6) 228 + #define MCDE_TVCR_SDTVMODE_CBY0CRY1 (1 << 6) 229 + #define MCDE_TVCR_AVRGEN BIT(8) 230 + #define MCDE_TVCR_CKINV BIT(9) 231 + 232 + /* TV blanking control register 1, channel A and B */ 233 + #define MCDE_TVBL1A 0x0000083C 234 + #define MCDE_TVBL1B 0x00000A3C 235 + #define MCDE_TVBL1_BEL1_SHIFT 0 /* VFP vertical front porch 11 bits */ 236 + #define MCDE_TVBL1_BSL1_SHIFT 16 /* VSW vertical sync pulse width 11 bits */ 237 + 238 + /* Pixel processing TV start line, channel A and B */ 239 + #define MCDE_TVISLA 0x00000840 240 + #define MCDE_TVISLB 0x00000A40 241 + #define MCDE_TVISL_FSL1_SHIFT 0 /* Field 1 identification start line 11 bits */ 242 + #define MCDE_TVISL_FSL2_SHIFT 16 /* Field 2 identification start line 11 bits */ 243 + 244 + /* Pixel processing TV DVO offset */ 245 + #define MCDE_TVDVOA 0x00000844 246 + #define MCDE_TVDVOB 0x00000A44 247 + #define MCDE_TVDVO_DVO1_SHIFT 0 /* VBP vertical back porch 0 = 0 */ 248 + #define MCDE_TVDVO_DVO2_SHIFT 16 249 + 250 + /* 251 + * Pixel processing TV Timing 1 252 + * HBP horizontal back porch 11 bits horizontal offset 253 + * 0 = 1 pixel HBP, 255 = 256 pixels, so actual value - 1 254 + */ 255 + #define MCDE_TVTIM1A 0x0000084C 256 + #define MCDE_TVTIM1B 0x00000A4C 257 + 258 + /* Pixel processing TV LBALW */ 259 + /* 0 = 1 clock cycle, 255 = 256 clock cycles */ 260 + #define MCDE_TVLBALWA 0x00000850 261 + #define MCDE_TVLBALWB 0x00000A50 262 + #define MCDE_TVLBALW_LBW_SHIFT 0 /* HSW horizonal sync width, line blanking width 11 bits */ 263 + #define MCDE_TVLBALW_ALW_SHIFT 16 /* HFP horizontal front porch, active line width 11 bits */ 264 + 265 + /* TV blanking control register 1, channel A and B */ 266 + #define MCDE_TVBL2A 0x00000854 267 + #define MCDE_TVBL2B 0x00000A54 268 + #define MCDE_TVBL2_BEL2_SHIFT 0 /* Field 2 blanking end line 11 bits */ 269 + #define MCDE_TVBL2_BSL2_SHIFT 16 /* Field 2 blanking start line 11 bits */ 270 + 271 + /* Pixel processing TV background */ 272 + #define MCDE_TVBLUA 0x00000858 273 + #define MCDE_TVBLUB 0x00000A58 274 + #define MCDE_TVBLU_TVBLU_SHIFT 0 /* 8 bits luminance */ 275 + #define MCDE_TVBLU_TVBCB_SHIFT 8 /* 8 bits Cb chrominance */ 276 + #define MCDE_TVBLU_TVBCR_SHIFT 16 /* 8 bits Cr chrominance */ 277 + 278 + /* Pixel processing LCD timing 1 */ 279 + #define MCDE_LCDTIM1A 0x00000860 280 + #define MCDE_LCDTIM1B 0x00000A60 281 + /* inverted vertical sync pulse for HRTFT 0 = active low, 1 active high */ 282 + #define MCDE_LCDTIM1B_IVP BIT(19) 283 + /* inverted vertical sync, 0 = active high (the normal), 1 = active low */ 284 + #define MCDE_LCDTIM1B_IVS BIT(20) 285 + /* inverted horizontal sync, 0 = active high (the normal), 1 = active low */ 286 + #define MCDE_LCDTIM1B_IHS BIT(21) 287 + /* inverted panel clock 0 = rising edge data out, 1 = falling edge data out */ 288 + #define MCDE_LCDTIM1B_IPC BIT(22) 289 + /* invert output enable 0 = active high, 1 = active low */ 290 + #define MCDE_LCDTIM1B_IOE BIT(23) 291 + 218 292 #define MCDE_CRC 0x00000C00 219 293 #define MCDE_CRC_C1EN BIT(2) 220 294 #define MCDE_CRC_C2EN BIT(3) ··· 434 360 #define MCDE_CRB1 0x00000A04 435 361 #define MCDE_CRX1_PCD_SHIFT 0 436 362 #define MCDE_CRX1_PCD_MASK 0x000003FF 363 + #define MCDE_CRX1_PCD_BITS 10 437 364 #define MCDE_CRX1_CLKSEL_SHIFT 10 438 365 #define MCDE_CRX1_CLKSEL_MASK 0x00001C00 439 366 #define MCDE_CRX1_CLKSEL_CLKPLL72 0 ··· 496 421 #define MCDE_ROTACONF 0x0000087C 497 422 #define MCDE_ROTBCONF 0x00000A7C 498 423 424 + /* Synchronization event configuration */ 499 425 #define MCDE_SYNCHCONFA 0x00000880 500 426 #define MCDE_SYNCHCONFB 0x00000A80 427 + #define MCDE_SYNCHCONF_HWREQVEVENT_SHIFT 0 428 + #define MCDE_SYNCHCONF_HWREQVEVENT_VSYNC (0 << 0) 429 + #define MCDE_SYNCHCONF_HWREQVEVENT_BACK_PORCH (1 << 0) 430 + #define MCDE_SYNCHCONF_HWREQVEVENT_ACTIVE_VIDEO (2 << 0) 431 + #define MCDE_SYNCHCONF_HWREQVEVENT_FRONT_PORCH (3 << 0) 432 + #define MCDE_SYNCHCONF_HWREQVCNT_SHIFT 2 /* 14 bits */ 433 + #define MCDE_SYNCHCONF_SWINTVEVENT_VSYNC (0 << 16) 434 + #define MCDE_SYNCHCONF_SWINTVEVENT_BACK_PORCH (1 << 16) 435 + #define MCDE_SYNCHCONF_SWINTVEVENT_ACTIVE_VIDEO (2 << 16) 436 + #define MCDE_SYNCHCONF_SWINTVEVENT_FRONT_PORCH (3 << 16) 437 + #define MCDE_SYNCHCONF_SWINTVCNT_SHIFT 18 /* 14 bits */ 501 438 502 439 /* Channel A+B control registers */ 503 440 #define MCDE_CTRLA 0x00000884
+10
drivers/gpu/drm/mcde/mcde_drm.h
··· 62 62 MCDE_VIDEO_TE_FLOW, 63 63 /* Video mode with the formatter itself as sync source */ 64 64 MCDE_VIDEO_FORMATTER_FLOW, 65 + /* DPI video with the formatter itsels as sync source */ 66 + MCDE_DPI_FORMATTER_FLOW, 65 67 }; 66 68 67 69 struct mcde { ··· 74 72 struct drm_connector *connector; 75 73 struct drm_simple_display_pipe pipe; 76 74 struct mipi_dsi_device *mdsi; 75 + bool dpi_output; 77 76 s16 stride; 78 77 enum mcde_flow_mode flow_mode; 79 78 unsigned int flow_active; ··· 85 82 struct clk *mcde_clk; 86 83 struct clk *lcd_clk; 87 84 struct clk *hdmi_clk; 85 + /* Handles to the clock dividers for FIFO A and B */ 86 + struct clk *fifoa_clk; 87 + struct clk *fifob_clk; 88 + /* Locks the MCDE FIFO control register A and B */ 89 + spinlock_t fifo_crx1_lock; 88 90 89 91 struct regulator *epod; 90 92 struct regulator *vana; ··· 112 104 void mcde_display_irq(struct mcde *mcde); 113 105 void mcde_display_disable_irqs(struct mcde *mcde); 114 106 int mcde_display_init(struct drm_device *drm); 107 + 108 + int mcde_init_clock_divider(struct mcde *mcde); 115 109 116 110 #endif /* _MCDE_DRM_H_ */
+34 -12
drivers/gpu/drm/mcde/mcde_drv.c
··· 22 22 * The hardware has four display pipes, and the layout is a little 23 23 * bit like this:: 24 24 * 25 - * Memory -> Overlay -> Channel -> FIFO -> 5 formatters -> DSI/DPI 26 - * External 0..5 0..3 A,B, 3 x DSI bridge 25 + * Memory -> Overlay -> Channel -> FIFO -> 8 formatters -> DSI/DPI 26 + * External 0..5 0..3 A,B, 6 x DSI bridge 27 27 * source 0..9 C0,C1 2 x DPI 28 28 * 29 29 * FIFOs A and B are for LCD and HDMI while FIFO CO/C1 are for 30 30 * panels with embedded buffer. 31 - * 3 of the formatters are for DSI. 31 + * 6 of the formatters are for DSI, 3 pairs for VID/CMD respectively. 32 32 * 2 of the formatters are for DPI. 33 33 * 34 34 * Behind the formatters are the DSI or DPI ports that route to ··· 130 130 struct mcde *mcde = to_mcde(drm); 131 131 int ret; 132 132 133 + /* 134 + * If no other bridge was found, check if we have a DPI panel or 135 + * any other bridge connected directly to the MCDE DPI output. 136 + * If a DSI bridge is found, DSI will take precedence. 137 + * 138 + * TODO: more elaborate bridge selection if we have more than one 139 + * thing attached to the system. 140 + */ 133 141 if (!mcde->bridge) { 134 - dev_err(drm->dev, "no display output bridge yet\n"); 135 - return -EPROBE_DEFER; 142 + struct drm_panel *panel; 143 + struct drm_bridge *bridge; 144 + 145 + ret = drm_of_find_panel_or_bridge(drm->dev->of_node, 146 + 0, 0, &panel, &bridge); 147 + if (ret) { 148 + dev_err(drm->dev, 149 + "Could not locate any output bridge or panel\n"); 150 + return ret; 151 + } 152 + if (panel) { 153 + bridge = drm_panel_bridge_add_typed(panel, 154 + DRM_MODE_CONNECTOR_DPI); 155 + if (IS_ERR(bridge)) { 156 + dev_err(drm->dev, 157 + "Could not connect panel bridge\n"); 158 + return PTR_ERR(bridge); 159 + } 160 + } 161 + mcde->dpi_output = true; 162 + mcde->bridge = bridge; 163 + mcde->flow_mode = MCDE_DPI_FORMATTER_FLOW; 136 164 } 137 165 138 166 mode_config = &drm->mode_config; ··· 184 156 return ret; 185 157 } 186 158 187 - /* 188 - * Attach the DSI bridge 189 - * 190 - * TODO: when adding support for the DPI bridge or several DSI bridges, 191 - * we selectively connect the bridge(s) here instead of this simple 192 - * attachment. 193 - */ 159 + /* Attach the bridge. */ 194 160 ret = drm_simple_display_pipe_attach_bridge(&mcde->pipe, 195 161 mcde->bridge); 196 162 if (ret) {