📄 controlfb.c
字号:
*//* A blank_mode of 1+VESA_NO_BLANKING or 1+VESA_POWERDOWN act alike... */ struct fb_info_control *p = (struct fb_info_control *) info; int ctrl; if(blank_mode == 1+VESA_NO_BLANKING) blank_mode = 1+VESA_POWERDOWN; ctrl = ld_le32(&p->control_regs->ctrl.r) | 0x33; if (blank_mode) --blank_mode; if (blank_mode & VESA_VSYNC_SUSPEND) ctrl &= ~3; if (blank_mode & VESA_HSYNC_SUSPEND) ctrl &= ~0x30; out_le32(&p->control_regs->ctrl.r, ctrl);/* TODO: Figure out how the heck to powerdown this thing! */ return;}static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; if (regno > 255) return 1; *red = (p->palette[regno].red<<8) | p->palette[regno].red; *green = (p->palette[regno].green<<8) | p->palette[regno].green; *blue = (p->palette[regno].blue<<8) | p->palette[regno].blue; *transp = 0; return 0;}static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; u_int i; __u8 r, g, b; if (regno > 255) return 1; r = red >> 8; g = green >> 8; b = blue >> 8; p->palette[regno].red = r; p->palette[regno].green = g; p->palette[regno].blue = b; out_8(&p->cmap_regs->addr, regno); /* tell clut what addr to fill */ out_8(&p->cmap_regs->lut, r); /* send one color channel at */ out_8(&p->cmap_regs->lut, g); /* a time... */ out_8(&p->cmap_regs->lut, b); if (regno < 16) switch (p->par.cmode) {#ifdef FBCON_HAS_CFB16 case CMODE_16: p->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno; break;#endif#ifdef FBCON_HAS_CFB32 case CMODE_32: i = (regno << 8) | regno; p->fbcon_cmap.cfb32[regno] = (i << 16) | i; break;#endif } return 0;}static void do_install_cmap(int con, struct fb_info *info){ if (con != currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, controlfb_setcolreg, info); else { int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg, info); }}static inline int control_vram_reqd(int video_mode, int color_mode){ return (control_reg_init[video_mode-1]->vres * control_reg_init[video_mode-1]->hres << color_mode) + control_reg_init[video_mode-1]->offset[color_mode];}static void set_control_clock(unsigned char *params){ struct adb_request req; int i;#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); while (!req.complete) cuda_poll(); }#endif }static void __init init_control(struct fb_info_control *p){ struct fb_par_control parstruct; struct fb_par_control *par = &parstruct; struct fb_var_screeninfo var; p->sense = read_control_sense(p); printk(KERN_INFO "Monitor sense value = 0x%x, ", p->sense); /* Try to pick a video mode out of NVRAM if we have one. */ if (default_vmode == VMODE_NVRAM) { par->vmode = nvram_read_byte(NV_VMODE); if(par->vmode <= 0 || par->vmode > VMODE_MAX || !control_reg_init[par->vmode - 1]) par->vmode = VMODE_CHOOSE; if(par->vmode == VMODE_CHOOSE) par->vmode = mac_map_monitor_sense(p->sense); if(!control_reg_init[par->vmode - 1]) par->vmode = VMODE_640_480_60; } else par->vmode=default_vmode; if (default_cmode == CMODE_NVRAM){ par->cmode = nvram_read_byte(NV_CMODE); if(par->cmode < CMODE_8 || par->cmode > CMODE_32) par->cmode = CMODE_8;} else par->cmode=default_cmode; /* * Reduce the pixel size if we don't have enough VRAM. */ while(par->cmode > CMODE_8 && control_vram_reqd(par->vmode, par->cmode) > p->total_vram) par->cmode--; printk("using video mode %d and color mode %d.\n", par->vmode, par->cmode); par->vxres = par->xres = control_reg_init[par->vmode - 1]->hres; par->yres = control_reg_init[par->vmode - 1]->vres; par->vyres = p->total_vram / (par->vxres << par->cmode); par->xoffset = par->yoffset = 0; control_init_info(&p->info, p); par_set = 1; /* Debug */ control_par_to_var(par, &var); var.activate = FB_ACTIVATE_NOW; control_set_var(&var, -1, &p->info); p->info.flags = FBINFO_FLAG_DEFAULT; if (register_framebuffer(&p->info) < 0) { kfree(p); return; } printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); }#define STORE_D2(a,d) \ out_8(&p->cmap_regs->addr, (a)); \ out_8(&p->cmap_regs->d2, (d))/* Now how about actually saying, Make it so! *//* Some things in here probably don't need to be done each time. */static void control_set_hardware(struct fb_info_control *p, struct fb_par_control *par){ struct control_regvals *init; volatile struct preg *rp; int flags, ctrl, i; int vmode, cmode; if(PAR_EQUAL(&p->par, par)) return; p->par = *par; vmode = p->par.vmode; cmode = p->par.cmode; init = control_reg_init[vmode - 1]; if (control_vram_reqd(vmode, cmode) > 0x200000) flags = 0x51; else if (p->control_use_bank2) flags = 0x39; else flags = 0x31; if (vmode >= VMODE_1280_960_75 && cmode >= CMODE_16) ctrl = 0x7f; else ctrl = 0x3b; /* Initialize display timing registers */ out_le32(&p->control_regs->ctrl.r, 0x43b); set_control_clock(init->clock_params); STORE_D2(0x20, init->radacal_ctrl[cmode]); STORE_D2(0x21, p->control_use_bank2 ? 0 : 1); STORE_D2(0x10, 0); STORE_D2(0x11, 0); rp = &p->control_regs->vswin; for (i = 0; i < 16; ++i, ++rp) out_le32(&rp->r, init->regs[i]); out_le32(&p->control_regs->pitch.r, par->vxres << cmode); out_le32(&p->control_regs->mode.r, init->mode[cmode]); out_le32(&p->control_regs->flags.r, flags); out_le32(&p->control_regs->start_addr.r, par->yoffset * (par->vxres << cmode)); out_le32(&p->control_regs->reg18.r, 0x1e5); out_le32(&p->control_regs->reg19.r, 0); for (i = 0; i < 16; ++i) { controlfb_setcolreg(color_table[i], default_red[i]<<8, default_grn[i]<<8, default_blu[i]<<8, 0, (struct fb_info *)p); }/* Does the above need to be here each time? -- danj */ /* Turn on display */ out_le32(&p->control_regs->ctrl.r, ctrl); #ifdef CONFIG_FB_COMPAT_XPMAC /* And let the world know the truth. */ if (!console_fb_info || console_fb_info == &p->info) { display_info.height = p->par.yres; display_info.width = p->par.xres; display_info.depth = (cmode == CMODE_32) ? 32 : ((cmode == CMODE_16) ? 16 : 8); display_info.pitch = p->par.vxres << p->par.cmode; display_info.mode = vmode; strncpy(display_info.name, "control", sizeof(display_info.name)); display_info.fb_address = p->frame_buffer_phys + control_reg_init[vmode-1]->offset[cmode]; display_info.cmap_adr_address = p->cmap_regs_phys; display_info.cmap_data_address = p->cmap_regs_phys + 0x30; display_info.disp_reg_address = p->control_regs_phys; console_fb_info = &p->info; }#endif /* CONFIG_FB_COMPAT_XPMAC */}int __init control_init(void){ struct device_node *dp; dp = find_devices("control"); if (dp != 0) control_of_init(dp); return 0;}static void __init control_of_init(struct device_node *dp){ struct fb_info_control *p; unsigned long addr, size; int i, bank1, bank2; if(dp->n_addrs != 2) { printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); return; } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) return; memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ for (i = 0; i < dp->n_addrs; ++i) { addr = dp->addrs[i].address; size = dp->addrs[i].size; /* Let's assume we can request either all or nothing */ if (!request_mem_region(addr, size, "controlfb")) { kfree(p); return; } if (size >= 0x800000) { /* use the big-endian aperture (??) */ addr += 0x800000; /* map at most 8MB for the frame buffer */ p->frame_buffer_phys = addr; p->frame_buffer = __ioremap(addr, 0x800000, _PAGE_WRITETHRU); } else { p->control_regs_phys = addr; p->control_regs = ioremap(addr, size); } } p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap"); p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); /* Work out which banks of VRAM we have installed. */ /* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */ /* afyfe: observations from an 8500: * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M * - with 2M vram in bank 2, it appears only at offset 6M * - with 4M vram, it appears only as a 4M block at offset 0. */ /* We know there is something at 2M if there is something at 0M. */ out_8(&p->frame_buffer[0x200000], 0xa5); out_8(&p->frame_buffer[0x200001], 0x38); asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory" ); out_8(&p->frame_buffer[0], 0x5a); out_8(&p->frame_buffer[1], 0xc7); asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" ); bank1 = (in_8(&p->frame_buffer[0x000000]) == 0x5a) && (in_8(&p->frame_buffer[0x000001]) == 0xc7); bank2 = (in_8(&p->frame_buffer[0x200000]) == 0xa5) && (in_8(&p->frame_buffer[0x200001]) == 0x38); if(bank2 && !bank1) printk(KERN_INFO "controlfb: Found memory at 2MB but not at 0! Please contact dan@debian.org\n"); if(!bank1) { out_8(&p->frame_buffer[0x600000], 0xa5); out_8(&p->frame_buffer[0x600001], 0x38); asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" ); bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5) && (in_8(&p->frame_buffer[0x600001]) == 0x38); /* If we don't have bank 1 installed, we hope we have bank 2 :-) */ p->control_use_bank2 = 1; p->frame_buffer += 0x600000; p->frame_buffer_phys += 0x600000; } p->total_vram = (bank1 + bank2) * 0x200000; printk(KERN_INFO "controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n", bank1 ? "present" : "absent", bank2 ? "present" : "absent", 2 * (bank1 + bank2)); init_control(p);}/* * Get the monitor sense value. * Note that this can be called before calibrate_delay, * so we can't use udelay. */static int read_control_sense(struct fb_info_control *p){ int sense; out_le32(&p->control_regs->mon_sense.r, 7); /* drive all lines high */ __delay(200); out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ __delay(2000); sense = (in_le32(&p->control_regs->mon_sense.r) & 0x1c0) << 2; /* drive each sense line low in turn and collect the other 2 */ out_le32(&p->control_regs->mon_sense.r, 033); /* drive A low */ __delay(2000); sense |= (in_le32(&p->control_regs->mon_sense.r) & 0xc0) >> 2; out_le32(&p->control_regs->mon_sense.r, 055); /* drive B low */ __delay(2000); sense |= ((in_le32(&p->control_regs->mon_sense.r) & 0x100) >> 5) | ((in_le32(&p->control_regs->mon_sense.r) & 0x40) >> 4); out_le32(&p->control_regs->mon_sense.r, 066); /* drive C low */ __delay(2000); sense |= (in_le32(&p->control_regs->mon_sense.r) & 0x180) >> 7; out_le32(&p->control_regs->mon_sense.r, 077); /* turn off drivers */ return sense;}/*********************** Various translation functions ***********************/#if 1/* This routine takes a user-supplied var, and picks the best vmode/cmode from it. */static int control_var_to_par(struct fb_var_screeninfo *var, struct fb_par_control *par, const struct fb_info *fb_info){ int xres = var->xres; int yres = var->yres; int bpp = var->bits_per_pixel; struct fb_info_control *p = (struct fb_info_control *) fb_info; /* * Get the video params out of 'var'. If a value doesn't fit, round it up, * if it's too big, return -EINVAL. * * Suggestion: Round up in the following order: bits_per_pixel, xres, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * bitfields, horizontal timing, vertical timing. */ /* swiped by jonh from atyfb.c */ if (xres <= 640 && yres <= 480) par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */ else if (xres <= 640 && yres <= 870) par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */ else if (xres <= 800 && yres <= 600) par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */ else if (xres <= 832 && yres <= 624) par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */ else if (xres <= 1024 && yres <= 768) par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */ else if (xres <= 1152 && yres <= 870) par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */ else if (xres <= 1280 && yres <= 960) par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */ else if (xres <= 1280 && yres <= 1024) par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */ else { printk(KERN_ERR "Bad x/y res in var_to_par\n"); return -EINVAL; } xres = control_reg_init[par->vmode-1]->hres;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -