/******************************************************************************* NAME pchLpcDiag.c SUMMARY Ibex Peak LPC interface function diagnostics VERSION %version: 1 % UPDATE DATE %date_modified: Jun 5 15:00 2009 % PROGRAMMER %created_by: Jim Tu % Copyright 2009 Quanta Corporation. All Rights Reserved. DESCRIPTION: This file has code to test Ibex Peak LPC interface NOTES: REFERENCE: *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "commPciChip.h" #include "pchDiag.h" //EXTERN int a20_test_short( void ); //EXTERN BOOLEAN sataD3ModeTest( void ); //EXTERN BOOLEAN usbD3ModeTest( void ); #define PCH_SOYUZ 0 #define PCH_PIKESPEAK 1 volatile void *gPchRcbaVirtualP = NULL; volatile int gPlatform = NULL; static struct rtc_time s_rtc_time; /********************************/ /** Register Access Function **/ /********************************/ void pchRegShow(unsigned short device, unsigned char offset) { struct pci_dev* pdev = NULL; unsigned char value; while ((pdev = pci_get_device(INTEL_VENDOR_ID, device, pdev))) { pci_read_config_byte(pdev, offset, &value); printk("[PCH] device: 0x%04X, offset: %02Xh, value: %02X\n", device, offset, value); } if(pdev == NULL) { printk("[PCH] cannot get device\n"); } } int pchRcbaAllocate( void ) { struct pci_dev *pdev = NULL; u32 pchRcbaVirtual; // Get LPC PCI device pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_LPC_DEVICE_ID, NULL ); if( !pdev ) { // Try old ID pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_LPC_DEVICE_ID_OLD, NULL ); if (pdev) { printk( "Cannot find Patsburg LPC device(%4.4X), you might be running PROTO 1.1\n", INTEL_PATSBURG_LPC_DEVICE_ID ); printk( "Please run with PROTO 1.2 or above Soyuz board revision\n" ); } } if ( !pdev ){ pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_LPC_DEVICE_ID, NULL ); } if( pdev ) { pci_read_config_dword( pdev, PCH_RCBA_OFFSET, &pchRcbaVirtual ); switch (pdev->device) { case INTEL_IBX_LPC_DEVICE_ID: gPchRcbaVirtualP = ioremap_nocache( (UINT64)pchRcbaVirtual, IBX_RCBA_LENGTH ); gPlatform = PCH_PIKESPEAK; return 0; break; case INTEL_PATSBURG_LPC_DEVICE_ID: case INTEL_PATSBURG_LPC_DEVICE_ID_OLD: gPchRcbaVirtualP = ioremap_nocache( (UINT64)pchRcbaVirtual - 1, PATSBURG_RCBA_LENGTH ); gPlatform = PCH_SOYUZ; return 0; break; } } // Error printk("[PCH] cannot get RCBA device\n"); commReportError(MEC_PATSBURG, PATSBURG_LPC_MEC, PATSBURG_PCI_NO_DEVICE_ERROR, MSG_PATSBURG_PCI_NO_DEVICE_ERROR, 0, 0, 0, 0); return -ENODEV; } void pchChipConfigRegShow(unsigned short offset) { printk("data = 0x%02X \n ",*(volatile unsigned char*)(gPchRcbaVirtualP + offset)); } /***********************************/ /** DMI Interface Test Function **/ /***********************************/ /******************************************/ /** PCI-Express Register Test Function **/ /******************************************/ /******************************************************************************* * PROCEDURE * * NAME: patsburgDmiLaneVerify * SUMMARY: Verification of DMI link width of PATSBURG * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchDmiLaneVerify( void ) { unsigned char temp; if( !gPchRcbaVirtualP ) goto ErrExit; if( gPlatform == PCH_PIKESPEAK ) { temp = *(volatile unsigned char *)(gPchRcbaVirtualP + IBX_DMI_LSTS_OFFSET); if(temp != PCH_PCIE_X4_LINK_WIDTH) { printk("[IBX] DMI lanes: %d\n", ((temp & 0xF0) >> 4)); printk("[IBX] temp: %d\n", temp); commReportError(MEC_PATSBURG, PATSBURG_PROCESSOR_INTERFACE_MEC, PATSBURG_PCI_WRONG_LANE_ERROR, MSG_PATSBURG_PCI_WRONG_LANE_ERROR, 0, 0, 0, 0); return FALSE; } } else if( gPlatform == PCH_SOYUZ ) { temp = *(volatile unsigned char *)(gPchRcbaVirtualP + PATSBURG_DMI_LSTS_OFFSET); if(temp != PATSBURG_DMI_X4_LINK_WIDTH) { printk("[PATSBURG] DMI lanes: %d\n", ((temp & 0xF0) >> 4)); printk("[PATSBURG] temp: %d\n", temp); commReportError(MEC_PATSBURG, PATSBURG_PROCESSOR_INTERFACE_MEC, PATSBURG_PCI_WRONG_LANE_ERROR, MSG_PATSBURG_PCI_WRONG_LANE_ERROR, 0, 0, 0, 0); return FALSE; } } else { ErrExit: // No device printk( "Cannot get PCH Device\n" ); commReportError(MEC_PATSBURG, PATSBURG_PROCESSOR_INTERFACE_MEC, PATSBURG_PCI_NO_DEVICE_ERROR, MSG_PATSBURG_PCI_NO_DEVICE_ERROR, 0, 0, 0, 0); return FALSE; } return TRUE; } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieRegReadTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPcieRegReadTest( void ) { return (pciRegTest(NIC_INTEL_82576, pciReadTest)); } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieAddressLineTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPcieAddressLineTest( void ) { return (pciRegTest(NIC_INTEL_82576, pciAddressLineTest)); } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieDataLineTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPcieDataLineTest( void ) { return (pciRegTest(NIC_INTEL_82576, pciDataLineTest)); } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieLaneVerify * SUMMARY: Verification of PCIE link width of PATSBURG * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPcieLaneVerify( void ) { struct pci_dev* pdev = NULL; unsigned char value; unsigned char lane_width=PCH_PCIE_X1_LINK_WIDTH; BOOLEAN result = TRUE; // Get Patsburg PCI-E Bridge pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_PCIE_PORT_1_DEVICE_ID, NULL ); if( !pdev ) { pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_PCIE_PORT_1_DEVICE_ID, NULL ); lane_width=PCH_PCIE_X4_LINK_WIDTH; } if( !pdev ) { printk( "[PCH] cannot get PCI-E root device\n" ); commReportError( MEC_PATSBURG, PATSBURG_PCIE_MEC, PATSBURG_PCI_NO_DEVICE_ERROR, MSG_PATSBURG_PCI_NO_DEVICE_ERROR, 0, 0, 0, 0 ); result = FALSE; goto ErrExit; } // Read Link status register pci_read_config_byte( pdev, PCH_PCIE_LSTS_OFFSET, &value ); if( value != lane_width ) { printk( "[PCH] PCIE lanes to 82576 Ethernet: %d\n", ((value & 0xF0) >> 4) ); commReportError( MEC_PATSBURG, PATSBURG_PCIE_MEC, PATSBURG_PCI_WRONG_LANE_ERROR, MSG_PATSBURG_PCI_WRONG_LANE_ERROR, 0, 0, 0, 0 ); result = FALSE; } ErrExit: //printk("[PATSBURG] PCIE lanes to 82576 Ethernet: %d\n", ((value & 0xF0) >> 4)); return result; } /**********************************/ /** PCI Register Test Function **/ /**********************************/ /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieRegReadTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPciRegReadTest( void ) { return (pciRegTest(NETAPP_ROCKET_FPGA, pciReadTest)); } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieAddressLineTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPciAddressLineTest( void ) { return (pciRegTest(NETAPP_ROCKET_FPGA, pciAddressLineTest)); } /******************************************************************************* * PROCEDURE * * NAME: patsburgPcieDataLineTest * SUMMARY: Generic pci register test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchPciDataLineTest( void ) { return (pciRegTest(NETAPP_ROCKET_FPGA, pciDataLineTest)); } /**************************/ /** ACPI Test Function **/ /**************************/ /******************************************************************************* * PROCEDURE * * NAME: pchAcpiD3ModeSet * SUMMARY: set device into D3 state * * SCOPE: Public * * DESCRIPTION: write the power management register of device to force device * into D3 state * * RETURNS: * * NOTES: * */ int pchAcpiD3ModeSet ( struct pci_dev* pdev, int status ) { int result = TRUE; unsigned char value; if (pdev->vendor != INTEL_VENDOR_ID) { printk("[PATSBURG ACPI] The device doesn't exist.\n"); } else { switch (pdev->device) { //NIC 82579 Controller case INTEL_PATSBURG_NIC_82579_DEVICE_ID: case INTEL_IBX_NIC_82577_DEVICE_ID: /* read original config from PMCS */ pci_read_config_byte(pdev, PCH_NIC_E1000_PMCS_OFFSET, &value); /* set power state */ if (status) { value |= PCH_PMCS_D3_STATE; } else { value &= PCH_PMCS_D0_STATE; } /* write new config to PMCS */ pci_write_config_byte(pdev, PCH_NIC_E1000_PMCS_OFFSET, value); break; //SATA Controller case INTEL_PATSBURG_SATA_AHCI_DEVICE_ID: case INTEL_IBX_SATA_AHCI_DEVICE_ID: /* read original config from PMCS */ pci_read_config_byte(pdev, PCH_SATA_PMCS_OFFSET, &value); /* set power state */ if (status) { value |= PCH_PMCS_D3_STATE; } else { value &= PCH_PMCS_D0_STATE; } /* write new config to PMCS */ pci_write_config_byte(pdev, PCH_SATA_PMCS_OFFSET, value); break; //USB Controller case INTEL_PATSBURG_EHCI_1_DEVICE_ID: case INTEL_PATSBURG_EHCI_2_DEVICE_ID: case INTEL_IBX_EHCI_1_DEVICE_ID: case INTEL_IBX_EHCI_2_DEVICE_ID: /* read original config from PMCS */ pci_read_config_byte(pdev, PCH_EHCI_PMCS_OFFSET, &value); /* set power state */ if (status) { value |= PCH_PMCS_D3_STATE; } else { value &= PCH_PMCS_D0_STATE; } /* write new config to PMCS */ pci_write_config_byte(pdev, PCH_EHCI_PMCS_OFFSET, value); break; //PCI-Express Port Controller case INTEL_PATSBURG_PCIE_PORT_1_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_2_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_3_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_4_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_5_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_6_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_7_DEVICE_ID: case INTEL_PATSBURG_PCIE_PORT_8_DEVICE_ID: case INTEL_IBX_PCIE_PORT_1_DEVICE_ID: /* read original config from PMCS */ pci_read_config_byte(pdev, PCH_PCIE_PORT_PMCS_OFFSET, &value); /* set power state */ if (status) { value |= PCH_PMCS_D3_STATE; } else { value &= PCH_PMCS_D0_STATE; } /* write new config to PMCS */ pci_write_config_byte(pdev, PCH_PCIE_PORT_PMCS_OFFSET, value); break; //Thermal Subsystem case INTEL_PATSBURG_THERMAL_DEVICE_ID: /* read original config from PMCS */ pci_read_config_byte(pdev, PATSBURG_THERMAL_PMCS_OFFSET, &value); /* set power state */ if (status) { value |= PCH_PMCS_D3_STATE; } else { value &= PCH_PMCS_D0_STATE; } /* write new config to PMCS */ pci_write_config_byte(pdev, PATSBURG_THERMAL_PMCS_OFFSET, value); break; //Other Device default: printk("[PCH ACPI] This device does not support D3 state in diagnostics.\n"); break; } } return result; } /******************************************************************************* * PROCEDURE * * NAME: patsburgAcpiD3StateDiag * SUMMARY: Ibex Peak D3 state test * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchAcpiD3StateDiag( void ) { int result = TRUE; struct pci_dev *sata, *usb, *pcie, *e1000; // Get SATA device sata = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_SATA_AHCI_DEVICE_ID, NULL ); if (sata) { // Get USB device usb = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_EHCI_1_DEVICE_ID, NULL ); // Get PCIE device pcie = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_PCIE_PORT_1_DEVICE_ID, NULL ); // Get NIC 82579 device e1000 = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_NIC_82579_DEVICE_ID, NULL ); }else{ // Get SATA device sata = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_SATA_AHCI_DEVICE_ID, NULL ); // Get USB device usb = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_EHCI_1_DEVICE_ID, NULL ); // Get PCIE device pcie = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_PCIE_PORT_1_DEVICE_ID, NULL ); // Get NIC 82579 device e1000 = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_NIC_82577_DEVICE_ID, NULL ); } // Sanity check if( !sata || !usb || !pcie || !e1000 ) goto ErrExit; /************************/ /* test SATA controller */ /************************/ disable_irq( sata->irq ); pchAcpiD3ModeSet( sata, TRUE ); //enable D3 state //if(sataD3ModeTest()) //{ // commReportError(MEC_PATSBURG, PATSBURG_POWER_MANAGEMENT_MEC, SATA_D3_MODE_ERROR, // MSG_SATA_D3_MODE_ERROR, 0, 0, 0, 0); // result = FALSE; //} pchAcpiD3ModeSet( sata, FALSE ); //enable D3 state enable_irq( sata->irq ); printk( "[PATSBURG][D3] SATA done.\n" ); /***********************/ /* test USB controller */ /***********************/ disable_irq( usb->irq ); pchAcpiD3ModeSet( usb, TRUE ); //enable D3 state //if(usbD3ModeTest()) // // commReportError(MEC_PATSBURG, PATSBURG_POWER_MANAGEMENT_MEC, USB_D3_MODE_ERROR, // MSG_USB_D3_MODE_ERROR, 0, 0, 0, 0); // result = FALSE; //} pchAcpiD3ModeSet( usb, FALSE ); //enable D3 state enable_irq( usb->irq ); printk( "[PATSBURG][D3] USB done.\n" ); #if 0 /*******************/ /* test PCI-E port */ /*******************/ disable_irq( pcie->irq ); pchAcpiD3ModeSet( pcie, TRUE ); //enable D3 state //verify PCI-E transfer: fix me pchAcpiD3ModeSet( pcie, FALSE ); //enable D3 state enable_irq( pcie->irq ); printk( "[PATSBURG][D3] PCI-E done.\n" ); #endif /******************/ /* test NIC 82579 */ /******************/ disable_irq( e1000->irq ); pchAcpiD3ModeSet( e1000, TRUE ); //enable D3 state //verify NIC transfer: fix me pchAcpiD3ModeSet( e1000, FALSE ); //enable D3 state enable_irq( e1000->irq ); printk( "[PCH][D3] e1000 done.\n" ); ErrExit: if( sata ) pci_dev_put( sata ); if( usb ) pci_dev_put( usb ); if( pcie ) pci_dev_put( pcie ); if( e1000 ) pci_dev_put( e1000 ); return result; } /**************************/ /** ACPI Test Function **/ /**************************/ /******************************************************************************* * PROCEDURE * * NAME: patsburgLpcRtcSetTarget * SUMMARY: set target register value to RTC port * * SCOPE: Public * * DESCRIPTION: set target register value to RTC port * * RETURNS: * * NOTES: * */ void pchLpcRtcSetTarget ( unsigned char pchRtcRegIndex, unsigned char target ) { //set register index outb(pchRtcRegIndex, PCH_RTC_1_INDEX_IOPORT); //set target value outb(target, PCH_RTC_1_TARGET_IOPORT); } /******************************************************************************* * PROCEDURE * * NAME: patsburgLpcRtcGetTarget * SUMMARY: get target register value from RTC port * * SCOPE: Public * * DESCRIPTION: get target register value from RTC port * * RETURNS: * * NOTES: * */ unsigned char pchLpcRtcGetTarget ( unsigned char pchRtcRegIndex ) { unsigned char target; //set register index outb(pchRtcRegIndex, PCH_RTC_1_INDEX_IOPORT); mdelay(1); //read target value target = inb(PCH_RTC_1_TARGET_IOPORT); //printk("[RTC] target: %02X \n", target); return target; } /******************************************************************************* * PROCEDURE * * NAME: patsburgLpcRtcSetDataMode * SUMMARY: Set RTC representation mode * * SCOPE: Public * * DESCRIPTION: Set RTC representation mode * * RETURNS: * * NOTES: 0: BCD * 1: Binary * */ void pchLpcRtcSetDataMode ( int mode ) { unsigned char temp; temp = pchLpcRtcGetTarget(PCH_RTC_REG_B_INDEX); if(mode == RTC_BCD_MODE) { temp = temp & (~RTC_DM_BIT); } else if(mode == RTC_BINARY_MODE) { temp = temp | RTC_DM_BIT; } else { printk("[RTC] Wrong representation mode.\n"); } pchLpcRtcSetTarget(PCH_RTC_REG_B_INDEX, temp); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcSetTime * SUMMARY: set time of the Ibex Peak real time clock * * SCOPE: Public * * DESCRIPTION: set time of the Ibex Peak real time clock * * RETURNS: * * NOTES: * */ void pchRtcSetTime ( struct rtc_time *tmP ) { unsigned char target, temp; //struct timespec tv; //set Update Cycle Inhibit target = pchLpcRtcGetTarget(PCH_RTC_REG_B_INDEX) | PCH_RTC_REG_B_SET_BIT; pchLpcRtcSetTarget(PCH_RTC_REG_B_INDEX, target); //set clock as binary mode and 24-hour mode target = pchLpcRtcGetTarget(PCH_RTC_REG_B_INDEX) | PCH_RTC_REG_B_HF_BIT; pchLpcRtcSetTarget(PCH_RTC_REG_B_INDEX, target); /*** set time to RTC ***/ temp = (((((unsigned char)(tmP->tm_year - 100)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_year - 100) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_YEAR_INDEX, temp); //year temp = (((((unsigned char)(tmP->tm_mon)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_mon) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_MONTH_INDEX, temp); //month temp = (((((unsigned char)(tmP->tm_mday)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_mday) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_DAY_OF_MONTH_INDEX, temp); //date //patsburgLpcRtcSetTarget(PATSBURG_RTC_DAY_OF_WEEK_INDEX, (unsigned char)(tmP->tm_wday + 1)); //weekday temp = (((((unsigned char)(tmP->tm_hour)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_hour) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_HOURS_INDEX, temp); //hour temp = (((((unsigned char)(tmP->tm_min)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_min) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_MINUTES_INDEX, temp); //minute temp = (((((unsigned char)(tmP->tm_sec)) / 10) << 4) & 0xF0) + (((unsigned char)(tmP->tm_sec) % 10) & 0x0F); pchLpcRtcSetTarget(PCH_RTC_SECONDS_INDEX, temp); //second //release Update Cycle Inhibit target = pchLpcRtcGetTarget(PCH_RTC_REG_B_INDEX) & (~PATSBURG_RTC_REG_B_SET_BIT); pchLpcRtcSetTarget(PCH_RTC_REG_B_INDEX, target); /*** set time to system clock ***/ /* tv.tv_sec = mktime(tmP->tm_year+1900,tmP->tm_mon+1,tmP->tm_mday, tmP->tm_hour,tmP->tm_min,tmP->tm_sec); tv.tv_nsec = 0; //compat_sys_clock_settime( CLOCK_REALTIME, &tv ); tv.tv_sec = 0; tv.tv_nsec = 1000000000 / SYSCLKRATE; //compat_sys_clock_getres( CLOCK_REALTIME, &tv ); */ } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcGetTime * SUMMARY: get time of the Ibex Peak real time clock * * SCOPE: Public * * DESCRIPTION: get time of the Ibex Peak real time clock * * RETURNS: * * NOTES: * */ void pchRtcGetTime ( struct rtc_time *tmP ) { //struct pci_dev* pdev = NULL; //struct timespec tv; unsigned char target, temp; //patsburgLpcRtcSetDataMode(RTC_BINARY_MODE); //verify if UIP is 0 target = pchLpcRtcGetTarget(PCH_RTC_REG_A_INDEX); while(((PCH_RTC_REG_A_INDEX & PCH_RTC_REG_A_UIP_BIT) != 0)) { //timer is not available, the update cycle will not start for at least 488 us udelay(50); target = pchLpcRtcGetTarget(PCH_RTC_REG_A_INDEX); } /*** read time from RTC ***/ temp = pchLpcRtcGetTarget(PCH_RTC_SECONDS_INDEX); tmP->tm_sec = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_MINUTES_INDEX); tmP->tm_min = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_HOURS_INDEX); tmP->tm_hour = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_HOURS_INDEX); tmP->tm_hour = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_DAY_OF_MONTH_INDEX); tmP->tm_mday = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_MONTH_INDEX); tmP->tm_mon = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F); temp = pchLpcRtcGetTarget(PCH_RTC_YEAR_INDEX); tmP->tm_year = ((temp & 0xF0) >> 4) * 10 + (temp & 0x0F) + 100; tmP->tm_wday = 0; tmP->tm_yday = 0; tmP->tm_isdst = 0; /*** set time to system clock ***/ /* tv.tv_sec = mktime(tmP->tm_year+1900,tmP->tm_mon+1,tmP->tm_mday, tmP->tm_hour,tmP->tm_min,tmP->tm_sec); tv.tv_nsec = 0; //compat_sys_clock_settime( CLOCK_REALTIME, &tv ); tv.tv_sec = 0; tv.tv_nsec = 1000000000 / SYSCLKRATE; //compat_sys_clock_getres( CLOCK_REALTIME, &tv ); */ } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcInit * SUMMARY: * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchRtcInit( void ) { int sec; /* turn RTC on if it was not on */ sec = pchLpcRtcGetTarget(PCH_RTC_SECONDS_INDEX); //if (sec & RTC_STOP) { //sec &= RTC_SECONDS_MASK; //cen = readb(DS1556_BASE_ADDR + RTC_CENTURY) & RTC_CENTURY_MASK; //writeb(RTC_WRITE, DS1556_BASE_ADDR + RTC_CONTROL); //writeb(sec, DS1556_BASE_ADDR + RTC_SECONDS); //writeb(cen & RTC_CENTURY_MASK, DS1556_BASE_ADDR + RTC_CONTROL); /* give time for rtc to run up */ //mdelay(2000); //} pchRtcGetTime(&s_rtc_time); return (0); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcTestClockTick * SUMMARY: * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchRtcTestClockTick( void ) { struct rtc_time tm; int current_sec = 0; int initial_sec = 0; int acc_wait_ms = 0; const int WAIT_MS = 100; const int MAX_WAIT_MS = 1100; //get initial time pchRtcGetTime(&tm); current_sec = tm.tm_sec; initial_sec = s_rtc_time.tm_sec; //if RTC is not ticking, force it to wait one more second while(current_sec == initial_sec) { mdelay(WAIT_MS); pchRtcGetTime(&tm); current_sec = tm.tm_sec; acc_wait_ms += WAIT_MS; if (acc_wait_ms > MAX_WAIT_MS) break; } //RTC is still not ticking if(current_sec == initial_sec) { commReportError(MEC_RTC, RTC_ITEM_1, RTC_CODE_1, RTC_ERR_MSG_1, 0, 0, 0, 0); return (-1); } return (0); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcTestClockTolerance * SUMMARY: * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchRtcTestClockTolerance( void ) { struct rtc_time tm; int current_sec = 0; unsigned long end_jiffies = 0; int i; /* Lower Tolerance Check */ pchRtcGetTime(&tm); current_sec = tm.tm_sec; /* Wait for end of current second */ for (i = 0; i < 1100; i++) { pchRtcGetTime(&tm); if (current_sec != tm.tm_sec) { break; } mdelay(1); } /* We got one second passed */ current_sec++; current_sec %= 60; /* Fail if waited more than 1.05 seconds for one second to expire */ if (i > 1050) { commReportError(MEC_RTC, RTC_ITEM_2, RTC_CODE_2, RTC_ERR_MSG_2, 0, 0, 0, 0); return (-1); } /* The clock second should only increase 4 */ end_jiffies = jiffies + ((4925 * HZ)/1000); do { udelay(500); }while (time_before(jiffies, end_jiffies)); pchRtcGetTime(&tm); if(((current_sec + 4)%60) != tm.tm_sec) { commReportError(MEC_RTC, RTC_ITEM_2, RTC_CODE_3, RTC_ERR_MSG_3, 0, 0, 0, 0); return (-1); } /* Upper Tolerance Check */ pchRtcGetTime(&tm); current_sec = tm.tm_sec; /* Wait for end of current second */ for(i = 0; i < 1100; i++) { pchRtcGetTime(&tm); if (current_sec != tm.tm_sec) break; mdelay(1); } /* We got one second passed */ current_sec++; current_sec %= 60; /* Fail if waited more than 1.05 seconds for one second to expire */ if(i > 1050) { commReportError(MEC_RTC, RTC_ITEM_2, RTC_CODE_2, RTC_ERR_MSG_2, 0, 0, 0, 0); return (-1); } /* The clock second should only increase 5 */ end_jiffies = jiffies + ((5075 * HZ)/1000); do { udelay(500); } while(time_before(jiffies, end_jiffies)); pchRtcGetTime(&tm); if(((current_sec + 5)%60) != tm.tm_sec) { commReportError(MEC_RTC, RTC_ITEM_2, RTC_CODE_4, RTC_ERR_MSG_4, 0, 0, 0, 0); return (-1); } return (0); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcDiag * SUMMARY: Ibex Peak real time clock diagnostics * * SCOPE: Public * * DESCRIPTION: 1. clock tick test * 2. clock tolerance test * * RETURNS: * * NOTES: * */ int pchRtcDiag( void ) { int ret = 0; pchRtcGetTime(&s_rtc_time); /* give time for rtc to run up */ mdelay( 2000 ); ret = pchRtcTestClockTick(); if (ret) return (ret); ret = pchRtcTestClockTolerance(); return (ret); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcDiag * * SUMMARY: setup RTC year, month, date * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ void pchRtcSetYMDOrig( unsigned char year, unsigned char month, unsigned char date ) { struct rtc_time tm_input; pchRtcGetTime(&tm_input); tm_input.tm_year = year - 1900; tm_input.tm_mon = month; tm_input.tm_mday = date; pchRtcSetTime(&tm_input); } void pchRtcSetYMD( unsigned char year, unsigned char month, unsigned char date ) { pchRtcSetYMDOrig( year, month, date ); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcSetHMS * * SUMMARY: setup RTC hour, minute, second * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ void pchRtcSetHMS ( unsigned char hour, unsigned char minute, unsigned char second ) { struct rtc_time tm_input; pchRtcGetTime(&tm_input); tm_input.tm_hour = hour; tm_input.tm_min = minute; tm_input.tm_sec = second; pchRtcSetTime(&tm_input); } /******************************************************************************* * PROCEDURE * * NAME: patsburgRtcShowTime * * SUMMARY: show real time clock time * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ void pchRtcShowTime( void ) { struct rtc_time tm_output; pchRtcGetTime(&tm_output); /* printk("year: %d \n", tm_output.tm_year + 1900); printk("month: %d \n", tm_output.tm_mon + 1); printk("date: %d \n", tm_output.tm_mday); printk("day: %d \n", tm_output.tm_wday); printk("hour: %d \n", tm_output.tm_hour); printk("minute: %d \n", tm_output.tm_min); printk("second: %d \n", tm_output.tm_sec); */ //show RTC time to console printk("Current Time: %d/%d/%d ", tm_output.tm_year + 1900, tm_output.tm_mon, tm_output.tm_mday); if(tm_output.tm_hour < 10) { printk("0%d:", tm_output.tm_hour); } else { printk("%d:", tm_output.tm_hour); } if(tm_output.tm_min < 10) { printk("0%d", tm_output.tm_min); } else { printk("%d", tm_output.tm_min); } printk("\n"); } unsigned int gRtcTimeYear; unsigned int gRtcTimeMon; unsigned int gRtcTimeDate; unsigned int gRtcTimeHour; unsigned int gRtcTimeMin; unsigned int gRtcTimeSec; void pchRtcTimeToScript( void ) { struct rtc_time tm_output; pchRtcGetTime(&tm_output); gRtcTimeYear = tm_output.tm_year + 1900; gRtcTimeMon= tm_output.tm_mon; gRtcTimeDate= tm_output.tm_mday; gRtcTimeHour= tm_output.tm_hour; gRtcTimeMin= tm_output.tm_min; } /************************************/ /** Interrupt/GPIO Test Function **/ /************************************/ /******************************************************************************* * PROCEDURE * * NAME: patsburgGpioDiag * SUMMARY: Ibex Peak GPIO-Board ID diagnostics * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchGpioDiag( void ) { int result = TRUE; struct pci_dev* pdev = NULL; u32 pchGpioBase; u8 pchGpioValue; // Get PCI LPC Device pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_LPC_DEVICE_ID, NULL ); if( !pdev ) { // Try old ID pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_PATSBURG_LPC_DEVICE_ID_OLD, NULL ); if (pdev) { printk( "Cannot find Patsburg LPC device(%4.4X), you might be running PROTO 1.1\n", INTEL_PATSBURG_LPC_DEVICE_ID ); printk( "Please run with PROTO 1.2 or above Soyuz board revision\n" ); } } if( !pdev ) { pdev = pci_get_device( INTEL_VENDOR_ID, INTEL_IBX_LPC_DEVICE_ID, NULL ); } if( !pdev ) { printk("[PCH] cannot get LPC device\n"); commReportError(MEC_PATSBURG, PATSBURG_PCIE_MEC, PATSBURG_PCI_NO_DEVICE_ERROR, MSG_PATSBURG_PCI_NO_DEVICE_ERROR, 0, 0, 0, 0); result = FALSE; goto ErrExit; } // Read GPIO Base address pci_read_config_dword( pdev, PCH_GPIO_BAR_OFFSET, &pchGpioBase ); if ( pdev->device != INTEL_IBX_LPC_DEVICE_ID ) { // Soyuz pchGpioBase &= ~0x01; pchGpioValue = inb( pchGpioBase + PCH_GPIO_LVL_OFFSET ); }else{ pchGpioValue = PIKESPEAK_GPIO_BOARDID; // GPIO not defined } printk(" pchGpioValue >>>> 0x%lx , 0x%x \n",pchGpioValue, (pchGpioValue & PCH_GPIO_BOARD_ID_SKU_BITS)); // Read GPIO pin status switch(pdev->device){ case INTEL_PATSBURG_LPC_DEVICE_ID: case INTEL_PATSBURG_LPC_DEVICE_ID_OLD: if((pchGpioValue & PCH_GPIO_BOARD_ID_SKU_BITS) != (SOYUZ_GPIO_BOARDID & PCH_GPIO_BOARD_ID_SKU_BITS)) { commReportError(MEC_PATSBURG, PATSBURG_INTERRUPT_GPIO_MEC, GPIO_BOARD_ID_SKU0_ERROR, MSG_GPIO_BOARD_ID_SKU0_ERROR, 0, 0, 0, 0); result = FALSE; } break; case INTEL_IBX_LPC_DEVICE_ID: if((pchGpioValue & PCH_GPIO_BOARD_ID_SKU_BITS) != (PIKESPEAK_GPIO_BOARDID & PCH_GPIO_BOARD_ID_SKU_BITS)) { commReportError(MEC_PATSBURG, PATSBURG_INTERRUPT_GPIO_MEC, GPIO_BOARD_ID_SKU1_ERROR, MSG_GPIO_BOARD_ID_SKU1_ERROR, 0, 0, 0, 0); result = FALSE; } break; } ErrExit: return result; } /*****************************************/ /** Processor Interface Test Function **/ /*****************************************/ /******************************************************************************* * PROCEDURE * * NAME: patsburgProcessorInterfaceDiag * * SUMMARY: Ibex Peak processor diagnostics * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * */ int pchProcessorInterfaceDiag( void ) { int result = TRUE; /* if(!a20_test_short()) { commReportError(MEC_PATSBURG, PATSBURG_PROCESSOR_INTERFACE_MEC, PROCESSOR_INTERFACE_ERROR, MSG_PROCESSOR_INTERFACE_ERROR, 0, 0, 0, 0); result = FALSE; } */ pchDmiLaneVerify(); return result; } static int __init pchInit( void ) { int ret; // Initialize RCBA ret = pchRcbaAllocate(); if( ret < 0 ) return ret; // Initialize RTC variables pchRtcTimeToScript(); return 0; } static void __exit pchExit( void ) { if( gPchRcbaVirtualP ) iounmap( gPchRcbaVirtualP ); } module_init( pchInit ); module_exit( pchExit ); MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "NetApp PCH Diag Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );