irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; int status; int handled = 0; status = MGA_READ(MGA_STATUS); /* VBLANK interrupt */ if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); atomic_inc(&dev_priv->vbl_received); drm_handle_vblank(dev, 0); handled = 1; } /* SOFTRAP interrupt */ if (status & MGA_SOFTRAPEN) { const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_end = MGA_READ(MGA_PRIMEND); MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); /* In addition to clearing the interrupt-pending bit, we * have to write to MGA_PRIMEND to re-start the DMA operation. */ <<<<<<< HEAD if ((prim_start & ~0x03) != (prim_end & ~0x03)) MGA_WRITE(MGA_PRIMEND, prim_end); ======= if ((prim_start & ~0x03) != (prim_end & ~0x03)) {
void mga_driver_irq_preinstall(struct drm_device * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; /* Disable *all* interrupts */ MGA_WRITE(MGA_IEN, 0); /* Clear bits if they're already high */ MGA_WRITE(MGA_ICLEAR, ~0); }
void mga_driver_irq_preinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; MGA_WRITE(MGA_IEN, 0); MGA_WRITE(MGA_ICLEAR, ~0); }
int mga_warp_init(drm_mga_private_t *dev_priv) { u32 wmisc; /* FIXME: Get rid of these damned magic numbers... */ switch (dev_priv->chipset) { case MGA_CARD_TYPE_G400: case MGA_CARD_TYPE_G550: MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND); MGA_WRITE(MGA_WGETMSB, 0x00000E00); MGA_WRITE(MGA_WVRTXSZ, 0x00001807); MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000); break; case MGA_CARD_TYPE_G200: MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND); MGA_WRITE(MGA_WGETMSB, 0x1606); MGA_WRITE(MGA_WVRTXSZ, 7); break; default: return -EINVAL; } MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE)); wmisc = MGA_READ(MGA_WMISC); if (wmisc != WMISC_EXPECTED) { DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n", wmisc, WMISC_EXPECTED); return -EINVAL; } return 0; }
void mga_driver_irq_postinstall(drm_device_t * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); /* Turn on vertical blank interrupt and soft trap interrupt. */ MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); }
int mga_driver_irq_postinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); return 0; }
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; int status; int handled = 0; status = MGA_READ(MGA_STATUS); /* VBLANK interrupt */ if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); handled = 1; } /* SOFTRAP interrupt */ if (status & MGA_SOFTRAPEN) { const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_end = MGA_READ(MGA_PRIMEND); MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); /* In addition to clearing the interrupt-pending bit, we * have to write to MGA_PRIMEND to re-start the DMA operation. */ if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) { MGA_WRITE(MGA_PRIMEND, prim_end); } atomic_inc(&dev_priv->last_fence_retired); DRM_WAKEUP(&dev_priv->fence_queue); handled = 1; } if ( handled ) { return IRQ_HANDLED; } return IRQ_NONE; }
void mga_do_dma_flush( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; u32 status = 0; int i; DMA_LOCALS; DRM_DEBUG( "\n" ); /* We need to wait so that we can do an safe flush */ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; if ( status == MGA_ENDPRDMASTS ) break; udelay( 1 ); } if ( primary->tail == primary->last_flush ) { DRM_DEBUG( " bailing out...\n" ); return; } tail = primary->tail + dev_priv->primary->offset; /* We need to pad the stream between flushes, as the card * actually (partially?) reads the first of these commands. * See page 4-16 in the G400 manual, middle of the page or so. */ BEGIN_DMA( 1 ); DMA_BLOCK( MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000 ); ADVANCE_DMA(); primary->last_flush = primary->tail; head = MGA_READ( MGA_PRIMADDRESS ); if ( head <= tail ) { primary->space = primary->size - primary->tail; } else { primary->space = head - tail; } DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); DRM_DEBUG( " space = 0x%06x\n", primary->space ); mga_flush_write_combine(); MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); DRM_DEBUG( "done.\n" ); }
void mga_driver_irq_uninstall(struct drm_device * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; if (!dev_priv) return; /* Disable *all* interrupts */ MGA_WRITE(MGA_IEN, 0); dev->irq_enabled = 0; }
int mga_driver_irq_postinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); /* Turn on soft trap interrupt. Vertical blank interrupts are enabled * in mga_enable_vblank. */ MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); return 0; }
int mga_enable_vblank(struct drm_device *dev, int crtc) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; if (crtc != 0) { DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", crtc); return 0; } MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); return 0; }
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; int status; int handled = 0; status = MGA_READ(MGA_STATUS); if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); atomic_inc(&dev_priv->vbl_received); drm_handle_vblank(dev, 0); handled = 1; } if (status & MGA_SOFTRAPEN) { const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_end = MGA_READ(MGA_PRIMEND); MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); if ((prim_start & ~0x03) != (prim_end & ~0x03)) MGA_WRITE(MGA_PRIMEND, prim_end); atomic_inc(&dev_priv->last_fence_retired); DRM_WAKEUP(&dev_priv->fence_queue); handled = 1; } if (handled) return IRQ_HANDLED; return IRQ_NONE; }
int mga_do_engine_reset( drm_mga_private_t *dev_priv ) { DRM_DEBUG( "\n" ); /* Okay, so we've completely screwed up and locked the engine. * How about we clean up after ourselves? */ MGA_WRITE( MGA_RST, MGA_SOFTRESET ); udelay( 15 ); /* Wait at least 10 usecs */ MGA_WRITE( MGA_RST, 0 ); /* Initialize the registers that get clobbered by the soft * reset. Many of the core register values survive a reset, * but the drawing registers are basically all gone. * * 3D clients should probably die after calling this. The X * server should reset the engine state to known values. */ #if 0 MGA_WRITE( MGA_PRIMPTR, virt_to_bus((void *)dev_priv->prim.status_page) | MGA_PRIMPTREN0 | MGA_PRIMPTREN1 ); #endif MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR ); MGA_WRITE( MGA_IEN, MGA_SOFTRAPIEN ); /* The primary DMA stream should look like new right about now. */ mga_do_dma_reset( dev_priv ); /* This bad boy will never fail. */ return 0; }
void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; u32 head = dev_priv->primary->offset; DRM_DEBUG( "\n" ); sarea_priv->last_wrap++; DRM_DEBUG( " wrap = %d\n", sarea_priv->last_wrap ); mga_flush_write_combine(); MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); clear_bit( 0, &primary->wrapped ); DRM_DEBUG( "done.\n" ); }
void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; DMA_LOCALS; DRM_DEBUG( "\n" ); BEGIN_DMA_WRAP(); DMA_BLOCK( MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000 ); ADVANCE_DMA(); tail = primary->tail + dev_priv->primary->offset; primary->tail = 0; primary->last_flush = 0; primary->last_wrap++; head = MGA_READ( MGA_PRIMADDRESS ); if ( head == dev_priv->primary->offset ) { primary->space = primary->size; } else { primary->space = head - dev_priv->primary->offset; } DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); DRM_DEBUG( " tail = 0x%06x\n", primary->tail ); DRM_DEBUG( " wrap = %d\n", primary->last_wrap ); DRM_DEBUG( " space = 0x%06x\n", primary->space ); mga_flush_write_combine(); MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); set_bit( 0, &primary->wrapped ); DRM_DEBUG( "done.\n" ); }
static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) { drm_mga_private_t *dev_priv; int ret; DRM_DEBUG( "\n" ); dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); if ( !dev_priv ) return -ENOMEM; memset( dev_priv, 0, sizeof(drm_mga_private_t) ); dev_priv->chipset = init->chipset; dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; if ( init->sgram ) { dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; } else { dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; } dev_priv->maccess = init->maccess; dev_priv->fb_cpp = init->fb_cpp; dev_priv->front_offset = init->front_offset; dev_priv->front_pitch = init->front_pitch; dev_priv->back_offset = init->back_offset; dev_priv->back_pitch = init->back_pitch; dev_priv->depth_cpp = init->depth_cpp; dev_priv->depth_offset = init->depth_offset; dev_priv->depth_pitch = init->depth_pitch; /* FIXME: Need to support AGP textures... */ dev_priv->texture_offset = init->texture_offset[0]; dev_priv->texture_size = init->texture_size[0]; DRM_GETSAREA(); if(!dev_priv->sarea) { DRM_ERROR( "failed to find sarea!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); if(!dev_priv->fb) { DRM_ERROR( "failed to find framebuffer!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR( "failed to find mmio region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->status, init->status_offset ); if(!dev_priv->status) { DRM_ERROR( "failed to find status page!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); if(!dev_priv->warp) { DRM_ERROR( "failed to find warp microcode region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); if(!dev_priv->primary) { DRM_ERROR( "failed to find primary dma region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if(!dev_priv->buffers) { DRM_ERROR( "failed to find dma buffer region!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -EINVAL; } dev_priv->sarea_priv = (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); DRM_IOREMAP( dev_priv->warp, dev ); DRM_IOREMAP( dev_priv->primary, dev ); DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || !dev_priv->buffers->handle ) { DRM_ERROR( "failed to ioremap agp regions!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -ENOMEM; } ret = mga_warp_install_microcode( dev_priv ); if ( ret < 0 ) { DRM_ERROR( "failed to install WARP ucode!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return ret; } ret = mga_warp_init( dev_priv ); if ( ret < 0 ) { DRM_ERROR( "failed to init WARP engine!\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return ret; } dev_priv->prim.status = (u32 *)dev_priv->status->handle; mga_do_wait_for_idle( dev_priv ); /* Init the primary DMA registers. */ MGA_WRITE( MGA_PRIMADDRESS, dev_priv->primary->offset | MGA_DMA_GENERAL ); #if 0 MGA_WRITE( MGA_PRIMPTR, virt_to_bus((void *)dev_priv->prim.status) | MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */ MGA_PRIMPTREN1 ); /* DWGSYNC */ #endif dev_priv->prim.start = (u8 *)dev_priv->primary->handle; dev_priv->prim.end = ((u8 *)dev_priv->primary->handle + dev_priv->primary->size); dev_priv->prim.size = dev_priv->primary->size; dev_priv->prim.tail = 0; dev_priv->prim.space = dev_priv->prim.size; dev_priv->prim.wrapped = 0; dev_priv->prim.last_flush = 0; dev_priv->prim.last_wrap = 0; dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE; dev_priv->prim.status[0] = dev_priv->primary->offset; dev_priv->prim.status[1] = 0; dev_priv->sarea_priv->last_wrap = 0; dev_priv->sarea_priv->last_frame.head = 0; dev_priv->sarea_priv->last_frame.wrap = 0; if ( mga_freelist_init( dev, dev_priv ) < 0 ) { DRM_ERROR( "could not initialize freelist\n" ); /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); return -ENOMEM; } /* Make dev_private visable to others. */ dev->dev_private = (void *)dev_priv; return 0; }