aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fsl-diu-fb.c
diff options
context:
space:
mode:
authorAnatolij Gustschin <agust@denx.de>2010-07-23 00:00:39 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-08-01 19:06:44 -0400
commit8b856f040c09024aa9d1f363c1a5cf2d3db73ebd (patch)
treef837d2cd8b2c133932e9741a04fc82020c4c58d5 /drivers/video/fsl-diu-fb.c
parenta027b33348df3512d7680eed29bada1247f01ad7 (diff)
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: Anatolij Gustschin <agust@denx.de> Acked-by: Timur Tabi <timur@freescale.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/video/fsl-diu-fb.c')
-rw-r--r--drivers/video/fsl-diu-fb.c80
1 files changed, 74 insertions, 6 deletions
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index db3e360e6aad..e38ad2224540 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -35,6 +35,7 @@
35 35
36#include <sysdev/fsl_soc.h> 36#include <sysdev/fsl_soc.h>
37#include <linux/fsl-diu-fb.h> 37#include <linux/fsl-diu-fb.h>
38#include "edid.h"
38 39
39/* 40/*
40 * These parameters give default parameters 41 * These parameters give default parameters
@@ -217,6 +218,7 @@ struct mfb_info {
217 int x_aoi_d; /* aoi display x offset to physical screen */ 218 int x_aoi_d; /* aoi display x offset to physical screen */
218 int y_aoi_d; /* aoi display y offset to physical screen */ 219 int y_aoi_d; /* aoi display y offset to physical screen */
219 struct fsl_diu_data *parent; 220 struct fsl_diu_data *parent;
221 u8 *edid_data;
220}; 222};
221 223
222 224
@@ -1185,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info)
1185 int rc; 1187 int rc;
1186 struct mfb_info *mfbi = info->par; 1188 struct mfb_info *mfbi = info->par;
1187 const char *aoi_mode, *init_aoi_mode = "320x240"; 1189 const char *aoi_mode, *init_aoi_mode = "320x240";
1190 struct fb_videomode *db = fsl_diu_mode_db;
1191 unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
1192 int has_default_mode = 1;
1188 1193
1189 if (init_fbinfo(info)) 1194 if (init_fbinfo(info))
1190 return -EINVAL; 1195 return -EINVAL;
1191 1196
1192 if (mfbi->index == 0) /* plane 0 */ 1197 if (mfbi->index == 0) { /* plane 0 */
1198 if (mfbi->edid_data) {
1199 /* Now build modedb from EDID */
1200 fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
1201 fb_videomode_to_modelist(info->monspecs.modedb,
1202 info->monspecs.modedb_len,
1203 &info->modelist);
1204 db = info->monspecs.modedb;
1205 dbsize = info->monspecs.modedb_len;
1206 }
1193 aoi_mode = fb_mode; 1207 aoi_mode = fb_mode;
1194 else 1208 } else {
1195 aoi_mode = init_aoi_mode; 1209 aoi_mode = init_aoi_mode;
1210 }
1196 pr_debug("mode used = %s\n", aoi_mode); 1211 pr_debug("mode used = %s\n", aoi_mode);
1197 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, 1212 rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
1198 ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); 1213 &fsl_diu_default_mode, default_bpp);
1199
1200 switch (rc) { 1214 switch (rc) {
1201 case 1: 1215 case 1:
1202 pr_debug("using mode specified in @mode\n"); 1216 pr_debug("using mode specified in @mode\n");
@@ -1214,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info)
1214 default: 1228 default:
1215 pr_debug("rc = %d\n", rc); 1229 pr_debug("rc = %d\n", rc);
1216 pr_debug("failed to find mode\n"); 1230 pr_debug("failed to find mode\n");
1217 return -EINVAL; 1231 /*
1232 * For plane 0 we continue and look into
1233 * driver's internal modedb.
1234 */
1235 if (mfbi->index == 0 && mfbi->edid_data)
1236 has_default_mode = 0;
1237 else
1238 return -EINVAL;
1218 break; 1239 break;
1219 } 1240 }
1220 1241
1242 if (!has_default_mode) {
1243 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
1244 ARRAY_SIZE(fsl_diu_mode_db),
1245 &fsl_diu_default_mode,
1246 default_bpp);
1247 if (rc > 0 && rc < 5)
1248 has_default_mode = 1;
1249 }
1250
1251 /* Still not found, use preferred mode from database if any */
1252 if (!has_default_mode && info->monspecs.modedb) {
1253 struct fb_monspecs *specs = &info->monspecs;
1254 struct fb_videomode *modedb = &specs->modedb[0];
1255
1256 /*
1257 * Get preferred timing. If not found,
1258 * first mode in database will be used.
1259 */
1260 if (specs->misc & FB_MISC_1ST_DETAIL) {
1261 int i;
1262
1263 for (i = 0; i < specs->modedb_len; i++) {
1264 if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
1265 modedb = &specs->modedb[i];
1266 break;
1267 }
1268 }
1269 }
1270
1271 info->var.bits_per_pixel = default_bpp;
1272 fb_videomode_to_var(&info->var, modedb);
1273 }
1274
1221 pr_debug("xres_virtual %d\n", info->var.xres_virtual); 1275 pr_debug("xres_virtual %d\n", info->var.xres_virtual);
1222 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); 1276 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
1223 1277
@@ -1256,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info)
1256 if (!mfbi->registered) 1310 if (!mfbi->registered)
1257 return; 1311 return;
1258 1312
1313 if (mfbi->index == 0)
1314 kfree(mfbi->edid_data);
1315
1259 unregister_framebuffer(info); 1316 unregister_framebuffer(info);
1260 unmap_video_memory(info); 1317 unmap_video_memory(info);
1261 if (&info->cmap) 1318 if (&info->cmap)
@@ -1456,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
1456 mfbi = machine_data->fsl_diu_info[i]->par; 1513 mfbi = machine_data->fsl_diu_info[i]->par;
1457 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); 1514 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
1458 mfbi->parent = machine_data; 1515 mfbi->parent = machine_data;
1516
1517 if (mfbi->index == 0) {
1518 const u8 *prop;
1519 int len;
1520
1521 /* Get EDID */
1522 prop = of_get_property(np, "edid", &len);
1523 if (prop && len == EDID_LENGTH)
1524 mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
1525 GFP_KERNEL);
1526 }
1459 } 1527 }
1460 1528
1461 ret = of_address_to_resource(np, 0, &res); 1529 ret = of_address_to_resource(np, 0, &res);