Received: by 2002:a05:6a11:4021:0:0:0:0 with SMTP id ky33csp3181574pxb; Sun, 26 Sep 2021 07:33:56 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy6hHjxysYKP4c38Kk/xGRG9q0LiJU8OmDnpcnjNbCFCB6/oCuhZLTnBQxf0SwE+8SF4ceb X-Received: by 2002:a50:e10d:: with SMTP id h13mr17774099edl.77.1632666836544; Sun, 26 Sep 2021 07:33:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1632666836; cv=none; d=google.com; s=arc-20160816; b=XdNAiMYePh40ZZWlN/E13ntIyomYWSFZH/piIO6U8evjZrv43ujv45sq3ePShmJrXy MqFSzgsqFFq1+aWuBbhw9uxufgr3nl1fSghxDU8CmAl7lSAi2UxfAb6BsQr7Fc4irFrc KCm7f8/46vJkQvPEPWnhBeFmh/XEJ9d6sA6eOY3TmGFWRaV4Q5aDE/6mmATkZzfDRleM Bp4PW3pubIwN49EPha4txwwU0RCAkeg/GPEC0d/vR8xJBR5QqQovV7utd02GIY+Juaqw AJVLxLnQioQ556UGStfFIzVrlDHtIkB4t5BniiYk8EH4RmIa1f4eLfofRPtq9xbrt43R E8GQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:cc:to:subject :message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=ZateHcMKRw5vqXICpo3Ff3SedPwpZGpT3o51Meadjgs=; b=ZgRSBuEfAgr4CmTe34liJWRrPVZcM9O5bHZ1OfsCd0LV4LCCCz7ztL0ANSndx+3VxR X7YWva6Er58l4JPpiK9mJjB/JdB2s0pjv0wbN9lFgzUe1yliYiYhxhLsvjlHQJmYUJlD f7zIeKO4IT0a0532oh5rHp34twGFTruYxIEhevtNvJlxRvsyp586FdNza6E7hXEERe2R Ey2YUkVI/qPjvSoZjSsXNIFf69E+upeYWFX9ORVv2zKFt+FxQhqV1D06n8p/3R/K4c0r ZIrnlNcfhY8tAz/FWFi4mrlfAo6USQWaaXuPVRMxHfdjdDJVjBXv2T8Qu6X1bBQzM0OF TnWQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Y829O3qF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id r8si15168498edb.185.2021.09.26.07.33.31; Sun, 26 Sep 2021 07:33:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Y829O3qF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231845AbhIZOdp (ORCPT + 99 others); Sun, 26 Sep 2021 10:33:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49456 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231743AbhIZOdo (ORCPT ); Sun, 26 Sep 2021 10:33:44 -0400 Received: from mail-lf1-x134.google.com (mail-lf1-x134.google.com [IPv6:2a00:1450:4864:20::134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A2F13C061570; Sun, 26 Sep 2021 07:32:07 -0700 (PDT) Received: by mail-lf1-x134.google.com with SMTP id i25so64890356lfg.6; Sun, 26 Sep 2021 07:32:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=ZateHcMKRw5vqXICpo3Ff3SedPwpZGpT3o51Meadjgs=; b=Y829O3qFz7Oz8aABOqZpuF+hcTgaTkskCqNIYdk/0r0xT9n9xpqTmQxFbXagEBtsHe SLSemwjlriV7ZcPeEb9q0ya8UFfCmuON0QoWhL5HWAvcQe+sSjTkMRTRyY9cvqF+OqqF SD5S+JQ3A38oaEjj/7kuV1VsTIgkR2Qvth+NKxUOKYC+b6CIge1mZLSNZWa9fKXw5KSp kWFf8B6OlEW8QAqJoSVNwz8xLCR509nJN+Jw7u7uthXAmKjnAfNK8D5mxAs9/S0K57TL bjjJpdI+FHMScqJj1ltg83mdJdiQ6WbFQL4FbLaGztVVJtxGFtJIAl4tNu59Z8+2D05Y 64LQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=ZateHcMKRw5vqXICpo3Ff3SedPwpZGpT3o51Meadjgs=; b=Kqo0Vljszd37dIRGBbkgf1ztPZs826IuqoJtxTqc6ni73mO4X683Glu2qlEIAeu3fJ IKFeQ4jht13bg4mBXYKh3VauneNAzTDNfZSndgowIczh8jebhm1SWo0g0nHoEWfK7IiJ K4jiWYN2GweKKlhr/TORS+JsEQmgIgpna8AQ9MFKxs0lIyu1ZOeHdx3LaVPTHHfpNHRh vEn/9hHMIeFeuj8IuAYKkS1Jm6iFXQ7gzzjKW5FB1IiviIu6cy3r0pgbT9+OS/3iosVT gRxEe68U9D112hNeEd+FUEMVS5Yml30sEgIz3tHwSUaXTx3ce4cdAY5OI345NTW2AYmp 2RLw== X-Gm-Message-State: AOAM532c6gYujmoK5XyttF98UL3bnJFDyM7tZ6ReVAmmjt7Zyr1vuijG KAEpyDChZKz9fVTKb07UCJrYZlNT8PWp1g2BUpw= X-Received: by 2002:a2e:8616:: with SMTP id a22mr22724128lji.365.1632666725650; Sun, 26 Sep 2021 07:32:05 -0700 (PDT) MIME-Version: 1.0 References: <20210813145302.3933-1-kevin3.tang@gmail.com> <20210813145302.3933-7-kevin3.tang@gmail.com> <20210917154047.leojvqjqjj2sg34l@gilmour> In-Reply-To: <20210917154047.leojvqjqjj2sg34l@gilmour> From: Kevin Tang Date: Sun, 26 Sep 2021 22:31:53 +0800 Message-ID: Subject: Re: [PATCH v6 6/6] drm/sprd: add Unisoc's drm mipi dsi&dphy driver To: Maxime Ripard Cc: Maarten Lankhorst , Sean Paul , David Airlie , Daniel Vetter , Rob Herring , Mark Rutland , pony1.wu@gmail.com, Orson Zhai , Chunyan Zhang , "Linux-Kernel@Vger. Kernel. Org" , ML dri-devel , devicetree@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Maxime Ripard =E4=BA=8E2021=E5=B9=B49=E6=9C=8817=E6=97= =A5=E5=91=A8=E4=BA=94 =E4=B8=8B=E5=8D=8811:40=E5=86=99=E9=81=93=EF=BC=9A > > On Fri, Aug 13, 2021 at 10:53:02PM +0800, Kevin Tang wrote: > > Adds dsi host controller support for the Unisoc's display subsystem. > > Adds dsi phy support for the Unisoc's display subsystem. > > Only MIPI DSI Displays supported, DP/TV/HMDI will be support > > in the feature. > > > > v1: > > - Remove dphy and dsi graph binding, merge the dphy driver into the d= si. > > > > v2: > > - Use drm_xxx to replace all DRM_XXX. > > - Use kzalloc to replace devm_kzalloc for sprd_dsi structure init. > > > > v4: > > - Use drmm_helpers to allocate encoder. > > - Move allocate encoder and connector to bind function. > > > > v5: > > - Drop the dsi ip file prefix. > > - Fix the checkpatch warnings. > > - Add Signed-off-by for dsi&dphy patch. > > - Use the mode_flags of mipi_dsi_device to setup crtc DPI and EDPI mo= de. > > > > v6: > > - Redesign the way to access the dsi register. > > - Reduce the dsi_context member variables. > > --- > > drivers/gpu/drm/sprd/Kconfig | 1 + > > drivers/gpu/drm/sprd/Makefile | 4 +- > > drivers/gpu/drm/sprd/megacores_pll.c | 317 +++++++ > > drivers/gpu/drm/sprd/megacores_pll.h | 146 +++ > > drivers/gpu/drm/sprd/sprd_dpu.c | 17 + > > drivers/gpu/drm/sprd/sprd_drm.c | 1 + > > drivers/gpu/drm/sprd/sprd_drm.h | 1 + > > drivers/gpu/drm/sprd/sprd_dsi.c | 1260 ++++++++++++++++++++++++++ > > drivers/gpu/drm/sprd/sprd_dsi.h | 94 ++ > > 9 files changed, 1840 insertions(+), 1 deletion(-) > > create mode 100644 drivers/gpu/drm/sprd/megacores_pll.c > > create mode 100644 drivers/gpu/drm/sprd/megacores_pll.h > > create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.c > > create mode 100644 drivers/gpu/drm/sprd/sprd_dsi.h > > > > diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfi= g > > index 37762c333..3edeaeca0 100644 > > --- a/drivers/gpu/drm/sprd/Kconfig > > +++ b/drivers/gpu/drm/sprd/Kconfig > > @@ -5,6 +5,7 @@ config DRM_SPRD > > select DRM_GEM_CMA_HELPER > > select DRM_KMS_CMA_HELPER > > select DRM_KMS_HELPER > > + select DRM_MIPI_DSI > > select VIDEOMODE_HELPERS > > help > > Choose this option if you have a Unisoc chipset. > > diff --git a/drivers/gpu/drm/sprd/Makefile b/drivers/gpu/drm/sprd/Makef= ile > > index ab12b95e6..73f96c459 100644 > > --- a/drivers/gpu/drm/sprd/Makefile > > +++ b/drivers/gpu/drm/sprd/Makefile > > @@ -1,4 +1,6 @@ > > # SPDX-License-Identifier: GPL-2.0 > > > > obj-y :=3D sprd_drm.o \ > > - sprd_dpu.o > > + sprd_dpu.o \ > > + sprd_dsi.o \ > > + megacores_pll.o > > diff --git a/drivers/gpu/drm/sprd/megacores_pll.c b/drivers/gpu/drm/spr= d/megacores_pll.c > > new file mode 100644 > > index 000000000..0dfd3c372 > > --- /dev/null > > +++ b/drivers/gpu/drm/sprd/megacores_pll.c > > @@ -0,0 +1,317 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2020 Unisoc Inc. > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "megacores_pll.h" > > + > > +#define L 0 > > +#define H 1 > > +#define CLK 0 > > +#define DATA 1 > > +#define INFINITY 0xffffffff > > +#define MIN_OUTPUT_FREQ (100) > > + > > +#define AVERAGE(a, b) (min(a, b) + abs((b) - (a)) / 2) > > + > > +/* sharkle */ > > +#define VCO_BAND_LOW 750 > > +#define VCO_BAND_MID 1100 > > +#define VCO_BAND_HIGH 1500 > > +#define PHY_REF_CLK 26000 > > + > > +static int dphy_calc_pll_param(struct dphy_pll *pll) > > +{ > > + const u32 khz =3D 1000; > > + const u32 mhz =3D 1000000; > > + const unsigned long long factor =3D 100; > > + unsigned long long tmp; > > + int i; > > + > > + pll->potential_fvco =3D pll->freq / khz; > > + pll->ref_clk =3D PHY_REF_CLK / khz; > > + > > + for (i =3D 0; i < 4; ++i) { > > + if (pll->potential_fvco >=3D VCO_BAND_LOW && > > + pll->potential_fvco <=3D VCO_BAND_HIGH) { > > + pll->fvco =3D pll->potential_fvco; > > + pll->out_sel =3D BIT(i); > > + break; > > + } > > + pll->potential_fvco <<=3D 1; > > + } > > + if (pll->fvco =3D=3D 0) > > + return -EINVAL; > > + > > + if (pll->fvco >=3D VCO_BAND_LOW && pll->fvco <=3D VCO_BAND_MID) { > > + /* vco band control */ > > + pll->vco_band =3D 0x0; > > + /* low pass filter control */ > > + pll->lpf_sel =3D 1; > > + } else if (pll->fvco > VCO_BAND_MID && pll->fvco <=3D VCO_BAND_HI= GH) { > > + pll->vco_band =3D 0x1; > > + pll->lpf_sel =3D 0; > > + } else > > + return -EINVAL; > > This doesn't follow the kernel coding style, make sure all the issues > with checkpatch.pl --strict are fixed. Here I should have used checkpatch to check, maybe the --strict parameter was not added, i will check it again. > > > + > > + pll->nint =3D pll->fvco / pll->ref_clk; > > + tmp =3D pll->fvco * factor * mhz; > > + do_div(tmp, pll->ref_clk); > > + tmp =3D tmp - pll->nint * factor * mhz; > > + tmp *=3D BIT(20); > > + do_div(tmp, 100000000); > > + pll->kint =3D (u32)tmp; > > + pll->refin =3D 3; /* pre-divider bypass */ > > + pll->sdm_en =3D true; /* use fraction N PLL */ > > + pll->fdk_s =3D 0x1; /* fraction */ > > + pll->cp_s =3D 0x0; > > + pll->det_delay =3D 0x1; > > + > > + return 0; > > +} > > + > > +static void dphy_set_pll_reg(struct dphy_pll *pll, struct regmap *regm= ap) > > +{ > > + struct pll_reg *reg =3D &pll->reg; > > + u8 *val; > > + int i; > > + > > + u8 reg_addr[] =3D { > > + 0x03, 0x04, 0x06, 0x08, 0x09, > > + 0x0a, 0x0b, 0x0e, 0x0f > > + }; > > + > > + reg->_03.bits.prbs_bist =3D 1; > > + reg->_03.bits.en_lp_treot =3D true; > > + reg->_03.bits.lpf_sel =3D pll->lpf_sel; > > + reg->_03.bits.txfifo_bypass =3D 0; > > + reg->_04.bits.div =3D pll->div; > > + reg->_04.bits.masterof8lane =3D 1; > > + reg->_04.bits.cp_s =3D pll->cp_s; > > + reg->_04.bits.fdk_s =3D pll->fdk_s; > > + reg->_06.bits.nint =3D pll->nint; > > + reg->_08.bits.vco_band =3D pll->vco_band; > > + reg->_08.bits.sdm_en =3D pll->sdm_en; > > + reg->_08.bits.refin =3D pll->refin; > > + reg->_09.bits.kint_h =3D pll->kint >> 12; > > + reg->_0a.bits.kint_m =3D (pll->kint >> 4) & 0xff; > > + reg->_0b.bits.out_sel =3D pll->out_sel; > > + reg->_0b.bits.kint_l =3D pll->kint & 0xf; > > + reg->_0e.bits.pll_pu_byp =3D 0; > > + reg->_0e.bits.pll_pu =3D 0; > > + reg->_0e.bits.stopstate_sel =3D 1; > > + reg->_0f.bits.det_delay =3D pll->det_delay; > > + > > + val =3D (u8 *)® > > + > > + for (i =3D 0; i < sizeof(reg_addr); ++i) { > > + regmap_write(regmap, reg_addr[i], val[i]); > > + DRM_DEBUG("%02x: %02x\n", reg_addr[i], val[i]); > > + } > > +} > > It would be great to also convert this part to a pattern without > structures. I will try it, but our pll registers, all not have official name from aisc design owner. If need to convert it, our pll regiters macro define, it can only be named as reg_01, reg_02... > > > + > > +int dphy_pll_config(struct dsi_context *ctx) > > +{ > > + struct sprd_dsi *dsi =3D container_of(ctx, struct sprd_dsi, ctx); > > + struct regmap *regmap =3D ctx->regmap; > > + struct dphy_pll *pll =3D ctx->pll; > > + int ret; > > + > > + pll->freq =3D dsi->slave->hs_rate; > > + > > + /* FREQ =3D 26M * (NINT + KINT / 2^20) / out_sel */ > > + ret =3D dphy_calc_pll_param(pll); > > + if (ret) { > > + drm_err(dsi->drm, "failed to calculate dphy pll parameter= s\n"); > > + return ret; > > + } > > + dphy_set_pll_reg(pll, regmap); > > + > > + return 0; > > +} > > + > > +static void dphy_set_timing_reg(struct regmap *regmap, int type, u8 va= l[]) > > +{ > > + switch (type) { > > + case REQUEST_TIME: > > + regmap_write(regmap, 0x31, val[CLK]); > > + regmap_write(regmap, 0x41, val[DATA]); > > + regmap_write(regmap, 0x51, val[DATA]); > > + regmap_write(regmap, 0x61, val[DATA]); > > + regmap_write(regmap, 0x71, val[DATA]); > > + > > + regmap_write(regmap, 0x90, val[CLK]); > > + regmap_write(regmap, 0xa0, val[DATA]); > > + regmap_write(regmap, 0xb0, val[DATA]); > > + regmap_write(regmap, 0xc0, val[DATA]); > > + regmap_write(regmap, 0xd0, val[DATA]); > > + break; > > defines and macros would help the readability here I will try it, but our pll registers, all not have official name from aisc design owner. If need to convert it, our pll regiters macro define, it can only be named as reg_01, reg_02... > > > + case PREPARE_TIME: > > + regmap_write(regmap, 0x32, val[CLK]); > > + regmap_write(regmap, 0x42, val[DATA]); > > + regmap_write(regmap, 0x52, val[DATA]); > > + regmap_write(regmap, 0x62, val[DATA]); > > + regmap_write(regmap, 0x72, val[DATA]); > > + > > + regmap_write(regmap, 0x91, val[CLK]); > > + regmap_write(regmap, 0xa1, val[DATA]); > > + regmap_write(regmap, 0xb1, val[DATA]); > > + regmap_write(regmap, 0xc1, val[DATA]); > > + regmap_write(regmap, 0xd1, val[DATA]); > > + break; > > + case ZERO_TIME: > > + regmap_write(regmap, 0x33, val[CLK]); > > + regmap_write(regmap, 0x43, val[DATA]); > > + regmap_write(regmap, 0x53, val[DATA]); > > + regmap_write(regmap, 0x63, val[DATA]); > > + regmap_write(regmap, 0x73, val[DATA]); > > + > > + regmap_write(regmap, 0x92, val[CLK]); > > + regmap_write(regmap, 0xa2, val[DATA]); > > + regmap_write(regmap, 0xb2, val[DATA]); > > + regmap_write(regmap, 0xc2, val[DATA]); > > + regmap_write(regmap, 0xd2, val[DATA]); > > + break; > > + case TRAIL_TIME: > > + regmap_write(regmap, 0x34, val[CLK]); > > + regmap_write(regmap, 0x44, val[DATA]); > > + regmap_write(regmap, 0x54, val[DATA]); > > + regmap_write(regmap, 0x64, val[DATA]); > > + regmap_write(regmap, 0x74, val[DATA]); > > + > > + regmap_write(regmap, 0x93, val[CLK]); > > + regmap_write(regmap, 0xa3, val[DATA]); > > + regmap_write(regmap, 0xb3, val[DATA]); > > + regmap_write(regmap, 0xc3, val[DATA]); > > + regmap_write(regmap, 0xd3, val[DATA]); > > + break; > > + case EXIT_TIME: > > + regmap_write(regmap, 0x36, val[CLK]); > > + regmap_write(regmap, 0x46, val[DATA]); > > + regmap_write(regmap, 0x56, val[DATA]); > > + regmap_write(regmap, 0x66, val[DATA]); > > + regmap_write(regmap, 0x76, val[DATA]); > > + > > + regmap_write(regmap, 0x95, val[CLK]); > > + regmap_write(regmap, 0xA5, val[DATA]); > > + regmap_write(regmap, 0xB5, val[DATA]); > > + regmap_write(regmap, 0xc5, val[DATA]); > > + regmap_write(regmap, 0xd5, val[DATA]); > > + break; > > + case CLKPOST_TIME: > > + regmap_write(regmap, 0x35, val[CLK]); > > + regmap_write(regmap, 0x94, val[CLK]); > > + break; > > + > > + /* the following just use default value */ > > + case SETTLE_TIME: > > + case TA_GET: > > + case TA_GO: > > + case TA_SURE: > > + break; > > you need to use fallthrough; for all those cases I get it, thks. > > > + default: > > + break; > > + } > > +} > > + > > +void dphy_timing_config(struct dsi_context *ctx) > > +{ > > + struct regmap *regmap =3D ctx->regmap; > > + struct dphy_pll *pll =3D ctx->pll; > > + const u32 factor =3D 2; > > + const u32 scale =3D 100; > > + u32 t_ui, t_byteck, t_half_byteck; > > + u32 range[2], constant; > > + u8 val[2]; > > + u32 tmp =3D 0; > > + > > + /* t_ui: 1 ui, byteck: 8 ui, half byteck: 4 ui */ > > + t_ui =3D 1000 * scale / (pll->freq / 1000); > > + t_byteck =3D t_ui << 3; > > + t_half_byteck =3D t_ui << 2; > > + constant =3D t_ui << 1; > > + > > + /* REQUEST_TIME: HS T-LPX: LP-01 > > + * For T-LPX, mipi spec defined min value is 50ns, > > + * but maybe it shouldn't be too small, because BTA, > > + * LP-10, LP-00, LP-01, all of this is related to T-LPX. > > + */ > > + range[L] =3D 50 * scale; > > + range[H] =3D INFINITY; > > + val[CLK] =3D DIV_ROUND_UP(range[L] * (factor << 1), t_byteck) - 2= ; > > + val[DATA] =3D val[CLK]; > > + dphy_set_timing_reg(regmap, REQUEST_TIME, val); > > + > > + /* PREPARE_TIME: HS sequence: LP-00 */ > > + range[L] =3D 38 * scale; > > + range[H] =3D 95 * scale; > > + tmp =3D AVERAGE(range[L], range[H]); > > + val[CLK] =3D DIV_ROUND_UP(AVERAGE(range[L], range[H]), > > + t_half_byteck) - 1; > > + range[L] =3D 40 * scale + 4 * t_ui; > > + range[H] =3D 85 * scale + 6 * t_ui; > > + tmp |=3D AVERAGE(range[L], range[H]) << 16; > > + val[DATA] =3D DIV_ROUND_UP(AVERAGE(range[L], range[H]), > > + t_half_byteck) - 1; > > + dphy_set_timing_reg(regmap, PREPARE_TIME, val); > > + > > + /* ZERO_TIME: HS-ZERO */ > > + range[L] =3D 300 * scale; > > + range[H] =3D INFINITY; > > + val[CLK] =3D DIV_ROUND_UP(range[L] * factor + (tmp & 0xffff) > > + - 525 * t_byteck / 100, t_byteck) - 2; > > + range[L] =3D 145 * scale + 10 * t_ui; > > + val[DATA] =3D DIV_ROUND_UP(range[L] * factor > > + + ((tmp >> 16) & 0xffff) - 525 * t_byteck / 100, > > + t_byteck) - 2; > > + dphy_set_timing_reg(regmap, ZERO_TIME, val); > > + > > + /* TRAIL_TIME: HS-TRAIL */ > > + range[L] =3D 60 * scale; > > + range[H] =3D INFINITY; > > + val[CLK] =3D DIV_ROUND_UP(range[L] * factor - constant, t_half_by= teck); > > + range[L] =3D max(8 * t_ui, 60 * scale + 4 * t_ui); > > + val[DATA] =3D DIV_ROUND_UP(range[L] * 3 / 2 - constant, t_half_by= teck) - 2; > > + dphy_set_timing_reg(regmap, TRAIL_TIME, val); > > + > > + /* EXIT_TIME: */ > > + range[L] =3D 100 * scale; > > + range[H] =3D INFINITY; > > + val[CLK] =3D DIV_ROUND_UP(range[L] * factor, t_byteck) - 2; > > + val[DATA] =3D val[CLK]; > > + dphy_set_timing_reg(regmap, EXIT_TIME, val); > > + > > + /* CLKPOST_TIME: */ > > + range[L] =3D 60 * scale + 52 * t_ui; > > + range[H] =3D INFINITY; > > + val[CLK] =3D DIV_ROUND_UP(range[L] * factor, t_byteck) - 2; > > + val[DATA] =3D val[CLK]; > > + dphy_set_timing_reg(regmap, CLKPOST_TIME, val); > > + > > + /* SETTLE_TIME: > > + * This time is used for receiver. So for transmitter, > > + * it can be ignored. > > + */ > > + > > + /* TA_GO: > > + * transmitter drives bridge state(LP-00) before releasing contro= l, > > + * reg 0x1f default value: 0x04, which is good. > > + */ > > + > > + /* TA_SURE: > > + * After LP-10 state and before bridge state(LP-00), > > + * reg 0x20 default value: 0x01, which is good. > > + */ > > + > > + /* TA_GET: > > + * receiver drives Bridge state(LP-00) before releasing control > > + * reg 0x21 default value: 0x03, which is good. > > + */ > > +} > > diff --git a/drivers/gpu/drm/sprd/megacores_pll.h b/drivers/gpu/drm/spr= d/megacores_pll.h > > new file mode 100644 > > index 000000000..bf20aae65 > > --- /dev/null > > +++ b/drivers/gpu/drm/sprd/megacores_pll.h > > @@ -0,0 +1,146 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +/* > > + * Copyright (C) 2020 Unisoc Inc. > > + */ > > + > > +#ifndef _MEGACORES_PLL_H_ > > +#define _MEGACORES_PLL_H_ > > + > > +#include "sprd_dsi.h" > > + > > +enum PLL_TIMING { > > + NONE, > > + REQUEST_TIME, > > + PREPARE_TIME, > > + SETTLE_TIME, > > + ZERO_TIME, > > + TRAIL_TIME, > > + EXIT_TIME, > > + CLKPOST_TIME, > > + TA_GET, > > + TA_GO, > > + TA_SURE, > > + TA_WAIT, > > +}; > > + > > +struct pll_reg { > > + union __reg_03__ { > > + struct __03 { > > + u8 prbs_bist: 1; > > + u8 en_lp_treot: 1; > > + u8 lpf_sel: 4; > > + u8 txfifo_bypass: 1; > > + u8 freq_hopping: 1; > > + } bits; > > + u8 val; > > + } _03; > > + union __reg_04__ { > > + struct __04 { > > + u8 div: 3; > > + u8 masterof8lane: 1; > > + u8 hop_trig: 1; > > + u8 cp_s: 2; > > + u8 fdk_s: 1; > > + } bits; > > + u8 val; > > + } _04; > > + union __reg_06__ { > > + struct __06 { > > + u8 nint: 7; > > + u8 mod_en: 1; > > + } bits; > > + u8 val; > > + } _06; > > + union __reg_07__ { > > + struct __07 { > > + u8 kdelta_h: 8; > > + } bits; > > + u8 val; > > + } _07; > > + union __reg_08__ { > > + struct __08 { > > + u8 vco_band: 1; > > + u8 sdm_en: 1; > > + u8 refin: 2; > > + u8 kdelta_l: 4; > > + } bits; > > + u8 val; > > + } _08; > > + union __reg_09__ { > > + struct __09 { > > + u8 kint_h: 8; > > + } bits; > > + u8 val; > > + } _09; > > + union __reg_0a__ { > > + struct __0a { > > + u8 kint_m: 8; > > + } bits; > > + u8 val; > > + } _0a; > > + union __reg_0b__ { > > + struct __0b { > > + u8 out_sel: 4; > > + u8 kint_l: 4; > > + } bits; > > + u8 val; > > + } _0b; > > + union __reg_0c__ { > > + struct __0c { > > + u8 kstep_h: 8; > > + } bits; > > + u8 val; > > + } _0c; > > + union __reg_0d__ { > > + struct __0d { > > + u8 kstep_m: 8; > > + } bits; > > + u8 val; > > + } _0d; > > + union __reg_0e__ { > > + struct __0e { > > + u8 pll_pu_byp: 1; > > + u8 pll_pu: 1; > > + u8 hsbist_len: 2; > > + u8 stopstate_sel: 1; > > + u8 kstep_l: 3; > > + } bits; > > + u8 val; > > + } _0e; > > + union __reg_0f__ { > > + struct __0f { > > + u8 det_delay:2; > > + u8 kdelta: 4; > > + u8 ldo0p4:2; > > + } bits; > > + u8 val; > > + } _0f; > > +}; > > + > > +struct dphy_pll { > > + u8 refin; /* Pre-divider control signal */ > > + u8 cp_s; /* 00: SDM_EN=3D1, 10: SDM_EN=3D0 */ > > + u8 fdk_s; /* PLL mode control: integer or fraction */ > > + u8 sdm_en; > > + u8 div; > > + u8 int_n; /* integer N PLL */ > > + u32 ref_clk; /* dphy reference clock, unit: MHz */ > > + u32 freq; /* panel config, unit: KHz */ > > + u32 fvco; > > + u32 potential_fvco; > > + u32 nint; /* sigma delta modulator NINT control */ > > + u32 kint; /* sigma delta modulator KINT control */ > > + u8 lpf_sel; /* low pass filter control */ > > + u8 out_sel; /* post divider control */ > > + u8 vco_band; /* vco range */ > > + u8 det_delay; > > + > > + struct pll_reg reg; > > +}; > > + > > +struct dsi_context; > > + > > +int dphy_pll_config(struct dsi_context *ctx); > > +void dphy_timing_config(struct dsi_context *ctx); > > + > > +#endif /* _MEGACORES_PLL_H_ */ > > diff --git a/drivers/gpu/drm/sprd/sprd_dpu.c b/drivers/gpu/drm/sprd/spr= d_dpu.c > > index 448dd4fb6..4e3b30abe 100644 > > --- a/drivers/gpu/drm/sprd/sprd_dpu.c > > +++ b/drivers/gpu/drm/sprd/sprd_dpu.c > > @@ -25,6 +25,7 @@ > > > > #include "sprd_drm.h" > > #include "sprd_dpu.h" > > +#include "sprd_dsi.h" > > > > /* Global control registers */ > > #define REG_DPU_CTRL 0x04 > > @@ -686,9 +687,25 @@ static void sprd_crtc_mode_set_nofb(struct drm_crt= c *crtc) > > { > > struct sprd_dpu *dpu =3D to_sprd_crtc(crtc); > > struct drm_display_mode *mode =3D &crtc->state->adjusted_mode; > > + struct drm_encoder *encoder; > > + struct mipi_dsi_device *slave; > > + struct sprd_dsi *dsi; > > > > drm_display_mode_to_videomode(mode, &dpu->ctx.vm); > > > > + drm_for_each_encoder(encoder, crtc->dev) { > > + if (encoder->crtc !=3D crtc) > > + continue; > > + > > + dsi =3D encoder_to_dsi(encoder); > > + slave =3D dsi->slave; > > + > > + if (slave->mode_flags & MIPI_DSI_MODE_VIDEO) > > + dpu->ctx.if_type =3D SPRD_DPU_IF_DPI; > > + else > > + dpu->ctx.if_type =3D SPRD_DPU_IF_EDPI; > > + } > > + > > You're not using if_type anywhere Used in sprd_dpu.c as for crtc output type dpi or edpi. > > > sprd_dpi_init(dpu); > > } > > > > diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/spr= d_drm.c > > index 549b71278..68cf0933c 100644 > > --- a/drivers/gpu/drm/sprd/sprd_drm.c > > +++ b/drivers/gpu/drm/sprd/sprd_drm.c > > @@ -183,6 +183,7 @@ static struct platform_driver sprd_drm_driver =3D { > > static struct platform_driver *sprd_drm_drivers[] =3D { > > &sprd_drm_driver, > > &sprd_dpu_driver, > > + &sprd_dsi_driver, > > }; > > > > static int __init sprd_drm_init(void) > > diff --git a/drivers/gpu/drm/sprd/sprd_drm.h b/drivers/gpu/drm/sprd/spr= d_drm.h > > index 85d4a8b9f..95d1b972f 100644 > > --- a/drivers/gpu/drm/sprd/sprd_drm.h > > +++ b/drivers/gpu/drm/sprd/sprd_drm.h > > @@ -14,5 +14,6 @@ struct sprd_drm { > > }; > > > > extern struct platform_driver sprd_dpu_driver; > > +extern struct platform_driver sprd_dsi_driver; > > > > #endif /* _SPRD_DRM_H_ */ > > diff --git a/drivers/gpu/drm/sprd/sprd_dsi.c b/drivers/gpu/drm/sprd/spr= d_dsi.c > > new file mode 100644 > > index 000000000..5ce98fe90 > > --- /dev/null > > +++ b/drivers/gpu/drm/sprd/sprd_dsi.c > > @@ -0,0 +1,1260 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2020 Unisoc Inc. > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include