---
 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

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to