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