[U-Boot] [PATCH] board: ge: bx50v3: Update display setup

Implements the below changes: - Disable LVDS1 on B450v3/B650v3 boards since the final boards no longer have connectors for the same. Only LVDS0 hardware connectors are present. - Implement imx6 EB821 or ERR009219 errata for LVDS clock switch. This patch was ported from Freescale 3.10.17_1.0.0_ga kernel to u-boot. - Split the display setup into 2 different functions. One for B850v3 that does a setup of LVDS and HDMI with clock source for LVDS/IPU_DI set to video PLL. The other for B450v3/B650v3 that does a setup of LVDS only with clock source for LVDS/IPU_DI set to USB PLL. This helps us generate accurate pixel clock required for display connected to LVDS.
Signed-off-by: Akshay Bhat akshay.bhat@timesys.com Cc: Stefano Babic sbabic@denx.de --- board/ge/bx50v3/bx50v3.c | 240 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 198 insertions(+), 42 deletions(-)
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c index 70c298d..cf2cd1a 100644 --- a/board/ge/bx50v3/bx50v3.c +++ b/board/ge/bx50v3/bx50v3.c @@ -390,55 +390,208 @@ struct display_info_t const displays[] = {{ } } }; size_t display_count = ARRAY_SIZE(displays);
-static void setup_display(void) +static void enable_videopll(void) +{ + struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + s32 timeout = 100000; + + setbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN); + + /* set video pll to 910MHz (24MHz * (37+11/12)) + * video pll post div to 910/4 = 227.5MHz + */ + clrsetbits_le32(&ccm->analog_pll_video, + BM_ANADIG_PLL_VIDEO_DIV_SELECT | + BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT, + BF_ANADIG_PLL_VIDEO_DIV_SELECT(37) | + BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0)); + + writel(BF_ANADIG_PLL_VIDEO_NUM_A(11), &ccm->analog_pll_video_num); + writel(BF_ANADIG_PLL_VIDEO_DENOM_B(12), &ccm->analog_pll_video_denom); + + clrbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN); + + while (timeout--) + if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK) + break; + if (timeout < 0) + printf("Warning: video pll lock timeout!\n"); + + clrsetbits_le32(&ccm->analog_pll_video, + BM_ANADIG_PLL_VIDEO_BYPASS, + BM_ANADIG_PLL_VIDEO_ENABLE); +} + +static void set_ldb_clock_source(u8 source) { struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; - struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; int reg; + /* + * Need to follow a strict procedure when changing the LDB + * clock, else we can introduce a glitch. Things to keep in + * mind: + * 1. The current and new parent clocks must be disabled. + * 2. The default clock for ldb_dio_clk is mmdc_ch1 which has + * no CG bit. + * 3. In the RTL implementation of the LDB_DI_CLK_SEL mux + * the top four options are in one mux and the PLL3 option along + * with another option is in the second mux. There is third mux + * used to decide between the first and second mux. + * The code below switches the parent to the bottom mux first + * and then manipulates the top mux. This ensures that no glitch + * will enter the divider. + * + * Need to disable MMDC_CH1 clock manually as there is no CG bit + * for this clock. The only way to disable this clock is to move + * it to pll3_sw_clk and then to disable pll3_sw_clk + * Make sure periph2_clk2_sel is set to pll3_sw_clk + */ + /* Set MMDC_CH1 mask bit */ + reg = readl(&mxc_ccm->ccdr); + reg |= MXC_CCM_CCDR_MMDC_CH1_HS_MASK; + writel(reg, &mxc_ccm->ccdr); + + /* Set periph2_clk2_sel to be sourced from PLL3_sw_clk */ + reg = readl(&mxc_ccm->cbcmr); + reg &= ~MXC_CCM_CBCMR_PERIPH2_CLK2_SEL; + writel(reg, &mxc_ccm->cbcmr); + + /* + * Set the periph2_clk_sel to the top mux so that + * mmdc_ch1 is from pll3_sw_clk. + */ + reg = readl(&mxc_ccm->cbcdr); + reg |= MXC_CCM_CBCDR_PERIPH2_CLK_SEL; + writel(reg, &mxc_ccm->cbcdr); + + /* Wait for the clock switch */ + while (readl(&mxc_ccm->cdhipr)) + ; + /* Disable pll3_sw_clk by selecting bypass clock source */ + reg = readl(&mxc_ccm->ccsr); + reg |= MXC_CCM_CCSR_PLL3_SW_CLK_SEL; + writel(reg, &mxc_ccm->ccsr); + + /* Set the ldb_di0_clk and ldb_di1_clk to 111b */ + reg = readl(&mxc_ccm->cs2cdr); + reg |= ((7 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET) + | (7 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)); + writel(reg, &mxc_ccm->cs2cdr);
- enable_ipu_clock(); - imx_setup_hdmi(); - - reg = readl(&mxc_ccm->CCGR3); - reg |= MXC_CCM_CCGR3_LDB_DI0_MASK; - writel(reg, &mxc_ccm->CCGR3); + /* Set the ldb_di0_clk and ldb_di1_clk to 100b */ + reg = readl(&mxc_ccm->cs2cdr); + reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK + | MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK); + reg |= ((4 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET) + | (4 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)); + writel(reg, &mxc_ccm->cs2cdr);
+ /* Set the ldb_di0_clk and ldb_di1_clk to desired source */ 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); + reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK + | MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK); + reg |= ((source << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET) + | (source << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET)); writel(reg, &mxc_ccm->cs2cdr);
- reg = readl(&mxc_ccm->cscmr2); - reg |= (MXC_CCM_CSCMR2_LDB_DI0_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); - writel(reg, &mxc_ccm->chsccdr); - - reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES - | IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH - | IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW - | IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG - | IOMUXC_GPR2_DATA_WIDTH_CH1_24BIT - | IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG - | IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT - | IOMUXC_GPR2_LVDS_CH1_MODE_ENABLED_DI0 - | IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0; - writel(reg, &iomux->gpr[2]); - - reg = readl(&iomux->gpr[3]); - reg = (reg & ~(IOMUXC_GPR3_LVDS0_MUX_CTL_MASK | - IOMUXC_GPR3_LVDS1_MUX_CTL_MASK | - IOMUXC_GPR3_HDMI_MUX_CTL_MASK)) - | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0 - << IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET) - | (IOMUXC_GPR3_MUX_SRC_IPU1_DI0 - << IOMUXC_GPR3_LVDS1_MUX_CTL_OFFSET); - writel(reg, &iomux->gpr[3]); + /* Unbypass pll3_sw_clk */ + reg = readl(&mxc_ccm->ccsr); + reg &= ~MXC_CCM_CCSR_PLL3_SW_CLK_SEL; + writel(reg, &mxc_ccm->ccsr); + + /* + * Set the periph2_clk_sel back to the bottom mux so that + * mmdc_ch1 is from its original parent. + */ + reg = readl(&mxc_ccm->cbcdr); + reg &= ~MXC_CCM_CBCDR_PERIPH2_CLK_SEL; + writel(reg, &mxc_ccm->cbcdr); + + /* Wait for the clock switch */ + while (readl(&mxc_ccm->cdhipr)) + ; + /* Clear MMDC_CH1 mask bit */ + reg = readl(&mxc_ccm->ccdr); + reg &= ~MXC_CCM_CCDR_MMDC_CH1_HS_MASK; + writel(reg, &mxc_ccm->ccdr); +} + +static void setup_display_b850v3(void) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; + + /* Set LDB clock to Video PLL */ + set_ldb_clock_source(0); + enable_videopll(); + + /* IPU1 D0 clock is 227.5 / 3.5 = 65MHz */ + clrbits_le32(&mxc_ccm->cscmr2, MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + + imx_setup_hdmi(); + + /* Set LDB_DI0 as clock source for IPU_DI0 */ + clrsetbits_le32(&mxc_ccm->chsccdr, + MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK, + (CHSCCDR_CLK_SEL_LDB_DI0 << + MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET)); + + /* Turn on IPU LDB DI0 clocks */ + setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK); + + enable_ipu_clock(); + + writel(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_24BIT | + IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG | + IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT | + IOMUXC_GPR2_SPLIT_MODE_EN_MASK | + IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0 | + IOMUXC_GPR2_LVDS_CH1_MODE_ENABLED_DI0, + &iomux->gpr[2]); + + clrbits_le32(&iomux->gpr[3], + IOMUXC_GPR3_LVDS0_MUX_CTL_MASK | + IOMUXC_GPR3_LVDS1_MUX_CTL_MASK | + IOMUXC_GPR3_HDMI_MUX_CTL_MASK); +} + +static void setup_display_bx50v3(void) +{ + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; + + /* Set LDB clock to USB PLL */ + set_ldb_clock_source(4); + + /* IPU1 DI0 clock is 480/7 = 68.5 MHz */ + setbits_le32(&mxc_ccm->cscmr2, MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + + /* Set LDB_DI0 as clock source for IPU_DI0 */ + clrsetbits_le32(&mxc_ccm->chsccdr, + MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK, + (CHSCCDR_CLK_SEL_LDB_DI0 << + MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET)); + + /* Turn on IPU LDB DI0 clocks */ + setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK); + + enable_ipu_clock(); + + writel(IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES | + IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW | + IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG | + IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT | + IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0, + &iomux->gpr[2]); + + clrsetbits_le32(&iomux->gpr[3], + IOMUXC_GPR3_LVDS0_MUX_CTL_MASK, + (IOMUXC_GPR3_MUX_SRC_IPU1_DI0 << + IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET));
/* backlights off until needed */ imx_iomux_v3_setup_multiple_pads(backlight_pads, @@ -487,7 +640,10 @@ int board_init(void) gpio_direction_output(SUS_S3_OUT, 1); gpio_direction_output(WIFI_EN, 1); #if defined(CONFIG_VIDEO_IPUV3) - setup_display(); + if (IS_ENABLED(CONFIG_TARGET_GE_B850V3)) + setup_display_b850v3(); + else + setup_display_bx50v3(); #endif /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;

Hi Stefano,
On Tue, Mar 15, 2016 at 2:10 PM, Akshay Bhat akshay.bhat@timesys.com wrote:
Implements the below changes:
- Disable LVDS1 on B450v3/B650v3 boards since the final boards no longer
have connectors for the same. Only LVDS0 hardware connectors are present.
- Implement imx6 EB821 or ERR009219 errata for LVDS clock switch.
This patch was ported from Freescale 3.10.17_1.0.0_ga kernel to u-boot.
- Split the display setup into 2 different functions. One for B850v3 that
does a setup of LVDS and HDMI with clock source for LVDS/IPU_DI set to video PLL. The other for B450v3/B650v3 that does a setup of LVDS only with clock source for LVDS/IPU_DI set to USB PLL. This helps us generate accurate pixel clock required for display connected to LVDS.
Signed-off-by: Akshay Bhat akshay.bhat@timesys.com Cc: Stefano Babic sbabic@denx.de
Can this be applied if there are no review comments.
Thanks, Akshay

Hi Akshay,
On 15/03/2016 19:10, Akshay Bhat wrote:
Implements the below changes:
- Disable LVDS1 on B450v3/B650v3 boards since the final boards no longer
have connectors for the same. Only LVDS0 hardware connectors are present.
- Implement imx6 EB821 or ERR009219 errata for LVDS clock switch.
This patch was ported from Freescale 3.10.17_1.0.0_ga kernel to u-boot.
- Split the display setup into 2 different functions. One for B850v3 that
does a setup of LVDS and HDMI with clock source for LVDS/IPU_DI set to video PLL. The other for B450v3/B650v3 that does a setup of LVDS only with clock source for LVDS/IPU_DI set to USB PLL. This helps us generate accurate pixel clock required for display connected to LVDS.
I propose you split your patch exactly as you describe in the commit message into 3 patches.
Generally, a patch/patchset should address a single issue. This lets to better understand the workarounf with MMDC handshake, and let use it on other boards too.
Signed-off-by: Akshay Bhat akshay.bhat@timesys.com Cc: Stefano Babic sbabic@denx.de
board/ge/bx50v3/bx50v3.c | 240 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 198 insertions(+), 42 deletions(-)
diff --git a/board/ge/bx50v3/bx50v3.c b/board/ge/bx50v3/bx50v3.c index 70c298d..cf2cd1a 100644 --- a/board/ge/bx50v3/bx50v3.c +++ b/board/ge/bx50v3/bx50v3.c @@ -390,55 +390,208 @@ struct display_info_t const displays[] = {{ } } }; size_t display_count = ARRAY_SIZE(displays);
-static void setup_display(void) +static void enable_videopll(void) +{
- struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- s32 timeout = 100000;
- setbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN);
- /* set video pll to 910MHz (24MHz * (37+11/12))
* video pll post div to 910/4 = 227.5MHz
*/
- clrsetbits_le32(&ccm->analog_pll_video,
BM_ANADIG_PLL_VIDEO_DIV_SELECT |
BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT,
BF_ANADIG_PLL_VIDEO_DIV_SELECT(37) |
BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0));
- writel(BF_ANADIG_PLL_VIDEO_NUM_A(11), &ccm->analog_pll_video_num);
- writel(BF_ANADIG_PLL_VIDEO_DENOM_B(12), &ccm->analog_pll_video_denom);
- clrbits_le32(&ccm->analog_pll_video, BM_ANADIG_PLL_VIDEO_POWERDOWN);
- while (timeout--)
if (readl(&ccm->analog_pll_video) & BM_ANADIG_PLL_VIDEO_LOCK)
break;
- if (timeout < 0)
printf("Warning: video pll lock timeout!\n");
- clrsetbits_le32(&ccm->analog_pll_video,
BM_ANADIG_PLL_VIDEO_BYPASS,
BM_ANADIG_PLL_VIDEO_ENABLE);
+}
+static void set_ldb_clock_source(u8 source) { struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; int reg;
- /*
* Need to follow a strict procedure when changing the LDB
* clock, else we can introduce a glitch. Things to keep in
* mind:
* 1. The current and new parent clocks must be disabled.
* 2. The default clock for ldb_dio_clk is mmdc_ch1 which has
* no CG bit.
* 3. In the RTL implementation of the LDB_DI_CLK_SEL mux
* the top four options are in one mux and the PLL3 option along
* with another option is in the second mux. There is third mux
* used to decide between the first and second mux.
* The code below switches the parent to the bottom mux first
* and then manipulates the top mux. This ensures that no glitch
* will enter the divider.
*
* Need to disable MMDC_CH1 clock manually as there is no CG bit
* for this clock. The only way to disable this clock is to move
* it to pll3_sw_clk and then to disable pll3_sw_clk
* Make sure periph2_clk2_sel is set to pll3_sw_clk
*/
- /* Set MMDC_CH1 mask bit */
- reg = readl(&mxc_ccm->ccdr);
- reg |= MXC_CCM_CCDR_MMDC_CH1_HS_MASK;
- writel(reg, &mxc_ccm->ccdr);
- /* Set periph2_clk2_sel to be sourced from PLL3_sw_clk */
- reg = readl(&mxc_ccm->cbcmr);
- reg &= ~MXC_CCM_CBCMR_PERIPH2_CLK2_SEL;
- writel(reg, &mxc_ccm->cbcmr);
- /*
* Set the periph2_clk_sel to the top mux so that
* mmdc_ch1 is from pll3_sw_clk.
*/
- reg = readl(&mxc_ccm->cbcdr);
- reg |= MXC_CCM_CBCDR_PERIPH2_CLK_SEL;
- writel(reg, &mxc_ccm->cbcdr);
- /* Wait for the clock switch */
- while (readl(&mxc_ccm->cdhipr))
;
- /* Disable pll3_sw_clk by selecting bypass clock source */
- reg = readl(&mxc_ccm->ccsr);
- reg |= MXC_CCM_CCSR_PLL3_SW_CLK_SEL;
- writel(reg, &mxc_ccm->ccsr);
- /* Set the ldb_di0_clk and ldb_di1_clk to 111b */
- reg = readl(&mxc_ccm->cs2cdr);
- reg |= ((7 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
| (7 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
- writel(reg, &mxc_ccm->cs2cdr);
- enable_ipu_clock();
- imx_setup_hdmi();
- reg = readl(&mxc_ccm->CCGR3);
- reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;
- writel(reg, &mxc_ccm->CCGR3);
/* Set the ldb_di0_clk and ldb_di1_clk to 100b */
reg = readl(&mxc_ccm->cs2cdr);
reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK
| MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK);
reg |= ((4 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
| (4 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
writel(reg, &mxc_ccm->cs2cdr);
/* Set the ldb_di0_clk and ldb_di1_clk to desired source */ 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);
- reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK
| MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK);
- reg |= ((source << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
writel(reg, &mxc_ccm->cs2cdr);| (source << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
- reg = readl(&mxc_ccm->cscmr2);
- reg |= (MXC_CCM_CSCMR2_LDB_DI0_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);
- writel(reg, &mxc_ccm->chsccdr);
- reg = IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES
| IOMUXC_GPR2_DI1_VS_POLARITY_ACTIVE_HIGH
| IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW
| IOMUXC_GPR2_BIT_MAPPING_CH1_SPWG
| IOMUXC_GPR2_DATA_WIDTH_CH1_24BIT
| IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG
| IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT
| IOMUXC_GPR2_LVDS_CH1_MODE_ENABLED_DI0
| IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0;
- writel(reg, &iomux->gpr[2]);
- reg = readl(&iomux->gpr[3]);
- reg = (reg & ~(IOMUXC_GPR3_LVDS0_MUX_CTL_MASK |
IOMUXC_GPR3_LVDS1_MUX_CTL_MASK |
IOMUXC_GPR3_HDMI_MUX_CTL_MASK))
| (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
<< IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET)
| (IOMUXC_GPR3_MUX_SRC_IPU1_DI0
<< IOMUXC_GPR3_LVDS1_MUX_CTL_OFFSET);
- writel(reg, &iomux->gpr[3]);
- /* Unbypass pll3_sw_clk */
- reg = readl(&mxc_ccm->ccsr);
- reg &= ~MXC_CCM_CCSR_PLL3_SW_CLK_SEL;
- writel(reg, &mxc_ccm->ccsr);
- /*
* Set the periph2_clk_sel back to the bottom mux so that
* mmdc_ch1 is from its original parent.
*/
- reg = readl(&mxc_ccm->cbcdr);
- reg &= ~MXC_CCM_CBCDR_PERIPH2_CLK_SEL;
- writel(reg, &mxc_ccm->cbcdr);
- /* Wait for the clock switch */
- while (readl(&mxc_ccm->cdhipr))
;
- /* Clear MMDC_CH1 mask bit */
- reg = readl(&mxc_ccm->ccdr);
- reg &= ~MXC_CCM_CCDR_MMDC_CH1_HS_MASK;
- writel(reg, &mxc_ccm->ccdr);
+}
I frankly ask you if you think that this function can be factorized and moved from board code to common code. What do you think ? Is there something that let the implementation bound to the board (I have not seen it) ?
+static void setup_display_b850v3(void) +{
- struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
- struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
- /* Set LDB clock to Video PLL */
- set_ldb_clock_source(0);
- enable_videopll();
- /* IPU1 D0 clock is 227.5 / 3.5 = 65MHz */
- clrbits_le32(&mxc_ccm->cscmr2, MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV);
- imx_setup_hdmi();
- /* Set LDB_DI0 as clock source for IPU_DI0 */
- clrsetbits_le32(&mxc_ccm->chsccdr,
MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK,
(CHSCCDR_CLK_SEL_LDB_DI0 <<
MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET));
- /* Turn on IPU LDB DI0 clocks */
- setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK);
- enable_ipu_clock();
- writel(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_24BIT |
IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG |
IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT |
IOMUXC_GPR2_SPLIT_MODE_EN_MASK |
IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0 |
IOMUXC_GPR2_LVDS_CH1_MODE_ENABLED_DI0,
&iomux->gpr[2]);
- clrbits_le32(&iomux->gpr[3],
IOMUXC_GPR3_LVDS0_MUX_CTL_MASK |
IOMUXC_GPR3_LVDS1_MUX_CTL_MASK |
IOMUXC_GPR3_HDMI_MUX_CTL_MASK);
+}
+static void setup_display_bx50v3(void) +{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR;
/* Set LDB clock to USB PLL */
set_ldb_clock_source(4);
/* IPU1 DI0 clock is 480/7 = 68.5 MHz */
setbits_le32(&mxc_ccm->cscmr2, MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV);
/* Set LDB_DI0 as clock source for IPU_DI0 */
clrsetbits_le32(&mxc_ccm->chsccdr,
MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK,
(CHSCCDR_CLK_SEL_LDB_DI0 <<
MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET));
/* Turn on IPU LDB DI0 clocks */
setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_LDB_DI0_MASK);
enable_ipu_clock();
writel(IOMUXC_GPR2_BGREF_RRMODE_EXTERNAL_RES |
IOMUXC_GPR2_DI0_VS_POLARITY_ACTIVE_LOW |
IOMUXC_GPR2_BIT_MAPPING_CH0_SPWG |
IOMUXC_GPR2_DATA_WIDTH_CH0_24BIT |
IOMUXC_GPR2_LVDS_CH0_MODE_ENABLED_DI0,
&iomux->gpr[2]);
clrsetbits_le32(&iomux->gpr[3],
IOMUXC_GPR3_LVDS0_MUX_CTL_MASK,
(IOMUXC_GPR3_MUX_SRC_IPU1_DI0 <<
IOMUXC_GPR3_LVDS0_MUX_CTL_OFFSET));
/* backlights off until needed */ imx_iomux_v3_setup_multiple_pads(backlight_pads,
@@ -487,7 +640,10 @@ int board_init(void) gpio_direction_output(SUS_S3_OUT, 1); gpio_direction_output(WIFI_EN, 1); #if defined(CONFIG_VIDEO_IPUV3)
- setup_display();
- if (IS_ENABLED(CONFIG_TARGET_GE_B850V3))
setup_display_b850v3();
- else
setup_display_bx50v3();
#endif /* address of boot parameters */ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
Best regards, Stefano Babic

On Wed, Apr 6, 2016 at 12:18 PM, Stefano Babic sbabic@denx.de wrote:
I frankly ask you if you think that this function can be factorized and moved from board code to common code. What do you think ? Is there something that let the implementation bound to the board (I have not seen it) ?
Agreed. This should be in common code so that other boards can use it.

On Wed, Apr 6, 2016 at 11:22 AM, Fabio Estevam festevam@gmail.com wrote:
On Wed, Apr 6, 2016 at 12:18 PM, Stefano Babic sbabic@denx.de wrote:
I frankly ask you if you think that this function can be factorized and moved from board code to common code. What do you think ? Is there something that let the implementation bound to the board (I have not seen it) ?
Agreed. This should be in common code so that other boards can use it.
Appreciate the feedback. I will break up the commits and resubmit the patch, moving the function to common code.
Fabio, does the errata apply to all i.MX6 based processors? If not, which ones should use the errata?
Thanks, Akshay

On Thu, Apr 7, 2016 at 2:10 AM, Akshay Bhat akshay.bhat@timesys.com wrote:
Appreciate the feedback. I will break up the commits and resubmit the patch, moving the function to common code.
Fabio, does the errata apply to all i.MX6 based processors? If not, which ones should use the errata?
mx6 quad/dl/solo.
participants (3)
-
Akshay Bhat
-
Fabio Estevam
-
Stefano Babic