diff options
| -rw-r--r-- | drivers/video/offb.c | 192 |
1 files changed, 142 insertions, 50 deletions
diff --git a/drivers/video/offb.c b/drivers/video/offb.c index d7b3dcc0dc43..e1d9eeb1aeaf 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c | |||
| @@ -47,6 +47,7 @@ enum { | |||
| 47 | cmap_M3B, /* ATI Rage Mobility M3 Head B */ | 47 | cmap_M3B, /* ATI Rage Mobility M3 Head B */ |
| 48 | cmap_radeon, /* ATI Radeon */ | 48 | cmap_radeon, /* ATI Radeon */ |
| 49 | cmap_gxt2000, /* IBM GXT2000 */ | 49 | cmap_gxt2000, /* IBM GXT2000 */ |
| 50 | cmap_avivo, /* ATI R5xx */ | ||
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | struct offb_par { | 53 | struct offb_par { |
| @@ -58,26 +59,36 @@ struct offb_par { | |||
| 58 | 59 | ||
| 59 | struct offb_par default_par; | 60 | struct offb_par default_par; |
| 60 | 61 | ||
| 61 | /* | ||
| 62 | * Interface used by the world | ||
| 63 | */ | ||
| 64 | |||
| 65 | static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
| 66 | u_int transp, struct fb_info *info); | ||
| 67 | static int offb_blank(int blank, struct fb_info *info); | ||
| 68 | |||
| 69 | #ifdef CONFIG_PPC32 | 62 | #ifdef CONFIG_PPC32 |
| 70 | extern boot_infos_t *boot_infos; | 63 | extern boot_infos_t *boot_infos; |
| 71 | #endif | 64 | #endif |
| 72 | 65 | ||
| 73 | static struct fb_ops offb_ops = { | 66 | /* Definitions used by the Avivo palette hack */ |
| 74 | .owner = THIS_MODULE, | 67 | #define AVIVO_DC_LUT_RW_SELECT 0x6480 |
| 75 | .fb_setcolreg = offb_setcolreg, | 68 | #define AVIVO_DC_LUT_RW_MODE 0x6484 |
| 76 | .fb_blank = offb_blank, | 69 | #define AVIVO_DC_LUT_RW_INDEX 0x6488 |
| 77 | .fb_fillrect = cfb_fillrect, | 70 | #define AVIVO_DC_LUT_SEQ_COLOR 0x648c |
| 78 | .fb_copyarea = cfb_copyarea, | 71 | #define AVIVO_DC_LUT_PWL_DATA 0x6490 |
| 79 | .fb_imageblit = cfb_imageblit, | 72 | #define AVIVO_DC_LUT_30_COLOR 0x6494 |
| 80 | }; | 73 | #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 |
| 74 | #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c | ||
| 75 | #define AVIVO_DC_LUT_AUTOFILL 0x64a0 | ||
| 76 | |||
| 77 | #define AVIVO_DC_LUTA_CONTROL 0x64c0 | ||
| 78 | #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 | ||
| 79 | #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 | ||
| 80 | #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc | ||
| 81 | #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 | ||
| 82 | #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 | ||
| 83 | #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 | ||
| 84 | |||
| 85 | #define AVIVO_DC_LUTB_CONTROL 0x6cc0 | ||
| 86 | #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4 | ||
| 87 | #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8 | ||
| 88 | #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc | ||
| 89 | #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0 | ||
| 90 | #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4 | ||
| 91 | #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8 | ||
| 81 | 92 | ||
| 82 | /* | 93 | /* |
| 83 | * Set a single color register. The values supplied are already | 94 | * Set a single color register. The values supplied are already |
| @@ -160,6 +171,17 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
| 160 | out_le32(((unsigned __iomem *) par->cmap_adr) + regno, | 171 | out_le32(((unsigned __iomem *) par->cmap_adr) + regno, |
| 161 | (red << 16 | green << 8 | blue)); | 172 | (red << 16 | green << 8 | blue)); |
| 162 | break; | 173 | break; |
| 174 | case cmap_avivo: | ||
| 175 | /* Write to both LUTs for now */ | ||
| 176 | writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 177 | writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); | ||
| 178 | writel(((red) << 22) | ((green) << 12) | ((blue) << 2), | ||
| 179 | par->cmap_adr + AVIVO_DC_LUT_30_COLOR); | ||
| 180 | writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 181 | writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); | ||
| 182 | writel(((red) << 22) | ((green) << 12) | ((blue) << 2), | ||
| 183 | par->cmap_adr + AVIVO_DC_LUT_30_COLOR); | ||
| 184 | break; | ||
| 163 | } | 185 | } |
| 164 | 186 | ||
| 165 | return 0; | 187 | return 0; |
| @@ -216,12 +238,59 @@ static int offb_blank(int blank, struct fb_info *info) | |||
| 216 | out_le32(((unsigned __iomem *) par->cmap_adr) + i, | 238 | out_le32(((unsigned __iomem *) par->cmap_adr) + i, |
| 217 | 0); | 239 | 0); |
| 218 | break; | 240 | break; |
| 241 | case cmap_avivo: | ||
| 242 | writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 243 | writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); | ||
| 244 | writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); | ||
| 245 | writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 246 | writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX); | ||
| 247 | writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR); | ||
| 248 | break; | ||
| 219 | } | 249 | } |
| 220 | } else | 250 | } else |
| 221 | fb_set_cmap(&info->cmap, info); | 251 | fb_set_cmap(&info->cmap, info); |
| 222 | return 0; | 252 | return 0; |
| 223 | } | 253 | } |
| 224 | 254 | ||
| 255 | static int offb_set_par(struct fb_info *info) | ||
| 256 | { | ||
| 257 | struct offb_par *par = (struct offb_par *) info->par; | ||
| 258 | |||
| 259 | /* On avivo, initialize palette control */ | ||
| 260 | if (par->cmap_type == cmap_avivo) { | ||
| 261 | writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL); | ||
| 262 | writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE); | ||
| 263 | writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN); | ||
| 264 | writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED); | ||
| 265 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE); | ||
| 266 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN); | ||
| 267 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED); | ||
| 268 | writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL); | ||
| 269 | writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE); | ||
| 270 | writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN); | ||
| 271 | writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED); | ||
| 272 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE); | ||
| 273 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN); | ||
| 274 | writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED); | ||
| 275 | writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 276 | writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); | ||
| 277 | writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); | ||
| 278 | writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT); | ||
| 279 | writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE); | ||
| 280 | writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK); | ||
| 281 | } | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static struct fb_ops offb_ops = { | ||
| 286 | .owner = THIS_MODULE, | ||
| 287 | .fb_setcolreg = offb_setcolreg, | ||
| 288 | .fb_set_par = offb_set_par, | ||
| 289 | .fb_blank = offb_blank, | ||
| 290 | .fb_fillrect = cfb_fillrect, | ||
| 291 | .fb_copyarea = cfb_copyarea, | ||
| 292 | .fb_imageblit = cfb_imageblit, | ||
| 293 | }; | ||
| 225 | 294 | ||
| 226 | static void __iomem *offb_map_reg(struct device_node *np, int index, | 295 | static void __iomem *offb_map_reg(struct device_node *np, int index, |
| 227 | unsigned long offset, unsigned long size) | 296 | unsigned long offset, unsigned long size) |
| @@ -245,6 +314,59 @@ static void __iomem *offb_map_reg(struct device_node *np, int index, | |||
| 245 | return ioremap(taddr + offset, size); | 314 | return ioremap(taddr + offset, size); |
| 246 | } | 315 | } |
| 247 | 316 | ||
| 317 | static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp, | ||
| 318 | const char *name, unsigned long address) | ||
| 319 | { | ||
| 320 | struct offb_par *par = (struct offb_par *) info->par; | ||
| 321 | |||
| 322 | if (dp && !strncmp(name, "ATY,Rage128", 11)) { | ||
| 323 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | ||
| 324 | if (par->cmap_adr) | ||
| 325 | par->cmap_type = cmap_r128; | ||
| 326 | } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) | ||
| 327 | || !strncmp(name, "ATY,RageM3p12A", 14))) { | ||
| 328 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | ||
| 329 | if (par->cmap_adr) | ||
| 330 | par->cmap_type = cmap_M3A; | ||
| 331 | } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { | ||
| 332 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | ||
| 333 | if (par->cmap_adr) | ||
| 334 | par->cmap_type = cmap_M3B; | ||
| 335 | } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { | ||
| 336 | par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); | ||
| 337 | if (par->cmap_adr) | ||
| 338 | par->cmap_type = cmap_radeon; | ||
| 339 | } else if (!strncmp(name, "ATY,", 4)) { | ||
| 340 | unsigned long base = address & 0xff000000UL; | ||
| 341 | par->cmap_adr = | ||
| 342 | ioremap(base + 0x7ff000, 0x1000) + 0xcc0; | ||
| 343 | par->cmap_data = par->cmap_adr + 1; | ||
| 344 | par->cmap_type = cmap_m64; | ||
| 345 | } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") || | ||
| 346 | of_device_is_compatible(dp, "pci1014,21c"))) { | ||
| 347 | par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); | ||
| 348 | if (par->cmap_adr) | ||
| 349 | par->cmap_type = cmap_gxt2000; | ||
| 350 | } else if (dp && !strncmp(name, "vga,Display-", 12)) { | ||
| 351 | /* Look for AVIVO initialized by SLOF */ | ||
| 352 | struct device_node *pciparent = of_get_parent(dp); | ||
| 353 | const u32 *vid, *did; | ||
| 354 | vid = of_get_property(pciparent, "vendor-id", NULL); | ||
| 355 | did = of_get_property(pciparent, "device-id", NULL); | ||
| 356 | /* This will match most R5xx */ | ||
| 357 | if (vid && did && *vid == 0x1002 && | ||
| 358 | ((*did >= 0x7100 && *did < 0x7800) || | ||
| 359 | (*did >= 0x9400))) { | ||
| 360 | par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000); | ||
| 361 | if (par->cmap_adr) | ||
| 362 | par->cmap_type = cmap_avivo; | ||
| 363 | } | ||
| 364 | of_node_put(pciparent); | ||
| 365 | } | ||
| 366 | info->fix.visual = (par->cmap_type != cmap_unknown) ? | ||
| 367 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; | ||
| 368 | } | ||
| 369 | |||
| 248 | static void __init offb_init_fb(const char *name, const char *full_name, | 370 | static void __init offb_init_fb(const char *name, const char *full_name, |
| 249 | int width, int height, int depth, | 371 | int width, int height, int depth, |
| 250 | int pitch, unsigned long address, | 372 | int pitch, unsigned long address, |
| @@ -283,6 +405,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, | |||
| 283 | 405 | ||
| 284 | fix = &info->fix; | 406 | fix = &info->fix; |
| 285 | var = &info->var; | 407 | var = &info->var; |
| 408 | info->par = par; | ||
| 286 | 409 | ||
| 287 | strcpy(fix->id, "OFfb "); | 410 | strcpy(fix->id, "OFfb "); |
| 288 | strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); | 411 | strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb ")); |
| @@ -298,39 +421,9 @@ static void __init offb_init_fb(const char *name, const char *full_name, | |||
| 298 | fix->type_aux = 0; | 421 | fix->type_aux = 0; |
| 299 | 422 | ||
| 300 | par->cmap_type = cmap_unknown; | 423 | par->cmap_type = cmap_unknown; |
| 301 | if (depth == 8) { | 424 | if (depth == 8) |
| 302 | if (dp && !strncmp(name, "ATY,Rage128", 11)) { | 425 | offb_init_palette_hacks(info, dp, name, address); |
| 303 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | 426 | else |
| 304 | if (par->cmap_adr) | ||
| 305 | par->cmap_type = cmap_r128; | ||
| 306 | } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) | ||
| 307 | || !strncmp(name, "ATY,RageM3p12A", 14))) { | ||
| 308 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | ||
| 309 | if (par->cmap_adr) | ||
| 310 | par->cmap_type = cmap_M3A; | ||
| 311 | } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { | ||
| 312 | par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff); | ||
| 313 | if (par->cmap_adr) | ||
| 314 | par->cmap_type = cmap_M3B; | ||
| 315 | } else if (dp && !strncmp(name, "ATY,Rage6", 9)) { | ||
| 316 | par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff); | ||
| 317 | if (par->cmap_adr) | ||
| 318 | par->cmap_type = cmap_radeon; | ||
| 319 | } else if (!strncmp(name, "ATY,", 4)) { | ||
| 320 | unsigned long base = address & 0xff000000UL; | ||
| 321 | par->cmap_adr = | ||
| 322 | ioremap(base + 0x7ff000, 0x1000) + 0xcc0; | ||
| 323 | par->cmap_data = par->cmap_adr + 1; | ||
| 324 | par->cmap_type = cmap_m64; | ||
| 325 | } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") || | ||
| 326 | of_device_is_compatible(dp, "pci1014,21c"))) { | ||
| 327 | par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000); | ||
| 328 | if (par->cmap_adr) | ||
| 329 | par->cmap_type = cmap_gxt2000; | ||
| 330 | } | ||
| 331 | fix->visual = (par->cmap_type != cmap_unknown) ? | ||
| 332 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; | ||
| 333 | } else | ||
| 334 | fix->visual = FB_VISUAL_TRUECOLOR; | 427 | fix->visual = FB_VISUAL_TRUECOLOR; |
| 335 | 428 | ||
| 336 | var->xoffset = var->yoffset = 0; | 429 | var->xoffset = var->yoffset = 0; |
| @@ -395,7 +488,6 @@ static void __init offb_init_fb(const char *name, const char *full_name, | |||
| 395 | 488 | ||
| 396 | info->fbops = &offb_ops; | 489 | info->fbops = &offb_ops; |
| 397 | info->screen_base = ioremap(address, fix->smem_len); | 490 | info->screen_base = ioremap(address, fix->smem_len); |
| 398 | info->par = par; | ||
| 399 | info->pseudo_palette = (void *) (info + 1); | 491 | info->pseudo_palette = (void *) (info + 1); |
| 400 | info->flags = FBINFO_DEFAULT | foreign_endian; | 492 | info->flags = FBINFO_DEFAULT | foreign_endian; |
| 401 | 493 | ||
