From patchwork Thu Nov 12 14:29:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 11900409 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01E9FC2D0A3 for ; Thu, 12 Nov 2020 14:29:36 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7907E2224B for ; Thu, 12 Nov 2020 14:29:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="zeYQGaCk" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7907E2224B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 82CD86E231; Thu, 12 Nov 2020 14:29:34 +0000 (UTC) Received: from mail-lf1-x142.google.com (mail-lf1-x142.google.com [IPv6:2a00:1450:4864:20::142]) by gabe.freedesktop.org (Postfix) with ESMTPS id 993FE6E231 for ; Thu, 12 Nov 2020 14:29:32 +0000 (UTC) Received: by mail-lf1-x142.google.com with SMTP id r9so8714424lfn.11 for ; Thu, 12 Nov 2020 06:29:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=m1ZZkgdRolUng3Hq596bCz1VgHevBtnaN/RxMVu/NJ0=; b=zeYQGaCkfRKlST5Cd3yVcDUXNuXEF4DTqo+QLCHAg/89DSinbV7hyWdFPDJtBytcYt 5/99vDt51t3uyovHkSEWGXOQBKAN2JDznAZeHObt0Kc0d/gBx52gxkOUQ6ydj+rs6N4P eXeocuPGyAFR0ZuQ5V03ZX0JYg8mFmuJ/AVVKrhgjTyf5VX2chcBt7XYhY6+ng+eOHuI b7uYQmOAxatSIImeao8FWeNCIgziuIbJ750NcuzQgjeo8pJXF17V/VqntQPHNXRKYDdQ 1GWJFceZHHkC66smfqN9fgVBpLhRKtUMxpsNNbvItKcjjlV6MZivHs82nKEhd1cFVA/C UCWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=m1ZZkgdRolUng3Hq596bCz1VgHevBtnaN/RxMVu/NJ0=; b=ixyS6zUxBPF+nwXdFbev65J1jVpQMudjq+nI/1ZjmV2YNpkSwraNHLbC4md7CW3bXo u58xDCFTNoUgExaMiODyg+bGkFVnAP7+/q1itv5hzfNRlqcX2PmalGM6rI4fR4dPkdBC gyz5LF35ED34fOoNOsFa8g0tBigPc8FeswifpPIyR91q+PBlFoONFXT4n2h/pnbmAl5Y 8v+Tgg1mPmg94aTp9qtbrJl4zUWIZZKNX0tAjHBm+u2xm9QtiZJWHmkSWjMpx/LA+aKW 8HBrTUUs6VJ+s+lLenSlMBA0+mGgeunCLChh2dlKJMuvIBVWDjlWo2OwgVACXsNJm7yQ eIvw== X-Gm-Message-State: AOAM531KrhwzbpN4IkBtNfgbIzl86pfREb3DYeu8bXj4bV8ZwrhnaP/B AahZxNgiI+A6SZbeTCWYQabIiSrdZ6SjOg== X-Google-Smtp-Source: ABdhPJwRG5K6waVOySwjA0m/u1JXvBb17oUD05ZeiByjVgs9+dUGDsm+VTMrxbDJpf5k2PXLbsOAXw== X-Received: by 2002:a19:7f8e:: with SMTP id a136mr12754104lfd.524.1605191370804; Thu, 12 Nov 2020 06:29:30 -0800 (PST) Received: from localhost.bredbandsbolaget (c-92d7225c.014-348-6c756e10.bbcust.telenor.se. [92.34.215.146]) by smtp.gmail.com with ESMTPSA id o21sm206956lfg.40.2020.11.12.06.29.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Nov 2020 06:29:30 -0800 (PST) From: Linus Walleij To: dri-devel@lists.freedesktop.org, Maarten Lankhorst , Maxime Ripard , Sean Paul Subject: [PATCH 1/2] drm/mcde: Break out DSI set-up routine Date: Thu, 12 Nov 2020 15:29:24 +0100 Message-Id: <20201112142925.2571179-1-linus.walleij@linaro.org> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, Stephan Gerhold , linux-arm-kernel@lists.infradead.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To be able to support DPI without messing things up we first break out the DSI set-up to a separate function. Cc: Stephan Gerhold Cc: phone-devel@vger.kernel.org Cc: upstreaming@lists.sr.ht Signed-off-by: Linus Walleij Acked-by: Sam Ravnborg --- drivers/gpu/drm/mcde/mcde_display.c | 135 +++++++++++++++------------- 1 file changed, 75 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index c271e5bf042e..66a07e340f8a 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -860,74 +860,44 @@ static int mcde_dsi_get_pkt_div(int ppl, int fifo_size) return 1; } -static void mcde_display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *cstate, - struct drm_plane_state *plane_state) +static void mcde_setup_dsi(struct mcde *mcde, const struct drm_display_mode *mode, + int cpp, int *fifo_wtrmrk_lvl, int *dsi_formatter_frame, + int *dsi_pkt_size) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_plane *plane = &pipe->plane; - struct drm_device *drm = crtc->dev; - struct mcde *mcde = to_mcde(drm); - const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; - u32 format = fb->format->format; u32 formatter_ppl = mode->hdisplay; /* pixels per line */ u32 formatter_lpf = mode->vdisplay; /* lines per frame */ - int pkt_size, fifo_wtrmrk; - int cpp = fb->format->cpp[0]; + int formatter_frame; int formatter_cpp; - struct drm_format_name_buf tmp; - u32 formatter_frame; + int fifo_wtrmrk; u32 pkt_div; + int pkt_size; u32 val; - int ret; - /* This powers up the entire MCDE block and the DSI hardware */ - ret = regulator_enable(mcde->epod); - if (ret) { - dev_err(drm->dev, "can't re-enable EPOD regulator\n"); - return; - } - - dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", - mode->hdisplay, mode->vdisplay, - drm_get_format_name(format, &tmp)); - if (!mcde->mdsi) { - /* TODO: deal with this for non-DSI output */ - dev_err(drm->dev, "no DSI master attached!\n"); - return; - } + dev_info(mcde->dev, "output in %s mode, format %dbpp\n", + (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? + "VIDEO" : "CMD", + mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format)); + formatter_cpp = + mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format) / 8; + dev_info(mcde->dev, "Overlay CPP: %d bytes, DSI formatter CPP %d bytes\n", + cpp, formatter_cpp); /* Set up the main control, watermark level at 7 */ val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; - /* 24 bits DPI: connect LSB Ch B to D[0:7] */ + + /* + * This is the internal silicon muxing of the DPI + * (parallell display) lines. Since we are not using + * this at all (we are using DSI) these are just + * dummy values from the vendor tree. + */ val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; - /* TV out: connect LSB Ch B to D[8:15] */ val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; - /* Don't care about this muxing */ val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; - /* 24 bits DPI: connect MID Ch B to D[24:31] */ val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; - /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */ val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; - /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */ writel(val, mcde->regs + MCDE_CONF0); - /* Clear any pending interrupts */ - mcde_display_disable_irqs(mcde); - writel(0, mcde->regs + MCDE_IMSCERR); - writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); - - dev_info(drm->dev, "output in %s mode, format %dbpp\n", - (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? - "VIDEO" : "CMD", - mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format)); - formatter_cpp = - mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format) / 8; - dev_info(drm->dev, "overlay CPP %d bytes, DSI CPP %d bytes\n", - cpp, - formatter_cpp); - /* Calculations from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */ /* @@ -948,9 +918,9 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, /* The FIFO is 640 entries deep on this v3 hardware */ pkt_div = mcde_dsi_get_pkt_div(mode->hdisplay, 640); } - dev_dbg(drm->dev, "FIFO watermark after flooring: %d bytes\n", + dev_dbg(mcde->dev, "FIFO watermark after flooring: %d bytes\n", fifo_wtrmrk); - dev_dbg(drm->dev, "Packet divisor: %d bytes\n", pkt_div); + dev_dbg(mcde->dev, "Packet divisor: %d bytes\n", pkt_div); /* NOTE: pkt_div is 1 for video mode */ pkt_size = (formatter_ppl * formatter_cpp) / pkt_div; @@ -958,16 +928,61 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, if (!(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)) pkt_size++; - dev_dbg(drm->dev, "DSI packet size: %d * %d bytes per line\n", + dev_dbg(mcde->dev, "DSI packet size: %d * %d bytes per line\n", pkt_size, pkt_div); - dev_dbg(drm->dev, "Overlay frame size: %u bytes\n", + dev_dbg(mcde->dev, "Overlay frame size: %u bytes\n", mode->hdisplay * mode->vdisplay * cpp); - mcde->stride = mode->hdisplay * cpp; - dev_dbg(drm->dev, "Overlay line stride: %u bytes\n", - mcde->stride); /* NOTE: pkt_div is 1 for video mode */ formatter_frame = pkt_size * pkt_div * formatter_lpf; - dev_dbg(drm->dev, "Formatter frame size: %u bytes\n", formatter_frame); + dev_dbg(mcde->dev, "Formatter frame size: %u bytes\n", formatter_frame); + + *fifo_wtrmrk_lvl = fifo_wtrmrk; + *dsi_pkt_size = pkt_size; + *dsi_formatter_frame = formatter_frame; +} + +static void mcde_display_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *cstate, + struct drm_plane_state *plane_state) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct drm_plane *plane = &pipe->plane; + struct drm_device *drm = crtc->dev; + struct mcde *mcde = to_mcde(drm); + const struct drm_display_mode *mode = &cstate->mode; + struct drm_framebuffer *fb = plane->state->fb; + u32 format = fb->format->format; + int dsi_pkt_size; + int fifo_wtrmrk; + int cpp = fb->format->cpp[0]; + struct drm_format_name_buf tmp; + u32 dsi_formatter_frame; + u32 val; + int ret; + + /* This powers up the entire MCDE block and the DSI hardware */ + ret = regulator_enable(mcde->epod); + if (ret) { + dev_err(drm->dev, "can't re-enable EPOD regulator\n"); + return; + } + + dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", + mode->hdisplay, mode->vdisplay, + drm_get_format_name(format, &tmp)); + + + /* Clear any pending interrupts */ + mcde_display_disable_irqs(mcde); + writel(0, mcde->regs + MCDE_IMSCERR); + writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); + + mcde_setup_dsi(mcde, mode, cpp, &fifo_wtrmrk, + &dsi_formatter_frame, &dsi_pkt_size); + + mcde->stride = mode->hdisplay * cpp; + dev_dbg(drm->dev, "Overlay line stride: %u bytes\n", + mcde->stride); /* Drain the FIFO A + channel 0 pipe so we have a clean slate */ mcde_drain_pipe(mcde, MCDE_FIFO_A, MCDE_CHANNEL_0); @@ -1011,7 +1026,7 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, /* Configure the DSI formatter 0 for the DSI panel output */ mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, - formatter_frame, pkt_size); + dsi_formatter_frame, dsi_pkt_size); switch (mcde->flow_mode) { case MCDE_COMMAND_TE_FLOW: From patchwork Thu Nov 12 14:29:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 11900411 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B369DC56202 for ; Thu, 12 Nov 2020 14:29:38 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3FB7F22249 for ; Thu, 12 Nov 2020 14:29:38 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="umwtQuw8" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3FB7F22249 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 4E1566E252; Thu, 12 Nov 2020 14:29:36 +0000 (UTC) Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by gabe.freedesktop.org (Postfix) with ESMTPS id E5D626E252 for ; Thu, 12 Nov 2020 14:29:34 +0000 (UTC) Received: by mail-lf1-x143.google.com with SMTP id f11so8739305lfs.3 for ; Thu, 12 Nov 2020 06:29:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=bO5P44QyzK94T1fLdOtO7VbJWKz59UThq9+6F6aJ7Tk=; b=umwtQuw8asE5Q3MHbQhm/LpJZmFhmPLehM76xpgJhdX6mP59VM7H5A6xwjUfrqdrBF 0MtHno95RdWaYT+xPD4nIapx5u9zjD+/xVtEAbXdx3tg8PwT92kIkzyjy986ZtNSkruw ZFzkyYjaDjJlIhPpHLAxbmGthMR55kfJS8VR8m7nWcnjAKBMEiabdD6gq4eF2Qx8QbzM gh4PLXIv/0Q54p7xYvUtBCjhmIL9uj1aXDwKLUxIoVxlUNm4/roaKFID4/PZbH5frOF4 hI/RuoUoy25DO8Kg4fUo7kn5/MTJTWSbLIoy/e5Myb743KZ17c2nIVvnyxgE9CbP4VPF xJpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=bO5P44QyzK94T1fLdOtO7VbJWKz59UThq9+6F6aJ7Tk=; b=qggk26Cbkj4xFePslYQHGyrFFA59MKDGvrGkY6sdZLxxzAURwH26iuHlJ/qdaCRyaT /iExOL9KLjpcOxskC7ZWNUQvi6zmcAwXA1m2RfXDzqfSGTbdqTXNkum3S88LNpGF+tEa X384Llas4gyvBu71mxQBfFtvauLF+h2hQQOkf83vyqfpbvuRWI8O+1pQH/tEpfeJ2YiV AMF3vAC93cAdVt3bIeheOp0MWbcLyFJ787gp1OYnTNi+p7u3bPbJ6LRJr2x5rAc1Swgb NydCo4gUsqBZk3plXNLAGtXfsvtt5+9gXZxnMRAvIGRYLV0ghdkT74yq8sW6zj3E447m bDJQ== X-Gm-Message-State: AOAM533WSbmhWlKudtaLnwjUFRzLfkyLO2ajjGWF5gtIKRtxKoUHv/w/ 5u5qOOEqAIOzIVOGZI7izv0vf2cB7gtEkQ== X-Google-Smtp-Source: ABdhPJyAL6jDdGOV34j9+zQ3mDCoz5iNfv89gDvASTzFrzGkuM0INYsT6VpDsQvjBnSXpFeVZACGSA== X-Received: by 2002:a19:c354:: with SMTP id t81mr10647348lff.283.1605191372801; Thu, 12 Nov 2020 06:29:32 -0800 (PST) Received: from localhost.bredbandsbolaget (c-92d7225c.014-348-6c756e10.bbcust.telenor.se. [92.34.215.146]) by smtp.gmail.com with ESMTPSA id o21sm206956lfg.40.2020.11.12.06.29.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Nov 2020 06:29:32 -0800 (PST) From: Linus Walleij To: dri-devel@lists.freedesktop.org, Maarten Lankhorst , Maxime Ripard , Sean Paul Subject: [PATCH 2/2] drm/mcde: Support DPI output Date: Thu, 12 Nov 2020 15:29:25 +0100 Message-Id: <20201112142925.2571179-2-linus.walleij@linaro.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20201112142925.2571179-1-linus.walleij@linaro.org> References: <20201112142925.2571179-1-linus.walleij@linaro.org> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: upstreaming@lists.sr.ht, phone-devel@vger.kernel.org, Stephan Gerhold , linux-arm-kernel@lists.infradead.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This implements support for DPI output using the port node in the device tree to connect a DPI LCD display to the MCDE. The block also supports TV-out but we leave that for another day when we have a hardware using it. We implement parsing and handling of the "port" node, and follow that to the DPI endpoint. The clock divider used by the MCDE to divide down the "lcdclk" (this has been designed for TV-like frequencies) is represented by an ordinary clock provider internally in the MCDE. This idea was inspired by the PL111 solution by Eric Anholt: the divider also works very similar to the Pl111 clock divider. We take care to clear up some errors regarding the number of available formatters and their type. We have 6 DSI formatters and 2 DPI formatters. Tested on the Samsung GT-I9070 Janice mobile phone. Cc: Stephan Gerhold Cc: phone-devel@vger.kernel.org Cc: upstreaming@lists.sr.ht Signed-off-by: Linus Walleij Acked-by: Sam Ravnborg --- drivers/gpu/drm/mcde/Kconfig | 1 + drivers/gpu/drm/mcde/Makefile | 2 +- drivers/gpu/drm/mcde/mcde_clk_div.c | 192 ++++++++++++++ drivers/gpu/drm/mcde/mcde_display.c | 304 ++++++++++++++++++++--- drivers/gpu/drm/mcde/mcde_display_regs.h | 87 +++++++ drivers/gpu/drm/mcde/mcde_drm.h | 10 + drivers/gpu/drm/mcde/mcde_drv.c | 46 +++- 7 files changed, 595 insertions(+), 47 deletions(-) create mode 100644 drivers/gpu/drm/mcde/mcde_clk_div.c diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig index b3990126562c..71c689b573c9 100644 --- a/drivers/gpu/drm/mcde/Kconfig +++ b/drivers/gpu/drm/mcde/Kconfig @@ -4,6 +4,7 @@ config DRM_MCDE depends on CMA depends on ARM || COMPILE_TEST depends on OF + depends on COMMON_CLK select MFD_SYSCON select DRM_MIPI_DSI select DRM_BRIDGE diff --git a/drivers/gpu/drm/mcde/Makefile b/drivers/gpu/drm/mcde/Makefile index fe28f4e0fe46..15d9c89a3273 100644 --- a/drivers/gpu/drm/mcde/Makefile +++ b/drivers/gpu/drm/mcde/Makefile @@ -1,3 +1,3 @@ -mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_display.o +mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_clk_div.o mcde_display.o obj-$(CONFIG_DRM_MCDE) += mcde_drm.o diff --git a/drivers/gpu/drm/mcde/mcde_clk_div.c b/drivers/gpu/drm/mcde/mcde_clk_div.c new file mode 100644 index 000000000000..038821d2ef80 --- /dev/null +++ b/drivers/gpu/drm/mcde/mcde_clk_div.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "mcde_drm.h" +#include "mcde_display_regs.h" + +/* The MCDE internal clock dividers for FIFO A and B */ +struct mcde_clk_div { + struct clk_hw hw; + struct mcde *mcde; + u32 cr; + u32 cr_div; +}; + +static int mcde_clk_div_enable(struct clk_hw *hw) +{ + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); + struct mcde *mcde = cdiv->mcde; + u32 val; + + spin_lock(&mcde->fifo_crx1_lock); + val = readl(mcde->regs + cdiv->cr); + /* + * Select the PLL72 (LCD) clock as parent + * FIXME: implement other parents. + */ + val &= ~MCDE_CRX1_CLKSEL_MASK; + val |= MCDE_CRX1_CLKSEL_CLKPLL72 << MCDE_CRX1_CLKSEL_SHIFT; + /* Internal clock */ + val |= MCDE_CRA1_CLKTYPE_TVXCLKSEL1; + + /* Clear then set the divider */ + val &= ~(MCDE_CRX1_BCD | MCDE_CRX1_PCD_MASK); + val |= cdiv->cr_div; + + writel(val, mcde->regs + cdiv->cr); + spin_unlock(&mcde->fifo_crx1_lock); + + return 0; +} + +static int mcde_clk_div_choose_div(struct clk_hw *hw, unsigned long rate, + unsigned long *prate, bool set_parent) +{ + int best_div = 1, div; + struct clk_hw *parent = clk_hw_get_parent(hw); + unsigned long best_prate = 0; + unsigned long best_diff = ~0ul; + int max_div = (1 << MCDE_CRX1_PCD_BITS) - 1; + + for (div = 1; div < max_div; div++) { + unsigned long this_prate, div_rate, diff; + + if (set_parent) + this_prate = clk_hw_round_rate(parent, rate * div); + else + this_prate = *prate; + div_rate = DIV_ROUND_UP_ULL(this_prate, div); + diff = abs(rate - div_rate); + + if (diff < best_diff) { + best_div = div; + best_diff = diff; + best_prate = this_prate; + } + } + + *prate = best_prate; + return best_div; +} + +static long mcde_clk_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int div = mcde_clk_div_choose_div(hw, rate, prate, true); + + return DIV_ROUND_UP_ULL(*prate, div); +} + +static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); + struct mcde *mcde = cdiv->mcde; + u32 cr; + int div; + + /* + * If the MCDE is not powered we can't access registers. + * It will come up with 0 in the divider register bits, which + * means "divide by 2". + */ + if (!regulator_is_enabled(mcde->epod)) + return DIV_ROUND_UP_ULL(prate, 2); + + cr = readl(mcde->regs + cdiv->cr); + if (cr & MCDE_CRX1_BCD) + return prate; + + /* 0 in the PCD means "divide by 2", 1 means "divide by 3" etc */ + div = cr & MCDE_CRX1_PCD_MASK; + div += 2; + + return DIV_ROUND_UP_ULL(prate, div); +} + +static int mcde_clk_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct mcde_clk_div *cdiv = container_of(hw, struct mcde_clk_div, hw); + int div = mcde_clk_div_choose_div(hw, rate, &prate, false); + u32 cr = 0; + + /* + * We cache the CR bits to set the divide in the state so that + * we can call this before we can even write to the hardware. + */ + if (div == 1) { + /* Bypass clock divider */ + cr |= MCDE_CRX1_BCD; + } else { + div -= 2; + cr |= div & MCDE_CRX1_PCD_MASK; + } + cdiv->cr_div = cr; + + return 0; +} + +static const struct clk_ops mcde_clk_div_ops = { + .enable = mcde_clk_div_enable, + .recalc_rate = mcde_clk_div_recalc_rate, + .round_rate = mcde_clk_div_round_rate, + .set_rate = mcde_clk_div_set_rate, +}; + +int mcde_init_clock_divider(struct mcde *mcde) +{ + struct device *dev = mcde->dev; + struct mcde_clk_div *fifoa; + struct mcde_clk_div *fifob; + const char *parent_name; + struct clk_init_data fifoa_init = { + .name = "fifoa", + .ops = &mcde_clk_div_ops, + .parent_names = &parent_name, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }; + struct clk_init_data fifob_init = { + .name = "fifob", + .ops = &mcde_clk_div_ops, + .parent_names = &parent_name, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }; + int ret; + + spin_lock_init(&mcde->fifo_crx1_lock); + parent_name = __clk_get_name(mcde->lcd_clk); + + /* Allocate 2 clocks */ + fifoa = devm_kzalloc(dev, sizeof(*fifoa), GFP_KERNEL); + if (!fifoa) + return -ENOMEM; + fifob = devm_kzalloc(dev, sizeof(*fifob), GFP_KERNEL); + if (!fifob) + return -ENOMEM; + + fifoa->mcde = mcde; + fifoa->cr = MCDE_CRA1; + fifoa->hw.init = &fifoa_init; + ret = devm_clk_hw_register(dev, &fifoa->hw); + if (ret) { + dev_err(dev, "error registering FIFO A clock divider\n"); + return ret; + } + mcde->fifoa_clk = fifoa->hw.clk; + + fifob->mcde = mcde; + fifob->cr = MCDE_CRB1; + fifob->hw.init = &fifob_init; + ret = devm_clk_hw_register(dev, &fifob->hw); + if (ret) { + dev_err(dev, "error registering FIFO B clock divider\n"); + return ret; + } + mcde->fifob_clk = fifob->hw.clk; + + return 0; +} diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index 66a07e340f8a..14c76d3a8e5a 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include