123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- // SPDX-License-Identifier: GPL-2.0
- /* Copyright 2018 Marty E. Plummer <[email protected]> */
- /* Copyright 2019 Linaro, Ltd., Rob Herring <[email protected]> */
- /* Copyright 2019 Collabora ltd. */
- #include <linux/bitfield.h>
- #include <linux/bitmap.h>
- #include <linux/delay.h>
- #include <linux/dma-mapping.h>
- #include <linux/interrupt.h>
- #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"
- #include "panfrost_issues.h"
- #include "panfrost_gpu.h"
- #include "panfrost_perfcnt.h"
- #include "panfrost_regs.h"
- static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
- {
- struct panfrost_device *pfdev = data;
- u32 state = gpu_read(pfdev, GPU_INT_STAT);
- u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
- if (!state)
- return IRQ_NONE;
- if (state & GPU_IRQ_MASK_ERROR) {
- u64 address = (u64) gpu_read(pfdev, GPU_FAULT_ADDRESS_HI) << 32;
- address |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO);
- dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n",
- fault_status, panfrost_exception_name(fault_status & 0xFF),
- address);
- if (state & GPU_IRQ_MULTIPLE_FAULT)
- dev_warn(pfdev->dev, "There were multiple GPU faults - some have not been reported\n");
- gpu_write(pfdev, GPU_INT_MASK, 0);
- }
- if (state & GPU_IRQ_PERFCNT_SAMPLE_COMPLETED)
- panfrost_perfcnt_sample_done(pfdev);
- if (state & GPU_IRQ_CLEAN_CACHES_COMPLETED)
- panfrost_perfcnt_clean_cache_done(pfdev);
- gpu_write(pfdev, GPU_INT_CLEAR, state);
- return IRQ_HANDLED;
- }
- int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
- {
- int ret;
- u32 val;
- gpu_write(pfdev, GPU_INT_MASK, 0);
- gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET);
- ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT,
- val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000);
- if (ret) {
- dev_err(pfdev->dev, "gpu soft reset timed out\n");
- return ret;
- }
- gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL);
- gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL);
- 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;
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8443) ||
- panfrost_has_hw_issue(pfdev, HW_ISSUE_11035))
- quirks |= SC_LS_PAUSEBUFFER_DISABLE;
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10327))
- quirks |= SC_SDC_DISABLE_OQ_DISCARD;
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10797))
- quirks |= SC_ENABLE_TEXGRD_FLAGS;
- if (!panfrost_has_hw_issue(pfdev, GPUCORE_1619)) {
- if (panfrost_model_cmp(pfdev, 0x750) < 0) /* T60x, T62x, T72x */
- quirks |= SC_LS_ATTR_CHECK_DISABLE;
- else if (panfrost_model_cmp(pfdev, 0x880) <= 0) /* T76x, T8xx */
- quirks |= SC_LS_ALLOW_ATTR_TYPES;
- }
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_TTRX_2968_TTRX_3162))
- quirks |= SC_VAR_ALGORITHM;
- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_TLS_HASHING))
- quirks |= SC_TLS_HASH_ENABLE;
- if (quirks)
- gpu_write(pfdev, GPU_SHADER_CONFIG, quirks);
- quirks = gpu_read(pfdev, GPU_TILER_CONFIG);
- /* Set tiler clock gate override if required */
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_T76X_3953))
- quirks |= TC_CLOCK_GATE_OVERRIDE;
- gpu_write(pfdev, GPU_TILER_CONFIG, quirks);
- quirks = 0;
- if ((panfrost_model_eq(pfdev, 0x860) || panfrost_model_eq(pfdev, 0x880)) &&
- pfdev->features.revision >= 0x2000)
- quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT;
- else if (panfrost_model_eq(pfdev, 0x6000) &&
- pfdev->features.coherency_features == COHERENCY_ACE)
- quirks |= (COHERENCY_ACE_LITE | COHERENCY_ACE) <<
- JM_FORCE_COHERENCY_FEATURES_SHIFT;
- if (panfrost_has_hw_feature(pfdev, HW_FEATURE_IDVS_GROUP_SIZE))
- quirks |= JM_DEFAULT_IDVS_GROUP_SIZE << JM_IDVS_GROUP_SIZE_SHIFT;
- 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
- struct panfrost_model {
- const char *name;
- u32 id;
- u32 id_mask;
- u64 features;
- u64 issues;
- struct {
- u32 revision;
- u64 issues;
- } revs[MAX_HW_REVS];
- };
- #define GPU_MODEL(_name, _id, ...) \
- {\
- .name = __stringify(_name), \
- .id = _id, \
- .features = hw_features_##_name, \
- .issues = hw_issues_##_name, \
- .revs = { __VA_ARGS__ }, \
- }
- #define GPU_REV_EXT(name, _rev, _p, _s, stat) \
- {\
- .revision = (_rev) << 12 | (_p) << 4 | (_s), \
- .issues = hw_issues_##name##_r##_rev##p##_p##stat, \
- }
- #define GPU_REV(name, r, p) GPU_REV_EXT(name, r, p, 0, )
- static const struct panfrost_model gpu_models[] = {
- /* T60x has an oddball version */
- GPU_MODEL(t600, 0x600,
- GPU_REV_EXT(t600, 0, 0, 1, _15dev0)),
- GPU_MODEL(t620, 0x620,
- GPU_REV(t620, 0, 1), GPU_REV(t620, 1, 0)),
- GPU_MODEL(t720, 0x720),
- GPU_MODEL(t760, 0x750,
- GPU_REV(t760, 0, 0), GPU_REV(t760, 0, 1),
- GPU_REV_EXT(t760, 0, 1, 0, _50rel0),
- GPU_REV(t760, 0, 2), GPU_REV(t760, 0, 3)),
- GPU_MODEL(t820, 0x820),
- GPU_MODEL(t830, 0x830),
- GPU_MODEL(t860, 0x860),
- GPU_MODEL(t880, 0x880),
- GPU_MODEL(g71, 0x6000,
- GPU_REV_EXT(g71, 0, 0, 1, _05dev0)),
- GPU_MODEL(g72, 0x6001),
- GPU_MODEL(g51, 0x7000),
- GPU_MODEL(g76, 0x7001),
- GPU_MODEL(g52, 0x7002),
- GPU_MODEL(g31, 0x7003,
- GPU_REV(g31, 1, 0)),
- GPU_MODEL(g57, 0x9001,
- GPU_REV(g57, 0, 0)),
- };
- static void panfrost_gpu_init_features(struct panfrost_device *pfdev)
- {
- u32 gpu_id, num_js, major, minor, status, rev;
- const char *name = "unknown";
- u64 hw_feat = 0;
- u64 hw_issues = hw_issues_all;
- const struct panfrost_model *model;
- int i;
- pfdev->features.l2_features = gpu_read(pfdev, GPU_L2_FEATURES);
- pfdev->features.core_features = gpu_read(pfdev, GPU_CORE_FEATURES);
- pfdev->features.tiler_features = gpu_read(pfdev, GPU_TILER_FEATURES);
- pfdev->features.mem_features = gpu_read(pfdev, GPU_MEM_FEATURES);
- pfdev->features.mmu_features = gpu_read(pfdev, GPU_MMU_FEATURES);
- pfdev->features.thread_features = gpu_read(pfdev, GPU_THREAD_FEATURES);
- pfdev->features.max_threads = gpu_read(pfdev, GPU_THREAD_MAX_THREADS);
- pfdev->features.thread_max_workgroup_sz = gpu_read(pfdev, GPU_THREAD_MAX_WORKGROUP_SIZE);
- pfdev->features.thread_max_barrier_sz = gpu_read(pfdev, GPU_THREAD_MAX_BARRIER_SIZE);
- pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES);
- pfdev->features.afbc_features = gpu_read(pfdev, GPU_AFBC_FEATURES);
- for (i = 0; i < 4; i++)
- pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i));
- pfdev->features.as_present = gpu_read(pfdev, GPU_AS_PRESENT);
- pfdev->features.js_present = gpu_read(pfdev, GPU_JS_PRESENT);
- num_js = hweight32(pfdev->features.js_present);
- for (i = 0; i < num_js; i++)
- pfdev->features.js_features[i] = gpu_read(pfdev, GPU_JS_FEATURES(i));
- pfdev->features.shader_present = gpu_read(pfdev, GPU_SHADER_PRESENT_LO);
- pfdev->features.shader_present |= (u64)gpu_read(pfdev, GPU_SHADER_PRESENT_HI) << 32;
- pfdev->features.tiler_present = gpu_read(pfdev, GPU_TILER_PRESENT_LO);
- pfdev->features.tiler_present |= (u64)gpu_read(pfdev, GPU_TILER_PRESENT_HI) << 32;
- pfdev->features.l2_present = gpu_read(pfdev, GPU_L2_PRESENT_LO);
- pfdev->features.l2_present |= (u64)gpu_read(pfdev, GPU_L2_PRESENT_HI) << 32;
- pfdev->features.nr_core_groups = hweight64(pfdev->features.l2_present);
- pfdev->features.stack_present = gpu_read(pfdev, GPU_STACK_PRESENT_LO);
- pfdev->features.stack_present |= (u64)gpu_read(pfdev, GPU_STACK_PRESENT_HI) << 32;
- pfdev->features.thread_tls_alloc = gpu_read(pfdev, GPU_THREAD_TLS_ALLOC);
- gpu_id = gpu_read(pfdev, GPU_ID);
- pfdev->features.revision = gpu_id & 0xffff;
- pfdev->features.id = gpu_id >> 16;
- /* The T60x has an oddball ID value. Fix it up to the standard Midgard
- * format so we (and userspace) don't have to special case it.
- */
- if (pfdev->features.id == 0x6956)
- pfdev->features.id = 0x0600;
- major = (pfdev->features.revision >> 12) & 0xf;
- minor = (pfdev->features.revision >> 4) & 0xff;
- status = pfdev->features.revision & 0xf;
- rev = pfdev->features.revision;
- gpu_id = pfdev->features.id;
- for (model = gpu_models; model->name; model++) {
- int best = -1;
- if (!panfrost_model_eq(pfdev, model->id))
- continue;
- name = model->name;
- hw_feat = model->features;
- hw_issues |= model->issues;
- for (i = 0; i < MAX_HW_REVS; i++) {
- if (model->revs[i].revision == rev) {
- best = i;
- break;
- } else if (model->revs[i].revision == (rev & ~0xf))
- best = i;
- }
- if (best >= 0)
- hw_issues |= model->revs[best].issues;
- break;
- }
- bitmap_from_u64(pfdev->features.hw_features, hw_feat);
- bitmap_from_u64(pfdev->features.hw_issues, hw_issues);
- dev_info(pfdev->dev, "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x",
- name, gpu_id, major, minor, status);
- dev_info(pfdev->dev, "features: %64pb, issues: %64pb",
- pfdev->features.hw_features,
- pfdev->features.hw_issues);
- dev_info(pfdev->dev, "Features: L2:0x%08x Shader:0x%08x Tiler:0x%08x Mem:0x%0x MMU:0x%08x AS:0x%x JS:0x%x",
- pfdev->features.l2_features,
- pfdev->features.core_features,
- pfdev->features.tiler_features,
- pfdev->features.mem_features,
- pfdev->features.mmu_features,
- pfdev->features.as_present,
- pfdev->features.js_present);
- dev_info(pfdev->dev, "shader_present=0x%0llx l2_present=0x%0llx",
- pfdev->features.shader_present, pfdev->features.l2_present);
- }
- void panfrost_gpu_power_on(struct panfrost_device *pfdev)
- {
- int ret;
- u32 val;
- u64 core_mask = U64_MAX;
- panfrost_gpu_init_quirks(pfdev);
- if (pfdev->features.l2_present != 1) {
- /*
- * Only support one core group now.
- * ~(l2_present - 1) unsets all bits in l2_present except
- * the bottom bit. (l2_present - 2) has all the bits in
- * the first core group set. AND them together to generate
- * a mask of cores in the first core group.
- */
- core_mask = ~(pfdev->features.l2_present - 1) &
- (pfdev->features.l2_present - 2);
- dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n",
- hweight64(core_mask),
- hweight64(pfdev->features.shader_present));
- }
- gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask);
- ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO,
- val, val == (pfdev->features.l2_present & core_mask),
- 100, 20000);
- if (ret)
- dev_err(pfdev->dev, "error powering up gpu L2");
- gpu_write(pfdev, SHADER_PWRON_LO,
- pfdev->features.shader_present & core_mask);
- ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO,
- val, val == (pfdev->features.shader_present & core_mask),
- 100, 20000);
- if (ret)
- dev_err(pfdev->dev, "error powering up gpu shader");
- gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present);
- ret = readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO,
- val, val == pfdev->features.tiler_present, 100, 1000);
- if (ret)
- dev_err(pfdev->dev, "error powering up gpu tiler");
- }
- void panfrost_gpu_power_off(struct panfrost_device *pfdev)
- {
- gpu_write(pfdev, TILER_PWROFF_LO, 0);
- gpu_write(pfdev, SHADER_PWROFF_LO, 0);
- gpu_write(pfdev, L2_PWROFF_LO, 0);
- }
- int panfrost_gpu_init(struct panfrost_device *pfdev)
- {
- int err, irq;
- err = panfrost_gpu_soft_reset(pfdev);
- if (err)
- return err;
- panfrost_gpu_init_features(pfdev);
- err = dma_set_mask_and_coherent(pfdev->dev,
- DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features)));
- if (err)
- return err;
- dma_set_max_seg_size(pfdev->dev, UINT_MAX);
- irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
- if (irq <= 0)
- return -ENODEV;
- err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler,
- IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev);
- if (err) {
- dev_err(pfdev->dev, "failed to request gpu irq");
- return err;
- }
- panfrost_gpu_power_on(pfdev);
- return 0;
- }
- void panfrost_gpu_fini(struct panfrost_device *pfdev)
- {
- panfrost_gpu_power_off(pfdev);
- }
- u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev)
- {
- 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;
- }
|