From patchwork Fri Jul 31 10:13:26 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Abriou X-Patchwork-Id: 6910171 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C9E77C05AC for ; Fri, 31 Jul 2015 10:28:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D5000205B7 for ; Fri, 31 Jul 2015 10:28:38 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id DAB3B20429 for ; Fri, 31 Jul 2015 10:28:32 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1E4A96E713; Fri, 31 Jul 2015 03:28:31 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx08-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7116A6E713 for ; Fri, 31 Jul 2015 03:28:28 -0700 (PDT) Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.14.5/8.14.5) with SMTP id t6VA8NUN032003; Fri, 31 Jul 2015 12:13:38 +0200 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 1vxw1uutx1-1 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 31 Jul 2015 12:13:37 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 32D8634; Fri, 31 Jul 2015 10:13:34 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas22.st.com [10.75.90.92]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 83F5A4DF5; Fri, 31 Jul 2015 10:13:35 +0000 (GMT) Received: from localhost (10.201.23.35) by Webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.195.1; Fri, 31 Jul 2015 12:13:35 +0200 From: Vincent Abriou To: Subject: [PATCH 3/4] drm/sti: rename files and functions Date: Fri, 31 Jul 2015 12:13:26 +0200 Message-ID: <1438337607-13122-4-git-send-email-vincent.abriou@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1438337607-13122-1-git-send-email-vincent.abriou@st.com> References: <1438337607-13122-1-git-send-email-vincent.abriou@st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.23.35] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:5.14.151, 1.0.33, 0.0.0000 definitions=2015-07-31_05:2015-07-30, 2015-07-31, 1970-01-01 signatures=0 Cc: Fabien Dessenne , Benjamin Gaignard , kernel@stlinux.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-5.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP replace all "sti_drm_" occurences by "sti_" Signed-off-by: Vincent Abriou Reviewed-by: Benjamin Gaignard --- drivers/gpu/drm/sti/Makefile | 6 +- drivers/gpu/drm/sti/sti_compositor.c | 24 +-- drivers/gpu/drm/sti/sti_compositor.h | 2 +- drivers/gpu/drm/sti/sti_crtc.c | 322 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_crtc.h | 22 +++ drivers/gpu/drm/sti/sti_cursor.c | 2 +- drivers/gpu/drm/sti/sti_drm_crtc.c | 322 -------------------------------- drivers/gpu/drm/sti/sti_drm_crtc.h | 22 --- drivers/gpu/drm/sti/sti_drm_drv.c | 294 ------------------------------ drivers/gpu/drm/sti/sti_drm_drv.h | 35 ---- drivers/gpu/drm/sti/sti_drm_plane.c | 344 ----------------------------------- drivers/gpu/drm/sti/sti_drm_plane.h | 105 ----------- drivers/gpu/drm/sti/sti_drv.c | 294 ++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_drv.h | 35 ++++ drivers/gpu/drm/sti/sti_gdp.c | 2 +- drivers/gpu/drm/sti/sti_hqvdp.c | 6 +- drivers/gpu/drm/sti/sti_mixer.h | 2 +- drivers/gpu/drm/sti/sti_plane.c | 343 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_plane.h | 105 +++++++++++ drivers/gpu/drm/sti/sti_tvout.c | 8 +- drivers/gpu/drm/sti/sti_vid.c | 2 +- 21 files changed, 1148 insertions(+), 1149 deletions(-) create mode 100644 drivers/gpu/drm/sti/sti_crtc.c create mode 100644 drivers/gpu/drm/sti/sti_crtc.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_crtc.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_crtc.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_drv.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_drv.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_plane.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_plane.h create mode 100644 drivers/gpu/drm/sti/sti_drv.c create mode 100644 drivers/gpu/drm/sti/sti_drv.h create mode 100644 drivers/gpu/drm/sti/sti_plane.c create mode 100644 drivers/gpu/drm/sti/sti_plane.h diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 505b3ba..e27490b 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -4,8 +4,8 @@ sticompositor-y := \ sti_vid.o \ sti_cursor.o \ sti_compositor.o \ - sti_drm_crtc.o \ - sti_drm_plane.o + sti_crtc.o \ + sti_plane.o stihdmi-y := sti_hdmi.o \ sti_hdmi_tx3g0c55phy.o \ @@ -23,4 +23,4 @@ obj-$(CONFIG_DRM_STI) = \ sticompositor.o \ sti_hqvdp.o \ stidvo.o \ - sti_drm_drv.o + sti_drv.o diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 68c5c95..d62ed7f 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -14,11 +14,11 @@ #include #include "sti_compositor.h" +#include "sti_crtc.h" #include "sti_cursor.h" -#include "sti_drm_crtc.h" -#include "sti_drm_drv.h" -#include "sti_drm_plane.h" +#include "sti_drv.h" #include "sti_gdp.h" +#include "sti_plane.h" #include "sti_vid.h" #include "sti_vtg.h" @@ -62,7 +62,7 @@ static int sti_compositor_bind(struct device *dev, struct sti_compositor *compo = dev_get_drvdata(dev); struct drm_device *drm_dev = data; unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; - struct sti_drm_private *dev_priv = drm_dev->dev_private; + struct sti_private *dev_priv = drm_dev->dev_private; struct drm_plane *cursor = NULL; struct drm_plane *primary = NULL; struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; @@ -116,8 +116,8 @@ static int sti_compositor_bind(struct device *dev, DRM_ERROR("Can't create CURSOR plane\n"); break; } - cursor = sti_drm_plane_init(drm_dev, plane, 1, - DRM_PLANE_TYPE_CURSOR); + cursor = sti_plane_init(drm_dev, plane, 1, + DRM_PLANE_TYPE_CURSOR); plane_id++; break; case STI_GPD_SUBDEV: @@ -127,9 +127,9 @@ static int sti_compositor_bind(struct device *dev, DRM_ERROR("Can't create GDP plane\n"); break; } - primary = sti_drm_plane_init(drm_dev, plane, - (1 << mixer_id) - 1, - plane_type); + primary = sti_plane_init(drm_dev, plane, + (1 << mixer_id) - 1, + plane_type); plane_id++; break; default: @@ -139,8 +139,8 @@ static int sti_compositor_bind(struct device *dev, /* The first planes are reserved for primary planes*/ if (crtc_id < mixer_id && primary) { - sti_drm_crtc_init(drm_dev, compo->mixer[crtc_id], - primary, cursor); + sti_crtc_init(drm_dev, compo->mixer[crtc_id], + primary, cursor); crtc_id++; cursor = NULL; primary = NULL; @@ -196,7 +196,7 @@ static int sti_compositor_probe(struct platform_device *pdev) return -ENOMEM; } compo->dev = dev; - compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb; + compo->vtg_vblank_nb.notifier_call = sti_crtc_vblank_cb; /* populate data structure depending on compatibility */ BUG_ON(!of_match_node(compositor_of_match, np)->data); diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h index 77f9978..1a4a73d 100644 --- a/drivers/gpu/drm/sti/sti_compositor.h +++ b/drivers/gpu/drm/sti/sti_compositor.h @@ -12,8 +12,8 @@ #include #include -#include "sti_drm_plane.h" #include "sti_mixer.h" +#include "sti_plane.h" #define WAIT_NEXT_VSYNC_MS 50 /*ms*/ diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c new file mode 100644 index 0000000..27b3ef2 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include +#include +#include +#include +#include + +#include "sti_compositor.h" +#include "sti_crtc.h" +#include "sti_drv.h" +#include "sti_vtg.h" + +static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + DRM_DEBUG_KMS("\n"); +} + +static void sti_crtc_prepare(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + + mixer->enabled = true; + + /* Prepare and enable the compo IP clock */ + if (mixer->id == STI_MIXER_MAIN) { + if (clk_prepare_enable(compo->clk_compo_main)) + DRM_INFO("Failed to prepare/enable compo_main clk\n"); + } else { + if (clk_prepare_enable(compo->clk_compo_aux)) + DRM_INFO("Failed to prepare/enable compo_aux clk\n"); + } + + sti_mixer_clear_all_planes(mixer); +} + +static void sti_crtc_commit(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct sti_plane *plane; + + if ((!mixer || !compo)) { + DRM_ERROR("Can't find mixer or compositor)\n"); + return; + } + + /* get GDP which is reserved to the CRTC FB */ + plane = to_sti_plane(crtc->primary); + if (!plane) + DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); + + /* Enable plane on mixer */ + if (sti_mixer_set_plane_status(mixer, plane, true)) + DRM_ERROR("Cannot enable plane at mixer\n"); + + drm_crtc_vblank_on(crtc); +} + +static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* accept the provided drm_display_mode, do not fix it up */ + return true; +} + +static int +sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct clk *clk; + int rate = mode->clock * 1000; + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + mode->base.id, mode->name); + + DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->vrefresh, mode->clock, + mode->hdisplay, + mode->hsync_start, mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, mode->vsync_end, + mode->vtotal, mode->type, mode->flags); + + /* Set rate and prepare/enable pixel clock */ + if (mixer->id == STI_MIXER_MAIN) + clk = compo->clk_pix_main; + else + clk = compo->clk_pix_aux; + + res = clk_set_rate(clk, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); + return -EINVAL; + } + if (clk_prepare_enable(clk)) { + DRM_ERROR("Failed to prepare/enable pix clk\n"); + return -EINVAL; + } + + sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, &crtc->mode); + + res = sti_mixer_active_video_area(mixer, &crtc->mode); + if (res) { + DRM_ERROR("Can't set active video area\n"); + return -EINVAL; + } + + return res; +} + +static void sti_crtc_disable(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + + if (!mixer->enabled) + return; + + DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); + + /* Disable Background */ + sti_mixer_set_background_status(mixer, false); + + drm_crtc_vblank_off(crtc); + + /* Disable pixel clock and compo IP clocks */ + if (mixer->id == STI_MIXER_MAIN) { + clk_disable_unprepare(compo->clk_pix_main); + clk_disable_unprepare(compo->clk_compo_main); + } else { + clk_disable_unprepare(compo->clk_pix_aux); + clk_disable_unprepare(compo->clk_compo_aux); + } + + mixer->enabled = false; +} + +static void +sti_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + sti_crtc_prepare(crtc); + sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); +} + +static void sti_crtc_atomic_begin(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (crtc->state->event) { + crtc->state->event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + mixer->pending_event = crtc->state->event; + crtc->state->event = NULL; + } +} + +static void sti_crtc_atomic_flush(struct drm_crtc *crtc) +{ +} + +static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { + .dpms = sti_crtc_dpms, + .prepare = sti_crtc_prepare, + .commit = sti_crtc_commit, + .mode_fixup = sti_crtc_mode_fixup, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = sti_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, + .disable = sti_crtc_disable, + .atomic_begin = sti_crtc_atomic_begin, + .atomic_flush = sti_crtc_atomic_flush, +}; + +static void sti_crtc_destroy(struct drm_crtc *crtc) +{ + DRM_DEBUG_KMS("\n"); + drm_crtc_cleanup(crtc); +} + +static int sti_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, + uint64_t val) +{ + DRM_DEBUG_KMS("\n"); + return 0; +} + +int sti_crtc_vblank_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct drm_device *drm_dev; + struct sti_compositor *compo = + container_of(nb, struct sti_compositor, vtg_vblank_nb); + int *crtc = data; + unsigned long flags; + struct sti_private *priv; + + drm_dev = compo->mixer[*crtc]->drm_crtc.dev; + priv = drm_dev->dev_private; + + if ((event != VTG_TOP_FIELD_EVENT) && + (event != VTG_BOTTOM_FIELD_EVENT)) { + DRM_ERROR("unknown event: %lu\n", event); + return -EINVAL; + } + + drm_handle_vblank(drm_dev, *crtc); + + spin_lock_irqsave(&drm_dev->event_lock, flags); + if (compo->mixer[*crtc]->pending_event) { + drm_send_vblank_event(drm_dev, -1, + compo->mixer[*crtc]->pending_event); + drm_vblank_put(drm_dev, *crtc); + compo->mixer[*crtc]->pending_event = NULL; + } + spin_unlock_irqrestore(&drm_dev->event_lock, flags); + + return 0; +} + +int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) +{ + struct sti_private *dev_priv = dev->dev_private; + struct sti_compositor *compo = dev_priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, + vtg_vblank_nb, crtc)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(sti_crtc_enable_vblank); + +void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) +{ + struct sti_private *priv = dev->dev_private; + struct sti_compositor *compo = priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); + + /* free the resources of the pending requests */ + if (compo->mixer[crtc]->pending_event) { + drm_vblank_put(dev, crtc); + compo->mixer[crtc]->pending_event = NULL; + } +} +EXPORT_SYMBOL(sti_crtc_disable_vblank); + +static struct drm_crtc_funcs sti_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = sti_crtc_destroy, + .set_property = sti_crtc_set_property, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +bool sti_crtc_is_main(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (mixer->id == STI_MIXER_MAIN) + return true; + + return false; +} +EXPORT_SYMBOL(sti_crtc_is_main); + +int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, + struct drm_plane *primary, struct drm_plane *cursor) +{ + struct drm_crtc *crtc = &mixer->drm_crtc; + int res; + + res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, + &sti_crtc_funcs); + if (res) { + DRM_ERROR("Can't initialze CRTC\n"); + return -EINVAL; + } + + drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); + + DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", + crtc->base.id, sti_mixer_to_str(mixer)); + + return 0; +} diff --git a/drivers/gpu/drm/sti/sti_crtc.h b/drivers/gpu/drm/sti/sti_crtc.h new file mode 100644 index 0000000..51963e6 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_crtc.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_CRTC_H_ +#define _STI_CRTC_H_ + +#include + +struct sti_mixer; + +int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, + struct drm_plane *primary, struct drm_plane *cursor); +int sti_crtc_enable_vblank(struct drm_device *dev, int crtc); +void sti_crtc_disable_vblank(struct drm_device *dev, int crtc); +int sti_crtc_vblank_cb(struct notifier_block *nb, + unsigned long event, void *data); +bool sti_crtc_is_main(struct drm_crtc *drm_crtc); + +#endif diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index cd12403..2868909 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -8,7 +8,7 @@ #include #include "sti_cursor.h" -#include "sti_drm_plane.h" +#include "sti_plane.h" #include "sti_vtg.h" /* Registers */ diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c deleted file mode 100644 index a489b04..0000000 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include - -#include -#include -#include -#include -#include - -#include "sti_compositor.h" -#include "sti_drm_drv.h" -#include "sti_drm_crtc.h" -#include "sti_vtg.h" - -static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("\n"); -} - -static void sti_drm_crtc_prepare(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - - mixer->enabled = true; - - /* Prepare and enable the compo IP clock */ - if (mixer->id == STI_MIXER_MAIN) { - if (clk_prepare_enable(compo->clk_compo_main)) - DRM_INFO("Failed to prepare/enable compo_main clk\n"); - } else { - if (clk_prepare_enable(compo->clk_compo_aux)) - DRM_INFO("Failed to prepare/enable compo_aux clk\n"); - } - - sti_mixer_clear_all_planes(mixer); -} - -static void sti_drm_crtc_commit(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_plane *plane; - - if ((!mixer || !compo)) { - DRM_ERROR("Can't find mixer or compositor)\n"); - return; - } - - /* get GDP which is reserved to the CRTC FB */ - plane = to_sti_plane(crtc->primary); - if (!plane) - DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); - - /* Enable plane on mixer */ - if (sti_mixer_set_plane_status(mixer, plane, true)) - DRM_ERROR("Cannot enable plane at mixer\n"); - - drm_crtc_vblank_on(crtc); -} - -static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - /* accept the provided drm_display_mode, do not fix it up */ - return true; -} - -static int -sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct clk *clk; - int rate = mode->clock * 1000; - int res; - - DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - mode->base.id, mode->name); - - DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->vrefresh, mode->clock, - mode->hdisplay, - mode->hsync_start, mode->hsync_end, - mode->htotal, - mode->vdisplay, - mode->vsync_start, mode->vsync_end, - mode->vtotal, mode->type, mode->flags); - - /* Set rate and prepare/enable pixel clock */ - if (mixer->id == STI_MIXER_MAIN) - clk = compo->clk_pix_main; - else - clk = compo->clk_pix_aux; - - res = clk_set_rate(clk, rate); - if (res < 0) { - DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); - return -EINVAL; - } - if (clk_prepare_enable(clk)) { - DRM_ERROR("Failed to prepare/enable pix clk\n"); - return -EINVAL; - } - - sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, &crtc->mode); - - res = sti_mixer_active_video_area(mixer, &crtc->mode); - if (res) { - DRM_ERROR("Can't set active video area\n"); - return -EINVAL; - } - - return res; -} - -static void sti_drm_crtc_disable(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - - if (!mixer->enabled) - return; - - DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); - - /* Disable Background */ - sti_mixer_set_background_status(mixer, false); - - drm_crtc_vblank_off(crtc); - - /* Disable pixel clock and compo IP clocks */ - if (mixer->id == STI_MIXER_MAIN) { - clk_disable_unprepare(compo->clk_pix_main); - clk_disable_unprepare(compo->clk_compo_main); - } else { - clk_disable_unprepare(compo->clk_pix_aux); - clk_disable_unprepare(compo->clk_compo_aux); - } - - mixer->enabled = false; -} - -static void -sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - sti_drm_crtc_prepare(crtc); - sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); -} - -static void sti_drm_crtc_atomic_begin(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - - if (crtc->state->event) { - crtc->state->event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - mixer->pending_event = crtc->state->event; - crtc->state->event = NULL; - } -} - -static void sti_drm_crtc_atomic_flush(struct drm_crtc *crtc) -{ -} - -static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { - .dpms = sti_drm_crtc_dpms, - .prepare = sti_drm_crtc_prepare, - .commit = sti_drm_crtc_commit, - .mode_fixup = sti_drm_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, - .mode_set_nofb = sti_drm_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, - .disable = sti_drm_crtc_disable, - .atomic_begin = sti_drm_crtc_atomic_begin, - .atomic_flush = sti_drm_crtc_atomic_flush, -}; - -static void sti_drm_crtc_destroy(struct drm_crtc *crtc) -{ - DRM_DEBUG_KMS("\n"); - drm_crtc_cleanup(crtc); -} - -static int sti_drm_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, - uint64_t val) -{ - DRM_DEBUG_KMS("\n"); - return 0; -} - -int sti_drm_crtc_vblank_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct drm_device *drm_dev; - struct sti_compositor *compo = - container_of(nb, struct sti_compositor, vtg_vblank_nb); - int *crtc = data; - unsigned long flags; - struct sti_drm_private *priv; - - drm_dev = compo->mixer[*crtc]->drm_crtc.dev; - priv = drm_dev->dev_private; - - if ((event != VTG_TOP_FIELD_EVENT) && - (event != VTG_BOTTOM_FIELD_EVENT)) { - DRM_ERROR("unknown event: %lu\n", event); - return -EINVAL; - } - - drm_handle_vblank(drm_dev, *crtc); - - spin_lock_irqsave(&drm_dev->event_lock, flags); - if (compo->mixer[*crtc]->pending_event) { - drm_send_vblank_event(drm_dev, -1, - compo->mixer[*crtc]->pending_event); - drm_vblank_put(drm_dev, *crtc); - compo->mixer[*crtc]->pending_event = NULL; - } - spin_unlock_irqrestore(&drm_dev->event_lock, flags); - - return 0; -} - -int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) -{ - struct sti_drm_private *dev_priv = dev->dev_private; - struct sti_compositor *compo = dev_priv->compo; - struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; - - DRM_DEBUG_DRIVER("\n"); - - if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, - vtg_vblank_nb, crtc)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(sti_drm_crtc_enable_vblank); - -void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) -{ - struct sti_drm_private *priv = dev->dev_private; - struct sti_compositor *compo = priv->compo; - struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; - - DRM_DEBUG_DRIVER("\n"); - - if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) - DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); - - /* free the resources of the pending requests */ - if (compo->mixer[crtc]->pending_event) { - drm_vblank_put(dev, crtc); - compo->mixer[crtc]->pending_event = NULL; - } -} -EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); - -static struct drm_crtc_funcs sti_crtc_funcs = { - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .destroy = sti_drm_crtc_destroy, - .set_property = sti_drm_crtc_set_property, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, -}; - -bool sti_drm_crtc_is_main(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - - if (mixer->id == STI_MIXER_MAIN) - return true; - - return false; -} -EXPORT_SYMBOL(sti_drm_crtc_is_main); - -int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, - struct drm_plane *primary, struct drm_plane *cursor) -{ - struct drm_crtc *crtc = &mixer->drm_crtc; - int res; - - res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, - &sti_crtc_funcs); - if (res) { - DRM_ERROR("Can't initialze CRTC\n"); - return -EINVAL; - } - - drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); - - DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", - crtc->base.id, sti_mixer_to_str(mixer)); - - return 0; -} diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.h b/drivers/gpu/drm/sti/sti_drm_crtc.h deleted file mode 100644 index caca8b1..0000000 --- a/drivers/gpu/drm/sti/sti_drm_crtc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_CRTC_H_ -#define _STI_DRM_CRTC_H_ - -#include - -struct sti_mixer; - -int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, - struct drm_plane *primary, struct drm_plane *cursor); -int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); -void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); -int sti_drm_crtc_vblank_cb(struct notifier_block *nb, - unsigned long event, void *data); -bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc); - -#endif diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c deleted file mode 100644 index 8ad9fe6..0000000 --- a/drivers/gpu/drm/sti/sti_drm_drv.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sti_drm_drv.h" -#include "sti_drm_crtc.h" - -#define DRIVER_NAME "sti" -#define DRIVER_DESC "STMicroelectronics SoC DRM" -#define DRIVER_DATE "20140601" -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 - -#define STI_MAX_FB_HEIGHT 4096 -#define STI_MAX_FB_WIDTH 4096 - -static void sti_drm_atomic_schedule(struct sti_drm_private *private, - struct drm_atomic_state *state) -{ - private->commit.state = state; - schedule_work(&private->commit.work); -} - -static void sti_drm_atomic_complete(struct sti_drm_private *private, - struct drm_atomic_state *state) -{ - struct drm_device *drm = private->drm_dev; - - /* - * Everything below can be run asynchronously without the need to grab - * any modeset locks at all under one condition: It must be guaranteed - * that the asynchronous work has either been cancelled (if the driver - * supports it, which at least requires that the framebuffers get - * cleaned up with drm_atomic_helper_cleanup_planes()) or completed - * before the new state gets committed on the software side with - * drm_atomic_helper_swap_state(). - * - * This scheme allows new atomic state updates to be prepared and - * checked in parallel to the asynchronous completion of the previous - * update. Which is important since compositors need to figure out the - * composition of the next frame right after having submitted the - * current layout. - */ - - drm_atomic_helper_commit_modeset_disables(drm, state); - drm_atomic_helper_commit_planes(drm, state); - drm_atomic_helper_commit_modeset_enables(drm, state); - - drm_atomic_helper_wait_for_vblanks(drm, state); - - drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_free(state); -} - -static void sti_drm_atomic_work(struct work_struct *work) -{ - struct sti_drm_private *private = container_of(work, - struct sti_drm_private, commit.work); - - sti_drm_atomic_complete(private, private->commit.state); -} - -static int sti_drm_atomic_commit(struct drm_device *drm, - struct drm_atomic_state *state, bool async) -{ - struct sti_drm_private *private = drm->dev_private; - int err; - - err = drm_atomic_helper_prepare_planes(drm, state); - if (err) - return err; - - /* serialize outstanding asynchronous commits */ - mutex_lock(&private->commit.lock); - flush_work(&private->commit.work); - - /* - * This is the point of no return - everything below never fails except - * when the hw goes bonghits. Which means we can commit the new state on - * the software side now. - */ - - drm_atomic_helper_swap_state(drm, state); - - if (async) - sti_drm_atomic_schedule(private, state); - else - sti_drm_atomic_complete(private, state); - - mutex_unlock(&private->commit.lock); - return 0; -} - -static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { - .fb_create = drm_fb_cma_create, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = sti_drm_atomic_commit, -}; - -static void sti_drm_mode_config_init(struct drm_device *dev) -{ - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - - /* - * set max width and height as default value. - * this value would be used to check framebuffer size limitation - * at drm_mode_addfb(). - */ - dev->mode_config.max_width = STI_MAX_FB_HEIGHT; - dev->mode_config.max_height = STI_MAX_FB_WIDTH; - - dev->mode_config.funcs = &sti_drm_mode_config_funcs; -} - -static int sti_drm_load(struct drm_device *dev, unsigned long flags) -{ - struct sti_drm_private *private; - int ret; - - private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL); - if (!private) { - DRM_ERROR("Failed to allocate private\n"); - return -ENOMEM; - } - dev->dev_private = (void *)private; - private->drm_dev = dev; - - mutex_init(&private->commit.lock); - INIT_WORK(&private->commit.work, sti_drm_atomic_work); - - drm_mode_config_init(dev); - drm_kms_helper_poll_init(dev); - - sti_drm_mode_config_init(dev); - - ret = component_bind_all(dev->dev, dev); - if (ret) { - drm_kms_helper_poll_fini(dev); - drm_mode_config_cleanup(dev); - kfree(private); - return ret; - } - - drm_mode_config_reset(dev); - -#ifdef CONFIG_DRM_STI_FBDEV - drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_crtc, - dev->mode_config.num_connector); -#endif - return 0; -} - -static const struct file_operations sti_drm_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .mmap = drm_gem_cma_mmap, - .poll = drm_poll, - .read = drm_read, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .release = drm_release, -}; - -static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags) -{ - /* we want to be able to write in mmapped buffer */ - flags |= O_RDWR; - return drm_gem_prime_export(dev, obj, flags); -} - -static struct drm_driver sti_drm_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | - DRIVER_GEM | DRIVER_PRIME, - .load = sti_drm_load, - .gem_free_object = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = drm_gem_cma_dumb_create, - .dumb_map_offset = drm_gem_cma_dumb_map_offset, - .dumb_destroy = drm_gem_dumb_destroy, - .fops = &sti_drm_driver_fops, - - .get_vblank_counter = drm_vblank_count, - .enable_vblank = sti_drm_crtc_enable_vblank, - .disable_vblank = sti_drm_crtc_disable_vblank, - - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = sti_drm_gem_prime_export, - .gem_prime_import = drm_gem_prime_import, - .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, - .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, - - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, -}; - -static int compare_of(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -static int sti_drm_bind(struct device *dev) -{ - return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); -} - -static void sti_drm_unbind(struct device *dev) -{ - drm_put_dev(dev_get_drvdata(dev)); -} - -static const struct component_master_ops sti_drm_ops = { - .bind = sti_drm_bind, - .unbind = sti_drm_unbind, -}; - -static int sti_drm_platform_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct device_node *child_np; - struct component_match *match = NULL; - - dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); - - of_platform_populate(node, NULL, NULL, dev); - - child_np = of_get_next_available_child(node, NULL); - - while (child_np) { - component_match_add(dev, &match, compare_of, child_np); - of_node_put(child_np); - child_np = of_get_next_available_child(node, child_np); - } - - return component_master_add_with_match(dev, &sti_drm_ops, match); -} - -static int sti_drm_platform_remove(struct platform_device *pdev) -{ - component_master_del(&pdev->dev, &sti_drm_ops); - of_platform_depopulate(&pdev->dev); - - return 0; -} - -static const struct of_device_id sti_drm_dt_ids[] = { - { .compatible = "st,sti-display-subsystem", }, - { /* end node */ }, -}; -MODULE_DEVICE_TABLE(of, sti_drm_dt_ids); - -static struct platform_driver sti_drm_platform_driver = { - .probe = sti_drm_platform_probe, - .remove = sti_drm_platform_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = sti_drm_dt_ids, - }, -}; - -module_platform_driver(sti_drm_platform_driver); - -MODULE_AUTHOR("Benjamin Gaignard "); -MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h deleted file mode 100644 index c413aa3..0000000 --- a/drivers/gpu/drm/sti/sti_drm_drv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_DRV_H_ -#define _STI_DRM_DRV_H_ - -#include - -struct sti_compositor; -struct sti_tvout; - -/** - * STI drm private structure - * This structure is stored as private in the drm_device - * - * @compo: compositor - * @plane_zorder_property: z-order property for CRTC planes - * @drm_dev: drm device - */ -struct sti_drm_private { - struct sti_compositor *compo; - struct drm_property *plane_zorder_property; - struct drm_device *drm_dev; - - struct { - struct drm_atomic_state *state; - struct work_struct work; - struct mutex lock; - } commit; -}; - -#endif diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c deleted file mode 100644 index 0d16722..0000000 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include -#include -#include -#include -#include - -#include "sti_compositor.h" -#include "sti_drm_drv.h" -#include "sti_drm_plane.h" -#include "sti_vtg.h" - -/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ -enum sti_plane_desc sti_plane_default_zorder[] = { - STI_GDP_0, - STI_GDP_1, - STI_HQVDP_0, - STI_GDP_2, - STI_GDP_3, -}; - -const char *sti_plane_to_str(struct sti_plane *plane) -{ - switch (plane->desc) { - case STI_GDP_0: - return "GDP0"; - case STI_GDP_1: - return "GDP1"; - case STI_GDP_2: - return "GDP2"; - case STI_GDP_3: - return "GDP3"; - case STI_HQVDP_0: - return "HQVDP0"; - case STI_CURSOR: - return "CURSOR"; - default: - return ""; - } -} -EXPORT_SYMBOL(sti_plane_to_str); - -static int sti_plane_prepare(struct sti_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_display_mode *mode, int mixer_id, - int dest_x, int dest_y, int dest_w, int dest_h, - int src_x, int src_y, int src_w, int src_h) -{ - struct drm_gem_cma_object *cma_obj; - unsigned int i; - int res; - - if (!plane || !fb || !mode) { - DRM_ERROR("Null fb, plane or mode\n"); - return 1; - } - - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return 1; - } - - plane->fb = fb; - plane->mode = mode; - plane->mixer_id = mixer_id; - plane->dst_x = dest_x; - plane->dst_y = dest_y; - plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); - plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); - plane->src_x = src_x; - plane->src_y = src_y; - plane->src_w = src_w; - plane->src_h = src_h; - plane->format = fb->pixel_format; - plane->vaddr = cma_obj->vaddr; - plane->paddr = cma_obj->paddr; - for (i = 0; i < 4; i++) { - plane->pitches[i] = fb->pitches[i]; - plane->offsets[i] = fb->offsets[i]; - } - - DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", - sti_plane_to_str(plane), - plane->mixer_id); - DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", - sti_plane_to_str(plane), - plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, - plane->src_w, plane->src_h, plane->src_x, - plane->src_y); - - DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, - (char *)&plane->format, (unsigned long)plane->paddr); - - if (!plane->ops->prepare) { - DRM_ERROR("Cannot prepare\n"); - return 1; - } - - res = plane->ops->prepare(plane, !plane->enabled); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return res; - } - - plane->enabled = true; - - return 0; -} - -static int sti_plane_commit(struct sti_plane *plane) -{ - if (!plane) - return 1; - - if (!plane->ops->commit) { - DRM_ERROR("Cannot commit\n"); - return 1; - } - - return plane->ops->commit(plane); -} - -static int sti_plane_disable(struct sti_plane *plane) -{ - int res; - - DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); - if (!plane) - return 1; - - if (!plane->enabled) - return 0; - - if (!plane->ops->disable) { - DRM_ERROR("Cannot disable\n"); - return 1; - } - - res = plane->ops->disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return res; - } - - plane->enabled = false; - - return 0; -} - -static void sti_drm_plane_destroy(struct drm_plane *drm_plane) -{ - DRM_DEBUG_DRIVER("\n"); - - drm_plane_helper_disable(drm_plane); - drm_plane_cleanup(drm_plane); -} - -static int sti_drm_plane_set_property(struct drm_plane *drm_plane, - struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = drm_plane->dev; - struct sti_drm_private *private = dev->dev_private; - struct sti_plane *plane = to_sti_plane(drm_plane); - - DRM_DEBUG_DRIVER("\n"); - - if (property == private->plane_zorder_property) { - plane->zorder = val; - return 0; - } - - return -EINVAL; -} - -static struct drm_plane_funcs sti_drm_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = sti_drm_plane_destroy, - .set_property = sti_drm_plane_set_property, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -static int sti_drm_plane_atomic_check(struct drm_plane *drm_plane, - struct drm_plane_state *state) -{ - return 0; -} - -static void sti_drm_plane_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct drm_plane_state *state = drm_plane->state; - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(state->crtc); - int res; - - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - state->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); - - res = sti_mixer_set_plane_depth(mixer, plane); - if (res) { - DRM_ERROR("Cannot set plane depth\n"); - return; - } - - /* src_x are in 16.16 format */ - res = sti_plane_prepare(plane, state->crtc, state->fb, - &state->crtc->mode, mixer->id, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x >> 16, state->src_y >> 16, - state->src_w >> 16, state->src_h >> 16); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return; - } - - res = sti_plane_commit(plane); - if (res) { - DRM_ERROR("Plane commit failed\n"); - return; - } - - res = sti_mixer_set_plane_status(mixer, plane, true); - if (res) { - DRM_ERROR("Cannot enable plane at mixer\n"); - return; - } -} - -static void sti_drm_plane_atomic_disable(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); - int res; - - if (!drm_plane->crtc) { - DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", - drm_plane->base.id); - return; - } - - DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - - /* Disable plane at mixer level */ - res = sti_mixer_set_plane_status(mixer, plane, false); - if (res) { - DRM_ERROR("Cannot disable plane at mixer\n"); - return; - } - - /* Wait a while to be sure that a Vsync event is received */ - msleep(WAIT_NEXT_VSYNC_MS); - - /* Then disable plane itself */ - res = sti_plane_disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return; - } -} - -static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { - .atomic_check = sti_drm_plane_atomic_check, - .atomic_update = sti_drm_plane_atomic_update, - .atomic_disable = sti_drm_plane_atomic_disable, -}; - -static void sti_drm_plane_attach_zorder_property(struct drm_plane *drm_plane) -{ - struct drm_device *dev = drm_plane->dev; - struct sti_drm_private *private = dev->dev_private; - struct sti_plane *plane = to_sti_plane(drm_plane); - struct drm_property *prop; - - prop = private->plane_zorder_property; - if (!prop) { - prop = drm_property_create_range(dev, 0, "zpos", 1, - GAM_MIXER_NB_DEPTH_LEVEL); - if (!prop) - return; - - private->plane_zorder_property = prop; - } - - drm_object_attach_property(&drm_plane->base, prop, plane->zorder); -} - -struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_plane *plane, - unsigned int possible_crtcs, - enum drm_plane_type type) -{ - int err, i; - - err = drm_universal_plane_init(dev, &plane->drm_plane, - possible_crtcs, - &sti_drm_plane_funcs, - plane->ops->get_formats(plane), - plane->ops->get_nb_formats(plane), - type); - if (err) { - DRM_ERROR("Failed to initialize universal plane\n"); - return NULL; - } - - drm_plane_helper_add(&plane->drm_plane, - &sti_drm_plane_helpers_funcs); - - for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) - if (sti_plane_default_zorder[i] == plane->desc) - break; - - plane->zorder = i + 1; - - if (type == DRM_PLANE_TYPE_OVERLAY) - sti_drm_plane_attach_zorder_property(&plane->drm_plane); - - DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", - plane->drm_plane.base.id, - sti_plane_to_str(plane), plane->zorder); - - return &plane->drm_plane; -} -EXPORT_SYMBOL(sti_drm_plane_init); diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h deleted file mode 100644 index e547366..0000000 --- a/drivers/gpu/drm/sti/sti_drm_plane.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_PLANE_H_ -#define _STI_DRM_PLANE_H_ - -#include - -#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) - -#define STI_PLANE_TYPE_SHIFT 8 -#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1)) - -enum sti_plane_type { - STI_GDP = 1 << STI_PLANE_TYPE_SHIFT, - STI_VDP = 2 << STI_PLANE_TYPE_SHIFT, - STI_CUR = 3 << STI_PLANE_TYPE_SHIFT, - STI_BCK = 4 << STI_PLANE_TYPE_SHIFT -}; - -enum sti_plane_id_of_type { - STI_ID_0 = 0, - STI_ID_1 = 1, - STI_ID_2 = 2, - STI_ID_3 = 3 -}; - -enum sti_plane_desc { - STI_GDP_0 = STI_GDP | STI_ID_0, - STI_GDP_1 = STI_GDP | STI_ID_1, - STI_GDP_2 = STI_GDP | STI_ID_2, - STI_GDP_3 = STI_GDP | STI_ID_3, - STI_HQVDP_0 = STI_VDP | STI_ID_0, - STI_CURSOR = STI_CUR, - STI_BACK = STI_BCK -}; - -/** - * STI plane structure - * - * @plane: drm plane it is bound to (if any) - * @fb: drm fb it is bound to - * @mode: display mode - * @desc: plane type & id - * @ops: plane functions - * @zorder: plane z-order - * @mixer_id: id of the mixer used to display the plane - * @enabled: to know if the plane is active or not - * @src_x src_y: coordinates of the input (fb) area - * @src_w src_h: size of the input (fb) area - * @dst_x dst_y: coordinates of the output (crtc) area - * @dst_w dst_h: size of the output (crtc) area - * @format: format - * @pitches: pitch of 'planes' (eg: Y, U, V) - * @offsets: offset of 'planes' - * @vaddr: virtual address of the input buffer - * @paddr: physical address of the input buffer - */ -struct sti_plane { - struct drm_plane drm_plane; - struct drm_framebuffer *fb; - struct drm_display_mode *mode; - enum sti_plane_desc desc; - const struct sti_plane_funcs *ops; - int zorder; - int mixer_id; - bool enabled; - int src_x, src_y; - int src_w, src_h; - int dst_x, dst_y; - int dst_w, dst_h; - uint32_t format; - unsigned int pitches[4]; - unsigned int offsets[4]; - void *vaddr; - dma_addr_t paddr; -}; - -/** - * STI plane functions structure - * - * @get_formats: get plane supported formats - * @get_nb_formats: get number of format supported - * @prepare: prepare plane before rendering - * @commit: set plane for rendering - * @disable: disable plane - */ -struct sti_plane_funcs { - const uint32_t* (*get_formats)(struct sti_plane *plane); - unsigned int (*get_nb_formats)(struct sti_plane *plane); - int (*prepare)(struct sti_plane *plane, bool first_prepare); - int (*commit)(struct sti_plane *plane); - int (*disable)(struct sti_plane *plane); -}; - -struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_plane *sti_plane, - unsigned int possible_crtcs, - enum drm_plane_type type); -const char *sti_plane_to_str(struct sti_plane *plane); - -#endif diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c new file mode 100644 index 0000000..6f4af6a --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sti_crtc.h" +#include "sti_drv.h" + +#define DRIVER_NAME "sti" +#define DRIVER_DESC "STMicroelectronics SoC DRM" +#define DRIVER_DATE "20140601" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +#define STI_MAX_FB_HEIGHT 4096 +#define STI_MAX_FB_WIDTH 4096 + +static void sti_atomic_schedule(struct sti_private *private, + struct drm_atomic_state *state) +{ + private->commit.state = state; + schedule_work(&private->commit.work); +} + +static void sti_atomic_complete(struct sti_private *private, + struct drm_atomic_state *state) +{ + struct drm_device *drm = private->drm_dev; + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one condition: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout. + */ + + drm_atomic_helper_commit_modeset_disables(drm, state); + drm_atomic_helper_commit_planes(drm, state); + drm_atomic_helper_commit_modeset_enables(drm, state); + + drm_atomic_helper_wait_for_vblanks(drm, state); + + drm_atomic_helper_cleanup_planes(drm, state); + drm_atomic_state_free(state); +} + +static void sti_atomic_work(struct work_struct *work) +{ + struct sti_private *private = container_of(work, + struct sti_private, commit.work); + + sti_atomic_complete(private, private->commit.state); +} + +static int sti_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *state, bool async) +{ + struct sti_private *private = drm->dev_private; + int err; + + err = drm_atomic_helper_prepare_planes(drm, state); + if (err) + return err; + + /* serialize outstanding asynchronous commits */ + mutex_lock(&private->commit.lock); + flush_work(&private->commit.work); + + /* + * This is the point of no return - everything below never fails except + * when the hw goes bonghits. Which means we can commit the new state on + * the software side now. + */ + + drm_atomic_helper_swap_state(drm, state); + + if (async) + sti_atomic_schedule(private, state); + else + sti_atomic_complete(private, state); + + mutex_unlock(&private->commit.lock); + return 0; +} + +static struct drm_mode_config_funcs sti_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = sti_atomic_commit, +}; + +static void sti_mode_config_init(struct drm_device *dev) +{ + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + /* + * set max width and height as default value. + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + dev->mode_config.max_width = STI_MAX_FB_HEIGHT; + dev->mode_config.max_height = STI_MAX_FB_WIDTH; + + dev->mode_config.funcs = &sti_mode_config_funcs; +} + +static int sti_load(struct drm_device *dev, unsigned long flags) +{ + struct sti_private *private; + int ret; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) { + DRM_ERROR("Failed to allocate private\n"); + return -ENOMEM; + } + dev->dev_private = (void *)private; + private->drm_dev = dev; + + mutex_init(&private->commit.lock); + INIT_WORK(&private->commit.work, sti_atomic_work); + + drm_mode_config_init(dev); + drm_kms_helper_poll_init(dev); + + sti_mode_config_init(dev); + + ret = component_bind_all(dev->dev, dev); + if (ret) { + drm_kms_helper_poll_fini(dev); + drm_mode_config_cleanup(dev); + kfree(private); + return ret; + } + + drm_mode_config_reset(dev); + +#ifdef CONFIG_DRM_STI_FBDEV + drm_fbdev_cma_init(dev, 32, + dev->mode_config.num_crtc, + dev->mode_config.num_connector); +#endif + return 0; +} + +static const struct file_operations sti_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .read = drm_read, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .release = drm_release, +}; + +static struct dma_buf *sti_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, + int flags) +{ + /* we want to be able to write in mmapped buffer */ + flags |= O_RDWR; + return drm_gem_prime_export(dev, obj, flags); +} + +static struct drm_driver sti_driver = { + .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | + DRIVER_GEM | DRIVER_PRIME, + .load = sti_load, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .fops = &sti_driver_fops, + + .get_vblank_counter = drm_vblank_count, + .enable_vblank = sti_crtc_enable_vblank, + .disable_vblank = sti_crtc_disable_vblank, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = sti_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .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, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static int sti_bind(struct device *dev) +{ + return drm_platform_init(&sti_driver, to_platform_device(dev)); +} + +static void sti_unbind(struct device *dev) +{ + drm_put_dev(dev_get_drvdata(dev)); +} + +static const struct component_master_ops sti_ops = { + .bind = sti_bind, + .unbind = sti_unbind, +}; + +static int sti_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *child_np; + struct component_match *match = NULL; + + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + + of_platform_populate(node, NULL, NULL, dev); + + child_np = of_get_next_available_child(node, NULL); + + while (child_np) { + component_match_add(dev, &match, compare_of, child_np); + of_node_put(child_np); + child_np = of_get_next_available_child(node, child_np); + } + + return component_master_add_with_match(dev, &sti_ops, match); +} + +static int sti_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &sti_ops); + of_platform_depopulate(&pdev->dev); + + return 0; +} + +static const struct of_device_id sti_dt_ids[] = { + { .compatible = "st,sti-display-subsystem", }, + { /* end node */ }, +}; +MODULE_DEVICE_TABLE(of, sti_dt_ids); + +static struct platform_driver sti_platform_driver = { + .probe = sti_platform_probe, + .remove = sti_platform_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = sti_dt_ids, + }, +}; + +module_platform_driver(sti_platform_driver); + +MODULE_AUTHOR("Benjamin Gaignard "); +MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h new file mode 100644 index 0000000..9372f69 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drv.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_DRV_H_ +#define _STI_DRV_H_ + +#include + +struct sti_compositor; +struct sti_tvout; + +/** + * STI drm private structure + * This structure is stored as private in the drm_device + * + * @compo: compositor + * @plane_zorder_property: z-order property for CRTC planes + * @drm_dev: drm device + */ +struct sti_private { + struct sti_compositor *compo; + struct drm_property *plane_zorder_property; + struct drm_device *drm_dev; + + struct { + struct drm_atomic_state *state; + struct work_struct work; + struct mutex lock; + } commit; +}; + +#endif diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index e94d0be..e323310 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -10,8 +10,8 @@ #include #include "sti_compositor.h" -#include "sti_drm_plane.h" #include "sti_gdp.h" +#include "sti_plane.h" #include "sti_vtg.h" #define ALPHASWITCH BIT(6) diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 54e8c2f..b91a009 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -13,8 +13,8 @@ #include -#include "sti_drm_plane.h" #include "sti_hqvdp_lut.h" +#include "sti_plane.h" #include "sti_vtg.h" /* Firmware name */ @@ -967,8 +967,8 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) /* Create HQVDP plane once xp70 is initialized */ plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); if (plane) - sti_drm_plane_init(hqvdp->drm_dev, plane, 1, - DRM_PLANE_TYPE_OVERLAY); + sti_plane_init(hqvdp->drm_dev, plane, 1, + DRM_PLANE_TYPE_OVERLAY); else DRM_ERROR("Can't create HQVDP plane\n"); diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 9d51eac..2f69b00 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -11,7 +11,7 @@ #include -#include "sti_drm_plane.h" +#include "sti_plane.h" #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c new file mode 100644 index 0000000..6a38521 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include "sti_compositor.h" +#include "sti_drv.h" +#include "sti_plane.h" +#include "sti_vtg.h" + +/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ +enum sti_plane_desc sti_plane_default_zorder[] = { + STI_GDP_0, + STI_GDP_1, + STI_HQVDP_0, + STI_GDP_2, + STI_GDP_3, +}; + +const char *sti_plane_to_str(struct sti_plane *plane) +{ + switch (plane->desc) { + case STI_GDP_0: + return "GDP0"; + case STI_GDP_1: + return "GDP1"; + case STI_GDP_2: + return "GDP2"; + case STI_GDP_3: + return "GDP3"; + case STI_HQVDP_0: + return "HQVDP0"; + case STI_CURSOR: + return "CURSOR"; + default: + return ""; + } +} +EXPORT_SYMBOL(sti_plane_to_str); + +static int sti_plane_prepare(struct sti_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_display_mode *mode, int mixer_id, + int dest_x, int dest_y, int dest_w, int dest_h, + int src_x, int src_y, int src_w, int src_h) +{ + struct drm_gem_cma_object *cma_obj; + unsigned int i; + int res; + + if (!plane || !fb || !mode) { + DRM_ERROR("Null fb, plane or mode\n"); + return 1; + } + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return 1; + } + + plane->fb = fb; + plane->mode = mode; + plane->mixer_id = mixer_id; + plane->dst_x = dest_x; + plane->dst_y = dest_y; + plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); + plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); + plane->src_x = src_x; + plane->src_y = src_y; + plane->src_w = src_w; + plane->src_h = src_h; + plane->format = fb->pixel_format; + plane->vaddr = cma_obj->vaddr; + plane->paddr = cma_obj->paddr; + for (i = 0; i < 4; i++) { + plane->pitches[i] = fb->pitches[i]; + plane->offsets[i] = fb->offsets[i]; + } + + DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", + sti_plane_to_str(plane), + plane->mixer_id); + DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, + plane->src_w, plane->src_h, plane->src_x, + plane->src_y); + + DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, + (char *)&plane->format, (unsigned long)plane->paddr); + + if (!plane->ops->prepare) { + DRM_ERROR("Cannot prepare\n"); + return 1; + } + + res = plane->ops->prepare(plane, !plane->enabled); + if (res) { + DRM_ERROR("Plane prepare failed\n"); + return res; + } + + plane->enabled = true; + + return 0; +} + +static int sti_plane_commit(struct sti_plane *plane) +{ + if (!plane) + return 1; + + if (!plane->ops->commit) { + DRM_ERROR("Cannot commit\n"); + return 1; + } + + return plane->ops->commit(plane); +} + +static int sti_plane_disable(struct sti_plane *plane) +{ + int res; + + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); + if (!plane) + return 1; + + if (!plane->enabled) + return 0; + + if (!plane->ops->disable) { + DRM_ERROR("Cannot disable\n"); + return 1; + } + + res = plane->ops->disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return res; + } + + plane->enabled = false; + + return 0; +} + +static void sti_plane_destroy(struct drm_plane *drm_plane) +{ + DRM_DEBUG_DRIVER("\n"); + + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); +} + +static int sti_plane_set_property(struct drm_plane *drm_plane, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = drm_plane->dev; + struct sti_private *private = dev->dev_private; + struct sti_plane *plane = to_sti_plane(drm_plane); + + DRM_DEBUG_DRIVER("\n"); + + if (property == private->plane_zorder_property) { + plane->zorder = val; + return 0; + } + + return -EINVAL; +} + +static struct drm_plane_funcs sti_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_plane_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static int sti_plane_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) +{ + return 0; +} + +static void sti_plane_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(state->crtc); + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + state->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + + res = sti_mixer_set_plane_depth(mixer, plane); + if (res) { + DRM_ERROR("Cannot set plane depth\n"); + return; + } + + /* src_x are in 16.16 format */ + res = sti_plane_prepare(plane, state->crtc, state->fb, + &state->crtc->mode, mixer->id, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); + if (res) { + DRM_ERROR("Plane prepare failed\n"); + return; + } + + res = sti_plane_commit(plane); + if (res) { + DRM_ERROR("Plane commit failed\n"); + return; + } + + res = sti_mixer_set_plane_status(mixer, plane, true); + if (res) { + DRM_ERROR("Cannot enable plane at mixer\n"); + return; + } +} + +static void sti_plane_atomic_disable(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); + int res; + + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } + + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + /* Disable plane at mixer level */ + res = sti_mixer_set_plane_status(mixer, plane, false); + if (res) { + DRM_ERROR("Cannot disable plane at mixer\n"); + return; + } + + /* Wait a while to be sure that a Vsync event is received */ + msleep(WAIT_NEXT_VSYNC_MS); + + /* Then disable plane itself */ + res = sti_plane_disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return; + } +} + +static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = { + .atomic_check = sti_plane_atomic_check, + .atomic_update = sti_plane_atomic_update, + .atomic_disable = sti_plane_atomic_disable, +}; + +static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) +{ + struct drm_device *dev = drm_plane->dev; + struct sti_private *private = dev->dev_private; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct drm_property *prop; + + prop = private->plane_zorder_property; + if (!prop) { + prop = drm_property_create_range(dev, 0, "zpos", 1, + GAM_MIXER_NB_DEPTH_LEVEL); + if (!prop) + return; + + private->plane_zorder_property = prop; + } + + drm_object_attach_property(&drm_plane->base, prop, plane->zorder); +} + +struct drm_plane *sti_plane_init(struct drm_device *dev, + struct sti_plane *plane, + unsigned int possible_crtcs, + enum drm_plane_type type) +{ + int err, i; + + err = drm_universal_plane_init(dev, &plane->drm_plane, + possible_crtcs, + &sti_plane_funcs, + plane->ops->get_formats(plane), + plane->ops->get_nb_formats(plane), + type); + if (err) { + DRM_ERROR("Failed to initialize universal plane\n"); + return NULL; + } + + drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs); + + for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) + if (sti_plane_default_zorder[i] == plane->desc) + break; + + plane->zorder = i + 1; + + if (type == DRM_PLANE_TYPE_OVERLAY) + sti_plane_attach_zorder_property(&plane->drm_plane); + + DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", + plane->drm_plane.base.id, + sti_plane_to_str(plane), plane->zorder); + + return &plane->drm_plane; +} +EXPORT_SYMBOL(sti_plane_init); diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h new file mode 100644 index 0000000..bd52754 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_PLANE_H_ +#define _STI_PLANE_H_ + +#include + +#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) + +#define STI_PLANE_TYPE_SHIFT 8 +#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1)) + +enum sti_plane_type { + STI_GDP = 1 << STI_PLANE_TYPE_SHIFT, + STI_VDP = 2 << STI_PLANE_TYPE_SHIFT, + STI_CUR = 3 << STI_PLANE_TYPE_SHIFT, + STI_BCK = 4 << STI_PLANE_TYPE_SHIFT +}; + +enum sti_plane_id_of_type { + STI_ID_0 = 0, + STI_ID_1 = 1, + STI_ID_2 = 2, + STI_ID_3 = 3 +}; + +enum sti_plane_desc { + STI_GDP_0 = STI_GDP | STI_ID_0, + STI_GDP_1 = STI_GDP | STI_ID_1, + STI_GDP_2 = STI_GDP | STI_ID_2, + STI_GDP_3 = STI_GDP | STI_ID_3, + STI_HQVDP_0 = STI_VDP | STI_ID_0, + STI_CURSOR = STI_CUR, + STI_BACK = STI_BCK +}; + +/** + * STI plane structure + * + * @plane: drm plane it is bound to (if any) + * @fb: drm fb it is bound to + * @mode: display mode + * @desc: plane type & id + * @ops: plane functions + * @zorder: plane z-order + * @mixer_id: id of the mixer used to display the plane + * @enabled: to know if the plane is active or not + * @src_x src_y: coordinates of the input (fb) area + * @src_w src_h: size of the input (fb) area + * @dst_x dst_y: coordinates of the output (crtc) area + * @dst_w dst_h: size of the output (crtc) area + * @format: format + * @pitches: pitch of 'planes' (eg: Y, U, V) + * @offsets: offset of 'planes' + * @vaddr: virtual address of the input buffer + * @paddr: physical address of the input buffer + */ +struct sti_plane { + struct drm_plane drm_plane; + struct drm_framebuffer *fb; + struct drm_display_mode *mode; + enum sti_plane_desc desc; + const struct sti_plane_funcs *ops; + int zorder; + int mixer_id; + bool enabled; + int src_x, src_y; + int src_w, src_h; + int dst_x, dst_y; + int dst_w, dst_h; + uint32_t format; + unsigned int pitches[4]; + unsigned int offsets[4]; + void *vaddr; + dma_addr_t paddr; +}; + +/** + * STI plane functions structure + * + * @get_formats: get plane supported formats + * @get_nb_formats: get number of format supported + * @prepare: prepare plane before rendering + * @commit: set plane for rendering + * @disable: disable plane + */ +struct sti_plane_funcs { + const uint32_t* (*get_formats)(struct sti_plane *plane); + unsigned int (*get_nb_formats)(struct sti_plane *plane); + int (*prepare)(struct sti_plane *plane, bool first_prepare); + int (*commit)(struct sti_plane *plane); + int (*disable)(struct sti_plane *plane); +}; + +struct drm_plane *sti_plane_init(struct drm_device *dev, + struct sti_plane *sti_plane, + unsigned int possible_crtcs, + enum drm_plane_type type); +const char *sti_plane_to_str(struct sti_plane *plane); + +#endif diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 576b5be..c1aac8e 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -16,7 +16,7 @@ #include #include -#include "sti_drm_crtc.h" +#include "sti_crtc.h" /* glue registers */ #define TVO_CSC_MAIN_M0 0x000 @@ -473,7 +473,7 @@ static void sti_dvo_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_dvo_encoder_disable(struct drm_encoder *encoder) @@ -523,7 +523,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_hda_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_hda_encoder_disable(struct drm_encoder *encoder) @@ -575,7 +575,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_hdmi_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index b82a34f..1e7e1d7 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -6,7 +6,7 @@ #include -#include "sti_drm_plane.h" +#include "sti_plane.h" #include "sti_vid.h" #include "sti_vtg.h"