gpu: host1x: Enable general interrupts for actmon

Host1x general interrupts include actmon-related interrupts, axi
timeout interrupts, and illegal access interrupts. This change enables
actmon-related interrupts only.

Bug 3788919

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
Change-Id: Iea1f1622a11afa72f70f8d10efebd857a51cc4e2
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2889825
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
Johnny Liu
2023-04-18 10:42:28 +00:00
committed by mobile promotions
parent 8733469474
commit 03fd3f1188
9 changed files with 251 additions and 27 deletions

View File

@@ -249,35 +249,27 @@ static void host1x_actmon_deinit(struct host1x_actmon *actmon)
static void host1x_actmon_module_init(struct host1x_actmon_module *module) static void host1x_actmon_module_init(struct host1x_actmon_module *module)
{ {
struct host1x_actmon *actmon = module->actmon;
u32 val;
/* Local control register */ /* Local control register */
val = 0; actmon_module_writel(module,
val |= HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(1); HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(1) |
val |= HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(1); HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(1) |
val |= HOST1X_ACTMON_MODULE_CTRL_K_VAL(module->k); HOST1X_ACTMON_MODULE_CTRL_K_VAL(module->k) |
val |= HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM(module->consec_upper_num); HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM(module->consec_upper_num) |
val |= HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(module->consec_lower_num); HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(module->consec_lower_num),
actmon_module_writel(module, val, HOST1X_ACTMON_MODULE_CTRL_REG); HOST1X_ACTMON_MODULE_CTRL_REG);
/* Interrupt enable register */ /* Interrupt enable register (disable interrupts by default) */
val = 0; actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INTR_ENB_REG);
val |= HOST1X_ACTMON_MODULE_INTR_AVG_BELOW_WORK_ENB(1);
val |= HOST1X_ACTMON_MODULE_INTR_AVG_ABOVE_WORK_ENB(1);
val |= HOST1X_ACTMON_MODULE_INTR_CONSEC_BELOW_WORK_ENB(1);
val |= HOST1X_ACTMON_MODULE_INTR_CONSEC_ABOVE_WORK_ENB(1);
actmon_module_writel(module, val, HOST1X_ACTMON_MODULE_INTR_ENB_REG);
/* Interrupt status register */ /* Interrupt status register */
actmon_module_writel(module, 0xffffffff, HOST1X_ACTMON_MODULE_INTR_STATUS_REG); actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
/* Consecutive watermark registers */ /* Consecutive watermark registers */
actmon_module_writel(module, 0xffffffff, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG); actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG);
/* Moving-average watermark registers */ /* Moving-average watermark registers */
actmon_module_writel(module, 0xffffffff, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG); actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_LOWER_WMARK_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_LOWER_WMARK_REG);
/* Init average value register */ /* Init average value register */
@@ -288,7 +280,7 @@ static void host1x_actmon_module_deinit(struct host1x_actmon_module *module)
{ {
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_CTRL_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_CTRL_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INTR_ENB_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INTR_ENB_REG);
actmon_module_writel(module, 0xffffffff, HOST1X_ACTMON_MODULE_INTR_STATUS_REG); actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG);
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG);
@@ -297,6 +289,40 @@ static void host1x_actmon_module_deinit(struct host1x_actmon_module *module)
actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_COUNT_WEIGHT_REG); actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_COUNT_WEIGHT_REG);
} }
void host1x_actmon_handle_interrupt(struct host1x *host, int classid)
{
unsigned long actmon_status, module_status;
struct host1x_actmon_module *module;
struct host1x_actmon *actmon;
struct host1x_client *client;
list_for_each_entry(actmon, &host->actmons, list) {
if (actmon->client->class == classid)
break;
}
client = actmon->client;
module = &actmon->modules[HOST1X_ACTMON_MODULE_ACTIVE];
actmon_status = actmon_readl(actmon, HOST1X_ACTMON_INTR_STATUS_REG);
module_status = actmon_module_readl(module, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
/* Trigger DFS if client supports it */
if (!client->ops->actmon_event)
;
else if (module_status & HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE)
client->ops->actmon_event(client, HOST1X_ACTMON_CONSEC_WMARK_ABOVE);
else if (module_status & HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW)
client->ops->actmon_event(client, HOST1X_ACTMON_CONSEC_WMARK_BELOW);
else if (module_status & HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE)
client->ops->actmon_event(client, HOST1X_ACTMON_AVG_WMARK_ABOVE);
else if (module_status & HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW)
client->ops->actmon_event(client, HOST1X_ACTMON_AVG_WMARK_BELOW);
actmon_module_writel(module, module_status, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
actmon_writel(actmon, actmon_status, HOST1X_ACTMON_INTR_STATUS_REG);
}
int host1x_actmon_register(struct host1x_client *client) int host1x_actmon_register(struct host1x_client *client)
{ {
struct host1x *host = dev_get_drvdata(client->host->parent); struct host1x *host = dev_get_drvdata(client->host->parent);
@@ -304,6 +330,7 @@ int host1x_actmon_register(struct host1x_client *client)
struct host1x_actmon_entry *entry = NULL; struct host1x_actmon_entry *entry = NULL;
struct host1x_actmon_module *module; struct host1x_actmon_module *module;
struct host1x_actmon *actmon; struct host1x_actmon *actmon;
unsigned long flags;
int i, err; int i, err;
if (!host->actmon_regs || !host->actmon_clk) if (!host->actmon_regs || !host->actmon_clk)
@@ -320,6 +347,12 @@ int host1x_actmon_register(struct host1x_client *client)
if (!actmon) if (!actmon)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&actmon->list);
spin_lock_irqsave(&host->actmons_lock, flags);
list_add_tail(&actmon->list, &host->actmons);
spin_unlock_irqrestore(&host->actmons_lock, flags);
actmon->client = client; actmon->client = client;
actmon->rate = clk_get_rate(host->actmon_clk); actmon->rate = clk_get_rate(host->actmon_clk);
actmon->regs = host->actmon_regs + entry->offset; actmon->regs = host->actmon_regs + entry->offset;
@@ -361,6 +394,7 @@ int host1x_actmon_unregister(struct host1x_client *client)
struct host1x_actmon_module *module; struct host1x_actmon_module *module;
struct host1x *host = dev_get_drvdata(client->host->parent); struct host1x *host = dev_get_drvdata(client->host->parent);
struct host1x_actmon *actmon = client->actmon; struct host1x_actmon *actmon = client->actmon;
unsigned long flags;
int i; int i;
if (!host->actmon_regs || !host->actmon_clk) if (!host->actmon_regs || !host->actmon_clk)
@@ -379,6 +413,10 @@ int host1x_actmon_unregister(struct host1x_client *client)
host1x_actmon_deinit(actmon); host1x_actmon_deinit(actmon);
spin_lock_irqsave(&host->actmons_lock, flags);
list_del(&actmon->list);
spin_unlock_irqrestore(&host->actmons_lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL(host1x_actmon_unregister); EXPORT_SYMBOL(host1x_actmon_unregister);

View File

@@ -40,6 +40,11 @@ struct host1x_actmon {
struct host1x_client *client; struct host1x_client *client;
struct host1x_actmon_module modules[8]; struct host1x_actmon_module modules[8];
struct dentry *debugfs; struct dentry *debugfs;
struct list_head list;
}; };
struct host1x;
void host1x_actmon_handle_interrupt(struct host1x *host, int classid);
#endif #endif

View File

@@ -47,6 +47,11 @@ void host1x_common_writel(struct host1x *host1x, u32 v, u32 r)
writel(v, host1x->common_regs + r); writel(v, host1x->common_regs + r);
} }
u32 host1x_common_readl(struct host1x *host1x, u32 r)
{
return readl(host1x->common_regs + r);
}
void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r) void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
{ {
writel(v, host1x->hv_regs + r); writel(v, host1x->hv_regs + r);
@@ -832,8 +837,12 @@ static int host1x_probe(struct platform_device *pdev)
if (host->syncpt_irq < 0) if (host->syncpt_irq < 0)
return host->syncpt_irq; return host->syncpt_irq;
host->general_irq = platform_get_irq_byname_optional(pdev, "host1x");
mutex_init(&host->devices_lock); mutex_init(&host->devices_lock);
INIT_LIST_HEAD(&host->devices); INIT_LIST_HEAD(&host->devices);
spin_lock_init(&host->actmons_lock);
INIT_LIST_HEAD(&host->actmons);
INIT_LIST_HEAD(&host->list); INIT_LIST_HEAD(&host->list);
host->dev = &pdev->dev; host->dev = &pdev->dev;
@@ -849,6 +858,12 @@ static int host1x_probe(struct platform_device *pdev)
return err; return err;
} }
if (host->general_irq > 0 && host->common_regs) {
err = host1x_hw_intr_init_host_general(host);
if (err)
return err;
}
err = host1x_get_assigned_resources(host); err = host1x_get_assigned_resources(host);
if (err) if (err)
return err; return err;
@@ -979,6 +994,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
struct host1x *host = dev_get_drvdata(dev); struct host1x *host = dev_get_drvdata(dev);
int err; int err;
host1x_hw_intr_disable_all_general_intrs(host);
host1x_intr_stop(host); host1x_intr_stop(host);
host1x_syncpt_save(host); host1x_syncpt_save(host);
@@ -999,6 +1015,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
resume_host1x: resume_host1x:
host1x_setup_virtualization_tables(host); host1x_setup_virtualization_tables(host);
host1x_syncpt_restore(host); host1x_syncpt_restore(host);
host1x_hw_intr_enable_general_intrs(host);
host1x_intr_start(host); host1x_intr_start(host);
return err; return err;
@@ -1035,6 +1052,7 @@ static int __maybe_unused host1x_runtime_resume(struct device *dev)
host1x_setup_virtualization_tables(host); host1x_setup_virtualization_tables(host);
host1x_syncpt_restore(host); host1x_syncpt_restore(host);
host1x_hw_intr_enable_general_intrs(host);
host1x_intr_start(host); host1x_intr_start(host);
return 0; return 0;

