diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/Kconfig | 1 | ||||
-rw-r--r-- | drivers/video/fsl-diu-fb.c | 80 |
2 files changed, 75 insertions, 6 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3d94a1471724..114aeb0d9971 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG | |||
1871 | config FB_FSL_DIU | 1871 | config FB_FSL_DIU |
1872 | tristate "Freescale DIU framebuffer support" | 1872 | tristate "Freescale DIU framebuffer support" |
1873 | depends on FB && FSL_SOC | 1873 | depends on FB && FSL_SOC |
1874 | select FB_MODE_HELPERS | ||
1874 | select FB_CFB_FILLRECT | 1875 | select FB_CFB_FILLRECT |
1875 | select FB_CFB_COPYAREA | 1876 | select FB_CFB_COPYAREA |
1876 | select FB_CFB_IMAGEBLIT | 1877 | select FB_CFB_IMAGEBLIT |
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); |