Commit 4f567b9f authored by Sandeep Singh's avatar Sandeep Singh Committed by Jiri Kosina
Browse files

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: default avatarNehal Shah <Nehal-bakulchandra.Shah@amd.com>
Signed-off-by: default avatarNehal Shah <Nehal-bakulchandra.Shah@amd.com>
Signed-off-by: default avatarSandeep Singh <sandeep.singh@amd.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 302f0dad
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1183,4 +1183,6 @@ source "drivers/hid/i2c-hid/Kconfig"

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

source "drivers/hid/amd-sfh-hid/Kconfig"

endmenu
+2 −0
Original line number Diff line number Diff line
@@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/

obj-$(CONFIG_INTEL_ISH_HID)	+= intel-ish-hid/
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER)	+= intel-ish-hid/

obj-$(CONFIG_AMD_SFH_HID)       += amd-sfh-hid/
+18 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-or-later
menu "AMD SFH HID Support"
	depends on X86_64 || COMPILE_TEST
	depends on PCI
	depends on HID

config AMD_SFH_HID
	tristate "AMD Sensor Fusion Hub"
	help
	  If you say yes to this option, support will be included for the
	  AMD Sensor Fusion Hub.
	  This driver will enable sensors functionality on AMD platforms
	  starting from 17h family of RYZEN parts.

	  This driver can also be built as a module. If so, the module will
	  be called amd-sfh.
	  Say Y or M here if you want to support AMD SFH. If unsure, say N.
endmenu
+13 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Makefile - AMD SFH HID drivers
# Copyright (c) 2019-2020, Advanced Micro Devices, Inc.
#
#
obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o
amd_sfh-objs := amd_sfh_hid.o
amd_sfh-objs += amd_sfh_client.o
amd_sfh-objs += amd_sfh_pcie.o
amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o

ccflags-y += -I $(srctree)/$(src)/
+152 −0
Original line number Diff line number Diff line
// 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(1)
#define GYRO_EN		BIT(2)
#define MAGNO_EN	BIT(3)
#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>");
Loading