0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h>
0043 #include <linux/kernel.h>
0044 #include <linux/errno.h>
0045 #include <linux/string.h>
0046 #include <linux/mm.h>
0047 #include <linux/slab.h>
0048 #include <linux/vmalloc.h>
0049 #include <linux/delay.h>
0050 #include <linux/interrupt.h>
0051 #include <linux/fb.h>
0052 #include <linux/selection.h>
0053 #include <linux/init.h>
0054 #include <linux/nvram.h>
0055 #include <linux/adb.h>
0056 #include <linux/cuda.h>
0057 #include <linux/of_address.h>
0058 #ifdef CONFIG_MAC
0059 #include <asm/macintosh.h>
0060 #endif
0061
0062 #include "macmodes.h"
0063 #include "valkyriefb.h"
0064
0065 static int default_vmode = VMODE_NVRAM;
0066 static int default_cmode = CMODE_NVRAM;
0067
0068 struct fb_par_valkyrie {
0069 int vmode, cmode;
0070 int xres, yres;
0071 int vxres, vyres;
0072 struct valkyrie_regvals *init;
0073 };
0074
0075 struct fb_info_valkyrie {
0076 struct fb_info info;
0077 struct fb_par_valkyrie par;
0078 struct cmap_regs __iomem *cmap_regs;
0079 unsigned long cmap_regs_phys;
0080
0081 struct valkyrie_regs __iomem *valkyrie_regs;
0082 unsigned long valkyrie_regs_phys;
0083
0084 __u8 __iomem *frame_buffer;
0085 unsigned long frame_buffer_phys;
0086
0087 int sense;
0088 unsigned long total_vram;
0089
0090 u32 pseudo_palette[16];
0091 };
0092
0093 static int valkyriefb_setup(char*);
0094
0095 static int valkyriefb_check_var(struct fb_var_screeninfo *var,
0096 struct fb_info *info);
0097 static int valkyriefb_set_par(struct fb_info *info);
0098 static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0099 u_int transp, struct fb_info *info);
0100 static int valkyriefb_blank(int blank_mode, struct fb_info *info);
0101
0102 static int read_valkyrie_sense(struct fb_info_valkyrie *p);
0103 static void set_valkyrie_clock(unsigned char *params);
0104 static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
0105 struct fb_par_valkyrie *par, const struct fb_info *fb_info);
0106
0107 static int valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p);
0108 static void valkyrie_par_to_fix(struct fb_par_valkyrie *par, struct fb_fix_screeninfo *fix);
0109 static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p);
0110
0111 static const struct fb_ops valkyriefb_ops = {
0112 .owner = THIS_MODULE,
0113 .fb_check_var = valkyriefb_check_var,
0114 .fb_set_par = valkyriefb_set_par,
0115 .fb_setcolreg = valkyriefb_setcolreg,
0116 .fb_blank = valkyriefb_blank,
0117 .fb_fillrect = cfb_fillrect,
0118 .fb_copyarea = cfb_copyarea,
0119 .fb_imageblit = cfb_imageblit,
0120 };
0121
0122
0123 static int valkyriefb_set_par(struct fb_info *info)
0124 {
0125 struct fb_info_valkyrie *p =
0126 container_of(info, struct fb_info_valkyrie, info);
0127 volatile struct valkyrie_regs __iomem *valkyrie_regs = p->valkyrie_regs;
0128 struct fb_par_valkyrie *par = info->par;
0129 struct valkyrie_regvals *init;
0130 int err;
0131
0132 if ((err = valkyrie_var_to_par(&info->var, par, info)))
0133 return err;
0134
0135 valkyrie_par_to_fix(par, &info->fix);
0136
0137
0138 out_8(&valkyrie_regs->status.r, 0);
0139 udelay(100);
0140
0141
0142 init = par->init;
0143 out_8(&valkyrie_regs->mode.r, init->mode | 0x80);
0144 out_8(&valkyrie_regs->depth.r, par->cmode + 3);
0145 set_valkyrie_clock(init->clock_params);
0146 udelay(100);
0147
0148
0149 out_8(&valkyrie_regs->mode.r, init->mode);
0150
0151 return 0;
0152 }
0153
0154 static inline int valkyrie_par_to_var(struct fb_par_valkyrie *par,
0155 struct fb_var_screeninfo *var)
0156 {
0157 return mac_vmode_to_var(par->vmode, par->cmode, var);
0158 }
0159
0160 static int
0161 valkyriefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0162 {
0163 int err;
0164 struct fb_par_valkyrie par;
0165
0166 if ((err = valkyrie_var_to_par(var, &par, info)))
0167 return err;
0168 valkyrie_par_to_var(&par, var);
0169 return 0;
0170 }
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 static int valkyriefb_blank(int blank_mode, struct fb_info *info)
0183 {
0184 struct fb_info_valkyrie *p =
0185 container_of(info, struct fb_info_valkyrie, info);
0186 struct fb_par_valkyrie *par = info->par;
0187 struct valkyrie_regvals *init = par->init;
0188
0189 if (init == NULL)
0190 return 1;
0191
0192 switch (blank_mode) {
0193 case FB_BLANK_UNBLANK:
0194 out_8(&p->valkyrie_regs->mode.r, init->mode);
0195 break;
0196 case FB_BLANK_NORMAL:
0197 return 1;
0198 case FB_BLANK_VSYNC_SUSPEND:
0199 case FB_BLANK_HSYNC_SUSPEND:
0200
0201
0202
0203
0204
0205 out_8(&p->valkyrie_regs->mode.r, init->mode | 0x40);
0206 break;
0207 case FB_BLANK_POWERDOWN:
0208 out_8(&p->valkyrie_regs->mode.r, 0x66);
0209 break;
0210 }
0211 return 0;
0212 }
0213
0214 static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
0215 u_int transp, struct fb_info *info)
0216 {
0217 struct fb_info_valkyrie *p =
0218 container_of(info, struct fb_info_valkyrie, info);
0219 volatile struct cmap_regs __iomem *cmap_regs = p->cmap_regs;
0220 struct fb_par_valkyrie *par = info->par;
0221
0222 if (regno > 255)
0223 return 1;
0224 red >>= 8;
0225 green >>= 8;
0226 blue >>= 8;
0227
0228
0229 out_8(&p->cmap_regs->addr, regno);
0230 udelay(1);
0231
0232 out_8(&cmap_regs->lut, red);
0233 out_8(&cmap_regs->lut, green);
0234 out_8(&cmap_regs->lut, blue);
0235
0236 if (regno < 16 && par->cmode == CMODE_16)
0237 ((u32 *)info->pseudo_palette)[regno] =
0238 (regno << 10) | (regno << 5) | regno;
0239
0240 return 0;
0241 }
0242
0243 static inline int valkyrie_vram_reqd(int video_mode, int color_mode)
0244 {
0245 int pitch;
0246 struct valkyrie_regvals *init = valkyrie_reg_init[video_mode-1];
0247
0248 if ((pitch = init->pitch[color_mode]) == 0)
0249 pitch = 2 * init->pitch[0];
0250 return init->vres * pitch;
0251 }
0252
0253 static void set_valkyrie_clock(unsigned char *params)
0254 {
0255 #ifdef CONFIG_ADB_CUDA
0256 struct adb_request req;
0257 int i;
0258
0259 for (i = 0; i < 3; ++i) {
0260 cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
0261 0x50, i + 1, params[i]);
0262 while (!req.complete)
0263 cuda_poll();
0264 }
0265 #endif
0266 }
0267
0268 static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
0269 {
0270 p->sense = read_valkyrie_sense(p);
0271 printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);
0272
0273
0274 #ifdef CONFIG_PPC_PMAC
0275 if (IS_REACHABLE(CONFIG_NVRAM) && default_vmode == VMODE_NVRAM)
0276 default_vmode = nvram_read_byte(NV_VMODE);
0277 #endif
0278 if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
0279 !valkyrie_reg_init[default_vmode - 1]) {
0280 default_vmode = mac_map_monitor_sense(p->sense);
0281 if (!valkyrie_reg_init[default_vmode - 1])
0282 default_vmode = VMODE_640_480_67;
0283 }
0284
0285 #ifdef CONFIG_PPC_PMAC
0286 if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM)
0287 default_cmode = nvram_read_byte(NV_CMODE);
0288 #endif
0289
0290
0291
0292 if (default_cmode < CMODE_8 || default_cmode > CMODE_16
0293 || valkyrie_reg_init[default_vmode-1]->pitch[default_cmode] == 0
0294 || valkyrie_vram_reqd(default_vmode, default_cmode) > p->total_vram)
0295 default_cmode = CMODE_8;
0296
0297 printk(KERN_INFO "using video mode %d and color mode %d.\n",
0298 default_vmode, default_cmode);
0299 }
0300
0301 static int __init valkyriefb_init(void)
0302 {
0303 struct fb_info_valkyrie *p;
0304 unsigned long frame_buffer_phys, cmap_regs_phys;
0305 int err;
0306 char *option = NULL;
0307
0308 if (fb_get_options("valkyriefb", &option))
0309 return -ENODEV;
0310 valkyriefb_setup(option);
0311
0312 #ifdef CONFIG_MAC
0313 if (!MACH_IS_MAC)
0314 return -ENODEV;
0315 if (!(mac_bi_data.id == MAC_MODEL_Q630
0316
0317 || mac_bi_data.id == MAC_MODEL_P588))
0318 return -ENODEV;
0319
0320
0321 frame_buffer_phys = 0xf9000000;
0322 cmap_regs_phys = 0x50f24000;
0323 #else
0324 {
0325 struct device_node *dp;
0326 struct resource r;
0327
0328 dp = of_find_node_by_name(NULL, "valkyrie");
0329 if (!dp)
0330 return 0;
0331
0332 if (of_address_to_resource(dp, 0, &r)) {
0333 printk(KERN_ERR "can't find address for valkyrie\n");
0334 return 0;
0335 }
0336
0337 frame_buffer_phys = r.start;
0338 cmap_regs_phys = r.start + 0x304000;
0339 }
0340 #endif
0341
0342 p = kzalloc(sizeof(*p), GFP_ATOMIC);
0343 if (!p)
0344 return -ENOMEM;
0345
0346
0347 if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
0348 kfree(p);
0349 return 0;
0350 }
0351 p->total_vram = 0x100000;
0352 p->frame_buffer_phys = frame_buffer_phys;
0353 #ifdef CONFIG_MAC
0354 p->frame_buffer = ioremap(frame_buffer_phys, p->total_vram);
0355 #else
0356 p->frame_buffer = ioremap_wt(frame_buffer_phys, p->total_vram);
0357 #endif
0358 p->cmap_regs_phys = cmap_regs_phys;
0359 p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
0360 p->valkyrie_regs_phys = cmap_regs_phys+0x6000;
0361 p->valkyrie_regs = ioremap(p->valkyrie_regs_phys, 0x1000);
0362 err = -ENOMEM;
0363 if (p->frame_buffer == NULL || p->cmap_regs == NULL
0364 || p->valkyrie_regs == NULL) {
0365 printk(KERN_ERR "valkyriefb: couldn't map resources\n");
0366 goto out_free;
0367 }
0368
0369 valkyrie_choose_mode(p);
0370 mac_vmode_to_var(default_vmode, default_cmode, &p->info.var);
0371 err = valkyrie_init_info(&p->info, p);
0372 if (err < 0)
0373 goto out_free;
0374 valkyrie_init_fix(&p->info.fix, p);
0375 if (valkyriefb_set_par(&p->info))
0376
0377 printk(KERN_ERR "valkyriefb: can't set default video mode\n");
0378
0379 if ((err = register_framebuffer(&p->info)) != 0)
0380 goto out_cmap_free;
0381
0382 fb_info(&p->info, "valkyrie frame buffer device\n");
0383 return 0;
0384
0385 out_cmap_free:
0386 fb_dealloc_cmap(&p->info.cmap);
0387 out_free:
0388 if (p->frame_buffer)
0389 iounmap(p->frame_buffer);
0390 if (p->cmap_regs)
0391 iounmap(p->cmap_regs);
0392 if (p->valkyrie_regs)
0393 iounmap(p->valkyrie_regs);
0394 kfree(p);
0395 return err;
0396 }
0397
0398
0399
0400
0401 static int read_valkyrie_sense(struct fb_info_valkyrie *p)
0402 {
0403 int sense, in;
0404
0405 out_8(&p->valkyrie_regs->msense.r, 0);
0406 __delay(20000);
0407 sense = ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x70) << 4;
0408
0409 out_8(&p->valkyrie_regs->msense.r, 4);
0410 __delay(20000);
0411 sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x30);
0412 out_8(&p->valkyrie_regs->msense.r, 2);
0413 __delay(20000);
0414 sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x40) >> 3;
0415 sense |= (in & 0x10) >> 2;
0416 out_8(&p->valkyrie_regs->msense.r, 1);
0417 __delay(20000);
0418 sense |= ((in = in_8(&p->valkyrie_regs->msense.r)) & 0x60) >> 5;
0419
0420 out_8(&p->valkyrie_regs->msense.r, 7);
0421
0422 return sense;
0423 }
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451 static int valkyrie_var_to_par(struct fb_var_screeninfo *var,
0452 struct fb_par_valkyrie *par, const struct fb_info *fb_info)
0453 {
0454 int vmode, cmode;
0455 struct valkyrie_regvals *init;
0456 struct fb_info_valkyrie *p =
0457 container_of(fb_info, struct fb_info_valkyrie, info);
0458
0459 if (mac_var_to_vmode(var, &vmode, &cmode) != 0) {
0460 printk(KERN_ERR "valkyriefb: can't do %dx%dx%d.\n",
0461 var->xres, var->yres, var->bits_per_pixel);
0462 return -EINVAL;
0463 }
0464
0465
0466 if (vmode < 1 || vmode > VMODE_MAX || !valkyrie_reg_init[vmode-1]) {
0467 printk(KERN_ERR "valkyriefb: vmode %d not valid.\n", vmode);
0468 return -EINVAL;
0469 }
0470
0471 if (cmode != CMODE_8 && cmode != CMODE_16) {
0472 printk(KERN_ERR "valkyriefb: cmode %d not valid.\n", cmode);
0473 return -EINVAL;
0474 }
0475
0476 if (var->xres_virtual > var->xres || var->yres_virtual > var->yres
0477 || var->xoffset != 0 || var->yoffset != 0) {
0478 return -EINVAL;
0479 }
0480
0481 init = valkyrie_reg_init[vmode-1];
0482 if (init->pitch[cmode] == 0) {
0483 printk(KERN_ERR "valkyriefb: vmode %d does not support "
0484 "cmode %d.\n", vmode, cmode);
0485 return -EINVAL;
0486 }
0487
0488 if (valkyrie_vram_reqd(vmode, cmode) > p->total_vram) {
0489 printk(KERN_ERR "valkyriefb: not enough ram for vmode %d, "
0490 "cmode %d.\n", vmode, cmode);
0491 return -EINVAL;
0492 }
0493
0494 par->vmode = vmode;
0495 par->cmode = cmode;
0496 par->init = init;
0497 par->xres = var->xres;
0498 par->yres = var->yres;
0499 par->vxres = par->xres;
0500 par->vyres = par->yres;
0501
0502 return 0;
0503 }
0504
0505 static void valkyrie_init_fix(struct fb_fix_screeninfo *fix, struct fb_info_valkyrie *p)
0506 {
0507 memset(fix, 0, sizeof(*fix));
0508 strcpy(fix->id, "valkyrie");
0509 fix->mmio_start = p->valkyrie_regs_phys;
0510 fix->mmio_len = sizeof(struct valkyrie_regs);
0511 fix->type = FB_TYPE_PACKED_PIXELS;
0512 fix->smem_start = p->frame_buffer_phys + 0x1000;
0513 fix->smem_len = p->total_vram;
0514
0515 fix->type_aux = 0;
0516 fix->ywrapstep = 0;
0517 fix->ypanstep = 0;
0518 fix->xpanstep = 0;
0519
0520 }
0521
0522
0523 static void valkyrie_par_to_fix(struct fb_par_valkyrie *par,
0524 struct fb_fix_screeninfo *fix)
0525 {
0526 fix->smem_len = valkyrie_vram_reqd(par->vmode, par->cmode);
0527 fix->visual = (par->cmode == CMODE_8) ?
0528 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
0529 fix->line_length = par->vxres << par->cmode;
0530
0531 }
0532
0533 static int __init valkyrie_init_info(struct fb_info *info,
0534 struct fb_info_valkyrie *p)
0535 {
0536 info->fbops = &valkyriefb_ops;
0537 info->screen_base = p->frame_buffer + 0x1000;
0538 info->flags = FBINFO_DEFAULT;
0539 info->pseudo_palette = p->pseudo_palette;
0540 info->par = &p->par;
0541 return fb_alloc_cmap(&info->cmap, 256, 0);
0542 }
0543
0544
0545
0546
0547
0548 static int __init valkyriefb_setup(char *options)
0549 {
0550 char *this_opt;
0551
0552 if (!options || !*options)
0553 return 0;
0554
0555 while ((this_opt = strsep(&options, ",")) != NULL) {
0556 if (!strncmp(this_opt, "vmode:", 6)) {
0557 int vmode = simple_strtoul(this_opt+6, NULL, 0);
0558 if (vmode > 0 && vmode <= VMODE_MAX)
0559 default_vmode = vmode;
0560 }
0561 else if (!strncmp(this_opt, "cmode:", 6)) {
0562 int depth = simple_strtoul(this_opt+6, NULL, 0);
0563 switch (depth) {
0564 case 8:
0565 default_cmode = CMODE_8;
0566 break;
0567 case 15:
0568 case 16:
0569 default_cmode = CMODE_16;
0570 break;
0571 }
0572 }
0573 }
0574 return 0;
0575 }
0576
0577 module_init(valkyriefb_init);
0578 MODULE_LICENSE("GPL");