-
Notifications
You must be signed in to change notification settings - Fork 6
/
chip_x6dva.c
181 lines (160 loc) · 5.87 KB
/
chip_x6dva.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
/*
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <sys/types.h>
#include "global.h"
/*
* Function prototypes
*/
int x6dva_main(int, struct sensors *);
/*
* External funcions (smbus_io.c)
*/
extern uint8_t read_byte(int, int, const char);
extern void write_byte(int, int, const char, const char);
/*
* External functions (chip_w83792d.c)
* NOTE: Yes, these are needed!
*/
extern uint8_t w83792d_divisor(const uint8_t);
extern uint32_t w83792d_rpmconv(const uint8_t, const uint8_t);
/*
* x6dva_main(int fd, struct sensors *)
*
* fd = Descriptor return from open() on a /dev/smbX device
* s = Pointer to sensors struct; see global.h for a definition
*
* Supermicro X6DVA / X6DVL / X6DAL register reading subroutine.
*
* These Supermicro boards are quite unique -- they use dual Winbond
* chips (one W83627HF, and one W83792D). This makes things complex
* when it comes to reading IC data.
*
* We do not want to risk using the standard w83792d_main() routine, since
* that may read some registers which aren't tied to anything and could
* put system stability at risk.
*
* The SMBus slave addresses are 0x2c for the W83627HF, and 0x2f for the
* W83792D. These are assumed/hard-coded in the below function, rather
* than passed in via boardlist[].
*
* The registers we care about are:
*
* Winbond W83627HF registers:
* CR20-CR25, CR27
* Winbond W83792D registers:
* CR20-CR21, CR28-CR2A, CR3E, CR47, CR5B-5C, CRB8-CRBA, CRC0, CRC8
*/
int
x6dva_main(int fd, struct sensors *s)
{
static u_char regmap[256];
int w83627hf_slave = 0x2c;
int w83792d_slave = 0x2f;
uint8_t fandiv;
VERBOSE("x6dva_main(fd = %d, s = %p)\n", fd, s);
memset(®map, 0, sizeof(regmap));
/*
* Winbond W83627HF portion
*
* Registers Pin name
* ----------- ----------
* CR20 VIN0
* CR21 VIN1
* CR22 VIN2
* CR23 VIN3
* CR24 12VSEN
* CR25 VSEN1
* CR27 TD1
* ----------- ----------
*/
regmap[0x20] = read_byte(fd, w83627hf_slave, 0x20);
regmap[0x21] = read_byte(fd, w83627hf_slave, 0x21);
regmap[0x22] = read_byte(fd, w83627hf_slave, 0x22);
regmap[0x23] = read_byte(fd, w83627hf_slave, 0x23);
regmap[0x24] = read_byte(fd, w83627hf_slave, 0x24);
regmap[0x25] = read_byte(fd, w83627hf_slave, 0x25);
regmap[0x25] = read_byte(fd, w83627hf_slave, 0x25);
regmap[0x27] = read_byte(fd, w83627hf_slave, 0x27);
/*
* Now calculate voltages and temperatures which use the populated
* regmap[] array. We do this BEFORE the Winbond W83792D reads,
* since regmap[] is re-used and overwrites some of the registers
* we use here (i.e. 0x20).
*/
s->voltages[VOLT_VIN0].value = regmap[0x20];
s->voltages[VOLT_VIN1].value = regmap[0x21];
s->voltages[VOLT_VIN2].value = regmap[0x22];
s->voltages[VOLT_VIN3].value = regmap[0x23];
s->voltages[VOLT_12VSEN].value = regmap[0x24];
s->voltages[VOLT_VSEN1].value = regmap[0x25];
s->voltages[VOLT_VSEN1].value *= -1; /* VSEN1 is a negative voltage */
s->temps[TEMP_TD1].value = regmap[0x27];
/*
* Zero out regmap[] as a precaution, since we do re-use it below.
*/
memset(®map, 0, sizeof(regmap));
/*
* Winbond W83792D portion
*
* Registers Pin name
* ----------- ----------
* CR20,CR3E VCOREA
* CR20,CR3E VCOREB
* CRC0,CRC1 TD2
* CRC8,CRC9 TD3
* CR28,CR47 FAN1
* CR29,CR47 FAN2
* CR2A,CR5B FAN3
* CRB8,CR5B FAN4
* CRB9,CR5C FAN5
* CRBA,CR5C FAN6
* ----------- ----------
*
* NOTE:
* 1. The bits used for CR3E (VCOREB) are undocumented; I assume 3-2.
* 2. The calculation formulas for VCOREA and VCOREB are suspect.
* The formulas given in the W83792D data sheet are either
* incorrect or Supermicro chose to use different resistors than
* what the Winbond specification recommends.
* 3. The official Winbond W83792D documentation says some temperature
* sensors are 9-bit, where the last bit defines .5 or .0. It
* doesn't appear that Supermicro wired these up, instead sticking
* to raw 8-bit values. This is why we don't read/use CRC1 or CRC9.
*/
regmap[0x20] = read_byte(fd, w83792d_slave, 0x20);
regmap[0x21] = read_byte(fd, w83792d_slave, 0x21);
regmap[0x28] = read_byte(fd, w83792d_slave, 0x28);
regmap[0x29] = read_byte(fd, w83792d_slave, 0x29);
regmap[0x2a] = read_byte(fd, w83792d_slave, 0x2a);
regmap[0x3e] = read_byte(fd, w83792d_slave, 0x3e);
regmap[0x47] = read_byte(fd, w83792d_slave, 0x47);
regmap[0x5b] = read_byte(fd, w83792d_slave, 0x5b);
regmap[0x5c] = read_byte(fd, w83792d_slave, 0x5c);
regmap[0xb8] = read_byte(fd, w83792d_slave, 0xb8);
regmap[0xb9] = read_byte(fd, w83792d_slave, 0xb9);
regmap[0xba] = read_byte(fd, w83792d_slave, 0xba);
regmap[0xc0] = read_byte(fd, w83792d_slave, 0xc0);
regmap[0xc8] = read_byte(fd, w83792d_slave, 0xc8);
s->voltages[VOLT_VCOREA].value = ((regmap[0x20] << 2) + (regmap[0x3e] & 0x03)) * 0.002;
s->voltages[VOLT_VCOREB].value = ((regmap[0x21] << 2) + ((regmap[0x3e] & 0x0c) >> 2)) * 0.002;
s->temps[TEMP_TD2].value = regmap[0xc0];
s->temps[TEMP_TD3].value = regmap[0xc8];
fandiv = w83792d_divisor(regmap[0x47] & 0x07);
s->fans[FAN_FAN1].value = w83792d_rpmconv(regmap[0x28], fandiv);
fandiv = w83792d_divisor((regmap[0x47] & 0x70) >> 4);
s->fans[FAN_FAN2].value = w83792d_rpmconv(regmap[0x29], fandiv);
fandiv = w83792d_divisor(regmap[0x5b] & 0x07);
s->fans[FAN_FAN3].value = w83792d_rpmconv(regmap[0x2a], fandiv);
fandiv = w83792d_divisor((regmap[0x5b] & 0x70) >> 4);
s->fans[FAN_FAN4].value = w83792d_rpmconv(regmap[0xb8], fandiv);
fandiv = w83792d_divisor(regmap[0x5c] & 0x07);
s->fans[FAN_FAN5].value = w83792d_rpmconv(regmap[0xb9], fandiv);
fandiv = w83792d_divisor((regmap[0x5c] & 0x70) >> 4);
s->fans[FAN_FAN6].value = w83792d_rpmconv(regmap[0xba], fandiv);
VERBOSE("x6dva_main() returning\n");
return (0);
}