-
Notifications
You must be signed in to change notification settings - Fork 1
/
intel.c
198 lines (162 loc) · 5.18 KB
/
intel.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include "helper.h"
#include "intel.h"
#include "vendor.h"
#define DEV_INTEL_LPC_BUS 0
#define DEV_INTEL_LPC_DEVICE 31
#define DEV_INTEL_LPC_FUNC 0
#define REG_INTEL_LPC_CTRL_INFO 0x00
#define REG_INTEL_LPC_GPIO_BASE 0x48
#define REG_INTEL_LPC_GPIO_CTRL 0x4C
#define REG_INTEL_LPC_IO_DECODE_RANGE 0x80
#define INTEL_ENABLE_FORWARD_4E4F 0x20000000
#define INTEL_GPIO23_BIT 0x00800000
#define INTEL_GPIO_REG_ENABLE 0x00000010
#define INTEL_GPIO_LOCK 0x00000001
uint32_t LPCGenericDecode[] = {0x84, 0x88, 0x8C, 0x90};
int num_intel_ranges = 0;
// default ranges
range intel_ranges[] = {
{0x200, 0xFC}, //200-2FF
{0x300, 0x70}, //300/310/320/330/340/350/360/370+3
{0x388, 0x1C}, //380-38F, 390-39F
{0xA00, 0xFC} //A00-AFF
};
uint32_t LPCEnc(uint32_t BASE, uint32_t MASK)
{
return BASE | (MASK << 16) | 0x01;
}
uint32_t Read_Intel_LPC(uint32_t reg)
{
return readpci(DEV_INTEL_LPC_BUS, DEV_INTEL_LPC_DEVICE, DEV_INTEL_LPC_FUNC, reg);
}
void Write_Intel_LPC(uint32_t reg, uint32_t val)
{
writepci(DEV_INTEL_LPC_BUS, DEV_INTEL_LPC_DEVICE, DEV_INTEL_LPC_FUNC, reg, val);
}
void PrintIntelLPCStates()
{
int i;
uint32_t decodeRange = Read_Intel_LPC(REG_INTEL_LPC_IO_DECODE_RANGE);
printf("LPC I/O Decode Range Config: %08lX\n", decodeRange);
for (i = 0; i < 4; i++)
{
uint32_t genRange;
genRange = Read_Intel_LPC(LPCGenericDecode[i]);
printf("LPC Generic Decode Range %d Config: %08lX\n", i, genRange);
}
}
int CheckIntelLPCController()
{
uint32_t tmp = Read_Intel_LPC(REG_INTEL_LPC_CTRL_INFO);
uint32_t ven = tmp & 0x0000FFFF;
// Check the LPC controller is there
if (ven != VEN_INTEL_LONG)
{
printf("Can't find Intel LPC controller.\n");
printf("(Got %04lX, expected %04X)\n", ven, VEN_INTEL);
return 0; // false
}
else
{
uint32_t dev = tmp >> 16;
printf("Found Intel LPC Controller. Dev ID: %04lX\n", dev);
return 1; // true
}
}
void Enable_LPC_Config_Forward()
{
// forward addresses 4E and 4F (Fintek ISA bridge config port) to the LPC bus
Write_Intel_LPC(REG_INTEL_LPC_IO_DECODE_RANGE, Read_Intel_LPC(REG_INTEL_LPC_IO_DECODE_RANGE) | INTEL_ENABLE_FORWARD_4E4F);
}
void Configure_LPC_Ranges()
{
int i;
for (i = 0; i < num_intel_ranges; i++)
{
printf("Enabling Range %d : Base %04lX, Mask %02lX, LPC %08lX\n", i, intel_ranges[i].base, intel_ranges[i].mask, LPCEnc(intel_ranges[i].base, intel_ranges[i].mask));
printf ("Ports : ");
listports(intel_ranges[i].base, intel_ranges[i].mask);
// forward the address ranges to the ISA bridge
Write_Intel_LPC(LPCGenericDecode[i], LPCEnc(intel_ranges[i].base, intel_ranges[i].mask));
}
}
void CheckLDRQ1GPIOStatus()
{
uint32_t gpiobase = Read_Intel_LPC(REG_INTEL_LPC_GPIO_BASE) & 0xFFFFFFFE;
uint32_t gpioctrl = Read_Intel_LPC(REG_INTEL_LPC_GPIO_CTRL);
uint32_t gpioflags;
#ifdef VERBOSE
printf("GPIO Base Address: %08lX\n", gpiobase);
printf("GPIO Control: %08lX\n", gpioctrl);
#endif
if (!(gpioctrl & INTEL_GPIO_REG_ENABLE))
{
printf("GPIO register access not enabled. Enabling it.\n");
Write_Intel_LPC(REG_INTEL_LPC_GPIO_CTRL, gpioctrl | INTEL_GPIO_REG_ENABLE);
}
gpioflags = _inpd((uint16_t)gpiobase);
#ifdef VERBOSE
printf("GPIO 0-31 Use: %08lX\n", gpioflags);
#endif
if (gpioflags & INTEL_GPIO23_BIT)
{
printf("LDRQ1# is being used as GPIO23.\n");
if (gpioctrl & INTEL_GPIO_LOCK)
{
printf("WARNING: GPIO control locked!\n");
}
else
{
printf("Changing LDRQ1# to native mode.\n");
_outpd((uint16_t)gpiobase, gpioflags & ~INTEL_GPIO23_BIT);
}
}
}
void ProcessIntelArgs(int argc, char* argv[])
{
// Usage : lpcisa [base1 mask1] [base2 mask2] [base3 mask3] [base4 mask4]
// By default it forwards the following ports :
// 200-2FF -- Soundblaster DSP
// 300/310/320/330/340/350/360/370 (+1/2/3) -- MPU-401 MIDI
// 380-38F, 390-39F -- Adlib
// A00-AFF -- PnP
int i;
if (argc < 3 || !(argc & 0x01))
{
printf("No or malformed args, using defaults\n");
num_intel_ranges = 4;
}
else
{
num_intel_ranges = (argc - 1) / 2;
if (num_intel_ranges > 4) num_intel_ranges = 4;
for (i = 0; i < num_intel_ranges; i++)
{
intel_ranges[i].base = strtoul(argv[(i * 2) + 1], NULL, 16);
intel_ranges[i].mask = strtoul(argv[(i * 2) + 2], NULL, 16);
}
}
}
int main_intel(int argc, char* argv[])
{
// Check Intel.
if (!CheckIntelLPCController())
{
clearpci();
return 1;
}
#ifdef VERBOSE
printf("Current LPC Controller status before processing:\n");
PrintIntelLPCStates();
#endif
ProcessIntelArgs(argc, argv);
Configure_LPC_Ranges();
// Enable forwarding 4E and 4F.
Enable_LPC_Config_Forward();
CheckLDRQ1GPIOStatus();
#ifdef VERBOSE
printf("Current LPC Controller status after processing:\n");
PrintIntelLPCStates();
#endif
return 0;
}