2005-04-17 02:20:36 +04:00
/*
* ALi AGPGART routines .
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/agp_backend.h>
2005-10-31 02:03:48 +03:00
# include <asm/page.h> /* PAGE_SIZE */
2005-04-17 02:20:36 +04:00
# include "agp.h"
# define ALI_AGPCTRL 0xb8
# define ALI_ATTBASE 0xbc
# define ALI_TLBCTRL 0xc0
# define ALI_TAGCTRL 0xc4
# define ALI_CACHE_FLUSH_CTRL 0xD0
# define ALI_CACHE_FLUSH_ADDR_MASK 0xFFFFF000
# define ALI_CACHE_FLUSH_EN 0x100
static int ali_fetch_size ( void )
{
int i ;
u32 temp ;
struct aper_size_info_32 * values ;
pci_read_config_dword ( agp_bridge - > dev , ALI_ATTBASE , & temp ) ;
temp & = ~ ( 0xfffffff0 ) ;
values = A_SIZE_32 ( agp_bridge - > driver - > aperture_sizes ) ;
for ( i = 0 ; i < agp_bridge - > driver - > num_aperture_sizes ; i + + ) {
if ( temp = = values [ i ] . size_value ) {
agp_bridge - > previous_size =
agp_bridge - > current_size = ( void * ) ( values + i ) ;
agp_bridge - > aperture_size_idx = i ;
return values [ i ] . size ;
}
}
return 0 ;
}
static void ali_tlbflush ( struct agp_memory * mem )
{
u32 temp ;
pci_read_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , & temp ) ;
temp & = 0xfffffff0 ;
temp | = ( 1 < < 0 | 1 < < 1 ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_TAGCTRL , temp ) ;
}
static void ali_cleanup ( void )
{
struct aper_size_info_32 * previous_size ;
u32 temp ;
previous_size = A_SIZE_32 ( agp_bridge - > previous_size ) ;
pci_read_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , & temp ) ;
// clear tag
pci_write_config_dword ( agp_bridge - > dev , ALI_TAGCTRL ,
( ( temp & 0xffffff00 ) | 0x00000001 | 0x00000002 ) ) ;
pci_read_config_dword ( agp_bridge - > dev , ALI_ATTBASE , & temp ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_ATTBASE ,
( ( temp & 0x00000ff0 ) | previous_size - > size_value ) ) ;
}
static int ali_configure ( void )
{
u32 temp ;
struct aper_size_info_32 * current_size ;
current_size = A_SIZE_32 ( agp_bridge - > current_size ) ;
/* aperture size and gatt addr */
pci_read_config_dword ( agp_bridge - > dev , ALI_ATTBASE , & temp ) ;
temp = ( ( ( temp & 0x00000ff0 ) | ( agp_bridge - > gatt_bus_addr & 0xfffff000 ) )
| ( current_size - > size_value & 0xf ) ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_ATTBASE , temp ) ;
/* tlb control */
pci_read_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , & temp ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , ( ( temp & 0xffffff00 ) | 0x00000010 ) ) ;
/* address to map to */
2014-01-04 05:26:58 +04:00
agp_bridge - > gart_bus_addr = pci_bus_address ( agp_bridge - > dev ,
AGP_APERTURE_BAR ) ;
2005-04-17 02:20:36 +04:00
#if 0
if ( agp_bridge - > type = = ALI_M1541 ) {
u32 nlvm_addr = 0 ;
switch ( current_size - > size_value ) {
case 0 : break ;
case 1 : nlvm_addr = 0x100000 ; break ;
case 2 : nlvm_addr = 0x200000 ; break ;
case 3 : nlvm_addr = 0x400000 ; break ;
case 4 : nlvm_addr = 0x800000 ; break ;
case 6 : nlvm_addr = 0x1000000 ; break ;
case 7 : nlvm_addr = 0x2000000 ; break ;
case 8 : nlvm_addr = 0x4000000 ; break ;
case 9 : nlvm_addr = 0x8000000 ; break ;
case 10 : nlvm_addr = 0x10000000 ; break ;
default : break ;
}
nlvm_addr - - ;
nlvm_addr & = 0xfff00000 ;
nlvm_addr + = agp_bridge - > gart_bus_addr ;
nlvm_addr | = ( agp_bridge - > gart_bus_addr > > 12 ) ;
2008-07-30 23:26:51 +04:00
dev_info ( & agp_bridge - > dev - > dev , " nlvm top &base = %8x \n " ,
nlvm_addr ) ;
2005-04-17 02:20:36 +04:00
}
# endif
pci_read_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , & temp ) ;
temp & = 0xffffff7f ; //enable TLB
pci_write_config_dword ( agp_bridge - > dev , ALI_TLBCTRL , temp ) ;
return 0 ;
}
static void m1541_cache_flush ( void )
{
int i , page_count ;
u32 temp ;
global_cache_flush ( ) ;
page_count = 1 < < A_SIZE_32 ( agp_bridge - > current_size ) - > page_order ;
for ( i = 0 ; i < PAGE_SIZE * page_count ; i + = PAGE_SIZE ) {
pci_read_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL ,
& temp ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL ,
( ( ( temp & ALI_CACHE_FLUSH_ADDR_MASK ) |
( agp_bridge - > gatt_bus_addr + i ) ) |
ALI_CACHE_FLUSH_EN ) ) ;
}
}
2009-06-12 08:11:41 +04:00
static struct page * m1541_alloc_page ( struct agp_bridge_data * bridge )
2005-04-17 02:20:36 +04:00
{
2009-06-12 08:11:41 +04:00
struct page * page = agp_generic_alloc_page ( agp_bridge ) ;
2005-04-17 02:20:36 +04:00
u32 temp ;
2009-06-12 08:11:41 +04:00
if ( ! page )
2005-04-17 02:20:36 +04:00
return NULL ;
2006-02-28 08:54:25 +03:00
2005-04-17 02:20:36 +04:00
pci_read_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL , & temp ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL ,
( ( ( temp & ALI_CACHE_FLUSH_ADDR_MASK ) |
2009-07-29 13:25:58 +04:00
page_to_phys ( page ) ) | ALI_CACHE_FLUSH_EN ) ) ;
2009-06-12 08:11:41 +04:00
return page ;
2005-04-17 02:20:36 +04:00
}
2009-06-12 08:11:41 +04:00
static void ali_destroy_page ( struct page * page , int flags )
2005-04-17 02:20:36 +04:00
{
2009-06-12 08:11:41 +04:00
if ( page ) {
2007-10-15 04:19:16 +04:00
if ( flags & AGP_PAGE_DESTROY_UNMAP ) {
global_cache_flush ( ) ; /* is this really needed? --hch */
2009-06-12 08:11:41 +04:00
agp_generic_destroy_page ( page , flags ) ;
2007-10-15 04:19:16 +04:00
} else
2009-06-12 08:11:41 +04:00
agp_generic_destroy_page ( page , flags ) ;
2005-04-17 02:20:36 +04:00
}
}
2009-06-12 08:11:41 +04:00
static void m1541_destroy_page ( struct page * page , int flags )
2005-04-17 02:20:36 +04:00
{
u32 temp ;
2009-06-12 08:11:41 +04:00
if ( page = = NULL )
2005-04-17 02:20:36 +04:00
return ;
2007-10-15 04:19:16 +04:00
if ( flags & AGP_PAGE_DESTROY_UNMAP ) {
global_cache_flush ( ) ;
2005-04-17 02:20:36 +04:00
2007-10-15 04:19:16 +04:00
pci_read_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL , & temp ) ;
pci_write_config_dword ( agp_bridge - > dev , ALI_CACHE_FLUSH_CTRL ,
( ( ( temp & ALI_CACHE_FLUSH_ADDR_MASK ) |
2009-07-29 13:25:58 +04:00
page_to_phys ( page ) ) | ALI_CACHE_FLUSH_EN ) ) ;
2007-10-15 04:19:16 +04:00
}
2009-06-12 08:11:41 +04:00
agp_generic_destroy_page ( page , flags ) ;
2005-04-17 02:20:36 +04:00
}
/* Setup function */
2007-02-23 02:41:28 +03:00
static const struct aper_size_info_32 ali_generic_sizes [ 7 ] =
2005-04-17 02:20:36 +04:00
{
{ 256 , 65536 , 6 , 10 } ,
{ 128 , 32768 , 5 , 9 } ,
{ 64 , 16384 , 4 , 8 } ,
{ 32 , 8192 , 3 , 7 } ,
{ 16 , 4096 , 2 , 6 } ,
{ 8 , 2048 , 1 , 4 } ,
{ 4 , 1024 , 0 , 3 }
} ;
2007-02-23 02:41:28 +03:00
static const struct agp_bridge_driver ali_generic_bridge = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. aperture_sizes = ali_generic_sizes ,
. size_type = U32_APER_SIZE ,
. num_aperture_sizes = 7 ,
2010-04-20 19:43:34 +04:00
. needs_scratch_page = true ,
2005-04-17 02:20:36 +04:00
. configure = ali_configure ,
. fetch_size = ali_fetch_size ,
. cleanup = ali_cleanup ,
. tlb_flush = ali_tlbflush ,
. mask_memory = agp_generic_mask_memory ,
. masks = NULL ,
. agp_enable = agp_generic_enable ,
. cache_flush = global_cache_flush ,
. create_gatt_table = agp_generic_create_gatt_table ,
. free_gatt_table = agp_generic_free_gatt_table ,
. insert_memory = agp_generic_insert_memory ,
. remove_memory = agp_generic_remove_memory ,
. alloc_by_type = agp_generic_alloc_by_type ,
. free_by_type = agp_generic_free_by_type ,
. agp_alloc_page = agp_generic_alloc_page ,
. agp_destroy_page = ali_destroy_page ,
2007-01-23 12:33:43 +03:00
. agp_type_to_mask_type = agp_generic_type_to_mask_type ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-23 02:41:28 +03:00
static const struct agp_bridge_driver ali_m1541_bridge = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. aperture_sizes = ali_generic_sizes ,
. size_type = U32_APER_SIZE ,
. num_aperture_sizes = 7 ,
. configure = ali_configure ,
. fetch_size = ali_fetch_size ,
. cleanup = ali_cleanup ,
. tlb_flush = ali_tlbflush ,
. mask_memory = agp_generic_mask_memory ,
. masks = NULL ,
. agp_enable = agp_generic_enable ,
. cache_flush = m1541_cache_flush ,
. create_gatt_table = agp_generic_create_gatt_table ,
. free_gatt_table = agp_generic_free_gatt_table ,
. insert_memory = agp_generic_insert_memory ,
. remove_memory = agp_generic_remove_memory ,
. alloc_by_type = agp_generic_alloc_by_type ,
. free_by_type = agp_generic_free_by_type ,
. agp_alloc_page = m1541_alloc_page ,
. agp_destroy_page = m1541_destroy_page ,
2007-01-23 12:33:43 +03:00
. agp_type_to_mask_type = agp_generic_type_to_mask_type ,
2005-04-17 02:20:36 +04:00
} ;
2012-11-19 22:24:36 +04:00
static struct agp_device_ids ali_agp_device_ids [ ] =
2005-04-17 02:20:36 +04:00
{
{
. device_id = PCI_DEVICE_ID_AL_M1541 ,
. chipset_name = " M1541 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1621 ,
. chipset_name = " M1621 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1631 ,
. chipset_name = " M1631 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1632 ,
. chipset_name = " M1632 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1641 ,
. chipset_name = " M1641 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1644 ,
. chipset_name = " M1644 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1647 ,
. chipset_name = " M1647 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1651 ,
. chipset_name = " M1651 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1671 ,
. chipset_name = " M1671 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1681 ,
. chipset_name = " M1681 " ,
} ,
{
. device_id = PCI_DEVICE_ID_AL_M1683 ,
. chipset_name = " M1683 " ,
} ,
{ } , /* dummy final entry, always present */
} ;
2012-12-22 03:12:08 +04:00
static int agp_ali_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
struct agp_device_ids * devs = ali_agp_device_ids ;
struct agp_bridge_data * bridge ;
u8 hidden_1621_id , cap_ptr ;
int j ;
cap_ptr = pci_find_capability ( pdev , PCI_CAP_ID_AGP ) ;
if ( ! cap_ptr )
return - ENODEV ;
/* probe for known chipsets */
for ( j = 0 ; devs [ j ] . chipset_name ; j + + ) {
if ( pdev - > device = = devs [ j ] . device_id )
goto found ;
}
2008-07-30 23:26:51 +04:00
dev_err ( & pdev - > dev , " unsupported ALi chipset [%04x/%04x]) \n " ,
pdev - > vendor , pdev - > device ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
found :
bridge = agp_alloc_bridge ( ) ;
if ( ! bridge )
return - ENOMEM ;
bridge - > dev = pdev ;
bridge - > capndx = cap_ptr ;
switch ( pdev - > device ) {
case PCI_DEVICE_ID_AL_M1541 :
bridge - > driver = & ali_m1541_bridge ;
break ;
case PCI_DEVICE_ID_AL_M1621 :
pci_read_config_byte ( pdev , 0xFB , & hidden_1621_id ) ;
switch ( hidden_1621_id ) {
case 0x31 :
devs [ j ] . chipset_name = " M1631 " ;
break ;
case 0x32 :
devs [ j ] . chipset_name = " M1632 " ;
break ;
case 0x41 :
devs [ j ] . chipset_name = " M1641 " ;
break ;
case 0x43 :
2009-06-10 23:41:11 +04:00
devs [ j ] . chipset_name = " M1621 " ;
2005-04-17 02:20:36 +04:00
break ;
case 0x47 :
devs [ j ] . chipset_name = " M1647 " ;
break ;
case 0x51 :
devs [ j ] . chipset_name = " M1651 " ;
break ;
default :
break ;
}
/*FALLTHROUGH*/
default :
bridge - > driver = & ali_generic_bridge ;
}
2008-07-30 23:26:51 +04:00
dev_info ( & pdev - > dev , " ALi %s chipset \n " , devs [ j ] . chipset_name ) ;
2005-04-17 02:20:36 +04:00
/* Fill in the mode register */
pci_read_config_dword ( pdev ,
bridge - > capndx + PCI_AGP_STATUS ,
& bridge - > mode ) ;
pci_set_drvdata ( pdev , bridge ) ;
return agp_add_bridge ( bridge ) ;
}
2012-11-19 22:26:26 +04:00
static void agp_ali_remove ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
struct agp_bridge_data * bridge = pci_get_drvdata ( pdev ) ;
agp_remove_bridge ( bridge ) ;
agp_put_bridge ( bridge ) ;
}
static struct pci_device_id agp_ali_pci_table [ ] = {
{
. class = ( PCI_CLASS_BRIDGE_HOST < < 8 ) ,
. class_mask = ~ 0 ,
. vendor = PCI_VENDOR_ID_AL ,
. device = PCI_ANY_ID ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( pci , agp_ali_pci_table ) ;
static struct pci_driver agp_ali_pci_driver = {
. name = " agpgart-ali " ,
. id_table = agp_ali_pci_table ,
. probe = agp_ali_probe ,
. remove = agp_ali_remove ,
} ;
static int __init agp_ali_init ( void )
{
if ( agp_off )
return - EINVAL ;
return pci_register_driver ( & agp_ali_pci_driver ) ;
}
static void __exit agp_ali_cleanup ( void )
{
pci_unregister_driver ( & agp_ali_pci_driver ) ;
}
module_init ( agp_ali_init ) ;
module_exit ( agp_ali_cleanup ) ;
2008-10-20 21:31:45 +04:00
MODULE_AUTHOR ( " Dave Jones <davej@redhat.com> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL and additional rights " ) ;