patch-2.3.99-pre6 linux/drivers/video/aty128fb.c
Next file: linux/drivers/video/cyber2000fb.c
Previous file: linux/drivers/video/acornfb.c
Back to the patch index
Back to the overall index
- Lines: 953
- Date:
Mon Apr 24 13:49:18 2000
- Orig file:
v2.3.99-pre5/linux/drivers/video/aty128fb.c
- Orig date:
Tue Apr 11 15:09:21 2000
diff -u --recursive --new-file v2.3.99-pre5/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
@@ -180,7 +180,7 @@
#ifndef MODULE
static const char *mode_option __initdata = NULL;
#endif
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
static void *bios_seg = NULL;
#endif
@@ -244,12 +244,13 @@
struct fb_info fb_info;
struct fb_info_aty128 *next;
struct aty128_constants constants; /* PLL and others */
- unsigned long regbase_phys; /* physical mmio */
+ u32 regbase_phys; /* physical mmio */
void *regbase; /* remapped mmio */
- unsigned long frame_buffer_phys; /* physical fb memory */
- unsigned long frame_buffer; /* remaped framebuffer */
- const struct aty128_meminfo *mem; /* onboard mem info */
+ u32 frame_buffer_phys; /* physical fb memory */
+ u32 frame_buffer; /* remaped framebuffer */
+ u32 io_base; /* unmapped io */
u32 vram_size; /* onboard video ram */
+ const struct aty128_meminfo *mem; /* onboard mem info */
struct aty128fb_par default_par, current_par;
struct display disp;
struct display_switch dispsw; /* for cursor and font */
@@ -301,6 +302,7 @@
struct fb_info *fb);
static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *info);
+static int aty128fb_rasterimg(struct fb_info *info, int start);
/*
@@ -308,8 +310,8 @@
*/
int aty128fb_init(void);
-static int aty128fbcon_switch(int con, struct fb_info *info);
-static void aty128fbcon_blank(int blank, struct fb_info *info);
+static int aty128fbcon_switch(int con, struct fb_info *fb);
+static void aty128fbcon_blank(int blank, struct fb_info *fb);
/*
* Internal routines
@@ -335,9 +337,9 @@
const struct aty128_chip_info *aci);
static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
*board_list, struct fb_info_aty128 *new_node);
-static int aty128find_ROM(struct fb_info_aty128 *info);
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
static void aty128_get_pllinfo(struct fb_info_aty128 *info);
+static int aty128find_ROM(struct fb_info_aty128 *info);
#endif
static void aty128_timings(struct fb_info_aty128 *info);
static void aty128_init_engine(const struct aty128fb_par *par,
@@ -385,29 +387,26 @@
static struct fb_ops aty128fb_ops = {
aty128fb_open, aty128fb_release, aty128fb_get_fix,
aty128fb_get_var, aty128fb_set_var, aty128fb_get_cmap,
- aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
+ aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl,
+ NULL, aty128fb_rasterimg
};
/*
* Functions to read from/write to the mmio registers
- * - endian conversions may possibly be avoided by flipping CONFIG_CNTL
- * or using the other register aperture? TODO.
+ * - endian conversions may possibly be avoided by
+ * using the other register aperture. TODO.
*/
static inline u32
_aty_ld_le32(volatile unsigned int regindex,
const struct fb_info_aty128 *info)
{
- unsigned long *temp;
u32 val;
#if defined(__powerpc__)
- eieio();
- temp = info->regbase;
- asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp));
+ asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(info->regbase));
#else
- temp = info->regbase+regindex;
- val = readl (temp);
+ val = readl (info->regbase + regindex);
#endif
return val;
@@ -417,35 +416,23 @@
_aty_st_le32(volatile unsigned int regindex, u32 val,
const struct fb_info_aty128 *info)
{
- unsigned long *temp;
-
#if defined(__powerpc__)
- temp = info->regbase;
- asm("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
- "memory");
-#elif defined(__mc68000__)
- *((volatile u32 *)(info->regbase+regindex)) = cpu_to_le32(val);
+ asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
+ "r"(info->regbase) : "memory");
#else
- temp = info->regbase+regindex;
- writel (val, temp);
+ writel (val, info->regbase + regindex);
#endif
}
static inline u8
_aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
return readb (info->regbase + regindex);
}
static inline void
_aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
writeb (val, info->regbase + regindex);
}
@@ -466,9 +453,6 @@
_aty_ld_pll(unsigned int pll_index,
const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F);
return aty_ld_le32(CLOCK_CNTL_DATA);
}
@@ -478,9 +462,6 @@
_aty_st_pll(unsigned int pll_index, u32 val,
const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN);
aty_st_le32(CLOCK_CNTL_DATA, val);
}
@@ -528,7 +509,8 @@
static int __init
register_test(const struct fb_info_aty128 *info)
{
- u32 val, flag = 0;
+ u32 val;
+ int flag = 0;
val = aty_ld_le32(BIOS_0_SCRATCH);
@@ -648,35 +630,34 @@
u32 pitch_value;
/* 3D scaler not spoken here */
+ wait_for_fifo(1, info);
aty_st_le32(SCALE_3D_CNTL, 0x00000000);
aty128_reset_engine(info);
- pitch_value = par->crtc.pitch; /* fix this up */
+ pitch_value = par->crtc.pitch;
if (par->crtc.bpp == 24) {
pitch_value = pitch_value * 3;
}
+ wait_for_fifo(4, info);
/* setup engine offset registers */
- wait_for_fifo(1, info);
aty_st_le32(DEFAULT_OFFSET, 0x00000000);
/* setup engine pitch registers */
aty_st_le32(DEFAULT_PITCH, pitch_value);
/* set the default scissor register to max dimensions */
- wait_for_fifo(1, info);
aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
/* set the drawing controls registers */
- wait_for_fifo(1, info);
aty_st_le32(DP_GUI_MASTER_CNTL,
GMC_SRC_PITCH_OFFSET_DEFAULT |
GMC_DST_PITCH_OFFSET_DEFAULT |
GMC_SRC_CLIP_DEFAULT |
GMC_DST_CLIP_DEFAULT |
GMC_BRUSH_SOLIDCOLOR |
- (bpp_to_depth(par->crtc.bpp << 8)) |
+ (bpp_to_depth(par->crtc.bpp) << 8) |
GMC_SRC_DSTCOLOR |
GMC_BYTE_ORDER_MSB_TO_LSB |
GMC_DP_CONVERSION_TEMP_6500 |
@@ -688,7 +669,6 @@
GMC_WRITE_MASK_SET);
wait_for_fifo(8, info);
-
/* clear the line drawing registers */
aty_st_le32(DST_BRES_ERR, 0);
aty_st_le32(DST_BRES_INC, 0);
@@ -766,23 +746,22 @@
/* input */
xres = var->xres;
yres = var->yres;
- vxres = var->xres_virtual;
- vyres = var->yres_virtual;
+ vxres = var->xres_virtual;
+ vyres = var->yres_virtual;
xoffset = var->xoffset;
yoffset = var->yoffset;
- bpp = var->bits_per_pixel;
- left = var->left_margin;
+ bpp = var->bits_per_pixel;
+ left = var->left_margin;
right = var->right_margin;
upper = var->upper_margin;
lower = var->lower_margin;
hslen = var->hsync_len;
vslen = var->vsync_len;
- sync = var->sync;
+ sync = var->sync;
vmode = var->vmode;
- /* check for mode eligibility */
-
- /* accept only non interlaced modes */
+ /* check for mode eligibility
+ * accept only non interlaced modes */
if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
return -EINVAL;
@@ -796,6 +775,7 @@
if (vyres < yres + yoffset)
vyres = yres + yoffset;
+ /* convert bpp into ATI register depth */
depth = bpp_to_depth(bpp);
/* make sure we didn't get an invalid depth */
@@ -804,7 +784,8 @@
return -EINVAL;
}
- bytpp = mode_bytpp[depth];
+ /* convert depth to bpp */
+ bytpp = mode_bytpp[depth];
/* make sure there is enough video ram for the mode */
if ((u32)(vxres * vyres * bytpp) > info->vram_size) {
@@ -813,24 +794,24 @@
}
h_disp = (xres >> 3) - 1;
- h_total = (((xres + right + hslen + left) / 8) - 1) & 0xFFFFL;
+ h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL;
v_disp = yres - 1;
v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL;
/* check to make sure h_total and v_total are in range */
- if ((h_total/8 - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
+ if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
printk(KERN_ERR "aty128fb: invalid width ranges\n");
return -EINVAL;
}
- h_sync_wid = (hslen+7)/8;
+ h_sync_wid = (hslen + 7) >> 3;
if (h_sync_wid == 0)
h_sync_wid = 1;
else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */
h_sync_wid = 0x3f;
- h_sync_strt = h_disp + (right/8);
+ h_sync_strt = h_disp + (right >> 3);
v_sync_wid = vslen;
if (v_sync_wid == 0)
@@ -855,7 +836,7 @@
crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
(v_sync_pol << 23);
- crtc->pitch = xres >> 3;
+ crtc->pitch = vxres >> 3;
crtc->offset = 0;
crtc->offset_cntl = 0;
@@ -922,7 +903,7 @@
var->transp.length = 8;
break;
default:
- printk(KERN_ERR "Invalid pixel width\n");
+ printk(KERN_ERR "aty128fb: Invalid pixel width\n");
return -EINVAL;
}
@@ -941,26 +922,27 @@
/* fun with masking */
h_total = crtc->h_total & 0x1ff;
- h_disp = (crtc->h_total>>16) & 0xff;
- h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff;
+ h_disp = (crtc->h_total >> 16) & 0xff;
+ h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff;
h_sync_dly = crtc->h_sync_strt_wid & 0x7;
- h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x3f;
- h_sync_pol = (crtc->h_sync_strt_wid>>23) & 0x1;
+ h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f;
+ h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1;
v_total = crtc->v_total & 0x7ff;
- v_disp = (crtc->v_total>>16) & 0x7ff;
+ v_disp = (crtc->v_total >> 16) & 0x7ff;
v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
- v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
- v_sync_pol = (crtc->v_sync_strt_wid>>23) & 0x1;
+ v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f;
+ v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1;
c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
- xres = (h_disp+1) << 3;
- yres = v_disp+1;
- left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
- right = (h_sync_strt-h_disp)*8+h_sync_dly;
- hslen = h_sync_wid*8;
- upper = v_total-v_sync_strt-v_sync_wid;
- lower = v_sync_strt-v_disp;
+ /* do conversions */
+ xres = (h_disp + 1) << 3;
+ yres = v_disp + 1;
+ left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly;
+ right = ((h_sync_strt - h_disp) << 3) + h_sync_dly;
+ hslen = h_sync_wid << 3;
+ upper = v_total - v_sync_strt - v_sync_wid;
+ lower = v_sync_strt - v_disp;
vslen = v_sync_wid;
sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
@@ -974,13 +956,13 @@
var->yres_virtual = crtc->vyres;
var->xoffset = crtc->xoffset;
var->yoffset = crtc->yoffset;
- var->left_margin = left;
+ var->left_margin = left;
var->right_margin = right;
var->upper_margin = upper;
var->lower_margin = lower;
var->hsync_len = hslen;
var->vsync_len = vslen;
- var->sync = sync;
+ var->sync = sync;
var->vmode = FB_VMODE_NONINTERLACED;
return 0;
@@ -990,7 +972,7 @@
static void
aty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info)
{
- int div3;
+ u32 div3;
unsigned char post_conv[] = /* register values for post dividers */
{ 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
@@ -1003,25 +985,23 @@
aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
/* write the reference divider */
+ aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff);
aty_pll_writeupdate(info);
- aty_pll_wait_readupdate(info);
div3 = aty_ld_pll(PPLL_DIV_3);
-
div3 &= ~PPLL_FB3_DIV_MASK;
div3 |= pll->feedback_divider;
-
div3 &= ~PPLL_POST3_DIV_MASK;
div3 |= post_conv[pll->post_divider] << 16;
/* write feedback and post dividers */
+ aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_DIV_3, div3);
aty_pll_writeupdate(info);
- aty_pll_wait_readupdate(info);
+ aty_pll_wait_readupdate(info);
aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */
-
aty_pll_writeupdate(info);
/* clear the reset, just in case */
@@ -1111,7 +1091,7 @@
bpp = 16;
n = xclk * fifo_width;
- d = pll->vclk*bpp;
+ d = pll->vclk * bpp;
x = round_div(n, d);
ron = 4 * m->MB +
@@ -1162,13 +1142,6 @@
struct fb_info_aty128 *info)
{
u32 config;
-#ifdef CONFIG_FB_COMPAT_XPMAC
-#if 0 /* enable this when macmodes gets updated */
- struct vc_mode disp_info;
-#endif
- struct fb_var_screeninfo var;
- int cmode, vmode;
-#endif
info->current_par = *par;
@@ -1210,31 +1183,15 @@
if (par->accel_flags & FB_ACCELF_TEXT)
aty128_init_engine(par, info);
-#if 0/*def CONFIG_FB_COMPAT_XPMAC*/
-#if 0 /* use this when macmodes gets updated */
- if (!console_fb_info || console_fb_info == &info->fb_info) {
- disp_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
- disp_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3;
- disp_info.depth = par->crtc.bpp;
- disp_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3;
- aty128_encode_var(&var, par, info);
- if (mac_var_to_vmode(&var, &vmode, &cmode))
- disp_info.mode = 0;
- else
- disp_info.mode = vmode;
- strcpy(disp_info.name, aty128fb_name);
- disp_info.fb_address = info->frame_buffer_phys;
- disp_info.cmap_adr_address = 0;
- disp_info.cmap_data_address = 0;
- disp_info.disp_reg_address = info->regbase_phys;
- register_compat_xpmac(disp_info);
- }
-#else
+#ifdef CONFIG_FB_COMPAT_XPMAC
if (!console_fb_info || console_fb_info == &info->fb_info) {
- display_info.width = ((par->crtc.v_total >> 16) & 0x7ff)+1;
- display_info.height = (((par->crtc.h_total >> 16) & 0xff)+1) << 3;
+ struct fb_var_screeninfo var;
+ int cmode, vmode;
+
+ display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
+ display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
display_info.depth = par->crtc.bpp;
- display_info.pitch = par->crtc.vxres*par->crtc.bpp >> 3;
+ display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3;
aty128_encode_var(&var, par, info);
if (mac_var_to_vmode(&var, &vmode, &cmode))
display_info.mode = 0;
@@ -1245,9 +1202,7 @@
display_info.cmap_adr_address = 0;
display_info.cmap_data_address = 0;
display_info.disp_reg_address = info->regbase_phys;
- register_compat_xpmac(display_info);
}
-#endif
#endif /* CONFIG_FB_COMPAT_XPMAC */
}
@@ -1491,15 +1446,15 @@
strcpy(fix->id, aty128fb_name);
- fix->smem_start = (long)info->frame_buffer_phys;
- fix->mmio_start = (long)info->regbase_phys;
+ fix->smem_start = (unsigned long)info->frame_buffer_phys;
+ fix->mmio_start = (unsigned long)info->regbase_phys;
- fix->smem_len = (u32)info->vram_size;
+ fix->smem_len = info->vram_size;
fix->mmio_len = 0x1fff;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
- fix->line_length = par->crtc.vxres*par->crtc.bpp >> 3;
+ fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR;
fix->ywrapstep = 0;
@@ -1547,7 +1502,7 @@
u32 offset;
u32 xres, yres;
- xres = (((par->crtc.h_total >> 16) & 0xff) + 1) * 8;
+ xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
xoffset = (var->xoffset +7) & ~7;
@@ -1617,7 +1572,6 @@
return 0;
}
-
/*
* Frame Buffer Specific ioctls
*/
@@ -1630,6 +1584,18 @@
}
+static int
+aty128fb_rasterimg(struct fb_info *info, int start)
+{
+ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info;
+
+ if (fb->blitter_may_be_busy)
+ wait_for_idle(fb);
+
+ return 0;
+}
+
+
#ifndef MODULE
int __init
aty128fb_setup(char *options)
@@ -1742,12 +1708,13 @@
/* fill in info */
strcpy(info->fb_info.modename, aty128fb_name);
- info->fb_info.node = -1;
+ info->fb_info.node = -1;
info->fb_info.fbops = &aty128fb_ops;
- info->fb_info.disp = &info->disp;
+ info->fb_info.disp = &info->disp;
strcpy(info->fb_info.fontname, fontname);
- info->fb_info.changevar = NULL;
+ info->fb_info.changevar = NULL;
info->fb_info.switch_con = &aty128fbcon_switch;
+ info->fb_info.updatevar = NULL;
info->fb_info.blank = &aty128fbcon_blank;
info->fb_info.flags = FBINFO_FLAG_DEFAULT;
@@ -1755,7 +1722,7 @@
var = default_var;
#else
memset(&var, 0, sizeof(var));
-#ifdef CONFIG_FB_COMPAT_XPMAC /* CONFIG_PPC implied */
+#ifdef CONFIG_PPC
if (_machine == _MACH_Pmac) {
if (mode_option) {
if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
@@ -1777,12 +1744,14 @@
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
}
+ } else {
+#endif /* CONFIG_PPC */
+ if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
+ &defaultmode, initdepth) == 0)
+ var = default_var;
+#ifdef CONFIG_PPC
}
-#else
- if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
- &defaultmode, initdepth) == 0)
- var = default_var;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
+#endif
#endif /* MODULE */
if (noaccel)
@@ -1873,35 +1842,36 @@
const struct aty128_chip_info *aci)
{
struct fb_info_aty128 *info = NULL;
- unsigned long fb_addr, reg_addr = 0;
- u16 tmp;
-
- struct resource *rp;
+ u32 fb_addr, reg_addr, io_addr = 0;
+ int err;
- rp = &pdev->resource[0];
- fb_addr = rp->start;
- fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ /* Request resources we're going to use */
+ io_addr = pci_resource_start(pdev, 1);
+ if (!request_region(io_addr, pci_resource_len(pdev, 1),
+ "aty128fb IO")) {
+ printk(KERN_ERR "aty128fb: cannot reserve I/O ports\n");
+ goto err_out_none;
+ }
- if (!request_mem_region(rp->start, rp->end - rp->start + 1,
+ fb_addr = pci_resource_start(pdev, 0);
+ if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0),
"aty128fb FB")) {
- release_mem_region(pdev->resource[0].start,
- pdev->resource[0].end -
- pdev->resource[0].start + 1);
- return -1;
+ printk(KERN_ERR "aty128fb: cannot reserve frame buffer memory\n");
+ goto err_free_fb;
}
- rp = &pdev->resource[2];
- reg_addr = rp->start;
- reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
-
- if (!request_mem_region(rp->start, rp->end - rp->start + 1,
- "aty128fb MMIO"))
- goto unmap_out;
+ reg_addr = pci_resource_start(pdev, 2);
+ if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2),
+ "aty128fb MMIO")) {
+ printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");
+ goto err_free_mmio;
+ }
+ /* We have the resources. Now virtualize them */
info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
if(!info) {
printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
- goto unmap_out;
+ goto err_unmap_out;
}
memset(info, 0, sizeof(struct fb_info_aty128));
@@ -1913,22 +1883,29 @@
info->regbase = ioremap(reg_addr, 0x1FFF);
if (!info->regbase)
- goto err_out;
+ goto err_free_info;
- info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+ /* Store io_base */
+ info->io_base = io_addr;
- pci_read_config_word(pdev, PCI_COMMAND, &tmp);
- if (!(tmp & PCI_COMMAND_MEMORY)) {
- tmp |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, tmp);
- }
+ /* Grab memory size from the card */
+ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
/* Virtualize the framebuffer */
info->frame_buffer_phys = fb_addr;
- info->frame_buffer = (unsigned long)ioremap(fb_addr, info->vram_size);
+ info->frame_buffer = (u32)ioremap(fb_addr, info->vram_size);
+
+ if (!info->frame_buffer) {
+ iounmap((void *)info->regbase);
+ goto err_free_info;
+ }
- if (!info->frame_buffer)
+ /* Enable device in PCI config */
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", err);
goto err_out;
+ }
/* If we can't test scratch registers, something is seriously wrong */
if (!register_test(info)) {
@@ -1936,21 +1913,17 @@
goto err_out;
}
- if (!aty128find_ROM(info)) {
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
+ if (!aty128find_ROM(info))
printk(KERN_INFO "aty128fb: Rage128 BIOS not located. Guessing...\n");
- aty128_timings(info);
- }
-#ifndef CONFIG_PPC
- else
+ else
aty128_get_pllinfo(info);
-
- /* free up to-be unused resources. bios_seg is mapped by
- * aty128find_ROM() and used by aty128_get_pllinfo()
- *
- * TODO: make more elegant. doesn't need to be global */
- if (bios_seg)
- iounmap(bios_seg);
#endif
+ aty128_timings(info);
+
+ if (!aty128_init(info, "PCI"))
+ goto err_out;
+
#ifdef CONFIG_MTRR
if (mtrr) {
info->mtrr.vram = mtrr_add(info->frame_buffer_phys, info->vram_size,
@@ -1961,32 +1934,34 @@
}
#endif /* CONFIG_MTRR */
- if (!aty128_init(info, "PCI"))
- goto err_out;
-
return 0;
err_out:
+ iounmap((void *)info->frame_buffer);
+ iounmap((void *)info->regbase);
+err_free_info:
kfree(info);
-unmap_out:
- release_mem_region(pdev->resource[0].start,
- pdev->resource[0].end -
- pdev->resource[0].start + 1);
- release_mem_region(pdev->resource[2].start,
- pdev->resource[2].end -
- pdev->resource[2].start + 1);
-
- return -1;
+err_unmap_out:
+ release_mem_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+err_free_mmio:
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+err_free_fb:
+ release_mem_region(pci_resource_start(pdev, 1),
+ pci_resource_len(pdev, 1));
+err_out_none:
+ return -ENODEV;
}
#endif /* CONFIG_PCI */
-/* PPC cannot read video ROM, so we fail by default */
+/* PPC and Sparc cannot read video ROM */
+#if !defined(CONFIG_PPC) && !defined(__sparc__)
static int __init
aty128find_ROM(struct fb_info_aty128 *info)
{
int flag = 0;
-#ifndef CONFIG_PPC
u32 segstart;
char *rom_base;
char *rom;
@@ -2043,12 +2018,10 @@
flag = 1;
break;
}
-#endif /* !CONFIG_PPC */
return (flag);
}
-#ifndef CONFIG_PPC
static void __init
aty128_get_pllinfo(struct fb_info_aty128 *info)
{
@@ -2076,11 +2049,12 @@
info->constants.ref_divider = (u32)pll.PCLK_ref_divider;
info->constants.dotclock = (u32)pll.PCLK_ref_freq;
- aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
- aty_pll_writeupdate(info);
-
- info->constants.fifo_width = 128;
- info->constants.fifo_depth = 32;
+ /* free up to be un-used resources. bios_seg is mapped by
+ * aty128find_ROM() and used by aty128_get_pllinfo()
+ *
+ * TODO: make more elegant. doesn't need to be global */
+ if (bios_seg)
+ iounmap(bios_seg);
#ifdef DEBUG
printk(KERN_DEBUG "get_pllinfo: ppll_max %d ppll_min %d xclk %d "
@@ -2089,56 +2063,59 @@
info->constants.xclk, info->constants.ref_divider,
info->constants.dotclock);
#endif
-
- switch(aty_ld_le32(MEM_CNTL) & 0x03) {
- case 0:
- info->mem = &sdr_128;
- break;
- case 1:
- info->mem = &sdr_sgram;
- break;
- case 2:
- info->mem = &ddr_sgram;
- break;
- default:
- info->mem = &sdr_sgram;
- }
-
return;
}
-#endif /* ! CONFIG_PPC */
+#endif /* !CONFIG_PPC */
/* fill in known card constants if pll_block is not available */
static void __init
aty128_timings(struct fb_info_aty128 *info)
{
- /* TODO make an attempt at probing */
+#ifdef CONFIG_PPC
+ /* instead of a table lookup, assume OF has properly
+ * setup the PLL registers and use their values
+ * to set the XCLK values and reference divider values */
+
+ u32 x_mpll_ref_fb_div;
+ u32 xclk_cntl;
+ u32 Nx, M;
+ unsigned PostDivSet[] =
+ { 0, 1, 2, 4, 8, 3, 6, 12 };
+#endif
+
if (!info->constants.dotclock)
info->constants.dotclock = 2950;
- /* from documentation */
- if (!info->constants.ppll_min)
- info->constants.ppll_min = 12500;
- if (!info->constants.ppll_max)
- info->constants.ppll_max = 25000; /* 23000 on some cards? */
+#ifdef CONFIG_PPC
+ x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
+ xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
+ Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
+ M = x_mpll_ref_fb_div & 0x0000ff;
+
+ info->constants.xclk = round_div((2 * Nx *
+ info->constants.dotclock), (M * PostDivSet[xclk_cntl]));
+
+ info->constants.ref_divider =
+ aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
-#if 1
- /* XXX TODO. Calculuate properly. */
- if (!info->constants.ref_divider)
+ if (!info->constants.ref_divider) {
info->constants.ref_divider = 0x3b;
- aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
- aty_pll_writeupdate(info);
- aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+ aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+ aty_pll_writeupdate(info);
+ }
+ aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
aty_pll_writeupdate(info);
-#else
- info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#endif
- /* TODO. Calculate */
+ /* from documentation */
+ if (!info->constants.ppll_min)
+ info->constants.ppll_min = 12500;
+ if (!info->constants.ppll_max)
+ info->constants.ppll_max = 25000; /* 23000 on some cards? */
if (!info->constants.xclk)
- info->constants.xclk = 0x1d4d; /* same as mclk */
+ info->constants.xclk = 0x1d4d; /* same as mclk */
info->constants.fifo_width = 128;
info->constants.fifo_depth = 32;
@@ -2225,7 +2202,6 @@
return 0;
}
-
/*
* Set a single color register. The values supplied are already
* rounded down to the hardware's capabilities (according to the
@@ -2314,22 +2290,36 @@
* Accelerated functions
*/
-static void
+static inline void
aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height,
struct fb_info_aty128 *info)
{
- u32 save_dp_datatype, save_dp_cntl;
+ u32 save_dp_datatype, save_dp_cntl, bppval;
+
+ if (!width || !height)
+ return;
+
+ bppval = bpp_to_depth(info->current_par.crtc.bpp);
+ if (bppval == DST_24BPP) {
+ srcx *= 3;
+ dstx *= 3;
+ width *= 3;
+ } else if (bppval == -EINVAL) {
+ printk("aty128fb: invalid depth\n");
+ return;
+ }
wait_for_fifo(2, info);
save_dp_datatype = aty_ld_le32(DP_DATATYPE);
save_dp_cntl = aty_ld_le32(DP_CNTL);
wait_for_fifo(6, info);
- aty_st_le32(DP_DATATYPE, (BRUSH_SOLIDCOLOR << 16) | SRC_DSTCOLOR);
+ aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
- aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
+ aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR);
+
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
@@ -2338,8 +2328,6 @@
wait_for_fifo(2, info);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
-
- wait_for_idle(info);
}
@@ -2569,12 +2557,12 @@
iounmap(info->regbase);
iounmap(&info->frame_buffer);
- release_mem_region(info->pdev->resource[0].start,
- info->pdev->resource[0].end -
- info->pdev->resource[0].start + 1);
- release_mem_region(info->pdev->resource[2].start,
- info->pdev->resource[2].end -
- info->pdev->resource[2].start + 1);
+ release_mem_region(pci_resource_start(info->pdev, 0),
+ pci_resource_len(info->pdev, 0));
+ release_mem_region(pci_resource_start(info->pdev, 1),
+ pci_resource_len(info->pdev, 1));
+ release_mem_region(pci_resource_start(info->pdev, 2),
+ pci_resource_len(info->pdev, 2));
kfree(info);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)