0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/component.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/pm_runtime.h>
0012
0013 #include "vc4_drv.h"
0014 #include "vc4_regs.h"
0015
0016 static const struct debugfs_reg32 v3d_regs[] = {
0017 VC4_REG32(V3D_IDENT0),
0018 VC4_REG32(V3D_IDENT1),
0019 VC4_REG32(V3D_IDENT2),
0020 VC4_REG32(V3D_SCRATCH),
0021 VC4_REG32(V3D_L2CACTL),
0022 VC4_REG32(V3D_SLCACTL),
0023 VC4_REG32(V3D_INTCTL),
0024 VC4_REG32(V3D_INTENA),
0025 VC4_REG32(V3D_INTDIS),
0026 VC4_REG32(V3D_CT0CS),
0027 VC4_REG32(V3D_CT1CS),
0028 VC4_REG32(V3D_CT0EA),
0029 VC4_REG32(V3D_CT1EA),
0030 VC4_REG32(V3D_CT0CA),
0031 VC4_REG32(V3D_CT1CA),
0032 VC4_REG32(V3D_CT00RA0),
0033 VC4_REG32(V3D_CT01RA0),
0034 VC4_REG32(V3D_CT0LC),
0035 VC4_REG32(V3D_CT1LC),
0036 VC4_REG32(V3D_CT0PC),
0037 VC4_REG32(V3D_CT1PC),
0038 VC4_REG32(V3D_PCS),
0039 VC4_REG32(V3D_BFC),
0040 VC4_REG32(V3D_RFC),
0041 VC4_REG32(V3D_BPCA),
0042 VC4_REG32(V3D_BPCS),
0043 VC4_REG32(V3D_BPOA),
0044 VC4_REG32(V3D_BPOS),
0045 VC4_REG32(V3D_BXCF),
0046 VC4_REG32(V3D_SQRSV0),
0047 VC4_REG32(V3D_SQRSV1),
0048 VC4_REG32(V3D_SQCNTL),
0049 VC4_REG32(V3D_SRQPC),
0050 VC4_REG32(V3D_SRQUA),
0051 VC4_REG32(V3D_SRQUL),
0052 VC4_REG32(V3D_SRQCS),
0053 VC4_REG32(V3D_VPACNTL),
0054 VC4_REG32(V3D_VPMBASE),
0055 VC4_REG32(V3D_PCTRC),
0056 VC4_REG32(V3D_PCTRE),
0057 VC4_REG32(V3D_PCTR(0)),
0058 VC4_REG32(V3D_PCTRS(0)),
0059 VC4_REG32(V3D_PCTR(1)),
0060 VC4_REG32(V3D_PCTRS(1)),
0061 VC4_REG32(V3D_PCTR(2)),
0062 VC4_REG32(V3D_PCTRS(2)),
0063 VC4_REG32(V3D_PCTR(3)),
0064 VC4_REG32(V3D_PCTRS(3)),
0065 VC4_REG32(V3D_PCTR(4)),
0066 VC4_REG32(V3D_PCTRS(4)),
0067 VC4_REG32(V3D_PCTR(5)),
0068 VC4_REG32(V3D_PCTRS(5)),
0069 VC4_REG32(V3D_PCTR(6)),
0070 VC4_REG32(V3D_PCTRS(6)),
0071 VC4_REG32(V3D_PCTR(7)),
0072 VC4_REG32(V3D_PCTRS(7)),
0073 VC4_REG32(V3D_PCTR(8)),
0074 VC4_REG32(V3D_PCTRS(8)),
0075 VC4_REG32(V3D_PCTR(9)),
0076 VC4_REG32(V3D_PCTRS(9)),
0077 VC4_REG32(V3D_PCTR(10)),
0078 VC4_REG32(V3D_PCTRS(10)),
0079 VC4_REG32(V3D_PCTR(11)),
0080 VC4_REG32(V3D_PCTRS(11)),
0081 VC4_REG32(V3D_PCTR(12)),
0082 VC4_REG32(V3D_PCTRS(12)),
0083 VC4_REG32(V3D_PCTR(13)),
0084 VC4_REG32(V3D_PCTRS(13)),
0085 VC4_REG32(V3D_PCTR(14)),
0086 VC4_REG32(V3D_PCTRS(14)),
0087 VC4_REG32(V3D_PCTR(15)),
0088 VC4_REG32(V3D_PCTRS(15)),
0089 VC4_REG32(V3D_DBGE),
0090 VC4_REG32(V3D_FDBGO),
0091 VC4_REG32(V3D_FDBGB),
0092 VC4_REG32(V3D_FDBGR),
0093 VC4_REG32(V3D_FDBGS),
0094 VC4_REG32(V3D_ERRSTAT),
0095 };
0096
0097 static int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
0098 {
0099 struct drm_info_node *node = (struct drm_info_node *)m->private;
0100 struct drm_device *dev = node->minor->dev;
0101 struct vc4_dev *vc4 = to_vc4_dev(dev);
0102 int ret = vc4_v3d_pm_get(vc4);
0103
0104 if (ret == 0) {
0105 uint32_t ident1 = V3D_READ(V3D_IDENT1);
0106 uint32_t nslc = VC4_GET_FIELD(ident1, V3D_IDENT1_NSLC);
0107 uint32_t tups = VC4_GET_FIELD(ident1, V3D_IDENT1_TUPS);
0108 uint32_t qups = VC4_GET_FIELD(ident1, V3D_IDENT1_QUPS);
0109
0110 seq_printf(m, "Revision: %d\n",
0111 VC4_GET_FIELD(ident1, V3D_IDENT1_REV));
0112 seq_printf(m, "Slices: %d\n", nslc);
0113 seq_printf(m, "TMUs: %d\n", nslc * tups);
0114 seq_printf(m, "QPUs: %d\n", nslc * qups);
0115 seq_printf(m, "Semaphores: %d\n",
0116 VC4_GET_FIELD(ident1, V3D_IDENT1_NSEM));
0117 vc4_v3d_pm_put(vc4);
0118 }
0119
0120 return 0;
0121 }
0122
0123
0124
0125
0126
0127 int
0128 vc4_v3d_pm_get(struct vc4_dev *vc4)
0129 {
0130 if (WARN_ON_ONCE(vc4->is_vc5))
0131 return -ENODEV;
0132
0133 mutex_lock(&vc4->power_lock);
0134 if (vc4->power_refcount++ == 0) {
0135 int ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
0136
0137 if (ret < 0) {
0138 vc4->power_refcount--;
0139 mutex_unlock(&vc4->power_lock);
0140 return ret;
0141 }
0142 }
0143 mutex_unlock(&vc4->power_lock);
0144
0145 return 0;
0146 }
0147
0148 void
0149 vc4_v3d_pm_put(struct vc4_dev *vc4)
0150 {
0151 if (WARN_ON_ONCE(vc4->is_vc5))
0152 return;
0153
0154 mutex_lock(&vc4->power_lock);
0155 if (--vc4->power_refcount == 0) {
0156 pm_runtime_mark_last_busy(&vc4->v3d->pdev->dev);
0157 pm_runtime_put_autosuspend(&vc4->v3d->pdev->dev);
0158 }
0159 mutex_unlock(&vc4->power_lock);
0160 }
0161
0162 static void vc4_v3d_init_hw(struct drm_device *dev)
0163 {
0164 struct vc4_dev *vc4 = to_vc4_dev(dev);
0165
0166
0167
0168
0169
0170 V3D_WRITE(V3D_VPMBASE, 0);
0171 }
0172
0173 int vc4_v3d_get_bin_slot(struct vc4_dev *vc4)
0174 {
0175 struct drm_device *dev = &vc4->base;
0176 unsigned long irqflags;
0177 int slot;
0178 uint64_t seqno = 0;
0179 struct vc4_exec_info *exec;
0180
0181 if (WARN_ON_ONCE(vc4->is_vc5))
0182 return -ENODEV;
0183
0184 try_again:
0185 spin_lock_irqsave(&vc4->job_lock, irqflags);
0186 slot = ffs(~vc4->bin_alloc_used);
0187 if (slot != 0) {
0188
0189 slot--;
0190 vc4->bin_alloc_used |= BIT(slot);
0191 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
0192 return slot;
0193 }
0194
0195
0196
0197
0198 exec = vc4_last_render_job(vc4);
0199 if (exec)
0200 seqno = exec->seqno;
0201 spin_unlock_irqrestore(&vc4->job_lock, irqflags);
0202
0203 if (seqno) {
0204 int ret = vc4_wait_for_seqno(dev, seqno, ~0ull, true);
0205
0206 if (ret == 0)
0207 goto try_again;
0208
0209 return ret;
0210 }
0211
0212 return -ENOMEM;
0213 }
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 static int bin_bo_alloc(struct vc4_dev *vc4)
0238 {
0239 struct vc4_v3d *v3d = vc4->v3d;
0240 uint32_t size = 16 * 1024 * 1024;
0241 int ret = 0;
0242 struct list_head list;
0243
0244 if (!v3d)
0245 return -ENODEV;
0246
0247
0248
0249
0250
0251
0252
0253 INIT_LIST_HEAD(&list);
0254
0255 while (true) {
0256 struct vc4_bo *bo = vc4_bo_create(&vc4->base, size, true,
0257 VC4_BO_TYPE_BIN);
0258
0259 if (IS_ERR(bo)) {
0260 ret = PTR_ERR(bo);
0261
0262 dev_err(&v3d->pdev->dev,
0263 "Failed to allocate memory for tile binning: "
0264 "%d. You may need to enable CMA or give it "
0265 "more memory.",
0266 ret);
0267 break;
0268 }
0269
0270
0271 if ((bo->base.paddr & 0xf0000000) ==
0272 ((bo->base.paddr + bo->base.base.size - 1) & 0xf0000000)) {
0273 vc4->bin_bo = bo;
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 vc4->bin_alloc_size = 512 * 1024;
0292 vc4->bin_alloc_used = 0;
0293 vc4->bin_alloc_overflow = 0;
0294 WARN_ON_ONCE(sizeof(vc4->bin_alloc_used) * 8 !=
0295 bo->base.base.size / vc4->bin_alloc_size);
0296
0297 kref_init(&vc4->bin_bo_kref);
0298
0299
0300
0301
0302
0303 V3D_WRITE(V3D_INTENA, V3D_INT_OUTOMEM);
0304
0305 break;
0306 }
0307
0308
0309 list_add(&bo->unref_head, &list);
0310 }
0311
0312
0313 while (!list_empty(&list)) {
0314 struct vc4_bo *bo = list_last_entry(&list,
0315 struct vc4_bo, unref_head);
0316
0317 list_del(&bo->unref_head);
0318 drm_gem_object_put(&bo->base.base);
0319 }
0320
0321 return ret;
0322 }
0323
0324 int vc4_v3d_bin_bo_get(struct vc4_dev *vc4, bool *used)
0325 {
0326 int ret = 0;
0327
0328 if (WARN_ON_ONCE(vc4->is_vc5))
0329 return -ENODEV;
0330
0331 mutex_lock(&vc4->bin_bo_lock);
0332
0333 if (used && *used)
0334 goto complete;
0335
0336 if (vc4->bin_bo)
0337 kref_get(&vc4->bin_bo_kref);
0338 else
0339 ret = bin_bo_alloc(vc4);
0340
0341 if (ret == 0 && used)
0342 *used = true;
0343
0344 complete:
0345 mutex_unlock(&vc4->bin_bo_lock);
0346
0347 return ret;
0348 }
0349
0350 static void bin_bo_release(struct kref *ref)
0351 {
0352 struct vc4_dev *vc4 = container_of(ref, struct vc4_dev, bin_bo_kref);
0353
0354 if (WARN_ON_ONCE(!vc4->bin_bo))
0355 return;
0356
0357 drm_gem_object_put(&vc4->bin_bo->base.base);
0358 vc4->bin_bo = NULL;
0359 }
0360
0361 void vc4_v3d_bin_bo_put(struct vc4_dev *vc4)
0362 {
0363 if (WARN_ON_ONCE(vc4->is_vc5))
0364 return;
0365
0366 mutex_lock(&vc4->bin_bo_lock);
0367 kref_put(&vc4->bin_bo_kref, bin_bo_release);
0368 mutex_unlock(&vc4->bin_bo_lock);
0369 }
0370
0371 #ifdef CONFIG_PM
0372 static int vc4_v3d_runtime_suspend(struct device *dev)
0373 {
0374 struct vc4_v3d *v3d = dev_get_drvdata(dev);
0375 struct vc4_dev *vc4 = v3d->vc4;
0376
0377 vc4_irq_disable(&vc4->base);
0378
0379 clk_disable_unprepare(v3d->clk);
0380
0381 return 0;
0382 }
0383
0384 static int vc4_v3d_runtime_resume(struct device *dev)
0385 {
0386 struct vc4_v3d *v3d = dev_get_drvdata(dev);
0387 struct vc4_dev *vc4 = v3d->vc4;
0388 int ret;
0389
0390 ret = clk_prepare_enable(v3d->clk);
0391 if (ret != 0)
0392 return ret;
0393
0394 vc4_v3d_init_hw(&vc4->base);
0395
0396
0397 enable_irq(vc4->irq);
0398 vc4_irq_enable(&vc4->base);
0399
0400 return 0;
0401 }
0402 #endif
0403
0404 static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
0405 {
0406 struct platform_device *pdev = to_platform_device(dev);
0407 struct drm_device *drm = dev_get_drvdata(master);
0408 struct vc4_dev *vc4 = to_vc4_dev(drm);
0409 struct vc4_v3d *v3d = NULL;
0410 int ret;
0411
0412 v3d = devm_kzalloc(&pdev->dev, sizeof(*v3d), GFP_KERNEL);
0413 if (!v3d)
0414 return -ENOMEM;
0415
0416 dev_set_drvdata(dev, v3d);
0417
0418 v3d->pdev = pdev;
0419
0420 v3d->regs = vc4_ioremap_regs(pdev, 0);
0421 if (IS_ERR(v3d->regs))
0422 return PTR_ERR(v3d->regs);
0423 v3d->regset.base = v3d->regs;
0424 v3d->regset.regs = v3d_regs;
0425 v3d->regset.nregs = ARRAY_SIZE(v3d_regs);
0426
0427 vc4->v3d = v3d;
0428 v3d->vc4 = vc4;
0429
0430 v3d->clk = devm_clk_get(dev, NULL);
0431 if (IS_ERR(v3d->clk)) {
0432 int ret = PTR_ERR(v3d->clk);
0433
0434 if (ret == -ENOENT) {
0435
0436 ret = 0;
0437 v3d->clk = NULL;
0438 } else {
0439 if (ret != -EPROBE_DEFER)
0440 dev_err(dev, "Failed to get V3D clock: %d\n",
0441 ret);
0442 return ret;
0443 }
0444 }
0445
0446 if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
0447 DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
0448 V3D_READ(V3D_IDENT0), V3D_EXPECTED_IDENT0);
0449 return -EINVAL;
0450 }
0451
0452 ret = clk_prepare_enable(v3d->clk);
0453 if (ret != 0)
0454 return ret;
0455
0456
0457
0458
0459 V3D_WRITE(V3D_BPOA, 0);
0460 V3D_WRITE(V3D_BPOS, 0);
0461
0462 vc4_v3d_init_hw(drm);
0463
0464 ret = platform_get_irq(pdev, 0);
0465 if (ret < 0)
0466 return ret;
0467 vc4->irq = ret;
0468
0469 ret = vc4_irq_install(drm, vc4->irq);
0470 if (ret) {
0471 DRM_ERROR("Failed to install IRQ handler\n");
0472 return ret;
0473 }
0474
0475 pm_runtime_set_active(dev);
0476 pm_runtime_use_autosuspend(dev);
0477 pm_runtime_set_autosuspend_delay(dev, 40);
0478 pm_runtime_enable(dev);
0479
0480 vc4_debugfs_add_file(drm, "v3d_ident", vc4_v3d_debugfs_ident, NULL);
0481 vc4_debugfs_add_regset32(drm, "v3d_regs", &v3d->regset);
0482
0483 return 0;
0484 }
0485
0486 static void vc4_v3d_unbind(struct device *dev, struct device *master,
0487 void *data)
0488 {
0489 struct drm_device *drm = dev_get_drvdata(master);
0490 struct vc4_dev *vc4 = to_vc4_dev(drm);
0491
0492 pm_runtime_disable(dev);
0493
0494 vc4_irq_uninstall(drm);
0495
0496
0497
0498
0499
0500 V3D_WRITE(V3D_BPOA, 0);
0501 V3D_WRITE(V3D_BPOS, 0);
0502
0503 vc4->v3d = NULL;
0504 }
0505
0506 static const struct dev_pm_ops vc4_v3d_pm_ops = {
0507 SET_RUNTIME_PM_OPS(vc4_v3d_runtime_suspend, vc4_v3d_runtime_resume, NULL)
0508 };
0509
0510 static const struct component_ops vc4_v3d_ops = {
0511 .bind = vc4_v3d_bind,
0512 .unbind = vc4_v3d_unbind,
0513 };
0514
0515 static int vc4_v3d_dev_probe(struct platform_device *pdev)
0516 {
0517 return component_add(&pdev->dev, &vc4_v3d_ops);
0518 }
0519
0520 static int vc4_v3d_dev_remove(struct platform_device *pdev)
0521 {
0522 component_del(&pdev->dev, &vc4_v3d_ops);
0523 return 0;
0524 }
0525
0526 const struct of_device_id vc4_v3d_dt_match[] = {
0527 { .compatible = "brcm,bcm2835-v3d" },
0528 { .compatible = "brcm,cygnus-v3d" },
0529 { .compatible = "brcm,vc4-v3d" },
0530 {}
0531 };
0532
0533 struct platform_driver vc4_v3d_driver = {
0534 .probe = vc4_v3d_dev_probe,
0535 .remove = vc4_v3d_dev_remove,
0536 .driver = {
0537 .name = "vc4_v3d",
0538 .of_match_table = vc4_v3d_dt_match,
0539 .pm = &vc4_v3d_pm_ops,
0540 },
0541 };