diff options
Diffstat (limited to 'drivers/gpu/drm/meson/meson_drv.c')
| -rw-r--r-- | drivers/gpu/drm/meson/meson_drv.c | 200 |
1 files changed, 114 insertions, 86 deletions
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 8a4ebcb6405c..397c33182f4f 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -1,55 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 BayLibre, SAS * Author: Neil Armstrong <narmstrong@baylibre.com> * Copyright (C) 2014 Endless Mobile * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * * Written by: * Jasper St. Pierre <jstpierre@mecheye.net> */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> #include <linux/component.h> +#include <linux/module.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/soc/amlogic/meson-canvas.h> -#include <drm/drmP.h> -#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_fb_cma_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_flip_work.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_plane_helper.h> +#include <drm/drm_irq.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_rect.h> +#include <drm/drm_vblank.h> +#include "meson_crtc.h" #include "meson_drv.h" -#include "meson_plane.h" #include "meson_overlay.h" -#include "meson_crtc.h" +#include "meson_plane.h" +#include "meson_registers.h" #include "meson_venc_cvbs.h" - -#include "meson_vpp.h" #include "meson_viu.h" -#include "meson_venc.h" -#include "meson_canvas.h" -#include "meson_registers.h" +#include "meson_vpp.h" #define DRIVER_NAME "meson" #define DRIVER_DESC "Amlogic Meson DRM driver" @@ -91,12 +73,22 @@ static irqreturn_t meson_irq(int irq, void *arg) return IRQ_HANDLED; } +static int meson_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + /* + * We need 64bytes aligned stride, and PAGE aligned size + */ + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64); + args->size = PAGE_ALIGN(args->pitch * args->height); + + return drm_gem_cma_dumb_create_internal(file, dev, args); +} + DEFINE_DRM_GEM_CMA_FOPS(fops); static struct drm_driver meson_driver = { - .driver_features = DRIVER_GEM | - DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC, + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, /* IRQ */ .irq_handler = meson_irq, @@ -104,8 +96,6 @@ static struct drm_driver meson_driver = { /* PRIME Ops */ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_export = drm_gem_prime_export, .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, .gem_prime_vmap = drm_gem_cma_prime_vmap, @@ -113,7 +103,7 @@ static struct drm_driver meson_driver = { .gem_prime_mmap = drm_gem_cma_prime_mmap, /* GEM Ops */ - .dumb_create = drm_gem_cma_dumb_create, + .dumb_create = meson_dumb_create, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, @@ -150,10 +140,28 @@ static struct regmap_config meson_regmap_config = { static void meson_vpu_init(struct meson_drm *priv) { - writel_relaxed(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); - writel_relaxed(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); - writel_relaxed(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); - writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); + u32 value; + + /* + * Slave dc0 and dc5 connected to master port 1. + * By default other slaves are connected to master port 0. + */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1)); + + /* Slave dc0 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2)); + + /* Slave dc4 and dc7 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) | + VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1)); + + /* Slave dc1 connected to master port 1 */ + value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1); + writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } static void meson_remove_framebuffers(void) @@ -201,6 +209,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) priv->drm = drm; priv->dev = dev; + priv->compat = (enum vpu_compatible)of_device_get_match_data(priv->dev); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) { @@ -231,50 +241,31 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) } priv->canvas = meson_canvas_get(dev); - if (!IS_ERR(priv->canvas)) { - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); - if (ret) - goto free_drm; - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - goto free_drm; - } - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); - goto free_drm; - } - ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); - if (ret) { - meson_canvas_free(priv->canvas, priv->canvas_id_osd1); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); - meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); - goto free_drm; - } - } else { - priv->canvas = NULL; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); - if (!res) { - ret = -EINVAL; - goto free_drm; - } - /* Simply ioremap since it may be a shared register zone */ - regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) { - ret = -EADDRNOTAVAIL; - goto free_drm; - } + if (IS_ERR(priv->canvas)) { + ret = PTR_ERR(priv->canvas); + goto free_drm; + } - priv->dmc = devm_regmap_init_mmio(dev, regs, - &meson_regmap_config); - if (IS_ERR(priv->dmc)) { - dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); - ret = PTR_ERR(priv->dmc); - goto free_drm; - } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); + if (ret) + goto free_drm; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + goto free_drm; + } + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); + if (ret) { + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); + goto free_drm; } priv->vsync_irq = platform_get_irq(pdev, 0); @@ -381,6 +372,33 @@ static const struct component_master_ops meson_drv_master_ops = { .unbind = meson_drv_unbind, }; +static int __maybe_unused meson_drv_pm_suspend(struct device *dev) +{ + struct meson_drm *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + + return drm_mode_config_helper_suspend(priv->drm); +} + +static int __maybe_unused meson_drv_pm_resume(struct device *dev) +{ + struct meson_drm *priv = dev_get_drvdata(dev); + + if (!priv) + return 0; + + meson_vpu_init(priv); + meson_venc_init(priv); + meson_vpp_init(priv); + meson_viu_init(priv); + + drm_mode_config_helper_resume(priv->drm); + + return 0; +} + static int compare_of(struct device *dev, void *data) { DRM_DEBUG_DRIVER("Comparing of node %pOF with %pOF\n", @@ -464,18 +482,28 @@ static int meson_drv_probe(struct platform_device *pdev) }; static const struct of_device_id dt_match[] = { - { .compatible = "amlogic,meson-gxbb-vpu" }, - { .compatible = "amlogic,meson-gxl-vpu" }, - { .compatible = "amlogic,meson-gxm-vpu" }, + { .compatible = "amlogic,meson-gxbb-vpu", + .data = (void *)VPU_COMPATIBLE_GXBB }, + { .compatible = "amlogic,meson-gxl-vpu", + .data = (void *)VPU_COMPATIBLE_GXL }, + { .compatible = "amlogic,meson-gxm-vpu", + .data = (void *)VPU_COMPATIBLE_GXM }, + { .compatible = "amlogic,meson-g12a-vpu", + .data = (void *)VPU_COMPATIBLE_G12A }, {} }; MODULE_DEVICE_TABLE(of, dt_match); +static const struct dev_pm_ops meson_drv_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(meson_drv_pm_suspend, meson_drv_pm_resume) +}; + static struct platform_driver meson_drm_platform_driver = { .probe = meson_drv_probe, .driver = { .name = "meson-drm", .of_match_table = dt_match, + .pm = &meson_drv_pm_ops, }, }; |
