1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | SMBus driver for nVidia nForce2 MCP |
4 | |
5 | Added nForce3 Pro 150 Thomas Leibold <thomas@plx.com>, |
6 | Ported to 2.5 Patrick Dreker <patrick@dreker.de>, |
7 | Copyright (c) 2003 Hans-Frieder Vogt <hfvogt@arcor.de>, |
8 | Based on |
9 | SMBus 2.0 driver for AMD-8111 IO-Hub |
10 | Copyright (c) 2002 Vojtech Pavlik |
11 | |
12 | */ |
13 | |
14 | /* |
15 | SUPPORTED DEVICES PCI ID |
16 | nForce2 MCP 0064 |
17 | nForce2 Ultra 400 MCP 0084 |
18 | nForce3 Pro150 MCP 00D4 |
19 | nForce3 250Gb MCP 00E4 |
20 | nForce4 MCP 0052 |
21 | nForce4 MCP-04 0034 |
22 | nForce MCP51 0264 |
23 | nForce MCP55 0368 |
24 | nForce MCP61 03EB |
25 | nForce MCP65 0446 |
26 | nForce MCP67 0542 |
27 | nForce MCP73 07D8 |
28 | nForce MCP78S 0752 |
29 | nForce MCP79 0AA2 |
30 | |
31 | This driver supports the 2 SMBuses that are included in the MCP of the |
32 | nForce2/3/4/5xx chipsets. |
33 | */ |
34 | |
35 | /* Note: we assume there can only be one nForce2, with two SMBus interfaces */ |
36 | |
37 | #include <linux/module.h> |
38 | #include <linux/pci.h> |
39 | #include <linux/kernel.h> |
40 | #include <linux/stddef.h> |
41 | #include <linux/ioport.h> |
42 | #include <linux/i2c.h> |
43 | #include <linux/delay.h> |
44 | #include <linux/dmi.h> |
45 | #include <linux/acpi.h> |
46 | #include <linux/slab.h> |
47 | #include <linux/io.h> |
48 | |
49 | MODULE_LICENSE("GPL" ); |
50 | MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>" ); |
51 | MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver" ); |
52 | |
53 | |
54 | struct nforce2_smbus { |
55 | struct i2c_adapter adapter; |
56 | int base; |
57 | int size; |
58 | int blockops; |
59 | int can_abort; |
60 | }; |
61 | |
62 | |
63 | /* |
64 | * nVidia nForce2 SMBus control register definitions |
65 | * (Newer incarnations use standard BARs 4 and 5 instead) |
66 | */ |
67 | #define NFORCE_PCI_SMB1 0x50 |
68 | #define NFORCE_PCI_SMB2 0x54 |
69 | |
70 | |
71 | /* |
72 | * ACPI 2.0 chapter 13 SMBus 2.0 EC register model |
73 | */ |
74 | #define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */ |
75 | #define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */ |
76 | #define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */ |
77 | #define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */ |
78 | #define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */ |
79 | #define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data |
80 | bytes */ |
81 | #define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to |
82 | check the status of |
83 | the abort command */ |
84 | #define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */ |
85 | |
86 | #define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that |
87 | abort succeeded */ |
88 | #define NVIDIA_SMB_CTRL_ABORT 0x20 |
89 | #define NVIDIA_SMB_STS_DONE 0x80 |
90 | #define NVIDIA_SMB_STS_ALRM 0x40 |
91 | #define NVIDIA_SMB_STS_RES 0x20 |
92 | #define NVIDIA_SMB_STS_STATUS 0x1f |
93 | |
94 | #define NVIDIA_SMB_PRTCL_WRITE 0x00 |
95 | #define NVIDIA_SMB_PRTCL_READ 0x01 |
96 | #define NVIDIA_SMB_PRTCL_QUICK 0x02 |
97 | #define NVIDIA_SMB_PRTCL_BYTE 0x04 |
98 | #define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06 |
99 | #define NVIDIA_SMB_PRTCL_WORD_DATA 0x08 |
100 | #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a |
101 | #define NVIDIA_SMB_PRTCL_PEC 0x80 |
102 | |
103 | /* Misc definitions */ |
104 | #define MAX_TIMEOUT 100 |
105 | |
106 | /* We disable the second SMBus channel on these boards */ |
107 | static const struct dmi_system_id nforce2_dmi_blacklist2[] = { |
108 | { |
109 | .ident = "DFI Lanparty NF4 Expert" , |
110 | .matches = { |
111 | DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD" ), |
112 | DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert" ), |
113 | }, |
114 | }, |
115 | { } |
116 | }; |
117 | |
118 | static struct pci_driver nforce2_driver; |
119 | |
120 | /* For multiplexing support, we need a global reference to the 1st |
121 | SMBus channel */ |
122 | #if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985) |
123 | struct i2c_adapter *nforce2_smbus; |
124 | EXPORT_SYMBOL_GPL(nforce2_smbus); |
125 | |
126 | static void nforce2_set_reference(struct i2c_adapter *adap) |
127 | { |
128 | nforce2_smbus = adap; |
129 | } |
130 | #else |
131 | static inline void nforce2_set_reference(struct i2c_adapter *adap) { } |
132 | #endif |
133 | |
134 | static void nforce2_abort(struct i2c_adapter *adap) |
135 | { |
136 | struct nforce2_smbus *smbus = adap->algo_data; |
137 | int timeout = 0; |
138 | unsigned char temp; |
139 | |
140 | dev_dbg(&adap->dev, "Aborting current transaction\n" ); |
141 | |
142 | outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL); |
143 | do { |
144 | msleep(msecs: 1); |
145 | temp = inb_p(NVIDIA_SMB_STATUS_ABRT); |
146 | } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) && |
147 | (timeout++ < MAX_TIMEOUT)); |
148 | if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS)) |
149 | dev_err(&adap->dev, "Can't reset the smbus\n" ); |
150 | outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT); |
151 | } |
152 | |
153 | static int nforce2_check_status(struct i2c_adapter *adap) |
154 | { |
155 | struct nforce2_smbus *smbus = adap->algo_data; |
156 | int timeout = 0; |
157 | unsigned char temp; |
158 | |
159 | do { |
160 | msleep(msecs: 1); |
161 | temp = inb_p(NVIDIA_SMB_STS); |
162 | } while ((!temp) && (timeout++ < MAX_TIMEOUT)); |
163 | |
164 | if (timeout > MAX_TIMEOUT) { |
165 | dev_dbg(&adap->dev, "SMBus Timeout!\n" ); |
166 | if (smbus->can_abort) |
167 | nforce2_abort(adap); |
168 | return -ETIMEDOUT; |
169 | } |
170 | if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { |
171 | dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n" , temp); |
172 | return -EIO; |
173 | } |
174 | return 0; |
175 | } |
176 | |
177 | /* Return negative errno on error */ |
178 | static s32 nforce2_access(struct i2c_adapter *adap, u16 addr, |
179 | unsigned short flags, char read_write, |
180 | u8 command, int size, union i2c_smbus_data *data) |
181 | { |
182 | struct nforce2_smbus *smbus = adap->algo_data; |
183 | unsigned char protocol, pec; |
184 | u8 len; |
185 | int i, status; |
186 | |
187 | protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : |
188 | NVIDIA_SMB_PRTCL_WRITE; |
189 | pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0; |
190 | |
191 | switch (size) { |
192 | case I2C_SMBUS_QUICK: |
193 | protocol |= NVIDIA_SMB_PRTCL_QUICK; |
194 | read_write = I2C_SMBUS_WRITE; |
195 | break; |
196 | |
197 | case I2C_SMBUS_BYTE: |
198 | if (read_write == I2C_SMBUS_WRITE) |
199 | outb_p(value: command, NVIDIA_SMB_CMD); |
200 | protocol |= NVIDIA_SMB_PRTCL_BYTE; |
201 | break; |
202 | |
203 | case I2C_SMBUS_BYTE_DATA: |
204 | outb_p(value: command, NVIDIA_SMB_CMD); |
205 | if (read_write == I2C_SMBUS_WRITE) |
206 | outb_p(value: data->byte, NVIDIA_SMB_DATA); |
207 | protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA; |
208 | break; |
209 | |
210 | case I2C_SMBUS_WORD_DATA: |
211 | outb_p(value: command, NVIDIA_SMB_CMD); |
212 | if (read_write == I2C_SMBUS_WRITE) { |
213 | outb_p(value: data->word, NVIDIA_SMB_DATA); |
214 | outb_p(value: data->word >> 8, NVIDIA_SMB_DATA + 1); |
215 | } |
216 | protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec; |
217 | break; |
218 | |
219 | case I2C_SMBUS_BLOCK_DATA: |
220 | outb_p(value: command, NVIDIA_SMB_CMD); |
221 | if (read_write == I2C_SMBUS_WRITE) { |
222 | len = data->block[0]; |
223 | if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) { |
224 | dev_err(&adap->dev, |
225 | "Transaction failed (requested block size: %d)\n" , |
226 | len); |
227 | return -EINVAL; |
228 | } |
229 | outb_p(value: len, NVIDIA_SMB_BCNT); |
230 | for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) |
231 | outb_p(value: data->block[i + 1], |
232 | NVIDIA_SMB_DATA + i); |
233 | } |
234 | protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec; |
235 | break; |
236 | |
237 | default: |
238 | dev_err(&adap->dev, "Unsupported transaction %d\n" , size); |
239 | return -EOPNOTSUPP; |
240 | } |
241 | |
242 | outb_p(value: (addr & 0x7f) << 1, NVIDIA_SMB_ADDR); |
243 | outb_p(value: protocol, NVIDIA_SMB_PRTCL); |
244 | |
245 | status = nforce2_check_status(adap); |
246 | if (status) |
247 | return status; |
248 | |
249 | if (read_write == I2C_SMBUS_WRITE) |
250 | return 0; |
251 | |
252 | switch (size) { |
253 | case I2C_SMBUS_BYTE: |
254 | case I2C_SMBUS_BYTE_DATA: |
255 | data->byte = inb_p(NVIDIA_SMB_DATA); |
256 | break; |
257 | |
258 | case I2C_SMBUS_WORD_DATA: |
259 | data->word = inb_p(NVIDIA_SMB_DATA) | |
260 | (inb_p(NVIDIA_SMB_DATA + 1) << 8); |
261 | break; |
262 | |
263 | case I2C_SMBUS_BLOCK_DATA: |
264 | len = inb_p(NVIDIA_SMB_BCNT); |
265 | if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { |
266 | dev_err(&adap->dev, |
267 | "Transaction failed (received block size: 0x%02x)\n" , |
268 | len); |
269 | return -EPROTO; |
270 | } |
271 | for (i = 0; i < len; i++) |
272 | data->block[i + 1] = inb_p(NVIDIA_SMB_DATA + i); |
273 | data->block[0] = len; |
274 | break; |
275 | } |
276 | |
277 | return 0; |
278 | } |
279 | |
280 | |
281 | static u32 nforce2_func(struct i2c_adapter *adapter) |
282 | { |
283 | /* other functionality might be possible, but is not tested */ |
284 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
285 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
286 | I2C_FUNC_SMBUS_PEC | |
287 | (((struct nforce2_smbus *)adapter->algo_data)->blockops ? |
288 | I2C_FUNC_SMBUS_BLOCK_DATA : 0); |
289 | } |
290 | |
291 | static const struct i2c_algorithm smbus_algorithm = { |
292 | .smbus_xfer = nforce2_access, |
293 | .functionality = nforce2_func, |
294 | }; |
295 | |
296 | |
297 | static const struct pci_device_id nforce2_ids[] = { |
298 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, |
299 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, |
300 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, |
301 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) }, |
302 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) }, |
303 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, |
304 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, |
305 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, |
306 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) }, |
307 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) }, |
308 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) }, |
309 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) }, |
310 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) }, |
311 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) }, |
312 | { 0 } |
313 | }; |
314 | |
315 | MODULE_DEVICE_TABLE(pci, nforce2_ids); |
316 | |
317 | |
318 | static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, |
319 | struct nforce2_smbus *smbus, const char *name) |
320 | { |
321 | int error; |
322 | |
323 | smbus->base = pci_resource_start(dev, bar); |
324 | if (smbus->base) { |
325 | smbus->size = pci_resource_len(dev, bar); |
326 | } else { |
327 | /* Older incarnations of the device used non-standard BARs */ |
328 | u16 iobase; |
329 | |
330 | error = pci_read_config_word(dev, where: alt_reg, val: &iobase); |
331 | if (error != PCIBIOS_SUCCESSFUL) { |
332 | dev_err(&dev->dev, "Error reading PCI config for %s\n" , |
333 | name); |
334 | return -EIO; |
335 | } |
336 | |
337 | smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; |
338 | smbus->size = 64; |
339 | } |
340 | |
341 | error = acpi_check_region(start: smbus->base, n: smbus->size, |
342 | name: nforce2_driver.name); |
343 | if (error) |
344 | return error; |
345 | |
346 | if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { |
347 | dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n" , |
348 | smbus->base, smbus->base+smbus->size-1, name); |
349 | return -EBUSY; |
350 | } |
351 | smbus->adapter.owner = THIS_MODULE; |
352 | smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
353 | smbus->adapter.algo = &smbus_algorithm; |
354 | smbus->adapter.algo_data = smbus; |
355 | smbus->adapter.dev.parent = &dev->dev; |
356 | snprintf(buf: smbus->adapter.name, size: sizeof(smbus->adapter.name), |
357 | fmt: "SMBus nForce2 adapter at %04x" , smbus->base); |
358 | |
359 | error = i2c_add_adapter(adap: &smbus->adapter); |
360 | if (error) { |
361 | release_region(smbus->base, smbus->size); |
362 | return error; |
363 | } |
364 | dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n" , |
365 | smbus->base); |
366 | return 0; |
367 | } |
368 | |
369 | |
370 | static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) |
371 | { |
372 | struct nforce2_smbus *smbuses; |
373 | int res1, res2; |
374 | |
375 | /* we support 2 SMBus adapters */ |
376 | smbuses = kcalloc(n: 2, size: sizeof(struct nforce2_smbus), GFP_KERNEL); |
377 | if (!smbuses) |
378 | return -ENOMEM; |
379 | pci_set_drvdata(pdev: dev, data: smbuses); |
380 | |
381 | switch (dev->device) { |
382 | case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS: |
383 | case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: |
384 | case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: |
385 | smbuses[0].blockops = 1; |
386 | smbuses[1].blockops = 1; |
387 | smbuses[0].can_abort = 1; |
388 | smbuses[1].can_abort = 1; |
389 | } |
390 | |
391 | /* SMBus adapter 1 */ |
392 | res1 = nforce2_probe_smb(dev, bar: 4, NFORCE_PCI_SMB1, smbus: &smbuses[0], name: "SMB1" ); |
393 | if (res1 < 0) |
394 | smbuses[0].base = 0; /* to have a check value */ |
395 | |
396 | /* SMBus adapter 2 */ |
397 | if (dmi_check_system(list: nforce2_dmi_blacklist2)) { |
398 | dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n" ); |
399 | res2 = -EPERM; |
400 | smbuses[1].base = 0; |
401 | } else { |
402 | res2 = nforce2_probe_smb(dev, bar: 5, NFORCE_PCI_SMB2, smbus: &smbuses[1], |
403 | name: "SMB2" ); |
404 | if (res2 < 0) |
405 | smbuses[1].base = 0; /* to have a check value */ |
406 | } |
407 | |
408 | if ((res1 < 0) && (res2 < 0)) { |
409 | /* we did not find even one of the SMBuses, so we give up */ |
410 | kfree(objp: smbuses); |
411 | return -ENODEV; |
412 | } |
413 | |
414 | nforce2_set_reference(adap: &smbuses[0].adapter); |
415 | return 0; |
416 | } |
417 | |
418 | |
419 | static void nforce2_remove(struct pci_dev *dev) |
420 | { |
421 | struct nforce2_smbus *smbuses = pci_get_drvdata(pdev: dev); |
422 | |
423 | nforce2_set_reference(NULL); |
424 | if (smbuses[0].base) { |
425 | i2c_del_adapter(adap: &smbuses[0].adapter); |
426 | release_region(smbuses[0].base, smbuses[0].size); |
427 | } |
428 | if (smbuses[1].base) { |
429 | i2c_del_adapter(adap: &smbuses[1].adapter); |
430 | release_region(smbuses[1].base, smbuses[1].size); |
431 | } |
432 | kfree(objp: smbuses); |
433 | } |
434 | |
435 | static struct pci_driver nforce2_driver = { |
436 | .name = "nForce2_smbus" , |
437 | .id_table = nforce2_ids, |
438 | .probe = nforce2_probe, |
439 | .remove = nforce2_remove, |
440 | }; |
441 | |
442 | module_pci_driver(nforce2_driver); |
443 | |