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
SMBusWriteByte(_In_ UCHAR Address,_In_ UCHAR Register,_In_ UCHAR Data)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
HalpXboxPowerAction(_In_ UCHAR Action)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
HalpReboot(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
HalReturnToFirmware(_In_ FIRMWARE_REENTRY Action)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