1 /* 2 * PROJECT: Xbox HAL 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Xbox reboot functions 5 * COPYRIGHT: Copyright 2004 Lehner Franz (franz@caos.at) 6 * Copyright 2019 Stanislav Motylkov (x86corez@gmail.com) 7 * 8 * REFERENCES: https://xboxdevwiki.net/SMBus 9 * https://github.com/XboxDev/cromwell/blob/master/drivers/pci/i2cio.c 10 * https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-amd756.c 11 * https://github.com/xqemu/xqemu/blob/master/hw/xbox/smbus_xbox_smc.c 12 */ 13 14 /* INCLUDES ******************************************************************/ 15 16 #include "halxbox.h" 17 18 /* PRIVATE FUNCTIONS *********************************************************/ 19 20 static VOID 21 SMBusWriteByte( 22 _In_ UCHAR Address, 23 _In_ UCHAR Register, 24 _In_ UCHAR Data) 25 { 26 INT Retries = 50; 27 28 /* Wait while bus is busy with any master traffic */ 29 while (READ_PORT_USHORT((PUSHORT)SMB_GLOBAL_STATUS) & 0x800) 30 { 31 NOTHING; 32 } 33 34 while (Retries--) 35 { 36 UCHAR b; 37 38 WRITE_PORT_UCHAR((PUCHAR)SMB_HOST_ADDRESS, Address << 1); 39 WRITE_PORT_UCHAR((PUCHAR)SMB_HOST_COMMAND, Register); 40 41 WRITE_PORT_UCHAR((PUCHAR)SMB_HOST_DATA, Data); 42 43 /* Clear down all preexisting errors */ 44 WRITE_PORT_USHORT((PUSHORT)SMB_GLOBAL_STATUS, READ_PORT_USHORT((PUSHORT)SMB_GLOBAL_STATUS)); 45 46 /* Let I2C SMBus know we're sending a single byte here */ 47 WRITE_PORT_UCHAR((PUCHAR)SMB_GLOBAL_ENABLE, 0x1A); 48 49 b = 0; 50 51 while (!(b & 0x36)) 52 { 53 b = READ_PORT_UCHAR((PUCHAR)SMB_GLOBAL_STATUS); 54 } 55 56 if (b & 0x10) 57 { 58 return; 59 } 60 61 KeStallExecutionProcessor(1); 62 } 63 } 64 65 static DECLSPEC_NORETURN 66 VOID 67 HalpXboxPowerAction( 68 _In_ UCHAR Action) 69 { 70 /* Disable interrupts */ 71 _disable(); 72 73 /* Send the command */ 74 SMBusWriteByte(SMB_DEVICE_SMC_PIC16LC, SMC_REG_POWER, Action); 75 76 /* Halt the CPU */ 77 __halt(); 78 UNREACHABLE; 79 } 80 81 DECLSPEC_NORETURN 82 VOID 83 HalpReboot(VOID) 84 { 85 HalpXboxPowerAction(SMC_REG_POWER_RESET); 86 } 87 88 /* PUBLIC FUNCTIONS **********************************************************/ 89 90 #ifndef _MINIHAL_ 91 /* 92 * @implemented 93 */ 94 VOID 95 NTAPI 96 HalReturnToFirmware( 97 _In_ FIRMWARE_REENTRY Action) 98 { 99 /* Check what kind of action this is */ 100 switch (Action) 101 { 102 /* All recognized actions: call the internal power function */ 103 case HalHaltRoutine: 104 case HalPowerDownRoutine: 105 { 106 HalpXboxPowerAction(SMC_REG_POWER_SHUTDOWN); 107 } 108 case HalRestartRoutine: 109 { 110 HalpXboxPowerAction(SMC_REG_POWER_CYCLE); 111 } 112 case HalRebootRoutine: 113 { 114 HalpXboxPowerAction(SMC_REG_POWER_RESET); 115 } 116 117 /* Anything else */ 118 default: 119 { 120 /* Print message and break */ 121 DbgPrint("HalReturnToFirmware(%d) called!\n", Action); 122 DbgBreakPoint(); 123 } 124 } 125 } 126 #endif // _MINIHAL_ 127 128 /* EOF */ 129