Skip to content

Commit 4f567b9

Browse files
Sandeep SinghJiri Kosina
authored andcommitted
SFH: PCIe driver to add support of AMD sensor fusion hub
AMD SFH (Sensor Fusion Hub) is a solution running on MP2 (which is ARM core connected to x86 for processing sensor data). AMD SFH uses HID over PCI bus to form the HID descriptors and talks to HID clients like the monitor-sensor/iio-proxy. MP2 which is exposed as a PCI device to the x86, uses mailboxes to talk to MP2 firmware to send/receive commands. Co-developed-by: Nehal Shah <[email protected]> Signed-off-by: Nehal Shah <[email protected]> Signed-off-by: Sandeep Singh <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 302f0da commit 4f567b9

File tree

6 files changed

+266
-0
lines changed

6 files changed

+266
-0
lines changed

drivers/hid/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,4 +1183,6 @@ source "drivers/hid/i2c-hid/Kconfig"
11831183

11841184
source "drivers/hid/intel-ish-hid/Kconfig"
11851185

1186+
source "drivers/hid/amd-sfh-hid/Kconfig"
1187+
11861188
endmenu

drivers/hid/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/
142142

143143
obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
144144
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
145+
146+
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/

drivers/hid/amd-sfh-hid/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# SPDX-License-Identifier: GPL-2.0-or-later
2+
menu "AMD SFH HID Support"
3+
depends on X86_64 || COMPILE_TEST
4+
depends on PCI
5+
depends on HID
6+
7+
config AMD_SFH_HID
8+
tristate "AMD Sensor Fusion Hub"
9+
help
10+
If you say yes to this option, support will be included for the
11+
AMD Sensor Fusion Hub.
12+
This driver will enable sensors functionality on AMD platforms
13+
starting from 17h family of RYZEN parts.
14+
15+
This driver can also be built as a module. If so, the module will
16+
be called amd-sfh.
17+
Say Y or M here if you want to support AMD SFH. If unsure, say N.
18+
endmenu

drivers/hid/amd-sfh-hid/Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# SPDX-License-Identifier: GPL-2.0-or-later
2+
#
3+
# Makefile - AMD SFH HID drivers
4+
# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
5+
#
6+
#
7+
obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o
8+
amd_sfh-objs := amd_sfh_hid.o
9+
amd_sfh-objs += amd_sfh_client.o
10+
amd_sfh-objs += amd_sfh_pcie.o
11+
amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o
12+
13+
ccflags-y += -I $(srctree)/$(src)/
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// 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 <[email protected]>
7+
* Sandeep Singh <[email protected]>
8+
*/
9+
10+
#include <linux/bitops.h>
11+
#include <linux/delay.h>
12+
#include <linux/dma-mapping.h>
13+
#include <linux/interrupt.h>
14+
#include <linux/io-64-nonatomic-lo-hi.h>
15+
#include <linux/module.h>
16+
#include <linux/slab.h>
17+
18+
#include "amd_sfh_pcie.h"
19+
20+
#define DRIVER_NAME "pcie_mp2_amd"
21+
#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver"
22+
23+
#define ACEL_EN BIT(1)
24+
#define GYRO_EN BIT(2)
25+
#define MAGNO_EN BIT(3)
26+
#define ALS_EN BIT(19)
27+
28+
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
29+
{
30+
union sfh_cmd_param cmd_param;
31+
union sfh_cmd_base cmd_base;
32+
33+
/* fill up command register */
34+
memset(&cmd_base, 0, sizeof(cmd_base));
35+
cmd_base.s.cmd_id = ENABLE_SENSOR;
36+
cmd_base.s.period = info.period;
37+
cmd_base.s.sensor_id = info.sensor_idx;
38+
39+
/* fill up command param register */
40+
memset(&cmd_param, 0, sizeof(cmd_param));
41+
cmd_param.s.buf_layout = 1;
42+
cmd_param.s.buf_length = 16;
43+
44+
writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2);
45+
writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1);
46+
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
47+
}
48+
49+
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
50+
{
51+
union sfh_cmd_base cmd_base;
52+
53+
/* fill up command register */
54+
memset(&cmd_base, 0, sizeof(cmd_base));
55+
cmd_base.s.cmd_id = DISABLE_SENSOR;
56+
cmd_base.s.period = 0;
57+
cmd_base.s.sensor_id = sensor_idx;
58+
59+
writeq(0x0, privdata->mmio + AMD_C2P_MSG2);
60+
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
61+
}
62+
63+
void amd_stop_all_sensors(struct amd_mp2_dev *privdata)
64+
{
65+
union sfh_cmd_base cmd_base;
66+
67+
/* fill up command register */
68+
memset(&cmd_base, 0, sizeof(cmd_base));
69+
cmd_base.s.cmd_id = STOP_ALL_SENSORS;
70+
cmd_base.s.period = 0;
71+
cmd_base.s.sensor_id = 0;
72+
73+
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0);
74+
}
75+
76+
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
77+
{
78+
int activestatus, num_of_sensors = 0;
79+
80+
privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3);
81+
activestatus = privdata->activecontrolstatus >> 4;
82+
if (ACEL_EN & activestatus)
83+
sensor_id[num_of_sensors++] = accel_idx;
84+
85+
if (GYRO_EN & activestatus)
86+
sensor_id[num_of_sensors++] = gyro_idx;
87+
88+
if (MAGNO_EN & activestatus)
89+
sensor_id[num_of_sensors++] = mag_idx;
90+
91+
if (ALS_EN & activestatus)
92+
sensor_id[num_of_sensors++] = als_idx;
93+
94+
return num_of_sensors;
95+
}
96+
97+
static void amd_mp2_pci_remove(void *privdata)
98+
{
99+
amd_sfh_hid_client_deinit(privdata);
100+
amd_stop_all_sensors(privdata);
101+
}
102+
103+
static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
104+
{
105+
struct amd_mp2_dev *privdata;
106+
int rc;
107+
108+
privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
109+
if (!privdata)
110+
return -ENOMEM;
111+
112+
privdata->pdev = pdev;
113+
pci_set_drvdata(pdev, privdata);
114+
rc = pcim_enable_device(pdev);
115+
if (rc)
116+
return rc;
117+
118+
rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME);
119+
if (rc)
120+
return rc;
121+
122+
privdata->mmio = pcim_iomap_table(pdev)[2];
123+
pci_set_master(pdev);
124+
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
125+
if (rc) {
126+
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
127+
return rc;
128+
}
129+
rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata);
130+
if (rc)
131+
return rc;
132+
133+
return amd_sfh_hid_client_init(privdata);
134+
}
135+
136+
static const struct pci_device_id amd_mp2_pci_tbl[] = {
137+
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
138+
{ }
139+
};
140+
MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
141+
142+
static struct pci_driver amd_mp2_pci_driver = {
143+
.name = DRIVER_NAME,
144+
.id_table = amd_mp2_pci_tbl,
145+
.probe = amd_mp2_pci_probe,
146+
};
147+
module_pci_driver(amd_mp2_pci_driver);
148+
149+
MODULE_DESCRIPTION(DRIVER_DESC);
150+
MODULE_LICENSE("Dual BSD/GPL");
151+
MODULE_AUTHOR("Shyam Sundar S K <[email protected]>");
152+
MODULE_AUTHOR("Sandeep Singh <[email protected]>");
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* AMD MP2 PCIe communication driver
4+
* Copyright 2020 Advanced Micro Devices, Inc.
5+
* Authors: Shyam Sundar S K <[email protected]>
6+
* Sandeep Singh <[email protected]>
7+
*/
8+
9+
#ifndef PCIE_MP2_AMD_H
10+
#define PCIE_MP2_AMD_H
11+
12+
#include <linux/pci.h>
13+
14+
#define PCI_DEVICE_ID_AMD_MP2 0x15E4
15+
16+
#define ENABLE_SENSOR 1
17+
#define DISABLE_SENSOR 2
18+
#define STOP_ALL_SENSORS 8
19+
20+
/* MP2 C2P Message Registers */
21+
#define AMD_C2P_MSG0 0x10500
22+
#define AMD_C2P_MSG1 0x10504
23+
#define AMD_C2P_MSG2 0x10508
24+
25+
/* MP2 P2C Message Registers */
26+
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
27+
28+
/* SFH Command register */
29+
union sfh_cmd_base {
30+
u32 ul;
31+
struct {
32+
u32 cmd_id : 8;
33+
u32 sensor_id : 8;
34+
u32 period : 16;
35+
} s;
36+
};
37+
38+
union sfh_cmd_param {
39+
u32 ul;
40+
struct {
41+
u32 buf_layout : 2;
42+
u32 buf_length : 6;
43+
u32 rsvd : 24;
44+
} s;
45+
};
46+
47+
struct sfh_cmd_reg {
48+
union sfh_cmd_base cmd_base;
49+
union sfh_cmd_param cmd_param;
50+
phys_addr_t phys_addr;
51+
};
52+
53+
enum sensor_idx {
54+
accel_idx = 0,
55+
gyro_idx = 1,
56+
mag_idx = 2,
57+
als_idx = 19
58+
};
59+
60+
struct amd_mp2_dev {
61+
struct pci_dev *pdev;
62+
struct amdtp_cl_data *cl_data;
63+
void __iomem *mmio;
64+
u32 activecontrolstatus;
65+
};
66+
67+
struct amd_mp2_sensor_info {
68+
u8 sensor_idx;
69+
u32 period;
70+
phys_addr_t phys_address;
71+
};
72+
73+
void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
74+
void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx);
75+
void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
76+
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
77+
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
78+
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
79+
#endif

0 commit comments

Comments
 (0)