From patchwork Tue Apr 8 12:19:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 27962 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ie0-f200.google.com (mail-ie0-f200.google.com [209.85.223.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 1CFCF20553 for ; Tue, 8 Apr 2014 12:20:47 +0000 (UTC) Received: by mail-ie0-f200.google.com with SMTP id lx4sf3702223iec.7 for ; Tue, 08 Apr 2014 05:20:47 -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=tYZ5AHmb4qQW4sPCB0/DUEQRww+w3E7ur0LBEB8fzkM=; b=ZJ4ru4OgzH6Be2ekC0a9ADcb98pJmdduNvimLxjlbJDwwkEx5PhE7F73PHjPG9Gt8P 9ARgaQQp/ER3nyGQ6F45SdAAvc4RyX80xAK11E7J48fVoMIYyYAOlGGBCID6PKyVgDJf 7caE1RYNIw3LjOzajwOMX0EoJ3if+/EECf7w1C9LCpeVmqdIvEH20OzT/bwFxTGtJny1 Q+NTWird98tr5pBvA6dk5kx6+2Cp8PSDCDJ8qSvUaM4RTt/IhMDnhU/9yhrCxH2NVlz7 fUBgdmeMU3FDwrUF6Xu2MkyTx+x0Q5U3wave7ClgUeDneSnenTXV73Y6e9pBHRHl9Rmg KMag== X-Gm-Message-State: ALoCoQkoYRbw4hghYtpXYHIJQ2LSdC3U6uUSirUzZbhbB/Leb0jURFvM8dhl2/L9PaIUY9jC0wQN X-Received: by 10.182.5.42 with SMTP id p10mr1608301obp.37.1396959647516; Tue, 08 Apr 2014 05:20:47 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.22.167 with SMTP id 36ls185359qgn.55.gmail; Tue, 08 Apr 2014 05:20:47 -0700 (PDT) X-Received: by 10.220.161.8 with SMTP id p8mr3019700vcx.4.1396959647354; Tue, 08 Apr 2014 05:20:47 -0700 (PDT) Received: from mail-vc0-f176.google.com (mail-vc0-f176.google.com [209.85.220.176]) by mx.google.com with ESMTPS id sc7si353821vdc.139.2014.04.08.05.20.47 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 08 Apr 2014 05:20:47 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.220.176 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.176; Received: by mail-vc0-f176.google.com with SMTP id lc6so651580vcb.7 for ; Tue, 08 Apr 2014 05:20:47 -0700 (PDT) X-Received: by 10.52.119.197 with SMTP id kw5mr2493534vdb.5.1396959647255; Tue, 08 Apr 2014 05:20:47 -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 v8csp240710vcv; Tue, 8 Apr 2014 05:20:46 -0700 (PDT) X-Received: by 10.68.135.195 with SMTP id pu3mr4307947pbb.70.1396959643971; Tue, 08 Apr 2014 05:20:43 -0700 (PDT) Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTP id fd9si990444pad.224.2014.04.08.05.20.43 for ; Tue, 08 Apr 2014 05:20:43 -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 A41976E9EB; Tue, 8 Apr 2014 05:20:42 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-we0-f169.google.com (mail-we0-f169.google.com [74.125.82.169]) by gabe.freedesktop.org (Postfix) with ESMTP id 1AA3D6E9F7 for ; Tue, 8 Apr 2014 05:20:38 -0700 (PDT) Received: by mail-we0-f169.google.com with SMTP id w62so860760wes.14 for ; Tue, 08 Apr 2014 05:20:38 -0700 (PDT) X-Received: by 10.194.173.193 with SMTP id bm1mr3451901wjc.55.1396959638212; Tue, 08 Apr 2014 05:20:38 -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.36 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 08 Apr 2014 05:20:37 -0700 (PDT) From: Benjamin Gaignard To: dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org Subject: [PATCH v1 09/19] drm: sti: add GDP layer Date: Tue, 8 Apr 2014 14:19:16 +0200 Message-Id: <1396959566-2960-10-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.176 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 Generic Display Pipeline are one of the compositor input sub-devices. GDP are dedicated to graphic input like RGB plans. Signed-off-by: Benjamin Gaignard Signed-off-by: Vincent Abriou Signed-off-by: Fabien Dessenne --- drivers/gpu/drm/sti/Makefile | 1 + drivers/gpu/drm/sti/sti_gdp.c | 491 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_gdp.h | 73 ++++++ drivers/gpu/drm/sti/sti_layer.h | 5 + drivers/gpu/drm/sti/sti_vtg.c | 14 +- drivers/gpu/drm/sti/sti_vtg_utils.h | 3 +- 6 files changed, 583 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/sti/sti_gdp.c create mode 100644 drivers/gpu/drm/sti/sti_gdp.h diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 447eccf..3d1ae3e 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -1,6 +1,7 @@ ccflags-y := -Iinclude/drm stidrm-y := \ + sti_gdp.o \ sti_tvout.o \ sti_hdmi.o \ sti_hdmi_tx3g0c55phy.o \ diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c new file mode 100644 index 0000000..00ff7f9 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include + +#include "sti_layer.h" +#include "sti_gdp.h" +#include "sti_vtg_utils.h" + +#define ENA_COLOR_FILL (1 << 8) +#define WAIT_NEXT_VSYNC (1 << 31) + +/* GDP color formats */ +#define GDP_RGB565 0x00 +#define GDP_RGB888 0x01 +#define GDP_RGB888_32 0x02 +#define GDP_ARGB8565 0x04 +#define GDP_ARGB8888 0x05 +#define GDP_ARGB1555 0x06 +#define GDP_ARGB4444 0x07 +#define GDP_CLUT8 0x0B +#define GDP_YCBR888 0x10 +#define GDP_YCBR422R 0x12 +#define GDP_AYCBR8888 0x15 + +#define GAM_GDP_CTL_OFFSET 0x00 +#define GAM_GDP_AGC_OFFSET 0x04 +#define GAM_GDP_VPO_OFFSET 0x0C +#define GAM_GDP_VPS_OFFSET 0x10 +#define GAM_GDP_PML_OFFSET 0x14 +#define GAM_GDP_PMP_OFFSET 0x18 +#define GAM_GDP_SIZE_OFFSET 0x1C +#define GAM_GDP_NVN_OFFSET 0x24 +#define GAM_GDP_KEY1_OFFSET 0x28 +#define GAM_GDP_KEY2_OFFSET 0x2C +#define GAM_GDP_PPT_OFFSET 0x34 +#define GAM_GDP_CML_OFFSET 0x3C +#define GAM_GDP_MST_OFFSET 0x68 + +#define GAM_GDP_ALPHARANGE_255 (1 << 5) +#define GAM_GDP_AGC_FULL_RANGE 0x00808080 +#define GAM_GDP_PPT_IGNORE ((1 << 1) | (1 << 0)) +#define GAM_GDP_SIZE_MAX 0x7FF + +static const uint32_t gdp_supported_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGB888, + DRM_FORMAT_AYUV, + DRM_FORMAT_YUV444, + DRM_FORMAT_VYUY, + DRM_FORMAT_C8, +}; + +static const uint32_t *sti_gdp_get_formats(void) +{ + return gdp_supported_formats; +} + +static int sti_gdp_get_nb_formats(void) +{ + return ARRAY_SIZE(gdp_supported_formats); +} + +static int sti_gdp_fourcc2format(int fourcc) +{ + switch (fourcc) { + case DRM_FORMAT_XRGB8888: + return GDP_RGB888_32; + case DRM_FORMAT_ARGB8888: + return GDP_ARGB8888; + case DRM_FORMAT_ARGB4444: + return GDP_ARGB4444; + case DRM_FORMAT_ARGB1555: + return GDP_ARGB1555; + case DRM_FORMAT_RGB565: + return GDP_RGB565; + case DRM_FORMAT_RGB888: + return GDP_RGB888; + case DRM_FORMAT_AYUV: + return GDP_AYCBR8888; + case DRM_FORMAT_YUV444: + return GDP_YCBR888; + case DRM_FORMAT_VYUY: + return GDP_YCBR422R; + case DRM_FORMAT_C8: + return GDP_CLUT8; + } + return -1; +} + +static int sti_gdp_get_alpharange(int format) +{ + switch (format) { + case GDP_ARGB8565: + case GDP_ARGB8888: + case GDP_AYCBR8888: + return GAM_GDP_ALPHARANGE_255; + } + return 0; +} + +/** + * sti_gdp_get_free_nodes + * @layer: gdp layer + * + * Look for a GDP node list that is not currently read by the HW. + * + * RETURNS: + * Pointer to the free GDP node list + */ +static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer) +{ + int hw_nvn; + void *virt_nvn; + struct sti_gdp *gdp = layer->gdp; + int i; + + hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); + if (!hw_nvn) + goto end; + + virt_nvn = dma_to_virt(gdp->dev, (dma_addr_t) hw_nvn); + + for (i = 0; i < GDP_NODE_NB_BANK; i++) + if ((virt_nvn != gdp->node_list[i].btm_field) && + (virt_nvn != gdp->node_list[i].top_field)) + return &gdp->node_list[i]; + +end: + return &gdp->node_list[0]; +} + +/** + * sti_gdp_get_current_nodes + * @layer: GDP layer + * + * Look for GDP nodes that are currently read by the HW. + * + * RETURNS: + * Pointer to the current GDP node list + */ +static +struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer) +{ + int hw_nvn; + void *virt_nvn; + struct sti_gdp *gdp = layer->gdp; + int i; + + hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); + if (!hw_nvn) + goto end; + + virt_nvn = dma_to_virt(gdp->dev, (dma_addr_t) hw_nvn); + + for (i = 0; i < GDP_NODE_NB_BANK; i++) + if ((virt_nvn == gdp->node_list[i].btm_field) || + (virt_nvn == gdp->node_list[i].top_field)) + return &gdp->node_list[i]; + +end: + return NULL; +} + +/** + * sti_gdp_prepare_layer + * @lay: gdp layer + * @first_prepare: true if it is the first time this function is called + * + * Update the free GDP node list according to the layer properties. + * + * RETURNS: + * 0 on success. + */ +static int sti_gdp_prepare_layer(void *lay, bool first_prepare) +{ + struct sti_layer *layer = (struct sti_layer *)lay; + struct sti_gdp_node_list *list; + struct sti_gdp_node *top_field, *btm_field; + struct drm_display_mode *mode = layer->mode; + struct device *dev = layer->gdp->dev; + int format, depth, bpp; + int rate = mode->clock * 1000; + int res; + u32 ydo, xdo, yds, xds; + + list = sti_gdp_get_free_nodes(layer); + top_field = list->top_field; + btm_field = list->btm_field; + + /* Build the top field from layer params */ + top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; + top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; + format = sti_gdp_fourcc2format(layer->format); + if (format == -1) { + DRM_ERROR("Format not supported by GDP %.4s\n", + (char *)&layer->format); + return 1; + } + top_field->gam_gdp_ctl |= format; + top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); + top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; + + /* pixel memory location */ + drm_fb_get_bpp_depth(layer->format, &depth, &bpp); + top_field->gam_gdp_pml = (u32) layer->paddr + layer->offsets[0]; + top_field->gam_gdp_pml += layer->src_x * (bpp >> 3); + top_field->gam_gdp_pml += layer->src_y * layer->pitches[0]; + + /* input parameters */ + top_field->gam_gdp_pmp = layer->pitches[0]; + top_field->gam_gdp_size = + clamp_val(layer->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | + clamp_val(layer->src_w, 0, GAM_GDP_SIZE_MAX); + + /* output parameters */ + ydo = sti_vtg_get_line_number(*mode, layer->dst_y); + yds = sti_vtg_get_line_number(*mode, layer->dst_y + layer->dst_h - 1); + xdo = sti_vtg_get_pixel_number(*mode, layer->dst_x); + xds = sti_vtg_get_pixel_number(*mode, layer->dst_x + layer->dst_w - 1); + top_field->gam_gdp_vpo = (ydo << 16) | xdo; + top_field->gam_gdp_vps = (yds << 16) | xds; + + /* Same content and chained together */ + memcpy(btm_field, top_field, sizeof(*btm_field)); + top_field->gam_gdp_nvn = virt_to_dma(dev, btm_field); + btm_field->gam_gdp_nvn = virt_to_dma(dev, top_field); + + /* Interlaced mode */ + if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) + btm_field->gam_gdp_pml = top_field->gam_gdp_pml + + layer->pitches[0]; + + if (first_prepare) { + /* Register gdp callback */ + if (sti_vtg_register_client(layer->mixer_id, + &layer->gdp->vtg_field_nb)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return 1; + } + + /* Set and enable gdp clock */ + if (layer->gdp->clk_pix) { + res = clk_set_rate(layer->gdp->clk_pix, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for gdp\n", + rate); + return 1; + } + + if (clk_prepare_enable(layer->gdp->clk_pix)) { + DRM_ERROR("Failed to prepare/enable gdp\n"); + return 1; + } + } + } + + return 0; +} + +/** + * sti_gdp_commit_layer + * @lay: gdp layer + * + * Update the NVN field of the 'right' field of the current GDP node (being + * used by the HW) with the address of the updated ('free') top field GDP node. + * - In interlaced mode the 'right' field is the bottom field as we update + * frames starting from their top field + * - In progressive mode, we update both bottom and top fields which are + * equal nodes. + * At the next VSYNC, the updated node list will be used by the HW. + * + * RETURNS: + * 0 on success. + */ +static int sti_gdp_commit_layer(void *lay) +{ + struct sti_layer *layer = (struct sti_layer *)lay; + struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(layer); + struct sti_gdp_node *updated_top_node = updated_list->top_field; + struct sti_gdp_node *updated_btm_node = updated_list->btm_field; + struct sti_gdp *gdp = layer->gdp; + u32 dma_updated_top = virt_to_dma(gdp->dev, updated_top_node); + u32 dma_updated_btm = virt_to_dma(gdp->dev, updated_btm_node); + struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer); + + dev_dbg(gdp->dev, "Current NVN:0x%X\n", + readl(gdp->regs + GAM_GDP_NVN_OFFSET)); + dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", + (unsigned long)layer->paddr, + readl(gdp->regs + GAM_GDP_PML_OFFSET)); + + if (curr_list == NULL) { + /* First update or invalid node should directly write in the + * hw register */ + writel(gdp->is_curr_top == true ? + dma_updated_btm : dma_updated_top, + gdp->regs + GAM_GDP_NVN_OFFSET); + return 0; + } + + if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) { + if (gdp->is_curr_top == true) { + /* Do not update in the middle of the frame, but + * postpone the update after the bottom field has + * been displayed */ + curr_list->btm_field->gam_gdp_nvn = dma_updated_top; + } else { + /* Direct update to avoid one frame delay */ + writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); + } + } else { + /* Direct update for progressive to avoid one frame delay */ + writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); + } + + return 0; +} + +/** + * sti_gdp_disable_layer + * @lay: gdp layer + * + * Disable a GDP. + * + * RETURNS: + * 0 on success. + */ +static int sti_gdp_disable_layer(void *lay) +{ + int i; + struct sti_layer *layer = (struct sti_layer *)lay; + struct sti_gdp *gdp = layer->gdp; + + /* Set the nodes as 'to be ignored on mixer' */ + for (i = 0; i < GDP_NODE_NB_BANK; i++) { + gdp->node_list[i].top_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; + gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; + } + + if (sti_vtg_unregister_client(layer->mixer_id, &gdp->vtg_field_nb)) + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); + + if (gdp->clk_pix) + clk_disable_unprepare(gdp->clk_pix); + + return 0; +} + +/** + * sti_gdp_field_cb + * @nb: notifier block + * @event: event message + * @data: private data + * + * Handle VTG top field and bottom field event. + * + * RETURNS: + * 0 on success. + */ +int sti_gdp_field_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); + + switch (event) { + case VTG_TOP_FIELD_EVENT: + gdp->is_curr_top = true; + break; + case VTG_BOTTOM_FIELD_EVENT: + gdp->is_curr_top = false; + break; + default: + DRM_ERROR("unsupported event: %lu\n", event); + break; + } + + return 0; +} + +/** + * sti_gdp_create + * @dev: device + * @id: gdp id + * @baseaddr: IO addr + * + * Create a gdp object. Allocate memory and initialize parameters. + * + * + * RETURNS: + * Pointer to the created gdp object. + */ +struct sti_gdp *sti_gdp_create(struct device *dev, int id, + void __iomem *baseaddr) +{ + struct sti_gdp *gdp; + struct device_node *np = dev->of_node; + dma_addr_t dma; + void *base; + int i, size; + + gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); + if (!gdp) { + DRM_ERROR("Failed to allocate memory for GDP\n"); + return NULL; + } + + /* Allocate all the nodes within a single memory page */ + size = sizeof(struct sti_gdp_node) * + GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK; + + base = dma_alloc_writecombine(dev, size, &dma, GFP_KERNEL | GFP_DMA); + if (!base) { + DRM_ERROR("Failed to allocate memory for GDP node\n"); + goto mem_err; + } + memset(base, 0, size); + + for (i = 0; i < GDP_NODE_NB_BANK; i++) { + if (virt_to_dma(dev, base) & 0xF) { + DRM_ERROR("Mem alignment failed\n"); + goto mem_err; + } + gdp->node_list[i].top_field = base; + DRM_DEBUG_DRIVER("node[%d].top_field=%p\n", i, base); + base += sizeof(struct sti_gdp_node); + + if (virt_to_dma(dev, base) & 0xF) { + DRM_ERROR("Mem alignment failed\n"); + goto mem_err; + } + gdp->node_list[i].btm_field = base; + DRM_DEBUG_DRIVER("node[%d].btm_field=%p\n", i, base); + base += sizeof(struct sti_gdp_node); + } + + gdp->dev = dev; + gdp->regs = baseaddr; + gdp->get_formats = sti_gdp_get_formats; + gdp->get_nb_formats = sti_gdp_get_nb_formats; + gdp->prepare = sti_gdp_prepare_layer; + gdp->commit = sti_gdp_commit_layer; + gdp->disable = sti_gdp_disable_layer; + gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; + + if (of_device_is_compatible(np, "st,stih407-compositor")) { + /* GDP of STiH407 chip have its own pixel clock */ + char *clk_name; + + switch (id) { + case STI_GDP_0: + clk_name = "pix_gdp1"; + break; + case STI_GDP_1: + clk_name = "pix_gdp2"; + break; + case STI_GDP_2: + clk_name = "pix_gdp3"; + break; + case STI_GDP_3: + clk_name = "pix_gdp4"; + break; + default: + DRM_ERROR("GDP id not recognized\n"); + goto err_clk_pix_gdp; + } + + gdp->clk_pix = devm_clk_get(dev, clk_name); + if (IS_ERR(gdp->clk_pix)) { + DRM_ERROR("Cannot get %s clock\n", clk_name); + goto err_clk_pix_gdp; + } + } + + return gdp; + +err_clk_pix_gdp: +mem_err: + devm_kfree(dev, gdp); + return NULL; +} diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h new file mode 100644 index 0000000..4f7f40b --- /dev/null +++ b/drivers/gpu/drm/sti/sti_gdp.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) STMicroelectronics SA 2013 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_GDP_H_ +#define _STI_GDP_H_ + +#include + +#define GDP_NODE_NB_BANK 2 +#define GDP_NODE_PER_FIELD 2 + +struct sti_gdp_node { + u32 gam_gdp_ctl; + u32 gam_gdp_agc; + u32 reserved1; + u32 gam_gdp_vpo; + u32 gam_gdp_vps; + u32 gam_gdp_pml; + u32 gam_gdp_pmp; + u32 gam_gdp_size; + u32 reserved2; + u32 gam_gdp_nvn; + u32 gam_gdp_key1; + u32 gam_gdp_key2; + u32 reserved3; + u32 gam_gdp_ppt; + u32 reserved4; + u32 gam_gdp_cml; +}; + +struct sti_gdp_node_list { + struct sti_gdp_node *top_field; + struct sti_gdp_node *btm_field; +}; + +/* + * STI GDP structure + * + * @device: driver device + * @regs: subdevice register + * @clk_pix: pixel clock for the current gdp + * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification + * @is_curr_top: true if the current node processed is the top field + * @get_formats: get GDP supported formats + * @get_nb_formats: get number of format supported + * @prepare: prepare GDP before rendering + * @commit: set GDP for rendering + * @disable: disable GDP + * @node_list: array of node list + */ +struct sti_gdp { + struct device *dev; + void __iomem *regs; + struct clk *clk_pix; + struct notifier_block vtg_field_nb; + bool is_curr_top; + const uint32_t* (*get_formats)(void); + int (*get_nb_formats)(void); + int (*prepare)(void *layer, bool first_prepare); + int (*commit)(void *layer); + int (*disable)(void *layer); + struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; +}; + +struct sti_gdp *sti_gdp_create(struct device *dev, int id, + void __iomem *baseaddr); + +#endif diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h index ed8386a..45cd1ea 100644 --- a/drivers/gpu/drm/sti/sti_layer.h +++ b/drivers/gpu/drm/sti/sti_layer.h @@ -10,6 +10,7 @@ #define _STI_LAYER_H_ #include +#include "sti_gdp.h" #define to_sti_layer(x) container_of(x, struct sti_layer, plane) @@ -67,6 +68,7 @@ struct sti_fps_info { * @offsets: offset of 'planes' * @paddr: physical address of the input buffer * @fps_info: frame per second info + * @gdp: related GDP (if the layer is a GDP) */ struct sti_layer { struct drm_plane plane; @@ -74,6 +76,7 @@ struct sti_layer { struct drm_display_mode *mode; enum sti_layer_desc desc; int zorder; + int mixer_id; bool enabled; int src_x, src_y; int src_w, src_h; @@ -84,12 +87,14 @@ struct sti_layer { int offsets[4]; dma_addr_t paddr; struct sti_fps_info fps_info; + struct sti_gdp *gdp; }; struct sti_layer *sti_layer_create(struct device *dev, int desc, void __iomem *baseaddr); int sti_layer_prepare(struct sti_layer *layer, 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, diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index d3514c1..d1ebe98 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -51,7 +51,10 @@ #define VTG_BOT_V_HD_3 0x0110 /* IRQ mask */ -#define VTG_IRQ_MASK ((1L<<1) | (1L<<0)) +#define VTG_IRQ_TOP_FIELD_MASK (1L << 1) +#define VTG_IRQ_BOTTOM_FIELD_MASK (1L << 0) +#define VTG_IRQ_MASK (VTG_IRQ_TOP_FIELD_MASK | \ + VTG_IRQ_BOTTOM_FIELD_MASK) /* Delay introduced by the AWG in nb of pixels */ #define AWG_DELAY_HD (-9) @@ -315,8 +318,13 @@ static irqreturn_t vtg_irq_thread(int irq, void *arg) /* sync bus write */ readl(regs + VTG_HOST_ITS); - raw_notifier_call_chain(&vtg->notifier_list, - VTG_VBLANK_EVENT, &vtg->type); + if (status & VTG_IRQ_TOP_FIELD_MASK) { + raw_notifier_call_chain(&vtg->notifier_list, + VTG_TOP_FIELD_EVENT, &vtg->type); + } else { + raw_notifier_call_chain(&vtg->notifier_list, + VTG_BOTTOM_FIELD_EVENT, &vtg->type); + } return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/sti/sti_vtg_utils.h b/drivers/gpu/drm/sti/sti_vtg_utils.h index 03d81ba..8992a04 100644 --- a/drivers/gpu/drm/sti/sti_vtg_utils.h +++ b/drivers/gpu/drm/sti/sti_vtg_utils.h @@ -14,7 +14,8 @@ #define VTG_MAIN 0 #define VTG_AUX 1 -#define VTG_VBLANK_EVENT 1 +#define VTG_TOP_FIELD_EVENT 1 +#define VTG_BOTTOM_FIELD_EVENT 2 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);