diff options
| -rw-r--r-- | Documentation/powerpc/dts-bindings/fsl/diu.txt | 6 | ||||
| -rw-r--r-- | drivers/video/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/video/fsl-diu-fb.c | 80 |
3 files changed, 81 insertions, 6 deletions
diff --git a/Documentation/powerpc/dts-bindings/fsl/diu.txt b/Documentation/powerpc/dts-bindings/fsl/diu.txt index 326cddfd7c25..b66cb6d31d69 100644 --- a/Documentation/powerpc/dts-bindings/fsl/diu.txt +++ b/Documentation/powerpc/dts-bindings/fsl/diu.txt | |||
| @@ -11,6 +11,11 @@ Required properties: | |||
| 11 | - interrupt-parent : the phandle for the interrupt controller that | 11 | - interrupt-parent : the phandle for the interrupt controller that |
| 12 | services interrupts for this device. | 12 | services interrupts for this device. |
| 13 | 13 | ||
| 14 | Optional properties: | ||
| 15 | - edid : verbatim EDID data block describing attached display. | ||
| 16 | Data from the detailed timing descriptor will be used to | ||
| 17 | program the display controller. | ||
| 18 | |||
| 14 | Example (MPC8610HPCD): | 19 | Example (MPC8610HPCD): |
| 15 | display@2c000 { | 20 | display@2c000 { |
| 16 | compatible = "fsl,diu"; | 21 | compatible = "fsl,diu"; |
| @@ -25,4 +30,5 @@ Example for MPC5121: | |||
| 25 | reg = <0x2100 0x100>; | 30 | reg = <0x2100 0x100>; |
| 26 | interrupts = <64 0x8>; | 31 | interrupts = <64 0x8>; |
| 27 | interrupt-parent = <&ipic>; | 32 | interrupt-parent = <&ipic>; |
| 33 | edid = [edid-data]; | ||
| 28 | }; | 34 | }; |
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); |
