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:
Snippetldb: 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
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!
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!
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
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.
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