📄 aty128fb.c
字号:
aty128_set_crt_enable(par, par->crt_on); aty128_set_lcd_enable(par, par->lcd_on); } if (par->accel_flags & FB_ACCELF_TEXT) aty128_init_engine(par);#ifdef CONFIG_BOOTX_TEXT btext_update_display(info->fix.smem_start, (((par->crtc.h_total>>16) & 0xff)+1)*8, ((par->crtc.v_total>>16) & 0x7ff)+1, par->crtc.bpp, par->crtc.vxres*par->crtc.bpp/8);#endif /* CONFIG_BOOTX_TEXT */ return 0;}/* * encode/decode the User Defined Part of the Display */static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par){ int err; struct aty128_crtc crtc; struct aty128_pll pll; struct aty128_ddafifo fifo_reg; if ((err = aty128_var_to_crtc(var, &crtc, par))) return err; if ((err = aty128_var_to_pll(var->pixclock, &pll, par))) return err; if ((err = aty128_ddafifo(&fifo_reg, &pll, crtc.depth, par))) return err; par->crtc = crtc; par->pll = pll; par->fifo_reg = fifo_reg; par->accel_flags = var->accel_flags; return 0;}static int aty128_encode_var(struct fb_var_screeninfo *var, const struct aty128fb_par *par){ int err; if ((err = aty128_crtc_to_var(&par->crtc, var))) return err; if ((err = aty128_pll_to_var(&par->pll, var))) return err; var->nonstd = 0; var->activate = 0; var->height = -1; var->width = -1; var->accel_flags = par->accel_flags; return 0;} static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct aty128fb_par par; int err; par = *(struct aty128fb_par *)info->par; if ((err = aty128_decode_var(var, &par)) != 0) return err; aty128_encode_var(var, &par); return 0;}/* * Pan or Wrap the Display */static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) { struct aty128fb_par *par = fb->par; u32 xoffset, yoffset; u32 offset; u32 xres, yres; xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; xoffset = (var->xoffset +7) & ~7; yoffset = var->yoffset; if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) return -EINVAL; par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; offset = ((yoffset * par->crtc.vxres + xoffset)*(par->crtc.bpp >> 3)) & ~7; if (par->crtc.bpp == 24) offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */ aty_st_le32(CRTC_OFFSET, offset); return 0;}/* * Helper function to store a single palette register */static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, struct aty128fb_par *par){ if (par->chip_gen == rage_M3) {#if 0 /* Note: For now, on M3, we set palette on both heads, which may * be useless. Can someone with a M3 check this ? * * This code would still be useful if using the second CRTC to * do mirroring */ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); aty_st_8(PALETTE_INDEX, regno); aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);#endif aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); } aty_st_8(PALETTE_INDEX, regno); aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);}static int aty128fb_sync(struct fb_info *info){ struct aty128fb_par *par = info->par; if (par->blitter_may_be_busy) wait_for_idle(par); return 0;}#ifndef MODULEstatic int __devinit aty128fb_setup(char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "lcd:", 4)) { default_lcd_on = simple_strtoul(this_opt+4, NULL, 0); continue; } else if (!strncmp(this_opt, "crt:", 4)) { default_crt_on = simple_strtoul(this_opt+4, NULL, 0); continue; } else if (!strncmp(this_opt, "backlight:", 10)) { backlight = simple_strtoul(this_opt+10, NULL, 0); continue; }#ifdef CONFIG_MTRR if(!strncmp(this_opt, "nomtrr", 6)) { mtrr = 0; continue; }#endif#ifdef CONFIG_PPC_PMAC /* vmode and cmode deprecated */ if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) default_vmode = vmode; continue; } else if (!strncmp(this_opt, "cmode:", 6)) { unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); switch (cmode) { case 0: case 8: default_cmode = CMODE_8; break; case 15: case 16: default_cmode = CMODE_16; break; case 24: case 32: default_cmode = CMODE_32; break; } continue; }#endif /* CONFIG_PPC_PMAC */ mode_option = this_opt; } return 0;}#endif /* MODULE *//* Backlight */#ifdef CONFIG_FB_ATY128_BACKLIGHT#define MAX_LEVEL 0xFFstatic int aty128_bl_get_level_brightness(struct aty128fb_par *par, int level){ struct fb_info *info = pci_get_drvdata(par->pdev); int atylevel; /* Get and convert the value */ /* No locking of bl_curve since we read a single value */ atylevel = MAX_LEVEL - (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL); if (atylevel < 0) atylevel = 0; else if (atylevel > MAX_LEVEL) atylevel = MAX_LEVEL; return atylevel;}/* We turn off the LCD completely instead of just dimming the backlight. * This provides greater power saving and the display is useless without * backlight anyway */#define BACKLIGHT_LVDS_OFF/* That one prevents proper CRT output with LCD off */#undef BACKLIGHT_DAC_OFFstatic int aty128_bl_update_status(struct backlight_device *bd){ struct aty128fb_par *par = bl_get_data(bd); unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); int level; if (bd->props.power != FB_BLANK_UNBLANK || bd->props.fb_blank != FB_BLANK_UNBLANK || !par->lcd_on) level = 0; else level = bd->props.brightness; reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (level > 0) { reg |= LVDS_DIGION; if (!(reg & LVDS_ON)) { reg &= ~LVDS_BLON; aty_st_le32(LVDS_GEN_CNTL, reg); aty_ld_le32(LVDS_GEN_CNTL); mdelay(10); reg |= LVDS_BLON; aty_st_le32(LVDS_GEN_CNTL, reg); } reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);#ifdef BACKLIGHT_LVDS_OFF reg |= LVDS_ON | LVDS_EN; reg &= ~LVDS_DISPLAY_DIS;#endif aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef BACKLIGHT_DAC_OFF aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));#endif } else { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);#ifdef BACKLIGHT_LVDS_OFF reg |= LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); aty_ld_le32(LVDS_GEN_CNTL); udelay(10); reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);#endif aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef BACKLIGHT_DAC_OFF aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);#endif } return 0;}static int aty128_bl_get_brightness(struct backlight_device *bd){ return bd->props.brightness;}static struct backlight_ops aty128_bl_data = { .get_brightness = aty128_bl_get_brightness, .update_status = aty128_bl_update_status,};static void aty128_bl_set_power(struct fb_info *info, int power){ if (info->bl_dev) { info->bl_dev->props.power = power; backlight_update_status(info->bl_dev); }}static void aty128_bl_init(struct aty128fb_par *par){ struct fb_info *info = pci_get_drvdata(par->pdev); struct backlight_device *bd; char name[12]; /* Could be extended to Rage128Pro LVDS output too */ if (par->chip_gen != rage_M3) return;#ifdef CONFIG_PMAC_BACKLIGHT if (!pmac_has_backlight_type("ati")) return;#endif snprintf(name, sizeof(name), "aty128bl%d", info->node); bd = backlight_device_register(name, info->dev, par, &aty128_bl_data); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "aty128: Backlight registration failed\n"); goto error; } info->bl_dev = bd; fb_bl_default_curve(info, 0, 63 * FB_BACKLIGHT_MAX / MAX_LEVEL, 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd->props.brightness = bd->props.max_brightness; bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("aty128: Backlight initialized (%s)\n", name); return;error: return;}static void aty128_bl_exit(struct backlight_device *bd){ backlight_device_unregister(bd); printk("aty128: Backlight unloaded\n");}#endif /* CONFIG_FB_ATY128_BACKLIGHT *//* * Initialisation */#ifdef CONFIG_PPC_PMAC__disabledstatic void aty128_early_resume(void *data){ struct aty128fb_par *par = data; if (try_acquire_console_sem()) return; pci_restore_state(par->pdev); aty128_do_resume(par->pdev); release_console_sem();}#endif /* CONFIG_PPC_PMAC */static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent){ struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par = info->par; struct fb_var_screeninfo var; char video_card[50]; u8 chip_rev; u32 dac; /* Get the chip revision */ chip_rev = (aty_ld_le32(CNFG_CNTL) >> 16) & 0x1F; strcpy(video_card, "Rage128 XX "); video_card[8] = ent->device >> 8; video_card[9] = ent->device & 0xFF; /* range check to make sure */ if (ent->driver_data < ARRAY_SIZE(r128_family)) strlcat(video_card, r128_family[ent->driver_data], sizeof(video_card)); printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); if (par->vram_size % (1024 * 1024) == 0) printk("%dM %s\n", par->vram_size / (1024*1024), par->mem->name); else printk("%dk %s\n", par->vram_size / 1024, par->mem->name); par->chip_gen = ent->driver_data; /* fill in info */ info->fbops = &aty128fb_ops; info->flags = FBINFO_FLAG_DEFAULT; par->lcd_on = default_lcd_on; par->crt_on = default_crt_on; var = default_var;#ifdef CONFIG_PPC_PMAC if (machine_is(powermac)) { /* Indicate sleep capability */ if (par->chip_gen == rage_M3) { pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1);#if 0 /* Disable the early video resume hack for now as it's causing problems, among * others we now rely on the PCI core restoring the config space for us, which * isn't the case with that hack, and that code path causes various things to * be called with interrupts off while they shouldn't. I'm leaving the code in * as it can be useful for debugging purposes */ pmac_set_early_video_resume(aty128_early_resume, par);#endif } /* Find default mode */ if (mode_option) { if (!mac_find_mode(&var, info, mode_option, 8)) var = default_var; } else { if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_1024_768_60; /* iMacs need that resolution * PowerMac2,1 first r128 iMacs * PowerMac2,2 summer 2000 iMacs * PowerMac4,1 january 2001 iMacs "flower power" */ if (machine_is_compatible("PowerMac2,1") || machine_is_compatible("PowerMac2,2") || machine_is_compatible("PowerMac4,1")) default_vmode = VMODE_1024_768_75; /* iBook SE */ if (machine_is_compatible("PowerBook2,2")) default_vmode = VMODE_800_600_60; /* PowerBook Firewire (Pismo), iBook Dual USB */ if (machine_is_compatible("PowerBook3,1") || machine_is_compatible("PowerBook4,1")) default_vmode = VMODE_1024_768_60; /* PowerBook Titanium */ if (machine_is_compatible("PowerBook3,2")) default_vmode = VMODE_1152_768_60; if (default_cmode > 16) default_cmode = CMODE_32; else if (default_cmode > 8) default_cmode = CMODE_16; else default_cmode = CMODE_8; if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; } } else#endif /* CONFIG_PPC_PMAC */ { if (mode_option) if (fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8) == 0) var = default_var; } var.accel_flags &= ~FB_ACCELF_TEXT;// var.accel_flags |= FB_ACCELF_TEXT;/* FIXME Will add accel later */ if (aty128fb_check_var(&var, info)) { printk(KERN_ERR "aty128fb: Cannot set default mode.\n"); return 0; } /* setup the DAC the way we like it */ dac = aty_ld_le32(DAC_CNTL); dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); dac |= DAC_MASK; if (par->chip_gen == rage_M3) dac |= DAC_PALETTE2_SNOOP_EN; aty_st_le32(DAC_CNTL, dac); /* turn off bus mastering, just in case */ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS); info->var = var; fb_alloc_cmap(&info->cmap, 256, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -