Skip to content
Snippets Groups Projects
Commit d8aaf171 authored by Dmitry Petrov's avatar Dmitry Petrov Committed by Mikhail Vanyulin
Browse files

video: mxsfb: port changes from SECO NE U-Boot


Signed-off-by: default avatarMikhail Vanyulin <mikhail.vanyulin@rtsoft.de>
parent c0ad522a
No related branches found
No related tags found
No related merge requests found
...@@ -44,6 +44,10 @@ ...@@ -44,6 +44,10 @@
#include <gis.h> #include <gis.h>
#endif #endif
#ifdef CONFIG_IMX_MIPI_DSI_BRIDGE
#include <imx_mipi_dsi_bridge.h>
#endif
#define PS2KHZ(ps) (1000000000UL / (ps)) #define PS2KHZ(ps) (1000000000UL / (ps))
#define HZ2PS(hz) (1000000000UL / ((hz) / 1000)) #define HZ2PS(hz) (1000000000UL / ((hz) / 1000))
...@@ -76,17 +80,16 @@ __weak void mxsfb_system_setup(void) ...@@ -76,17 +80,16 @@ __weak void mxsfb_system_setup(void)
*/ */
static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr, static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr,
struct display_timing *timings, int bpp, bool bridge) struct ctfb_res_modes *mode, int bpp,
bool bridge, bool enable_pol)
{ {
struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)(reg_base); struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)(reg_base);
const enum display_flags flags = timings->flags;
uint32_t word_len = 0, bus_width = 0; uint32_t word_len = 0, bus_width = 0;
uint8_t valid_data = 0; uint8_t valid_data = 0;
uint32_t vdctrl0;
#if !(CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8)) #if !(CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8))
/* Kick in the LCDIF clock */ /* Kick in the LCDIF clock */
mxs_set_lcdclk((u32)reg_base, timings->pixelclock.typ / 1000); mxs_set_lcdclk((u32)reg_base, PS2KHZ(mode->pixclock));
#endif #endif
/* Restart the LCDIF block */ /* Restart the LCDIF block */
...@@ -127,37 +130,30 @@ static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr, ...@@ -127,37 +130,30 @@ static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr,
mxsfb_system_setup(); mxsfb_system_setup();
writel((timings->vactive.typ << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) | writel((mode->yres << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) | mode->xres,
timings->hactive.typ, &regs->hw_lcdif_transfer_count); &regs->hw_lcdif_transfer_count);
vdctrl0 = LCDIF_VDCTRL0_ENABLE_PRESENT | if (!enable_pol)
LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT | writel(LCDIF_VDCTRL0_ENABLE_PRESENT |
LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
timings->vsync_len.typ; LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
mode->vsync_len, &regs->hw_lcdif_vdctrl0);
if(flags & DISPLAY_FLAGS_HSYNC_HIGH) else
vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL; writel(LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
if(flags & DISPLAY_FLAGS_VSYNC_HIGH) LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
vdctrl0 |= LCDIF_VDCTRL0_VSYNC_POL; LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
if(flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) mode->vsync_len, &regs->hw_lcdif_vdctrl0);
vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL;
if(flags & DISPLAY_FLAGS_DE_HIGH) writel(mode->upper_margin + mode->lower_margin + mode->vsync_len + mode->yres,
vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL; &regs->hw_lcdif_vdctrl1);
writel((mode->hsync_len << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET) |
writel(vdctrl0, &regs->hw_lcdif_vdctrl0); (mode->left_margin + mode->right_margin + mode->hsync_len + mode->xres),
writel(timings->vback_porch.typ + timings->vfront_porch.typ + &regs->hw_lcdif_vdctrl2);
timings->vsync_len.typ + timings->vactive.typ, writel(((mode->left_margin + mode->hsync_len) << LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_OFFSET) |
&regs->hw_lcdif_vdctrl1); (mode->upper_margin + mode->vsync_len),
writel((timings->hsync_len.typ << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET) | &regs->hw_lcdif_vdctrl3);
(timings->hback_porch.typ + timings->hfront_porch.typ + writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET) | mode->xres,
timings->hsync_len.typ + timings->hactive.typ), &regs->hw_lcdif_vdctrl4);
&regs->hw_lcdif_vdctrl2);
writel(((timings->hback_porch.typ + timings->hsync_len.typ) <<
LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_OFFSET) |
(timings->vback_porch.typ + timings->vsync_len.typ),
&regs->hw_lcdif_vdctrl3);
writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET) | timings->hactive.typ,
&regs->hw_lcdif_vdctrl4);
writel(fb_addr, &regs->hw_lcdif_cur_buf); writel(fb_addr, &regs->hw_lcdif_cur_buf);
writel(fb_addr, &regs->hw_lcdif_next_buf); writel(fb_addr, &regs->hw_lcdif_next_buf);
...@@ -177,11 +173,11 @@ static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr, ...@@ -177,11 +173,11 @@ static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr,
writel(LCDIF_CTRL_RUN, &regs->hw_lcdif_ctrl_set); writel(LCDIF_CTRL_RUN, &regs->hw_lcdif_ctrl_set);
} }
static int mxs_probe_common(phys_addr_t reg_base, struct display_timing *timings, static int mxs_probe_common(phys_addr_t reg_base, struct ctfb_res_modes *mode, int bpp, u32 fb,
int bpp, u32 fb, bool bridge) bool bridge, bool enable_pol)
{ {
/* Start framebuffer */ /* Start framebuffer */
mxs_lcd_init(reg_base, fb, timings, bpp, bridge); mxs_lcd_init(reg_base, fb, mode, bpp, bridge, enable_pol);
#ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM #ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM
/* /*
...@@ -231,8 +227,12 @@ static int mxs_remove_common(phys_addr_t reg_base, u32 fb) ...@@ -231,8 +227,12 @@ static int mxs_remove_common(phys_addr_t reg_base, u32 fb)
break; break;
udelay(1); udelay(1);
} }
#if !defined(CONFIG_IMX_PERSIST_INIT)
mxs_reset_block((struct mxs_register_32 *)&regs->hw_lcdif_ctrl_reg); mxs_reset_block((struct mxs_register_32 *)&regs->hw_lcdif_ctrl_reg);
#else
/* Stop! */
writel(LCDIF_CTRL_RUN, &regs->hw_lcdif_ctrl_clr);
#endif
return 0; return 0;
} }
...@@ -272,11 +272,9 @@ void lcdif_power_down(void) ...@@ -272,11 +272,9 @@ void lcdif_power_down(void)
void *video_hw_init(void) void *video_hw_init(void)
{ {
int bpp = -1; int bpp = -1;
int ret = 0;
char *penv; char *penv;
void *fb = NULL; void *fb = NULL;
struct ctfb_res_modes mode; struct ctfb_res_modes mode;
struct display_timing timings;
puts("Video: "); puts("Video: ");
...@@ -306,9 +304,6 @@ void *video_hw_init(void) ...@@ -306,9 +304,6 @@ void *video_hw_init(void)
bpp = depth; bpp = depth;
} }
mode.pixclock_khz = PS2KHZ(mode.pixclock);
mode.pixclock = mode.pixclock_khz * 1000;
if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) { if (CONFIG_IS_ENABLED(IMX_MODULE_FUSE)) {
if (check_module_fused(MODULE_LCDIF)) { if (check_module_fused(MODULE_LCDIF)) {
printf("LCDIF@0x%x is fused, disable it\n", MXS_LCDIF_BASE); printf("LCDIF@0x%x is fused, disable it\n", MXS_LCDIF_BASE);
...@@ -344,6 +339,7 @@ void *video_hw_init(void) ...@@ -344,6 +339,7 @@ void *video_hw_init(void)
panel.memSize = mode.xres * mode.yres * panel.gdfBytesPP; panel.memSize = mode.xres * mode.yres * panel.gdfBytesPP;
#ifndef CONFIG_FB_ADDR
/* Allocate framebuffer */ /* Allocate framebuffer */
fb = memalign(ARCH_DMA_MINALIGN, fb = memalign(ARCH_DMA_MINALIGN,
roundup(panel.memSize, ARCH_DMA_MINALIGN)); roundup(panel.memSize, ARCH_DMA_MINALIGN));
...@@ -351,20 +347,43 @@ void *video_hw_init(void) ...@@ -351,20 +347,43 @@ void *video_hw_init(void)
printf("MXSFB: Error allocating framebuffer!\n"); printf("MXSFB: Error allocating framebuffer!\n");
return NULL; return NULL;
} }
#else
fb = (void *)CONFIG_FB_ADDR;
#endif
/* Wipe framebuffer */ /* Wipe framebuffer */
memset(fb, 0, panel.memSize); memset(fb, 0, panel.memSize);
panel.frameAdrs = (u32)fb; panel.frameAdrs = (ulong)fb;
printf("%s\n", panel.modeIdent); printf("%s\n", panel.modeIdent);
video_ctfb_mode_to_display_timing(&mode, &timings); #ifdef CONFIG_IMX_MIPI_DSI_BRIDGE
timings.flags |= DISPLAY_FLAGS_DE_HIGH; /* Force enable pol */ int dsi_ret;
imx_mipi_dsi_bridge_mode_set(&fbmode);
dsi_ret = imx_mipi_dsi_bridge_enable();
if (dsi_ret) {
printf("Enable DSI bridge failed, err %d\n", dsi_ret);
return NULL;
}
ret = mxs_probe_common(panel.isaBase, &timings, bpp, (u32)fb, false); bool bridge = true;
if (ret) #else
goto dealloc_fb; bool bridge = false;
#endif
#ifdef CONFIG_IMX_SEC_MIPI_DSI
bool enable_pol = false;
#else
bool enable_pol = true;
#endif
if (mxs_probe_common(panel.isaBase, &mode, bpp, (ulong)fb, bridge, enable_pol)) {
#ifndef CONFIG_FB_ADDR
free(fb);
#endif
return NULL;
}
#ifdef CONFIG_VIDEO_GIS #ifdef CONFIG_VIDEO_GIS
/* Entry for GIS */ /* Entry for GIS */
...@@ -372,11 +391,6 @@ void *video_hw_init(void) ...@@ -372,11 +391,6 @@ void *video_hw_init(void)
#endif #endif
return (void *)&panel; return (void *)&panel;
dealloc_fb:
free(fb);
return NULL;
} }
#else /* ifndef CONFIG_DM_VIDEO */ #else /* ifndef CONFIG_DM_VIDEO */
...@@ -508,11 +522,12 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -508,11 +522,12 @@ static int mxs_video_probe(struct udevice *dev)
struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev);
struct mxsfb_priv *priv = dev_get_priv(dev); struct mxsfb_priv *priv = dev_get_priv(dev);
struct ctfb_res_modes mode;
struct display_timing timings; struct display_timing timings;
u32 bpp = 0; u32 bpp = 0;
u32 fb_start, fb_end; u32 fb_start, fb_end;
int ret; int ret;
bool enable_bridge = false; bool enable_pol = true, enable_bridge = false;
debug("%s() plat: base 0x%lx, size 0x%x\n", debug("%s() plat: base 0x%lx, size 0x%x\n",
__func__, plat->base, plat->size); __func__, plat->base, plat->size);
...@@ -526,7 +541,6 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -526,7 +541,6 @@ static int mxs_video_probe(struct udevice *dev)
ret = mxs_of_get_timings(dev, &timings, &bpp); ret = mxs_of_get_timings(dev, &timings, &bpp);
if (ret) if (ret)
return ret; return ret;
timings.flags |= DISPLAY_FLAGS_DE_HIGH;
#if CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8) #if CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8)
ret = clk_get_by_name(dev, "pix", &priv->lcdif_pix); ret = clk_get_by_name(dev, "pix", &priv->lcdif_pix);
...@@ -595,8 +609,8 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -595,8 +609,8 @@ static int mxs_video_probe(struct udevice *dev)
enable_bridge = true; enable_bridge = true;
/* sec dsim needs enable ploarity at low, default we set to high */ /* sec dsim needs enable ploarity at low, default we set to high */
if (!strcmp(priv->disp_dev->driver->name, "imx_sec_dsim")) if (dev_read_bool(dev, "enable_polarity_low"))
timings.flags &= ~DISPLAY_FLAGS_DE_HIGH; enable_pol = false;
} }
#endif #endif
...@@ -611,6 +625,16 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -611,6 +625,16 @@ static int mxs_video_probe(struct udevice *dev)
} }
} }
mode.xres = timings.hactive.typ;
mode.yres = timings.vactive.typ;
mode.left_margin = timings.hback_porch.typ;
mode.right_margin = timings.hfront_porch.typ;
mode.upper_margin = timings.vback_porch.typ;
mode.lower_margin = timings.vfront_porch.typ;
mode.hsync_len = timings.hsync_len.typ;
mode.vsync_len = timings.vsync_len.typ;
mode.pixclock = HZ2PS(timings.pixelclock.typ);
#if CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8) #if CONFIG_IS_ENABLED(CLK) && IS_ENABLED(CONFIG_IMX8)
ret = clk_set_rate(&priv->lcdif_pix, timings.pixelclock.typ); ret = clk_set_rate(&priv->lcdif_pix, timings.pixelclock.typ);
if (ret < 0) { if (ret < 0) {
...@@ -625,7 +649,7 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -625,7 +649,7 @@ static int mxs_video_probe(struct udevice *dev)
} }
#endif #endif
ret = mxs_probe_common(priv->reg_base, &timings, bpp, plat->base, enable_bridge); ret = mxs_probe_common(priv->reg_base, &mode, bpp, plat->base, enable_bridge, enable_pol);
if (ret) if (ret)
return ret; return ret;
...@@ -646,8 +670,8 @@ static int mxs_video_probe(struct udevice *dev) ...@@ -646,8 +670,8 @@ static int mxs_video_probe(struct udevice *dev)
return -EINVAL; return -EINVAL;
} }
uc_priv->xsize = timings.hactive.typ; uc_priv->xsize = mode.xres;
uc_priv->ysize = timings.vactive.typ; uc_priv->ysize = mode.yres;
/* Enable dcache for the frame buffer */ /* Enable dcache for the frame buffer */
fb_start = plat->base; fb_start = plat->base;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment