0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/component.h>
0012 #include <linux/module.h>
0013 #include <linux/of_graph.h>
0014 #include <linux/sys_soc.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/soc/amlogic/meson-canvas.h>
0017
0018 #include <drm/drm_aperture.h>
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_drv.h>
0021 #include <drm/drm_fb_helper.h>
0022 #include <drm/drm_gem_cma_helper.h>
0023 #include <drm/drm_gem_framebuffer_helper.h>
0024 #include <drm/drm_modeset_helper_vtables.h>
0025 #include <drm/drm_module.h>
0026 #include <drm/drm_probe_helper.h>
0027 #include <drm/drm_vblank.h>
0028
0029 #include "meson_crtc.h"
0030 #include "meson_drv.h"
0031 #include "meson_overlay.h"
0032 #include "meson_plane.h"
0033 #include "meson_osd_afbcd.h"
0034 #include "meson_registers.h"
0035 #include "meson_encoder_cvbs.h"
0036 #include "meson_encoder_hdmi.h"
0037 #include "meson_viu.h"
0038 #include "meson_vpp.h"
0039 #include "meson_rdma.h"
0040
0041 #define DRIVER_NAME "meson"
0042 #define DRIVER_DESC "Amlogic Meson DRM driver"
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 static const struct drm_mode_config_funcs meson_mode_config_funcs = {
0060 .atomic_check = drm_atomic_helper_check,
0061 .atomic_commit = drm_atomic_helper_commit,
0062 .fb_create = drm_gem_fb_create,
0063 };
0064
0065 static const struct drm_mode_config_helper_funcs meson_mode_config_helpers = {
0066 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
0067 };
0068
0069 static irqreturn_t meson_irq(int irq, void *arg)
0070 {
0071 struct drm_device *dev = arg;
0072 struct meson_drm *priv = dev->dev_private;
0073
0074 (void)readl_relaxed(priv->io_base + _REG(VENC_INTFLAG));
0075
0076 meson_crtc_irq(priv);
0077
0078 return IRQ_HANDLED;
0079 }
0080
0081 static int meson_dumb_create(struct drm_file *file, struct drm_device *dev,
0082 struct drm_mode_create_dumb *args)
0083 {
0084
0085
0086
0087 args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64);
0088 args->size = PAGE_ALIGN(args->pitch * args->height);
0089
0090 return drm_gem_cma_dumb_create_internal(file, dev, args);
0091 }
0092
0093 DEFINE_DRM_GEM_CMA_FOPS(fops);
0094
0095 static const struct drm_driver meson_driver = {
0096 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0097
0098
0099 DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(meson_dumb_create),
0100
0101
0102 .fops = &fops,
0103 .name = DRIVER_NAME,
0104 .desc = DRIVER_DESC,
0105 .date = "20161109",
0106 .major = 1,
0107 .minor = 0,
0108 };
0109
0110 static bool meson_vpu_has_available_connectors(struct device *dev)
0111 {
0112 struct device_node *ep, *remote;
0113
0114
0115 for_each_endpoint_of_node(dev->of_node, ep) {
0116
0117 remote = of_graph_get_remote_port(ep);
0118 if (remote) {
0119 of_node_put(remote);
0120 of_node_put(ep);
0121 return true;
0122 }
0123 }
0124
0125 return false;
0126 }
0127
0128 static struct regmap_config meson_regmap_config = {
0129 .reg_bits = 32,
0130 .val_bits = 32,
0131 .reg_stride = 4,
0132 .max_register = 0x1000,
0133 };
0134
0135 static void meson_vpu_init(struct meson_drm *priv)
0136 {
0137 u32 value;
0138
0139
0140
0141
0142
0143 value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) |
0144 VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1);
0145 writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
0146
0147
0148 value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1);
0149 writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
0150
0151
0152 value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) |
0153 VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1);
0154 writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
0155
0156
0157 value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1);
0158 writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
0159 }
0160
0161 struct meson_drm_soc_attr {
0162 struct meson_drm_soc_limits limits;
0163 const struct soc_device_attribute *attrs;
0164 };
0165
0166 static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
0167
0168 {
0169 .limits = {
0170 .max_hdmi_phy_freq = 1650000,
0171 },
0172 .attrs = (const struct soc_device_attribute []) {
0173 { .soc_id = "GXL (S805*)", },
0174 { }
0175 }
0176 },
0177 };
0178
0179 static int meson_drv_bind_master(struct device *dev, bool has_components)
0180 {
0181 struct platform_device *pdev = to_platform_device(dev);
0182 const struct meson_drm_match_data *match;
0183 struct meson_drm *priv;
0184 struct drm_device *drm;
0185 struct resource *res;
0186 void __iomem *regs;
0187 int ret, i;
0188
0189
0190 if (!meson_vpu_has_available_connectors(dev)) {
0191 dev_err(dev, "No output connector available\n");
0192 return -ENODEV;
0193 }
0194
0195 match = of_device_get_match_data(dev);
0196 if (!match)
0197 return -ENODEV;
0198
0199 drm = drm_dev_alloc(&meson_driver, dev);
0200 if (IS_ERR(drm))
0201 return PTR_ERR(drm);
0202
0203 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0204 if (!priv) {
0205 ret = -ENOMEM;
0206 goto free_drm;
0207 }
0208 drm->dev_private = priv;
0209 priv->drm = drm;
0210 priv->dev = dev;
0211 priv->compat = match->compat;
0212 priv->afbcd.ops = match->afbcd_ops;
0213
0214 regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
0215 if (IS_ERR(regs)) {
0216 ret = PTR_ERR(regs);
0217 goto free_drm;
0218 }
0219
0220 priv->io_base = regs;
0221
0222 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
0223 if (!res) {
0224 ret = -EINVAL;
0225 goto free_drm;
0226 }
0227
0228 regs = devm_ioremap(dev, res->start, resource_size(res));
0229 if (!regs) {
0230 ret = -EADDRNOTAVAIL;
0231 goto free_drm;
0232 }
0233
0234 priv->hhi = devm_regmap_init_mmio(dev, regs,
0235 &meson_regmap_config);
0236 if (IS_ERR(priv->hhi)) {
0237 dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
0238 ret = PTR_ERR(priv->hhi);
0239 goto free_drm;
0240 }
0241
0242 priv->canvas = meson_canvas_get(dev);
0243 if (IS_ERR(priv->canvas)) {
0244 ret = PTR_ERR(priv->canvas);
0245 goto free_drm;
0246 }
0247
0248 ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
0249 if (ret)
0250 goto free_drm;
0251 ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
0252 if (ret) {
0253 meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
0254 goto free_drm;
0255 }
0256 ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1);
0257 if (ret) {
0258 meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
0259 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
0260 goto free_drm;
0261 }
0262 ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2);
0263 if (ret) {
0264 meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
0265 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
0266 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
0267 goto free_drm;
0268 }
0269
0270 priv->vsync_irq = platform_get_irq(pdev, 0);
0271
0272 ret = drm_vblank_init(drm, 1);
0273 if (ret)
0274 goto free_drm;
0275
0276
0277 for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) {
0278 if (soc_device_match(meson_drm_soc_attrs[i].attrs)) {
0279 priv->limits = &meson_drm_soc_attrs[i].limits;
0280 break;
0281 }
0282 }
0283
0284
0285
0286
0287
0288 ret = drm_aperture_remove_framebuffers(false, &meson_driver);
0289 if (ret)
0290 goto free_drm;
0291
0292 ret = drmm_mode_config_init(drm);
0293 if (ret)
0294 goto free_drm;
0295 drm->mode_config.max_width = 3840;
0296 drm->mode_config.max_height = 2160;
0297 drm->mode_config.funcs = &meson_mode_config_funcs;
0298 drm->mode_config.helper_private = &meson_mode_config_helpers;
0299
0300
0301
0302 meson_vpu_init(priv);
0303 meson_venc_init(priv);
0304 meson_vpp_init(priv);
0305 meson_viu_init(priv);
0306 if (priv->afbcd.ops) {
0307 ret = priv->afbcd.ops->init(priv);
0308 if (ret)
0309 goto free_drm;
0310 }
0311
0312
0313
0314 ret = meson_encoder_cvbs_init(priv);
0315 if (ret)
0316 goto exit_afbcd;
0317
0318 if (has_components) {
0319 ret = component_bind_all(drm->dev, drm);
0320 if (ret) {
0321 dev_err(drm->dev, "Couldn't bind all components\n");
0322 goto exit_afbcd;
0323 }
0324 }
0325
0326 ret = meson_encoder_hdmi_init(priv);
0327 if (ret)
0328 goto exit_afbcd;
0329
0330 ret = meson_plane_create(priv);
0331 if (ret)
0332 goto exit_afbcd;
0333
0334 ret = meson_overlay_create(priv);
0335 if (ret)
0336 goto exit_afbcd;
0337
0338 ret = meson_crtc_create(priv);
0339 if (ret)
0340 goto exit_afbcd;
0341
0342 ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm);
0343 if (ret)
0344 goto exit_afbcd;
0345
0346 drm_mode_config_reset(drm);
0347
0348 drm_kms_helper_poll_init(drm);
0349
0350 platform_set_drvdata(pdev, priv);
0351
0352 ret = drm_dev_register(drm, 0);
0353 if (ret)
0354 goto uninstall_irq;
0355
0356 drm_fbdev_generic_setup(drm, 32);
0357
0358 return 0;
0359
0360 uninstall_irq:
0361 free_irq(priv->vsync_irq, drm);
0362 exit_afbcd:
0363 if (priv->afbcd.ops)
0364 priv->afbcd.ops->exit(priv);
0365 free_drm:
0366 drm_dev_put(drm);
0367
0368 return ret;
0369 }
0370
0371 static int meson_drv_bind(struct device *dev)
0372 {
0373 return meson_drv_bind_master(dev, true);
0374 }
0375
0376 static void meson_drv_unbind(struct device *dev)
0377 {
0378 struct meson_drm *priv = dev_get_drvdata(dev);
0379 struct drm_device *drm = priv->drm;
0380
0381 if (priv->canvas) {
0382 meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
0383 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
0384 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
0385 meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2);
0386 }
0387
0388 drm_dev_unregister(drm);
0389 drm_kms_helper_poll_fini(drm);
0390 drm_atomic_helper_shutdown(drm);
0391 component_unbind_all(dev, drm);
0392 free_irq(priv->vsync_irq, drm);
0393 drm_dev_put(drm);
0394
0395 if (priv->afbcd.ops)
0396 priv->afbcd.ops->exit(priv);
0397 }
0398
0399 static const struct component_master_ops meson_drv_master_ops = {
0400 .bind = meson_drv_bind,
0401 .unbind = meson_drv_unbind,
0402 };
0403
0404 static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
0405 {
0406 struct meson_drm *priv = dev_get_drvdata(dev);
0407
0408 if (!priv)
0409 return 0;
0410
0411 return drm_mode_config_helper_suspend(priv->drm);
0412 }
0413
0414 static int __maybe_unused meson_drv_pm_resume(struct device *dev)
0415 {
0416 struct meson_drm *priv = dev_get_drvdata(dev);
0417
0418 if (!priv)
0419 return 0;
0420
0421 meson_vpu_init(priv);
0422 meson_venc_init(priv);
0423 meson_vpp_init(priv);
0424 meson_viu_init(priv);
0425 if (priv->afbcd.ops)
0426 priv->afbcd.ops->init(priv);
0427
0428 return drm_mode_config_helper_resume(priv->drm);
0429 }
0430
0431 static void meson_drv_shutdown(struct platform_device *pdev)
0432 {
0433 struct meson_drm *priv = dev_get_drvdata(&pdev->dev);
0434
0435 if (!priv)
0436 return;
0437
0438 drm_kms_helper_poll_fini(priv->drm);
0439 drm_atomic_helper_shutdown(priv->drm);
0440 }
0441
0442
0443 static const struct of_device_id connectors_match[] = {
0444 { .compatible = "composite-video-connector" },
0445 { .compatible = "svideo-connector" },
0446 {}
0447 };
0448
0449 static int meson_drv_probe(struct platform_device *pdev)
0450 {
0451 struct component_match *match = NULL;
0452 struct device_node *np = pdev->dev.of_node;
0453 struct device_node *ep, *remote;
0454 int count = 0;
0455
0456 for_each_endpoint_of_node(np, ep) {
0457 remote = of_graph_get_remote_port_parent(ep);
0458 if (!remote || !of_device_is_available(remote)) {
0459 of_node_put(remote);
0460 continue;
0461 }
0462
0463
0464 if (of_match_node(connectors_match, remote)) {
0465 ++count;
0466 of_node_put(remote);
0467 continue;
0468 }
0469
0470 dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n",
0471 np, remote, dev_name(&pdev->dev));
0472
0473 component_match_add(&pdev->dev, &match, component_compare_of, remote);
0474
0475 of_node_put(remote);
0476
0477 ++count;
0478 }
0479
0480 if (count && !match)
0481 return meson_drv_bind_master(&pdev->dev, false);
0482
0483
0484 if (count) {
0485 dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count);
0486
0487 return component_master_add_with_match(&pdev->dev,
0488 &meson_drv_master_ops,
0489 match);
0490 }
0491
0492
0493 return 0;
0494 };
0495
0496 static struct meson_drm_match_data meson_drm_gxbb_data = {
0497 .compat = VPU_COMPATIBLE_GXBB,
0498 };
0499
0500 static struct meson_drm_match_data meson_drm_gxl_data = {
0501 .compat = VPU_COMPATIBLE_GXL,
0502 };
0503
0504 static struct meson_drm_match_data meson_drm_gxm_data = {
0505 .compat = VPU_COMPATIBLE_GXM,
0506 .afbcd_ops = &meson_afbcd_gxm_ops,
0507 };
0508
0509 static struct meson_drm_match_data meson_drm_g12a_data = {
0510 .compat = VPU_COMPATIBLE_G12A,
0511 .afbcd_ops = &meson_afbcd_g12a_ops,
0512 };
0513
0514 static const struct of_device_id dt_match[] = {
0515 { .compatible = "amlogic,meson-gxbb-vpu",
0516 .data = (void *)&meson_drm_gxbb_data },
0517 { .compatible = "amlogic,meson-gxl-vpu",
0518 .data = (void *)&meson_drm_gxl_data },
0519 { .compatible = "amlogic,meson-gxm-vpu",
0520 .data = (void *)&meson_drm_gxm_data },
0521 { .compatible = "amlogic,meson-g12a-vpu",
0522 .data = (void *)&meson_drm_g12a_data },
0523 {}
0524 };
0525 MODULE_DEVICE_TABLE(of, dt_match);
0526
0527 static const struct dev_pm_ops meson_drv_pm_ops = {
0528 SET_SYSTEM_SLEEP_PM_OPS(meson_drv_pm_suspend, meson_drv_pm_resume)
0529 };
0530
0531 static struct platform_driver meson_drm_platform_driver = {
0532 .probe = meson_drv_probe,
0533 .shutdown = meson_drv_shutdown,
0534 .driver = {
0535 .name = "meson-drm",
0536 .of_match_table = dt_match,
0537 .pm = &meson_drv_pm_ops,
0538 },
0539 };
0540
0541 drm_module_platform_driver(meson_drm_platform_driver);
0542
0543 MODULE_AUTHOR("Jasper St. Pierre <jstpierre@mecheye.net>");
0544 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0545 MODULE_DESCRIPTION(DRIVER_DESC);
0546 MODULE_LICENSE("GPL");