18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 38c2ecf20Sopenharmony_ci/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/clk.h> 68c2ecf20Sopenharmony_ci#include <linux/reset.h> 78c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 88c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 98c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "panfrost_device.h" 128c2ecf20Sopenharmony_ci#include "panfrost_devfreq.h" 138c2ecf20Sopenharmony_ci#include "panfrost_features.h" 148c2ecf20Sopenharmony_ci#include "panfrost_gpu.h" 158c2ecf20Sopenharmony_ci#include "panfrost_job.h" 168c2ecf20Sopenharmony_ci#include "panfrost_mmu.h" 178c2ecf20Sopenharmony_ci#include "panfrost_perfcnt.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int panfrost_reset_init(struct panfrost_device *pfdev) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci int err; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci pfdev->rstc = devm_reset_control_array_get(pfdev->dev, false, true); 248c2ecf20Sopenharmony_ci if (IS_ERR(pfdev->rstc)) { 258c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc)); 268c2ecf20Sopenharmony_ci return PTR_ERR(pfdev->rstc); 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci err = reset_control_deassert(pfdev->rstc); 308c2ecf20Sopenharmony_ci if (err) 318c2ecf20Sopenharmony_ci return err; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return 0; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void panfrost_reset_fini(struct panfrost_device *pfdev) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci reset_control_assert(pfdev->rstc); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int panfrost_clk_init(struct panfrost_device *pfdev) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int err; 448c2ecf20Sopenharmony_ci unsigned long rate; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci pfdev->clock = devm_clk_get(pfdev->dev, NULL); 478c2ecf20Sopenharmony_ci if (IS_ERR(pfdev->clock)) { 488c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock)); 498c2ecf20Sopenharmony_ci return PTR_ERR(pfdev->clock); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci rate = clk_get_rate(pfdev->clock); 538c2ecf20Sopenharmony_ci dev_info(pfdev->dev, "clock rate = %lu\n", rate); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci err = clk_prepare_enable(pfdev->clock); 568c2ecf20Sopenharmony_ci if (err) 578c2ecf20Sopenharmony_ci return err; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci pfdev->bus_clock = devm_clk_get_optional(pfdev->dev, "bus"); 608c2ecf20Sopenharmony_ci if (IS_ERR(pfdev->bus_clock)) { 618c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "get bus_clock failed %ld\n", 628c2ecf20Sopenharmony_ci PTR_ERR(pfdev->bus_clock)); 638c2ecf20Sopenharmony_ci err = PTR_ERR(pfdev->bus_clock); 648c2ecf20Sopenharmony_ci goto disable_clock; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (pfdev->bus_clock) { 688c2ecf20Sopenharmony_ci rate = clk_get_rate(pfdev->bus_clock); 698c2ecf20Sopenharmony_ci dev_info(pfdev->dev, "bus_clock rate = %lu\n", rate); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci err = clk_prepare_enable(pfdev->bus_clock); 728c2ecf20Sopenharmony_ci if (err) 738c2ecf20Sopenharmony_ci goto disable_clock; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cidisable_clock: 798c2ecf20Sopenharmony_ci clk_disable_unprepare(pfdev->clock); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return err; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void panfrost_clk_fini(struct panfrost_device *pfdev) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci clk_disable_unprepare(pfdev->bus_clock); 878c2ecf20Sopenharmony_ci clk_disable_unprepare(pfdev->clock); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int panfrost_regulator_init(struct panfrost_device *pfdev) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int ret, i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci pfdev->regulators = devm_kcalloc(pfdev->dev, pfdev->comp->num_supplies, 958c2ecf20Sopenharmony_ci sizeof(*pfdev->regulators), 968c2ecf20Sopenharmony_ci GFP_KERNEL); 978c2ecf20Sopenharmony_ci if (!pfdev->regulators) 988c2ecf20Sopenharmony_ci return -ENOMEM; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (i = 0; i < pfdev->comp->num_supplies; i++) 1018c2ecf20Sopenharmony_ci pfdev->regulators[i].supply = pfdev->comp->supply_names[i]; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(pfdev->dev, 1048c2ecf20Sopenharmony_ci pfdev->comp->num_supplies, 1058c2ecf20Sopenharmony_ci pfdev->regulators); 1068c2ecf20Sopenharmony_ci if (ret < 0) { 1078c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 1088c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "failed to get regulators: %d\n", 1098c2ecf20Sopenharmony_ci ret); 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(pfdev->comp->num_supplies, 1148c2ecf20Sopenharmony_ci pfdev->regulators); 1158c2ecf20Sopenharmony_ci if (ret < 0) { 1168c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "failed to enable regulators: %d\n", ret); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void panfrost_regulator_fini(struct panfrost_device *pfdev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci if (!pfdev->regulators) 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci regulator_bulk_disable(pfdev->comp->num_supplies, pfdev->regulators); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void panfrost_pm_domain_fini(struct panfrost_device *pfdev) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int i; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pfdev->pm_domain_devs); i++) { 1368c2ecf20Sopenharmony_ci if (!pfdev->pm_domain_devs[i]) 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (pfdev->pm_domain_links[i]) 1408c2ecf20Sopenharmony_ci device_link_del(pfdev->pm_domain_links[i]); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci dev_pm_domain_detach(pfdev->pm_domain_devs[i], true); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int panfrost_pm_domain_init(struct panfrost_device *pfdev) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int err; 1498c2ecf20Sopenharmony_ci int i, num_domains; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci num_domains = of_count_phandle_with_args(pfdev->dev->of_node, 1528c2ecf20Sopenharmony_ci "power-domains", 1538c2ecf20Sopenharmony_ci "#power-domain-cells"); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * Single domain is handled by the core, and, if only a single power 1578c2ecf20Sopenharmony_ci * the power domain is requested, the property is optional. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci if (num_domains < 2 && pfdev->comp->num_pm_domains < 2) 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (num_domains != pfdev->comp->num_pm_domains) { 1638c2ecf20Sopenharmony_ci dev_err(pfdev->dev, 1648c2ecf20Sopenharmony_ci "Incorrect number of power domains: %d provided, %d needed\n", 1658c2ecf20Sopenharmony_ci num_domains, pfdev->comp->num_pm_domains); 1668c2ecf20Sopenharmony_ci return -EINVAL; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (WARN(num_domains > ARRAY_SIZE(pfdev->pm_domain_devs), 1708c2ecf20Sopenharmony_ci "Too many supplies in compatible structure.\n")) 1718c2ecf20Sopenharmony_ci return -EINVAL; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci for (i = 0; i < num_domains; i++) { 1748c2ecf20Sopenharmony_ci pfdev->pm_domain_devs[i] = 1758c2ecf20Sopenharmony_ci dev_pm_domain_attach_by_name(pfdev->dev, 1768c2ecf20Sopenharmony_ci pfdev->comp->pm_domain_names[i]); 1778c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(pfdev->pm_domain_devs[i])) { 1788c2ecf20Sopenharmony_ci err = PTR_ERR(pfdev->pm_domain_devs[i]) ? : -ENODATA; 1798c2ecf20Sopenharmony_ci pfdev->pm_domain_devs[i] = NULL; 1808c2ecf20Sopenharmony_ci dev_err(pfdev->dev, 1818c2ecf20Sopenharmony_ci "failed to get pm-domain %s(%d): %d\n", 1828c2ecf20Sopenharmony_ci pfdev->comp->pm_domain_names[i], i, err); 1838c2ecf20Sopenharmony_ci goto err; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci pfdev->pm_domain_links[i] = device_link_add(pfdev->dev, 1878c2ecf20Sopenharmony_ci pfdev->pm_domain_devs[i], DL_FLAG_PM_RUNTIME | 1888c2ecf20Sopenharmony_ci DL_FLAG_STATELESS | DL_FLAG_RPM_ACTIVE); 1898c2ecf20Sopenharmony_ci if (!pfdev->pm_domain_links[i]) { 1908c2ecf20Sopenharmony_ci dev_err(pfdev->pm_domain_devs[i], 1918c2ecf20Sopenharmony_ci "adding device link failed!\n"); 1928c2ecf20Sopenharmony_ci err = -ENODEV; 1938c2ecf20Sopenharmony_ci goto err; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cierr: 2008c2ecf20Sopenharmony_ci panfrost_pm_domain_fini(pfdev); 2018c2ecf20Sopenharmony_ci return err; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciint panfrost_device_init(struct panfrost_device *pfdev) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci int err; 2078c2ecf20Sopenharmony_ci struct resource *res; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci mutex_init(&pfdev->sched_lock); 2108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pfdev->scheduled_jobs); 2118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pfdev->as_lru_list); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci spin_lock_init(&pfdev->as_lock); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci err = panfrost_clk_init(pfdev); 2168c2ecf20Sopenharmony_ci if (err) { 2178c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "clk init failed %d\n", err); 2188c2ecf20Sopenharmony_ci return err; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci err = panfrost_devfreq_init(pfdev); 2228c2ecf20Sopenharmony_ci if (err) { 2238c2ecf20Sopenharmony_ci if (err != -EPROBE_DEFER) 2248c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "devfreq init failed %d\n", err); 2258c2ecf20Sopenharmony_ci goto out_clk; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* OPP will handle regulators */ 2298c2ecf20Sopenharmony_ci if (!pfdev->pfdevfreq.opp_of_table_added) { 2308c2ecf20Sopenharmony_ci err = panfrost_regulator_init(pfdev); 2318c2ecf20Sopenharmony_ci if (err) 2328c2ecf20Sopenharmony_ci goto out_devfreq; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci err = panfrost_reset_init(pfdev); 2368c2ecf20Sopenharmony_ci if (err) { 2378c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "reset init failed %d\n", err); 2388c2ecf20Sopenharmony_ci goto out_regulator; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci err = panfrost_pm_domain_init(pfdev); 2428c2ecf20Sopenharmony_ci if (err) 2438c2ecf20Sopenharmony_ci goto out_reset; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); 2468c2ecf20Sopenharmony_ci pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); 2478c2ecf20Sopenharmony_ci if (IS_ERR(pfdev->iomem)) { 2488c2ecf20Sopenharmony_ci dev_err(pfdev->dev, "failed to ioremap iomem\n"); 2498c2ecf20Sopenharmony_ci err = PTR_ERR(pfdev->iomem); 2508c2ecf20Sopenharmony_ci goto out_pm_domain; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci err = panfrost_gpu_init(pfdev); 2548c2ecf20Sopenharmony_ci if (err) 2558c2ecf20Sopenharmony_ci goto out_pm_domain; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci err = panfrost_mmu_init(pfdev); 2588c2ecf20Sopenharmony_ci if (err) 2598c2ecf20Sopenharmony_ci goto out_gpu; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci err = panfrost_job_init(pfdev); 2628c2ecf20Sopenharmony_ci if (err) 2638c2ecf20Sopenharmony_ci goto out_mmu; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci err = panfrost_perfcnt_init(pfdev); 2668c2ecf20Sopenharmony_ci if (err) 2678c2ecf20Sopenharmony_ci goto out_job; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ciout_job: 2718c2ecf20Sopenharmony_ci panfrost_job_fini(pfdev); 2728c2ecf20Sopenharmony_ciout_mmu: 2738c2ecf20Sopenharmony_ci panfrost_mmu_fini(pfdev); 2748c2ecf20Sopenharmony_ciout_gpu: 2758c2ecf20Sopenharmony_ci panfrost_gpu_fini(pfdev); 2768c2ecf20Sopenharmony_ciout_pm_domain: 2778c2ecf20Sopenharmony_ci panfrost_pm_domain_fini(pfdev); 2788c2ecf20Sopenharmony_ciout_reset: 2798c2ecf20Sopenharmony_ci panfrost_reset_fini(pfdev); 2808c2ecf20Sopenharmony_ciout_regulator: 2818c2ecf20Sopenharmony_ci panfrost_regulator_fini(pfdev); 2828c2ecf20Sopenharmony_ciout_devfreq: 2838c2ecf20Sopenharmony_ci panfrost_devfreq_fini(pfdev); 2848c2ecf20Sopenharmony_ciout_clk: 2858c2ecf20Sopenharmony_ci panfrost_clk_fini(pfdev); 2868c2ecf20Sopenharmony_ci return err; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid panfrost_device_fini(struct panfrost_device *pfdev) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci panfrost_perfcnt_fini(pfdev); 2928c2ecf20Sopenharmony_ci panfrost_job_fini(pfdev); 2938c2ecf20Sopenharmony_ci panfrost_mmu_fini(pfdev); 2948c2ecf20Sopenharmony_ci panfrost_gpu_fini(pfdev); 2958c2ecf20Sopenharmony_ci panfrost_pm_domain_fini(pfdev); 2968c2ecf20Sopenharmony_ci panfrost_reset_fini(pfdev); 2978c2ecf20Sopenharmony_ci panfrost_devfreq_fini(pfdev); 2988c2ecf20Sopenharmony_ci panfrost_regulator_fini(pfdev); 2998c2ecf20Sopenharmony_ci panfrost_clk_fini(pfdev); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ciconst char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci switch (exception_code) { 3058c2ecf20Sopenharmony_ci /* Non-Fault Status code */ 3068c2ecf20Sopenharmony_ci case 0x00: return "NOT_STARTED/IDLE/OK"; 3078c2ecf20Sopenharmony_ci case 0x01: return "DONE"; 3088c2ecf20Sopenharmony_ci case 0x02: return "INTERRUPTED"; 3098c2ecf20Sopenharmony_ci case 0x03: return "STOPPED"; 3108c2ecf20Sopenharmony_ci case 0x04: return "TERMINATED"; 3118c2ecf20Sopenharmony_ci case 0x08: return "ACTIVE"; 3128c2ecf20Sopenharmony_ci /* Job exceptions */ 3138c2ecf20Sopenharmony_ci case 0x40: return "JOB_CONFIG_FAULT"; 3148c2ecf20Sopenharmony_ci case 0x41: return "JOB_POWER_FAULT"; 3158c2ecf20Sopenharmony_ci case 0x42: return "JOB_READ_FAULT"; 3168c2ecf20Sopenharmony_ci case 0x43: return "JOB_WRITE_FAULT"; 3178c2ecf20Sopenharmony_ci case 0x44: return "JOB_AFFINITY_FAULT"; 3188c2ecf20Sopenharmony_ci case 0x48: return "JOB_BUS_FAULT"; 3198c2ecf20Sopenharmony_ci case 0x50: return "INSTR_INVALID_PC"; 3208c2ecf20Sopenharmony_ci case 0x51: return "INSTR_INVALID_ENC"; 3218c2ecf20Sopenharmony_ci case 0x52: return "INSTR_TYPE_MISMATCH"; 3228c2ecf20Sopenharmony_ci case 0x53: return "INSTR_OPERAND_FAULT"; 3238c2ecf20Sopenharmony_ci case 0x54: return "INSTR_TLS_FAULT"; 3248c2ecf20Sopenharmony_ci case 0x55: return "INSTR_BARRIER_FAULT"; 3258c2ecf20Sopenharmony_ci case 0x56: return "INSTR_ALIGN_FAULT"; 3268c2ecf20Sopenharmony_ci case 0x58: return "DATA_INVALID_FAULT"; 3278c2ecf20Sopenharmony_ci case 0x59: return "TILE_RANGE_FAULT"; 3288c2ecf20Sopenharmony_ci case 0x5A: return "ADDR_RANGE_FAULT"; 3298c2ecf20Sopenharmony_ci case 0x60: return "OUT_OF_MEMORY"; 3308c2ecf20Sopenharmony_ci /* GPU exceptions */ 3318c2ecf20Sopenharmony_ci case 0x80: return "DELAYED_BUS_FAULT"; 3328c2ecf20Sopenharmony_ci case 0x88: return "SHAREABILITY_FAULT"; 3338c2ecf20Sopenharmony_ci /* MMU exceptions */ 3348c2ecf20Sopenharmony_ci case 0xC1: return "TRANSLATION_FAULT_LEVEL1"; 3358c2ecf20Sopenharmony_ci case 0xC2: return "TRANSLATION_FAULT_LEVEL2"; 3368c2ecf20Sopenharmony_ci case 0xC3: return "TRANSLATION_FAULT_LEVEL3"; 3378c2ecf20Sopenharmony_ci case 0xC4: return "TRANSLATION_FAULT_LEVEL4"; 3388c2ecf20Sopenharmony_ci case 0xC8: return "PERMISSION_FAULT"; 3398c2ecf20Sopenharmony_ci case 0xC9 ... 0xCF: return "PERMISSION_FAULT"; 3408c2ecf20Sopenharmony_ci case 0xD1: return "TRANSTAB_BUS_FAULT_LEVEL1"; 3418c2ecf20Sopenharmony_ci case 0xD2: return "TRANSTAB_BUS_FAULT_LEVEL2"; 3428c2ecf20Sopenharmony_ci case 0xD3: return "TRANSTAB_BUS_FAULT_LEVEL3"; 3438c2ecf20Sopenharmony_ci case 0xD4: return "TRANSTAB_BUS_FAULT_LEVEL4"; 3448c2ecf20Sopenharmony_ci case 0xD8: return "ACCESS_FLAG"; 3458c2ecf20Sopenharmony_ci case 0xD9 ... 0xDF: return "ACCESS_FLAG"; 3468c2ecf20Sopenharmony_ci case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT"; 3478c2ecf20Sopenharmony_ci case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT"; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return "UNKNOWN"; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_civoid panfrost_device_reset(struct panfrost_device *pfdev) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci panfrost_gpu_soft_reset(pfdev); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci panfrost_gpu_power_on(pfdev); 3588c2ecf20Sopenharmony_ci panfrost_mmu_reset(pfdev); 3598c2ecf20Sopenharmony_ci panfrost_job_enable_interrupts(pfdev); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 3638c2ecf20Sopenharmony_ciint panfrost_device_resume(struct device *dev) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 3668c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = platform_get_drvdata(pdev); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci panfrost_device_reset(pfdev); 3698c2ecf20Sopenharmony_ci panfrost_devfreq_resume(pfdev); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciint panfrost_device_suspend(struct device *dev) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 3778c2ecf20Sopenharmony_ci struct panfrost_device *pfdev = platform_get_drvdata(pdev); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!panfrost_job_is_idle(pfdev)) 3808c2ecf20Sopenharmony_ci return -EBUSY; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci panfrost_devfreq_suspend(pfdev); 3838c2ecf20Sopenharmony_ci panfrost_gpu_power_off(pfdev); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci#endif 388