diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/video/bcm2835.c | 4 | ||||
-rw-r--r-- | drivers/video/display-uclass.c | 15 | ||||
-rw-r--r-- | drivers/video/dw_hdmi.c | 13 | ||||
-rw-r--r-- | drivers/video/fsl_dcu_fb.c | 213 | ||||
-rw-r--r-- | drivers/video/meson/meson_dw_hdmi.c | 10 | ||||
-rw-r--r-- | drivers/video/mxsfb.c | 74 | ||||
-rw-r--r-- | drivers/video/rockchip/rk_hdmi.c | 3 | ||||
-rw-r--r-- | drivers/video/simple_panel.c | 1 | ||||
-rw-r--r-- | drivers/video/sunxi/sunxi_dw_hdmi.c | 3 |
10 files changed, 260 insertions, 78 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c3781b160d..261fa98517 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -484,7 +484,7 @@ config VIDEO_IVYBRIDGE_IGD config VIDEO_FSL_DCU_FB bool "Enable Freescale Display Control Unit" - depends on VIDEO + depends on VIDEO || DM_VIDEO help This enables support for Freescale Display Control Unit (DCU4) module found on Freescale Vybrid and QorIQ family of SoCs. diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index bc41090aed..1d2eda084c 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -19,13 +19,15 @@ static int bcm2835_video_probe(struct udevice *dev) debug("bcm2835: Query resolution...\n"); ret = bcm2835_get_video_size(&w, &h); - if (ret) + if (ret || w == 0 || h == 0) return -EIO; debug("bcm2835: Setting up display for %d x %d\n", w, h); ret = bcm2835_set_video_params(&w, &h, 32, BCM2835_MBOX_PIXEL_ORDER_RGB, BCM2835_MBOX_ALPHA_MODE_IGNORED, &fb_base, &fb_size, &pitch); + if (ret) + return -EIO; debug("bcm2835: Final resolution is %d x %d\n", w, h); diff --git a/drivers/video/display-uclass.c b/drivers/video/display-uclass.c index 99ef5e76f5..1a29ce5d85 100644 --- a/drivers/video/display-uclass.c +++ b/drivers/video/display-uclass.c @@ -37,6 +37,17 @@ int display_enable(struct udevice *dev, int panel_bpp, return 0; } +static bool display_mode_valid(void *priv, const struct display_timing *timing) +{ + struct udevice *dev = priv; + struct dm_display_ops *ops = display_get_ops(dev); + + if (ops && ops->mode_valid) + return ops->mode_valid(dev, timing); + + return true; +} + int display_read_timing(struct udevice *dev, struct display_timing *timing) { struct dm_display_ops *ops = display_get_ops(dev); @@ -53,7 +64,9 @@ int display_read_timing(struct udevice *dev, struct display_timing *timing) if (ret < 0) return ret; - return edid_get_timing(buf, ret, timing, &panel_bits_per_colour); + return edid_get_timing_validate(buf, ret, timing, + &panel_bits_per_colour, + display_mode_valid, dev); } bool display_in_use(struct udevice *dev) diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c index 463436edf3..bf74d6adf2 100644 --- a/drivers/video/dw_hdmi.c +++ b/drivers/video/dw_hdmi.c @@ -8,6 +8,7 @@ #include <common.h> #include <fdtdec.h> #include <asm/io.h> +#include <i2c.h> #include <media_bus_format.h> #include "dw_hdmi.h" @@ -812,6 +813,18 @@ static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff) u32 trytime = 5; u32 n; + if (CONFIG_IS_ENABLED(DM_I2C) && hdmi->ddc_bus) { + struct udevice *chip; + + edid_read_err = i2c_get_chip(hdmi->ddc_bus, + HDMI_I2CM_SLAVE_DDC_ADDR, + 1, &chip); + if (edid_read_err) + return edid_read_err; + + return dm_i2c_read(chip, shift, buff, HDMI_EDID_BLOCK_SIZE); + } + /* set ddc i2c clk which devided from ddc_clk to 100khz */ hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR); hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR); diff --git a/drivers/video/fsl_dcu_fb.c b/drivers/video/fsl_dcu_fb.c index 9f6e7f83b0..add64b85b5 100644 --- a/drivers/video/fsl_dcu_fb.c +++ b/drivers/video/fsl_dcu_fb.c @@ -1,16 +1,19 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2019 Toradex AG * * FSL DCU Framebuffer driver */ #include <asm/io.h> #include <common.h> +#include <dm.h> #include <fdt_support.h> #include <fsl_dcu_fb.h> #include <linux/fb.h> #include <malloc.h> +#include <video.h> #include <video_fb.h> #include "videomodes.h" @@ -218,8 +221,6 @@ struct dcu_reg { u32 ctrldescl[DCU_LAYER_MAX_NUM][16]; }; -static struct fb_info info; - static void reset_total_layers(void) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; @@ -240,20 +241,22 @@ static void reset_total_layers(void) } } -static int layer_ctrldesc_init(int index, u32 pixel_format) +static int layer_ctrldesc_init(struct fb_info fbinfo, + int index, u32 pixel_format) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int bpp = BPP_24_RGB888; dcu_write32(®s->ctrldescl[index][0], - DCU_CTRLDESCLN_1_HEIGHT(info.var.yres) | - DCU_CTRLDESCLN_1_WIDTH(info.var.xres)); + DCU_CTRLDESCLN_1_HEIGHT(fbinfo.var.yres) | + DCU_CTRLDESCLN_1_WIDTH(fbinfo.var.xres)); dcu_write32(®s->ctrldescl[index][1], DCU_CTRLDESCLN_2_POSY(0) | DCU_CTRLDESCLN_2_POSX(0)); - dcu_write32(®s->ctrldescl[index][2], (unsigned int)info.screen_base); + dcu_write32(®s->ctrldescl[index][2], + (unsigned int)fbinfo.screen_base); switch (pixel_format) { case 16: @@ -294,42 +297,46 @@ static int layer_ctrldesc_init(int index, u32 pixel_format) return 0; } -int fsl_dcu_init(unsigned int xres, unsigned int yres, - unsigned int pixel_format) +int fsl_dcu_init(struct fb_info *fbinfo, unsigned int xres, + unsigned int yres, unsigned int pixel_format) { struct dcu_reg *regs = (struct dcu_reg *)CONFIG_SYS_DCU_ADDR; unsigned int div, mode; +/* + * When DM_VIDEO is enabled reservation of framebuffer is done + * in advance during bind() call. + */ +#if !CONFIG_IS_ENABLED(DM_VIDEO) + fbinfo->screen_size = fbinfo->var.xres * fbinfo->var.yres * + (fbinfo->var.bits_per_pixel / 8); - info.screen_size = - info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8); - - if (info.screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) { - info.screen_size = 0; + if (fbinfo->screen_size > CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB) { + fbinfo->screen_size = 0; return -ENOMEM; } - /* Reserve framebuffer at the end of memory */ gd->fb_base = gd->bd->bi_dram[0].start + - gd->bd->bi_dram[0].size - info.screen_size; - info.screen_base = (char *)gd->fb_base; + gd->bd->bi_dram[0].size - fbinfo->screen_size; + fbinfo->screen_base = (char *)gd->fb_base; - memset(info.screen_base, 0, info.screen_size); + memset(fbinfo->screen_base, 0, fbinfo->screen_size); +#endif reset_total_layers(); dcu_write32(®s->disp_size, - DCU_DISP_SIZE_DELTA_Y(info.var.yres) | - DCU_DISP_SIZE_DELTA_X(info.var.xres / 16)); + DCU_DISP_SIZE_DELTA_Y(fbinfo->var.yres) | + DCU_DISP_SIZE_DELTA_X(fbinfo->var.xres / 16)); dcu_write32(®s->hsyn_para, - DCU_HSYN_PARA_BP(info.var.left_margin) | - DCU_HSYN_PARA_PW(info.var.hsync_len) | - DCU_HSYN_PARA_FP(info.var.right_margin)); + DCU_HSYN_PARA_BP(fbinfo->var.left_margin) | + DCU_HSYN_PARA_PW(fbinfo->var.hsync_len) | + DCU_HSYN_PARA_FP(fbinfo->var.right_margin)); dcu_write32(®s->vsyn_para, - DCU_VSYN_PARA_BP(info.var.upper_margin) | - DCU_VSYN_PARA_PW(info.var.vsync_len) | - DCU_VSYN_PARA_FP(info.var.lower_margin)); + DCU_VSYN_PARA_BP(fbinfo->var.upper_margin) | + DCU_VSYN_PARA_PW(fbinfo->var.vsync_len) | + DCU_VSYN_PARA_FP(fbinfo->var.lower_margin)); dcu_write32(®s->synpol, DCU_SYN_POL_INV_PXCK_FALL | @@ -352,9 +359,9 @@ int fsl_dcu_init(unsigned int xres, unsigned int yres, mode = dcu_read32(®s->mode); dcu_write32(®s->mode, mode | DCU_MODE_NORMAL); - layer_ctrldesc_init(0, pixel_format); + layer_ctrldesc_init(*fbinfo, 0, pixel_format); - div = dcu_set_pixel_clock(info.var.pixclock); + div = dcu_set_pixel_clock(fbinfo->var.pixclock); dcu_write32(®s->div_ratio, (div - 1)); dcu_write32(®s->update_mode, DCU_UPDATE_MODE_READREG); @@ -367,24 +374,26 @@ ulong board_get_usable_ram_top(ulong total_size) return gd->ram_top - CONFIG_VIDEO_FSL_DCU_MAX_FB_SIZE_MB; } -void *video_hw_init(void) +int fsl_probe_common(struct fb_info *fbinfo, unsigned int *win_x, + unsigned int *win_y) { - static GraphicDevice ctfb; const char *options; unsigned int depth = 0, freq = 0; + struct fb_videomode *fsl_dcu_mode_db = &fsl_dcu_mode_480_272; - if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq, + if (!video_get_video_mode(win_x, win_y, &depth, &freq, &options)) - return NULL; + return -EINVAL; /* Find the monitor port, which is a required option */ if (!options) - return NULL; + return -EINVAL; + if (strncmp(options, "monitor=", 8) != 0) - return NULL; + return -EINVAL; - switch (RESOLUTION(ctfb.winSizeX, ctfb.winSizeY)) { + switch (RESOLUTION(*win_x, *win_y)) { case RESOLUTION(480, 272): fsl_dcu_mode_db = &fsl_dcu_mode_480_272; break; @@ -402,39 +411,31 @@ void *video_hw_init(void) break; default: printf("unsupported resolution %ux%u\n", - ctfb.winSizeX, ctfb.winSizeY); + *win_x, *win_y); } - info.var.xres = fsl_dcu_mode_db->xres; - info.var.yres = fsl_dcu_mode_db->yres; - info.var.bits_per_pixel = 32; - info.var.pixclock = fsl_dcu_mode_db->pixclock; - info.var.left_margin = fsl_dcu_mode_db->left_margin; - info.var.right_margin = fsl_dcu_mode_db->right_margin; - info.var.upper_margin = fsl_dcu_mode_db->upper_margin; - info.var.lower_margin = fsl_dcu_mode_db->lower_margin; - info.var.hsync_len = fsl_dcu_mode_db->hsync_len; - info.var.vsync_len = fsl_dcu_mode_db->vsync_len; - info.var.sync = fsl_dcu_mode_db->sync; - info.var.vmode = fsl_dcu_mode_db->vmode; - info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8; - - if (platform_dcu_init(ctfb.winSizeX, ctfb.winSizeY, - options + 8, fsl_dcu_mode_db) < 0) - return NULL; - - ctfb.frameAdrs = (unsigned int)info.screen_base; - ctfb.plnSizeX = ctfb.winSizeX; - ctfb.plnSizeY = ctfb.winSizeY; - - ctfb.gdfBytesPP = 4; - ctfb.gdfIndex = GDF_32BIT_X888RGB; - - ctfb.memSize = info.screen_size; - - return &ctfb; + fbinfo->var.xres = fsl_dcu_mode_db->xres; + fbinfo->var.yres = fsl_dcu_mode_db->yres; + fbinfo->var.bits_per_pixel = 32; + fbinfo->var.pixclock = fsl_dcu_mode_db->pixclock; + fbinfo->var.left_margin = fsl_dcu_mode_db->left_margin; + fbinfo->var.right_margin = fsl_dcu_mode_db->right_margin; + fbinfo->var.upper_margin = fsl_dcu_mode_db->upper_margin; + fbinfo->var.lower_margin = fsl_dcu_mode_db->lower_margin; + fbinfo->var.hsync_len = fsl_dcu_mode_db->hsync_len; + fbinfo->var.vsync_len = fsl_dcu_mode_db->vsync_len; + fbinfo->var.sync = fsl_dcu_mode_db->sync; + fbinfo->var.vmode = fsl_dcu_mode_db->vmode; + fbinfo->fix.line_length = fbinfo->var.xres * + fbinfo->var.bits_per_pixel / 8; + + return platform_dcu_init(fbinfo, *win_x, *win_y, + options + 8, fsl_dcu_mode_db); } +#ifndef CONFIG_DM_VIDEO +static struct fb_info info; + #if defined(CONFIG_OF_BOARD_SETUP) int fsl_dcu_fixedfb_setup(void *blob) { @@ -457,3 +458,89 @@ int fsl_dcu_fixedfb_setup(void *blob) return 0; } #endif + +void *video_hw_init(void) +{ + static GraphicDevice ctfb; + + if (fsl_probe_common(&info, &ctfb.winSizeX, &ctfb.winSizeY) < 0) + return NULL; + + ctfb.frameAdrs = (unsigned int)info.screen_base; + ctfb.plnSizeX = ctfb.winSizeX; + ctfb.plnSizeY = ctfb.winSizeY; + + ctfb.gdfBytesPP = 4; + ctfb.gdfIndex = GDF_32BIT_X888RGB; + + ctfb.memSize = info.screen_size; + + return &ctfb; +} + +#else /* ifndef CONFIG_DM_VIDEO */ + +static int fsl_dcu_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 fb_info fbinfo = { 0 }; + unsigned int win_x; + unsigned int win_y; + u32 fb_start, fb_end; + int ret = 0; + + fb_start = plat->base & ~(MMU_SECTION_SIZE - 1); + fb_end = plat->base + plat->size; + fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT); + + fbinfo.screen_base = (char *)fb_start; + fbinfo.screen_size = plat->size; + + ret = fsl_probe_common(&fbinfo, &win_x, &win_y); + if (ret < 0) + return ret; + + uc_priv->bpix = VIDEO_BPP32; + uc_priv->xsize = win_x; + uc_priv->ysize = win_y; + + /* Enable dcache for the frame buffer */ + mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start, + DCACHE_WRITEBACK); + video_set_flush_dcache(dev, true); + return ret; +} + +static int fsl_dcu_video_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + unsigned int win_x; + unsigned int win_y; + unsigned int depth = 0, freq = 0; + const char *options; + int ret = 0; + + ret = video_get_video_mode(&win_x, &win_y, &depth, &freq, &options); + if (ret < 0) + return ret; + + plat->size = win_x * win_y * 32; + + return 0; +} + +static const struct udevice_id fsl_dcu_video_ids[] = { + { .compatible = "fsl,vf610-dcu" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(fsl_dcu_video) = { + .name = "fsl_dcu_video", + .id = UCLASS_VIDEO, + .of_match = fsl_dcu_video_ids, + .bind = fsl_dcu_video_bind, + .probe = fsl_dcu_video_probe, + .flags = DM_FLAG_PRE_RELOC, +}; +#endif /* ifndef CONFIG_DM_VIDEO */ diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c index 483c93f6b6..9831d978fc 100644 --- a/drivers/video/meson/meson_dw_hdmi.c +++ b/drivers/video/meson/meson_dw_hdmi.c @@ -375,6 +375,9 @@ static int meson_dw_hdmi_probe(struct udevice *dev) } #endif + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &priv->hdmi.ddc_bus); + ret = reset_get_bulk(dev, &resets); if (ret) return ret; @@ -426,9 +429,16 @@ static int meson_dw_hdmi_probe(struct udevice *dev) return ret; } +static bool meson_dw_hdmi_mode_valid(struct udevice *dev, + const struct display_timing *timing) +{ + return meson_venc_hdmi_supported_mode(timing); +} + static const struct dm_display_ops meson_dw_hdmi_ops = { .read_edid = meson_dw_hdmi_read_edid, .enable = meson_dw_hdmi_enable, + .mode_valid = meson_dw_hdmi_mode_valid, }; static const struct udevice_id meson_dw_hdmi_ids[] = { diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index f02ba20138..6c9a7c05e8 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -271,6 +271,42 @@ dealloc_fb: } #else /* ifndef CONFIG_DM_VIDEO */ +static int mxs_of_get_timings(struct udevice *dev, + struct display_timing *timings, + u32 *bpp) +{ + int ret = 0; + u32 display_phandle; + ofnode display_node; + + ret = ofnode_read_u32(dev_ofnode(dev), "display", &display_phandle); + if (ret) { + dev_err(dev, "required display property isn't provided\n"); + return -EINVAL; + } + + display_node = ofnode_get_by_phandle(display_phandle); + if (!ofnode_valid(display_node)) { + dev_err(dev, "failed to find display subnode\n"); + return -EINVAL; + } + + ret = ofnode_read_u32(display_node, "bits-per-pixel", bpp); + if (ret) { + dev_err(dev, + "required bits-per-pixel property isn't provided\n"); + return -EINVAL; + } + + ret = ofnode_decode_display_timing(display_node, 0, timings); + if (ret) { + dev_err(dev, "failed to get any display timings\n"); + return -EINVAL; + } + + return ret; +} + static int mxs_video_probe(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); @@ -278,18 +314,16 @@ static int mxs_video_probe(struct udevice *dev) struct ctfb_res_modes mode; struct display_timing timings; - int bpp = -1; + u32 bpp = 0; 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; - } + ret = mxs_of_get_timings(dev, &timings, &bpp); + if (ret) + return ret; mode.xres = timings.hactive.typ; mode.yres = timings.vactive.typ; @@ -301,13 +335,12 @@ static int mxs_video_probe(struct udevice *dev) 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 32: case 24: case 18: uc_priv->bpix = VIDEO_BPP32; @@ -341,15 +374,32 @@ static int mxs_video_bind(struct udevice *dev) { struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); struct display_timing timings; + u32 bpp = 0; + u32 bytes_pp = 0; int ret; - ret = ofnode_decode_display_timing(dev_ofnode(dev), 0, &timings); - if (ret) { - dev_err(dev, "failed to get any display timings\n"); + ret = mxs_of_get_timings(dev, &timings, &bpp); + if (ret) + return ret; + + switch (bpp) { + case 32: + case 24: + case 18: + bytes_pp = 4; + break; + case 16: + bytes_pp = 2; + break; + case 8: + bytes_pp = 1; + break; + default: + dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp); return -EINVAL; } - plat->size = timings.hactive.typ * timings.vactive.typ * BYTES_PP; + plat->size = timings.hactive.typ * timings.vactive.typ * bytes_pp; return 0; } diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index 51931ceefa..5b44a7e8c9 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -93,6 +93,9 @@ int rk_hdmi_ofdata_to_platdata(struct udevice *dev) priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &hdmi->ddc_bus); + return 0; } diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index 7a968e740c..c3c0e84732 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -105,6 +105,7 @@ static const struct udevice_id simple_panel_ids[] = { { .compatible = "auo,b133xtn01" }, { .compatible = "auo,b116xw03" }, { .compatible = "auo,b133htn01" }, + { .compatible = "lg,lb070wv8" }, { } }; diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c index 6fe1aa7ee4..cec23295b5 100644 --- a/drivers/video/sunxi/sunxi_dw_hdmi.c +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c @@ -373,6 +373,9 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev) priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg; priv->mux = uc_plat->source_id; + uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus", + &priv->hdmi.ddc_bus); + dw_hdmi_init(&priv->hdmi); return 0; |