Hi All,
This series patches extend Pawel's patches to Versatile Express HDLCD DVI output support. Before apply this patches, please apply Pawel's patches first. This series patches implements base on Linaro release 13.06 branch "ll_20130621.0".
here is Pawel's patches [1] http://lists.freedesktop.org/archives/dri-devel/2013-April/037519.html
Show Liu (2): Fixed for compatible with kernel 3.10.0-rc6 CDFv2 for VExpress HDLCD DVI output support
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 6 +- drivers/video/Kconfig | 2 + drivers/video/arm-hdlcd.c | 116 +++++++++++++++++++++++++--- drivers/video/fbmon.c | 12 ++- drivers/video/vexpress-dvimode.c | 11 +++ drivers/video/vexpress-muxfpga.c | 8 +- include/linux/arm-hdlcd.h | 6 ++ 7 files changed, 142 insertions(+), 19 deletions(-)
--- drivers/video/Kconfig | 2 ++ drivers/video/fbmon.c | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2e14e0b..b0a0947 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -324,6 +324,7 @@ config FB_ARMCLCD select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT select FB_MODE_HELPERS if OF + select VIDEOMODE_HELPERS help This framebuffer device driver is for the ARM PrimeCell PL110 Colour LCD controller. ARM PrimeCells provide the building @@ -340,6 +341,7 @@ config FB_ARMHDLCD select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select VIDEOMODE_HELPERS help This framebuffer device driver is for the ARM High Definition Colour LCD controller. diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 304cf37..aaa5be7 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -1440,17 +1440,15 @@ void videomode_from_fb_var_screeninfo(const struct fb_var_screeninfo *var, vm->vback_porch = var->upper_margin; vm->vsync_len = var->vsync_len;
- vm->dmt_flags = 0; + vm->flags = 0; if (var->sync & FB_SYNC_HOR_HIGH_ACT) - vm->dmt_flags |= VESA_DMT_HSYNC_HIGH; + vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; if (var->sync & FB_SYNC_VERT_HIGH_ACT) - vm->dmt_flags |= VESA_DMT_VSYNC_HIGH; - - vm->data_flags = 0; + vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; if (var->vmode & FB_VMODE_INTERLACED) - vm->data_flags |= DISPLAY_FLAGS_INTERLACED; + vm->flags |= DISPLAY_FLAGS_INTERLACED; if (var->vmode & FB_VMODE_DOUBLE) - vm->data_flags |= DISPLAY_FLAGS_DOUBLESCAN; + vm->flags |= DISPLAY_FLAGS_DOUBLESCAN; } EXPORT_SYMBOL_GPL(videomode_from_fb_var_screeninfo);
--- arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 6 +- drivers/video/arm-hdlcd.c | 116 +++++++++++++++++++++++++--- drivers/video/vexpress-dvimode.c | 11 +++ drivers/video/vexpress-muxfpga.c | 8 +- include/linux/arm-hdlcd.h | 6 ++ 5 files changed, 135 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts index f1dc620..aeef32d 100644 --- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts @@ -145,10 +145,14 @@ compatible = "arm,hdlcd"; reg = <0 0x2b000000 0 0x1000>; interrupts = <0 85 4>; - mode = "1024x768-16@60"; framebuffer = <0 0xff000000 0 0x01000000>; clocks = <&oscclk5>; clock-names = "pxlclk"; + label = "V2P-CA15_A7 HDLCD"; + display = <&v2m_muxfpga 0xf>; + max-hactive = <1280>; + max-vactive = <1024>; + max-bpp = <16>; };
memory-controller@2b0a0000 { diff --git a/drivers/video/arm-hdlcd.c b/drivers/video/arm-hdlcd.c index cfd631e..528239f 100644 --- a/drivers/video/arm-hdlcd.c +++ b/drivers/video/arm-hdlcd.c @@ -31,7 +31,8 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #endif - +#include <video/display.h> +#include <video/videomode.h> #include "edid.h"
#ifdef CONFIG_SERIAL_AMBA_PCU_UART @@ -41,6 +42,8 @@ int get_edid(u8 *msgbuf);
#define to_hdlcd_device(info) container_of(info, struct hdlcd_device, fb)
+#define MAX_FB_MODE_NAME 128 + static struct of_device_id hdlcd_of_matches[] = { { .compatible = "arm,hdlcd" }, {}, @@ -129,12 +132,20 @@ static inline void hdlcd_enable(struct hdlcd_device *hdlcd) { dev_dbg(hdlcd->dev, "HDLCD: output enabled\n"); writel(1, hdlcd->base + HDLCD_REG_COMMAND); + + if (hdlcd->display) + display_entity_set_state( hdlcd->display, + DISPLAY_ENTITY_STATE_ON); }
static inline void hdlcd_disable(struct hdlcd_device *hdlcd) { dev_dbg(hdlcd->dev, "HDLCD: output disabled\n"); writel(0, hdlcd->base + HDLCD_REG_COMMAND); + + if (hdlcd->display) + display_entity_set_state(hdlcd->display, + DISPLAY_ENTITY_STATE_OFF); }
static int hdlcd_set_bitfields(struct hdlcd_device *hdlcd, @@ -267,6 +278,13 @@ static int hdlcd_set_par(struct fb_info *info)
hdlcd_disable(hdlcd);
+ if(hdlcd->display) { + struct videomode mode; + + videomode_from_fb_var_screeninfo(&hdlcd->fb.var, &mode); + display_entity_update(hdlcd->display, &mode); + } + WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_LENGTH, hdlcd->fb.var.xres * bytes_per_pixel); WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_PITCH, hdlcd->fb.var.xres * bytes_per_pixel); WRITE_HDLCD_REG(HDLCD_REG_FB_LINE_COUNT, hdlcd->fb.var.yres - 1); @@ -520,8 +538,8 @@ static int hdlcd_setup(struct hdlcd_device *hdlcd)
hdlcd->fb.var.nonstd = 0; hdlcd->fb.var.activate = FB_ACTIVATE_NOW; - hdlcd->fb.var.height = -1; - hdlcd->fb.var.width = -1; + hdlcd->fb.var.height = hdlcd->height; + hdlcd->fb.var.width = hdlcd->width; hdlcd->fb.var.accel_flags = 0;
init_completion(&hdlcd->vsync_completion); @@ -542,7 +560,7 @@ static int hdlcd_setup(struct hdlcd_device *hdlcd) hdlcd->fb.monspecs.vfmin = 0; hdlcd->fb.monspecs.vfmax = 400; hdlcd->fb.monspecs.dclkmin = 1000000; - hdlcd->fb.monspecs.dclkmax = 100000000; + hdlcd->fb.monspecs.dclkmax = 140000000; fb_find_mode(&hdlcd->fb.var, &hdlcd->fb, fb_mode, NULL, 0, &hdlcd_default_mode, 32); }
@@ -633,6 +651,75 @@ static int parse_edid_data(struct hdlcd_device *hdlcd, const u8 *edid_data, int return 0; }
+#ifdef CONFIG_OF +static int hdlcd_of_init_display(struct hdlcd_device *hdlcd, struct device_node *of_node) +{ + int err, i; + int modes_num, best_mode = -1; + char *mode_name; + const struct videomode *modes; + + u32 max_bpp = 32; + u32 max_hactive = (u32)~0UL; + u32 max_vactive = (u32)~0UL; + unsigned int width, height; + + /* get the display entity */ + hdlcd->display = of_display_entity_get(of_node, 0); + if (hdlcd->display == NULL) { + dev_err( hdlcd->dev, "HDLCD: cannot get display entity\n"); + return -EPROBE_DEFER; + } + + /* get videomodes from display entity */ + modes_num = display_entity_get_modes(hdlcd->display, &modes); + if (modes_num < 0) { + dev_err( hdlcd->dev, "HDLCD: cannot get videomode from display entity\n"); + return modes_num; + } + + /* Pick the "best" (the widest, then the highest) mode from the list */ + of_property_read_u32(of_node, "max-hactive", &max_hactive); + of_property_read_u32(of_node, "max-vactive", &max_vactive); + + for (i = 0; i < modes_num; i++) { + if (modes[i].hactive > max_hactive || + modes[i].vactive > max_vactive) + continue; + if (best_mode < 0 ||(modes[i].hactive >= modes[best_mode].hactive && + modes[i].vactive > modes[best_mode].vactive)) + best_mode = i; + } + + if (best_mode < 0) + return -ENODEV; + + err = fb_videomode_from_videomode(&modes[best_mode], &hdlcd->mode); + if (err) + return err; + + of_property_read_u32(of_node, "max-bpp", &max_bpp); + + + i = snprintf(NULL, 0, "%ux%u-%u@%u", hdlcd->mode.xres, + hdlcd->mode.yres, max_bpp, hdlcd->mode.refresh); + + mode_name = devm_kzalloc( hdlcd->dev, i + 1, GFP_KERNEL); + snprintf( mode_name, i + 1, "%ux%u-%u@%u", hdlcd->mode.xres, + hdlcd->mode.yres, max_bpp, hdlcd->mode.refresh); + + hdlcd->mode.name = mode_name; + + if(display_entity_get_size(hdlcd->display, &width, &height) != 0) + width = height = 0; + + hdlcd->width = width; + hdlcd->height = height; + + return 0; +} +#endif + static int hdlcd_probe(struct platform_device *pdev) { int err = 0, i; @@ -652,13 +739,22 @@ static int hdlcd_probe(struct platform_device *pdev)
#ifdef CONFIG_OF of_node = pdev->dev.of_node; - if (of_node) { - int len; + hdlcd->dev = &pdev->dev; + + /*initial display entity*/ + err = hdlcd_of_init_display( hdlcd, of_node); + if(err < 0) + return err; + + if (of_node) { + int len = strnlen(hdlcd->mode.name, MAX_FB_MODE_NAME); const u8 *edid; - const __be32 *prop = of_get_property(of_node, "mode", &len); - if (prop) + + const __be32 *prop = (__be32 *)hdlcd->mode.name; + if (prop) strncpy(fb_mode, (char *)prop, len); - prop = of_get_property(of_node, "framebuffer", &len); + + prop = of_get_property( of_node, "framebuffer", &len); if (prop) { hdlcd->fb.fix.smem_start = of_read_ulong(prop, of_n_addr_cells(of_node)); @@ -669,7 +765,7 @@ static int hdlcd_probe(struct platform_device *pdev) framebuffer_size = HDLCD_MAX_FRAMEBUFFER_SIZE; dev_dbg(&pdev->dev, "HDLCD: phys_addr = 0x%lx, size = 0x%lx\n", hdlcd->fb.fix.smem_start, framebuffer_size); - } + } edid = of_get_property(of_node, "edid", &len); if (edid) { err = parse_edid_data(hdlcd, edid, len); diff --git a/drivers/video/vexpress-dvimode.c b/drivers/video/vexpress-dvimode.c index 85d5608..4b38765 100644 --- a/drivers/video/vexpress-dvimode.c +++ b/drivers/video/vexpress-dvimode.c @@ -115,10 +115,21 @@ static int vexpress_dvimode_display_get_params(struct display_entity *display, return 0; }
+int vexpress_dvimode_display_get_size(struct display_entity *entity, + unsigned int *width, unsigned int *height) +{ + + *width = -1; + *height = -1; + + return 0; +} + static const struct display_entity_control_ops vexpress_dvimode_display_ops = { .update = vexpress_dvimode_display_update, .get_modes = vexpress_dvimode_display_get_modes, .get_params = vexpress_dvimode_display_get_params, + .get_size = vexpress_dvimode_display_get_size, };
static struct display_entity vexpress_dvimode_display = { diff --git a/drivers/video/vexpress-muxfpga.c b/drivers/video/vexpress-muxfpga.c index 1731ad0..c54e54d 100644 --- a/drivers/video/vexpress-muxfpga.c +++ b/drivers/video/vexpress-muxfpga.c @@ -121,17 +121,23 @@ static int vexpress_muxfpga_display_get_params(struct display_entity *display, return display_entity_get_params(vexpress_muxfpga_output, params); }
+int vexpress_muxfpga_display_get_size(struct display_entity *entity, + unsigned int *width, unsigned int *height) +{ + return display_entity_get_size(vexpress_muxfpga_output, width, height); +} + static const struct display_entity_control_ops vexpress_muxfpga_display_ops = { .update = vexpress_muxfpga_display_update, .get_modes = vexpress_muxfpga_display_get_modes, .get_params = vexpress_muxfpga_display_get_params, + .get_size = vexpress_muxfpga_display_get_size, };
static ssize_t vexpress_muxfpga_show_source(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", vexpress_muxfpga_source_site); }
diff --git a/include/linux/arm-hdlcd.h b/include/linux/arm-hdlcd.h index 939f3a8..79b6285 100644 --- a/include/linux/arm-hdlcd.h +++ b/include/linux/arm-hdlcd.h @@ -12,6 +12,7 @@
#include <linux/fb.h> #include <linux/completion.h> +#include <video/display.h>
/* register offsets */ #define HDLCD_REG_VERSION 0x0000 /* ro */ @@ -119,4 +120,9 @@ struct hdlcd_device { int irq; struct completion vsync_completion; unsigned char *edid; + + unsigned int width; + unsigned int height; + struct display_entity *display; + struct fb_videomode mode; };
On Wed, 2013-07-17 at 11:08 +0100, Show Liu wrote:
This series patches extend Pawel's patches to Versatile Express HDLCD DVI output support. Before apply this patches, please apply Pawel's patches first. This series patches implements base on Linaro release 13.06 branch "ll_20130621.0".
here is Pawel's patches [1] http://lists.freedesktop.org/archives/dri-devel/2013-April/037519.html
Glad to see someone thinking the same way ;-) Thanks for trying it and particularly for the fixes in vexpress-* code. I'll keep them in mind when the time comes :-)
Of course neither the CDF patch nor the HDLCD driver are upstream yet. Laurent promised to post next (hopefully final ;-) version of his patches soon, but the API has apparently changed so we'll have to adapt to it. As to the HDLCD driver - there is some work going on converting it to DRM/KMS and upstreaming as such, using CDF if it's available by that time as well.
Paweł
On Wednesday 17 July 2013 11:49:49 Pawel Moll wrote:
On Wed, 2013-07-17 at 11:08 +0100, Show Liu wrote:
This series patches extend Pawel's patches to Versatile Express HDLCD DVI output support. Before apply this patches, please apply Pawel's patches first. This series patches implements base on Linaro release 13.06 branch "ll_20130621.0".
here is Pawel's patches [1] http://lists.freedesktop.org/archives/dri-devel/2013-April/037519.html
Glad to see someone thinking the same way ;-) Thanks for trying it and particularly for the fixes in vexpress-* code. I'll keep them in mind when the time comes :-)
Of course neither the CDF patch nor the HDLCD driver are upstream yet. Laurent promised to post next (hopefully final ;-)
I don't think it will be the final version, but there should be no major change to the API after that. I still expect a couple of versions before the code reaches a mergeable stable, but it shouldn't take too long this time. Further enhancements then will likely go in as follow-up patchs.
version of his patches soon,
Hopefully by the end of the week (which ends on Sunday, not Friday ;-)), give or take a couple of days.
but the API has apparently changed so we'll have to adapt to it. As to the HDLCD driver - there is some work going on converting it to DRM/KMS and upstreaming as such, using CDF if it's available by that time as well.
linaro-kernel@lists.linaro.org