Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea98a92f authored by Dave Airlie's avatar Dave Airlie Committed by Dave Airlie
Browse files

drm: add radeon PCI express support



Add support for Radeon PCI Express cards (needs a new X.org DDX)
Also allows PCI GART table to be stored in VRAM for non PCIE cards

Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 9d17601c
Loading
Loading
Loading
Loading
+49 −33
Original line number Diff line number Diff line
@@ -91,9 +91,7 @@ static void drm_ati_free_pcigart_table( unsigned long address )
	free_pages( address, ATI_PCIGART_TABLE_ORDER );
}

int drm_ati_pcigart_cleanup( drm_device_t *dev,
			      unsigned long addr,
			      dma_addr_t bus_addr)
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
{
	drm_sg_mem_t *entry = dev->sg;
	unsigned long pages;
@@ -105,10 +103,12 @@ int drm_ati_pcigart_cleanup( drm_device_t *dev,
		return 0;
	}

	if ( bus_addr ) {
		pci_unmap_single(dev->pdev, bus_addr,
	if (gart_info->bus_addr) {
		if (gart_info->gart_table_location==DRM_ATI_GART_MAIN) {
			pci_unmap_single(dev->pdev, gart_info->bus_addr,
					 ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
					 PCI_DMA_TODEVICE);
		}

		pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
		        ? entry->pages : ATI_MAX_PCIGART_PAGES;
@@ -118,19 +118,21 @@ int drm_ati_pcigart_cleanup( drm_device_t *dev,
			pci_unmap_single(dev->pdev, entry->busaddr[i],
					 PAGE_SIZE, PCI_DMA_TODEVICE);
		}
		
 		if (gart_info->gart_table_location==DRM_ATI_GART_MAIN)
			gart_info->bus_addr=0;
	}

	if ( addr ) {
		drm_ati_free_pcigart_table( addr );
 	if (gart_info->gart_table_location==DRM_ATI_GART_MAIN && gart_info->addr) {
		drm_ati_free_pcigart_table(gart_info->addr);
		gart_info->addr=0;
	}

	return 1;
}
EXPORT_SYMBOL(drm_ati_pcigart_cleanup);

int drm_ati_pcigart_init( drm_device_t *dev,
			   unsigned long *addr,
			   dma_addr_t *bus_addr)
int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
{
	drm_sg_mem_t *entry = dev->sg;
	unsigned long address = 0;
@@ -143,6 +145,10 @@ int drm_ati_pcigart_init( drm_device_t *dev,
		goto done;
	}

	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
	{
		DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
		
		address = drm_ati_alloc_pcigart_table();
		if ( !address ) {
			DRM_ERROR( "cannot allocate PCI GART page!\n" );
@@ -163,6 +169,13 @@ int drm_ati_pcigart_init( drm_device_t *dev,
			address = 0;
			goto done;
		}
	}
	else
	{
		address = gart_info->addr;
		bus_address = gart_info->bus_addr;
 		DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", bus_address, address);
	}

	pci_gart = (u32 *)address;

@@ -179,7 +192,7 @@ int drm_ati_pcigart_init( drm_device_t *dev,
					   PCI_DMA_TODEVICE);
		if (entry->busaddr[i] == 0) {
			DRM_ERROR( "unable to map PCIGART pages!\n" );
			drm_ati_pcigart_cleanup( dev, address, bus_address );
			drm_ati_pcigart_cleanup(dev, gart_info);
			address = 0;
			bus_address = 0;
			goto done;
@@ -187,6 +200,9 @@ int drm_ati_pcigart_init( drm_device_t *dev,
		page_base = (u32) entry->busaddr[i];

		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
			if (gart_info->is_pcie)
				*pci_gart = (cpu_to_le32(page_base)>>8) | 0xc;
			else
				*pci_gart++ = cpu_to_le32( page_base );
			page_base += ATI_PCIGART_PAGE_SIZE;
		}
@@ -201,8 +217,8 @@ int drm_ati_pcigart_init( drm_device_t *dev,
#endif

done:
	*addr = address;
	*bus_addr = bus_address;
	gart_info->addr = address;
 	gart_info->bus_addr = bus_address;
	return ret;
}
EXPORT_SYMBOL(drm_ati_pcigart_init);
+18 −6
Original line number Diff line number Diff line
@@ -532,6 +532,17 @@ typedef struct drm_vbl_sig {
} drm_vbl_sig_t;


/* location of GART table */
#define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB   2

typedef struct ati_pcigart_info {
	int gart_table_location;
	int is_pcie;
	unsigned long addr;
	dma_addr_t bus_addr;
} drm_ati_pcigart_info;

/**
 * DRM driver structure. This structure represent the common code for
 * a family of cards. There will one drm_device for each card present
@@ -975,12 +986,8 @@ extern int drm_sg_free(struct inode *inode, struct file *filp,
				   unsigned int cmd, unsigned long arg);

                               /* ATI PCIGART support (ati_pcigart.h) */
extern int            drm_ati_pcigart_init(drm_device_t *dev,
					    unsigned long *addr,
					    dma_addr_t *bus_addr);
extern int            drm_ati_pcigart_cleanup(drm_device_t *dev,
					       unsigned long addr,
					       dma_addr_t bus_addr);
extern int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info *gart_info);
extern int drm_ati_pcigart_cleanup(drm_device_t * dev, drm_ati_pcigart_info *gart_info);

extern drm_dma_handle_t *drm_pci_alloc(drm_device_t *dev, size_t size,
				       size_t align, dma_addr_t maxaddr);
@@ -1038,6 +1045,11 @@ static __inline__ int drm_device_is_agp(drm_device_t *dev)
	return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP);
}

static __inline__ int drm_device_is_pcie(drm_device_t *dev)
{
	return pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
}

static __inline__ void drm_core_dropmap(struct drm_map *map)
{
}
+9 −7
Original line number Diff line number Diff line
@@ -562,14 +562,16 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
#if __OS_HAS_AGP
	if ( dev_priv->is_pci ) {
#endif
		if (!drm_ati_pcigart_init( dev, &dev_priv->phys_pci_gart,
     					    &dev_priv->bus_pci_gart) ) {
		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
		dev_priv->gart_info.addr = dev_priv->gart_info.bus_addr = 0;
 		dev_priv->gart_info.is_pcie = 0;
		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
			DRM_ERROR( "failed to init PCI GART!\n" );
			dev->dev_private = (void *)dev_priv;
			r128_do_cleanup_cce( dev );
			return DRM_ERR(ENOMEM);
		}
		R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart );
		R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
#if __OS_HAS_AGP
	}
#endif
@@ -607,9 +609,9 @@ int r128_do_cleanup_cce( drm_device_t *dev )
		} else
#endif
		{
 			if (dev_priv->gart_info.bus_addr)
				if (!drm_ati_pcigart_cleanup( dev,
						dev_priv->phys_pci_gart,
						dev_priv->bus_pci_gart ))
							      &dev_priv->gart_info))
					DRM_ERROR( "failed to cleanup PCI GART!\n" );
		}

+1 −2
Original line number Diff line number Diff line
@@ -88,8 +88,6 @@ typedef struct drm_r128_private {

	int usec_timeout;
	int is_pci;
	unsigned long phys_pci_gart;
	dma_addr_t bus_pci_gart;
	unsigned long cce_buffers_offset;

	atomic_t idle_count;
@@ -120,6 +118,7 @@ typedef struct drm_r128_private {
	drm_local_map_t *cce_ring;
	drm_local_map_t *ring_rptr;
	drm_local_map_t *agp_textures;
	drm_ati_pcigart_info gart_info;
} drm_r128_private_t;

typedef struct drm_r128_buf_priv {
+70 −7
Original line number Diff line number Diff line
@@ -825,6 +825,12 @@ static int RADEON_READ_PLL(drm_device_t *dev, int addr)
	return RADEON_READ(RADEON_CLOCK_CNTL_DATA);
}

static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
{
	RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff);
	return RADEON_READ(RADEON_PCIE_DATA);
}

#if RADEON_FIFO_DEBUG
static void radeon_status( drm_radeon_private_t *dev_priv )
{
@@ -1241,17 +1247,46 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev,
		       RADEON_ISYNC_CPSCRATCH_IDLEGUI) );
}

/* Enable or disable PCI-E GART on the chip */
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
	u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
	if (on) {

		DRM_DEBUG("programming pcie %08X %08lX %08X\n",
			  dev_priv->gart_vm_start, (long)dev_priv->gart_info.bus_addr,
			  dev_priv->gart_size);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, dev_priv->gart_vm_start);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE, dev_priv->gart_info.bus_addr);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO, dev_priv->gart_vm_start);
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_END_LO, dev_priv->gart_vm_start
				  + dev_priv->gart_size - 1);
		
		RADEON_WRITE(RADEON_MC_AGP_LOCATION, 0xffffffc0);	/* ?? */
		
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, RADEON_PCIE_TX_GART_EN);
	} else {
		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN);
	}
}

/* Enable or disable PCI GART on the chip */
static void radeon_set_pcigart( drm_radeon_private_t *dev_priv, int on )
{
	u32 tmp	= RADEON_READ( RADEON_AIC_CNTL );

	if (dev_priv->flags & CHIP_IS_PCIE)
	{
		radeon_set_pciegart(dev_priv, on);
		return;
	}

	if ( on ) {
		RADEON_WRITE( RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN );

		/* set PCI GART page-table base address
		 */
		RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart );
		RADEON_WRITE(RADEON_AIC_PT_BASE, dev_priv->gart_info.bus_addr);

		/* set address range for PCI address translate
		 */
@@ -1519,8 +1554,28 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init )
	} else
#endif
	{
		if (!drm_ati_pcigart_init( dev, &dev_priv->phys_pci_gart,
					    &dev_priv->bus_pci_gart)) {
		/* if we have an offset set from userspace */
		if (dev_priv->pcigart_offset) {
			dev_priv->gart_info.bus_addr = dev_priv->pcigart_offset + dev_priv->fb_location;
			dev_priv->gart_info.addr = (unsigned long)drm_ioremap(dev_priv->gart_info.bus_addr, RADEON_PCIGART_TABLE_SIZE, dev);

			dev_priv->gart_info.is_pcie = !!(dev_priv->flags & CHIP_IS_PCIE);
			dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB;
			
			DRM_DEBUG("Setting phys_pci_gart to %08lX %08lX\n", dev_priv->gart_info.addr, dev_priv->pcigart_offset);
		}
		else {
			dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
			dev_priv->gart_info.addr = dev_priv->gart_info.bus_addr= 0;
			if (dev_priv->flags & CHIP_IS_PCIE)
			{
				DRM_ERROR("Cannot use PCI Express without GART in FB memory\n");
				radeon_do_cleanup_cp(dev);
				return DRM_ERR(EINVAL);
			}
		}

		if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
			DRM_ERROR( "failed to init PCI GART!\n" );
			dev->dev_private = (void *)dev_priv;
			radeon_do_cleanup_cp(dev);
@@ -1568,10 +1623,15 @@ static int radeon_do_cleanup_cp( drm_device_t *dev )
	} else
#endif
	{
		if (!drm_ati_pcigart_cleanup( dev,
					      dev_priv->phys_pci_gart,
					      dev_priv->bus_pci_gart ))
		if (dev_priv->gart_info.bus_addr)
			if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
				DRM_ERROR("failed to cleanup PCI GART!\n");
		
		if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
		{
			drm_ioremapfree((void *)dev_priv->gart_info.addr, RADEON_PCIGART_TABLE_SIZE, dev);
			dev_priv->gart_info.addr = 0;
		}
	}
	
	/* only clear to the start of flags */
@@ -2057,6 +2117,9 @@ int radeon_driver_preinit(struct drm_device *dev, unsigned long flags)
	if (drm_device_is_agp(dev))
		dev_priv->flags |= CHIP_IS_AGP;
	
	if (drm_device_is_pcie(dev))
		dev_priv->flags |= CHIP_IS_PCIE;

	DRM_DEBUG("%s card detected\n",
		  ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI"));
	return ret;
Loading