2012-07-05 21:36:32 +10:00
# include <linux/module.h>
2012-07-11 10:44:20 +10:00
# include <core/device.h>
2012-07-05 21:36:32 +10:00
2012-07-11 10:44:20 +10:00
# include "nouveau_drm.h"
2012-07-05 21:36:32 +10:00
# include "nouveau_agp.h"
2012-07-11 10:44:20 +10:00
# include "nouveau_reg.h"
2012-07-05 21:36:32 +10:00
# if __OS_HAS_AGP
MODULE_PARM_DESC ( agpmode , " AGP mode (0 to disable AGP) " ) ;
static int nouveau_agpmode = - 1 ;
module_param_named ( agpmode , nouveau_agpmode , int , 0400 ) ;
static unsigned long
2012-07-11 10:44:20 +10:00
get_agp_mode ( struct nouveau_drm * drm , unsigned long mode )
2012-07-05 21:36:32 +10:00
{
2012-07-11 10:44:20 +10:00
struct nouveau_device * device = nv_device ( drm - > device ) ;
2012-07-05 21:36:32 +10:00
/*
* FW seems to be broken on nv18 , it makes the card lock up
* randomly .
*/
2012-07-11 10:44:20 +10:00
if ( device - > chipset = = 0x18 )
2012-07-05 21:36:32 +10:00
mode & = ~ PCI_AGP_COMMAND_FW ;
/*
* AGP mode set in the command line .
*/
if ( nouveau_agpmode > 0 ) {
bool agpv3 = mode & 0x8 ;
int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode ;
mode = ( mode & ~ 0x7 ) | ( rate & 0x7 ) ;
}
return mode ;
}
static bool
2012-07-11 10:44:20 +10:00
nouveau_agp_enabled ( struct nouveau_drm * drm )
2012-07-05 21:36:32 +10:00
{
2012-07-11 10:44:20 +10:00
struct drm_device * dev = drm - > dev ;
2012-07-05 21:36:32 +10:00
if ( ! drm_pci_device_is_agp ( dev ) | | ! dev - > agp )
return false ;
2012-07-11 10:44:20 +10:00
if ( drm - > agp . stat = = UNKNOWN ) {
2012-07-05 21:36:32 +10:00
if ( ! nouveau_agpmode )
return false ;
2013-02-26 02:33:11 +01:00
# ifdef __powerpc__
/* Disable AGP by default on all PowerPC machines for
* now - - At least some UniNorth - 2 AGP bridges are
* known to be broken : DMA from the host to the card
* works just fine , but writeback from the card to the
* host goes straight to memory untranslated bypassing
* the GATT somehow , making them quite painful to deal
* with . . .
*/
if ( nouveau_agpmode = = - 1 )
return false ;
# endif
2012-07-11 10:44:20 +10:00
return true ;
2012-07-05 21:36:32 +10:00
}
2012-07-11 10:44:20 +10:00
return ( drm - > agp . stat = = ENABLED ) ;
2012-07-05 21:36:32 +10:00
}
# endif
void
2012-07-11 10:44:20 +10:00
nouveau_agp_reset ( struct nouveau_drm * drm )
2012-07-05 21:36:32 +10:00
{
# if __OS_HAS_AGP
2012-07-11 10:44:20 +10:00
struct nouveau_device * device = nv_device ( drm - > device ) ;
struct drm_device * dev = drm - > dev ;
2012-07-05 21:36:32 +10:00
u32 save [ 2 ] ;
int ret ;
2012-07-11 10:44:20 +10:00
if ( ! nouveau_agp_enabled ( drm ) )
2012-07-05 21:36:32 +10:00
return ;
/* First of all, disable fast writes, otherwise if it's
* already enabled in the AGP bridge and we disable the card ' s
* AGP controller we might be locking ourselves out of it . */
2012-07-11 10:44:20 +10:00
if ( ( nv_rd32 ( device , NV04_PBUS_PCI_NV_19 ) |
2012-07-05 21:36:32 +10:00
dev - > agp - > mode ) & PCI_AGP_COMMAND_FW ) {
struct drm_agp_info info ;
struct drm_agp_mode mode ;
ret = drm_agp_info ( dev , & info ) ;
if ( ret )
return ;
2012-07-11 10:44:20 +10:00
mode . mode = get_agp_mode ( drm , info . mode ) ;
2012-07-05 21:36:32 +10:00
mode . mode & = ~ PCI_AGP_COMMAND_FW ;
ret = drm_agp_enable ( dev , mode ) ;
if ( ret )
return ;
}
/* clear busmaster bit, and disable AGP */
2012-07-11 10:44:20 +10:00
save [ 0 ] = nv_mask ( device , NV04_PBUS_PCI_NV_1 , 0x00000004 , 0x00000000 ) ;
nv_wr32 ( device , NV04_PBUS_PCI_NV_19 , 0 ) ;
2012-07-05 21:36:32 +10:00
/* reset PGRAPH, PFIFO and PTIMER */
2012-07-11 10:44:20 +10:00
save [ 1 ] = nv_mask ( device , 0x000200 , 0x00011100 , 0x00000000 ) ;
nv_mask ( device , 0x000200 , 0x00011100 , save [ 1 ] ) ;
2012-07-05 21:36:32 +10:00
/* and restore bustmaster bit (gives effect of resetting AGP) */
2012-07-11 10:44:20 +10:00
nv_wr32 ( device , NV04_PBUS_PCI_NV_1 , save [ 0 ] ) ;
2012-07-05 21:36:32 +10:00
# endif
}
void
2012-07-11 10:44:20 +10:00
nouveau_agp_init ( struct nouveau_drm * drm )
2012-07-05 21:36:32 +10:00
{
# if __OS_HAS_AGP
2012-07-11 10:44:20 +10:00
struct nouveau_device * device = nv_device ( drm - > device ) ;
struct drm_device * dev = drm - > dev ;
2012-07-05 21:36:32 +10:00
struct drm_agp_info info ;
struct drm_agp_mode mode ;
int ret ;
2012-07-11 10:44:20 +10:00
if ( ! nouveau_agp_enabled ( drm ) )
2012-07-05 21:36:32 +10:00
return ;
2012-07-11 10:44:20 +10:00
drm - > agp . stat = DISABLE ;
2012-07-05 21:36:32 +10:00
ret = drm_agp_acquire ( dev ) ;
if ( ret ) {
2012-07-11 10:44:20 +10:00
nv_error ( device , " unable to acquire AGP: %d \n " , ret ) ;
2012-07-05 21:36:32 +10:00
return ;
}
ret = drm_agp_info ( dev , & info ) ;
if ( ret ) {
2012-07-11 10:44:20 +10:00
nv_error ( device , " unable to get AGP info: %d \n " , ret ) ;
2012-07-05 21:36:32 +10:00
return ;
}
/* see agp.h for the AGPSTAT_* modes available */
2012-07-11 10:44:20 +10:00
mode . mode = get_agp_mode ( drm , info . mode ) ;
2012-07-05 21:36:32 +10:00
ret = drm_agp_enable ( dev , mode ) ;
if ( ret ) {
2012-07-11 10:44:20 +10:00
nv_error ( device , " unable to enable AGP: %d \n " , ret ) ;
2012-07-05 21:36:32 +10:00
return ;
}
2012-07-11 10:44:20 +10:00
drm - > agp . stat = ENABLED ;
drm - > agp . base = info . aperture_base ;
drm - > agp . size = info . aperture_size ;
2012-07-05 21:36:32 +10:00
# endif
}
void
2012-07-11 10:44:20 +10:00
nouveau_agp_fini ( struct nouveau_drm * drm )
2012-07-05 21:36:32 +10:00
{
# if __OS_HAS_AGP
2012-07-11 10:44:20 +10:00
struct drm_device * dev = drm - > dev ;
2012-07-05 21:36:32 +10:00
if ( dev - > agp & & dev - > agp - > acquired )
drm_agp_release ( dev ) ;
# endif
}