View File

@@ -12,6 +12,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include "actmon.h"
#include "cdma.h" #include "cdma.h"
#include "channel.h" #include "channel.h"
#include "context.h" #include "context.h"
@@ -73,6 +74,12 @@ struct host1x_syncpt_ops {
void (*enable_protection)(struct host1x *host); void (*enable_protection)(struct host1x *host);
}; };
struct host1x_intr_general_ops {
int (*init_host_general)(struct host1x *host);
void (*enable_general_intrs)(struct host1x *host);
void (*disable_all_general_intrs)(struct host1x *host);
};
struct host1x_intr_ops { struct host1x_intr_ops {
int (*init_host_sync)(struct host1x *host, u32 cpm); int (*init_host_sync)(struct host1x *host, u32 cpm);
void (*set_syncpt_threshold)( void (*set_syncpt_threshold)(
@@ -142,6 +149,7 @@ struct host1x {
void __iomem *common_regs; void __iomem *common_regs;
void __iomem *actmon_regs; void __iomem *actmon_regs;
int syncpt_irq; int syncpt_irq;
int general_irq;
struct host1x_syncpt *syncpt; struct host1x_syncpt *syncpt;
struct host1x_syncpt_base *bases; struct host1x_syncpt_base *bases;
struct device *dev; struct device *dev;
@@ -166,6 +174,7 @@ struct host1x {
struct mutex intr_mutex; struct mutex intr_mutex;
const struct host1x_syncpt_ops *syncpt_op; const struct host1x_syncpt_ops *syncpt_op;
const struct host1x_intr_general_ops *intr_general_op;
const struct host1x_intr_ops *intr_op; const struct host1x_intr_ops *intr_op;
const struct host1x_channel_ops *channel_op; const struct host1x_channel_ops *channel_op;
const struct host1x_cdma_ops *cdma_op; const struct host1x_cdma_ops *cdma_op;
@@ -185,6 +194,9 @@ struct host1x {
struct mutex devices_lock; struct mutex devices_lock;
struct list_head devices; struct list_head devices;
spinlock_t actmons_lock;
struct list_head actmons;
struct list_head list; struct list_head list;
struct device_dma_parameters dma_parms; struct device_dma_parameters dma_parms;
@@ -193,6 +205,7 @@ struct host1x {
}; };
void host1x_common_writel(struct host1x *host1x, u32 v, u32 r); void host1x_common_writel(struct host1x *host1x, u32 v, u32 r);
u32 host1x_common_readl(struct host1x *host1x, u32 r);
void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v); void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v);
u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r); u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r);
void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v);
@@ -242,6 +255,30 @@ static inline void host1x_hw_syncpt_enable_protection(struct host1x *host)
return host->syncpt_op->enable_protection(host); return host->syncpt_op->enable_protection(host);
} }
static inline int host1x_hw_intr_init_host_general(struct host1x *host)
{
if (!host->intr_general_op)
return -EPERM;
return host->intr_general_op->init_host_general(host);
}
static inline void host1x_hw_intr_enable_general_intrs(struct host1x *host)
{
if (!host->intr_general_op)
return;
host->intr_general_op->enable_general_intrs(host);
}
static inline void host1x_hw_intr_disable_all_general_intrs(struct host1x *host)
{
if (!host->intr_general_op)
return;
host->intr_general_op->disable_all_general_intrs(host);
}
static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm) static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm)
{ {
return host->intr_op->init_host_sync(host, cpm); return host->intr_op->init_host_sync(host, cpm);

View File

@@ -12,6 +12,7 @@
#define HOST1X_ACTMON_CTRL_REG 0x0 #define HOST1X_ACTMON_CTRL_REG 0x0
#define HOST1X_ACTMON_INTR_ENB_REG 0x4 #define HOST1X_ACTMON_INTR_ENB_REG 0x4
#define HOST1X_ACTMON_INTR_STATUS_REG 0x8
#define HOST1X_ACTMON_MODULE_INIT_AVG_REG 0x14 #define HOST1X_ACTMON_MODULE_INIT_AVG_REG 0x14
#define HOST1X_ACTMON_MODULE_CTRL_REG 0x80 #define HOST1X_ACTMON_MODULE_CTRL_REG 0x80
#define HOST1X_ACTMON_MODULE_INTR_ENB_REG 0x84 #define HOST1X_ACTMON_MODULE_INTR_ENB_REG 0x84
@@ -31,14 +32,19 @@
#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(v) ((v & 0x7) << 21) #define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(v) ((v & 0x7) << 21)
#define HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(v) ((v & 0x1) << 13) #define HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(v) ((v & 0x1) << 13)
#define HOST1X_ACTMON_MODULE_CTRL_K_VAL(v) ((v & 0x7) << 10) #define HOST1X_ACTMON_MODULE_CTRL_K_VAL(v) ((v & 0x7) << 10)
#define HOST1X_ACTMON_MODULE_INTR_CONSEC_ABOVE_WORK_ENB(v) ((v & 0x1) << 31) #define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE_ENB(v) ((v & 0x1) << 31)
#define HOST1X_ACTMON_MODULE_INTR_CONSEC_BELOW_WORK_ENB(v) ((v & 0x1) << 30) #define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW_ENB(v) ((v & 0x1) << 30)
#define HOST1X_ACTMON_MODULE_INTR_AVG_ABOVE_WORK_ENB(v) ((v & 0x1) << 29) #define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE_ENB(v) ((v & 0x1) << 29)
#define HOST1X_ACTMON_MODULE_INTR_AVG_BELOW_WORK_ENB(v) ((v & 0x1) << 28) #define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW_ENB(v) ((v & 0x1) << 28)
#define HOST1X_ACTMON_CTRL_SAMPLE_PERIOD_MASK 0xff #define HOST1X_ACTMON_CTRL_SAMPLE_PERIOD_MASK 0xff
#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM_MASK (0x7 << 26) #define HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM_MASK (0x7 << 26)
#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM_MASK (0x7 << 21) #define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM_MASK (0x7 << 21)
#define HOST1X_ACTMON_MODULE_CTRL_K_VAL_MASK (0x7 << 10) #define HOST1X_ACTMON_MODULE_CTRL_K_VAL_MASK (0x7 << 10)
#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE BIT(31)
#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW BIT(30)
#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE BIT(29)
#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW BIT(28)
#endif #endif

View File

@@ -2,7 +2,7 @@
/* /*
* Host1x init for Tegra234 SoCs * Host1x init for Tegra234 SoCs
* *
* Copyright (c) 2022 NVIDIA Corporation. * Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/ */
/* include hw specification */ /* include hw specification */
@@ -15,6 +15,7 @@
#include "cdma_hw.c" #include "cdma_hw.c"
#include "channel_hw.c" #include "channel_hw.c"
#include "debug_hw.c" #include "debug_hw.c"
#include "intr_general_hw.c"
#include "intr_hw.c" #include "intr_hw.c"
#include "syncpt_hw.c" #include "syncpt_hw.c"
@@ -26,6 +27,7 @@ int host1x08_init(struct host1x *host)
host->cdma_op = &host1x_cdma_ops; host->cdma_op = &host1x_cdma_ops;
host->cdma_pb_op = &host1x_pushbuffer_ops; host->cdma_pb_op = &host1x_pushbuffer_ops;
host->syncpt_op = &host1x_syncpt_ops; host->syncpt_op = &host1x_syncpt_ops;
host->intr_general_op = &host1x_intr_general_ops;
host->intr_op = &host1x_intr_ops; host->intr_op = &host1x_intr_ops;
host->debug_op = &host1x_debug_ops; host->debug_op = &host1x_debug_ops;

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2022 NVIDIA Corporation. * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/ */
#define HOST1X_COMMON_OFA_MLOCK 0x4050 #define HOST1X_COMMON_OFA_MLOCK 0x4050
@@ -9,3 +9,20 @@
#define HOST1X_COMMON_NVENC_MLOCK 0x407c #define HOST1X_COMMON_NVENC_MLOCK 0x407c
#define HOST1X_COMMON_NVDEC_MLOCK 0x4080 #define HOST1X_COMMON_NVDEC_MLOCK 0x4080
#define HOST1X_COMMON_NVJPG_MLOCK 0x4084 #define HOST1X_COMMON_NVJPG_MLOCK 0x4084
#define HOST1X_COMMON_INTR_CPU0_MASK 0x4
#define HOST1X_COMMON_THOST_INTRSTATUS 0x1c
#define HOST1X_COMMON_THOST_INTRMASK 0x30
#define HOST1X_COMMON_THOST_GLOBAL_INTRMASK 0x44
#define HOST1X_COMMON_THOST_INTRMASK_NVENC_ACTMON(v) (v << 2)
#define HOST1X_COMMON_THOST_INTRMASK_VIC_ACTMON(v) (v << 3)
#define HOST1X_COMMON_THOST_INTRMASK_NVDEC_ACTMON(v) (v << 4)
#define HOST1X_COMMON_THOST_INTRMASK_NVJPG_ACTMON(v) (v << 5)
#define HOST1X_COMMON_THOST_INTRMASK_NVJPG1_ACTMON(v) (v << 6)
#define HOST1X_COMMON_THOST_INTRSTATUS_NVENC_ACTMON_INTR BIT(2)
#define HOST1X_COMMON_THOST_INTRSTATUS_VIC_ACTMON_INTR BIT(3)
#define HOST1X_COMMON_THOST_INTRSTATUS_NVDEC_ACTMON_INTR BIT(4)
#define HOST1X_COMMON_THOST_INTRSTATUS_NVJPG_ACTMON_INTR BIT(5)
#define HOST1X_COMMON_THOST_INTRSTATUS_NVJPG1_ACTMON_INTR BIT(6)

View File

@@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Tegra host1x General Interrupt Management
*
* Copyright (C) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/interrupt.h>
#include "../dev.h"
static irqreturn_t host1x_general_isr(int irq, void *dev_id)
{
struct host1x *host = dev_id;
unsigned long status;
status = host1x_common_readl(host, HOST1X_COMMON_THOST_INTRSTATUS);
if (status & HOST1X_COMMON_THOST_INTRSTATUS_NVENC_ACTMON_INTR)
host1x_actmon_handle_interrupt(host, HOST1X_CLASS_NVENC);
if (status & HOST1X_COMMON_THOST_INTRSTATUS_VIC_ACTMON_INTR)
host1x_actmon_handle_interrupt(host, HOST1X_CLASS_VIC);
if (status & HOST1X_COMMON_THOST_INTRSTATUS_NVDEC_ACTMON_INTR)
host1x_actmon_handle_interrupt(host, HOST1X_CLASS_NVDEC);
if (status & HOST1X_COMMON_THOST_INTRSTATUS_NVJPG_ACTMON_INTR)
host1x_actmon_handle_interrupt(host, HOST1X_CLASS_NVJPG);
if (status & HOST1X_COMMON_THOST_INTRSTATUS_NVJPG1_ACTMON_INTR)
host1x_actmon_handle_interrupt(host, HOST1X_CLASS_NVJPG1);
host1x_common_writel(host, status, HOST1X_COMMON_THOST_INTRSTATUS);
return IRQ_HANDLED;
}
static int host1x_intr_init_host_general(struct host1x *host)
{
int err;
host1x_hw_intr_disable_all_general_intrs(host);
err = devm_request_threaded_irq(host->dev,
host->general_irq,
NULL, host1x_general_isr,
IRQF_ONESHOT, "host1x_general",
host);
if (err < 0) {
devm_free_irq(host->dev, host->general_irq, host);
return err;
}
return 0;
}
static void host1x_intr_enable_general_intrs(struct host1x *host)
{
if (!host->common_regs)
return;
/* Assign CPU0 for host1x general interrupts */
host1x_common_writel(host, 0x1, HOST1X_COMMON_INTR_CPU0_MASK);
/* Allow host1x general interrupts go to CPU0 only */
host1x_common_writel(host, 0x1, HOST1X_COMMON_THOST_GLOBAL_INTRMASK);
/* Enable host1x general interrupts */
host1x_common_writel(host,
HOST1X_COMMON_THOST_INTRMASK_NVENC_ACTMON(1) |
HOST1X_COMMON_THOST_INTRMASK_VIC_ACTMON(1) |
HOST1X_COMMON_THOST_INTRMASK_NVDEC_ACTMON(1) |
HOST1X_COMMON_THOST_INTRMASK_NVJPG_ACTMON(1) |
HOST1X_COMMON_THOST_INTRMASK_NVJPG1_ACTMON(1),
HOST1X_COMMON_THOST_INTRMASK);
}
static void host1x_intr_disable_all_general_intrs(struct host1x *host)
{
if (!host->common_regs)
return;
host1x_common_writel(host, 0x0, HOST1X_COMMON_THOST_INTRMASK);
}
static const struct host1x_intr_general_ops host1x_intr_general_ops = {
.init_host_general = host1x_intr_init_host_general,
.enable_general_intrs = host1x_intr_enable_general_intrs,
.disable_all_general_intrs = host1x_intr_disable_all_general_intrs,
};

View File

@@ -27,6 +27,13 @@ enum host1x_class {
HOST1X_CLASS_NVDEC1 = 0xF5, HOST1X_CLASS_NVDEC1 = 0xF5,
}; };
enum host1x_actmon_wmark_event {
HOST1X_ACTMON_AVG_WMARK_BELOW,
HOST1X_ACTMON_AVG_WMARK_ABOVE,
HOST1X_ACTMON_CONSEC_WMARK_BELOW,
HOST1X_ACTMON_CONSEC_WMARK_ABOVE,
};
struct host1x; struct host1x;
struct host1x_client; struct host1x_client;
struct iommu_group; struct iommu_group;
@@ -69,6 +76,7 @@ static inline void host1x_bo_cache_destroy(struct host1x_bo_cache *cache)
* @suspend: host1x client suspend code * @suspend: host1x client suspend code
* @resume: host1x client resume code * @resume: host1x client resume code
* @get_rate: host1x client get clock rate code * @get_rate: host1x client get clock rate code
* @actmon_event: host1x client actmon event handling code in threaded interrupt context
*/ */
struct host1x_client_ops { struct host1x_client_ops {
int (*early_init)(struct host1x_client *client); int (*early_init)(struct host1x_client *client);
@@ -78,6 +86,8 @@ struct host1x_client_ops {
int (*suspend)(struct host1x_client *client); int (*suspend)(struct host1x_client *client);
int (*resume)(struct host1x_client *client); int (*resume)(struct host1x_client *client);
unsigned long (*get_rate)(struct host1x_client *client); unsigned long (*get_rate)(struct host1x_client *client);
void (*actmon_event)(struct host1x_client *client,
enum host1x_actmon_wmark_event event);
}; };
struct host1x_actmon; struct host1x_actmon;