From: Geert U. <ge...@li...> - 2001-05-31 18:14:44
|
Hi, I managed to make atyfb work in RGB565 (depth 15, bpp 16) mode. As expected, the most hairy part turned out to be the palette DAC handling. The patch (relative to the `new' atyfb at SourceForge, project linux-fbdev, module atyfb) is included below. With some minor changes it can be made to work with the old atyfb as well. I haven't checked it in yet because of two reasons: - XF68_FBDev (from 3.3.x) stops working in depth 15, and the new depth 16 doesn't work neither. I guess I'm too fascist with the bitfield tests, although that's fbdev standard policy. I haven't tried XFree86 4.x yet. - Although it works fine in the console, my directcolor test from the fbtest package (module fbtest) fails miserably. Index: src/atyfb_base.c =================================================================== RCS file: /cvsroot/linux-fbdev/atyfb/src/atyfb_base.c,v retrieving revision 1.7 diff -u -r1.7 atyfb_base.c --- src/atyfb_base.c 2001/05/31 17:31:54 1.7 +++ src/atyfb_base.c 2001/05/31 17:57:01 @@ -117,14 +117,6 @@ * The Hardware parameters for each card */ -struct aty_cmap_regs { - u8 windex; - u8 lut; - u8 mask; - u8 rindex; - u8 cntl; -}; - struct pci_mmap_map { unsigned long voff; unsigned long poff; @@ -423,6 +415,11 @@ #endif /* defined(CONFIG_PPC) */ #if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) + + /* + * LCD register access + */ + static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) { unsigned long temp; @@ -446,6 +443,32 @@ } #endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */ + + /* + * DAC register access + */ + +#ifdef __sparc__ +static void aty_ld_dac(int index, u8 *red, u8 *green, u8 *blue, + const struct fb_info_aty *info) +{ + aty_st_8(DAC_R_INDEX, index, info); + *red = aty_ld_8(DAC_DATA, info) << 16; + *green = aty_ld_8(DAC_DATA, info) << 8; + *blue = aty_ld_8(DAC_DATA, info); +} +#endif + +static void aty_st_dac(int index, u8 red, u8 green, u8 blue, + const struct fb_info_aty *info) +{ + aty_st_8(DAC_W_INDEX, index, info); + aty_st_8(DAC_DATA, red, info); + aty_st_8(DAC_DATA, green, info); + aty_st_8(DAC_DATA, blue, info); +} + + /* ------------------------------------------------------------------------- */ /* @@ -464,6 +487,36 @@ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info); } +static const struct { + u32 bpp; + u32 rlen, glen, blen, alen; + int integrated_only; + u32 pix_width; + u32 dp_pix_width; + u32 dp_chain_mask; +} formats[] = { + { + 8, 8, 8, 8, 8, 0, CRTC_PIX_WIDTH_8BPP, + HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB, 0x8080 + }, { + 16, 5, 5, 5, 0, 0, CRTC_PIX_WIDTH_15BPP, + HOST_15BPP | SRC_15BPP | DST_15BPP | BYTE_ORDER_LSB_TO_MSB, 0x4210 + }, +#ifdef CONFIG_FB_ATY_CT + { + 16, 5, 6, 5, 0, 1, CRTC_PIX_WIDTH_16BPP, + HOST_16BPP | SRC_16BPP | DST_16BPP | BYTE_ORDER_LSB_TO_MSB, 0x8410 + }, { + 24, 8, 8, 8, 0, 1, CRTC_PIX_WIDTH_24BPP, + HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB, 0x8080 + }, +#endif /* CONFIG_FB_ATY_CT */ + { + 32, 8, 8, 8, 8, 0, CRTC_PIX_WIDTH_32BPP, + HOST_32BPP | SRC_32BPP | DST_32BPP | BYTE_ORDER_LSB_TO_MSB, 0x8080 + } +}; + static int aty_var_to_crtc(const struct fb_info_aty *info, const struct fb_var_screeninfo *var, struct crtc *crtc) @@ -473,6 +526,8 @@ u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; + u32 rlen, glen, blen, alen; + int i; /* input */ xres = var->xres; @@ -490,6 +545,10 @@ vslen = var->vsync_len; sync = var->sync; vmode = var->vmode; + rlen = var->red.length; + glen = var->green.length; + blen = var->blue.length; + alen = var->transp.length; /* convert (and round up) and validate */ xres = (xres+7) & ~7; @@ -530,36 +589,25 @@ c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; - if (bpp <= 8) { - bpp = 8; - pix_width = CRTC_PIX_WIDTH_8BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else if (bpp <= 16) { - bpp = 16; - pix_width = CRTC_PIX_WIDTH_15BPP; - dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x4210; - } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { - bpp = 24; - pix_width = CRTC_PIX_WIDTH_24BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else if (bpp <= 32) { - bpp = 32; - pix_width = CRTC_PIX_WIDTH_32BPP; - dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; - } else - FAIL("invalid bpp"); + for (i = 0; i < sizeof(formats)/sizeof(*formats); i++) + if (bpp <= formats[i].bpp && rlen <= formats[i].rlen && + glen <= formats[i].glen && blen <= formats[i].blen && + alen <= formats[i].alen && + (M64_HAS(INTEGRATED) || !formats[i].integrated_only)) { + bpp = formats[i].bpp; + pix_width = formats[i].pix_width; + dp_pix_width = formats[i].dp_pix_width; + dp_chain_mask = formats[i].dp_chain_mask; + break; + } + if (i == sizeof(formats)/sizeof(*formats)) + FAIL("invalid pixel format"); if (vxres*vyres*bpp/8 > info->total_vram) FAIL("not enough video RAM"); if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - FAIL("invalid vmode"); + FAIL("invalid format"); /* output */ crtc->vxres = vxres; @@ -660,7 +708,7 @@ var->transp.offset = 0; var->transp.length = 0; break; -#if 0 +#ifdef CONFIG_FB_ATY_CT case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ bpp = 16; var->red.offset = 11; @@ -672,7 +720,6 @@ var->transp.offset = 0; var->transp.length = 0; break; -#endif case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ bpp = 24; var->red.offset = 16; @@ -684,6 +731,7 @@ var->transp.offset = 0; var->transp.length = 0; break; +#endif /* CONFIG_FB_ATY_CT */ case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ bpp = 32; var->red.offset = 16; @@ -1089,6 +1137,7 @@ struct atyfb_par par; struct display *display; int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; + int oldgreenlen; int activate = var->activate; if (con >= 0) @@ -1107,12 +1156,14 @@ oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; + oldgreenlen = display->var.green.length; oldaccel = display->var.accel_flags; display->var = *var; accel = var->accel_flags & FB_ACCELF_TEXT; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { + oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags || + oldgreenlen != var->green.length) { struct fb_fix_screeninfo fix; encode_fix(&fix, &par, info); @@ -1137,7 +1188,8 @@ atyfb_set_par(&par, info); atyfb_set_dispsw(display, info, par.crtc.bpp, accel); } - if (oldbpp != var->bits_per_pixel) { + if (oldbpp != var->bits_per_pixel || + oldgreenlen != var->green.length) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con, &info->fb_info); @@ -1438,14 +1490,11 @@ aty_st_8(DAC_CNTL, tmp, info); aty_st_8(DAC_MASK, 0xff, info); - writeb(i, &info->aty_cmap_regs->rindex); - atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); - writeb(i, &info->aty_cmap_regs->windex); - writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); + aty_ld_dac(i, &atyfb_save.r[enter][i], &atyfb_save.g[enter][i], + &atyfb_save.b[enter][i], info); + aty_st_dac(i, atyfb_save.r[1-enter][i], + atyfb_save.g[1-enter][i], atyfb_save.b[1-enter][i], + info); } } @@ -1745,7 +1794,6 @@ #endif u8 pll_ref_div; - info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); type = chip_id & CFG_CHIP_TYPE; rev = (chip_id & CFG_CHIP_REV)>>24; @@ -2744,7 +2792,7 @@ u_int transp, struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; - int i, scale; + int i, scale = 0; if (regno > 255) return 1; @@ -2759,32 +2807,53 @@ i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ aty_st_8(DAC_CNTL, i, info); aty_st_8(DAC_MASK, 0xff, info); - scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; - writeb(regno << scale, &info->aty_cmap_regs->windex); - writeb(red, &info->aty_cmap_regs->lut); - writeb(green, &info->aty_cmap_regs->lut); - writeb(blue, &info->aty_cmap_regs->lut); - if (regno < 16) - switch (info->current_par.crtc.bpp) { + switch (info->current_par.crtc.gen_cntl & CRTC_PIX_WIDTH_MASK) { + case CRTC_PIX_WIDTH_15BPP: + if (M64_HAS(INTEGRATED)) + scale = 3; #ifdef FBCON_HAS_CFB16 - case 16: + if (regno < 16) info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno; - break; #endif + break; + +#ifdef CONFIG_FB_ATY_CT + case CRTC_PIX_WIDTH_16BPP: + /* + * Green has 6 bits and is stored every 4 entries + * Red and blue have only 5 bits and are stored every 8 entries + */ + aty_st_dac(regno << 2, info->palette[regno/2].red, green, + info->palette[regno/2].blue, info); + green = info->palette[(2*regno) & 0xff].green; + scale = 3; +#ifdef FBCON_HAS_CFB16 + if (regno < 16) + info->fbcon_cmap.cfb16[regno] = (regno << 11) | (regno << 5) | + regno; +#endif + break; + #ifdef FBCON_HAS_CFB24 - case 24: + case CRTC_PIX_WIDTH_24BPP: + if (regno < 16) info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno; - break; + break; #endif +#endif /* CONFIG_FB_ATY_CT */ + #ifdef FBCON_HAS_CFB32 - case 32: + case CRTC_PIX_WIDTH_32BPP: + if (regno < 16) { i = (regno << 8) | regno; info->fbcon_cmap.cfb32[regno] = (i << 16) | i; - break; -#endif } + break; +#endif + } + aty_st_dac(regno << scale, red, green, blue, info); return 0; } Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ge...@li... In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds |