amd_sfh_pcie.c 10 KB

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