1f3ba9122SRob Herring // SPDX-License-Identifier: GPL-2.0
2f3ba9122SRob Herring /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
3f3ba9122SRob Herring /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
4f3ba9122SRob Herring
5f3ba9122SRob Herring #include <linux/clk.h>
6f3ba9122SRob Herring #include <linux/reset.h>
7f3ba9122SRob Herring #include <linux/platform_device.h>
8506629c8SNicolas Boichat #include <linux/pm_domain.h>
9*53d36818SPaul Cercueil #include <linux/pm_runtime.h>
10f3ba9122SRob Herring #include <linux/regulator/consumer.h>
11f3ba9122SRob Herring
12f3ba9122SRob Herring #include "panfrost_device.h"
13f3ba9122SRob Herring #include "panfrost_devfreq.h"
14f3ba9122SRob Herring #include "panfrost_features.h"
150c0af438SAlyssa Rosenzweig #include "panfrost_issues.h"
16f3ba9122SRob Herring #include "panfrost_gpu.h"
17f3ba9122SRob Herring #include "panfrost_job.h"
18f3ba9122SRob Herring #include "panfrost_mmu.h"
197786fd10SBoris Brezillon #include "panfrost_perfcnt.h"
20f3ba9122SRob Herring
panfrost_reset_init(struct panfrost_device * pfdev)21f3ba9122SRob Herring static int panfrost_reset_init(struct panfrost_device *pfdev)
22f3ba9122SRob Herring {
230d32c2a7SYejune Deng pfdev->rstc = devm_reset_control_array_get_optional_exclusive(pfdev->dev);
24f3ba9122SRob Herring if (IS_ERR(pfdev->rstc)) {
25f3ba9122SRob Herring dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc));
26f3ba9122SRob Herring return PTR_ERR(pfdev->rstc);
27f3ba9122SRob Herring }
28f3ba9122SRob Herring
293c4641d4SQinglang Miao return reset_control_deassert(pfdev->rstc);
30f3ba9122SRob Herring }
31f3ba9122SRob Herring
panfrost_reset_fini(struct panfrost_device * pfdev)32f3ba9122SRob Herring static void panfrost_reset_fini(struct panfrost_device *pfdev)
33f3ba9122SRob Herring {
34f3ba9122SRob Herring reset_control_assert(pfdev->rstc);
35f3ba9122SRob Herring }
36f3ba9122SRob Herring
panfrost_clk_init(struct panfrost_device * pfdev)37f3ba9122SRob Herring static int panfrost_clk_init(struct panfrost_device *pfdev)
38f3ba9122SRob Herring {
39f3ba9122SRob Herring int err;
40f3ba9122SRob Herring unsigned long rate;
41f3ba9122SRob Herring
42f3ba9122SRob Herring pfdev->clock = devm_clk_get(pfdev->dev, NULL);
43f3ba9122SRob Herring if (IS_ERR(pfdev->clock)) {
44f3ba9122SRob Herring dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock));
45f3ba9122SRob Herring return PTR_ERR(pfdev->clock);
46f3ba9122SRob Herring }
47f3ba9122SRob Herring
48f3ba9122SRob Herring rate = clk_get_rate(pfdev->clock);
49f3ba9122SRob Herring dev_info(pfdev->dev, "clock rate = %lu\n", rate);
50f3ba9122SRob Herring
51f3ba9122SRob Herring err = clk_prepare_enable(pfdev->clock);
52f3ba9122SRob Herring if (err)
53f3ba9122SRob Herring return err;
54f3ba9122SRob Herring
55b681af0bSClément Péron pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus");
56b681af0bSClément Péron if (IS_ERR(pfdev->bus_clock)) {
57b681af0bSClément Péron dev_err(pfdev->dev, "get bus_clock failed %ld\n",
58b681af0bSClément Péron PTR_ERR(pfdev->bus_clock));
59f4249870SWei Yongjun err = PTR_ERR(pfdev->bus_clock);
60f4249870SWei Yongjun goto disable_clock;
61b681af0bSClément Péron }
62b681af0bSClément Péron
63b681af0bSClément Péron if (pfdev->bus_clock) {
64b681af0bSClément Péron rate = clk_get_rate(pfdev->bus_clock);
65b681af0bSClément Péron dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate);
66b681af0bSClément Péron
67b681af0bSClément Péron err = clk_prepare_enable(pfdev->bus_clock);
68b681af0bSClément Péron if (err)
69b681af0bSClément Péron goto disable_clock;
70b681af0bSClément Péron }
71b681af0bSClément Péron
72f3ba9122SRob Herring return 0;
73b681af0bSClément Péron
74b681af0bSClément Péron disable_clock:
75b681af0bSClément Péron clk_disable_unprepare(pfdev->clock);
76b681af0bSClément Péron
77b681af0bSClément Péron return err;
78f3ba9122SRob Herring }
79f3ba9122SRob Herring
panfrost_clk_fini(struct panfrost_device * pfdev)80f3ba9122SRob Herring static void panfrost_clk_fini(struct panfrost_device *pfdev)
81f3ba9122SRob Herring {
82b681af0bSClément Péron clk_disable_unprepare(pfdev->bus_clock);
83f3ba9122SRob Herring clk_disable_unprepare(pfdev->clock);
84f3ba9122SRob Herring }
85f3ba9122SRob Herring
panfrost_regulator_init(struct panfrost_device * pfdev)86f3ba9122SRob Herring static int panfrost_regulator_init(struct panfrost_device *pfdev)
87f3ba9122SRob Herring {
883e1399bcSNicolas Boichat int ret, i;
89f3ba9122SRob Herring
90512f2122SClément Péron pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies,
91512f2122SClément Péron sizeof(*pfdev->regulators),
92512f2122SClément Péron GFP_KERNEL);
93512f2122SClément Péron if (!pfdev->regulators)
94512f2122SClément Péron return -ENOMEM;
953e1399bcSNicolas Boichat
963e1399bcSNicolas Boichat for (i = 0; i < pfdev->comp->num_supplies; i++)
973e1399bcSNicolas Boichat pfdev->regulators[i].supply = pfdev->comp->supply_names[i];
983e1399bcSNicolas Boichat
993e1399bcSNicolas Boichat ret = devm_regulator_bulk_get(pfdev->dev,
1003e1399bcSNicolas Boichat pfdev->comp->num_supplies,
1013e1399bcSNicolas Boichat pfdev->regulators);
1023e1399bcSNicolas Boichat if (ret < 0) {
103e63adeccSKrzysztof Kozlowski if (ret != -EPROBE_DEFER)
104e63adeccSKrzysztof Kozlowski dev_err(pfdev->dev, "failed to get regulators: %d\n",
105e63adeccSKrzysztof Kozlowski ret);
106f3ba9122SRob Herring return ret;
107f3ba9122SRob Herring }
108f3ba9122SRob Herring
1093e1399bcSNicolas Boichat ret = regulator_bulk_enable(pfdev->comp->num_supplies,
1103e1399bcSNicolas Boichat pfdev->regulators);
111f3ba9122SRob Herring if (ret < 0) {
1123e1399bcSNicolas Boichat dev_err(pfdev->dev, "failed to enable regulators: %d\n", ret);
113f3ba9122SRob Herring return ret;
114f3ba9122SRob Herring }
115f3ba9122SRob Herring
116f3ba9122SRob Herring return 0;
117f3ba9122SRob Herring }
118f3ba9122SRob Herring
panfrost_regulator_fini(struct panfrost_device * pfdev)119f3ba9122SRob Herring static void panfrost_regulator_fini(struct panfrost_device *pfdev)
120f3ba9122SRob Herring {
121512f2122SClément Péron if (!pfdev->regulators)
122512f2122SClément Péron return;
123512f2122SClément Péron
124512f2122SClément Péron regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators);
125f3ba9122SRob Herring }
126f3ba9122SRob Herring
panfrost_pm_domain_fini(struct panfrost_device * pfdev)127506629c8SNicolas Boichat static void panfrost_pm_domain_fini(struct panfrost_device *pfdev)
128506629c8SNicolas Boichat {
129506629c8SNicolas Boichat int i;
130506629c8SNicolas Boichat
131506629c8SNicolas Boichat for (i = 0; i < ARRAY_SIZE(pfdev->pm_domain_devs); i++) {
132506629c8SNicolas Boichat if (!pfdev->pm_domain_devs[i])
133506629c8SNicolas Boichat break;
134506629c8SNicolas Boichat
135506629c8SNicolas Boichat if (pfdev->pm_domain_links[i])
136506629c8SNicolas Boichat device_link_del(pfdev->pm_domain_links[i]);
137506629c8SNicolas Boichat
138506629c8SNicolas Boichat dev_pm_domain_detach(pfdev->pm_domain_devs[i], true);
139506629c8SNicolas Boichat }
140506629c8SNicolas Boichat }
141506629c8SNicolas Boichat
panfrost_pm_domain_init(struct panfrost_device * pfdev)142506629c8SNicolas Boichat static int panfrost_pm_domain_init(struct panfrost_device *pfdev)
143506629c8SNicolas Boichat {
144506629c8SNicolas Boichat int err;
145506629c8SNicolas Boichat int i, num_domains;
146506629c8SNicolas Boichat
147506629c8SNicolas Boichat num_domains = of_count_phandle_with_args(pfdev->dev->of_node,
148506629c8SNicolas Boichat "power-domains",
149506629c8SNicolas Boichat "#power-domain-cells");
150506629c8SNicolas Boichat
151506629c8SNicolas Boichat /*
152506629c8SNicolas Boichat * Single domain is handled by the core, and, if only a single power
153506629c8SNicolas Boichat * the power domain is requested, the property is optional.
154506629c8SNicolas Boichat */
155506629c8SNicolas Boichat if (num_domains < 2 && pfdev->comp->num_pm_domains < 2)
156506629c8SNicolas Boichat return 0;
157506629c8SNicolas Boichat
158506629c8SNicolas Boichat if (num_domains != pfdev->comp->num_pm_domains) {
159506629c8SNicolas Boichat dev_err(pfdev->dev,
160506629c8SNicolas Boichat "Incorrect number of power domains: %d provided, %d needed\n",
161506629c8SNicolas Boichat num_domains, pfdev->comp->num_pm_domains);
162506629c8SNicolas Boichat return -EINVAL;
163506629c8SNicolas Boichat }
164506629c8SNicolas Boichat
165506629c8SNicolas Boichat if (WARN(num_domains > ARRAY_SIZE(pfdev->pm_domain_devs),
166506629c8SNicolas Boichat "Too many supplies in compatible structure.\n"))
167506629c8SNicolas Boichat return -EINVAL;
168506629c8SNicolas Boichat
169506629c8SNicolas Boichat for (i = 0; i < num_domains; i++) {
170506629c8SNicolas Boichat pfdev->pm_domain_devs[i] =
171506629c8SNicolas Boichat dev_pm_domain_attach_by_name(pfdev->dev,
172506629c8SNicolas Boichat pfdev->comp->pm_domain_names[i]);
173506629c8SNicolas Boichat if (IS_ERR_OR_NULL(pfdev->pm_domain_devs[i])) {
174506629c8SNicolas Boichat err = PTR_ERR(pfdev->pm_domain_devs[i]) ? : -ENODATA;
175506629c8SNicolas Boichat pfdev->pm_domain_devs[i] = NULL;
176506629c8SNicolas Boichat dev_err(pfdev->dev,
177506629c8SNicolas Boichat "failed to get pm-domain %s(%d): %d\n",
178506629c8SNicolas Boichat pfdev->comp->pm_domain_names[i], i, err);
179506629c8SNicolas Boichat goto err;
180506629c8SNicolas Boichat }
181506629c8SNicolas Boichat
182506629c8SNicolas Boichat pfdev->pm_domain_links[i] = device_link_add(pfdev->dev,
183506629c8SNicolas Boichat pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME |
184506629c8SNicolas Boichat DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE);
185506629c8SNicolas Boichat if (!pfdev->pm_domain_links[i]) {
186506629c8SNicolas Boichat dev_err(pfdev->pm_domain_devs[i],
187506629c8SNicolas Boichat "adding device link failed!\n");
188506629c8SNicolas Boichat err = -ENODEV;
189506629c8SNicolas Boichat goto err;
190506629c8SNicolas Boichat }
191506629c8SNicolas Boichat }
192506629c8SNicolas Boichat
193506629c8SNicolas Boichat return 0;
194506629c8SNicolas Boichat
195506629c8SNicolas Boichat err:
196506629c8SNicolas Boichat panfrost_pm_domain_fini(pfdev);
197506629c8SNicolas Boichat return err;
198506629c8SNicolas Boichat }
199506629c8SNicolas Boichat
panfrost_device_init(struct panfrost_device * pfdev)200f3ba9122SRob Herring int panfrost_device_init(struct panfrost_device *pfdev)
201f3ba9122SRob Herring {
202f3ba9122SRob Herring int err;
203f3ba9122SRob Herring
204f3ba9122SRob Herring mutex_init(&pfdev->sched_lock);
205f3ba9122SRob Herring INIT_LIST_HEAD(&pfdev->scheduled_jobs);
2067282f764SRob Herring INIT_LIST_HEAD(&pfdev->as_lru_list);
207f3ba9122SRob Herring
2087282f764SRob Herring spin_lock_init(&pfdev->as_lock);
209f3ba9122SRob Herring
210f3ba9122SRob Herring err = panfrost_clk_init(pfdev);
211f3ba9122SRob Herring if (err) {
212f3ba9122SRob Herring dev_err(pfdev->dev, "clk init failed %d\n", err);
213f3ba9122SRob Herring return err;
214f3ba9122SRob Herring }
215f3ba9122SRob Herring
21625e247bbSClément Péron err = panfrost_devfreq_init(pfdev);
21725e247bbSClément Péron if (err) {
21825e247bbSClément Péron if (err != -EPROBE_DEFER)
21925e247bbSClément Péron dev_err(pfdev->dev, "devfreq init failed %d\n", err);
22025e247bbSClément Péron goto out_clk;
22125e247bbSClément Péron }
22225e247bbSClément Péron
223fd587ff0SClément Péron /* OPP will handle regulators */
224fd587ff0SClément Péron if (!pfdev->pfdevfreq.opp_of_table_added) {
225f3ba9122SRob Herring err = panfrost_regulator_init(pfdev);
226e63adeccSKrzysztof Kozlowski if (err)
22725e247bbSClément Péron goto out_devfreq;
228fd587ff0SClément Péron }
229f3ba9122SRob Herring
230f3ba9122SRob Herring err = panfrost_reset_init(pfdev);
231f3ba9122SRob Herring if (err) {
232f3ba9122SRob Herring dev_err(pfdev->dev, "reset init failed %d\n", err);
233d3c335daSClément Péron goto out_regulator;
234f3ba9122SRob Herring }
235f3ba9122SRob Herring
236506629c8SNicolas Boichat err = panfrost_pm_domain_init(pfdev);
237506629c8SNicolas Boichat if (err)
238d3c335daSClément Péron goto out_reset;
239506629c8SNicolas Boichat
2403605eaccSCai Huoqing pfdev->iomem = devm_platform_ioremap_resource(pfdev->pdev, 0);
241f3ba9122SRob Herring if (IS_ERR(pfdev->iomem)) {
242f3ba9122SRob Herring err = PTR_ERR(pfdev->iomem);
243d3c335daSClément Péron goto out_pm_domain;
244f3ba9122SRob Herring }
245f3ba9122SRob Herring
246f3ba9122SRob Herring err = panfrost_gpu_init(pfdev);
247f3ba9122SRob Herring if (err)
248d3c335daSClément Péron goto out_pm_domain;
249f3ba9122SRob Herring
250f3ba9122SRob Herring err = panfrost_mmu_init(pfdev);
251f3ba9122SRob Herring if (err)
252d3c335daSClément Péron goto out_gpu;
253f3ba9122SRob Herring
254f3ba9122SRob Herring err = panfrost_job_init(pfdev);
255f3ba9122SRob Herring if (err)
256d3c335daSClément Péron goto out_mmu;
257f3ba9122SRob Herring
2587786fd10SBoris Brezillon err = panfrost_perfcnt_init(pfdev);
2597786fd10SBoris Brezillon if (err)
260d3c335daSClément Péron goto out_job;
2617786fd10SBoris Brezillon
262f3ba9122SRob Herring return 0;
263d3c335daSClément Péron out_job:
2647786fd10SBoris Brezillon panfrost_job_fini(pfdev);
265d3c335daSClément Péron out_mmu:
266f3ba9122SRob Herring panfrost_mmu_fini(pfdev);
267d3c335daSClément Péron out_gpu:
268f3ba9122SRob Herring panfrost_gpu_fini(pfdev);
269d3c335daSClément Péron out_pm_domain:
270506629c8SNicolas Boichat panfrost_pm_domain_fini(pfdev);
271d3c335daSClément Péron out_reset:
272f3ba9122SRob Herring panfrost_reset_fini(pfdev);
273d3c335daSClément Péron out_regulator:
274f3ba9122SRob Herring panfrost_regulator_fini(pfdev);
27525e247bbSClément Péron out_devfreq:
27625e247bbSClément Péron panfrost_devfreq_fini(pfdev);
277d3c335daSClément Péron out_clk:
278f3ba9122SRob Herring panfrost_clk_fini(pfdev);
279f3ba9122SRob Herring return err;
280f3ba9122SRob Herring }
281f3ba9122SRob Herring
panfrost_device_fini(struct panfrost_device * pfdev)282f3ba9122SRob Herring void panfrost_device_fini(struct panfrost_device *pfdev)
283f3ba9122SRob Herring {
2847786fd10SBoris Brezillon panfrost_perfcnt_fini(pfdev);
285197b23e9SBoris Brezillon panfrost_job_fini(pfdev);
286197b23e9SBoris Brezillon panfrost_mmu_fini(pfdev);
287197b23e9SBoris Brezillon panfrost_gpu_fini(pfdev);
288506629c8SNicolas Boichat panfrost_pm_domain_fini(pfdev);
289197b23e9SBoris Brezillon panfrost_reset_fini(pfdev);
29025e247bbSClément Péron panfrost_devfreq_fini(pfdev);
291f3ba9122SRob Herring panfrost_regulator_fini(pfdev);
292f3ba9122SRob Herring panfrost_clk_fini(pfdev);
293f3ba9122SRob Herring }
294f3ba9122SRob Herring
2957319965fSBoris Brezillon #define PANFROST_EXCEPTION(id) \
2967319965fSBoris Brezillon [DRM_PANFROST_EXCEPTION_ ## id] = { \
2977319965fSBoris Brezillon .name = #id, \
298f3ba9122SRob Herring }
299f3ba9122SRob Herring
3007319965fSBoris Brezillon struct panfrost_exception_info {
3017319965fSBoris Brezillon const char *name;
3027319965fSBoris Brezillon };
3037319965fSBoris Brezillon
3047319965fSBoris Brezillon static const struct panfrost_exception_info panfrost_exception_infos[] = {
3057319965fSBoris Brezillon PANFROST_EXCEPTION(OK),
3067319965fSBoris Brezillon PANFROST_EXCEPTION(DONE),
3077319965fSBoris Brezillon PANFROST_EXCEPTION(INTERRUPTED),
3087319965fSBoris Brezillon PANFROST_EXCEPTION(STOPPED),
3097319965fSBoris Brezillon PANFROST_EXCEPTION(TERMINATED),
3107319965fSBoris Brezillon PANFROST_EXCEPTION(KABOOM),
3117319965fSBoris Brezillon PANFROST_EXCEPTION(EUREKA),
3127319965fSBoris Brezillon PANFROST_EXCEPTION(ACTIVE),
3137319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_CONFIG_FAULT),
3147319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_POWER_FAULT),
3157319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_READ_FAULT),
3167319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_WRITE_FAULT),
3177319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_AFFINITY_FAULT),
3187319965fSBoris Brezillon PANFROST_EXCEPTION(JOB_BUS_FAULT),
3197319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_INVALID_PC),
3207319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_INVALID_ENC),
3217319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_TYPE_MISMATCH),
3227319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_OPERAND_FAULT),
3237319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_TLS_FAULT),
3247319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_BARRIER_FAULT),
3257319965fSBoris Brezillon PANFROST_EXCEPTION(INSTR_ALIGN_FAULT),
3267319965fSBoris Brezillon PANFROST_EXCEPTION(DATA_INVALID_FAULT),
3277319965fSBoris Brezillon PANFROST_EXCEPTION(TILE_RANGE_FAULT),
3287319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_RANGE_FAULT),
3297319965fSBoris Brezillon PANFROST_EXCEPTION(IMPRECISE_FAULT),
3307319965fSBoris Brezillon PANFROST_EXCEPTION(OOM),
3317319965fSBoris Brezillon PANFROST_EXCEPTION(OOM_AFBC),
3327319965fSBoris Brezillon PANFROST_EXCEPTION(UNKNOWN),
3337319965fSBoris Brezillon PANFROST_EXCEPTION(DELAYED_BUS_FAULT),
3347319965fSBoris Brezillon PANFROST_EXCEPTION(GPU_SHAREABILITY_FAULT),
3357319965fSBoris Brezillon PANFROST_EXCEPTION(SYS_SHAREABILITY_FAULT),
3367319965fSBoris Brezillon PANFROST_EXCEPTION(GPU_CACHEABILITY_FAULT),
3377319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_0),
3387319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_1),
3397319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_2),
3407319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_3),
3417319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_4),
3427319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSLATION_FAULT_IDENTITY),
3437319965fSBoris Brezillon PANFROST_EXCEPTION(PERM_FAULT_0),
3447319965fSBoris Brezillon PANFROST_EXCEPTION(PERM_FAULT_1),
3457319965fSBoris Brezillon PANFROST_EXCEPTION(PERM_FAULT_2),
3467319965fSBoris Brezillon PANFROST_EXCEPTION(PERM_FAULT_3),
3477319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_0),
3487319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_1),
3497319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_2),
3507319965fSBoris Brezillon PANFROST_EXCEPTION(TRANSTAB_BUS_FAULT_3),
3517319965fSBoris Brezillon PANFROST_EXCEPTION(ACCESS_FLAG_0),
3527319965fSBoris Brezillon PANFROST_EXCEPTION(ACCESS_FLAG_1),
3537319965fSBoris Brezillon PANFROST_EXCEPTION(ACCESS_FLAG_2),
3547319965fSBoris Brezillon PANFROST_EXCEPTION(ACCESS_FLAG_3),
3557319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN0),
3567319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN1),
3577319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN2),
3587319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_IN3),
3597319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT0),
3607319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT1),
3617319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT2),
3627319965fSBoris Brezillon PANFROST_EXCEPTION(ADDR_SIZE_FAULT_OUT3),
3637319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_FAULT_0),
3647319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_FAULT_1),
3657319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_FAULT_2),
3667319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_FAULT_3),
3677319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_0),
3687319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_1),
3697319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_2),
3707319965fSBoris Brezillon PANFROST_EXCEPTION(MEM_ATTR_NONCACHE_3),
3717319965fSBoris Brezillon };
3727319965fSBoris Brezillon
panfrost_exception_name(u32 exception_code)3737319965fSBoris Brezillon const char *panfrost_exception_name(u32 exception_code)
3747319965fSBoris Brezillon {
3757319965fSBoris Brezillon if (WARN_ON(exception_code >= ARRAY_SIZE(panfrost_exception_infos) ||
3767319965fSBoris Brezillon !panfrost_exception_infos[exception_code].name))
3777319965fSBoris Brezillon return "Unknown exception type";
3787319965fSBoris Brezillon
3797319965fSBoris Brezillon return panfrost_exception_infos[exception_code].name;
380f3ba9122SRob Herring }
381f3ba9122SRob Herring
panfrost_exception_needs_reset(const struct panfrost_device * pfdev,u32 exception_code)3822905db27SBoris Brezillon bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
3832905db27SBoris Brezillon u32 exception_code)
3842905db27SBoris Brezillon {
3850c0af438SAlyssa Rosenzweig /* If an occlusion query write causes a bus fault on affected GPUs,
3860c0af438SAlyssa Rosenzweig * future fragment jobs may hang. Reset to workaround.
3872905db27SBoris Brezillon */
3880c0af438SAlyssa Rosenzweig if (exception_code == DRM_PANFROST_EXCEPTION_JOB_BUS_FAULT)
3890c0af438SAlyssa Rosenzweig return panfrost_has_hw_issue(pfdev, HW_ISSUE_TTRX_3076);
3900c0af438SAlyssa Rosenzweig
3910c0af438SAlyssa Rosenzweig /* No other GPUs we support need a reset */
3922905db27SBoris Brezillon return false;
3932905db27SBoris Brezillon }
3942905db27SBoris Brezillon
panfrost_device_reset(struct panfrost_device * pfdev)39573e467f6SRob Herring void panfrost_device_reset(struct panfrost_device *pfdev)
39673e467f6SRob Herring {
39773e467f6SRob Herring panfrost_gpu_soft_reset(pfdev);
39873e467f6SRob Herring
39973e467f6SRob Herring panfrost_gpu_power_on(pfdev);
40073e467f6SRob Herring panfrost_mmu_reset(pfdev);
40173e467f6SRob Herring panfrost_job_enable_interrupts(pfdev);
40273e467f6SRob Herring }
40373e467f6SRob Herring
panfrost_device_resume(struct device * dev)404*53d36818SPaul Cercueil static int panfrost_device_resume(struct device *dev)
405f3ba9122SRob Herring {
406fba5265fSWolfram Sang struct panfrost_device *pfdev = dev_get_drvdata(dev);
407f3ba9122SRob Herring
40873e467f6SRob Herring panfrost_device_reset(pfdev);
409f3ba9122SRob Herring panfrost_devfreq_resume(pfdev);
410f3ba9122SRob Herring
411f3ba9122SRob Herring return 0;
412f3ba9122SRob Herring }
413f3ba9122SRob Herring
panfrost_device_suspend(struct device * dev)414*53d36818SPaul Cercueil static int panfrost_device_suspend(struct device *dev)
415f3ba9122SRob Herring {
416fba5265fSWolfram Sang struct panfrost_device *pfdev = dev_get_drvdata(dev);
417f3ba9122SRob Herring
418f3ba9122SRob Herring if (!panfrost_job_is_idle(pfdev))
419f3ba9122SRob Herring return -EBUSY;
420f3ba9122SRob Herring
421f3ba9122SRob Herring panfrost_devfreq_suspend(pfdev);
422f3ba9122SRob Herring panfrost_gpu_power_off(pfdev);
423f3ba9122SRob Herring
424f3ba9122SRob Herring return 0;
425f3ba9122SRob Herring }
426*53d36818SPaul Cercueil
427*53d36818SPaul Cercueil EXPORT_GPL_RUNTIME_DEV_PM_OPS(panfrost_pm_ops, panfrost_device_suspend,
428*53d36818SPaul Cercueil panfrost_device_resume, NULL);
429