1/* 2 * linux/drivers/video/macmodes.c -- Standard MacOS video modes 3 * 4 * Copyright (C) 1998 Geert Uytterhoeven 5 * 6 * 2000 - Removal of OpenFirmware dependencies by: 7 * - Ani Joshi 8 * - Brad Douglas <brad@neruo.com> 9 * 10 * 2001 - Documented with DocBook 11 * - Brad Douglas <brad@neruo.com> 12 * 13 * This file is subject to the terms and conditions of the GNU General Public 14 * License. See the file COPYING in the main directory of this archive for 15 * more details. 16 */ 17 18#include <linux/errno.h> 19#include <linux/fb.h> 20#include <linux/string.h> 21#include <linux/module.h> 22 23#include "macmodes.h" 24 25 /* 26 * MacOS video mode definitions 27 * 28 * Order IS important! If you change these, don't forget to update 29 * mac_modes[] below! 30 */ 31 32#define DEFAULT_MODEDB_INDEX 0 33 34static const struct fb_videomode mac_modedb[] = { 35 { 36 /* 512x384, 60Hz, Non-Interlaced (15.67 MHz dot clock) */ 37 "mac2", 60, 512, 384, 63828, 80, 16, 19, 1, 32, 3, 38 0, FB_VMODE_NONINTERLACED 39 }, { 40 /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ 41 "mac5", 60, 640, 480, 39722, 32, 32, 33, 10, 96, 2, 42 0, FB_VMODE_NONINTERLACED 43 }, { 44 /* 640x480, 67Hz, Non-Interlaced (30.0 MHz dotclock) */ 45 "mac6", 67, 640, 480, 33334, 80, 80, 39, 3, 64, 3, 46 0, FB_VMODE_NONINTERLACED 47 }, { 48 /* 640x870, 75Hz (portrait), Non-Interlaced (57.28 MHz dot clock) */ 49 "mac7", 75, 640, 870, 17457, 80, 32, 42, 3, 80, 3, 50 0, FB_VMODE_NONINTERLACED 51 }, { 52 /* 800x600, 56 Hz, Non-Interlaced (36.00 MHz dotclock) */ 53 "mac9", 56, 800, 600, 27778, 112, 40, 22, 1, 72, 2, 54 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 55 }, { 56 /* 800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock) */ 57 "mac10", 60, 800, 600, 25000, 72, 56, 23, 1, 128, 4, 58 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 59 }, { 60 /* 800x600, 72 Hz, Non-Interlaced (50.00 MHz dotclock) */ 61 "mac11", 72, 800, 600, 20000, 48, 72, 23, 37, 120, 6, 62 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 63 }, { 64 /* 800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock) */ 65 "mac12", 75, 800, 600, 20203, 144, 32, 21, 1, 80, 3, 66 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 67 }, { 68 /* 832x624, 75Hz, Non-Interlaced (57.6 MHz dotclock) */ 69 "mac13", 75, 832, 624, 17362, 208, 48, 39, 1, 64, 3, 70 0, FB_VMODE_NONINTERLACED 71 }, { 72 /* 1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock) */ 73 "mac14", 60, 1024, 768, 15385, 144, 40, 29, 3, 136, 6, 74 0, FB_VMODE_NONINTERLACED 75 }, { 76 /* 1024x768, 72 Hz, Non-Interlaced (75.00 MHz dotclock) */ 77 "mac15", 72, 1024, 768, 13334, 128, 40, 29, 3, 136, 6, 78 0, FB_VMODE_NONINTERLACED 79 }, { 80 /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ 81 "mac16", 75, 1024, 768, 12699, 176, 16, 28, 1, 96, 3, 82 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 83 }, { 84 /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ 85 "mac17", 75, 1024, 768, 12699, 160, 32, 28, 1, 96, 3, 86 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 87 }, { 88 /* 1152x870, 75 Hz, Non-Interlaced (100.0 MHz dotclock) */ 89 "mac18", 75, 1152, 870, 10000, 128, 48, 39, 3, 128, 3, 90 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 91 }, { 92 /* 1280x960, 75 Hz, Non-Interlaced (126.00 MHz dotclock) */ 93 "mac19", 75, 1280, 960, 7937, 224, 32, 36, 1, 144, 3, 94 0, FB_VMODE_NONINTERLACED 95 }, { 96 /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */ 97 "mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3, 98 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 99 }, { 100 /* 1152x768, 60 Hz, Titanium PowerBook */ 101 "mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6, 102 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 103 }, { 104 /* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */ 105 "mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1, 106 FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED 107 } 108 109#if 0 110 /* Anyone who has timings for these? */ 111 { 112 /* VMODE_512_384_60I: 512x384, 60Hz, Interlaced (NTSC) */ 113 "mac1", 60, 512, 384, pixclock, left, right, upper, lower, hslen, vslen, 114 sync, FB_VMODE_INTERLACED 115 }, { 116 /* VMODE_640_480_50I: 640x480, 50Hz, Interlaced (PAL) */ 117 "mac3", 50, 640, 480, pixclock, left, right, upper, lower, hslen, vslen, 118 sync, FB_VMODE_INTERLACED 119 }, { 120 /* VMODE_640_480_60I: 640x480, 60Hz, Interlaced (NTSC) */ 121 "mac4", 60, 640, 480, pixclock, left, right, upper, lower, hslen, vslen, 122 sync, FB_VMODE_INTERLACED 123 }, { 124 /* VMODE_768_576_50I: 768x576, 50Hz (PAL full frame), Interlaced */ 125 "mac8", 50, 768, 576, pixclock, left, right, upper, lower, hslen, vslen, 126 sync, FB_VMODE_INTERLACED 127 }, 128#endif 129}; 130 131 132 /* 133 * Mapping between MacOS video mode numbers and video mode definitions 134 * 135 * These MUST be ordered in 136 * - increasing resolution 137 * - decreasing pixel clock period 138 */ 139 140static const struct mode_map { 141 int vmode; 142 const struct fb_videomode *mode; 143} mac_modes[] = { 144 /* 512x384 */ 145 { VMODE_512_384_60, &mac_modedb[0] }, 146 /* 640x480 */ 147 { VMODE_640_480_60, &mac_modedb[1] }, 148 { VMODE_640_480_67, &mac_modedb[2] }, 149 /* 640x870 */ 150 { VMODE_640_870_75P, &mac_modedb[3] }, 151 /* 800x600 */ 152 { VMODE_800_600_56, &mac_modedb[4] }, 153 { VMODE_800_600_60, &mac_modedb[5] }, 154 { VMODE_800_600_75, &mac_modedb[7] }, 155 { VMODE_800_600_72, &mac_modedb[6] }, 156 /* 832x624 */ 157 { VMODE_832_624_75, &mac_modedb[8] }, 158 /* 1024x768 */ 159 { VMODE_1024_768_60, &mac_modedb[9] }, 160 { VMODE_1024_768_70, &mac_modedb[10] }, 161 { VMODE_1024_768_75V, &mac_modedb[11] }, 162 { VMODE_1024_768_75, &mac_modedb[12] }, 163 /* 1152x768 */ 164 { VMODE_1152_768_60, &mac_modedb[16] }, 165 /* 1152x870 */ 166 { VMODE_1152_870_75, &mac_modedb[13] }, 167 /* 1280x960 */ 168 { VMODE_1280_960_75, &mac_modedb[14] }, 169 /* 1280x1024 */ 170 { VMODE_1280_1024_75, &mac_modedb[15] }, 171 /* 1600x1024 */ 172 { VMODE_1600_1024_60, &mac_modedb[17] }, 173 { -1, NULL } 174}; 175 176 177 /* 178 * Mapping between monitor sense values and MacOS video mode numbers 179 */ 180 181static const struct monitor_map { 182 int sense; 183 int vmode; 184} mac_monitors[] = { 185 { 0x000, VMODE_1280_1024_75 }, /* 21" RGB */ 186 { 0x114, VMODE_640_870_75P }, /* Portrait Monochrome */ 187 { 0x221, VMODE_512_384_60 }, /* 12" RGB*/ 188 { 0x331, VMODE_1280_1024_75 }, /* 21" RGB (Radius) */ 189 { 0x334, VMODE_1280_1024_75 }, /* 21" mono (Radius) */ 190 { 0x335, VMODE_1280_1024_75 }, /* 21" mono */ 191 { 0x40A, VMODE_640_480_60I }, /* NTSC */ 192 { 0x51E, VMODE_640_870_75P }, /* Portrait RGB */ 193 { 0x603, VMODE_832_624_75 }, /* 12"-16" multiscan */ 194 { 0x60b, VMODE_1024_768_70 }, /* 13"-19" multiscan */ 195 { 0x623, VMODE_1152_870_75 }, /* 13"-21" multiscan */ 196 { 0x62b, VMODE_640_480_67 }, /* 13"/14" RGB */ 197 { 0x700, VMODE_640_480_50I }, /* PAL */ 198 { 0x714, VMODE_640_480_60I }, /* NTSC */ 199 { 0x717, VMODE_800_600_75 }, /* VGA */ 200 { 0x72d, VMODE_832_624_75 }, /* 16" RGB (Goldfish) */ 201 { 0x730, VMODE_768_576_50I }, /* PAL (Alternate) */ 202 { 0x73a, VMODE_1152_870_75 }, /* 3rd party 19" */ 203 { 0x73f, VMODE_640_480_67 }, /* no sense lines connected at all */ 204 { 0xBEEF, VMODE_1600_1024_60 }, /* 22" Apple Cinema Display */ 205 { -1, VMODE_640_480_60 }, /* catch-all, must be last */ 206}; 207 208/** 209 * mac_vmode_to_var - converts vmode/cmode pair to var structure 210 * @vmode: MacOS video mode 211 * @cmode: MacOS color mode 212 * @var: frame buffer video mode structure 213 * 214 * Converts a MacOS vmode/cmode pair to a frame buffer video 215 * mode structure. 216 * 217 * Returns negative errno on error, or zero for success. 218 * 219 */ 220 221int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var) 222{ 223 const struct fb_videomode *mode = NULL; 224 const struct mode_map *map; 225 226 for (map = mac_modes; map->vmode != -1; map++) 227 if (map->vmode == vmode) { 228 mode = map->mode; 229 break; 230 } 231 if (!mode) 232 return -EINVAL; 233 234 memset(var, 0, sizeof(struct fb_var_screeninfo)); 235 switch (cmode) { 236 case CMODE_8: 237 var->bits_per_pixel = 8; 238 var->red.offset = 0; 239 var->red.length = 8; 240 var->green.offset = 0; 241 var->green.length = 8; 242 var->blue.offset = 0; 243 var->blue.length = 8; 244 break; 245 246 case CMODE_16: 247 var->bits_per_pixel = 16; 248 var->red.offset = 10; 249 var->red.length = 5; 250 var->green.offset = 5; 251 var->green.length = 5; 252 var->blue.offset = 0; 253 var->blue.length = 5; 254 break; 255 256 case CMODE_32: 257 var->bits_per_pixel = 32; 258 var->red.offset = 16; 259 var->red.length = 8; 260 var->green.offset = 8; 261 var->green.length = 8; 262 var->blue.offset = 0; 263 var->blue.length = 8; 264 var->transp.offset = 24; 265 var->transp.length = 8; 266 break; 267 268 default: 269 return -EINVAL; 270 } 271 var->xres = mode->xres; 272 var->yres = mode->yres; 273 var->xres_virtual = mode->xres; 274 var->yres_virtual = mode->yres; 275 var->height = -1; 276 var->width = -1; 277 var->pixclock = mode->pixclock; 278 var->left_margin = mode->left_margin; 279 var->right_margin = mode->right_margin; 280 var->upper_margin = mode->upper_margin; 281 var->lower_margin = mode->lower_margin; 282 var->hsync_len = mode->hsync_len; 283 var->vsync_len = mode->vsync_len; 284 var->sync = mode->sync; 285 var->vmode = mode->vmode; 286 return 0; 287} 288EXPORT_SYMBOL(mac_vmode_to_var); 289 290/** 291 * mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair 292 * @var: frame buffer video mode structure 293 * @vmode: MacOS video mode 294 * @cmode: MacOS color mode 295 * 296 * Converts a frame buffer video mode structure to a MacOS 297 * vmode/cmode pair. 298 * 299 * Returns negative errno on error, or zero for success. 300 * 301 */ 302 303int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode, 304 int *cmode) 305{ 306 const struct mode_map *map; 307 308 if (var->bits_per_pixel <= 8) 309 *cmode = CMODE_8; 310 else if (var->bits_per_pixel <= 16) 311 *cmode = CMODE_16; 312 else if (var->bits_per_pixel <= 32) 313 *cmode = CMODE_32; 314 else 315 return -EINVAL; 316 317 /* 318 * Find the mac_mode with a matching resolution or failing that, the 319 * closest larger resolution. Skip modes with a shorter pixel clock period. 320 */ 321 for (map = mac_modes; map->vmode != -1; map++) { 322 const struct fb_videomode *mode = map->mode; 323 324 if (var->xres > mode->xres || var->yres > mode->yres) 325 continue; 326 if (var->xres_virtual > mode->xres || var->yres_virtual > mode->yres) 327 continue; 328 if (var->pixclock > mode->pixclock) 329 continue; 330 if ((var->vmode & FB_VMODE_MASK) != mode->vmode) 331 continue; 332 *vmode = map->vmode; 333 334 /* 335 * Having found a good resolution, find the matching pixel clock 336 * or failing that, the closest longer pixel clock period. 337 */ 338 map++; 339 while (map->vmode != -1) { 340 const struct fb_videomode *clk_mode = map->mode; 341 342 if (mode->xres != clk_mode->xres || mode->yres != clk_mode->yres) 343 break; 344 if (var->pixclock > mode->pixclock) 345 break; 346 if (mode->vmode != clk_mode->vmode) 347 continue; 348 *vmode = map->vmode; 349 map++; 350 } 351 return 0; 352 } 353 return -EINVAL; 354} 355 356/** 357 * mac_map_monitor_sense - Convert monitor sense to vmode 358 * @sense: Macintosh monitor sense number 359 * 360 * Converts a Macintosh monitor sense number to a MacOS 361 * vmode number. 362 * 363 * Returns MacOS vmode video mode number. 364 * 365 */ 366 367int mac_map_monitor_sense(int sense) 368{ 369 const struct monitor_map *map; 370 371 for (map = mac_monitors; map->sense != -1; map++) 372 if (map->sense == sense) 373 break; 374 return map->vmode; 375} 376EXPORT_SYMBOL(mac_map_monitor_sense); 377 378/** 379 * mac_find_mode - find a video mode 380 * @var: frame buffer user defined part of display 381 * @info: frame buffer info structure 382 * @mode_option: video mode name (see mac_modedb[]) 383 * @default_bpp: default color depth in bits per pixel 384 * 385 * Finds a suitable video mode. Tries to set mode specified 386 * by @mode_option. If the name of the wanted mode begins with 387 * 'mac', the Mac video mode database will be used, otherwise it 388 * will fall back to the standard video mode database. 389 * 390 * Note: Function marked as __init and can only be used during 391 * system boot. 392 * 393 * Returns error code from fb_find_mode (see fb_find_mode 394 * function). 395 * 396 */ 397 398int mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info, 399 const char *mode_option, unsigned int default_bpp) 400{ 401 const struct fb_videomode *db = NULL; 402 unsigned int dbsize = 0; 403 404 if (mode_option && !strncmp(mode_option, "mac", 3)) { 405 mode_option += 3; 406 db = mac_modedb; 407 dbsize = ARRAY_SIZE(mac_modedb); 408 } 409 return fb_find_mode(var, info, mode_option, db, dbsize, 410 &mac_modedb[DEFAULT_MODEDB_INDEX], default_bpp); 411} 412EXPORT_SYMBOL(mac_find_mode); 413 414MODULE_LICENSE("GPL"); 415