1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * AMD MP2 PCIe communication driver
4 * Copyright 2020-2021 Advanced Micro Devices, Inc.
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>
11 #include <linux/bitops.h>
12 #include <linux/delay.h>
13 #include <linux/devm-helpers.h>
14 #include <linux/dma-mapping.h>
15 #include <linux/dmi.h>
16 #include <linux/interrupt.h>
17 #include <linux/io-64-nonatomic-lo-hi.h>
18 #include <linux/iopoll.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
22 #include "amd_sfh_pcie.h"
23 #include "sfh1_1/amd_sfh_init.h"
25 #define DRIVER_NAME "pcie_mp2_amd"
26 #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
28 #define ACEL_EN BIT(0)
29 #define GYRO_EN BIT(1)
30 #define MAGNO_EN BIT(2)
31 #define HPD_EN BIT(16)
32 #define ALS_EN BIT(19)
33 #define ACS_EN BIT(22)
35 static int sensor_mask_override
= -1;
36 module_param_named(sensor_mask
, sensor_mask_override
, int, 0444);
37 MODULE_PARM_DESC(sensor_mask
, "override the detected sensors mask");
39 static bool intr_disable
= true;
41 static int amd_sfh_wait_response_v2(struct amd_mp2_dev
*mp2
, u8 sid
, u32 sensor_sts
)
43 union cmd_response cmd_resp
;
45 /* Get response with status within a max of 10 seconds timeout */
46 if (!readl_poll_timeout(mp2
->mmio
+ AMD_P2C_MSG(0), cmd_resp
.resp
,
47 (cmd_resp
.response_v2
.response
== sensor_sts
&&
48 cmd_resp
.response_v2
.status
== 0 && (sid
== 0xff ||
49 cmd_resp
.response_v2
.sensor_id
== sid
)), 500, 10000000))
50 return cmd_resp
.response_v2
.response
;
52 return SENSOR_DISABLED
;
55 static void amd_start_sensor_v2(struct amd_mp2_dev
*privdata
, struct amd_mp2_sensor_info info
)
57 union sfh_cmd_base cmd_base
;
60 cmd_base
.cmd_v2
.cmd_id
= ENABLE_SENSOR
;
61 cmd_base
.cmd_v2
.intr_disable
= intr_disable
;
62 cmd_base
.cmd_v2
.period
= info
.period
;
63 cmd_base
.cmd_v2
.sensor_id
= info
.sensor_idx
;
64 cmd_base
.cmd_v2
.length
= 16;
66 if (info
.sensor_idx
== als_idx
)
67 cmd_base
.cmd_v2
.mem_type
= USE_C2P_REG
;
69 writeq(info
.dma_address
, privdata
->mmio
+ AMD_C2P_MSG1
);
70 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
73 static void amd_stop_sensor_v2(struct amd_mp2_dev
*privdata
, u16 sensor_idx
)
75 union sfh_cmd_base cmd_base
;
78 cmd_base
.cmd_v2
.cmd_id
= DISABLE_SENSOR
;
79 cmd_base
.cmd_v2
.intr_disable
= intr_disable
;
80 cmd_base
.cmd_v2
.period
= 0;
81 cmd_base
.cmd_v2
.sensor_id
= sensor_idx
;
82 cmd_base
.cmd_v2
.length
= 16;
84 writeq(0x0, privdata
->mmio
+ AMD_C2P_MSG1
);
85 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
88 static void amd_stop_all_sensor_v2(struct amd_mp2_dev
*privdata
)
90 union sfh_cmd_base cmd_base
;
92 cmd_base
.cmd_v2
.cmd_id
= STOP_ALL_SENSORS
;
93 cmd_base
.cmd_v2
.intr_disable
= intr_disable
;
94 cmd_base
.cmd_v2
.period
= 0;
95 cmd_base
.cmd_v2
.sensor_id
= 0;
97 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
100 void amd_sfh_clear_intr_v2(struct amd_mp2_dev
*privdata
)
102 if (readl(privdata
->mmio
+ amd_get_p2c_val(privdata
, 4))) {
103 writel(0, privdata
->mmio
+ amd_get_p2c_val(privdata
, 4));
104 writel(0xf, privdata
->mmio
+ amd_get_p2c_val(privdata
, 5));
108 void amd_sfh_clear_intr(struct amd_mp2_dev
*privdata
)
110 if (privdata
->mp2_ops
->clear_intr
)
111 privdata
->mp2_ops
->clear_intr(privdata
);
114 static irqreturn_t
amd_sfh_irq_handler(int irq
, void *data
)
116 amd_sfh_clear_intr(data
);
121 int amd_sfh_irq_init_v2(struct amd_mp2_dev
*privdata
)
125 pci_intx(privdata
->pdev
, true);
127 rc
= devm_request_irq(&privdata
->pdev
->dev
, privdata
->pdev
->irq
,
128 amd_sfh_irq_handler
, 0, DRIVER_NAME
, privdata
);
130 dev_err(&privdata
->pdev
->dev
, "failed to request irq %d err=%d\n",
131 privdata
->pdev
->irq
, rc
);
138 static int amd_sfh_dis_sts_v2(struct amd_mp2_dev
*privdata
)
140 return (readl(privdata
->mmio
+ AMD_P2C_MSG(1)) &
141 SENSOR_DISCOVERY_STATUS_MASK
) >> SENSOR_DISCOVERY_STATUS_SHIFT
;
144 static void amd_start_sensor(struct amd_mp2_dev
*privdata
, struct amd_mp2_sensor_info info
)
146 union sfh_cmd_param cmd_param
;
147 union sfh_cmd_base cmd_base
;
149 /* fill up command register */
150 memset(&cmd_base
, 0, sizeof(cmd_base
));
151 cmd_base
.s
.cmd_id
= ENABLE_SENSOR
;
152 cmd_base
.s
.period
= info
.period
;
153 cmd_base
.s
.sensor_id
= info
.sensor_idx
;
155 /* fill up command param register */
156 memset(&cmd_param
, 0, sizeof(cmd_param
));
157 cmd_param
.s
.buf_layout
= 1;
158 cmd_param
.s
.buf_length
= 16;
160 writeq(info
.dma_address
, privdata
->mmio
+ AMD_C2P_MSG2
);
161 writel(cmd_param
.ul
, privdata
->mmio
+ AMD_C2P_MSG1
);
162 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
165 static void amd_stop_sensor(struct amd_mp2_dev
*privdata
, u16 sensor_idx
)
167 union sfh_cmd_base cmd_base
;
169 /* fill up command register */
170 memset(&cmd_base
, 0, sizeof(cmd_base
));
171 cmd_base
.s
.cmd_id
= DISABLE_SENSOR
;
172 cmd_base
.s
.period
= 0;
173 cmd_base
.s
.sensor_id
= sensor_idx
;
175 writeq(0x0, privdata
->mmio
+ AMD_C2P_MSG2
);
176 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
179 static void amd_stop_all_sensors(struct amd_mp2_dev
*privdata
)
181 union sfh_cmd_base cmd_base
;
183 /* fill up command register */
184 memset(&cmd_base
, 0, sizeof(cmd_base
));
185 cmd_base
.s
.cmd_id
= STOP_ALL_SENSORS
;
186 cmd_base
.s
.period
= 0;
187 cmd_base
.s
.sensor_id
= 0;
189 writel(cmd_base
.ul
, privdata
->mmio
+ AMD_C2P_MSG0
);
192 static const struct dmi_system_id dmi_sensor_mask_overrides
[] = {
195 DMI_MATCH(DMI_PRODUCT_NAME
, "HP ENVY x360 Convertible 13-ag0xxx"),
197 .driver_data
= (void *)(ACEL_EN
| MAGNO_EN
),
201 DMI_MATCH(DMI_PRODUCT_NAME
, "HP ENVY x360 Convertible 15-cp0xxx"),
203 .driver_data
= (void *)(ACEL_EN
| MAGNO_EN
),
208 int amd_mp2_get_sensor_num(struct amd_mp2_dev
*privdata
, u8
*sensor_id
)
210 int activestatus
, num_of_sensors
= 0;
211 const struct dmi_system_id
*dmi_id
;
213 if (sensor_mask_override
== -1) {
214 dmi_id
= dmi_first_match(dmi_sensor_mask_overrides
);
216 sensor_mask_override
= (long)dmi_id
->driver_data
;
219 if (sensor_mask_override
>= 0) {
220 activestatus
= sensor_mask_override
;
222 activestatus
= privdata
->mp2_acs
>> 4;
225 if (ACEL_EN
& activestatus
)
226 sensor_id
[num_of_sensors
++] = accel_idx
;
228 if (GYRO_EN
& activestatus
)
229 sensor_id
[num_of_sensors
++] = gyro_idx
;
231 if (MAGNO_EN
& activestatus
)
232 sensor_id
[num_of_sensors
++] = mag_idx
;
234 if (ALS_EN
& activestatus
)
235 sensor_id
[num_of_sensors
++] = als_idx
;
237 if (HPD_EN
& activestatus
)
238 sensor_id
[num_of_sensors
++] = HPD_IDX
;
240 if (ACS_EN
& activestatus
)
241 sensor_id
[num_of_sensors
++] = ACS_IDX
;
243 return num_of_sensors
;
246 static void amd_mp2_pci_remove(void *privdata
)
248 struct amd_mp2_dev
*mp2
= privdata
;
249 amd_sfh_hid_client_deinit(privdata
);
250 mp2
->mp2_ops
->stop_all(mp2
);
251 pci_intx(mp2
->pdev
, false);
252 amd_sfh_clear_intr(mp2
);
255 static struct amd_mp2_ops amd_sfh_ops_v2
= {
256 .start
= amd_start_sensor_v2
,
257 .stop
= amd_stop_sensor_v2
,
258 .stop_all
= amd_stop_all_sensor_v2
,
259 .response
= amd_sfh_wait_response_v2
,
260 .clear_intr
= amd_sfh_clear_intr_v2
,
261 .init_intr
= amd_sfh_irq_init_v2
,
262 .discovery_status
= amd_sfh_dis_sts_v2
,
263 .remove
= amd_mp2_pci_remove
,
266 static struct amd_mp2_ops amd_sfh_ops
= {
267 .start
= amd_start_sensor
,
268 .stop
= amd_stop_sensor
,
269 .stop_all
= amd_stop_all_sensors
,
270 .remove
= amd_mp2_pci_remove
,
273 static void mp2_select_ops(struct amd_mp2_dev
*privdata
)
277 privdata
->mp2_acs
= readl(privdata
->mmio
+ AMD_P2C_MSG3
);
278 acs
= privdata
->mp2_acs
& GENMASK(3, 0);
282 privdata
->mp2_ops
= &amd_sfh_ops_v2
;
285 privdata
->mp2_ops
= &amd_sfh_ops
;
290 int amd_sfh_irq_init(struct amd_mp2_dev
*privdata
)
292 if (privdata
->mp2_ops
->init_intr
)
293 return privdata
->mp2_ops
->init_intr(privdata
);
298 static int mp2_disable_intr(const struct dmi_system_id
*id
)
300 intr_disable
= false;
304 static const struct dmi_system_id dmi_sfh_table
[] = {
307 * https://bugzilla.kernel.org/show_bug.cgi?id=218104
309 .callback
= mp2_disable_intr
,
311 DMI_MATCH(DMI_SYS_VENDOR
, "HP"),
312 DMI_MATCH(DMI_PRODUCT_NAME
, "HP ProBook x360 435 G7"),
318 static const struct dmi_system_id dmi_nodevs
[] = {
321 * Google Chromebooks use Chrome OS Embedded Controller Sensor
322 * Hub instead of Sensor Hub Fusion and leaves MP2
323 * uninitialized, which disables all functionalities, even
324 * including the registers necessary for feature detections.
327 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
333 static void sfh1_1_init_work(struct work_struct
*work
)
335 struct amd_mp2_dev
*mp2
= container_of(work
, struct amd_mp2_dev
, work
);
338 rc
= mp2
->sfh1_1_ops
->init(mp2
);
342 amd_sfh_clear_intr(mp2
);
346 static void sfh_init_work(struct work_struct
*work
)
348 struct amd_mp2_dev
*mp2
= container_of(work
, struct amd_mp2_dev
, work
);
349 struct pci_dev
*pdev
= mp2
->pdev
;
352 rc
= amd_sfh_hid_client_init(mp2
);
354 amd_sfh_clear_intr(mp2
);
355 dev_err(&pdev
->dev
, "amd_sfh_hid_client_init failed err %d\n", rc
);
359 amd_sfh_clear_intr(mp2
);
363 static void amd_sfh_remove(struct pci_dev
*pdev
)
365 struct amd_mp2_dev
*mp2
= pci_get_drvdata(pdev
);
367 flush_work(&mp2
->work
);
369 mp2
->mp2_ops
->remove(mp2
);
372 static int amd_mp2_pci_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
374 struct amd_mp2_dev
*privdata
;
377 if (dmi_first_match(dmi_nodevs
))
380 dmi_check_system(dmi_sfh_table
);
382 privdata
= devm_kzalloc(&pdev
->dev
, sizeof(*privdata
), GFP_KERNEL
);
386 privdata
->pdev
= pdev
;
387 dev_set_drvdata(&pdev
->dev
, privdata
);
388 rc
= pcim_enable_device(pdev
);
392 rc
= pcim_iomap_regions(pdev
, BIT(2), DRIVER_NAME
);
396 privdata
->mmio
= pcim_iomap_table(pdev
)[2];
397 pci_set_master(pdev
);
398 rc
= dma_set_mask_and_coherent(&pdev
->dev
, DMA_BIT_MASK(64));
400 dev_err(&pdev
->dev
, "failed to set DMA mask\n");
404 privdata
->cl_data
= devm_kzalloc(&pdev
->dev
, sizeof(struct amdtp_cl_data
), GFP_KERNEL
);
405 if (!privdata
->cl_data
)
408 privdata
->sfh1_1_ops
= (const struct amd_sfh1_1_ops
*)id
->driver_data
;
409 if (privdata
->sfh1_1_ops
) {
410 if (boot_cpu_data
.x86
>= 0x1A)
413 rc
= devm_work_autocancel(&pdev
->dev
, &privdata
->work
, sfh1_1_init_work
);
417 schedule_work(&privdata
->work
);
421 mp2_select_ops(privdata
);
423 rc
= amd_sfh_irq_init(privdata
);
425 dev_err(&pdev
->dev
, "amd_sfh_irq_init failed\n");
429 rc
= devm_work_autocancel(&pdev
->dev
, &privdata
->work
, sfh_init_work
);
431 amd_sfh_clear_intr(privdata
);
435 schedule_work(&privdata
->work
);
439 static void amd_sfh_shutdown(struct pci_dev
*pdev
)
441 struct amd_mp2_dev
*mp2
= pci_get_drvdata(pdev
);
444 flush_work(&mp2
->work
);
446 mp2
->mp2_ops
->stop_all(mp2
);
450 static int __maybe_unused
amd_mp2_pci_resume(struct device
*dev
)
452 struct amd_mp2_dev
*mp2
= dev_get_drvdata(dev
);
454 flush_work(&mp2
->work
);
456 mp2
->mp2_ops
->resume(mp2
);
461 static int __maybe_unused
amd_mp2_pci_suspend(struct device
*dev
)
463 struct amd_mp2_dev
*mp2
= dev_get_drvdata(dev
);
465 flush_work(&mp2
->work
);
467 mp2
->mp2_ops
->suspend(mp2
);
472 static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops
, amd_mp2_pci_suspend
,
475 static const struct pci_device_id amd_mp2_pci_tbl
[] = {
476 { PCI_VDEVICE(AMD
, PCI_DEVICE_ID_AMD_MP2
) },
477 { PCI_VDEVICE(AMD
, PCI_DEVICE_ID_AMD_MP2_1_1
),
478 .driver_data
= (kernel_ulong_t
)&sfh1_1_ops
},
481 MODULE_DEVICE_TABLE(pci
, amd_mp2_pci_tbl
);
483 static struct pci_driver amd_mp2_pci_driver
= {
485 .id_table
= amd_mp2_pci_tbl
,
486 .probe
= amd_mp2_pci_probe
,
487 .driver
.pm
= &amd_mp2_pm_ops
,
488 .shutdown
= amd_sfh_shutdown
,
489 .remove
= amd_sfh_remove
,
491 module_pci_driver(amd_mp2_pci_driver
);
493 MODULE_DESCRIPTION(DRIVER_DESC
);
494 MODULE_LICENSE("Dual BSD/GPL");
495 MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
496 MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
497 MODULE_AUTHOR("Basavaraj Natikar <Basavaraj.Natikar@amd.com>");