0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/module.h>
0016 #include <linux/kernel.h>
0017 #include <linux/errno.h>
0018 #include <linux/string.h>
0019 #include <linux/mm.h>
0020 #include <linux/vmalloc.h>
0021 #include <linux/delay.h>
0022 #include <linux/of.h>
0023 #include <linux/of_address.h>
0024 #include <linux/interrupt.h>
0025 #include <linux/fb.h>
0026 #include <linux/init.h>
0027 #include <linux/ioport.h>
0028 #include <linux/pci.h>
0029 #include <linux/platform_device.h>
0030 #include <asm/io.h>
0031
0032 #ifdef CONFIG_PPC32
0033 #include <asm/bootx.h>
0034 #endif
0035
0036 #include "macmodes.h"
0037
0038
0039 enum {
0040 cmap_unknown,
0041 cmap_simple,
0042 cmap_r128,
0043 cmap_M3A,
0044 cmap_M3B,
0045 cmap_radeon,
0046 cmap_gxt2000,
0047 cmap_avivo,
0048 cmap_qemu,
0049 };
0050
0051 struct offb_par {
0052 volatile void __iomem *cmap_adr;
0053 volatile void __iomem *cmap_data;
0054 int cmap_type;
0055 int blanked;
0056 };
0057
0058 struct offb_par default_par;
0059
0060 #ifdef CONFIG_PPC32
0061 extern boot_infos_t *boot_infos;
0062 #endif
0063
0064
0065 #define AVIVO_DC_LUT_RW_SELECT 0x6480
0066 #define AVIVO_DC_LUT_RW_MODE 0x6484
0067 #define AVIVO_DC_LUT_RW_INDEX 0x6488
0068 #define AVIVO_DC_LUT_SEQ_COLOR 0x648c
0069 #define AVIVO_DC_LUT_PWL_DATA 0x6490
0070 #define AVIVO_DC_LUT_30_COLOR 0x6494
0071 #define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498
0072 #define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c
0073 #define AVIVO_DC_LUT_AUTOFILL 0x64a0
0074
0075 #define AVIVO_DC_LUTA_CONTROL 0x64c0
0076 #define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4
0077 #define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8
0078 #define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc
0079 #define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0
0080 #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4
0081 #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8
0082
0083 #define AVIVO_DC_LUTB_CONTROL 0x6cc0
0084 #define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE 0x6cc4
0085 #define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN 0x6cc8
0086 #define AVIVO_DC_LUTB_BLACK_OFFSET_RED 0x6ccc
0087 #define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE 0x6cd0
0088 #define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN 0x6cd4
0089 #define AVIVO_DC_LUTB_WHITE_OFFSET_RED 0x6cd8
0090
0091
0092
0093
0094
0095
0096
0097 static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0098 u_int transp, struct fb_info *info)
0099 {
0100 struct offb_par *par = (struct offb_par *) info->par;
0101
0102 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
0103 u32 *pal = info->pseudo_palette;
0104 u32 cr = red >> (16 - info->var.red.length);
0105 u32 cg = green >> (16 - info->var.green.length);
0106 u32 cb = blue >> (16 - info->var.blue.length);
0107 u32 value;
0108
0109 if (regno >= 16)
0110 return -EINVAL;
0111
0112 value = (cr << info->var.red.offset) |
0113 (cg << info->var.green.offset) |
0114 (cb << info->var.blue.offset);
0115 if (info->var.transp.length > 0) {
0116 u32 mask = (1 << info->var.transp.length) - 1;
0117 mask <<= info->var.transp.offset;
0118 value |= mask;
0119 }
0120 pal[regno] = value;
0121 return 0;
0122 }
0123
0124 if (regno > 255)
0125 return -EINVAL;
0126
0127 red >>= 8;
0128 green >>= 8;
0129 blue >>= 8;
0130
0131 if (!par->cmap_adr)
0132 return 0;
0133
0134 switch (par->cmap_type) {
0135 case cmap_simple:
0136 writeb(regno, par->cmap_adr);
0137 writeb(red, par->cmap_data);
0138 writeb(green, par->cmap_data);
0139 writeb(blue, par->cmap_data);
0140 break;
0141 case cmap_M3A:
0142
0143 out_le32(par->cmap_adr + 0x58,
0144 in_le32(par->cmap_adr + 0x58) & ~0x20);
0145 fallthrough;
0146 case cmap_r128:
0147
0148 out_8(par->cmap_adr + 0xb0, regno);
0149 out_le32(par->cmap_adr + 0xb4,
0150 (red << 16 | green << 8 | blue));
0151 break;
0152 case cmap_M3B:
0153
0154 out_le32(par->cmap_adr + 0x58,
0155 in_le32(par->cmap_adr + 0x58) | 0x20);
0156
0157 out_8(par->cmap_adr + 0xb0, regno);
0158 out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
0159 break;
0160 case cmap_radeon:
0161
0162 out_8(par->cmap_adr + 0xb0, regno);
0163 out_le32(par->cmap_adr + 0xb4, (red << 16 | green << 8 | blue));
0164 break;
0165 case cmap_gxt2000:
0166 out_le32(((unsigned __iomem *) par->cmap_adr) + regno,
0167 (red << 16 | green << 8 | blue));
0168 break;
0169 case cmap_avivo:
0170
0171 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0172 writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
0173 writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
0174 par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
0175 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0176 writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
0177 writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
0178 par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
0179 break;
0180 }
0181
0182 return 0;
0183 }
0184
0185
0186
0187
0188
0189 static int offb_blank(int blank, struct fb_info *info)
0190 {
0191 struct offb_par *par = (struct offb_par *) info->par;
0192 int i, j;
0193
0194 if (!par->cmap_adr)
0195 return 0;
0196
0197 if (!par->blanked)
0198 if (!blank)
0199 return 0;
0200
0201 par->blanked = blank;
0202
0203 if (blank)
0204 for (i = 0; i < 256; i++) {
0205 switch (par->cmap_type) {
0206 case cmap_simple:
0207 writeb(i, par->cmap_adr);
0208 for (j = 0; j < 3; j++)
0209 writeb(0, par->cmap_data);
0210 break;
0211 case cmap_M3A:
0212
0213 out_le32(par->cmap_adr + 0x58,
0214 in_le32(par->cmap_adr + 0x58) & ~0x20);
0215 fallthrough;
0216 case cmap_r128:
0217
0218 out_8(par->cmap_adr + 0xb0, i);
0219 out_le32(par->cmap_adr + 0xb4, 0);
0220 break;
0221 case cmap_M3B:
0222
0223 out_le32(par->cmap_adr + 0x58,
0224 in_le32(par->cmap_adr + 0x58) | 0x20);
0225
0226 out_8(par->cmap_adr + 0xb0, i);
0227 out_le32(par->cmap_adr + 0xb4, 0);
0228 break;
0229 case cmap_radeon:
0230 out_8(par->cmap_adr + 0xb0, i);
0231 out_le32(par->cmap_adr + 0xb4, 0);
0232 break;
0233 case cmap_gxt2000:
0234 out_le32(((unsigned __iomem *) par->cmap_adr) + i,
0235 0);
0236 break;
0237 case cmap_avivo:
0238 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0239 writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
0240 writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
0241 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0242 writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
0243 writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
0244 break;
0245 }
0246 } else
0247 fb_set_cmap(&info->cmap, info);
0248 return 0;
0249 }
0250
0251 static int offb_set_par(struct fb_info *info)
0252 {
0253 struct offb_par *par = (struct offb_par *) info->par;
0254
0255
0256 if (par->cmap_type == cmap_avivo) {
0257 writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL);
0258 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE);
0259 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN);
0260 writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED);
0261 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE);
0262 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN);
0263 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED);
0264 writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL);
0265 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE);
0266 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN);
0267 writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED);
0268 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE);
0269 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN);
0270 writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED);
0271 writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0272 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
0273 writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
0274 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
0275 writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
0276 writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
0277 }
0278 return 0;
0279 }
0280
0281 static void offb_destroy(struct fb_info *info)
0282 {
0283 if (info->screen_base)
0284 iounmap(info->screen_base);
0285 release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
0286 fb_dealloc_cmap(&info->cmap);
0287 framebuffer_release(info);
0288 }
0289
0290 static const struct fb_ops offb_ops = {
0291 .owner = THIS_MODULE,
0292 .fb_destroy = offb_destroy,
0293 .fb_setcolreg = offb_setcolreg,
0294 .fb_set_par = offb_set_par,
0295 .fb_blank = offb_blank,
0296 .fb_fillrect = cfb_fillrect,
0297 .fb_copyarea = cfb_copyarea,
0298 .fb_imageblit = cfb_imageblit,
0299 };
0300
0301 static void __iomem *offb_map_reg(struct device_node *np, int index,
0302 unsigned long offset, unsigned long size)
0303 {
0304 const __be32 *addrp;
0305 u64 asize, taddr;
0306 unsigned int flags;
0307
0308 addrp = of_get_pci_address(np, index, &asize, &flags);
0309 if (addrp == NULL)
0310 addrp = of_get_address(np, index, &asize, &flags);
0311 if (addrp == NULL)
0312 return NULL;
0313 if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
0314 return NULL;
0315 if ((offset + size) > asize)
0316 return NULL;
0317 taddr = of_translate_address(np, addrp);
0318 if (taddr == OF_BAD_ADDR)
0319 return NULL;
0320 return ioremap(taddr + offset, size);
0321 }
0322
0323 static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp,
0324 unsigned long address)
0325 {
0326 struct offb_par *par = (struct offb_par *) info->par;
0327
0328 if (of_node_name_prefix(dp, "ATY,Rage128")) {
0329 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
0330 if (par->cmap_adr)
0331 par->cmap_type = cmap_r128;
0332 } else if (of_node_name_prefix(dp, "ATY,RageM3pA") ||
0333 of_node_name_prefix(dp, "ATY,RageM3p12A")) {
0334 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
0335 if (par->cmap_adr)
0336 par->cmap_type = cmap_M3A;
0337 } else if (of_node_name_prefix(dp, "ATY,RageM3pB")) {
0338 par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
0339 if (par->cmap_adr)
0340 par->cmap_type = cmap_M3B;
0341 } else if (of_node_name_prefix(dp, "ATY,Rage6")) {
0342 par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
0343 if (par->cmap_adr)
0344 par->cmap_type = cmap_radeon;
0345 } else if (of_node_name_prefix(dp, "ATY,")) {
0346 unsigned long base = address & 0xff000000UL;
0347 par->cmap_adr =
0348 ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
0349 par->cmap_data = par->cmap_adr + 1;
0350 par->cmap_type = cmap_simple;
0351 } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
0352 of_device_is_compatible(dp, "pci1014,21c"))) {
0353 par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
0354 if (par->cmap_adr)
0355 par->cmap_type = cmap_gxt2000;
0356 } else if (of_node_name_prefix(dp, "vga,Display-")) {
0357
0358 struct device_node *pciparent = of_get_parent(dp);
0359 const u32 *vid, *did;
0360 vid = of_get_property(pciparent, "vendor-id", NULL);
0361 did = of_get_property(pciparent, "device-id", NULL);
0362
0363 if (vid && did && *vid == 0x1002 &&
0364 ((*did >= 0x7100 && *did < 0x7800) ||
0365 (*did >= 0x9400))) {
0366 par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000);
0367 if (par->cmap_adr)
0368 par->cmap_type = cmap_avivo;
0369 }
0370 of_node_put(pciparent);
0371 } else if (dp && of_device_is_compatible(dp, "qemu,std-vga")) {
0372 #ifdef __BIG_ENDIAN
0373 const __be32 io_of_addr[3] = { 0x01000000, 0x0, 0x0 };
0374 #else
0375 const __be32 io_of_addr[3] = { 0x00000001, 0x0, 0x0 };
0376 #endif
0377 u64 io_addr = of_translate_address(dp, io_of_addr);
0378 if (io_addr != OF_BAD_ADDR) {
0379 par->cmap_adr = ioremap(io_addr + 0x3c8, 2);
0380 if (par->cmap_adr) {
0381 par->cmap_type = cmap_simple;
0382 par->cmap_data = par->cmap_adr + 1;
0383 }
0384 }
0385 }
0386 info->fix.visual = (par->cmap_type != cmap_unknown) ?
0387 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
0388 }
0389
0390 static void offb_init_fb(struct platform_device *parent, const char *name,
0391 int width, int height, int depth,
0392 int pitch, unsigned long address,
0393 int foreign_endian, struct device_node *dp)
0394 {
0395 unsigned long res_size = pitch * height;
0396 struct offb_par *par = &default_par;
0397 unsigned long res_start = address;
0398 struct fb_fix_screeninfo *fix;
0399 struct fb_var_screeninfo *var;
0400 struct fb_info *info;
0401
0402 if (!request_mem_region(res_start, res_size, "offb"))
0403 return;
0404
0405 printk(KERN_INFO
0406 "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
0407 width, height, name, address, depth, pitch);
0408 if (depth != 8 && depth != 15 && depth != 16 && depth != 32) {
0409 printk(KERN_ERR "%pOF: can't use depth = %d\n", dp, depth);
0410 release_mem_region(res_start, res_size);
0411 return;
0412 }
0413
0414 info = framebuffer_alloc(sizeof(u32) * 16, &parent->dev);
0415
0416 if (!info) {
0417 release_mem_region(res_start, res_size);
0418 return;
0419 }
0420 platform_set_drvdata(parent, info);
0421
0422 fix = &info->fix;
0423 var = &info->var;
0424 info->par = par;
0425
0426 if (name) {
0427 strcpy(fix->id, "OFfb ");
0428 strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
0429 fix->id[sizeof(fix->id) - 1] = '\0';
0430 } else
0431 snprintf(fix->id, sizeof(fix->id), "OFfb %pOFn", dp);
0432
0433
0434 var->xres = var->xres_virtual = width;
0435 var->yres = var->yres_virtual = height;
0436 fix->line_length = pitch;
0437
0438 fix->smem_start = address;
0439 fix->smem_len = pitch * height;
0440 fix->type = FB_TYPE_PACKED_PIXELS;
0441 fix->type_aux = 0;
0442
0443 par->cmap_type = cmap_unknown;
0444 if (depth == 8)
0445 offb_init_palette_hacks(info, dp, address);
0446 else
0447 fix->visual = FB_VISUAL_TRUECOLOR;
0448
0449 var->xoffset = var->yoffset = 0;
0450 switch (depth) {
0451 case 8:
0452 var->bits_per_pixel = 8;
0453 var->red.offset = 0;
0454 var->red.length = 8;
0455 var->green.offset = 0;
0456 var->green.length = 8;
0457 var->blue.offset = 0;
0458 var->blue.length = 8;
0459 var->transp.offset = 0;
0460 var->transp.length = 0;
0461 break;
0462 case 15:
0463 var->bits_per_pixel = 16;
0464 var->red.offset = 10;
0465 var->red.length = 5;
0466 var->green.offset = 5;
0467 var->green.length = 5;
0468 var->blue.offset = 0;
0469 var->blue.length = 5;
0470 var->transp.offset = 0;
0471 var->transp.length = 0;
0472 break;
0473 case 16:
0474 var->bits_per_pixel = 16;
0475 var->red.offset = 11;
0476 var->red.length = 5;
0477 var->green.offset = 5;
0478 var->green.length = 6;
0479 var->blue.offset = 0;
0480 var->blue.length = 5;
0481 var->transp.offset = 0;
0482 var->transp.length = 0;
0483 break;
0484 case 32:
0485 var->bits_per_pixel = 32;
0486 var->red.offset = 16;
0487 var->red.length = 8;
0488 var->green.offset = 8;
0489 var->green.length = 8;
0490 var->blue.offset = 0;
0491 var->blue.length = 8;
0492 var->transp.offset = 24;
0493 var->transp.length = 8;
0494 break;
0495 }
0496 var->red.msb_right = var->green.msb_right = var->blue.msb_right =
0497 var->transp.msb_right = 0;
0498 var->grayscale = 0;
0499 var->nonstd = 0;
0500 var->activate = 0;
0501 var->height = var->width = -1;
0502 var->pixclock = 10000;
0503 var->left_margin = var->right_margin = 16;
0504 var->upper_margin = var->lower_margin = 16;
0505 var->hsync_len = var->vsync_len = 8;
0506 var->sync = 0;
0507 var->vmode = FB_VMODE_NONINTERLACED;
0508
0509
0510 info->apertures = alloc_apertures(1);
0511 if (!info->apertures)
0512 goto out_aper;
0513 info->apertures->ranges[0].base = address;
0514 info->apertures->ranges[0].size = fix->smem_len;
0515
0516 info->fbops = &offb_ops;
0517 info->screen_base = ioremap(address, fix->smem_len);
0518 info->pseudo_palette = (void *) (info + 1);
0519 info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian;
0520
0521 fb_alloc_cmap(&info->cmap, 256, 0);
0522
0523 if (register_framebuffer(info) < 0)
0524 goto out_err;
0525
0526 fb_info(info, "Open Firmware frame buffer device on %pOF\n", dp);
0527 return;
0528
0529 out_err:
0530 fb_dealloc_cmap(&info->cmap);
0531 iounmap(info->screen_base);
0532 out_aper:
0533 iounmap(par->cmap_adr);
0534 par->cmap_adr = NULL;
0535 framebuffer_release(info);
0536 release_mem_region(res_start, res_size);
0537 }
0538
0539
0540 static void offb_init_nodriver(struct platform_device *parent, struct device_node *dp,
0541 int no_real_node)
0542 {
0543 unsigned int len;
0544 int i, width = 640, height = 480, depth = 8, pitch = 640;
0545 unsigned int flags, rsize, addr_prop = 0;
0546 unsigned long max_size = 0;
0547 u64 rstart, address = OF_BAD_ADDR;
0548 const __be32 *pp, *addrp, *up;
0549 u64 asize;
0550 int foreign_endian = 0;
0551
0552 #ifdef __BIG_ENDIAN
0553 if (of_get_property(dp, "little-endian", NULL))
0554 foreign_endian = FBINFO_FOREIGN_ENDIAN;
0555 #else
0556 if (of_get_property(dp, "big-endian", NULL))
0557 foreign_endian = FBINFO_FOREIGN_ENDIAN;
0558 #endif
0559
0560 pp = of_get_property(dp, "linux,bootx-depth", &len);
0561 if (pp == NULL)
0562 pp = of_get_property(dp, "depth", &len);
0563 if (pp && len == sizeof(u32))
0564 depth = be32_to_cpup(pp);
0565
0566 pp = of_get_property(dp, "linux,bootx-width", &len);
0567 if (pp == NULL)
0568 pp = of_get_property(dp, "width", &len);
0569 if (pp && len == sizeof(u32))
0570 width = be32_to_cpup(pp);
0571
0572 pp = of_get_property(dp, "linux,bootx-height", &len);
0573 if (pp == NULL)
0574 pp = of_get_property(dp, "height", &len);
0575 if (pp && len == sizeof(u32))
0576 height = be32_to_cpup(pp);
0577
0578 pp = of_get_property(dp, "linux,bootx-linebytes", &len);
0579 if (pp == NULL)
0580 pp = of_get_property(dp, "linebytes", &len);
0581 if (pp && len == sizeof(u32) && (*pp != 0xffffffffu))
0582 pitch = be32_to_cpup(pp);
0583 else
0584 pitch = width * ((depth + 7) / 8);
0585
0586 rsize = (unsigned long)pitch * (unsigned long)height;
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598 up = of_get_property(dp, "linux,bootx-addr", &len);
0599 if (up == NULL)
0600 up = of_get_property(dp, "address", &len);
0601 if (up && len == sizeof(u32))
0602 addr_prop = *up;
0603
0604
0605 if (no_real_node)
0606 goto skip_addr;
0607
0608 for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
0609 != NULL; i++) {
0610 int match_addrp = 0;
0611
0612 if (!(flags & IORESOURCE_MEM))
0613 continue;
0614 if (asize < rsize)
0615 continue;
0616 rstart = of_translate_address(dp, addrp);
0617 if (rstart == OF_BAD_ADDR)
0618 continue;
0619 if (addr_prop && (rstart <= addr_prop) &&
0620 ((rstart + asize) >= (addr_prop + rsize)))
0621 match_addrp = 1;
0622 if (match_addrp) {
0623 address = addr_prop;
0624 break;
0625 }
0626 if (rsize > max_size) {
0627 max_size = rsize;
0628 address = OF_BAD_ADDR;
0629 }
0630
0631 if (address == OF_BAD_ADDR)
0632 address = rstart;
0633 }
0634 skip_addr:
0635 if (address == OF_BAD_ADDR && addr_prop)
0636 address = (u64)addr_prop;
0637 if (address != OF_BAD_ADDR) {
0638 #ifdef CONFIG_PCI
0639 const __be32 *vidp, *didp;
0640 u32 vid, did;
0641 struct pci_dev *pdev;
0642
0643 vidp = of_get_property(dp, "vendor-id", NULL);
0644 didp = of_get_property(dp, "device-id", NULL);
0645 if (vidp && didp) {
0646 vid = be32_to_cpup(vidp);
0647 did = be32_to_cpup(didp);
0648 pdev = pci_get_device(vid, did, NULL);
0649 if (!pdev || pci_enable_device(pdev))
0650 return;
0651 }
0652 #endif
0653
0654 if (of_node_name_eq(dp, "valkyrie"))
0655 address += 0x1000;
0656 offb_init_fb(parent, no_real_node ? "bootx" : NULL,
0657 width, height, depth, pitch, address,
0658 foreign_endian, no_real_node ? NULL : dp);
0659 }
0660 }
0661
0662 static int offb_remove(struct platform_device *pdev)
0663 {
0664 struct fb_info *info = platform_get_drvdata(pdev);
0665
0666 if (info)
0667 unregister_framebuffer(info);
0668
0669 return 0;
0670 }
0671
0672 static int offb_probe_bootx_noscreen(struct platform_device *pdev)
0673 {
0674 offb_init_nodriver(pdev, of_chosen, 1);
0675
0676 return 0;
0677 }
0678
0679 static struct platform_driver offb_driver_bootx_noscreen = {
0680 .driver = {
0681 .name = "bootx-noscreen",
0682 },
0683 .probe = offb_probe_bootx_noscreen,
0684 .remove = offb_remove,
0685 };
0686
0687 static int offb_probe_display(struct platform_device *pdev)
0688 {
0689 offb_init_nodriver(pdev, pdev->dev.of_node, 0);
0690
0691 return 0;
0692 }
0693
0694 static const struct of_device_id offb_of_match_display[] = {
0695 { .compatible = "display", },
0696 { },
0697 };
0698 MODULE_DEVICE_TABLE(of, offb_of_match_display);
0699
0700 static struct platform_driver offb_driver_display = {
0701 .driver = {
0702 .name = "of-display",
0703 .of_match_table = offb_of_match_display,
0704 },
0705 .probe = offb_probe_display,
0706 .remove = offb_remove,
0707 };
0708
0709 static int __init offb_init(void)
0710 {
0711 if (fb_get_options("offb", NULL))
0712 return -ENODEV;
0713
0714 platform_driver_register(&offb_driver_bootx_noscreen);
0715 platform_driver_register(&offb_driver_display);
0716
0717 return 0;
0718 }
0719 module_init(offb_init);
0720
0721 static void __exit offb_exit(void)
0722 {
0723 platform_driver_unregister(&offb_driver_display);
0724 platform_driver_unregister(&offb_driver_bootx_noscreen);
0725 }
0726 module_exit(offb_exit);
0727
0728 MODULE_LICENSE("GPL");