Merge "defconfig: quinvm: Enable HGSL"

This commit is contained in:
qctecmdr 2021-02-26 11:10:59 -08:00 • committed by Gerrit - the friendly Code Review server
commit 5751df3b77
13 changed files with 2075 additions and 0 deletions

View file

@ -31,3 +31,5 @@ CONFIG_RENAME_BLOCK_DEVICE=y
CONFIG_DM_INIT=y
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
# CONFIG_BUILD_ARM64_KERNEL_COMPRESSION_GZIP is not set
CONFIG_QCOM_HGSL=y
CONFIG_QCOM_HGSL_TCSR_SIGNAL=y

View file

@ -658,6 +658,7 @@ config QCOM_GLINK_PKT
some glink packets channel.
source "drivers/soc/qcom/hab/Kconfig"
source "drivers/soc/qcom/hgsl/Kconfig"
config MSM_PERFORMANCE
tristate "msm performance driver to support userspace fmin/fmax request"

View file

@ -96,6 +96,7 @@ obj-$(CONFIG_QTI_HW_KEY_MANAGER) += hwkm.o crypto-qti-hwkm.o
obj-$(CONFIG_QCOM_WDT_CORE) += qcom_wdt_core.o
obj-$(CONFIG_QCOM_SOC_WATCHDOG) += qcom_soc_wdt.o
obj-$(CONFIG_MSM_HAB) += hab/
obj-$(CONFIG_QCOM_HGSL) += hgsl/
ifdef CONFIG_DEBUG_FS
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd-debug.o
endif

View file

@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Hypervisor graphics system layer configuration
#
config QCOM_HGSL
bool "Graphics driver for Hypervisor"
depends on QTI_QUIN_GVM
help
This driver could help commands submmitting functions for
hypervisor Linux. With HFI feature provided by A6x, it
could submit commands directly to hardware without passing
them to host system.
config QCOM_HGSL_TCSR_SIGNAL
bool "TCSR signal for Hypervisor GSL"
depends on MFD_SYSCON && QCOM_HGSL
help
The TCSR compute signal module provides hgsl driver
in hypervisor Linux a way to send/receive signals
to/from A6x GPU hardware directly, without going
through host system.

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_QCOM_HGSL) += hgsl.o
obj-$(CONFIG_QCOM_HGSL_TCSR_SIGNAL) += hgsl_tcsr.o

