📄 controlfb.c
字号:
}static void controlfb_blank(int blank_mode, struct fb_info *info){ struct fb_info_control *p = (struct fb_info_control *) info; unsigned ctrl; ctrl = ld_le32(CNTRL_REG(p,ctrl)); if (blank_mode > 0) switch (blank_mode - 1) { case VESA_VSYNC_SUSPEND: ctrl &= ~3; break; case VESA_HSYNC_SUSPEND: ctrl &= ~0x30; break; case VESA_POWERDOWN: ctrl &= ~0x33; /* fall through */ case VESA_NO_BLANKING: ctrl |= 0x400; break; default: break; } else { ctrl &= ~0x400; ctrl |= 0x33; } out_le32(CNTRL_REG(p,ctrl), ctrl); return;}/* * low level cmap set/get ops */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(struct display *disp, struct fb_info *info){ if (disp->cmap.len) fb_set_cmap(&disp->cmap, 1, controlfb_setcolreg, info); else { int size = disp->var.bits_per_pixel == 16 ? 32 : 256; fb_set_cmap(fb_default_cmap(size), 1, controlfb_setcolreg, info); }}static void set_control_clock(unsigned char *params){#ifdef CONFIG_ADB_CUDA struct adb_request req; int i; 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 }/* * finish off the driver initialization and register */static int __init init_control(struct fb_info_control *p){ int full, sense, vmode, cmode, vyres; struct fb_var_screeninfo var; printk(KERN_INFO "controlfb: "); full = p->total_vram == 0x400000;#ifdef CONFIG_NVRAM /* Try to pick a video mode out of NVRAM if we have one. */ if (default_cmode == CMODE_NVRAM) cmode = nvram_read_byte(NV_CMODE); if (default_vmode == VMODE_NVRAM) { vmode = nvram_read_byte(NV_VMODE); if (vmode < 1 || vmode > VMODE_MAX || control_mac_modes[vmode - 1].m[full] < cmode) { sense = read_control_sense(p); printk("Monitor sense value = 0x%x, ", sense); vmode = mac_map_monitor_sense(sense); if (control_mac_modes[vmode - 1].m[full] < cmode) vmode = VMODE_640_480_60; } }#endif /* If we didn't get something from NVRAM, pick a * sane default. */ if (vmode <= 0 || vmode > VMODE_MAX) vmode = VMODE_640_480_67; if (cmode < CMODE_8 || cmode > CMODE_32) cmode = CMODE_8; if (mac_vmode_to_var(vmode, cmode, &var) < 0) { /* This shouldn't happen! */ printk("mac_vmode_to_var(%d, %d,) failed\n", vmode, cmode);try_again: vmode = VMODE_640_480_60; cmode = CMODE_8; if (mac_vmode_to_var(vmode, cmode, &var) < 0) { printk(KERN_ERR "controlfb: mac_vmode_to_var() failed\n"); return -ENXIO; } printk(KERN_INFO "controlfb: "); } printk("using video mode %d and color mode %d.\n", vmode, cmode); vyres = (p->total_vram - CTRLFB_OFF) / (var.xres << cmode); if (vyres > var.yres) var.yres_virtual = vyres; control_init_info(&p->info, p); currcon = -1; var.activate = FB_ACTIVATE_NOW; if (control_set_var(&var, -1, &p->info) < 0) { if (vmode != VMODE_640_480_60 || cmode != CMODE_8) goto try_again; printk(KERN_ERR "controlfb: initilization failed\n"); return -ENXIO; } p->info.flags = FBINFO_FLAG_DEFAULT; if (register_framebuffer(&p->info) < 0) return -ENXIO; printk(KERN_INFO "fb%d: control display adapter\n", GET_FB_IDX(p->info.node)); return 0;}#define RADACAL_WRITE(a,d) \ out_8(&p->cmap_regs->addr, (a)); \ out_8(&p->cmap_regs->dat, (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 *r; volatile struct preg *rp; int i, cmode; if (PAR_EQUAL(&p->par, par)) { /* * check if only xoffset or yoffset differs. * this prevents flickers in typical VT switch case. */ if (p->par.xoffset != par->xoffset || p->par.yoffset != par->yoffset) set_screen_start(par->xoffset, par->yoffset, p); return; } p->par = *par; cmode = p->par.cmode; r = &par->regvals; /* Turn off display */ out_le32(CNTRL_REG(p,ctrl), 0x400 | par->ctrl); set_control_clock(r->clock_params); RADACAL_WRITE(0x20, r->radacal_ctrl); RADACAL_WRITE(0x21, p->control_use_bank2 ? 0 : 1); RADACAL_WRITE(0x10, 0); RADACAL_WRITE(0x11, 0); rp = &p->control_regs->vswin; for (i = 0; i < 16; ++i, ++rp) out_le32(&rp->r, r->regs[i]); out_le32(CNTRL_REG(p,pitch), par->pitch); out_le32(CNTRL_REG(p,mode), r->mode); out_le32(CNTRL_REG(p,vram_attr), p->vram_attr); out_le32(CNTRL_REG(p,start_addr), par->yoffset * par->pitch + (par->xoffset << cmode)); out_le32(CNTRL_REG(p,rfrcnt), 0x1e5); out_le32(CNTRL_REG(p,intr_ena), 0); /* Turn on display */ out_le32(CNTRL_REG(p,ctrl), par->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.pitch; display_info.mode = p->par.vmode; strncpy(display_info.name, "control", sizeof(display_info.name)); display_info.fb_address = p->frame_buffer_phys + CTRLFB_OFF; 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 */#ifdef CONFIG_BOOTX_TEXT btext_update_display(p->frame_buffer_phys + CTRLFB_OFF, p->par.xres, p->par.yres, (cmode == CMODE_32? 32: cmode == CMODE_16? 16: 8), p->par.pitch);#endif /* CONFIG_BOOTX_TEXT */}/* * Called from fbmem.c for probing & intializing */int __init control_init(void){ struct device_node *dp; dp = find_devices("control"); if (dp != 0 && !control_of_init(dp)) return 0; return -ENXIO;}/* Work out which banks of VRAM we have installed. *//* danj: I guess the card just ignores writes to nonexistant VRAM... */static void __init find_vram_size(struct fb_info_control *p){ int bank1, bank2; /* * Set VRAM in 2MB (bank 1) mode * VRAM Bank 2 will be accessible through offset 0x600000 if present * and VRAM Bank 1 will not respond at that offset even if present */ out_le32(CNTRL_REG(p,vram_attr), 0x31); out_8(&p->frame_buffer[0x600000], 0xb3); out_8(&p->frame_buffer[0x600001], 0x71); asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" ); mb(); asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" ); mb(); bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xb3) && (in_8(&p->frame_buffer[0x600001]) == 0x71); /* * Set VRAM in 2MB (bank 2) mode * VRAM Bank 1 will be accessible through offset 0x000000 if present * and VRAM Bank 2 will not respond at that offset even if present */ out_le32(CNTRL_REG(p,vram_attr), 0x39); out_8(&p->frame_buffer[0], 0x5a); out_8(&p->frame_buffer[1], 0xc7); asm volatile("eieio; dcbf 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" ); mb(); asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" ); mb(); bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) && (in_8(&p->frame_buffer[1]) == 0xc7); if (bank2) { if (!bank1) { /* * vram bank 2 only */ p->control_use_bank2 = 1; p->vram_attr = 0x39; p->frame_buffer += 0x600000; p->frame_buffer_phys += 0x600000; } else { /* * 4 MB vram */ p->vram_attr = 0x51; } } else { /* * vram bank 1 only */ p->vram_attr = 0x31; } p->total_vram = (bank1 + bank2) * 0x200000; printk(KERN_INFO "controlfb: VRAM Total = %dMB " "(%dMB @ bank 1, %dMB @ bank 2)\n", (bank1 + bank2) << 1, bank1 << 1, bank2 << 1);}/* * find "control" and initialize */static int __init control_of_init(struct device_node *dp){ struct fb_info_control *p; unsigned long addr; int i; if (control_fb) { printk(KERN_ERR "controlfb: only one control is supported\n"); return -ENXIO; } if(dp->n_addrs != 2) { printk(KERN_ERR "expecting 2 address for control (got %d)", dp->n_addrs); return -ENXIO; } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (p == 0) return -ENXIO; control_fb = p; /* save it for cleanups */ memset(p, 0, sizeof(*p)); /* Map in frame buffer and registers */ for (i = 0; i < dp->n_addrs; ++i) { addr = dp->addrs[i].address; if (dp->addrs[i].size >= 0x800000) { p->fb_orig_base = addr; p->fb_orig_size = dp->addrs[i].size; /* use the big-endian aperture (??) */ p->frame_buffer_phys = addr + 0x800000; } else { p->control_regs_phys = addr; p->control_regs_size = dp->addrs[i].size; } } if (!p->fb_orig_base || !request_mem_region(p->fb_orig_base,p->fb_orig_size,"controlfb")) { p->fb_orig_base = 0; goto error_out; } /* map at most 8MB for the frame buffer */ p->frame_buffer = __ioremap(p->frame_buffer_phys, 0x800000, _PAGE_WRITETHRU); if (!p->control_regs_phys || !request_mem_region(p->control_regs_phys, p->control_regs_size, "controlfb regs")) { p->control_regs_phys = 0; goto error_out; } p->control_regs = ioremap(p->control_regs_phys, p->control_regs_size); p->cmap_regs_phys = 0xf301b000; /* XXX not in prom? */ if (!request_mem_region(p->cmap_regs_phys, 0x1000, "controlfb cmap")) { p->cmap_regs_phys = 0; goto error_out; } p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000); if (!p->cmap_regs || !p->control_regs || !p->frame_buffer) goto error_out; find_vram_size(p); if (!p->total_vram) goto error_out; if (init_control(p) < 0) goto error_out; return 0;error_out: control_cleanup(); return -ENXIO;}/* * 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(CNTRL_REG(p,mon_sense), 7); /* drive all lines high */ __delay(200); out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ __delay(2000); sense = (in_le32(CNTRL_REG(p,mon_sense)) & 0x1c0) << 2; /* drive each sense line low in turn and collect the other 2 */ out_le32(CNTRL_REG(p,mon_sense), 033); /* drive A low */ __delay(2000); sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0xc0) >> 2; out_le32(CNTRL_REG(p,mon_sense), 055); /* drive B low */ __delay(2000); sense |= ((in_le32(CNTRL_REG(p,mon_sense)) & 0x100) >> 5) | ((in_le32(CNTRL_REG(p,mon_sense)) & 0x40) >> 4); out_le32(CNTRL_REG(p,mon_sense), 066); /* drive C low */ __delay(2000); sense |= (in_le32(CNTRL_REG(p,mon_sense)) & 0x180) >> 7; out_le32(CNTRL_REG(p,mon_sense), 077); /* turn off drivers */ return sense;}/********************** Various translation functions **********************/#define CONTROL_PIXCLOCK_BASE 256016#define CONTROL_PIXCLOCK_MIN 5000 /* ~ 200 MHz dot clock *//* * calculate the clock paramaters to be sent to CUDA according to given * pixclock in pico second. */static int calc_clock_params(unsigned long clk, unsigned char *param)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -