diff options
author | Igor Opaniuk <igor.opaniuk@toradex.com> | 2019-06-04 00:05:59 +0300 |
---|---|---|
committer | Anatolij Gustschin <agust@denx.de> | 2019-06-05 00:25:54 +0300 |
commit | 8c1df09f070f1796730ce4eca104897093fea191 (patch) | |
tree | 5eccea0c4751e59ace11ceaf414641701baedf3f /drivers/video | |
parent | 9a6720522812b5d9bfda8964196407a3abbf6bb4 (diff) | |
download | u-boot-8c1df09f070f1796730ce4eca104897093fea191.tar.xz |
video: mxsfb: add DM_VIDEO support
Extend the driver to build with DM_VIDEO enabled. DTS files
must additionally include 'u-boot,dm-pre-reloc' property in
soc and child nodes to enable driver binding to mxsfb device.
Signed-off-by: Igor Opaniuk <igor.opaniuk@toradex.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/mxsfb.c | 145 |
1 files changed, 136 insertions, 9 deletions
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index 6e269409d6..f02ba20138 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -5,8 +5,10 @@ * Copyright (C) 2011-2013 Marek Vasut <marex@denx.de> */ #include <common.h> +#include <dm.h> #include <linux/errno.h> #include <malloc.h> +#include <video.h> #include <video_fb.h> #include <asm/arch/clock.h> @@ -18,8 +20,11 @@ #include "videomodes.h" #define PS2KHZ(ps) (1000000000UL / (ps)) +#define HZ2PS(hz) (1000000000UL / ((hz) / 1000)) + +#define BITS_PP 18 +#define BYTES_PP 4 -static GraphicDevice panel; struct mxs_dma_desc desc; /** @@ -128,10 +133,10 @@ static void mxs_lcd_init(u32 fb_addr, struct ctfb_res_modes *mode, int bpp) writel(LCDIF_CTRL_RUN, ®s->hw_lcdif_ctrl_set); } -static int mxs_probe_common(struct ctfb_res_modes *mode, int bpp, void *fb) +static int mxs_probe_common(struct ctfb_res_modes *mode, int bpp, u32 fb) { /* Start framebuffer */ - mxs_lcd_init((u32)fb, mode, bpp); + mxs_lcd_init(fb, mode, bpp); #ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM /* @@ -159,16 +164,16 @@ static int mxs_probe_common(struct ctfb_res_modes *mode, int bpp, void *fb) return 0; } -void lcdif_power_down(void) +static int mxs_remove_common(u32 fb) { struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; int timeout = 1000000; - if (!panel.frameAdrs) - return; + if (!fb) + return -EINVAL; - writel(panel.frameAdrs, ®s->hw_lcdif_cur_buf_reg); - writel(panel.frameAdrs, ®s->hw_lcdif_next_buf_reg); + writel(fb, ®s->hw_lcdif_cur_buf_reg); + writel(fb, ®s->hw_lcdif_next_buf_reg); writel(LCDIF_CTRL1_VSYNC_EDGE_IRQ, ®s->hw_lcdif_ctrl1_clr); while (--timeout) { if (readl(®s->hw_lcdif_ctrl1_reg) & @@ -177,6 +182,17 @@ void lcdif_power_down(void) udelay(1); } mxs_reset_block((struct mxs_register_32 *)®s->hw_lcdif_ctrl_reg); + + return 0; +} + +#ifndef CONFIG_DM_VIDEO + +static GraphicDevice panel; + +void lcdif_power_down(void) +{ + mxs_remove_common(panel.frameAdrs); } void *video_hw_init(void) @@ -242,7 +258,7 @@ void *video_hw_init(void) printf("%s\n", panel.modeIdent); - ret = mxs_probe_common(&mode, bpp, fb); + ret = mxs_probe_common(&mode, bpp, (u32)fb); if (ret) goto dealloc_fb; @@ -253,3 +269,114 @@ dealloc_fb: return NULL; } +#else /* ifndef CONFIG_DM_VIDEO */ + +static int mxs_video_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + + struct ctfb_res_modes mode; + struct display_timing timings; + int bpp = -1; + u32 fb_start, fb_end; + int ret; + + debug("%s() plat: base 0x%lx, size 0x%x\n", + __func__, plat->base, plat->size); + + ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings); + if (ret) { + dev_err(dev, "failed to get any display timings\n"); + return -EINVAL; + } + + 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); + + bpp = BITS_PP; + + ret = mxs_probe_common(&mode, bpp, plat->base); + if (ret) + return ret; + + switch (bpp) { + case 24: + case 18: + uc_priv->bpix = VIDEO_BPP32; + break; + case 16: + uc_priv->bpix = VIDEO_BPP16; + break; + case 8: + uc_priv->bpix = VIDEO_BPP8; + break; + default: + dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp); + return -EINVAL; + } + + uc_priv->xsize = mode.xres; + uc_priv->ysize = mode.yres; + + /* Enable dcache for the frame buffer */ + fb_start = plat->base & ~(MMU_SECTION_SIZE - 1); + fb_end = plat->base + plat->size; + fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT); + mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start, + DCACHE_WRITEBACK); + video_set_flush_dcache(dev, true); + + return ret; +} + +static int mxs_video_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct display_timing timings; + int ret; + + ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings); + if (ret) { + dev_err(dev, "failed to get any display timings\n"); + return -EINVAL; + } + + plat->size = timings.hactive.typ * timings.vactive.typ * BYTES_PP; + + return 0; +} + +static int mxs_video_remove(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + mxs_remove_common(plat->base); + + return 0; +} + +static const struct udevice_id mxs_video_ids[] = { + { .compatible = "fsl,imx23-lcdif" }, + { .compatible = "fsl,imx28-lcdif" }, + { .compatible = "fsl,imx7ulp-lcdif" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mxs_video) = { + .name = "mxs_video", + .id = UCLASS_VIDEO, + .of_match = mxs_video_ids, + .bind = mxs_video_bind, + .probe = mxs_video_probe, + .remove = mxs_video_remove, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif /* ifndef CONFIG_DM_VIDEO */ |