void video_hw_init(void *lcdbase) { int ret; unsigned int div = 0, best = 0, pix_clk; u32 frac1; const unsigned long lcd_clk = 480000000; u32 lcd_ctrl = LCD_CTRL_DEFAULT | LCDIF_CTRL_RUN; u32 lcd_ctrl1 = LCD_CTRL1_DEFAULT, lcd_ctrl2 = LCD_CTRL2_DEFAULT; u32 lcd_vdctrl0 = LCD_VDCTRL0_DEFAULT; u32 lcd_vdctrl1 = LCD_VDCTRL1_DEFAULT; u32 lcd_vdctrl2 = LCD_VDCTRL2_DEFAULT; u32 lcd_vdctrl3 = LCD_VDCTRL3_DEFAULT; u32 lcd_vdctrl4 = LCD_VDCTRL4_DEFAULT; struct mxs_clkctrl_regs *clk_regs = (void *)MXS_CLKCTRL_BASE; char buf1[16], buf2[16]; /* pixel format in memory */ switch (color_depth) { case 8: lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_8BIT; lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(1); break; case 16: lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_16BIT; lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(3); break; case 18: lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_18BIT; lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7); break; case 24: lcd_ctrl |= LCDIF_CTRL_WORD_LENGTH_24BIT; lcd_ctrl1 |= LCDIF_CTRL1_BYTE_PACKING_FORMAT(7); break; default: printf("Invalid bpp: %d\n", color_depth); return; } /* pixel format on the LCD data pins */ switch (pix_fmt) { case PIX_FMT_RGB332: lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_8BIT; break; case PIX_FMT_RGB565: lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_16BIT; break; case PIX_FMT_BGR666: lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET; /* fallthru */ case PIX_FMT_RGB666: lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_18BIT; break; case PIX_FMT_BGR24: lcd_ctrl |= 1 << LCDIF_CTRL_INPUT_DATA_SWIZZLE_OFFSET; /* fallthru */ case PIX_FMT_RGB24: lcd_ctrl |= LCDIF_CTRL_LCD_DATABUS_WIDTH_24BIT; break; default: printf("Invalid pixel format: %c%c%c%c\n", fourcc_str(pix_fmt)); return; } pix_clk = PICOS2KHZ(mxsfb_var.pixclock); debug("designated pix_clk: %sMHz\n", strmhz(buf1, pix_clk * 1000)); for (frac1 = 18; frac1 < 36; frac1++) { static unsigned int err = ~0; unsigned long clk = lcd_clk / 1000 * 18 / frac1; unsigned int d = (clk + pix_clk - 1) / pix_clk; unsigned int diff = abs(clk / d - pix_clk); debug("frac1=%u div=%u lcd_clk=%-8sMHz pix_clk=%-8sMHz diff=%u err=%u\n", frac1, d, strmhz(buf1, clk * 1000), strmhz(buf2, clk * 1000 / d), diff, err); if (clk < pix_clk) break; if (d > 255) continue; if (diff < err) { best = frac1; div = d; err = diff; if (err == 0) break; } } if (div == 0) { printf("Requested pixel clock %sMHz out of range\n", strmhz(buf1, pix_clk * 1000)); return; } debug("div=%lu(%u*%u/18) for pixel clock %sMHz with base clock %sMHz\n", lcd_clk / pix_clk / 1000, best, div, strmhz(buf1, lcd_clk / div * 18 / best), strmhz(buf2, lcd_clk)); frac1 = (readl(&clk_regs->hw_clkctrl_frac1_reg) & ~0xff) | best; writel(frac1, &clk_regs->hw_clkctrl_frac1_reg); writel(1 << 14, &clk_regs->hw_clkctrl_clkseq_clr); /* enable LCD clk and fractional divider */ writel(div, &clk_regs->hw_clkctrl_lcdif_reg); while (readl(&clk_regs->hw_clkctrl_lcdif_reg) & (1 << 29)) ; ret = mxs_reset_block(&lcd_regs->hw_lcdif_ctrl_reg); if (ret) { printf("Failed to reset LCD controller: LCDIF_CTRL: %08x CLKCTRL_LCDIF: %08x\n", readl(&lcd_regs->hw_lcdif_ctrl_reg), readl(&clk_regs->hw_clkctrl_lcdif_reg)); return; } if (mxsfb_var.sync & FB_SYNC_HOR_HIGH_ACT) lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL; if (mxsfb_var.sync & FB_SYNC_VERT_HIGH_ACT) lcd_vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL; if (mxsfb_var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT) lcd_vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL; if (mxsfb_var.sync & FB_SYNC_DOTCLK_FALLING_ACT) lcd_vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL; lcd_vdctrl0 |= LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH(mxsfb_var.vsync_len); lcd_vdctrl1 |= LCDIF_VDCTRL1_VSYNC_PERIOD(mxsfb_var.vsync_len + mxsfb_var.upper_margin + mxsfb_var.lower_margin + mxsfb_var.yres); lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH(mxsfb_var.hsync_len); lcd_vdctrl2 |= LCDIF_VDCTRL2_HSYNC_PERIOD(mxsfb_var.hsync_len + mxsfb_var.left_margin + mxsfb_var.right_margin + mxsfb_var.xres); lcd_vdctrl3 |= LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT(mxsfb_var.left_margin + mxsfb_var.hsync_len); lcd_vdctrl3 |= LCDIF_VDCTRL3_VERTICAL_WAIT_CNT(mxsfb_var.upper_margin + mxsfb_var.vsync_len); lcd_vdctrl4 |= LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT(mxsfb_var.xres); writel((u32)lcdbase, &lcd_regs->hw_lcdif_next_buf_reg); writel(LCDIF_TRANSFER_COUNT_H_COUNT(mxsfb_var.xres) | LCDIF_TRANSFER_COUNT_V_COUNT(mxsfb_var.yres), &lcd_regs->hw_lcdif_transfer_count_reg); writel(lcd_vdctrl0, &lcd_regs->hw_lcdif_vdctrl0_reg); writel(lcd_vdctrl1, &lcd_regs->hw_lcdif_vdctrl1_reg); writel(lcd_vdctrl2, &lcd_regs->hw_lcdif_vdctrl2_reg); writel(lcd_vdctrl3, &lcd_regs->hw_lcdif_vdctrl3_reg); writel(lcd_vdctrl4, &lcd_regs->hw_lcdif_vdctrl4_reg); writel(lcd_ctrl1, &lcd_regs->hw_lcdif_ctrl1_reg); writel(lcd_ctrl2, &lcd_regs->hw_lcdif_ctrl2_reg); writel(lcd_ctrl, &lcd_regs->hw_lcdif_ctrl_reg); debug("mxsfb framebuffer driver initialized\n"); }
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to eLCDIF apb_clk for each instance. */ static const clock_ip_name_t s_elcdifApbClocks[] = LCDIF_CLOCKS; #if defined(LCDIF_PERIPH_CLOCKS) /*! @brief Pointers to eLCDIF pix_clk for each instance. */ static const clock_ip_name_t s_elcdifPixClocks[] = LCDIF_PERIPH_CLOCKS; #endif #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief The control register value to select different pixel format. */ elcdif_pixel_format_reg_t s_pixelFormatReg[] = { /* kELCDIF_PixelFormatRAW8 */ {/* Register CTRL. */ LCDIF_CTRL_WORD_LENGTH(1U), /* Register CTRL1. */ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)}, /* kELCDIF_PixelFormatRGB565 */ {/* Register CTRL. */ LCDIF_CTRL_WORD_LENGTH(0U), /* Register CTRL1. */ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)}, /* kELCDIF_PixelFormatRGB666 */ {/* Register CTRL. */ LCDIF_CTRL_WORD_LENGTH(3U) | LCDIF_CTRL_DATA_FORMAT_24_BIT(1U), /* Register CTRL1. */ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)}, /* kELCDIF_PixelFormatXRGB8888 */ {/* Register CTRL. 24-bit. */ LCDIF_CTRL_WORD_LENGTH(3U), /* Register CTRL1. */ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},