Wrong LVDS-clock from i.MX6

cancel
Showing results for 
Search instead for 
Did you mean: 

Wrong LVDS-clock from i.MX6

2,674 Views
steffendoster
Contributor IV

Hi,

I'm running mad with that!

The i.MX6S on my custom board has only a display connected to LVDS0. I managed to get a working U-Boot and Linux 4.5 (mainline) environment.

But I still have a big problem with the display: the LVDS clock semm to be stuck at 72MHz (U-Boot) and 68MHz (Linux).

I already tried to change the timuings, but the clock dosn't ever change.

My configurations are derived from NXP's SabreSD-Board.

 

Heres my LDB-Entry from Devicetree:

Snippet
ldb: ldb@020e0008 {
         #address-cells = <1>;
         #size-cells = <0>;
         compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb";
         gpr = <&gpr>;
         clocks = <&clks IMX6QDL_CLK_LDB_DI0>, <&clks IMX6QDL_CLK_LDB_DI1>,
                    <&clks IMX6QDL_CLK_IPU1_DI0_SEL>, <&clks IMX6QDL_CLK_IPU1_DI1_SEL>,
                    <&clks IMX6QDL_CLK_IPU2_DI0_SEL>,
                    <&clks IMX6QDL_CLK_LDB_DI0_DIV_3_5>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_3_5>,
                    <&clks IMX6QDL_CLK_LDB_DI0_DIV_7>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_7>,
                    <&clks IMX6QDL_CLK_LDB_DI0_DIV_SEL>, <&clks IMX6QDL_CLK_LDB_DI1_DIV_SEL>;
         clock-names = "ldb_di0", "ldb_di1",
                         "di0_sel", "di1_sel",
                         "di2_sel",
                         "ldb_di0_div_3_5", "ldb_di1_div_3_5",
                         "ldb_di0_div_7", "ldb_di1_div_7",
                         "ldb_di0_div_sel", "ldb_di1_div_sel";
         status = "okay";
           lvds-channel@0 {
             #address-cells = <1>;
             #size-cells = <0>;
             reg = <0>;
             fsl,data-mapping = "jeida";
             fsl,data-width = <24>;                    /* JEIDA only support 24bit */
             status = "okay";
               /*crtc = "ipu1-di0";*/
             /*fsl,data-mapping = "spwg";*/
             /*primary;*/
               display-timings {
                 native-mode = <&timing0>;
                   /* Display Timings for TFT-Display DLC0700JMG */
                 timing0: dlc0700jmg {
                     clock-frequency = <51200000>;
                     hactive = <1024>;
                     vactive = <600>;
                     hfront-porch = <16 160 216>;
                     hback-porch = <160>;
                     hsync-len = <1 70 140>;
                     hsync-active = <1>;
                     vfront-porch = <1 12 127>;
                     vback-porch = <23>;
                     vsync-len = <1 10 20>;
                     vsync-active = <1>;
                 };
             };
               port@0 {
                 reg = <0>;
                 lvds0_mux_0: endpoint {
                     remote-endpoint = <&ipu1_di0_lvds0>;
                 };
             };
               port@1 {
                 reg = <1>;
                 lvds0_mux_1: endpoint {
                     remote-endpoint = <&ipu1_di1_lvds0>;
                 };
             };
         };
           /* LVDS-Channel 1 leads only to ICT-Pads and doesn't have any function. */
         lvds-channel@1 {
             #address-cells = <1>;
             #size-cells = <0>;
             reg = <1>;
             crtc = "ipu1-di1";
             /*fsl,data-mapping = "jeida";*/
             fsl,data-mapping = "spwg";             fsl,data-width = <18>;
             status = "disabled";
               port@0 {
                 reg = <0>;
                 lvds1_mux_0: endpoint {
                     remote-endpoint = <&ipu1_di0_lvds1>;
                 };
             };
               port@1 {
                 reg = <1>;
                 lvds1_mux_1: endpoint {
                     remote-endpoint = <&ipu1_di1_lvds1>;
                 };
             };
         };
     }; 

And this is the timing in U-Boot:

