diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:35:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:39:31 +0000 |
commit | 85c675d0d09a45a135bddd15d7b385f8758c32fb (patch) | |
tree | 76267dbc9b9a130337be3640948fe397b04ac629 /drivers/gpu/host1x | |
parent | Adding upstream version 6.6.15. (diff) | |
download | linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.tar.xz linux-85c675d0d09a45a135bddd15d7b385f8758c32fb.zip |
Adding upstream version 6.7.7.upstream/6.7.7
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/host1x')
-rw-r--r-- | drivers/gpu/host1x/channel.c | 26 | ||||
-rw-r--r-- | drivers/gpu/host1x/channel.h | 4 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.c | 32 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.h | 3 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/intr_hw.c | 46 |
5 files changed, 93 insertions, 18 deletions
diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 2d0051d631..08077afe4c 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -27,6 +27,8 @@ int host1x_channel_list_init(struct host1x_channel_list *chlist, return -ENOMEM; } + mutex_init(&chlist->lock); + return 0; } @@ -79,6 +81,25 @@ void host1x_channel_stop(struct host1x_channel *channel) } EXPORT_SYMBOL(host1x_channel_stop); +/** + * host1x_channel_stop_all() - disable CDMA on allocated channels + * @host: host1x instance + * + * Stop CDMA on allocated channels + */ +void host1x_channel_stop_all(struct host1x *host) +{ + struct host1x_channel_list *chlist = &host->channel_list; + int bit; + + mutex_lock(&chlist->lock); + + for_each_set_bit(bit, chlist->allocated_channels, host->info->nb_channels) + host1x_channel_stop(&chlist->channels[bit]); + + mutex_unlock(&chlist->lock); +} + static void release_channel(struct kref *kref) { struct host1x_channel *channel = @@ -104,8 +125,11 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host) unsigned int max_channels = host->info->nb_channels; unsigned int index; + mutex_lock(&chlist->lock); + index = find_first_zero_bit(chlist->allocated_channels, max_channels); if (index >= max_channels) { + mutex_unlock(&chlist->lock); dev_err(host->dev, "failed to find free channel\n"); return NULL; } @@ -114,6 +138,8 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host) set_bit(index, chlist->allocated_channels); + mutex_unlock(&chlist->lock); + return &chlist->channels[index]; } diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h index 39044ff6c3..d7aede204d 100644 --- a/drivers/gpu/host1x/channel.h +++ b/drivers/gpu/host1x/channel.h @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/kref.h> +#include <linux/mutex.h> #include "cdma.h" @@ -18,6 +19,8 @@ struct host1x_channel; struct host1x_channel_list { struct host1x_channel *channels; + + struct mutex lock; unsigned long *allocated_channels; }; @@ -37,5 +40,6 @@ int host1x_channel_list_init(struct host1x_channel_list *chlist, void host1x_channel_list_free(struct host1x_channel_list *chlist); struct host1x_channel *host1x_channel_get_index(struct host1x *host, unsigned int index); +void host1x_channel_stop_all(struct host1x *host); #endif diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 7c6699aed7..42fd504abb 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -488,7 +488,7 @@ static int host1x_get_resets(struct host1x *host) static int host1x_probe(struct platform_device *pdev) { struct host1x *host; - int err; + int err, i; host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) @@ -516,9 +516,30 @@ static int host1x_probe(struct platform_device *pdev) return PTR_ERR(host->regs); } - host->syncpt_irq = platform_get_irq(pdev, 0); - if (host->syncpt_irq < 0) - return host->syncpt_irq; + for (i = 0; i < ARRAY_SIZE(host->syncpt_irqs); i++) { + char irq_name[] = "syncptX"; + + sprintf(irq_name, "syncpt%d", i); + + err = platform_get_irq_byname_optional(pdev, irq_name); + if (err == -ENXIO) + break; + if (err < 0) + return err; + + host->syncpt_irqs[i] = err; + } + + host->num_syncpt_irqs = i; + + /* Device tree without irq names */ + if (i == 0) { + host->syncpt_irqs[0] = platform_get_irq(pdev, 0); + if (host->syncpt_irqs[0] < 0) + return host->syncpt_irqs[0]; + + host->num_syncpt_irqs = 1; + } mutex_init(&host->devices_lock); INIT_LIST_HEAD(&host->devices); @@ -655,6 +676,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev) struct host1x *host = dev_get_drvdata(dev); int err; + host1x_channel_stop_all(host); host1x_intr_stop(host); host1x_syncpt_save(host); @@ -719,7 +741,7 @@ release_reset: static const struct dev_pm_ops host1x_pm_ops = { SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, NULL) - /* TODO: add system suspend-resume once driver will be ready for that */ + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra_host1x_driver = { diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 75de50fe03..c8e302de76 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -124,7 +124,8 @@ struct host1x { void __iomem *regs; void __iomem *hv_regs; /* hypervisor region */ void __iomem *common_regs; - int syncpt_irq; + int syncpt_irqs[8]; + int num_syncpt_irqs; struct host1x_syncpt *syncpt; struct host1x_syncpt_base *bases; struct device *dev; diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index b915ef7d03..9880e0c472 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c @@ -13,13 +13,20 @@ #include "../intr.h" #include "../dev.h" +struct host1x_intr_irq_data { + struct host1x *host; + u32 offset; +}; + static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) { - struct host1x *host = dev_id; + struct host1x_intr_irq_data *irq_data = dev_id; + struct host1x *host = irq_data->host; unsigned long reg; unsigned int i, id; - for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { + for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32); + i += host->num_syncpt_irqs) { reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); @@ -67,26 +74,41 @@ static void intr_hw_init(struct host1x *host, u32 cpm) /* * Program threshold interrupt destination among 8 lines per VM, - * per syncpoint. For now, just direct all to the first interrupt - * line. + * per syncpoint. For each group of 32 syncpoints (corresponding to one + * interrupt status register), direct to one interrupt line, going + * around in a round robin fashion. */ - for (id = 0; id < host->info->nb_pts; id++) - host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); + for (id = 0; id < host->info->nb_pts; id++) { + u32 reg_offset = id / 32; + u32 irq_index = reg_offset % host->num_syncpt_irqs; + + host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); + } #endif } static int host1x_intr_init_host_sync(struct host1x *host, u32 cpm) { - int err; + int err, i; + struct host1x_intr_irq_data *irq_data; + + irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); + if (!irq_data) + return -ENOMEM; host1x_hw_intr_disable_all_syncpt_intrs(host); - err = devm_request_irq(host->dev, host->syncpt_irq, - syncpt_thresh_isr, IRQF_SHARED, - "host1x_syncpt", host); - if (err < 0) - return err; + for (i = 0; i < host->num_syncpt_irqs; i++) { + irq_data[i].host = host; + irq_data[i].offset = i; + + err = devm_request_irq(host->dev, host->syncpt_irqs[i], + syncpt_thresh_isr, IRQF_SHARED, + "host1x_syncpt", &irq_data[i]); + if (err < 0) + return err; + } intr_hw_init(host, cpm); |