diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 20:46:16 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 20:46:16 +0300 |
commit | 93b694d096cc10994c817730d4d50288f9ae3d66 (patch) | |
tree | 5bd967686d0003f7dbbe1da49f5399cb4a92f074 /drivers/gpu/drm/panfrost | |
parent | 726eb70e0d34dc4bc4dada71f52bba8ed638431e (diff) | |
parent | 640eee067d9aae0bb98d8706001976ff1affaf00 (diff) | |
download | linux-93b694d096cc10994c817730d4d50288f9ae3d66.tar.xz |
Merge tag 'drm-next-2020-10-15' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Not a major amount of change, the i915 trees got split into display
and gt trees to better facilitate higher level review, and there's a
major refactoring of i915 GEM locking to use more core kernel concepts
(like ww-mutexes). msm gets per-process pagetables, older AMD SI cards
get DC support, nouveau got a bump in displayport support with common
code extraction from i915.
Outside of drm this contains a couple of patches for hexint
moduleparams which you've acked, and a virtio common code tree that
you should also get via it's regular path.
New driver:
- Cadence MHDP8546 DisplayPort bridge driver
core:
- cross-driver scatterlist cleanups
- devm_drm conversions
- remove drm_dev_init
- devm_drm_dev_alloc conversion
ttm:
- lots of refactoring and cleanups
bridges:
- chained bridge support in more drivers
panel:
- misc new panels
scheduler:
- cleanup priority levels
displayport:
- refactor i915 code into helpers for nouveau
i915:
- split into display and GT trees
- WW locking refactoring in GEM
- execbuf2 extension mechanism
- syncobj timeline support
- GEN 12 HOBL display powersaving
- Rocket Lake display additions
- Disable FBC on Tigerlake
- Tigerlake Type-C + DP improvements
- Hotplug interrupt refactoring
amdgpu:
- Sienna Cichlid updates
- Navy Flounder updates
- DCE6 (SI) support for DC
- Plane rotation enabled
- TMZ state info ioctl
- PCIe DPC recovery support
- DC interrupt handling refactor
- OLED panel fixes
amdkfd:
- add SMI events for thermal throttling
- SMI interface events ioctl update
- process eviction counters
radeon:
- move to dma_ for allocations
- expose sclk via sysfs
msm:
- DSI support for sm8150/sm8250
- per-process GPU pagetable support
- Displayport support
mediatek:
- move HDMI phy driver to PHY
- convert mtk-dpi to bridge API
- disable mt2701 tmds
tegra:
- bridge support
exynos:
- misc cleanups
vc4:
- dual display cleanups
ast:
- cleanups
gma500:
- conversion to GPIOd API
hisilicon:
- misc reworks
ingenic:
- clock handling and format improvements
mcde:
- DSI support
mgag200:
- desktop g200 support
mxsfb:
- i.MX7 + i.MX8M
- alpha plane support
panfrost:
- devfreq support
- amlogic SoC support
ps8640:
- EDID from eDP retrieval
tidss:
- AM65xx YUV workaround
virtio:
- virtio-gpu exported resources
rcar-du:
- R8A7742, R8A774E1 and R8A77961 support
- YUV planar format fixes
- non-visible plane handling
- VSP device reference count fix
- Kconfig fix to avoid displaying disabled options in .config"
* tag 'drm-next-2020-10-15' of git://anongit.freedesktop.org/drm/drm: (1494 commits)
drm/ingenic: Fix bad revert
drm/amdgpu: Fix invalid number of character '{' in amdgpu_acpi_init
drm/amdgpu: Remove warning for virtual_display
drm/amdgpu: kfd_initialized can be static
drm/amd/pm: setup APU dpm clock table in SMU HW initialization
drm/amdgpu: prevent spurious warning
drm/amdgpu/swsmu: fix ARC build errors
drm/amd/display: Fix OPTC_DATA_FORMAT programming
drm/amd/display: Don't allow pstate if no support in blank
drm/panfrost: increase readl_relaxed_poll_timeout values
MAINTAINERS: Update entry for st7703 driver after the rename
Revert "gpu/drm: ingenic: Add option to mmap GEM buffers cached"
drm/amd/display: HDMI remote sink need mode validation for Linux
drm/amd/display: Change to correct unit on audio rate
drm/amd/display: Avoid set zero in the requested clk
drm/amdgpu: align frag_end to covered address space
drm/amdgpu: fix NULL pointer dereference for Renoir
drm/vmwgfx: fix regression in thp code due to ttm init refactor.
drm/amdgpu/swsmu: add interrupt work handler for smu11 parts
drm/amdgpu/swsmu: add interrupt work function
...
Diffstat (limited to 'drivers/gpu/drm/panfrost')
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_devfreq.c | 175 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_devfreq.h | 30 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_device.c | 61 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_device.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_drv.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_gem.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_gpu.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_gpu.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_job.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_mmu.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/panfrost/panfrost_regs.h | 4 |
12 files changed, 257 insertions, 127 deletions
diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 413987038fbf..8ab025d0035f 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -1,20 +1,29 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright 2019 Collabora ltd. */ + +#include <linux/clk.h> #include <linux/devfreq.h> #include <linux/devfreq_cooling.h> #include <linux/platform_device.h> #include <linux/pm_opp.h> -#include <linux/clk.h> -#include <linux/regulator/consumer.h> #include "panfrost_device.h" #include "panfrost_devfreq.h" -#include "panfrost_features.h" -#include "panfrost_issues.h" -#include "panfrost_gpu.h" -#include "panfrost_regs.h" -static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev); +static void panfrost_devfreq_update_utilization(struct panfrost_devfreq *pfdevfreq) +{ + ktime_t now, last; + + now = ktime_get(); + last = pfdevfreq->time_last_update; + + if (pfdevfreq->busy_count > 0) + pfdevfreq->busy_time += ktime_sub(now, last); + else + pfdevfreq->idle_time += ktime_sub(now, last); + + pfdevfreq->time_last_update = now; +} static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) @@ -34,30 +43,37 @@ static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, return 0; } -static void panfrost_devfreq_reset(struct panfrost_device *pfdev) +static void panfrost_devfreq_reset(struct panfrost_devfreq *pfdevfreq) { - pfdev->devfreq.busy_time = 0; - pfdev->devfreq.idle_time = 0; - pfdev->devfreq.time_last_update = ktime_get(); + pfdevfreq->busy_time = 0; + pfdevfreq->idle_time = 0; + pfdevfreq->time_last_update = ktime_get(); } static int panfrost_devfreq_get_dev_status(struct device *dev, struct devfreq_dev_status *status) { struct panfrost_device *pfdev = dev_get_drvdata(dev); - - panfrost_devfreq_update_utilization(pfdev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + unsigned long irqflags; status->current_frequency = clk_get_rate(pfdev->clock); - status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.busy_time, - pfdev->devfreq.idle_time)); - status->busy_time = ktime_to_ns(pfdev->devfreq.busy_time); + spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + + status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, + pfdevfreq->idle_time)); + + status->busy_time = ktime_to_ns(pfdevfreq->busy_time); + + panfrost_devfreq_reset(pfdevfreq); - panfrost_devfreq_reset(pfdev); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); - dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, - status->total_time, + dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", + status->busy_time, status->total_time, status->busy_time / (status->total_time / 100), status->current_frequency / 1000 / 1000); @@ -77,21 +93,43 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) unsigned long cur_freq; struct device *dev = &pfdev->pdev->dev; struct devfreq *devfreq; + struct opp_table *opp_table; struct thermal_cooling_device *cooling; + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names, + pfdev->comp->num_supplies); + if (IS_ERR(opp_table)) { + ret = PTR_ERR(opp_table); + /* Continue if the optional regulator is missing */ + if (ret != -ENODEV) { + DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); + goto err_fini; + } + } else { + pfdevfreq->regulators_opp_table = opp_table; + } ret = dev_pm_opp_of_add_table(dev); - if (ret == -ENODEV) /* Optional, continue without devfreq */ - return 0; - else if (ret) - return ret; + if (ret) { + /* Optional, continue without devfreq */ + if (ret == -ENODEV) + ret = 0; + goto err_fini; + } + pfdevfreq->opp_of_table_added = true; + + spin_lock_init(&pfdevfreq->lock); - panfrost_devfreq_reset(pfdev); + panfrost_devfreq_reset(pfdevfreq); cur_freq = clk_get_rate(pfdev->clock); opp = devfreq_recommended_opp(dev, &cur_freq, 0); - if (IS_ERR(opp)) - return PTR_ERR(opp); + if (IS_ERR(opp)) { + ret = PTR_ERR(opp); + goto err_fini; + } panfrost_devfreq_profile.initial_freq = cur_freq; dev_pm_opp_put(opp); @@ -100,75 +138,94 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL); if (IS_ERR(devfreq)) { DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); - dev_pm_opp_of_remove_table(dev); - return PTR_ERR(devfreq); + ret = PTR_ERR(devfreq); + goto err_fini; } - pfdev->devfreq.devfreq = devfreq; + pfdevfreq->devfreq = devfreq; cooling = of_devfreq_cooling_register(dev->of_node, devfreq); if (IS_ERR(cooling)) DRM_DEV_INFO(dev, "Failed to register cooling device\n"); else - pfdev->devfreq.cooling = cooling; + pfdevfreq->cooling = cooling; return 0; + +err_fini: + panfrost_devfreq_fini(pfdev); + return ret; } void panfrost_devfreq_fini(struct panfrost_device *pfdev) { - if (pfdev->devfreq.cooling) - devfreq_cooling_unregister(pfdev->devfreq.cooling); - dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (pfdevfreq->cooling) { + devfreq_cooling_unregister(pfdevfreq->cooling); + pfdevfreq->cooling = NULL; + } + + if (pfdevfreq->opp_of_table_added) { + dev_pm_opp_of_remove_table(&pfdev->pdev->dev); + pfdevfreq->opp_of_table_added = false; + } + + if (pfdevfreq->regulators_opp_table) { + dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table); + pfdevfreq->regulators_opp_table = NULL; + } } void panfrost_devfreq_resume(struct panfrost_device *pfdev) { - if (!pfdev->devfreq.devfreq) + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (!pfdevfreq->devfreq) return; - panfrost_devfreq_reset(pfdev); + panfrost_devfreq_reset(pfdevfreq); - devfreq_resume_device(pfdev->devfreq.devfreq); + devfreq_resume_device(pfdevfreq->devfreq); } void panfrost_devfreq_suspend(struct panfrost_device *pfdev) { - if (!pfdev->devfreq.devfreq) + struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + + if (!pfdevfreq->devfreq) return; - devfreq_suspend_device(pfdev->devfreq.devfreq); + devfreq_suspend_device(pfdevfreq->devfreq); } -static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev) +void panfrost_devfreq_record_busy(struct panfrost_devfreq *pfdevfreq) { - ktime_t now; - ktime_t last; + unsigned long irqflags; - if (!pfdev->devfreq.devfreq) + if (!pfdevfreq->devfreq) return; - now = ktime_get(); - last = pfdev->devfreq.time_last_update; + spin_lock_irqsave(&pfdevfreq->lock, irqflags); - if (atomic_read(&pfdev->devfreq.busy_count) > 0) - pfdev->devfreq.busy_time += ktime_sub(now, last); - else - pfdev->devfreq.idle_time += ktime_sub(now, last); + panfrost_devfreq_update_utilization(pfdevfreq); - pfdev->devfreq.time_last_update = now; -} + pfdevfreq->busy_count++; -void panfrost_devfreq_record_busy(struct panfrost_device *pfdev) -{ - panfrost_devfreq_update_utilization(pfdev); - atomic_inc(&pfdev->devfreq.busy_count); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); } -void panfrost_devfreq_record_idle(struct panfrost_device *pfdev) +void panfrost_devfreq_record_idle(struct panfrost_devfreq *pfdevfreq) { - int count; + unsigned long irqflags; + + if (!pfdevfreq->devfreq) + return; + + spin_lock_irqsave(&pfdevfreq->lock, irqflags); + + panfrost_devfreq_update_utilization(pfdevfreq); + + WARN_ON(--pfdevfreq->busy_count < 0); - panfrost_devfreq_update_utilization(pfdev); - count = atomic_dec_if_positive(&pfdev->devfreq.busy_count); - WARN_ON(count < 0); + spin_unlock_irqrestore(&pfdevfreq->lock, irqflags); } diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index 0611beffc8d0..db6ea48e21f9 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -4,13 +4,39 @@ #ifndef __PANFROST_DEVFREQ_H__ #define __PANFROST_DEVFREQ_H__ +#include <linux/spinlock.h> +#include <linux/ktime.h> + +struct devfreq; +struct opp_table; +struct thermal_cooling_device; + +struct panfrost_device; + +struct panfrost_devfreq { + struct devfreq *devfreq; + struct opp_table *regulators_opp_table; + struct thermal_cooling_device *cooling; + bool opp_of_table_added; + + ktime_t busy_time; + ktime_t idle_time; + ktime_t time_last_update; + int busy_count; + /* + * Protect busy_time, idle_time, time_last_update and busy_count + * because these can be updated concurrently between multiple jobs. + */ + spinlock_t lock; +}; + int panfrost_devfreq_init(struct panfrost_device *pfdev); void panfrost_devfreq_fini(struct panfrost_device *pfdev); void panfrost_devfreq_resume(struct panfrost_device *pfdev); void panfrost_devfreq_suspend(struct panfrost_device *pfdev); -void panfrost_devfreq_record_busy(struct panfrost_device *pfdev); -void panfrost_devfreq_record_idle(struct panfrost_device *pfdev); +void panfrost_devfreq_record_busy(struct panfrost_devfreq *devfreq); +void panfrost_devfreq_record_idle(struct panfrost_devfreq *devfreq); #endif /* __PANFROST_DEVFREQ_H__ */ diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index b172087eee6a..e6896733838a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -90,9 +90,11 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) { int ret, i; - if (WARN(pfdev->comp->num_supplies > ARRAY_SIZE(pfdev->regulators), - "Too many supplies in compatible structure.\n")) - return -EINVAL; + pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, + sizeof(*pfdev->regulators), + GFP_KERNEL); + if (!pfdev->regulators) + return -ENOMEM; for (i = 0; i < pfdev->comp->num_supplies; i++) pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; @@ -119,8 +121,10 @@ static int panfrost_regulator_init(struct panfrost_device *pfdev) static void panfrost_regulator_fini(struct panfrost_device *pfdev) { - regulator_bulk_disable(pfdev->comp->num_supplies, - pfdev->regulators); + if (!pfdev->regulators) + return; + + regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); } static void panfrost_pm_domain_fini(struct panfrost_device *pfdev) @@ -214,58 +218,70 @@ int panfrost_device_init(struct panfrost_device *pfdev) return err; } - err = panfrost_regulator_init(pfdev); - if (err) - goto err_out0; + err = panfrost_devfreq_init(pfdev); + if (err) { + if (err != -EPROBE_DEFER) + dev_err(pfdev->dev, "devfreq init failed %d\n", err); + goto out_clk; + } + + /* OPP will handle regulators */ + if (!pfdev->pfdevfreq.opp_of_table_added) { + err = panfrost_regulator_init(pfdev); + if (err) + goto out_devfreq; + } err = panfrost_reset_init(pfdev); if (err) { dev_err(pfdev->dev, "reset init failed %d\n", err); - goto err_out1; + goto out_regulator; } err = panfrost_pm_domain_init(pfdev); if (err) - goto err_out2; + goto out_reset; res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); if (IS_ERR(pfdev->iomem)) { dev_err(pfdev->dev, "failed to ioremap iomem\n"); err = PTR_ERR(pfdev->iomem); - goto err_out3; + goto out_pm_domain; } err = panfrost_gpu_init(pfdev); if (err) - goto err_out3; + goto out_pm_domain; err = panfrost_mmu_init(pfdev); if (err) - goto err_out4; + goto out_gpu; err = panfrost_job_init(pfdev); if (err) - goto err_out5; + goto out_mmu; err = panfrost_perfcnt_init(pfdev); if (err) - goto err_out6; + goto out_job; return 0; -err_out6: +out_job: panfrost_job_fini(pfdev); -err_out5: +out_mmu: panfrost_mmu_fini(pfdev); -err_out4: +out_gpu: panfrost_gpu_fini(pfdev); -err_out3: +out_pm_domain: panfrost_pm_domain_fini(pfdev); -err_out2: +out_reset: panfrost_reset_fini(pfdev); -err_out1: +out_regulator: panfrost_regulator_fini(pfdev); -err_out0: +out_devfreq: + panfrost_devfreq_fini(pfdev); +out_clk: panfrost_clk_fini(pfdev); return err; } @@ -278,6 +294,7 @@ void panfrost_device_fini(struct panfrost_device *pfdev) panfrost_gpu_fini(pfdev); panfrost_pm_domain_fini(pfdev); panfrost_reset_fini(pfdev); + panfrost_devfreq_fini(pfdev); panfrost_regulator_fini(pfdev); panfrost_clk_fini(pfdev); } diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index c30c719a8059..2e9cbd1c4a58 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -13,6 +13,8 @@ #include <drm/drm_mm.h> #include <drm/gpu_scheduler.h> +#include "panfrost_devfreq.h" + struct panfrost_device; struct panfrost_mmu; struct panfrost_job_slot; @@ -20,7 +22,6 @@ struct panfrost_job; struct panfrost_perfcnt; #define NUM_JOB_SLOTS 3 -#define MAX_REGULATORS 2 #define MAX_PM_DOMAINS 3 struct panfrost_features { @@ -69,6 +70,9 @@ struct panfrost_compatible { int num_pm_domains; /* Only required if num_pm_domains > 1. */ const char * const *pm_domain_names; + + /* Vendor implementation quirks callback */ + void (*vendor_quirk)(struct panfrost_device *pfdev); }; struct panfrost_device { @@ -79,7 +83,7 @@ struct panfrost_device { void __iomem *iomem; struct clk *clock; struct clk *bus_clock; - struct regulator_bulk_data regulators[MAX_REGULATORS]; + struct regulator_bulk_data *regulators; struct reset_control *rstc; /* pm_domains for devices with more than one. */ struct device *pm_domain_devs[MAX_PM_DOMAINS]; @@ -107,14 +111,7 @@ struct panfrost_device { struct list_head shrinker_list; struct shrinker shrinker; - struct { - struct devfreq *devfreq; - struct thermal_cooling_device *cooling; - ktime_t busy_time; - ktime_t idle_time; - ktime_t time_last_update; - atomic_t busy_count; - } devfreq; + struct panfrost_devfreq pfdevfreq; }; struct panfrost_mmu { diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index ada51df9a7a3..37d4cb7a5491 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -14,7 +14,6 @@ #include <drm/drm_utils.h> #include "panfrost_device.h" -#include "panfrost_devfreq.h" #include "panfrost_gem.h" #include "panfrost_mmu.h" #include "panfrost_job.h" @@ -606,13 +605,6 @@ static int panfrost_probe(struct platform_device *pdev) goto err_out0; } - err = panfrost_devfreq_init(pfdev); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Fatal error during devfreq init\n"); - goto err_out1; - } - pm_runtime_set_active(pfdev->dev); pm_runtime_mark_last_busy(pfdev->dev); pm_runtime_enable(pfdev->dev); @@ -625,16 +617,14 @@ static int panfrost_probe(struct platform_device *pdev) */ err = drm_dev_register(ddev, 0); if (err < 0) - goto err_out2; + goto err_out1; panfrost_gem_shrinker_init(ddev); return 0; -err_out2: - pm_runtime_disable(pfdev->dev); - panfrost_devfreq_fini(pfdev); err_out1: + pm_runtime_disable(pfdev->dev); panfrost_device_fini(pfdev); err_out0: drm_dev_put(ddev); @@ -650,7 +640,6 @@ static int panfrost_remove(struct platform_device *pdev) panfrost_gem_shrinker_cleanup(ddev); pm_runtime_get_sync(pfdev->dev); - panfrost_devfreq_fini(pfdev); panfrost_device_fini(pfdev); pm_runtime_put_sync_suspend(pfdev->dev); pm_runtime_disable(pfdev->dev); @@ -667,7 +656,18 @@ static const struct panfrost_compatible default_data = { .pm_domain_names = NULL, }; +static const struct panfrost_compatible amlogic_data = { + .num_supplies = ARRAY_SIZE(default_supplies), + .supply_names = default_supplies, + .vendor_quirk = panfrost_gpu_amlogic_quirk, +}; + static const struct of_device_id dt_match[] = { + /* Set first to probe before the generic compatibles */ + { .compatible = "amlogic,meson-gxm-mali", + .data = &amlogic_data, }, + { .compatible = "amlogic,meson-g12a-mali", + .data = &amlogic_data, }, { .compatible = "arm,mali-t604", .data = &default_data, }, { .compatible = "arm,mali-t624", .data = &default_data, }, { .compatible = "arm,mali-t628", .data = &default_data, }, @@ -677,6 +677,7 @@ static const struct of_device_id dt_match[] = { { .compatible = "arm,mali-t830", .data = &default_data, }, { .compatible = "arm,mali-t860", .data = &default_data, }, { .compatible = "arm,mali-t880", .data = &default_data, }, + { .compatible = "arm,mali-bifrost", .data = &default_data, }, {} }; MODULE_DEVICE_TABLE(of, dt_match); diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index 33355dd302f1..1a6cea0e0bd7 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -41,8 +41,8 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj) for (i = 0; i < n_sgt; i++) { if (bo->sgts[i].sgl) { - dma_unmap_sg(pfdev->dev, bo->sgts[i].sgl, - bo->sgts[i].nents, DMA_BIDIRECTIONAL); + dma_unmap_sgtable(pfdev->dev, &bo->sgts[i], + DMA_BIDIRECTIONAL, 0); sg_free_table(&bo->sgts[i]); } } diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index f2c1ddc41a9b..2aae636f1cf5 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include "panfrost_device.h" #include "panfrost_features.h" @@ -75,6 +76,17 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) return 0; } +void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev) +{ + /* + * The Amlogic integrated Mali-T820, Mali-G31 & Mali-G52 needs + * these undocumented bits in GPU_PWR_OVERRIDE1 to be set in order + * to operate correctly. + */ + gpu_write(pfdev, GPU_PWR_KEY, GPU_PWR_KEY_UNLOCK); + gpu_write(pfdev, GPU_PWR_OVERRIDE1, 0xfff | (0x20 << 16)); +} + static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) { u32 quirks = 0; @@ -135,6 +147,10 @@ static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) if (quirks) gpu_write(pfdev, GPU_JM_CONFIG, quirks); + + /* Here goes platform specific quirks */ + if (pfdev->comp->vendor_quirk) + pfdev->comp->vendor_quirk(pfdev); } #define MAX_HW_REVS 6 @@ -304,16 +320,18 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) int ret; u32 val; + panfrost_gpu_init_quirks(pfdev); + /* Just turn on everything for now */ gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, - val, val == pfdev->features.l2_present, 100, 1000); + val, val == pfdev->features.l2_present, 100, 20000); if (ret) dev_err(pfdev->dev, "error powering up gpu L2"); gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, - val, val == pfdev->features.shader_present, 100, 1000); + val, val == pfdev->features.shader_present, 100, 20000); if (ret) dev_err(pfdev->dev, "error powering up gpu shader"); @@ -343,6 +361,7 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) dma_set_mask_and_coherent(pfdev->dev, DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); + dma_set_max_seg_size(pfdev->dev, UINT_MAX); irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); if (irq <= 0) @@ -355,7 +374,6 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) return err; } - panfrost_gpu_init_quirks(pfdev); panfrost_gpu_power_on(pfdev); return 0; @@ -368,7 +386,16 @@ void panfrost_gpu_fini(struct panfrost_device *pfdev) u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) { - if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) - return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); + u32 flush_id; + + if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) { + /* Flush reduction only makes sense when the GPU is kept powered on between jobs */ + if (pm_runtime_get_if_in_use(pfdev->dev)) { + flush_id = gpu_read(pfdev, GPU_LATEST_FLUSH_ID); + pm_runtime_put(pfdev->dev); + return flush_id; + } + } + return 0; } diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h index 4112412087b2..468c51e7e46d 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h @@ -16,4 +16,6 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); void panfrost_gpu_power_on(struct panfrost_device *pfdev); void panfrost_gpu_power_off(struct panfrost_device *pfdev); +void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev); + #endif diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 360146f6f3d9..30e7b7196dab 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -145,7 +145,7 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) u64 jc_head = job->jc; int ret; - panfrost_devfreq_record_busy(pfdev); + panfrost_devfreq_record_busy(&pfdev->pfdevfreq); ret = pm_runtime_get_sync(pfdev->dev); if (ret < 0) @@ -410,7 +410,7 @@ static void panfrost_job_timedout(struct drm_sched_job *sched_job) for (i = 0; i < NUM_JOB_SLOTS; i++) { if (pfdev->jobs[i]) { pm_runtime_put_noidle(pfdev->dev); - panfrost_devfreq_record_idle(pfdev); + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); pfdev->jobs[i] = NULL; } } @@ -478,7 +478,7 @@ static irqreturn_t panfrost_job_irq_handler(int irq, void *data) pfdev->jobs[j] = NULL; panfrost_mmu_as_put(pfdev, &job->file_priv->mmu); - panfrost_devfreq_record_idle(pfdev); + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); dma_fence_signal_locked(job->done_fence); pm_runtime_put_autosuspend(pfdev->dev); @@ -581,10 +581,6 @@ int panfrost_job_is_idle(struct panfrost_device *pfdev) struct panfrost_job_slot *js = pfdev->js; int i; - /* Check whether the hardware is idle */ - if (atomic_read(&pfdev->devfreq.busy_count)) - return false; - for (i = 0; i < NUM_JOB_SLOTS; i++) { /* If there are any jobs in the HW queue, we're not idle */ if (atomic_read(&js->queue[i].sched.hw_rq_count)) diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index e8f7b11352d2..776448c527ea 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -253,7 +253,7 @@ static int mmu_map_sg(struct panfrost_device *pfdev, struct panfrost_mmu *mmu, struct io_pgtable_ops *ops = mmu->pgtbl_ops; u64 start_iova = iova; - for_each_sg(sgt->sgl, sgl, sgt->nents, count) { + for_each_sgtable_dma_sg(sgt, sgl, count) { unsigned long paddr = sg_dma_address(sgl); size_t len = sg_dma_len(sgl); @@ -517,10 +517,9 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, if (ret) goto err_pages; - if (!dma_map_sg(pfdev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL)) { - ret = -EINVAL; + ret = dma_map_sgtable(pfdev->dev, sgt, DMA_BIDIRECTIONAL, 0); + if (ret) goto err_map; - } mmu_map_sg(pfdev, bomapping->mmu, addr, IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt); diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c index ec4695cf3caf..fdbc8d949135 100644 --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c @@ -83,11 +83,13 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev, ret = pm_runtime_get_sync(pfdev->dev); if (ret < 0) - return ret; + goto err_put_pm; bo = drm_gem_shmem_create(pfdev->ddev, perfcnt->bosize); - if (IS_ERR(bo)) - return PTR_ERR(bo); + if (IS_ERR(bo)) { + ret = PTR_ERR(bo); + goto err_put_pm; + } /* Map the perfcnt buf in the address space attached to file_priv. */ ret = panfrost_gem_open(&bo->base, file_priv); @@ -168,6 +170,8 @@ err_close_bo: panfrost_gem_close(&bo->base, file_priv); err_put_bo: drm_gem_object_put(&bo->base); +err_put_pm: + pm_runtime_put(pfdev->dev); return ret; } diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index ea38ac60581c..eddaa62ad8b0 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -51,6 +51,10 @@ #define GPU_STATUS 0x34 #define GPU_STATUS_PRFCNT_ACTIVE BIT(2) #define GPU_LATEST_FLUSH_ID 0x38 +#define GPU_PWR_KEY 0x50 /* (WO) Power manager key register */ +#define GPU_PWR_KEY_UNLOCK 0x2968A819 +#define GPU_PWR_OVERRIDE0 0x54 /* (RW) Power manager override settings */ +#define GPU_PWR_OVERRIDE1 0x58 /* (RW) Power manager override settings */ #define GPU_FAULT_STATUS 0x3C #define GPU_FAULT_ADDRESS_LO 0x40 #define GPU_FAULT_ADDRESS_HI 0x44 |