blob: ff131f450bdcc7a5c2aaa32d99a723d072a510d3 [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
4 * Copyright 2020 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 */
9
10#include <linux/bitops.h>
11#include <linux/delay.h>
12#include <linux/dma-mapping.h>
Hans de Goede25615e42021-01-28 13:12:19 +010013#include <linux/dmi.h>
Sandeep Singh4f567b92020-10-10 01:31:36 +053014#include <linux/interrupt.h>
15#include <linux/io-64-nonatomic-lo-hi.h>
16#include <linux/module.h>
17#include <linux/slab.h>
18
19#include "amd_sfh_pcie.h"
20
21#define DRIVER_NAME "pcie_mp2_amd"
22#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
23
Sandeep Singh4b393f02020-10-28 14:30:10 +053024#define ACEL_EN BIT(0)
25#define GYRO_EN BIT(1)
Hans de Goede952f7d12021-01-28 13:12:18 +010026#define MAGNO_EN BIT(2)
Sandeep Singh4f567b92020-10-10 01:31:36 +053027#define ALS_EN BIT(19)
28
Hans de Goede952f7d12021-01-28 13:12:18 +010029static int sensor_mask_override = -1;
30module_param_named(sensor_mask, sensor_mask_override, int, 0444);
31MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
32
Basavaraj Natikarf2644812021-06-18 13:48:36 +053033static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
34{
35 union sfh_cmd_base cmd_base;
36
37 cmd_base.ul = 0;
38 cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
39 cmd_base.cmd_v2.period = info.period;
40 cmd_base.cmd_v2.sensor_id = info.sensor_idx;
41 cmd_base.cmd_v2.length = 16;
42
43 if (info.sensor_idx == als_idx)
44 cmd_base.cmd_v2.mem_type = USE_C2P_REG;
45
46 writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG1);
47 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
48}
49
50static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
51{
52 union sfh_cmd_base cmd_base;
53
54 cmd_base.ul = 0;
55 cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
56 cmd_base.cmd_v2.period = 0;
57 cmd_base.cmd_v2.sensor_id = sensor_idx;
58 cmd_base.cmd_v2.length = 16;
59
60 writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
61 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
62}
63
64static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
65{
66 union sfh_cmd_base cmd_base;
67
68 cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
69 cmd_base.cmd_v2.period = 0;
70 cmd_base.cmd_v2.sensor_id = 0;
71
72 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
73}
74
Sandeep Singh4f567b92020-10-10 01:31:36 +053075void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
76{
77 union sfh_cmd_param cmd_param;
78 union sfh_cmd_base cmd_base;
79
80 /* fill up command register */
81 memset(&cmd_base, 0, sizeof(cmd_base));
82 cmd_base.s.cmd_id = ENABLE_SENSOR;
83 cmd_base.s.period = info.period;
84 cmd_base.s.sensor_id = info.sensor_idx;
85
86 /* fill up command param register */
87 memset(&cmd_param, 0, sizeof(cmd_param));
88 cmd_param.s.buf_layout = 1;
89 cmd_param.s.buf_length = 16;
90
Arnd Bergmannde304912021-01-03 14:53:55 +010091 writeq(info.dma_address, privdata->mmio + AMD_C2P_MSG2);
Sandeep Singh4f567b92020-10-10 01:31:36 +053092 writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
93 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
94}
95
96void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
97{
98 union sfh_cmd_base cmd_base;
99
100 /* fill up command register */
101 memset(&cmd_base, 0, sizeof(cmd_base));
102 cmd_base.s.cmd_id = DISABLE_SENSOR;
103 cmd_base.s.period = 0;
104 cmd_base.s.sensor_id = sensor_idx;
105
106 writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
107 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
108}
109
110void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
111{
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 = STOP_ALL_SENSORS;
117 cmd_base.s.period = 0;
118 cmd_base.s.sensor_id = 0;
119
120 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
121}
122
Hans de Goede25615e42021-01-28 13:12:19 +0100123static const struct dmi_system_id dmi_sensor_mask_overrides[] = {
124 {
125 .matches = {
126 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 13-ag0xxx"),
127 },
128 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
129 },
130 {
131 .matches = {
132 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 15-cp0xxx"),
133 },
134 .driver_data = (void *)(ACEL_EN | MAGNO_EN),
135 },
136 { }
137};
138
Sandeep Singh4f567b92020-10-10 01:31:36 +0530139int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
140{
141 int activestatus, num_of_sensors = 0;
Hans de Goede25615e42021-01-28 13:12:19 +0100142 const struct dmi_system_id *dmi_id;
Sandeep Singh4f567b92020-10-10 01:31:36 +0530143
Hans de Goede25615e42021-01-28 13:12:19 +0100144 if (sensor_mask_override == -1) {
145 dmi_id = dmi_first_match(dmi_sensor_mask_overrides);
146 if (dmi_id)
147 sensor_mask_override = (long)dmi_id->driver_data;
148 }
149
Hans de Goede952f7d12021-01-28 13:12:18 +0100150 if (sensor_mask_override >= 0) {
151 activestatus = sensor_mask_override;
152 } else {
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530153 activestatus = privdata->mp2_acs >> 4;
Hans de Goede952f7d12021-01-28 13:12:18 +0100154 }
Hans de Goedea9e54f42021-01-28 13:12:17 +0100155
Sandeep Singh4f567b92020-10-10 01:31:36 +0530156 if (ACEL_EN & activestatus)
157 sensor_id[num_of_sensors++] = accel_idx;
158
159 if (GYRO_EN & activestatus)
160 sensor_id[num_of_sensors++] = gyro_idx;
161
162 if (MAGNO_EN & activestatus)
163 sensor_id[num_of_sensors++] = mag_idx;
164
165 if (ALS_EN & activestatus)
166 sensor_id[num_of_sensors++] = als_idx;
167
168 return num_of_sensors;
169}
170
171static void amd_mp2_pci_remove(void *privdata)
172{
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530173 struct amd_mp2_dev *mp2 = privdata;
Sandeep Singh4f567b92020-10-10 01:31:36 +0530174 amd_sfh_hid_client_deinit(privdata);
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530175 mp2->mp2_ops->stop_all(mp2);
176}
177
178static const struct amd_mp2_ops amd_sfh_ops_v2 = {
179 .start = amd_start_sensor_v2,
180 .stop = amd_stop_sensor_v2,
181 .stop_all = amd_stop_all_sensor_v2,
182};
183
184static const struct amd_mp2_ops amd_sfh_ops = {
185 .start = amd_start_sensor,
186 .stop = amd_stop_sensor,
187 .stop_all = amd_stop_all_sensors,
188};
189
190static void mp2_select_ops(struct amd_mp2_dev *privdata)
191{
192 u8 acs;
193
194 privdata->mp2_acs = readl(privdata->mmio + AMD_P2C_MSG3);
195 acs = privdata->mp2_acs & GENMASK(3, 0);
196
197 switch (acs) {
198 case V2_STATUS:
199 privdata->mp2_ops = &amd_sfh_ops_v2;
200 break;
201 default:
202 privdata->mp2_ops = &amd_sfh_ops;
203 break;
204 }
Sandeep Singh4f567b92020-10-10 01:31:36 +0530205}
206
207static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
208{
209 struct amd_mp2_dev *privdata;
210 int rc;
211
212 privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
213 if (!privdata)
214 return -ENOMEM;
215
216 privdata->pdev = pdev;
217 pci_set_drvdata(pdev, privdata);
218 rc = pcim_enable_device(pdev);
219 if (rc)
220 return rc;
221
222 rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
223 if (rc)
224 return rc;
225
226 privdata->mmio = pcim_iomap_table(pdev)[2];
227 pci_set_master(pdev);
228 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
229 if (rc) {
230 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
231 return rc;
232 }
Basavaraj Natikar0aad9c92021-06-18 13:48:37 +0530233
234 privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
235 if (!privdata->cl_data)
236 return -ENOMEM;
237
Sandeep Singh4f567b92020-10-10 01:31:36 +0530238 rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
239 if (rc)
240 return rc;
241
Basavaraj Natikarf2644812021-06-18 13:48:36 +0530242 mp2_select_ops(privdata);
243
Sandeep Singh4f567b92020-10-10 01:31:36 +0530244 return amd_sfh_hid_client_init(privdata);
245}
246
247static const struct pci_device_id amd_mp2_pci_tbl[] = {
248 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
249 { }
250};
251MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
252
253static struct pci_driver amd_mp2_pci_driver = {
254 .name = DRIVER_NAME,
255 .id_table = amd_mp2_pci_tbl,
256 .probe = amd_mp2_pci_probe,
257};
258module_pci_driver(amd_mp2_pci_driver);
259
260MODULE_DESCRIPTION(DRIVER_DESC);
261MODULE_LICENSE("Dual BSD/GPL");
262MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>");
263MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>");