1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AMD MP2 PCIe communication driver
4 * Copyright 2020-2021 Advanced Micro Devices, Inc.
5 *
6 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
7 * Sandeep Singh <Sandeep.singh@amd.com>
8 * Basavaraj Natikar <Basavaraj.Natikar@amd.com>
9 */
10
11 #include <linux/bitops.h>
12 #include <linux/delay.h>
13 #include <linux/dma-mapping.h>
14 #include <linux/dmi.h>
15 #include <linux/interrupt.h>
16 #include <linux/io-64-nonatomic-lo-hi.h>
17 #include <linux/iopoll.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20
21 #include "amd_sfh_pcie.h"
22
23 #define DRIVER_NAME "pcie_mp2_amd"
24 #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
25
26 #define ACEL_EN BIT(0)
27 #define GYRO_EN BIT(1)
28 #define MAGNO_EN BIT(2)
29 #define HPD_EN BIT(16)
30 #define ALS_EN BIT(19)
31
32 static int sensor_mask_override = -1;
33 module_param_named(sensor_mask, sensor_mask_override, int, 0444);
34 MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
35
amd_sfh_wait_response_v2(struct amd_mp2_dev * mp2,u8 sid,u32 sensor_sts)36 static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
37 {
38 union cmd_response cmd_resp;
39
40 /* Get response with status within a max of 1600 ms timeout */
41 if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
42 (cmd_resp.response_v2.response == sensor_sts &&
43 cmd_resp.response_v2.status == 0 && (sid == 0xff ||
44 cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
45 return cmd_resp.response_v2.response;
46
47 return SENSOR_DISABLED;
48 }
49
amd_start_sensor_v2(struct amd_mp2_dev * privdata,struct amd_mp2_sensor_info info)50 static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
51 {
52 union sfh_cmd_base cmd_base;
53
54 cmd_base.ul = 0;
55 cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
56 cmd_base.cmd_v2.intr_disable = 1;
57 cmd_base.cmd_v2.period = info.period;
58 cmd_base.cmd_v2.sensor_id = info.sensor_idx;
59 cmd_base.cmd_v2.length = 16;
60
61 if (info.sensor_idx == als_idx)
62 cmd_base.cmd_v2.mem_type = USE_C2P_REG;
63
64 writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
65 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
66 }
67
amd_stop_sensor_v2(struct amd_mp2_dev * privdata,u16 sensor_idx)68 static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
69 {
70 union sfh_cmd_base cmd_base;
71
72 cmd_base.ul = 0;
73 cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
74 cmd_base.cmd_v2.intr_disable = 1;
75 cmd_base.cmd_v2.period = 0;
76 cmd_base.cmd_v2.sensor_id = sensor_idx;
77 cmd_base.cmd_v2.length = 16;
78
79 writeq(0x0, privdata->mmio + AMD_C2P_MSG1);
80 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
81 }
82
amd_stop_all_sensor_v2(struct amd_mp2_dev * privdata)83 static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
84 {
85 union sfh_cmd_base cmd_base;
86
87 cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
88 cmd_base.cmd_v2.intr_disable = 1;
89 cmd_base.cmd_v2.period = 0;
90 cmd_base.cmd_v2.sensor_id = 0;
91
92 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
93 }
94
amd_sfh_clear_intr_v2(struct amd_mp2_dev * privdata)95 static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata)
96 {
97 if (readl(privdata->mmio + AMD_P2C_MSG(4))) {
98 writel(0, privdata->mmio + AMD_P2C_MSG(4));
99 writel(0xf, privdata->mmio + AMD_P2C_MSG(5));
100 }
101 }
102
amd_sfh_clear_intr(struct amd_mp2_dev * privdata)103 static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata)
104 {
105 if (privdata->mp2_ops->clear_intr)
106 privdata->mp2_ops->clear_intr(privdata);
107 }
108
amd_sfh_irq_handler(int irq,void * data)109 static irqreturn_t amd_sfh_irq_handler(int irq, void *data)
110 {
111 amd_sfh_clear_intr(data);
112
113 return IRQ_HANDLED;
114 }
115
amd_sfh_irq_init_v2(struct amd_mp2_dev * privdata)116 static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata)
117 {
118 int rc;
119
120 pci_intx(privdata->pdev, true);
121
122 rc = devm_request_irq(&privdata->pdev->dev, privdata->pdev->irq,
123 amd_sfh_irq_handler, 0, DRIVER_NAME, privdata);
124 if (rc) {
125 dev_err(&privdata->pdev->dev, "failed to request irq %d err=%d\n",
126 privdata->pdev->irq, rc);
127 return rc;
128 }
129
130 return 0;
131 }
132
amd_sfh_dis_sts_v2(struct amd_mp2_dev * privdata)133 static int amd_sfh_dis_sts_v2(struct amd_mp2_dev *privdata)
134 {
135 return (readl(privdata->mmio + AMD_P2C_MSG(1)) &
136 SENSOR_DISCOVERY_STATUS_MASK) >> SENSOR_DISCOVERY_STATUS_SHIFT;
137 }
138
amd_start_sensor(struct amd_mp2_dev * privdata,struct amd_mp2_sensor_info info)139 void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
140 {
141 union sfh_cmd_param cmd_param;
142 union sfh_cmd_base cmd_base;
143
144 /* fill up command register */
145 memset(&cmd_base, 0, sizeof(cmd_base));
146 cmd_base.s.cmd_id = ENABLE_SENSOR;
147 cmd_base.s.period = info.period;
148 cmd_base.s.sensor_id = info.sensor_idx;
149
150 /* fill up command param register */
151 memset(&cmd_param, 0, sizeof(cmd_param));
152 cmd_param.s.buf_layout = 1;
153 cmd_param.s.buf_length = 16;
154
155 writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG2);
156 writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
157 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
158 }
159
amd_stop_sensor(struct amd_mp2_dev * privdata,u16 sensor_idx)160 void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
161 {
162 union sfh_cmd_base cmd_base;
163
164 /* fill up command register */
165 memset(&cmd_base, 0, sizeof(cmd_base));
166 cmd_base.s.cmd_id = DISABLE_SENSOR;
167 cmd_base.s.period = 0;
168 cmd_base.s.sensor_id = sensor_idx;
169
170 writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
171 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
172 }
173
amd_stop_all_sensors(struct amd_mp2_dev * privdata)174 void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
175 {
176 union sfh_cmd_base cmd_base;
177
178 /* fill up command register */
179 memset(&cmd_base, 0, sizeof(cmd_base));
180 cmd_base.s.cmd_id = STOP_ALL_SENSORS;
181 cmd_base.s.period = 0;
182 cmd_base.s.sensor_id = 0;
183
184 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
185 }
186
187 static const struct dmi_system_id dmi_sensor_mask_overrides[] = {
188 {
189 .matches = {
190 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 13-ag0xxx"),
191 },
192 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
193 },
194 {
195 .matches = {
196 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 15-cp0xxx"),
197 },
198 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
199 },
200 { }
201 };
202
amd_mp2_get_sensor_num(struct amd_mp2_dev * privdata,u8 * sensor_id)203 int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
204 {
205 int activestatus, num_of_sensors = 0;
206 const struct dmi_system_id *dmi_id;
207
208 if (sensor_mask_override == -1) {
209 dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
210 if (dmi_id)
211 sensor_mask_override = (long)dmi_id->driver_data;
212 }
213
214 if (sensor_mask_override >= 0) {
215 activestatus = sensor_mask_override;
216 } else {
217 activestatus = privdata->mp2_acs >> 4;
218 }
219
220 if (ACEL_EN & activestatus)
221 sensor_id[num_of_sensors++] = accel_idx;
222
223 if (GYRO_EN & activestatus)
224 sensor_id[num_of_sensors++] = gyro_idx;
225
226 if (MAGNO_EN & activestatus)
227 sensor_id[num_of_sensors++] = mag_idx;
228
229 if (ALS_EN & activestatus)
230 sensor_id[num_of_sensors++] = als_idx;
231
232 if (HPD_EN & activestatus)
233 sensor_id[num_of_sensors++] = HPD_IDX;
234
235 return num_of_sensors;
236 }
237
amd_mp2_pci_remove(void * privdata)238 static void amd_mp2_pci_remove(void *privdata)
239 {
240 struct amd_mp2_dev *mp2 = privdata;
241 amd_sfh_hid_client_deinit(privdata);
242 mp2->mp2_ops->stop_all(mp2);
243 pci_intx(mp2->pdev, false);
244 amd_sfh_clear_intr(mp2);
245 }
246
247 static const struct amd_mp2_ops amd_sfh_ops_v2 = {
248 .start = amd_start_sensor_v2,
249 .stop = amd_stop_sensor_v2,
250 .stop_all = amd_stop_all_sensor_v2,
251 .response = amd_sfh_wait_response_v2,
252 .clear_intr = amd_sfh_clear_intr_v2,
253 .init_intr = amd_sfh_irq_init_v2,
254 .discovery_status = amd_sfh_dis_sts_v2,
255 };
256
257 static const struct amd_mp2_ops amd_sfh_ops = {
258 .start = amd_start_sensor,
259 .stop = amd_stop_sensor,
260 .stop_all = amd_stop_all_sensors,
261 };
262
mp2_select_ops(struct amd_mp2_dev * privdata)263 static void mp2_select_ops(struct amd_mp2_dev *privdata)
264 {
265 u8 acs;
266
267 privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
268 acs = privdata->mp2_acs & GENMASK(3, 0);
269
270 switch (acs) {
271 case V2_STATUS:
272 privdata->mp2_ops = &amd_sfh_ops_v2;
273 break;
274 default:
275 privdata->mp2_ops = &amd_sfh_ops;
276 break;
277 }
278 }
279
amd_sfh_irq_init(struct amd_mp2_dev * privdata)280 static int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
281 {
282 if (privdata->mp2_ops->init_intr)
283 return privdata->mp2_ops->init_intr(privdata);
284
285 return 0;
286 }
287
288 static const struct dmi_system_id dmi_nodevs[] = {
289 {
290 /*
291 * Google Chromebooks use Chrome OS Embedded Controller Sensor
292 * Hub instead of Sensor Hub Fusion and leaves MP2
293 * uninitialized, which disables all functionalities, even
294 * including the registers necessary for feature detections.
295 */
296 .matches = {
297 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
298 },
299 },
300 { }
301 };
302
amd_mp2_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)303 static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
304 {
305 struct amd_mp2_dev *privdata;
306 int rc;
307
308 if (dmi_first_match(dmi_nodevs))
309 return -ENODEV;
310
311 privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
312 if (!privdata)
313 return -ENOMEM;
314
315 privdata->pdev = pdev;
316 dev_set_drvdata(&pdev->dev, privdata);
317 rc = pcim_enable_device(pdev);
318 if (rc)
319 return rc;
320
321 rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
322 if (rc)
323 return rc;
324
325 privdata->mmio = pcim_iomap_table(pdev)[2];
326 pci_set_master(pdev);
327 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
328 if (rc) {
329 dev_err(&pdev->dev, "failed to set DMA mask\n");
330 return rc;
331 }
332
333 privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
334 if (!privdata->cl_data)
335 return -ENOMEM;
336
337 mp2_select_ops(privdata);
338
339 rc = amd_sfh_irq_init(privdata);
340 if (rc) {
341 dev_err(&pdev->dev, "amd_sfh_irq_init failed\n");
342 return rc;
343 }
344
345 rc = amd_sfh_hid_client_init(privdata);
346 if (rc) {
347 amd_sfh_clear_intr(privdata);
348 if (rc != -EOPNOTSUPP)
349 dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
350 return rc;
351 }
352
353 amd_sfh_clear_intr(privdata);
354
355 return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
356 }
357
amd_mp2_pci_resume(struct device * dev)358 static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
359 {
360 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
361 struct amdtp_cl_data *cl_data = mp2->cl_data;
362 struct amd_mp2_sensor_info info;
363 int i, status;
364
365 for (i = 0; i < cl_data->num_hid_devices; i++) {
366 if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
367 info.period = AMD_SFH_IDLE_LOOP;
368 info.sensor_idx = cl_data->sensor_idx[i];
369 info.dma_address = cl_data->sensor_dma_addr[i];
370 mp2->mp2_ops->start(mp2, info);
371 status = amd_sfh_wait_for_response
372 (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
373 if (status == SENSOR_ENABLED)
374 cl_data->sensor_sts[i] = SENSOR_ENABLED;
375 dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
376 cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
377 cl_data->sensor_sts[i]);
378 }
379 }
380
381 schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
382 amd_sfh_clear_intr(mp2);
383
384 return 0;
385 }
386
amd_mp2_pci_suspend(struct device * dev)387 static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
388 {
389 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
390 struct amdtp_cl_data *cl_data = mp2->cl_data;
391 int i, status;
392
393 for (i = 0; i < cl_data->num_hid_devices; i++) {
394 if (cl_data->sensor_idx[i] != HPD_IDX &&
395 cl_data->sensor_sts[i] == SENSOR_ENABLED) {
396 mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
397 status = amd_sfh_wait_for_response
398 (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
399 if (status != SENSOR_ENABLED)
400 cl_data->sensor_sts[i] = SENSOR_DISABLED;
401 dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n",
402 cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
403 cl_data->sensor_sts[i]);
404 }
405 }
406
407 cancel_delayed_work_sync(&cl_data->work_buffer);
408 amd_sfh_clear_intr(mp2);
409
410 return 0;
411 }
412
413 static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
414 amd_mp2_pci_resume);
415
416 static const struct pci_device_id amd_mp2_pci_tbl[] = {
417 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
418 { }
419 };
420 MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
421
422 static struct pci_driver amd_mp2_pci_driver = {
423 .name = DRIVER_NAME,
424 .id_table = amd_mp2_pci_tbl,
425 .probe = amd_mp2_pci_probe,
426 .driver.pm = &amd_mp2_pm_ops,
427 };
428 module_pci_driver(amd_mp2_pci_driver);
429
430 MODULE_DESCRIPTION(DRIVER_DESC);
431 MODULE_LICENSE("Dual BSD/GPL");
432 MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
433 MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
434 MODULE_AUTHOR("Basavaraj Natikar <Basavaraj.Natikar@amd.com>");
435