1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Nvidia GPU I2C controller Driver |
4 | * |
5 | * Copyright (C) 2018 NVIDIA Corporation. All rights reserved. |
6 | * Author: Ajay Gupta <ajayg@nvidia.com> |
7 | */ |
8 | #include <linux/delay.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/iopoll.h> |
12 | #include <linux/module.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/pm_runtime.h> |
17 | #include <linux/power_supply.h> |
18 | |
19 | #include <asm/unaligned.h> |
20 | |
21 | #include "i2c-ccgx-ucsi.h" |
22 | |
23 | /* I2C definitions */ |
24 | #define I2C_MST_CNTL 0x00 |
25 | #define I2C_MST_CNTL_GEN_START BIT(0) |
26 | #define I2C_MST_CNTL_GEN_STOP BIT(1) |
27 | #define I2C_MST_CNTL_CMD_READ (1 << 2) |
28 | #define I2C_MST_CNTL_CMD_WRITE (2 << 2) |
29 | #define I2C_MST_CNTL_BURST_SIZE_SHIFT 6 |
30 | #define I2C_MST_CNTL_GEN_NACK BIT(28) |
31 | #define I2C_MST_CNTL_STATUS GENMASK(30, 29) |
32 | #define I2C_MST_CNTL_STATUS_OKAY (0 << 29) |
33 | #define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29) |
34 | #define I2C_MST_CNTL_STATUS_TIMEOUT (2 << 29) |
35 | #define I2C_MST_CNTL_STATUS_BUS_BUSY (3 << 29) |
36 | #define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31) |
37 | |
38 | #define I2C_MST_ADDR 0x04 |
39 | |
40 | #define I2C_MST_I2C0_TIMING 0x08 |
41 | #define I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ 0x10e |
42 | #define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT 16 |
43 | #define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX 255 |
44 | #define I2C_MST_I2C0_TIMING_TIMEOUT_CHECK BIT(24) |
45 | |
46 | #define I2C_MST_DATA 0x0c |
47 | |
48 | #define I2C_MST_HYBRID_PADCTL 0x20 |
49 | #define I2C_MST_HYBRID_PADCTL_MODE_I2C BIT(0) |
50 | #define I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV BIT(14) |
51 | #define I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV BIT(15) |
52 | |
53 | struct gpu_i2c_dev { |
54 | struct device *dev; |
55 | void __iomem *regs; |
56 | struct i2c_adapter adapter; |
57 | struct i2c_board_info *gpu_ccgx_ucsi; |
58 | struct i2c_client *ccgx_client; |
59 | }; |
60 | |
61 | static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd) |
62 | { |
63 | u32 val; |
64 | |
65 | /* enable I2C */ |
66 | val = readl(addr: i2cd->regs + I2C_MST_HYBRID_PADCTL); |
67 | val |= I2C_MST_HYBRID_PADCTL_MODE_I2C | |
68 | I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | |
69 | I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV; |
70 | writel(val, addr: i2cd->regs + I2C_MST_HYBRID_PADCTL); |
71 | |
72 | /* enable 100KHZ mode */ |
73 | val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ; |
74 | val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX |
75 | << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT); |
76 | val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK; |
77 | writel(val, addr: i2cd->regs + I2C_MST_I2C0_TIMING); |
78 | } |
79 | |
80 | static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd) |
81 | { |
82 | u32 val; |
83 | int ret; |
84 | |
85 | ret = readl_poll_timeout(i2cd->regs + I2C_MST_CNTL, val, |
86 | !(val & I2C_MST_CNTL_CYCLE_TRIGGER) || |
87 | (val & I2C_MST_CNTL_STATUS) != I2C_MST_CNTL_STATUS_BUS_BUSY, |
88 | 500, 1000 * USEC_PER_MSEC); |
89 | |
90 | if (ret) { |
91 | dev_err(i2cd->dev, "i2c timeout error %x\n" , val); |
92 | return -ETIMEDOUT; |
93 | } |
94 | |
95 | val = readl(addr: i2cd->regs + I2C_MST_CNTL); |
96 | switch (val & I2C_MST_CNTL_STATUS) { |
97 | case I2C_MST_CNTL_STATUS_OKAY: |
98 | return 0; |
99 | case I2C_MST_CNTL_STATUS_NO_ACK: |
100 | return -ENXIO; |
101 | case I2C_MST_CNTL_STATUS_TIMEOUT: |
102 | return -ETIMEDOUT; |
103 | default: |
104 | return 0; |
105 | } |
106 | } |
107 | |
108 | static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len) |
109 | { |
110 | int status; |
111 | u32 val; |
112 | |
113 | val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_READ | |
114 | (len << I2C_MST_CNTL_BURST_SIZE_SHIFT) | |
115 | I2C_MST_CNTL_CYCLE_TRIGGER | I2C_MST_CNTL_GEN_NACK; |
116 | writel(val, addr: i2cd->regs + I2C_MST_CNTL); |
117 | |
118 | status = gpu_i2c_check_status(i2cd); |
119 | if (status < 0) |
120 | return status; |
121 | |
122 | val = readl(addr: i2cd->regs + I2C_MST_DATA); |
123 | switch (len) { |
124 | case 1: |
125 | data[0] = val; |
126 | break; |
127 | case 2: |
128 | put_unaligned_be16(val, p: data); |
129 | break; |
130 | case 3: |
131 | put_unaligned_be24(val, p: data); |
132 | break; |
133 | case 4: |
134 | put_unaligned_be32(val, p: data); |
135 | break; |
136 | default: |
137 | break; |
138 | } |
139 | return status; |
140 | } |
141 | |
142 | static int gpu_i2c_start(struct gpu_i2c_dev *i2cd) |
143 | { |
144 | writel(I2C_MST_CNTL_GEN_START, addr: i2cd->regs + I2C_MST_CNTL); |
145 | return gpu_i2c_check_status(i2cd); |
146 | } |
147 | |
148 | static int gpu_i2c_stop(struct gpu_i2c_dev *i2cd) |
149 | { |
150 | writel(I2C_MST_CNTL_GEN_STOP, addr: i2cd->regs + I2C_MST_CNTL); |
151 | return gpu_i2c_check_status(i2cd); |
152 | } |
153 | |
154 | static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data) |
155 | { |
156 | u32 val; |
157 | |
158 | writel(val: data, addr: i2cd->regs + I2C_MST_DATA); |
159 | |
160 | val = I2C_MST_CNTL_CMD_WRITE | (1 << I2C_MST_CNTL_BURST_SIZE_SHIFT); |
161 | writel(val, addr: i2cd->regs + I2C_MST_CNTL); |
162 | |
163 | return gpu_i2c_check_status(i2cd); |
164 | } |
165 | |
166 | static int gpu_i2c_master_xfer(struct i2c_adapter *adap, |
167 | struct i2c_msg *msgs, int num) |
168 | { |
169 | struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap); |
170 | int status, status2; |
171 | bool send_stop = true; |
172 | int i, j; |
173 | |
174 | /* |
175 | * The controller supports maximum 4 byte read due to known |
176 | * limitation of sending STOP after every read. |
177 | */ |
178 | pm_runtime_get_sync(dev: i2cd->dev); |
179 | for (i = 0; i < num; i++) { |
180 | if (msgs[i].flags & I2C_M_RD) { |
181 | /* program client address before starting read */ |
182 | writel(val: msgs[i].addr, addr: i2cd->regs + I2C_MST_ADDR); |
183 | /* gpu_i2c_read has implicit start */ |
184 | status = gpu_i2c_read(i2cd, data: msgs[i].buf, len: msgs[i].len); |
185 | if (status < 0) |
186 | goto exit; |
187 | } else { |
188 | u8 addr = i2c_8bit_addr_from_msg(msg: msgs + i); |
189 | |
190 | status = gpu_i2c_start(i2cd); |
191 | if (status < 0) { |
192 | if (i == 0) |
193 | send_stop = false; |
194 | goto exit; |
195 | } |
196 | |
197 | status = gpu_i2c_write(i2cd, data: addr); |
198 | if (status < 0) |
199 | goto exit; |
200 | |
201 | for (j = 0; j < msgs[i].len; j++) { |
202 | status = gpu_i2c_write(i2cd, data: msgs[i].buf[j]); |
203 | if (status < 0) |
204 | goto exit; |
205 | } |
206 | } |
207 | } |
208 | send_stop = false; |
209 | status = gpu_i2c_stop(i2cd); |
210 | if (status < 0) |
211 | goto exit; |
212 | |
213 | status = i; |
214 | exit: |
215 | if (send_stop) { |
216 | status2 = gpu_i2c_stop(i2cd); |
217 | if (status2 < 0) |
218 | dev_err(i2cd->dev, "i2c stop failed %d\n" , status2); |
219 | } |
220 | pm_runtime_mark_last_busy(dev: i2cd->dev); |
221 | pm_runtime_put_autosuspend(dev: i2cd->dev); |
222 | return status; |
223 | } |
224 | |
225 | static const struct i2c_adapter_quirks gpu_i2c_quirks = { |
226 | .max_read_len = 4, |
227 | .max_comb_2nd_msg_len = 4, |
228 | .flags = I2C_AQ_COMB_WRITE_THEN_READ, |
229 | }; |
230 | |
231 | static u32 gpu_i2c_functionality(struct i2c_adapter *adap) |
232 | { |
233 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; |
234 | } |
235 | |
236 | static const struct i2c_algorithm gpu_i2c_algorithm = { |
237 | .master_xfer = gpu_i2c_master_xfer, |
238 | .functionality = gpu_i2c_functionality, |
239 | }; |
240 | |
241 | /* |
242 | * This driver is for Nvidia GPU cards with USB Type-C interface. |
243 | * We want to identify the cards using vendor ID and class code only |
244 | * to avoid dependency of adding product id for any new card which |
245 | * requires this driver. |
246 | * Currently there is no class code defined for UCSI device over PCI |
247 | * so using UNKNOWN class for now and it will be updated when UCSI |
248 | * over PCI gets a class code. |
249 | * There is no other NVIDIA cards with UNKNOWN class code. Even if the |
250 | * driver gets loaded for an undesired card then eventually i2c_read() |
251 | * (initiated from UCSI i2c_client) will timeout or UCSI commands will |
252 | * timeout. |
253 | */ |
254 | #define PCI_CLASS_SERIAL_UNKNOWN 0x0c80 |
255 | static const struct pci_device_id gpu_i2c_ids[] = { |
256 | { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, |
257 | PCI_CLASS_SERIAL_UNKNOWN << 8, 0xffffff00}, |
258 | { } |
259 | }; |
260 | MODULE_DEVICE_TABLE(pci, gpu_i2c_ids); |
261 | |
262 | static const struct property_entry ccgx_props[] = { |
263 | /* Use FW built for NVIDIA GPU only */ |
264 | PROPERTY_ENTRY_STRING("firmware-name" , "nvidia,gpu" ), |
265 | /* USB-C doesn't power the system */ |
266 | PROPERTY_ENTRY_U8("scope" , POWER_SUPPLY_SCOPE_DEVICE), |
267 | { } |
268 | }; |
269 | |
270 | static const struct software_node ccgx_node = { |
271 | .properties = ccgx_props, |
272 | }; |
273 | |
274 | static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
275 | { |
276 | struct device *dev = &pdev->dev; |
277 | struct gpu_i2c_dev *i2cd; |
278 | int status; |
279 | |
280 | i2cd = devm_kzalloc(dev, size: sizeof(*i2cd), GFP_KERNEL); |
281 | if (!i2cd) |
282 | return -ENOMEM; |
283 | |
284 | i2cd->dev = dev; |
285 | dev_set_drvdata(dev, data: i2cd); |
286 | |
287 | status = pcim_enable_device(pdev); |
288 | if (status < 0) |
289 | return dev_err_probe(dev, err: status, fmt: "pcim_enable_device failed\n" ); |
290 | |
291 | pci_set_master(dev: pdev); |
292 | |
293 | i2cd->regs = pcim_iomap(pdev, bar: 0, maxlen: 0); |
294 | if (!i2cd->regs) |
295 | return dev_err_probe(dev, err: -ENOMEM, fmt: "pcim_iomap failed\n" ); |
296 | |
297 | status = pci_alloc_irq_vectors(dev: pdev, min_vecs: 1, max_vecs: 1, PCI_IRQ_MSI); |
298 | if (status < 0) |
299 | return dev_err_probe(dev, err: status, fmt: "pci_alloc_irq_vectors err\n" ); |
300 | |
301 | gpu_enable_i2c_bus(i2cd); |
302 | |
303 | i2c_set_adapdata(adap: &i2cd->adapter, data: i2cd); |
304 | i2cd->adapter.owner = THIS_MODULE; |
305 | strscpy(p: i2cd->adapter.name, q: "NVIDIA GPU I2C adapter" , |
306 | size: sizeof(i2cd->adapter.name)); |
307 | i2cd->adapter.algo = &gpu_i2c_algorithm; |
308 | i2cd->adapter.quirks = &gpu_i2c_quirks; |
309 | i2cd->adapter.dev.parent = dev; |
310 | status = i2c_add_adapter(adap: &i2cd->adapter); |
311 | if (status < 0) |
312 | goto free_irq_vectors; |
313 | |
314 | i2cd->ccgx_client = i2c_new_ccgx_ucsi(adapter: &i2cd->adapter, irq: pdev->irq, swnode: &ccgx_node); |
315 | if (IS_ERR(ptr: i2cd->ccgx_client)) { |
316 | status = dev_err_probe(dev, err: PTR_ERR(ptr: i2cd->ccgx_client), fmt: "register UCSI failed\n" ); |
317 | goto del_adapter; |
318 | } |
319 | |
320 | pm_runtime_set_autosuspend_delay(dev, delay: 3000); |
321 | pm_runtime_use_autosuspend(dev); |
322 | pm_runtime_put_autosuspend(dev); |
323 | pm_runtime_allow(dev); |
324 | |
325 | return 0; |
326 | |
327 | del_adapter: |
328 | i2c_del_adapter(adap: &i2cd->adapter); |
329 | free_irq_vectors: |
330 | pci_free_irq_vectors(dev: pdev); |
331 | return status; |
332 | } |
333 | |
334 | static void gpu_i2c_remove(struct pci_dev *pdev) |
335 | { |
336 | struct gpu_i2c_dev *i2cd = pci_get_drvdata(pdev); |
337 | |
338 | pm_runtime_get_noresume(dev: i2cd->dev); |
339 | i2c_del_adapter(adap: &i2cd->adapter); |
340 | pci_free_irq_vectors(dev: pdev); |
341 | } |
342 | |
343 | #define gpu_i2c_suspend NULL |
344 | |
345 | static __maybe_unused int gpu_i2c_resume(struct device *dev) |
346 | { |
347 | struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev); |
348 | |
349 | gpu_enable_i2c_bus(i2cd); |
350 | /* |
351 | * Runtime resume ccgx client so that it can see for any |
352 | * connector change event. Old ccg firmware has known |
353 | * issue of not triggering interrupt when a device is |
354 | * connected to runtime resume the controller. |
355 | */ |
356 | pm_request_resume(dev: &i2cd->ccgx_client->dev); |
357 | return 0; |
358 | } |
359 | |
360 | static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume, |
361 | NULL); |
362 | |
363 | static struct pci_driver gpu_i2c_driver = { |
364 | .name = "nvidia-gpu" , |
365 | .id_table = gpu_i2c_ids, |
366 | .probe = gpu_i2c_probe, |
367 | .remove = gpu_i2c_remove, |
368 | .driver = { |
369 | .pm = &gpu_i2c_driver_pm, |
370 | }, |
371 | }; |
372 | |
373 | module_pci_driver(gpu_i2c_driver); |
374 | |
375 | MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>" ); |
376 | MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver" ); |
377 | MODULE_LICENSE("GPL v2" ); |
378 | |