提交 8b856f04 编写于 作者: A Anatolij Gustschin 提交者: Grant Likely

powerpc/fsl-diu-fb: Support setting display mode using EDID

Adds support for encoding display mode information
in the device tree using verbatim EDID block.

If the EDID entry in the DIU node is present, the
driver will build mode database using EDID data
and allow setting the display modes from this database.
Otherwise display mode will be set using mode
entries from driver's internal database as usual.

This patch also updates device tree bindings.
Signed-off-by: NAnatolij Gustschin <agust@denx.de>
Acked-by: NTimur Tabi <timur@freescale.com>
Signed-off-by: NGrant Likely <grant.likely@secretlab.ca>
上级 a027b333
...@@ -11,6 +11,11 @@ Required properties: ...@@ -11,6 +11,11 @@ Required properties:
- interrupt-parent : the phandle for the interrupt controller that - interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device. services interrupts for this device.
Optional properties:
- edid : verbatim EDID data block describing attached display.
Data from the detailed timing descriptor will be used to
program the display controller.
Example (MPC8610HPCD): Example (MPC8610HPCD):
display@2c000 { display@2c000 {
compatible = "fsl,diu"; compatible = "fsl,diu";
...@@ -25,4 +30,5 @@ Example for MPC5121: ...@@ -25,4 +30,5 @@ Example for MPC5121:
reg = <0x2100 0x100>; reg = <0x2100 0x100>;
interrupts = <64 0x8>; interrupts = <64 0x8>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
edid = [edid-data];
}; };
...@@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG ...@@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG
config FB_FSL_DIU config FB_FSL_DIU
tristate "Freescale DIU framebuffer support" tristate "Freescale DIU framebuffer support"
depends on FB && FSL_SOC depends on FB && FSL_SOC
select FB_MODE_HELPERS
select FB_CFB_FILLRECT select FB_CFB_FILLRECT
select FB_CFB_COPYAREA select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT select FB_CFB_IMAGEBLIT
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include <linux/fsl-diu-fb.h> #include <linux/fsl-diu-fb.h>
#include "edid.h"
/* /*
* These parameters give default parameters * These parameters give default parameters
...@@ -217,6 +218,7 @@ struct mfb_info { ...@@ -217,6 +218,7 @@ struct mfb_info {
int x_aoi_d; /* aoi display x offset to physical screen */ int x_aoi_d; /* aoi display x offset to physical screen */
int y_aoi_d; /* aoi display y offset to physical screen */ int y_aoi_d; /* aoi display y offset to physical screen */
struct fsl_diu_data *parent; struct fsl_diu_data *parent;
u8 *edid_data;
}; };
...@@ -1185,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info) ...@@ -1185,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info)
int rc; int rc;
struct mfb_info *mfbi = info->par; struct mfb_info *mfbi = info->par;
const char *aoi_mode, *init_aoi_mode = "320x240"; const char *aoi_mode, *init_aoi_mode = "320x240";
struct fb_videomode *db = fsl_diu_mode_db;
unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
int has_default_mode = 1;
if (init_fbinfo(info)) if (init_fbinfo(info))
return -EINVAL; return -EINVAL;
if (mfbi->index == 0) /* plane 0 */ if (mfbi->index == 0) { /* plane 0 */
if (mfbi->edid_data) {
/* Now build modedb from EDID */
fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
fb_videomode_to_modelist(info->monspecs.modedb,
info->monspecs.modedb_len,
&info->modelist);
db = info->monspecs.modedb;
dbsize = info->monspecs.modedb_len;
}
aoi_mode = fb_mode; aoi_mode = fb_mode;
else } else {
aoi_mode = init_aoi_mode; aoi_mode = init_aoi_mode;
}
pr_debug("mode used = %s\n", aoi_mode); pr_debug("mode used = %s\n", aoi_mode);
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); &fsl_diu_default_mode, default_bpp);
switch (rc) { switch (rc) {
case 1: case 1:
pr_debug("using mode specified in @mode\n"); pr_debug("using mode specified in @mode\n");
...@@ -1214,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info) ...@@ -1214,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info)
default: default:
pr_debug("rc = %d\n", rc); pr_debug("rc = %d\n", rc);
pr_debug("failed to find mode\n"); pr_debug("failed to find mode\n");
return -EINVAL; /*
* For plane 0 we continue and look into
* driver's internal modedb.
*/
if (mfbi->index == 0 && mfbi->edid_data)
has_default_mode = 0;
else
return -EINVAL;
break; break;
} }
if (!has_default_mode) {
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
ARRAY_SIZE(fsl_diu_mode_db),
&fsl_diu_default_mode,
default_bpp);
if (rc > 0 && rc < 5)
has_default_mode = 1;
}
/* Still not found, use preferred mode from database if any */
if (!has_default_mode && info->monspecs.modedb) {
struct fb_monspecs *specs = &info->monspecs;
struct fb_videomode *modedb = &specs->modedb[0];
/*
* Get preferred timing. If not found,
* first mode in database will be used.
*/
if (specs->misc & FB_MISC_1ST_DETAIL) {
int i;
for (i = 0; i < specs->modedb_len; i++) {
if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
modedb = &specs->modedb[i];
break;
}
}
}
info->var.bits_per_pixel = default_bpp;
fb_videomode_to_var(&info->var, modedb);
}
pr_debug("xres_virtual %d\n", info->var.xres_virtual); pr_debug("xres_virtual %d\n", info->var.xres_virtual);
pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
...@@ -1256,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info) ...@@ -1256,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info)
if (!mfbi->registered) if (!mfbi->registered)
return; return;
if (mfbi->index == 0)
kfree(mfbi->edid_data);
unregister_framebuffer(info); unregister_framebuffer(info);
unmap_video_memory(info); unmap_video_memory(info);
if (&info->cmap) if (&info->cmap)
...@@ -1456,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev, ...@@ -1456,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
mfbi = machine_data->fsl_diu_info[i]->par; mfbi = machine_data->fsl_diu_info[i]->par;
memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
mfbi->parent = machine_data; mfbi->parent = machine_data;
if (mfbi->index == 0) {
const u8 *prop;
int len;
/* Get EDID */
prop = of_get_property(np, "edid", &len);
if (prop && len == EDID_LENGTH)
mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
GFP_KERNEL);
}
} }
ret = of_address_to_resource(np, 0, &res); ret = of_address_to_resource(np, 0, &res);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册