1510
drivers/soc/qcom/hgsl/hgsl.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,279 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "hgsl_tcsr.h"
/* Sender registers */
#define TCSR_GLB_CFG_COMPUTE_SIGNALING_REG 0x000
#define TCSR_COMPUTE_SIGNALING_REG 0x000
/* Receiver registers */
#define TCSR_COMPUTE_SIGNAL_STATUS_REG 0x000
#define TCSR_COMPUTE_SIGNAL_CLEAR_REG 0x400
#define TCSR_COMPUTE_SIGNAL_MASK_REG 0x800
struct hgsl_tcsr {
struct platform_device *pdev;
struct device *client_dev;
struct regmap *regmap;
struct regmap *glb_regmap;
enum hgsl_tcsr_role role;
unsigned int enable_count;
struct mutex dev_mutex;
unsigned int irq_num;
irqreturn_t (*isr)(struct device *dev, u32 status);
};
static irqreturn_t hgsl_tcsr_isr(int irq, void *ptr)
{
struct hgsl_tcsr *tcsr = ptr;
u32 status;
regmap_read(tcsr->regmap, TCSR_COMPUTE_SIGNAL_STATUS_REG, &status);
regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNAL_CLEAR_REG, status);
return tcsr->isr(tcsr->client_dev, status);
}
static int hgsl_tcsr_init_sender(struct hgsl_tcsr *tcsr)
{
struct device *dev = &tcsr->pdev->dev;
struct device_node *np = dev->of_node;
if (tcsr->glb_regmap != NULL)
return 0;
tcsr->regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR_OR_NULL(tcsr->regmap)) {
dev_err(dev, "failed to map sender register\n");
return -ENODEV;
}
tcsr->glb_regmap = syscon_regmap_lookup_by_phandle(np, "syscon-glb");
if (IS_ERR_OR_NULL(tcsr->glb_regmap)) {
dev_err(dev, "failed to map sender global register\n");
tcsr->glb_regmap = NULL;
return -ENODEV;
}
return 0;
}
static int hgsl_tcsr_init_receiver(struct hgsl_tcsr *tcsr)
{
struct device *dev = &tcsr->pdev->dev;
struct device_node *np = dev->of_node;
int ret;
if (tcsr->irq_num != 0)
return 0;
tcsr->regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR_OR_NULL(tcsr->regmap)) {
dev_err(dev, "failed to map receiver register\n");
return -ENODEV;
}
tcsr->irq_num = irq_of_parse_and_map(np, 0);
if (tcsr->irq_num == 0) {
dev_err(dev, "failed to get irq\n");
return -ENODEV;
}
ret = devm_request_irq(dev, tcsr->irq_num, hgsl_tcsr_isr,
IRQF_TRIGGER_HIGH, "hgsl-tcsr", tcsr);
if (ret < 0) {
dev_err(dev, "failed to request IRQ%u: %d\n",
tcsr->irq_num, ret);
tcsr->irq_num = 0;
return ret;
}
disable_irq(tcsr->irq_num);
return 0;
}
struct hgsl_tcsr *hgsl_tcsr_request(struct platform_device *pdev,
enum hgsl_tcsr_role role,
struct device *client,
irqreturn_t (*isr)(struct device *, u32))
{
struct hgsl_tcsr *tcsr = platform_get_drvdata(pdev);
int ret;
if (!tcsr)
return ERR_PTR(-ENODEV);
else if (tcsr->role != role)
return ERR_PTR(-EINVAL);
else if (tcsr->client_dev)
return ERR_PTR(-EBUSY);
if (role == HGSL_TCSR_ROLE_RECEIVER) {
if (tcsr->isr)
return ERR_PTR(-EBUSY);
else if (!isr)
return ERR_PTR(-EINVAL);
ret = hgsl_tcsr_init_receiver(tcsr);
} else { /* HGSL_TCSR_ROLE_SENDER */
if (isr)
return ERR_PTR(-EINVAL);
ret = hgsl_tcsr_init_sender(tcsr);
}
if (ret == 0) {
tcsr->client_dev = client;
tcsr->isr = isr;
}
return tcsr;
}
void hgsl_tcsr_free(struct hgsl_tcsr *tcsr)
{
tcsr->client_dev = NULL;
tcsr->isr = NULL;
}
int hgsl_tcsr_enable(struct hgsl_tcsr *tcsr)
{
mutex_lock(&tcsr->dev_mutex);
if (tcsr->enable_count > 0)
goto done;
if (tcsr->irq_num)
enable_irq(tcsr->irq_num);
done:
tcsr->enable_count++;
mutex_unlock(&tcsr->dev_mutex);
return 0;
}
void hgsl_tcsr_disable(struct hgsl_tcsr *tcsr)
{
mutex_lock(&tcsr->dev_mutex);
if (--tcsr->enable_count > 0)
goto done;
if (tcsr->irq_num)
disable_irq(tcsr->irq_num);
done:
mutex_unlock(&tcsr->dev_mutex);
}
bool hgsl_tcsr_is_enabled(struct hgsl_tcsr *tcsr)
{
return (tcsr->enable_count > 0);
}
void hgsl_tcsr_irq_trigger(struct hgsl_tcsr *tcsr, int irq_id)
{
u32 reg;
/*
* Read back this global config register in case
* it has been modified by others.
*/
regmap_read(tcsr->glb_regmap,
TCSR_GLB_CFG_COMPUTE_SIGNALING_REG, &reg);
reg = irq_id << reg;
regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNALING_REG, reg);
}
void hgsl_tcsr_irq_enable(struct hgsl_tcsr *tcsr, u32 mask, bool enable)
{
u32 reg;
regmap_read(tcsr->regmap, TCSR_COMPUTE_SIGNAL_MASK_REG, &reg);
reg = enable ? (reg | mask) : (reg & ~mask);
regmap_write(tcsr->regmap, TCSR_COMPUTE_SIGNAL_MASK_REG, reg);
}
static const struct of_device_id hgsl_tcsr_match_table[] = {
{ .compatible = "qcom,hgsl-tcsr-sender" },
{ .compatible = "qcom,hgsl-tcsr-receiver" },
{}
};
static int hgsl_tcsr_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct hgsl_tcsr *tcsr = devm_kzalloc(dev, sizeof(*tcsr),
GFP_KERNEL);
if (!tcsr)
return -ENOMEM;
if (of_device_is_compatible(np, "qcom,hgsl-tcsr-receiver")) {
tcsr->role = HGSL_TCSR_ROLE_RECEIVER;
} else if (of_device_is_compatible(np, "qcom,hgsl-tcsr-sender")) {
tcsr->role = HGSL_TCSR_ROLE_SENDER;
} else {
dev_err(dev, "Not compatible device\n");
return -ENODEV;
}
mutex_init(&tcsr->dev_mutex);
tcsr->pdev = pdev;
platform_set_drvdata(pdev, tcsr);
return 0;
}
static int hgsl_tcsr_remove(struct platform_device *pdev)
{
struct hgsl_tcsr *tcsr = platform_get_drvdata(pdev);
mutex_destroy(&tcsr->dev_mutex);
return 0;
}
static struct platform_driver hgsl_tcsr_driver = {
.probe = hgsl_tcsr_probe,
.remove = hgsl_tcsr_remove,
.driver = {
.name = "hgsl-tcsr",
.of_match_table = hgsl_tcsr_match_table,
}
};
static int __init hgsl_tcsr_init(void)
{
return platform_driver_register(&hgsl_tcsr_driver);
}
static void __exit hgsl_tcsr_exit(void)
{
platform_driver_unregister(&hgsl_tcsr_driver);
}
subsys_initcall(hgsl_tcsr_init);
module_exit(hgsl_tcsr_exit);

View file

@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __HGSL_TCSR_H
#define __HGSL_TCSR_H
#include <linux/device.h>
#include <linux/irqreturn.h>
#include <linux/platform_device.h>
/*
* We need to separate bit slots between KMD and GMU,
* to avoid one processor signaling back to itself.
* GMU should have the same definitions.
*
* Allocated 4 bits for KMD and 2 for GMU. 3 KMD bits
* can be used by submission and 1 GMU bits for TS
* retire. The other 1 bit is reserved for furture use.
*/
#define TCSR_KMD_TRIGGER_IRQ_ID_0 0
#define TCSR_KMD_TRIGGER_IRQ_ID_1 1
#define TCSR_KMD_TRIGGER_IRQ_ID_2 2
#define TCSR_KMD_TRIGGER_IRQ_ID_3 3
#define TCSR_GMU_TRIGGER_IRQ_ID_0 8
#define TCSR_GMU_TRIGGER_IRQ_ID_1 9
/* Define Source and Destination IRQ for KMD */
#define TCSR_SRC_IRQ_ID_0 TCSR_KMD_TRIGGER_IRQ_ID_0
#define TCSR_SRC_IRQ_ID_1 TCSR_KMD_TRIGGER_IRQ_ID_1
#define TCSR_SRC_IRQ_ID_2 TCSR_KMD_TRIGGER_IRQ_ID_2
#define TCSR_SRC_IRQ_ID_3 TCSR_KMD_TRIGGER_IRQ_ID_3
#define TCSR_DEST_IRQ_ID_0 TCSR_GMU_TRIGGER_IRQ_ID_0
#define TCSR_DEST_IRQ_ID_1 TCSR_GMU_TRIGGER_IRQ_ID_1
#define TCSR_DEST_IRQ_MASK_0 (1 << TCSR_DEST_IRQ_ID_0)
#define TCSR_DEST_IRQ_MASK_1 (1 << TCSR_DEST_IRQ_ID_1)
#define TCSR_DEST_IRQ_MASK (TCSR_DEST_IRQ_MASK_0 | TCSR_DEST_IRQ_MASK_1)
enum hgsl_tcsr_role {
HGSL_TCSR_ROLE_SENDER = 0,
HGSL_TCSR_ROLE_RECEIVER = 1,
HGSL_TCSR_ROLE_MAX,
};
struct hgsl_tcsr;
#ifdef CONFIG_QCOM_HGSL_TCSR_SIGNAL
struct hgsl_tcsr *hgsl_tcsr_request(struct platform_device *pdev,
enum hgsl_tcsr_role role,
struct device *client,
irqreturn_t (*isr)(struct device *, u32));
void hgsl_tcsr_free(struct hgsl_tcsr *tcsr);
int hgsl_tcsr_enable(struct hgsl_tcsr *tcsr);
void hgsl_tcsr_disable(struct hgsl_tcsr *tcsr);
bool hgsl_tcsr_is_enabled(struct hgsl_tcsr *tcsr);
void hgsl_tcsr_irq_trigger(struct hgsl_tcsr *tcsr, int irq_id);
void hgsl_tcsr_irq_enable(struct hgsl_tcsr *tcsr, u32 mask, bool enable);
#else
static inline struct hgsl_tcsr *hgsl_tcsr_request(struct platform_device *pdev,
enum hgsl_tcsr_role role,
struct device *client,
irqreturn_t (*isr)(struct device *, u32))
{
return NULL;
}
static inline void hgsl_tcsr_free(struct hgsl_tcsr *tcsr)
{
}
static inline int hgsl_tcsr_enable(struct hgsl_tcsr *tcsr)
{
return -ENODEV;
}
static inline void hgsl_tcsr_disable(struct hgsl_tcsr *tcsr)
{
}
static inline bool hgsl_tcsr_is_enabled(struct hgsl_tcsr *tcsr)
{
return false;
}
static inline void hgsl_tcsr_irq_trigger(struct hgsl_tcsr *tcsr, int irq_id)
{
}
static inline void hgsl_tcsr_irq_enable(struct hgsl_tcsr *tcsr, u32 mask,
bool enable)
{
}
#endif
#endif /* __HGSL_TCSR_H */

View file

@ -644,6 +644,7 @@ gen_headers_out_arm = [
"linux/zorro_ids.h",
"linux/hab_ioctl.h",
"linux/habmmid.h",
"linux/hgsl.h",
"media/msm_cvp_private.h",
"media/radio-iris-commands.h",
"media/radio-iris.h",

View file

@ -639,6 +639,7 @@ gen_headers_out_arm64 = [
"linux/zorro_ids.h",
"linux/hab_ioctl.h",
"linux/habmmid.h",
"linux/hgsl.h",
"media/msm_cvp_private.h",
"media/radio-iris-commands.h",
"media/radio-iris.h",

View file

@ -639,6 +639,7 @@ gen_headers_out_arm64 = [
"linux/zorro_ids.h",
"linux/hab_ioctl.h",
"linux/habmmid.h",
"linux/hgsl.h",
"media/msm_cvp_private.h",
"media/radio-iris-commands.h",
"media/radio-iris.h",

View file

@ -644,6 +644,7 @@ gen_headers_out_arm = [
"linux/zorro_ids.h",
"linux/hab_ioctl.h",
"linux/habmmid.h",
"linux/hgsl.h",
"media/msm_cvp_private.h",
"media/radio-iris-commands.h",
"media/radio-iris.h",

147
include/uapi/linux/hgsl.h Normal file
View file

@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _UAPI_MSM_HGSL_H
#define _UAPI_MSM_HGSL_H
#include <linux/types.h>
#include <linux/ioctl.h>
struct hgsl_ibdesc {
__u64 gpuaddr;
__u64 sizedwords;
};
struct hgsl_mem_object {
__u64 gpuaddr;
__u64 sizedwords;
};
#define HGSL_IOCTL_BASE 'h'
#define HGSL_IORW(n, t) _IOWR(HGSL_IOCTL_BASE, n, t)
#define HGSL_IOW(n, t) _IOW(HGSL_IOCTL_BASE, n, t)
/**
* return current status of Doorbell system
*/
#define DB_STATE_Q_MASK 0xffff
#define DB_STATE_Q_UNINIT 1
#define DB_STATE_Q_INIT_DONE 2
#define DB_STATE_Q_FAULT 3
#define HGSL_IOCTL_DBQ_GETSTATE HGSL_IORW(0x01, __s32)
/**
* struct hgsl_db_queue_inf - initialize Doorbell
* @fd: File descriptor of DB queue
* @head_dwords: Size of DB queue header
* @head_off_dwords: offset of DB queue header
* @queue_dwords: size of DB queue
* @queue_off_dwords: offset of DB queue
* @db_signal: DB signal type, One of DB_SIGNAL_* values
*
**/
struct hgsl_db_queue_inf {
__s32 fd;
__u32 head_dwords;
__s32 head_off_dwords;
__u32 queue_dwords;
__s32 queue_off_dwords;
__u32 db_signal;
};
#define DB_SIGNAL_INVALID 0
#define DB_SIGNAL_GLOBAL_0 1
#define DB_SIGNAL_GLOBAL_1 2
#define DB_SIGNAL_LOCAL 3
#define DB_SIGNAL_MAX DB_SIGNAL_LOCAL
#define HGSL_IOCTL_DBQ_INIT \
HGSL_IORW(0x02, struct hgsl_db_queue_inf)
/**
* Assign a DB to current instance, input is DB index.
*/
#define HGSL_IOCTL_DBQ_ASSIGN HGSL_IORW(0x03, __u32)
/**
* struct hgsl_dbq_release_info - release DB queue
* @ref_count; userspace could inform PVM to do cleanup
* if this param is zero
* @ctxt_id: Current context
*/
struct hgsl_dbq_release_info {
__u32 ref_count;
__u32 ctxt_id;
};
#define HGSL_IOCTL_DBQ_RELEASE \
HGSL_IORW(0x04, struct hgsl_dbq_release_info)
/**
* struct hgsl_fhi_issud_cmds - submit cmds to DB queue
* @ibs: db commands list
* @num_ibs: Number of db commands
* @bos: buffer objects list
* @num_bos: Number of buffer objects
* @context_id: Current context for these cmds
* @flags: reserved
* @timestamp: Userspace time stamp
*/
struct hgsl_fhi_issud_cmds {
__u64 ibs;
__u32 num_ibs;
__u64 bos;
__u32 num_bos;
__u32 context_id;
__u32 flags;
__u32 timestamp;
__u32 padding;
};
#define HGSL_IOCTL_ISSUE_CMDS \
HGSL_IORW(0x05, struct hgsl_fhi_issud_cmds)
/**
* struct hgsl_ctxt_create_info - create a DB context
* @context_id: Current context for these cmds
* @shadow_fd: File descriptor of time stamp buffer
* @shadow_sop_offset: Offset for start timestamp written
* by GPU before cmds
* @shadow_eop_offset: Offset for end timestamp written
* by GPU after cmds
*/
struct hgsl_ctxt_create_info {
__u32 context_id;
__s32 shadow_fd;
__u32 shadow_sop_offset;
__u32 shadow_eop_offset;
};
#define HGSL_IOCTL_CTXT_CREATE HGSL_IOW(0x10, \
struct hgsl_ctxt_create_info)
/**
* Destroy a DB context - param is id of DB context
*/
#define HGSL_IOCTL_CTXT_DESTROY HGSL_IOW(0x11, __u32)
/**
* struct hgsl_wait_ts_info - wait a time step to be retired
* @timestamp: The user timestamp to wait
* @timeout: Expiry timeout
*/
struct hgsl_wait_ts_info {
__u32 context_id;
__u32 timestamp;
__u32 timeout;
__u32 padding;
};
#define HGSL_IOCTL_WAIT_TIMESTAMP \
HGSL_IOW(0x12, struct hgsl_wait_ts_info)
#endif /* _UAPI_MSM_HGSL_H */