blob: 7236b223fb68eab6789ac546d427426dbd2de0cb [file] [log] [blame]
Sandeep Singh4f567b92020-10-10 01:31:36 +05301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * AMD MP2 PCIe communication driver
Basavaraj Natikarf75203c2021-09-23 17:59:30 +05304 * Copyright 2020-2021 Advanced Micro Devices, Inc.
Sandeep Singh4f567b92020-10-10 01:31:36 +05305 *
6 * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
7 * Sandeep Singh <Sandeep.singh@amd.com>
Basavaraj Natikarf75203c2021-09-23 17:59:30 +05308 * Basavaraj Natikar <Basavaraj.Natikar@amd.com>
Sandeep Singh4f567b92020-10-10 01:31:36 +05309 */
10
11#include <linux/bitops.h>
12#include <linux/delay.h>
13#include <linux/dma-mapping.h>
Hans de Goede25615e42021-01-28 13:12:19 +010014#include <linux/dmi.h>
Sandeep Singh4f567b92020-10-10 01:31:36 +053015#include <linux/interrupt.h>
16#include <linux/io-64-nonatomic-lo-hi.h>
Basavaraj Natikar173709f2021-08-02 19:33:38 +053017#include <linux/iopoll.h>
Sandeep Singh4f567b92020-10-10 01:31:36 +053018#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
Sandeep Singh4b393f02020-10-28 14:30:10 +053026#define ACEL_EN BIT(0)
27#define GYRO_EN BIT(1)
Hans de Goede952f7d12021-01-28 13:12:18 +010028#define MAGNO_EN BIT(2)
Basavaraj Natikar24a31ea2021-06-18 13:48:38 +053029#define HPD_EN BIT(16)
Sandeep Singh4f567b92020-10-10 01:31:36 +053030#define ALS_EN BIT(19)
31
Hans de Goede952f7d12021-01-28 13:12:18 +010032static int sensor_mask_override = -1;
33module_param_named(sensor_mask, sensor_mask_override, int, 0444);
34MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
35
Basavaraj Natikar173709f2021-08-02 19:33:38 +053036static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
37{
38 union cmd_response cmd_resp;
39
Basavaraj Natikara7072c02022-01-31 22:48:32 +053040 /* Get response with status within a max of 1600 ms timeout */
Basavaraj Natikar173709f2021-08-02 19:33:38 +053041 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 ||
Basavaraj Natikara7072c02022-01-31 22:48:32 +053044 cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
Basavaraj Natikar173709f2021-08-02 19:33:38 +053045 return cmd_resp.response_v2.response;
46
47 return SENSOR_DISABLED;
48}
49
Basavaraj Natikarf2644812021-06-18 13:48:36 +053050static 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;
Basavaraj Natikarb3006672022-02-08 17:51:10 +053056 cmd_base.cmd_v2.intr_disable = 1;
Basavaraj Natikarf2644812021-06-18 13:48:36 +053057 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
68static 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;
Basavaraj Natikarb3006672022-02-08 17:51:10 +053074 cmd_base.cmd_v2.intr_disable = 1;
Basavaraj Natikarf2644812021-06-18 13:48:36 +053075 cmd_base.cmd_v2.period = 0;
76 cmd_base.cmd_v2.sensor_id = sensor_idx;
77 cmd_base.cmd_v2.length = 16;
78
Dylan MacKenzie8aa63482021-07-13 16:31:07 -070079 writeq(0x0, privdata->mmio + AMD_C2P_MSG1);
Basavaraj Natikarf2644812021-06-18 13:48:36 +053080 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
81}
82
83static 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;
Basavaraj Natikarb3006672022-02-08 17:51:10 +053088 cmd_base.cmd_v2.intr_disable = 1;
Basavaraj Natikarf2644812021-06-18 13:48:36 +053089 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
Basavaraj Natikarfb75a372022-02-08 17:51:11 +053095static 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
103static 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
Sandeep Singh4f567b92020-10-10 01:31:36 +0530109void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
110{
111 union sfh_cmd_param cmd_param;
112 union sfh_cmd_base cmd_base;
113
114 /* fill up command register */
115 memset(&cmd_base, 0, sizeof(cmd_base));
116 cmd_base.s.cmd_id = ENABLE_SENSOR;
117 cmd_base.s.period = info.period;
118 cmd_base.s.sensor_id = info.sensor_idx;
119
120 /* fill up command param register */
121 memset(&cmd_param, 0, sizeof(cmd_param));
122 cmd_param.s.buf_layout = 1;
123 cmd_param.s.buf_length = 16;
124
Arnd Bergmannde304912021-01-03 14:53:55 +0100125 writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG2);
Sandeep Singh4f567b92020-10-10 01:31:36 +0530126 writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
127 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
128}
129
130void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
131{
132 union sfh_cmd_base cmd_base;
133
134 /* fill up command register */
135 memset(&cmd_base, 0, sizeof(cmd_base));
136 cmd_base.s.cmd_id = DISABLE_SENSOR;
137 cmd_base.s.period = 0;
138 cmd_base.s.sensor_id = sensor_idx;
139
140 writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
141 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
142}
143
144void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
145{
146 union sfh_cmd_base cmd_base;
147
148 /* fill up command register */
149 memset(&cmd_base, 0, sizeof(cmd_base));
150 cmd_base.s.cmd_id = STOP_ALL_SENSORS;
151 cmd_base.s.period = 0;
152 cmd_base.s.sensor_id = 0;
153
154 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
155}
156
Hans de Goede25615e42021-01-28 13:12:19 +0100157static const struct dmi_system_id dmi_sensor_mask_overrides[] = {
158 {
159 .matches = {
160 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 13-ag0xxx"),
161 },
162 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
163 },
164 {
165 .matches = {
166 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 15-cp0xxx"),
167 },
168 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
169 },
170 { }
171};
172
Sandeep Singh4f567b92020-10-10 01:31:36 +0530173int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
174{
175 int activestatus, num_of_sensors = 0;
Hans de Goede25615e42021-01-28 13:12:19 +0100176 const struct dmi_system_id *dmi_id;
Sandeep Singh4f567b92020-10-10 01:31:36 +0530177
Hans de Goede25615e42021-01-28 13:12:19 +0100178 if (sensor_mask_override == -1) {
179 dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
180 if (dmi_id)
181 sensor_mask_override = (long)dmi_id->driver_data;
182 }
183
Hans de Goede952f7d12021-01-28 13:12:18 +0100184 if (sensor_mask_override >= 0) {
185 activestatus = sensor_mask_override;
186 } else {
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530187 activestatus = privdata->mp2_acs >> 4;
Hans de Goede952f7d12021-01-28 13:12:18 +0100188 }
Hans de Goedea9e54f42021-01-28 13:12:17 +0100189
Sandeep Singh4f567b92020-10-10 01:31:36 +0530190 if (ACEL_EN & activestatus)
191 sensor_id[num_of_sensors++] = accel_idx;
192
193 if (GYRO_EN & activestatus)
194 sensor_id[num_of_sensors++] = gyro_idx;
195
196 if (MAGNO_EN & activestatus)
197 sensor_id[num_of_sensors++] = mag_idx;
198
199 if (ALS_EN & activestatus)
200 sensor_id[num_of_sensors++] = als_idx;
201
Basavaraj Natikar24a31ea2021-06-18 13:48:38 +0530202 if (HPD_EN & activestatus)
203 sensor_id[num_of_sensors++] = HPD_IDX;
204
Sandeep Singh4f567b92020-10-10 01:31:36 +0530205 return num_of_sensors;
206}
207
208static void amd_mp2_pci_remove(void *privdata)
209{
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530210 struct amd_mp2_dev *mp2 = privdata;
Sandeep Singh4f567b92020-10-10 01:31:36 +0530211 amd_sfh_hid_client_deinit(privdata);
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530212 mp2->mp2_ops->stop_all(mp2);
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530213 amd_sfh_clear_intr(mp2);
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530214}
215
216static const struct amd_mp2_ops amd_sfh_ops_v2 = {
217 .start = amd_start_sensor_v2,
218 .stop = amd_stop_sensor_v2,
219 .stop_all = amd_stop_all_sensor_v2,
Basavaraj Natikar173709f2021-08-02 19:33:38 +0530220 .response = amd_sfh_wait_response_v2,
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530221 .clear_intr = amd_sfh_clear_intr_v2,
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530222};
223
224static const struct amd_mp2_ops amd_sfh_ops = {
225 .start = amd_start_sensor,
226 .stop = amd_stop_sensor,
227 .stop_all = amd_stop_all_sensors,
228};
229
230static void mp2_select_ops(struct amd_mp2_dev *privdata)
231{
232 u8 acs;
233
234 privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
235 acs = privdata->mp2_acs & GENMASK(3, 0);
236
237 switch (acs) {
238 case V2_STATUS:
239 privdata->mp2_ops = &amd_sfh_ops_v2;
240 break;
241 default:
242 privdata->mp2_ops = &amd_sfh_ops;
243 break;
244 }
Sandeep Singh4f567b92020-10-10 01:31:36 +0530245}
246
247static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
248{
249 struct amd_mp2_dev *privdata;
250 int rc;
251
252 privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
253 if (!privdata)
254 return -ENOMEM;
255
256 privdata->pdev = pdev;
Basavaraj Natikarba70a4f2021-09-23 17:59:29 +0530257 dev_set_drvdata(&pdev->dev, privdata);
Sandeep Singh4f567b92020-10-10 01:31:36 +0530258 rc = pcim_enable_device(pdev);
259 if (rc)
260 return rc;
261
262 rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
263 if (rc)
264 return rc;
265
266 privdata->mmio = pcim_iomap_table(pdev)[2];
267 pci_set_master(pdev);
Basavaraj Natikarc45d2b52021-09-23 17:59:28 +0530268 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
Sandeep Singh4f567b92020-10-10 01:31:36 +0530269 if (rc) {
Basavaraj Natikarc45d2b52021-09-23 17:59:28 +0530270 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
271 if (rc) {
272 dev_err(&pdev->dev, "failed to set DMA mask\n");
273 return rc;
274 }
Sandeep Singh4f567b92020-10-10 01:31:36 +0530275 }
Basavaraj Natikar0aad9c92021-06-18 13:48:37 +0530276
277 privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
278 if (!privdata->cl_data)
279 return -ENOMEM;
280
Basavaraj Natikar88a04042021-09-23 17:59:27 +0530281 mp2_select_ops(privdata);
282
283 rc = amd_sfh_hid_client_init(privdata);
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530284 if (rc) {
285 amd_sfh_clear_intr(privdata);
286 dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
Sandeep Singh4f567b92020-10-10 01:31:36 +0530287 return rc;
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530288 }
289
290 amd_sfh_clear_intr(privdata);
Sandeep Singh4f567b92020-10-10 01:31:36 +0530291
Basavaraj Natikar88a04042021-09-23 17:59:27 +0530292 return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
Sandeep Singh4f567b92020-10-10 01:31:36 +0530293}
294
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530295static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
296{
Basavaraj Natikarba70a4f2021-09-23 17:59:29 +0530297 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530298 struct amdtp_cl_data *cl_data = mp2->cl_data;
299 struct amd_mp2_sensor_info info;
300 int i, status;
301
302 for (i = 0; i < cl_data->num_hid_devices; i++) {
303 if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
304 info.period = AMD_SFH_IDLE_LOOP;
305 info.sensor_idx = cl_data->sensor_idx[i];
306 info.dma_address = cl_data->sensor_dma_addr[i];
307 mp2->mp2_ops->start(mp2, info);
308 status = amd_sfh_wait_for_response
309 (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
310 if (status == SENSOR_ENABLED)
311 cl_data->sensor_sts[i] = SENSOR_ENABLED;
Basavaraj Natikare6657752021-08-02 19:33:41 +0530312 dev_dbg(dev, "resume sid 0x%x status 0x%x\n",
313 cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530314 }
315 }
316
Basavaraj Natikar0cf74232022-02-08 17:51:08 +0530317 schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530318 amd_sfh_clear_intr(mp2);
Basavaraj Natikar0cf74232022-02-08 17:51:08 +0530319
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530320 return 0;
321}
322
323static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
324{
Basavaraj Natikarba70a4f2021-09-23 17:59:29 +0530325 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530326 struct amdtp_cl_data *cl_data = mp2->cl_data;
327 int i, status;
328
329 for (i = 0; i < cl_data->num_hid_devices; i++) {
330 if (cl_data->sensor_idx[i] != HPD_IDX &&
331 cl_data->sensor_sts[i] == SENSOR_ENABLED) {
332 mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
333 status = amd_sfh_wait_for_response
334 (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
335 if (status != SENSOR_ENABLED)
336 cl_data->sensor_sts[i] = SENSOR_DISABLED;
Basavaraj Natikare6657752021-08-02 19:33:41 +0530337 dev_dbg(dev, "suspend sid 0x%x status 0x%x\n",
338 cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530339 }
340 }
341
Basavaraj Natikar0cf74232022-02-08 17:51:08 +0530342 cancel_delayed_work_sync(&cl_data->work_buffer);
Basavaraj Natikarfb75a372022-02-08 17:51:11 +0530343 amd_sfh_clear_intr(mp2);
Basavaraj Natikar0cf74232022-02-08 17:51:08 +0530344
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530345 return 0;
346}
347
348static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
349 amd_mp2_pci_resume);
350
Sandeep Singh4f567b92020-10-10 01:31:36 +0530351static const struct pci_device_id amd_mp2_pci_tbl[] = {
352 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
353 { }
354};
355MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
356
357static struct pci_driver amd_mp2_pci_driver = {
358 .name = DRIVER_NAME,
359 .id_table = amd_mp2_pci_tbl,
360 .probe = amd_mp2_pci_probe,
Basavaraj Natikar0873d1a2021-08-02 19:33:40 +0530361 .driver.pm = &amd_mp2_pm_ops,
Sandeep Singh4f567b92020-10-10 01:31:36 +0530362};
363module_pci_driver(amd_mp2_pci_driver);
364
365MODULE_DESCRIPTION(DRIVER_DESC);
366MODULE_LICENSE("Dual BSD/GPL");
367MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
368MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");
Basavaraj Natikarf75203c2021-09-23 17:59:30 +0530369MODULE_AUTHOR("Basavaraj Natikar <Basavaraj.Natikar@amd.com>");