--- 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; }; -- 1.7.9.5 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel