xref: /reactos/hal/halx86/xbox/reboot.c (revision b3194e32)
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