From patchwork Tue Apr 8 12:19:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 27955 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pd0-f198.google.com (mail-pd0-f198.google.com [209.85.192.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 8DF9F20553 for ; Tue, 8 Apr 2014 12:20:34 +0000 (UTC) Received: by mail-pd0-f198.google.com with SMTP id fp1sf2435092pdb.9 for ; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:delivered-to:from:to:subject:date :message-id:in-reply-to:references:cc:precedence:list-id :list-unsubscribe:list-archive:list-post:list-help:list-subscribe :mime-version:errors-to:sender:x-original-sender :x-original-authentication-results:mailing-list:content-type :content-transfer-encoding; bh=0F0Oic5OXi3yw+Z8W6Zw7nEdsiZj3Tstiqf2iGkFy4c=; b=AFac9StZAR5Crvx1otwF8HPRDPiSTdCd1//CxmjCGMbJK/YKshai3FGINToi4Vh8ku +RWCUlfiVo9AfoGyuZoYC5ir+9zPDbIj85uvJ+yOdeqxFM0Ues7pSQBxp216AaWTOzM4 qFwuIr1I75jBk5MqcgCnweGnkQ4GsjIacy0TJWUHn19LV3wmKbaSDGwWLusjXMVM2bd/ UsbrgvcUS0PXg56w5/RDBnJNfChjhwwwezzB2OqQp4owjGt6wOTxtTtWRbUxUSwgLgVe 3ihmgCb7MB5iokNh5rEWswiWb1mBvL1Q9RsqRXnCOM3/X0m+JvpQC1ziGGietrKAVIAf t3fQ== X-Gm-Message-State: ALoCoQmemlVC34AnCvbOV3OMrM0KaSAT4Fbx8LI9jDGBrbiFQfwyki/SIy5LelhjmSyQj5u/EdrS X-Received: by 10.67.2.101 with SMTP id bn5mr1265836pad.29.1396959633846; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.92.163 with SMTP id b32ls183693qge.22.gmail; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) X-Received: by 10.52.95.135 with SMTP id dk7mr256630vdb.32.1396959633664; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) Received: from mail-vc0-f181.google.com (mail-vc0-f181.google.com [209.85.220.181]) by mx.google.com with ESMTPS id bf4si349614vec.208.2014.04.08.05.20.33 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 08 Apr 2014 05:20:33 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.181 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.220.181; Received: by mail-vc0-f181.google.com with SMTP id id10so691160vcb.12 for ; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) X-Received: by 10.221.58.144 with SMTP id wk16mr1522060vcb.23.1396959633562; Tue, 08 Apr 2014 05:20:33 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.12.8 with SMTP id v8csp240686vcv; Tue, 8 Apr 2014 05:20:33 -0700 (PDT) X-Received: by 10.68.113.194 with SMTP id ja2mr4317202pbb.30.1396959632781; Tue, 08 Apr 2014 05:20:32 -0700 (PDT) Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTP id nd6si987088pbc.282.2014.04.08.05.20.31 for ; Tue, 08 Apr 2014 05:20:32 -0700 (PDT) Received-SPF: pass (google.com: domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5E9E66E9DA; Tue, 8 Apr 2014 05:20:29 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wi0-f172.google.com (mail-wi0-f172.google.com [209.85.212.172]) by gabe.freedesktop.org (Postfix) with ESMTP id 646CD6E916 for ; Tue, 8 Apr 2014 05:20:27 -0700 (PDT) Received: by mail-wi0-f172.google.com with SMTP id hi2so6891543wib.5 for ; Tue, 08 Apr 2014 05:20:26 -0700 (PDT) X-Received: by 10.180.37.178 with SMTP id z18mr31588574wij.46.1396959626664; Tue, 08 Apr 2014 05:20:26 -0700 (PDT) Received: from lmenx321.lme.st.com (LPuteaux-656-01-48-212.w82-127.abo.wanadoo.fr. [82.127.83.212]) by mx.google.com with ESMTPSA id v6sm2683904wif.0.2014.04.08.05.20.25 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 08 Apr 2014 05:20:26 -0700 (PDT) From: Benjamin Gaignard To: dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [PATCH v1 02/19] drm: sti: add VTG driver Date: Tue, 8 Apr 2014 14:19:09 +0200 Message-Id: <1396959566-2960-3-git-send-email-benjamin.gaignard@linaro.org> X-Mailer: git-send-email 1.9.0 In-Reply-To: <1396959566-2960-1-git-send-email-benjamin.gaignard@linaro.org> References: <1396959566-2960-1-git-send-email-benjamin.gaignard@linaro.org> Cc: Fabien Dessenne , Benjamin Gaignard X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: benjamin.gaignard@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.220.181 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 Video Time Generator drivers are used to synchronize the compositor and tvout hardware IPs by providing line count, sample count, synchronization signals (HSYNC, VSYNC) and top and bottom fields indication. VTG are used by pair for each data path (main or auxiliary): one for master and one for slave. Signed-off-by: Benjamin Gaignard Signed-off-by: Vincent Abriou Signed-off-by: Fabien Dessenne --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/sti/Kconfig | 11 + drivers/gpu/drm/sti/Makefile | 3 + drivers/gpu/drm/sti/sti_vtg.c | 430 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_vtg.h | 20 ++ drivers/gpu/drm/sti/sti_vtg_utils.c | 99 +++++++++ drivers/gpu/drm/sti/sti_vtg_utils.h | 26 +++ 8 files changed, 592 insertions(+) create mode 100644 drivers/gpu/drm/sti/Kconfig create mode 100644 drivers/gpu/drm/sti/Makefile create mode 100644 drivers/gpu/drm/sti/sti_vtg.c create mode 100644 drivers/gpu/drm/sti/sti_vtg.h create mode 100644 drivers/gpu/drm/sti/sti_vtg_utils.c create mode 100644 drivers/gpu/drm/sti/sti_vtg_utils.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index d1cc2f6..0e30029 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -201,3 +201,5 @@ source "drivers/gpu/drm/tegra/Kconfig" source "drivers/gpu/drm/panel/Kconfig" source "drivers/gpu/drm/bridge/Kconfig" + +source "drivers/gpu/drm/sti/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5e792b0..44f7b17 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_DRM_QXL) += qxl/ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ +obj-$(CONFIG_DRM_STI) += sti/ obj-y += i2c/ obj-y += panel/ obj-y += bridge/ diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig new file mode 100644 index 0000000..b3c751c --- /dev/null +++ b/drivers/gpu/drm/sti/Kconfig @@ -0,0 +1,11 @@ +config DRM_STI + tristate "DRM Support for STMicroelectronics SoC stiH41x Series" + depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) + help + Choose this option to enable DRM on STM stiH41x chipset + +config VTG_STI + tristate "Video Timing Generator for STMicroelectronics SoC stiH41x Series" + depends on DRM_STI + help + Choose this option to enable VTG on STM stiH41x chipset diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile new file mode 100644 index 0000000..33216e1 --- /dev/null +++ b/drivers/gpu/drm/sti/Makefile @@ -0,0 +1,3 @@ +ccflags-y := -Iinclude/drm + +obj-$(CONFIG_VTG_STI) += sti_vtg.o sti_vtg_utils.o diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c new file mode 100644 index 0000000..d3514c1 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * Vincent Abriou + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include + +#include "sti_vtg_utils.h" +#include "sti_vtg.h" + +#define VTG_TYPE_MASTER 0 +#define VTG_TYPE_SLAVE_BY_EXT0 1 + +/* registers offset */ +#define VTG_MODE 0x0000 +#define VTG_CLKLN 0x0008 +#define VTG_HLFLN 0x000C +#define VTG_DRST_AUTOC 0x0010 +#define VTG_VID_TFO 0x0040 +#define VTG_VID_TFS 0x0044 +#define VTG_VID_BFO 0x0048 +#define VTG_VID_BFS 0x004C + +#define VTG_HOST_ITS 0x0078 +#define VTG_HOST_ITS_BCLR 0x007C +#define VTG_HOST_ITM_BCLR 0x0088 +#define VTG_HOST_ITM_BSET 0x008C + +#define VTG_H_HD_1 0x00C0 +#define VTG_TOP_V_VD_1 0x00C4 +#define VTG_BOT_V_VD_1 0x00C8 +#define VTG_TOP_V_HD_1 0x00CC +#define VTG_BOT_V_HD_1 0x00D0 + +#define VTG_H_HD_2 0x00E0 +#define VTG_TOP_V_VD_2 0x00E4 +#define VTG_BOT_V_VD_2 0x00E8 +#define VTG_TOP_V_HD_2 0x00EC +#define VTG_BOT_V_HD_2 0x00F0 + +#define VTG_H_HD_3 0x0100 +#define VTG_TOP_V_VD_3 0x0104 +#define VTG_BOT_V_VD_3 0x0108 +#define VTG_TOP_V_HD_3 0x010C +#define VTG_BOT_V_HD_3 0x0110 + +/* IRQ mask */ +#define VTG_IRQ_MASK ((1L<<1) | (1L<<0)) + +/* Delay introduced by the AWG in nb of pixels */ +#define AWG_DELAY_HD (-9) +#define AWG_DELAY_ED (-8) +#define AWG_DELAY_SD (-7) + +static const struct of_device_id vtg_match_types[]; + +/* + * STI VTG data structure + * + * @nb_reg: number of memory resources to register + * @reg_names: names of the memory resources to register + * @regs: ioremapped registers + */ +#define MAX_MEM_REGION 2 +#define VTG_MASTER 0 +#define VTG_SLAVE 1 +struct sti_vtg_data { + int nb_reg; + char *reg_names[MAX_MEM_REGION]; + void __iomem *regs[MAX_MEM_REGION]; +}; + +/* + * STI VTG structure + * + * @dev: pointer to device driver + * @data: data associated to the device + * @irq: VTG irq + * @type: VTG type (main or aux) + * @notifier_list: notifier callback + */ +struct sti_vtg { + struct device *dev; + struct sti_vtg_data data; + int irq; + int type; + struct raw_notifier_head notifier_list; +}; + +/* + * STiH416: + * -------- + * VTG slave is connected to the VTG master by the ext0 input (ext1 input is + * left unconnected). + * + * MPE ! ! SAS + * ________ ! ! ________ + * | | ! ! ext0 | | + * | | _________! !_________ ----->| | + * | VTG | hsync | ! ! | hsync | | VTG | + * | |------------>| VTAC Tx !==>! VTAC Rx |-------- | | + * | master | vsync |_________! !_________| vsync | slave | + * | | ! ! ---->| | + * |________| ! ! ext1 |________| + * ! ! | + * ! ! synchro_irq + * */ +struct sti_vtg_data stih416_vtg_data = { + .nb_reg = 2, + .reg_names = {"master", "slave"}, +}; + +/* + * STiH407: + * -------- + * Only VTG master is used. There is no MPE and SAS domain => only one domain. + * + * MPE + * ________ + * | | + * | | + * | VTG | hsync + * | |------------> + * | master | vsync + * | | + * |________| + * | + * synchro_irq + * */ +struct sti_vtg_data stih407_vtg_data = { + .nb_reg = 1, + .reg_names = {"master"}, +}; + +static int vtg_reset(void __iomem *regs) +{ + writel(1, regs + VTG_DRST_AUTOC); + return 0; +} + +static int vtg_reg_dump(struct device *dev, void __iomem *regs) +{ + dev_dbg(dev, "regs %p\n", regs); + dev_dbg(dev, "VTG_MODE 0x%x\n", readl(regs + VTG_MODE)); + dev_dbg(dev, "VTG_CLKLN 0x%x\n", readl(regs + VTG_CLKLN)); + dev_dbg(dev, "VTG_HLFLN 0x%x\n", readl(regs + VTG_HLFLN)); + dev_dbg(dev, "VTG_VID_TFO 0x%x\n", readl(regs + VTG_VID_TFO)); + dev_dbg(dev, "VTG_VID_BFO 0x%x\n", readl(regs + VTG_VID_BFO)); + dev_dbg(dev, "VTG_VID_TFS 0x%x\n", readl(regs + VTG_VID_TFS)); + dev_dbg(dev, "VTG_VID_BFS 0x%x\n", readl(regs + VTG_VID_BFS)); + dev_dbg(dev, "VTG_H_HD_1 0x%x\n", readl(regs + VTG_H_HD_1)); + dev_dbg(dev, "VTG_TOP_V_VD_1 0x%x\n", readl(regs + VTG_TOP_V_VD_1)); + dev_dbg(dev, "VTG_BOT_V_VD_1 0x%x\n", readl(regs + VTG_BOT_V_VD_1)); + dev_dbg(dev, "VTG_TOP_V_HD_1 0x%x\n", readl(regs + VTG_TOP_V_HD_1)); + dev_dbg(dev, "VTG_BOT_V_HD_1 0x%x\n", readl(regs + VTG_BOT_V_HD_1)); + dev_dbg(dev, "VTG_H_HD_2 0x%x\n", readl(regs + VTG_H_HD_2)); + dev_dbg(dev, "VTG_TOP_V_VD_2 0x%x\n", readl(regs + VTG_TOP_V_VD_2)); + dev_dbg(dev, "VTG_BOT_V_VD_2 0x%x\n", readl(regs + VTG_BOT_V_VD_2)); + dev_dbg(dev, "VTG_TOP_V_HD_2 0x%x\n", readl(regs + VTG_TOP_V_HD_2)); + dev_dbg(dev, "VTG_BOT_V_HD_2 0x%x\n", readl(regs + VTG_BOT_V_HD_2)); + dev_dbg(dev, "VTG_H_HD_3 0x%x\n", readl(regs + VTG_H_HD_3)); + dev_dbg(dev, "VTG_TOP_V_VD_3 0x%x\n", readl(regs + VTG_TOP_V_VD_3)); + dev_dbg(dev, "VTG_BOT_V_VD_3 0x%x\n", readl(regs + VTG_BOT_V_VD_3)); + dev_dbg(dev, "VTG_TOP_V_HD_3 0x%x\n", readl(regs + VTG_TOP_V_HD_3)); + dev_dbg(dev, "VTG_BOT_V_HD_3 0x%x\n", readl(regs + VTG_BOT_V_HD_3)); + return 0; +} + +static int vtg_write_reg(void __iomem *regs, + int type, const struct drm_display_mode *mode) +{ + int fo, fs, h_hd, v_vd, v_hd; + + writel(mode->htotal, regs + VTG_CLKLN); + writel(mode->vtotal * 2, regs + VTG_HLFLN); + + fo = (mode->vtotal - mode->vsync_start + 1) << 16; + fo |= mode->htotal - mode->hsync_start; + writel(fo, regs + VTG_VID_TFO); + writel(fo, regs + VTG_VID_BFO); + + fs = (mode->vdisplay + mode->vtotal - mode->vsync_start + 1) << 16; + fs |= mode->hdisplay + mode->htotal - mode->hsync_start; + writel(fs, regs + VTG_VID_TFS); + writel(fs, regs + VTG_VID_BFS); + + /* Prepare VTG set 1 for HDMI and VTG set 3 for HD DAC */ + h_hd = (mode->hsync_end - mode->hsync_start) << 16; + writel(h_hd, regs + VTG_H_HD_1); + + v_vd = (mode->vsync_end - mode->vsync_start + 1) << 16; + v_vd |= 1; + writel(v_vd, regs + VTG_TOP_V_VD_1); + writel(v_vd, regs + VTG_BOT_V_VD_1); + writel(0, regs + VTG_TOP_V_HD_1); + writel(0, regs + VTG_BOT_V_HD_1); + + /* Prepare VTG set 2 for for HD DCS */ + writel(h_hd, regs + VTG_H_HD_2); + writel(v_vd, regs + VTG_TOP_V_VD_2); + writel(v_vd, regs + VTG_BOT_V_VD_2); + writel(0, regs + VTG_TOP_V_HD_2); + writel(0, regs + VTG_BOT_V_HD_2); + + /* Prepare VTG set 3 for HD Analog in HD mode */ + h_hd = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16; + h_hd |= mode->htotal + AWG_DELAY_HD; + writel(h_hd, regs + VTG_H_HD_3); + + v_vd = (mode->vsync_end - mode->vsync_start) << 16; + v_vd |= mode->vtotal; + writel(v_vd, regs + VTG_TOP_V_VD_3); + writel(v_vd, regs + VTG_BOT_V_VD_3); + + v_hd = (mode->htotal + AWG_DELAY_HD) << 16; + v_hd |= mode->htotal + AWG_DELAY_HD; + writel(v_hd, regs + VTG_TOP_V_HD_3); + writel(v_hd, regs + VTG_BOT_V_HD_3); + + /* Mode */ + writel(type, regs + VTG_MODE); + return 0; +} + +static int vtg_disable_irq(void __iomem *regs) +{ + /* Clear interrupt status and mask */ + writel(0xFFFF, regs + VTG_HOST_ITS_BCLR); + writel(0xFFFF, regs + VTG_HOST_ITM_BCLR); + return 0; +} + +static int vtg_enable_irq(void __iomem *regs) +{ + vtg_disable_irq(regs); + writel(VTG_IRQ_MASK, regs + VTG_HOST_ITM_BSET); + return 0; +} + +int vtg_set_config(struct device *dev, const struct drm_display_mode *mode) +{ + struct sti_vtg *vtg = dev_get_drvdata(dev); + struct sti_vtg_data *data = &vtg->data; + + if (!vtg) + return 1; + + if (!data->regs[VTG_MASTER]) + return 1; + + /* write slave / master configuration */ + if (data->regs[VTG_SLAVE]) + vtg_write_reg(data->regs[VTG_SLAVE], + VTG_TYPE_SLAVE_BY_EXT0, mode); + + vtg_write_reg(data->regs[VTG_MASTER], VTG_TYPE_MASTER, mode); + + /* reset slave and then master */ + if (data->regs[VTG_SLAVE]) + vtg_reset(data->regs[VTG_SLAVE]); + + vtg_reset(data->regs[VTG_MASTER]); + + /* Enable irq for the vtg vblank synchro */ + if (data->regs[VTG_SLAVE]) + vtg_enable_irq(data->regs[VTG_SLAVE]); + else + vtg_enable_irq(data->regs[VTG_MASTER]); + + if (data->regs[VTG_SLAVE]) + vtg_reg_dump(dev, data->regs[VTG_SLAVE]); + + vtg_reg_dump(dev, data->regs[VTG_MASTER]); + + return 0; +} + +int vtg_register_client(struct device *dev, struct notifier_block *nb) +{ + struct sti_vtg *vtg = dev_get_drvdata(dev); + return raw_notifier_chain_register(&vtg->notifier_list, nb); +} + +int vtg_unregister_client(struct device *dev, struct notifier_block *nb) +{ + struct sti_vtg *vtg = dev_get_drvdata(dev); + return raw_notifier_chain_unregister(&vtg->notifier_list, nb); +} + +static irqreturn_t vtg_irq_thread(int irq, void *arg) +{ + struct sti_vtg *vtg = arg; + struct sti_vtg_data *data = &vtg->data; + void __iomem *regs; + u32 status; + + if (data->regs[VTG_SLAVE]) + regs = data->regs[VTG_SLAVE]; + else + regs = data->regs[VTG_MASTER]; + + status = readl(regs + VTG_HOST_ITS); + + writel(status, regs + VTG_HOST_ITS_BCLR); + /* TODO: check why this sync bus write solves the problem which + * is that without this line, the handler is sometimes called twice, + * first with status = 1 or 2, and immediately after with status=0 + */ + /* sync bus write */ + readl(regs + VTG_HOST_ITS); + + raw_notifier_call_chain(&vtg->notifier_list, + VTG_VBLANK_EVENT, &vtg->type); + + return IRQ_HANDLED; +} + +static const char *vtg_get_name(struct sti_vtg *vtg) +{ + if (vtg->type == VTG_MAIN) + return "main"; + else if (vtg->type == VTG_AUX) + return "aux"; + else + return "?"; +} + +static int vtg_compositor_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct sti_vtg *vtg; + struct resource *res; + char irq_name[32]; + struct sti_vtg_data *data; + int i; + int ret; + + if (!np) + return -ENXIO; + + vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL); + if (!vtg) { + DRM_ERROR("Failed to allocate VTG context\n"); + return -ENOMEM; + } + + vtg->dev = dev; + + /* populate data structure depending on compatibility */ + BUG_ON(!of_match_node(vtg_match_types, np)->data); + + memcpy(&vtg->data, of_match_node(vtg_match_types, np)->data, + sizeof(struct sti_vtg_data)); + + data = &vtg->data; + + /* Get resources */ + for (i = 0; i < data->nb_reg; i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + data->reg_names[i]); + if (!res) { + DRM_ERROR("Invalid resource\n"); + return -ENOMEM; + } + data->regs[i] = devm_ioremap_nocache(dev, + res->start, + resource_size(res)); + if (IS_ERR(data->regs[i])) + return PTR_ERR(data->regs[i]); + } + + vtg->irq = platform_get_irq_byname(pdev, "synchro_irq"); + if (IS_ERR_VALUE(vtg->irq)) { + DRM_ERROR("Failed to get VTG interrupt\n"); + return vtg->irq; + } + + snprintf(irq_name, sizeof(irq_name), "vsync-%s", vtg_get_name(vtg)); + + RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list); + + ret = devm_request_threaded_irq(dev, vtg->irq, NULL, vtg_irq_thread, + IRQF_ONESHOT, irq_name, vtg); + if (IS_ERR_VALUE(ret)) { + DRM_ERROR("Failed to register VTG interrupt\n"); + return ret; + } + + if (of_property_read_bool(np, "vtg-aux")) { + vtg->type = VTG_AUX; + vtg_aux = dev; + } else { + vtg->type = VTG_MAIN; + vtg_main = dev; + } + + platform_set_drvdata(pdev, vtg); + + DRM_INFO("%s VTG %s\n", __func__, vtg_get_name(vtg)); + + return 0; +} + +static const struct of_device_id vtg_match_types[] = { + { + .compatible = "st,stih416-vtg", + .data = &stih416_vtg_data, + }, + { + .compatible = "st,stih407-vtg", + .data = &stih407_vtg_data, + }, + { /* end node */ } +}; + +struct platform_driver sti_vtg_driver = { + .driver = { + .name = "sti-vtg", + .owner = THIS_MODULE, + .of_match_table = vtg_match_types, + }, + .probe = vtg_compositor_probe, +}; diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h new file mode 100644 index 0000000..da67eb3 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_vtg.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_VTG_H_ +#define _STI_VTG_H_ + +#include +#include + +extern struct device *vtg_main; +extern struct device *vtg_aux; + +int vtg_set_config(struct device *dev, const struct drm_display_mode *mode); +int vtg_register_client(struct device *dev, struct notifier_block *nb); +int vtg_unregister_client(struct device *dev, struct notifier_block *nb); + +#endif diff --git a/drivers/gpu/drm/sti/sti_vtg_utils.c b/drivers/gpu/drm/sti/sti_vtg_utils.c new file mode 100644 index 0000000..06bb4b4 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_vtg_utils.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include "sti_vtg_utils.h" +#include "sti_vtg.h" + +struct device *vtg_main; +struct device *vtg_aux; + +int sti_vtg_setconfig(int main_aux, const struct drm_display_mode *mode) +{ + if (main_aux == VTG_MAIN && vtg_main) + return vtg_set_config(vtg_main, mode); + + if (main_aux == VTG_AUX && vtg_aux) + return vtg_set_config(vtg_aux, mode); + + return 1; +} + +int sti_vtg_register_client(int main_aux, struct notifier_block *nb) +{ + if (main_aux == VTG_MAIN && vtg_main) + return vtg_register_client(vtg_main, nb); + + if (main_aux == VTG_AUX && vtg_aux) + return vtg_register_client(vtg_aux, nb); + + return 1; +} + +int sti_vtg_unregister_client(int main_aux, struct notifier_block *nb) +{ + if (main_aux == VTG_MAIN && vtg_main) + return vtg_unregister_client(vtg_main, nb); + + if (main_aux == VTG_AUX && vtg_aux) + return vtg_unregister_client(vtg_aux, nb); + + return 1; +} + +/* + * Active Front Sync Back Active + * Region Porch Porch Region + * <---------------><-------->0<---------><--------><-----------------> + * + * ///////////////| | ///////////////| + * /////////////// | | /////////////// | + * /////////////// |......... ..........|/////////////// | + * 0___________ x/ymin x/ymax + * + * <--[hv]display--> <--[hv]display--> + * <--[hv]sync_start---------> <--[hv]sync_start- + * <--[hv]sync_end-----------------------> <--[hv]sync_end--- + * <--[hv]total------------------------------------> <--[hv]total------ + */ + +/* + * sti_vtg_get_line_number + * + * @mode: display mode to be used + * @y: line + * + * Return the line number according to the display mode taking + * into account the Sync and Back Porch information. + * Video frame line numbers start at 1, y starts at 0. + * In interlaced modes the start line is the field line number of the odd + * field, but y is still defined as a progressive frame. + */ +u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) +{ + int start_line = mode.vtotal - mode.vsync_start + 1; + + if (mode.flags & DRM_MODE_FLAG_INTERLACE) + start_line *= 2; + + return start_line + y; +} + +/* + * sti_vtg_get_pixel_number + * + * @mode: display mode to be used + * @x: row + * + * Return the pixel number according to the display mode taking + * into account the Sync and Back Porch information. + * Pixels are counted from 0. + */ +u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) +{ + return mode.htotal - mode.hsync_start + x; +} diff --git a/drivers/gpu/drm/sti/sti_vtg_utils.h b/drivers/gpu/drm/sti/sti_vtg_utils.h new file mode 100644 index 0000000..03d81ba --- /dev/null +++ b/drivers/gpu/drm/sti/sti_vtg_utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_VTG_UTILS_H_ +#define _STI_VTG_UTILS_H_ + +#include + +#define VTG_MAIN 0 +#define VTG_AUX 1 + +#define VTG_VBLANK_EVENT 1 + +int sti_vtg_setconfig(int main_aux, const struct drm_display_mode *mode); +int sti_vtg_register_client(int main_aux, struct notifier_block *nb); +int sti_vtg_unregister_client(int main_aux, struct notifier_block *nb); + +u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y); +u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x); + +#endif