2005-05-01 19:58:49 +04:00
/*
* This is a good place to put board specific reboot fixups .
*
* List of supported fixups :
* geode - gx1 / cs5530a - Jaya Kumar < jayalk @ intworks . biz >
2007-07-06 22:17:30 +04:00
* geode - gx / lx / cs5536 - Andres Salomon < dilinger @ debian . org >
2005-05-01 19:58:49 +04:00
*
*/
# include <asm/delay.h>
# include <linux/pci.h>
2007-08-07 13:13:18 +04:00
# include <linux/interrupt.h>
2007-05-02 21:27:06 +04:00
# include <asm/reboot_fixups.h>
2007-07-06 22:17:30 +04:00
# include <asm/msr.h>
2009-12-15 05:00:39 +03:00
# include <linux/cs5535.h>
2005-05-01 19:58:49 +04:00
static void cs5530a_warm_reset ( struct pci_dev * dev )
{
/* writing 1 to the reset control register, 0x44 causes the
cs5530a to perform a system warm reset */
pci_write_config_byte ( dev , 0x44 , 0x1 ) ;
udelay ( 50 ) ; /* shouldn't get here but be safe and spin-a-while */
return ;
}
2007-07-06 22:17:30 +04:00
static void cs5536_warm_reset ( struct pci_dev * dev )
{
2007-10-18 23:26:51 +04:00
/* writing 1 to the LSB of this MSR causes a hard reset */
wrmsrl ( MSR_DIVIL_SOFT_RESET , 1ULL ) ;
2007-07-06 22:17:30 +04:00
udelay ( 50 ) ; /* shouldn't get here but be safe and spin a while */
}
2008-01-30 15:33:36 +03:00
static void rdc321x_reset ( struct pci_dev * dev )
{
unsigned i ;
/* Voluntary reset the watchdog timer */
outl ( 0x80003840 , 0xCF8 ) ;
/* Generate a CPU reset on next tick */
i = inl ( 0xCFC ) ;
/* Use the minimum timer resolution */
i | = 0x1600 ;
outl ( i , 0xCFC ) ;
outb ( 1 , 0x92 ) ;
}
2010-11-09 23:08:08 +03:00
static void ce4100_reset ( struct pci_dev * dev )
{
int i ;
for ( i = 0 ; i < 10 ; i + + ) {
outb ( 0x2 , 0xcf9 ) ;
udelay ( 50 ) ;
}
}
2005-05-01 19:58:49 +04:00
struct device_fixup {
unsigned int vendor ;
unsigned int device ;
void ( * reboot_fixup ) ( struct pci_dev * ) ;
} ;
2010-11-09 23:08:08 +03:00
/*
* PCI ids solely used for fixups_table go here
*/
# define PCI_DEVICE_ID_INTEL_CE4100 0x0708
2008-05-12 17:43:38 +04:00
static const struct device_fixup fixups_table [ ] = {
2005-05-01 19:58:49 +04:00
{ PCI_VENDOR_ID_CYRIX , PCI_DEVICE_ID_CYRIX_5530_LEGACY , cs5530a_warm_reset } ,
2007-07-06 22:17:30 +04:00
{ PCI_VENDOR_ID_AMD , PCI_DEVICE_ID_AMD_CS5536_ISA , cs5536_warm_reset } ,
2007-11-17 18:27:02 +03:00
{ PCI_VENDOR_ID_NS , PCI_DEVICE_ID_NS_SC1100_BRIDGE , cs5530a_warm_reset } ,
2008-01-30 15:33:36 +03:00
{ PCI_VENDOR_ID_RDC , PCI_DEVICE_ID_RDC_R6030 , rdc321x_reset } ,
2010-11-09 23:08:08 +03:00
{ PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_CE4100 , ce4100_reset } ,
2005-05-01 19:58:49 +04:00
} ;
/*
* we see if any fixup is available for our current hardware . if there
* is a fixup , we call it and we expect to never return from it . if we
* do return , we keep looking and then eventually fall back to the
* standard mach_reboot on return .
*/
void mach_reboot_fixups ( void )
{
2008-05-12 17:43:38 +04:00
const struct device_fixup * cur ;
2005-05-01 19:58:49 +04:00
struct pci_dev * dev ;
int i ;
2007-08-07 13:13:18 +04:00
/* we can be called from sysrq-B code. In such a case it is
* prohibited to dig PCI */
if ( in_interrupt ( ) )
return ;
2005-11-07 11:58:31 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( fixups_table ) ; i + + ) {
2005-05-01 19:58:49 +04:00
cur = & ( fixups_table [ i ] ) ;
2005-10-31 02:03:29 +03:00
dev = pci_get_device ( cur - > vendor , cur - > device , NULL ) ;
2005-05-01 19:58:49 +04:00
if ( ! dev )
continue ;
cur - > reboot_fixup ( dev ) ;
2009-12-03 14:06:40 +03:00
pci_dev_put ( dev ) ;
2005-05-01 19:58:49 +04:00
}
}