struct display_info_t const displays[] = { {
     .bus     = -1,
     .addr     = 0,
     .pixfmt = IPU_PIX_FMT_LVDS666,
     .detect = NULL,
     .enable     = enable_lvds,
     .mode     = {
         .name = "DLC0700JBG",         // Typ. Clock Frequency = 51200000 Hz
        .refresh         = 60,
         .xres            = 1024,
         .yres            = 600,
         .pixclock        = 19531,   // = 10^12 / Clock Frequency
        .left_margin     = 160,
         .right_margin    = 160,
         .upper_margin    = 12,
         .lower_margin    = 23,
         .hsync_len       = 70,
         .vsync_len       = 10,
         .sync            = 0,
         .vmode           = FB_VMODE_NONINTERLACED
 } }, followed by two unused timings

I already read, that there must be some misconfiguration about the wrong clock-parent or something like this

Tags (1)
0 Kudos
4 Replies

1,131 Views
steffendoster
Contributor IV

OK, I managed to get the correct clock from Linux-Kernel. I changed:

clks: ccm@020c4000 {
    compatible = "fsl,imx6q-ccm";
    reg = <0x020c4000 0x4000>;
    interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>,
                 <0 88 IRQ_TYPE_LEVEL_HIGH>;
    #clock-cells = <1>;
    assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
                      <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
    assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
                             <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
};

to:
clks: ccm@020c4000 {
    compatible = "fsl,imx6q-ccm";
    reg = <0x020c4000 0x4000>;
    interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>,
                 <0 88 IRQ_TYPE_LEVEL_HIGH>;
    #clock-cells = <1>;
    assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
                      <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
    assigned-clock-parents = <&clks IMX6QDL_CLK_PLL5_VIDEO>,
                             <&clks IMX6QDL_CLK_PLL5_VIDEO>;
};

This fixed my problem in Linux. Now I have the desired 51.2MHz clock there. But the bootloader (U-Boot) still hangs at 74MHz.

So how do I switch the Bootloader to use PLL5 Video???

PS: The original clks-Sektion was directly copied from the i.MX6-SabreSD-Devicetree created by NXP!!!

=> Nobody's perfekct!

0 Kudos

1,131 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hello Steffen,

(1)    Open mx6sabresd.c file in u-boot, please! you will find a function named 'static void setup_display(void)', see below:

{

...

    /* set LDB0, LDB1 clk select to 011/011 */
    reg = readl(&mxc_ccm->cs2cdr);
    reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
         | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
    reg |= (3 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
          | (3 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
    writel(reg, &mxc_ccm->cs2cdr);

    reg = readl(&mxc_ccm->cscmr2);
    reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV | MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV;
    writel(reg, &mxc_ccm->cscmr2);

    reg = readl(&mxc_ccm->chsccdr);
    reg |= (CHSCCDR_CLK_SEL_LDB_DI0
        << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
    reg |= (CHSCCDR_CLK_SEL_LDB_DI0
        << MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET);
    writel(reg, &mxc_ccm->chsccdr);

    reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
         | IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_LOW
         | IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
         | IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
         | IOMUXC_GPR2_DATA_WIDTH_CH1_18BIT
         | IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
         | IOMUXC_GPR2_DATA_WIDTH_CH0_18BIT
         | IOMUXC_GPR2_LVDS_CH0_MODE_DISABLED
         | IOMUXC_GPR2_LVDS_CH1_MODE_ENABLED_DI0;
    writel(reg, &iomux->gpr[2]);

    reg = readl(&iomux->gpr[3]);
    reg = (reg & ~(IOMUXC_GPR3_LVDS1_MUX_CTL_MASK
            | IOMUXC_GPR3_HDMI_MUX_CTL_MASK))
        | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
           << IOMUXC_GPR3_LVDS1_MUX_CTL_OFFSET);
    writel(reg, &iomux->gpr[3]);
}

(2) See page 845 in imx6sdlrm.pdf( reference manual), bit[14:12] & bit[11:9] are used to select clock source!

pastedImage_3.png

Please adjust the part of source code in u-boot! Then try to measure clock output!

Hope above information can help you!

Best Regards,

Weidong

0 Kudos

1,131 Views
steffendoster
Contributor IV

I managed to get pll5 working with a pixel-clock of about 53MHz. But I think this is just a workaround. I added:

/* PLL5 enable */
reg = readl(&anatop_reg->pll_video);
reg &= ~((1 << 16) | (1 << 12) | 0x18007F);
reg |= ((1 << 13) | (1 << 18) | 0x08001e);
writel(reg, &anatop_reg->pll_video); 

on top of static void setup_display(void). Is there no better way to let U-Boot do this with the .pixclock-value in display-timings?

Now I have a pixelclock which I can configure with the needed clock. The Value 0x08001e stands for the Divider and the Post-Divider of PLL5 and configures the clock-rate.

But I still got an synchronization issue. My logo is wobbling.

0 Kudos

1,131 Views
steffendoster
Contributor IV

I tried your suggestion, but didn't work. With the first try I even had no LVDS-Clock anymore, because you disable LVDS Channel 0 and that's the display I use.

I use a custom Board, but derived the Board-File from SabreSD.

Here's the Snippet in my configuration I'm currently using:

static void setup_display(void)
{
    struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
    struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
    int reg;

    /* Setup HSYNC, VSYNC, DISP_CLK for debugging purposes */
    imx_iomux_v3_setup_multiple_pads(di0_pads, ARRAY_SIZE(di0_pads));

    enable_ipu_clock();
    imx_setup_hdmi();

    /* Turn on LDB0, LDB1, IPU,IPU DI0 clocks */
    reg = readl(&mxc_ccm->CCGR3);
    reg |=  MXC_CCM_CCGR3_LDB_DI0_MASK | MXC_CCM_CCGR3_LDB_DI1_MASK;
    writel(reg, &mxc_ccm->CCGR3);

    /* set LDB0, LDB1 clk select to 011/011 */
    reg = readl(&mxc_ccm->cs2cdr);
    reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK
        | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);
    reg |= (3 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)
        | (3 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);
    writel(reg, &mxc_ccm->cs2cdr);

    /* LDB clock div by 7 */
    reg = readl(&mxc_ccm->cscmr2);
    reg |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV | MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV;
    writel(reg, &mxc_ccm->cscmr2);

    /* derive ipu1_di0_clk_root clock from ldb_di0_clk */
    reg = readl(&mxc_ccm->chsccdr);
    reg |= (CHSCCDR_CLK_SEL_LDB_DI0 << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET);
    reg |= (CHSCCDR_CLK_SEL_LDB_DI0 << MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET);
    writel(reg, &mxc_ccm->chsccdr);

    reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
        | IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_LOW
        | IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW                           

        | IOMUXC_GPR2_BIT_MAPPING_CH1_JEIDA

        | IOMUXC_GPR2_DATA_WIDTH_CH1_24BIT
        | IOMUXC_GPR2_BIT_MAPPING_CH0_JEIDA
        | IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT
        | IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0

        | IOMUXC_GPR2_LVDS_CH1_MODE_DISABLED;   // Display 1 Disabled because not used
    writel(reg, &iomux->gpr[2]);

    reg = readl(&iomux->gpr[3]);
    reg = (reg & ~(IOMUXC_GPR3_LVDS1_MUX_CTL_MASK | IOMUXC_GPR3_HDMI_MUX_CTL_MASK))
        | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0 << IOMUXC_GPR3_LVDS1_MUX_CTL_OFFSET);
    writel(reg, &iomux->gpr[3]);

    enable_lvds(&displays[0]);
}
#endif /* CONFIG_VIDEO_IPUV3 */

I think the Problem is the Selector for ldb_di0 clock multiplexer in CS2CDR. As you see in my Devicetree-Fix, I had to change the LDB Clock-Source to PLL5. Like this:


    /* set LDB0, LDB1 clk select to 011/011 */

    reg = readl(&mxc_ccm->cs2cdr);

    reg &= ~(MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK

                 | MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK);

    reg |= (0 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)

            | (0 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET);

    writel(reg, &mxc_ccm->cs2cdr);

I think this is the correct setting but I still get about 74MHz instead of 51.2MHz

0 Kudos