diff options
author | Jiri Kosina <jkosina@suse.cz> | 2020-12-16 11:33:06 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2020-12-16 11:37:48 +0100 |
commit | 36ed0958feaffc99214b17f668127bc2cfdcf5b4 (patch) | |
tree | 5c8202f751d73a37d2892d004b5cd15bff72292c /drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | |
parent | c870d50ce387d84b6438211a7044c60afbd5d60a (diff) | |
parent | 6e6eae04f5123b7b2f4265f7a702b5200fa5863b (diff) |
Merge branch 'for-5.11/amd-sfh-hid' into for-linus
From Sandeep Singh.
AMD SFH (Sensor Fusion Hub) is HID based driver.SFH FW is part of MP2 processor
(MP2 which is an ARM core connected to x86 for processing sensor data) and it
runs on MP2 where in the driver resides on X86. The driver functionalities are
divided into three parts:
1: amd-mp2-pcie:- This part of the module will communicate with MP2
firmware. MP2 which is exposed as a PCI device to the
X86, uses mailboxes to talk to MP2 firmware to
send/receive commands.
2: Client Layer:- This part of the driver will use DRAM data and convert
the data into HID format based on HID reports.
3: Transport layer :- This part of the driver the will communicate with HID
core.Communication between devices and HID core is
mostly done via HID reports
In terms of architecture, it resembles like ISH (Intel Integrated Sensor Hub).
However the major difference is all the hid reports are generated as part of
the kernel driver.
AMD SFH is integrated as a part of SoC, starting from 17h family of processors.
The solution is working well on several OEM products. AMD SFH uses HID over
PCIe bus.
Diffstat (limited to 'drivers/hid/amd-sfh-hid/amd_sfh_pcie.c')
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c new file mode 100644 index 000000000000..a51c7b76283b --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 PCIe communication driver + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "amd_sfh_pcie.h" + +#define DRIVER_NAME "pcie_mp2_amd" +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" + +#define ACEL_EN BIT(0) +#define GYRO_EN BIT(1) +#define MAGNO_EN BIT(2) +#define ALS_EN BIT(19) + +void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) +{ + union sfh_cmd_param cmd_param; + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = ENABLE_SENSOR; + cmd_base.s.period = info.period; + cmd_base.s.sensor_id = info.sensor_idx; + + /* fill up command param register */ + memset(&cmd_param, 0, sizeof(cmd_param)); + cmd_param.s.buf_layout = 1; + cmd_param.s.buf_length = 16; + + writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2); + writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1); + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) +{ + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = DISABLE_SENSOR; + cmd_base.s.period = 0; + cmd_base.s.sensor_id = sensor_idx; + + writeq(0x0, privdata->mmio + AMD_C2P_MSG2); + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +void amd_stop_all_sensors(struct amd_mp2_dev *privdata) +{ + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = STOP_ALL_SENSORS; + cmd_base.s.period = 0; + cmd_base.s.sensor_id = 0; + + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id) +{ + int activestatus, num_of_sensors = 0; + + privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); + activestatus = privdata->activecontrolstatus >> 4; + if (ACEL_EN & activestatus) + sensor_id[num_of_sensors++] = accel_idx; + + if (GYRO_EN & activestatus) + sensor_id[num_of_sensors++] = gyro_idx; + + if (MAGNO_EN & activestatus) + sensor_id[num_of_sensors++] = mag_idx; + + if (ALS_EN & activestatus) + sensor_id[num_of_sensors++] = als_idx; + + return num_of_sensors; +} + +static void amd_mp2_pci_remove(void *privdata) +{ + amd_sfh_hid_client_deinit(privdata); + amd_stop_all_sensors(privdata); +} + +static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct amd_mp2_dev *privdata; + int rc; + + privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL); + if (!privdata) + return -ENOMEM; + + privdata->pdev = pdev; + pci_set_drvdata(pdev, privdata); + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME); + if (rc) + return rc; + + privdata->mmio = pcim_iomap_table(pdev)[2]; + pci_set_master(pdev); + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + return rc; + } + rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); + if (rc) + return rc; + + return amd_sfh_hid_client_init(privdata); +} + +static const struct pci_device_id amd_mp2_pci_tbl[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, + { } +}; +MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl); + +static struct pci_driver amd_mp2_pci_driver = { + .name = DRIVER_NAME, + .id_table = amd_mp2_pci_tbl, + .probe = amd_mp2_pci_probe, +}; +module_pci_driver(amd_mp2_pci_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>"); +MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>"); |