From mboxrd@z Thu Jan 1 00:00:00 1970 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=-13.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED 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 319C3C433C1 for ; Fri, 26 Mar 2021 20:17:42 +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 0262761A18 for ; Fri, 26 Mar 2021 20:17:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0262761A18 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=codeaurora.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 161D86F3FB; Fri, 26 Mar 2021 20:17:41 +0000 (UTC) Received: from m43-7.mailgun.net (m43-7.mailgun.net [69.72.43.7]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7C0BB6F469 for ; Fri, 26 Mar 2021 17:53:52 +0000 (UTC) DKIM-Signature: a=rsa-sha256; v=1; c=relaxed/relaxed; d=mg.codeaurora.org; q=dns/txt; s=smtp; t=1616781232; h=Message-ID: References: In-Reply-To: Subject: Cc: To: From: Date: Content-Transfer-Encoding: Content-Type: MIME-Version: Sender; bh=xHXfitMrgTR/ACiw6YJKaHlo5HuRjQ8H7V2F4Lqui3k=; b=WSZPeg1F4m0uxD167QB0XL24mwwhGdD+73lLe7EsgfCSX4eLPGYJy9pENNNbrz63p42F0T8g z/xaFyHK2DQ0IK3d9aRY5iZ677oUB+UPXw91C/3McBbLMg316wQfQQ5urjz4QvjogLV/OzSg 4ElJ0xVP0ELNW2HufROExQgYLgs= X-Mailgun-Sending-Ip: 69.72.43.7 X-Mailgun-Sid: WyJkOTU5ZSIsICJkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnIiwgImJlOWU0YSJd Received: from smtp.codeaurora.org (ec2-35-166-182-171.us-west-2.compute.amazonaws.com [35.166.182.171]) by smtp-out-n02.prod.us-west-2.postgun.com with SMTP id 605e1e7ea2ab6642dbb6241a (version=TLS1.2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256); Fri, 26 Mar 2021 17:48:46 GMT Received: by smtp.codeaurora.org (Postfix, from userid 1001) id 30C88C433C6; Fri, 26 Mar 2021 17:48:45 +0000 (UTC) Received: from mail.codeaurora.org (localhost.localdomain [127.0.0.1]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) (Authenticated sender: abhinavk) by smtp.codeaurora.org (Postfix) with ESMTPSA id 069E8C433C6; Fri, 26 Mar 2021 17:48:16 +0000 (UTC) MIME-Version: 1.0 Date: Fri, 26 Mar 2021 10:48:16 -0700 From: abhinavk@codeaurora.org To: Dmitry Baryshkov Subject: Re: [Freedreno] [PATCH v2 05/28] drm/msm/dsi: fuse dsi_pll_* code into dsi_phy_* code In-Reply-To: <20210324151846.2774204-6-dmitry.baryshkov@linaro.org> References: <20210324151846.2774204-1-dmitry.baryshkov@linaro.org> <20210324151846.2774204-6-dmitry.baryshkov@linaro.org> Message-ID: <330743854d9b04c246a7c1bdfb852197@codeaurora.org> X-Sender: abhinavk@codeaurora.org User-Agent: Roundcube Webmail/1.3.9 X-Mailman-Approved-At: Fri, 26 Mar 2021 20:17:39 +0000 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: freedreno@lists.freedesktop.org, Jonathan Marek , Stephen Boyd , linux-arm-msm@vger.kernel.org, Michael Turquette , dri-devel@lists.freedesktop.org, David Airlie , Sean Paul , linux-clk@vger.kernel.org Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On 2021-03-24 08:18, Dmitry Baryshkov wrote: > Each phy version is tightly coupled with the corresponding PLL code, > there is no need to keep them separate. Fuse source files together in > order to simplify DSI code. > > Signed-off-by: Dmitry Baryshkov Reviewed-by: Abhinav Kumar > --- > drivers/gpu/drm/msm/Makefile | 9 +- > drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 873 +++++++++++++ > drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c | 1089 ++++++++++++++++ > drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c | 637 ++++++++++ > .../gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c | 519 ++++++++ > drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c | 905 ++++++++++++++ > .../gpu/drm/msm/dsi/{pll => phy}/dsi_pll.c | 0 > .../gpu/drm/msm/dsi/{pll => phy}/dsi_pll.h | 0 > drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c | 881 ------------- > drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c | 1096 ----------------- > drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c | 643 ---------- > .../gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c | 526 -------- > drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c | 913 -------------- > 13 files changed, 4024 insertions(+), 4067 deletions(-) > rename drivers/gpu/drm/msm/dsi/{pll => phy}/dsi_pll.c (100%) > rename drivers/gpu/drm/msm/dsi/{pll => phy}/dsi_pll.h (100%) > delete mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c > delete mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c > delete mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c > delete mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c > delete mode 100644 drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c > > diff --git a/drivers/gpu/drm/msm/Makefile > b/drivers/gpu/drm/msm/Makefile > index 3cc906121fb3..1be6996b80b7 100644 > --- a/drivers/gpu/drm/msm/Makefile > +++ b/drivers/gpu/drm/msm/Makefile > @@ -136,13 +136,6 @@ msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += > dsi/phy/dsi_phy_14nm.o > msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/phy/dsi_phy_10nm.o > msm-$(CONFIG_DRM_MSM_DSI_7NM_PHY) += dsi/phy/dsi_phy_7nm.o > > -ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) > -msm-y += dsi/pll/dsi_pll.o > -msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o > -msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o > -msm-$(CONFIG_DRM_MSM_DSI_14NM_PHY) += dsi/pll/dsi_pll_14nm.o > -msm-$(CONFIG_DRM_MSM_DSI_10NM_PHY) += dsi/pll/dsi_pll_10nm.o > -msm-$(CONFIG_DRM_MSM_DSI_7NM_PHY) += dsi/pll/dsi_pll_7nm.o > -endif > +msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/phy/dsi_pll.o > > obj-$(CONFIG_DRM_MSM) += msm.o > diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c > index 655fa17a0452..5da369b5c475 100644 > --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c > +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c > @@ -3,11 +3,884 @@ > * Copyright (c) 2018, The Linux Foundation > */ > > +#include > +#include > #include > > +#include "dsi_pll.h" > #include "dsi_phy.h" > #include "dsi.xml.h" > > +/* > + * DSI PLL 10nm - clock diagram (eg: DSI0): > + * > + * dsi0_pll_out_div_clk dsi0_pll_bit_clk > + * | | > + * | | > + * +---------+ | +----------+ | +----+ > + * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- > dsi0_phy_pll_out_byteclk > + * +---------+ | +----------+ | +----+ > + * | | > + * | | > dsi0_pll_by_2_bit_clk > + * | | | > + * | | +----+ | |\ > dsi0_pclk_mux > + * | |--| /2 |--o--| \ | > + * | | +----+ | \ > | +---------+ > + * | --------------| > |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk > + * |------------------------------| / > +---------+ > + * | +-----+ | / > + * -----------| /4? |--o----------|/ > + * +-----+ | | > + * | > |dsiclk_sel > + * | > + * > dsi0_pll_post_out_div_clk > + */ > + > +#define DSI_BYTE_PLL_CLK 0 > +#define DSI_PIXEL_PLL_CLK 1 > +#define NUM_PROVIDED_CLKS 2 > + > +#define VCO_REF_CLK_RATE 19200000 > + > +struct dsi_pll_regs { > + u32 pll_prop_gain_rate; > + u32 pll_lockdet_rate; > + u32 decimal_div_start; > + u32 frac_div_start_low; > + u32 frac_div_start_mid; > + u32 frac_div_start_high; > + u32 pll_clock_inverters; > + u32 ssc_stepsize_low; > + u32 ssc_stepsize_high; > + u32 ssc_div_per_low; > + u32 ssc_div_per_high; > + u32 ssc_adjper_low; > + u32 ssc_adjper_high; > + u32 ssc_control; > +}; > + > +struct dsi_pll_config { > + u32 ref_freq; > + bool div_override; > + u32 output_div; > + bool ignore_frac; > + bool disable_prescaler; > + bool enable_ssc; > + bool ssc_center; > + u32 dec_bits; > + u32 frac_bits; > + u32 lock_timer; > + u32 ssc_freq; > + u32 ssc_offset; > + u32 ssc_adj_per; > + u32 thresh_cycles; > + u32 refclk_cycles; > +}; > + > +struct pll_10nm_cached_state { > + unsigned long vco_rate; > + u8 bit_clk_div; > + u8 pix_clk_div; > + u8 pll_out_div; > + u8 pll_mux; > +}; > + > +struct dsi_pll_10nm { > + struct msm_dsi_pll base; > + > + int id; > + struct platform_device *pdev; > + > + void __iomem *phy_cmn_mmio; > + void __iomem *mmio; > + > + u64 vco_ref_clk_rate; > + u64 vco_current_rate; > + > + /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ > + spinlock_t postdiv_lock; > + > + int vco_delay; > + struct dsi_pll_config pll_configuration; > + struct dsi_pll_regs reg_setup; > + > + /* private clocks: */ > + struct clk_hw *out_div_clk_hw; > + struct clk_hw *bit_clk_hw; > + struct clk_hw *byte_clk_hw; > + struct clk_hw *by_2_bit_clk_hw; > + struct clk_hw *post_out_div_clk_hw; > + struct clk_hw *pclk_mux_hw; > + struct clk_hw *out_dsiclk_hw; > + > + /* clock-provider: */ > + struct clk_hw_onecell_data *hw_data; > + > + struct pll_10nm_cached_state cached_state; > + > + enum msm_dsi_phy_usecase uc; > + struct dsi_pll_10nm *slave; > +}; > + > +#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base) > + > +/* > + * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > + * mode, where the master PLL's clk_ops needs access the slave's > private data > + */ > +static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; > + > +static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + > + config->ref_freq = pll->vco_ref_clk_rate; > + config->output_div = 1; > + config->dec_bits = 8; > + config->frac_bits = 18; > + config->lock_timer = 64; > + config->ssc_freq = 31500; > + config->ssc_offset = 5000; > + config->ssc_adj_per = 2; > + config->thresh_cycles = 32; > + config->refclk_cycles = 256; > + > + config->div_override = false; > + config->ignore_frac = false; > + config->disable_prescaler = false; > + > + config->enable_ssc = false; > + config->ssc_center = 0; > +} > + > +static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + u64 fref = pll->vco_ref_clk_rate; > + u64 pll_freq; > + u64 divider; > + u64 dec, dec_multiple; > + u32 frac; > + u64 multiplier; > + > + pll_freq = pll->vco_current_rate; > + > + if (config->disable_prescaler) > + divider = fref; > + else > + divider = fref * 2; > + > + multiplier = 1 << config->frac_bits; > + dec_multiple = div_u64(pll_freq * multiplier, divider); > + dec = div_u64_rem(dec_multiple, multiplier, &frac); > + > + if (pll_freq <= 1900000000UL) > + regs->pll_prop_gain_rate = 8; > + else if (pll_freq <= 3000000000UL) > + regs->pll_prop_gain_rate = 10; > + else > + regs->pll_prop_gain_rate = 12; > + if (pll_freq < 1100000000UL) > + regs->pll_clock_inverters = 8; > + else > + regs->pll_clock_inverters = 0; > + > + regs->pll_lockdet_rate = config->lock_timer; > + regs->decimal_div_start = dec; > + regs->frac_div_start_low = (frac & 0xff); > + regs->frac_div_start_mid = (frac & 0xff00) >> 8; > + regs->frac_div_start_high = (frac & 0x30000) >> 16; > +} > + > +#define SSC_CENTER BIT(0) > +#define SSC_EN BIT(1) > + > +static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + u32 ssc_per; > + u32 ssc_mod; > + u64 ssc_step_size; > + u64 frac; > + > + if (!config->enable_ssc) { > + DBG("SSC not enabled\n"); > + return; > + } > + > + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - > 1; > + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); > + ssc_per -= ssc_mod; > + > + frac = regs->frac_div_start_low | > + (regs->frac_div_start_mid << 8) | > + (regs->frac_div_start_high << 16); > + ssc_step_size = regs->decimal_div_start; > + ssc_step_size *= (1 << config->frac_bits); > + ssc_step_size += frac; > + ssc_step_size *= config->ssc_offset; > + ssc_step_size *= (config->ssc_adj_per + 1); > + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); > + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); > + > + regs->ssc_div_per_low = ssc_per & 0xFF; > + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; > + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); > + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); > + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; > + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; > + > + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; > + > + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", > + regs->decimal_div_start, frac, config->frac_bits); > + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", > + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); > +} > + > +static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) > +{ > + void __iomem *base = pll->mmio; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + > + if (pll->pll_configuration.enable_ssc) { > + pr_debug("SSC is enabled\n"); > + > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, > + regs->ssc_stepsize_low); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, > + regs->ssc_stepsize_high); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, > + regs->ssc_div_per_low); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, > + regs->ssc_div_per_high); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, > + regs->ssc_adjper_low); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, > + regs->ssc_adjper_high); > + pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, > + SSC_EN | regs->ssc_control); > + } > +} > + > +static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) > +{ > + void __iomem *base = pll->mmio; > + > + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); > + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); > + pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); > + pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); > + pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); > + pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); > + pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, > + 0xba); > + pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, > 0x0c); > + pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); > + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0xfa); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, > + 0x4c); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); > + pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); > +} > + > +static void dsi_pll_commit(struct dsi_pll_10nm *pll) > +{ > + void __iomem *base = pll->mmio; > + struct dsi_pll_regs *reg = &pll->reg_setup; > + > + pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); > + pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, > + reg->decimal_div_start); > + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, > + reg->frac_div_start_low); > + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, > + reg->frac_div_start_mid); > + pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, > + reg->frac_div_start_high); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, > + reg->pll_lockdet_rate); > + pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); > + pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); > + pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, > + reg->pll_clock_inverters); > +} > + > +static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + > + DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, > + parent_rate); > + > + pll_10nm->vco_current_rate = rate; > + pll_10nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > + > + dsi_pll_setup_config(pll_10nm); > + > + dsi_pll_calc_dec_frac(pll_10nm); > + > + dsi_pll_calc_ssc(pll_10nm); > + > + dsi_pll_commit(pll_10nm); > + > + dsi_pll_config_hzindep_reg(pll_10nm); > + > + dsi_pll_ssc_commit(pll_10nm); > + > + /* flush, ensure all register writes are done*/ > + wmb(); > + > + return 0; > +} > + > +static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) > +{ > + struct device *dev = &pll->pdev->dev; > + int rc; > + u32 status = 0; > + u32 const delay_us = 100; > + u32 const timeout_us = 5000; > + > + rc = readl_poll_timeout_atomic(pll->mmio + > + REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, > + status, > + ((status & BIT(0)) > 0), > + delay_us, > + timeout_us); > + if (rc) > + DRM_DEV_ERROR(dev, "DSI PLL(%d) lock failed, status=0x%08x\n", > + pll->id, status); > + > + return rc; > +} > + > +static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) > +{ > + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); > + > + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); > + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, > + data & ~BIT(5)); > + ndelay(250); > +} > + > +static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) > +{ > + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); > + > + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, > + data | BIT(5)); > + pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); > + ndelay(250); > +} > + > +static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) > +{ > + u32 data; > + > + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, > + data & ~BIT(5)); > +} > + > +static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) > +{ > + u32 data; > + > + data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, > + data | BIT(5)); > +} > + > +static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct device *dev = &pll_10nm->pdev->dev; > + int rc; > + > + dsi_pll_enable_pll_bias(pll_10nm); > + if (pll_10nm->slave) > + dsi_pll_enable_pll_bias(pll_10nm->slave); > + > + rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0); > + if (rc) { > + DRM_DEV_ERROR(dev, "vco_set_rate failed, rc=%d\n", rc); > + return rc; > + } > + > + /* Start PLL */ > + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, > + 0x01); > + > + /* > + * ensure all PLL configurations are written prior to checking > + * for PLL lock. > + */ > + wmb(); > + > + /* Check for PLL lock */ > + rc = dsi_pll_10nm_lock_status(pll_10nm); > + if (rc) { > + DRM_DEV_ERROR(dev, "PLL(%d) lock failed\n", pll_10nm->id); > + goto error; > + } > + > + pll->pll_on = true; > + > + dsi_pll_enable_global_clk(pll_10nm); > + if (pll_10nm->slave) > + dsi_pll_enable_global_clk(pll_10nm->slave); > + > + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, > + 0x01); > + if (pll_10nm->slave) > + pll_write(pll_10nm->slave->phy_cmn_mmio + > + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); > + > +error: > + return rc; > +} > + > +static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) > +{ > + pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); > + dsi_pll_disable_pll_bias(pll); > +} > + > +static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + > + /* > + * To avoid any stray glitches while abruptly powering down the PLL > + * make sure to gate the clock using the clock enable bit before > + * powering down the PLL > + */ > + dsi_pll_disable_global_clk(pll_10nm); > + pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, > 0); > + dsi_pll_disable_sub(pll_10nm); > + if (pll_10nm->slave) { > + dsi_pll_disable_global_clk(pll_10nm->slave); > + dsi_pll_disable_sub(pll_10nm->slave); > + } > + /* flush, ensure all register writes are done */ > + wmb(); > + pll->pll_on = false; > +} > + > +static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct dsi_pll_config *config = &pll_10nm->pll_configuration; > + void __iomem *base = pll_10nm->mmio; > + u64 ref_clk = pll_10nm->vco_ref_clk_rate; > + u64 vco_rate = 0x0; > + u64 multiplier; > + u32 frac; > + u32 dec; > + u64 pll_freq, tmp64; > + > + dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); > + dec &= 0xff; > + > + frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); > + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) > & > + 0xff) << 8); > + frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) > & > + 0x3) << 16); > + > + /* > + * TODO: > + * 1. Assumes prescaler is disabled > + */ > + multiplier = 1 << config->frac_bits; > + pll_freq = dec * (ref_clk * 2); > + tmp64 = (ref_clk * 2 * frac); > + pll_freq += div_u64(tmp64, multiplier); > + > + vco_rate = pll_freq; > + > + DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", > + pll_10nm->id, (unsigned long)vco_rate, dec, frac); > + > + return (unsigned long)vco_rate; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { > + .round_rate = msm_dsi_pll_helper_clk_round_rate, > + .set_rate = dsi_pll_10nm_vco_set_rate, > + .recalc_rate = dsi_pll_10nm_vco_recalc_rate, > + .prepare = dsi_pll_10nm_vco_prepare, > + .unprepare = dsi_pll_10nm_vco_unprepare, > +}; > + > +/* > + * PLL Callbacks > + */ > + > +static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; > + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; > + u32 cmn_clk_cfg0, cmn_clk_cfg1; > + > + cached->pll_out_div = pll_read(pll_10nm->mmio + > + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); > + cached->pll_out_div &= 0x3; > + > + cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); > + cached->bit_clk_div = cmn_clk_cfg0 & 0xf; > + cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; > + > + cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > + cached->pll_mux = cmn_clk_cfg1 & 0x3; > + > + DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", > + pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, > + cached->pix_clk_div, cached->pll_mux); > +} > + > +static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; > + void __iomem *phy_base = pll_10nm->phy_cmn_mmio; > + u32 val; > + int ret; > + > + val = pll_read(pll_10nm->mmio + > REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); > + val &= ~0x3; > + val |= cached->pll_out_div; > + pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, > val); > + > + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, > + cached->bit_clk_div | (cached->pix_clk_div << 4)); > + > + val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > + val &= ~0x3; > + val |= cached->pll_mux; > + pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); > + > + ret = dsi_pll_10nm_vco_set_rate(&pll->clk_hw, > pll_10nm->vco_current_rate, pll_10nm->vco_ref_clk_rate); > + if (ret) { > + DRM_DEV_ERROR(&pll_10nm->pdev->dev, > + "restore vco rate failed. ret=%d\n", ret); > + return ret; > + } > + > + DBG("DSI PLL%d", pll_10nm->id); > + > + return 0; > +} > + > +static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, > + enum msm_dsi_phy_usecase uc) > +{ > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + void __iomem *base = pll_10nm->phy_cmn_mmio; > + u32 data = 0x0; /* internal PLL */ > + > + DBG("DSI PLL%d", pll_10nm->id); > + > + switch (uc) { > + case MSM_DSI_PHY_STANDALONE: > + break; > + case MSM_DSI_PHY_MASTER: > + pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; > + break; > + case MSM_DSI_PHY_SLAVE: > + data = 0x1; /* external PLL */ > + break; > + default: > + return -EINVAL; > + } > + > + /* set PLL src */ > + pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); > + > + pll_10nm->uc = uc; > + > + return 0; > +} > + > +static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, > + struct clk **byte_clk_provider, > + struct clk **pixel_clk_provider) > +{ > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; > + > + DBG("DSI PLL%d", pll_10nm->id); > + > + if (byte_clk_provider) > + *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > + if (pixel_clk_provider) > + *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > + > + return 0; > +} > + > +static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > + struct device *dev = &pll_10nm->pdev->dev; > + > + DBG("DSI PLL%d", pll_10nm->id); > + of_clk_del_provider(dev->of_node); > + > + clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); > + clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); > + clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); > + clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); > + clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); > + clk_hw_unregister_divider(pll_10nm->bit_clk_hw); > + clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); > + clk_hw_unregister(&pll_10nm->base.clk_hw); > +} > + > +/* > + * The post dividers and mux clocks are created using the standard > divider and > + * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its > dividers/mux > + * state to follow the master PLL's divider/mux state. Therefore, we > don't > + * require special clock ops that also configure the slave PLL > registers > + */ > +static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) > +{ > + char clk_name[32], parent[32], vco_name[32]; > + char parent2[32], parent3[32], parent4[32]; > + struct clk_init_data vco_init = { > + .parent_names = (const char *[]){ "xo" }, > + .num_parents = 1, > + .name = vco_name, > + .flags = CLK_IGNORE_UNUSED, > + .ops = &clk_ops_dsi_pll_10nm_vco, > + }; > + struct device *dev = &pll_10nm->pdev->dev; > + struct clk_hw_onecell_data *hw_data; > + struct clk_hw *hw; > + int ret; > + > + DBG("DSI%d", pll_10nm->id); > + > + hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > + NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > + GFP_KERNEL); > + if (!hw_data) > + return -ENOMEM; > + > + snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); > + pll_10nm->base.clk_hw.init = &vco_init; > + > + ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); > + if (ret) > + return ret; > + > + snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > + snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); > + > + hw = clk_hw_register_divider(dev, clk_name, > + parent, CLK_SET_RATE_PARENT, > + pll_10nm->mmio + > + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, > + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_base_clk_hw; > + } > + > + pll_10nm->out_div_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > + > + /* BIT CLK: DIV_CTRL_3_0 */ > + hw = clk_hw_register_divider(dev, clk_name, parent, > + CLK_SET_RATE_PARENT, > + pll_10nm->phy_cmn_mmio + > + REG_DSI_10nm_PHY_CMN_CLK_CFG0, > + 0, 4, CLK_DIVIDER_ONE_BASED, > + &pll_10nm->postdiv_lock); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_out_div_clk_hw; > + } > + > + pll_10nm->bit_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > + > + /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + CLK_SET_RATE_PARENT, 1, 8); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_bit_clk_hw; > + } > + > + pll_10nm->byte_clk_hw = hw; > + hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > + > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + 0, 1, 2); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_byte_clk_hw; > + } > + > + pll_10nm->by_2_bit_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > + > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + 0, 1, 4); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_by_2_bit_clk_hw; > + } > + > + pll_10nm->post_out_div_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > + snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); > + snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > + snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); > + > + hw = clk_hw_register_mux(dev, clk_name, > + ((const char *[]){ > + parent, parent2, parent3, parent4 > + }), 4, 0, pll_10nm->phy_cmn_mmio + > + REG_DSI_10nm_PHY_CMN_CLK_CFG1, > + 0, 2, 0, NULL); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_post_out_div_clk_hw; > + } > + > + pll_10nm->pclk_mux_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id); > + snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); > + > + /* PIX CLK DIV : DIV_CTRL_7_4*/ > + hw = clk_hw_register_divider(dev, clk_name, parent, > + 0, pll_10nm->phy_cmn_mmio + > + REG_DSI_10nm_PHY_CMN_CLK_CFG0, > + 4, 4, CLK_DIVIDER_ONE_BASED, > + &pll_10nm->postdiv_lock); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_pclk_mux_hw; > + } > + > + pll_10nm->out_dsiclk_hw = hw; > + hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > + > + hw_data->num = NUM_PROVIDED_CLKS; > + pll_10nm->hw_data = hw_data; > + > + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > + pll_10nm->hw_data); > + if (ret) { > + DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > + goto err_dsiclk_hw; > + } > + > + return 0; > + > +err_dsiclk_hw: > + clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); > +err_pclk_mux_hw: > + clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); > +err_post_out_div_clk_hw: > + clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); > +err_by_2_bit_clk_hw: > + clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); > +err_byte_clk_hw: > + clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); > +err_bit_clk_hw: > + clk_hw_unregister_divider(pll_10nm->bit_clk_hw); > +err_out_div_clk_hw: > + clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); > +err_base_clk_hw: > + clk_hw_unregister(&pll_10nm->base.clk_hw); > + > + return ret; > +} > + > +struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device > *pdev, int id) > +{ > + struct dsi_pll_10nm *pll_10nm; > + struct msm_dsi_pll *pll; > + int ret; > + > + pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); > + if (!pll_10nm) > + return ERR_PTR(-ENOMEM); > + > + DBG("DSI PLL%d", id); > + > + pll_10nm->pdev = pdev; > + pll_10nm->id = id; > + pll_10nm_list[id] = pll_10nm; > + > + pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > + if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > + if (IS_ERR_OR_NULL(pll_10nm->mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + spin_lock_init(&pll_10nm->postdiv_lock); > + > + pll = &pll_10nm->base; > + pll->min_rate = 1000000000UL; > + pll->max_rate = 3500000000UL; > + pll->get_provider = dsi_pll_10nm_get_provider; > + pll->destroy = dsi_pll_10nm_destroy; > + pll->save_state = dsi_pll_10nm_save_state; > + pll->restore_state = dsi_pll_10nm_restore_state; > + pll->set_usecase = dsi_pll_10nm_set_usecase; > + > + pll_10nm->vco_delay = 1; > + > + ret = pll_10nm_register(pll_10nm); > + if (ret) { > + DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > + return ERR_PTR(ret); > + } > + > + /* TODO: Remove this when we have proper display handover support */ > + msm_dsi_pll_save_state(pll); > + > + return pll; > +} > + > static int dsi_phy_hw_v3_0_is_pll_on(struct msm_dsi_phy *phy) > { > void __iomem *base = phy->base; > diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c > index 6989730b5fbd..6a63901da7a4 100644 > --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c > +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c > @@ -3,13 +3,1102 @@ > * Copyright (c) 2016, The Linux Foundation. All rights reserved. > */ > > +#include > +#include > #include > > #include "dsi_phy.h" > +#include "dsi_pll.h" > #include "dsi.xml.h" > > #define PHY_14NM_CKLN_IDX 4 > > +/* > + * DSI PLL 14nm - clock diagram (eg: DSI0): > + * > + * dsi0n1_postdiv_clk > + * | > + * | > + * +----+ | +----+ > + * dsi0vco_clk ---| n1 |--o--| /8 |-- dsi0pllbyte > + * +----+ | +----+ > + * | dsi0n1_postdivby2_clk > + * | +----+ | > + * o---| /2 |--o--|\ > + * | +----+ | \ +----+ > + * | | |--| n2 |-- dsi0pll > + * o--------------| / +----+ > + * |/ > + */ > + > +#define POLL_MAX_READS 15 > +#define POLL_TIMEOUT_US 1000 > + > +#define NUM_PROVIDED_CLKS 2 > + > +#define VCO_REF_CLK_RATE 19200000 > +#define VCO_MIN_RATE 1300000000UL > +#define VCO_MAX_RATE 2600000000UL > + > +#define DSI_BYTE_PLL_CLK 0 > +#define DSI_PIXEL_PLL_CLK 1 > + > +#define DSI_PLL_DEFAULT_VCO_POSTDIV 1 > + > +struct dsi_pll_input { > + u32 fref; /* reference clk */ > + u32 fdata; /* bit clock rate */ > + u32 dsiclk_sel; /* Mux configuration (see diagram) */ > + u32 ssc_en; /* SSC enable/disable */ > + u32 ldo_en; > + > + /* fixed params */ > + u32 refclk_dbler_en; > + u32 vco_measure_time; > + u32 kvco_measure_time; > + u32 bandgap_timer; > + u32 pll_wakeup_timer; > + u32 plllock_cnt; > + u32 plllock_rng; > + u32 ssc_center; > + u32 ssc_adj_period; > + u32 ssc_spread; > + u32 ssc_freq; > + u32 pll_ie_trim; > + u32 pll_ip_trim; > + u32 pll_iptat_trim; > + u32 pll_cpcset_cur; > + u32 pll_cpmset_cur; > + > + u32 pll_icpmset; > + u32 pll_icpcset; > + > + u32 pll_icpmset_p; > + u32 pll_icpmset_m; > + > + u32 pll_icpcset_p; > + u32 pll_icpcset_m; > + > + u32 pll_lpf_res1; > + u32 pll_lpf_cap1; > + u32 pll_lpf_cap2; > + u32 pll_c3ctrl; > + u32 pll_r3ctrl; > +}; > + > +struct dsi_pll_output { > + u32 pll_txclk_en; > + u32 dec_start; > + u32 div_frac_start; > + u32 ssc_period; > + u32 ssc_step_size; > + u32 plllock_cmp; > + u32 pll_vco_div_ref; > + u32 pll_vco_count; > + u32 pll_kvco_div_ref; > + u32 pll_kvco_count; > + u32 pll_misc1; > + u32 pll_lpf2_postdiv; > + u32 pll_resetsm_cntrl; > + u32 pll_resetsm_cntrl2; > + u32 pll_resetsm_cntrl5; > + u32 pll_kvco_code; > + > + u32 cmn_clk_cfg0; > + u32 cmn_clk_cfg1; > + u32 cmn_ldo_cntrl; > + > + u32 pll_postdiv; > + u32 fcvo; > +}; > + > +struct pll_14nm_cached_state { > + unsigned long vco_rate; > + u8 n2postdiv; > + u8 n1postdiv; > +}; > + > +struct dsi_pll_14nm { > + struct msm_dsi_pll base; > + > + int id; > + struct platform_device *pdev; > + > + void __iomem *phy_cmn_mmio; > + void __iomem *mmio; > + > + int vco_delay; > + > + struct dsi_pll_input in; > + struct dsi_pll_output out; > + > + /* protects REG_DSI_14nm_PHY_CMN_CLK_CFG0 register */ > + spinlock_t postdiv_lock; > + > + u64 vco_current_rate; > + u64 vco_ref_clk_rate; > + > + /* private clocks: */ > + struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; > + u32 num_hws; > + > + /* clock-provider: */ > + struct clk_hw_onecell_data *hw_data; > + > + struct pll_14nm_cached_state cached_state; > + > + enum msm_dsi_phy_usecase uc; > + struct dsi_pll_14nm *slave; > +}; > + > +#define to_pll_14nm(x) container_of(x, struct dsi_pll_14nm, base) > + > +/* > + * Private struct for N1/N2 post-divider clocks. These clocks are > similar to > + * the generic clk_divider class of clocks. The only difference is > that it > + * also sets the slave DSI PLL's post-dividers if in Dual DSI mode > + */ > +struct dsi_pll_14nm_postdiv { > + struct clk_hw hw; > + > + /* divider params */ > + u8 shift; > + u8 width; > + u8 flags; /* same flags as used by clk_divider struct */ > + > + struct dsi_pll_14nm *pll; > +}; > + > +#define to_pll_14nm_postdiv(_hw) container_of(_hw, struct > dsi_pll_14nm_postdiv, hw) > + > +/* > + * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > + * mode, where the master PLL's clk_ops needs access the slave's > private data > + */ > +static struct dsi_pll_14nm *pll_14nm_list[DSI_MAX]; > + > +static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm, > + u32 nb_tries, u32 timeout_us) > +{ > + bool pll_locked = false; > + void __iomem *base = pll_14nm->mmio; > + u32 tries, val; > + > + tries = nb_tries; > + while (tries--) { > + val = pll_read(base + > + REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); > + pll_locked = !!(val & BIT(5)); > + > + if (pll_locked) > + break; > + > + udelay(timeout_us); > + } > + > + if (!pll_locked) { > + tries = nb_tries; > + while (tries--) { > + val = pll_read(base + > + REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); > + pll_locked = !!(val & BIT(0)); > + > + if (pll_locked) > + break; > + > + udelay(timeout_us); > + } > + } > + > + DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > + > + return pll_locked; > +} > + > +static void dsi_pll_14nm_input_init(struct dsi_pll_14nm *pll) > +{ > + pll->in.fref = pll->vco_ref_clk_rate; > + pll->in.fdata = 0; > + pll->in.dsiclk_sel = 1; /* Use the /2 path in Mux */ > + pll->in.ldo_en = 0; /* disabled for now */ > + > + /* fixed input */ > + pll->in.refclk_dbler_en = 0; > + pll->in.vco_measure_time = 5; > + pll->in.kvco_measure_time = 5; > + pll->in.bandgap_timer = 4; > + pll->in.pll_wakeup_timer = 5; > + pll->in.plllock_cnt = 1; > + pll->in.plllock_rng = 0; > + > + /* > + * SSC is enabled by default. We might need DT props for configuring > + * some SSC params like PPM and center/down spread etc. > + */ > + pll->in.ssc_en = 1; > + pll->in.ssc_center = 0; /* down spread by default */ > + pll->in.ssc_spread = 5; /* PPM / 1000 */ > + pll->in.ssc_freq = 31500; /* default recommended */ > + pll->in.ssc_adj_period = 37; > + > + pll->in.pll_ie_trim = 4; > + pll->in.pll_ip_trim = 4; > + pll->in.pll_cpcset_cur = 1; > + pll->in.pll_cpmset_cur = 1; > + pll->in.pll_icpmset = 4; > + pll->in.pll_icpcset = 4; > + pll->in.pll_icpmset_p = 0; > + pll->in.pll_icpmset_m = 0; > + pll->in.pll_icpcset_p = 0; > + pll->in.pll_icpcset_m = 0; > + pll->in.pll_lpf_res1 = 3; > + pll->in.pll_lpf_cap1 = 11; > + pll->in.pll_lpf_cap2 = 1; > + pll->in.pll_iptat_trim = 7; > + pll->in.pll_c3ctrl = 2; > + pll->in.pll_r3ctrl = 1; > +} > + > +#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) > + > +static void pll_14nm_ssc_calc(struct dsi_pll_14nm *pll) > +{ > + u32 period, ssc_period; > + u32 ref, rem; > + u64 step_size; > + > + DBG("vco=%lld ref=%lld", pll->vco_current_rate, > pll->vco_ref_clk_rate); > + > + ssc_period = pll->in.ssc_freq / 500; > + period = (u32)pll->vco_ref_clk_rate / 1000; > + ssc_period = CEIL(period, ssc_period); > + ssc_period -= 1; > + pll->out.ssc_period = ssc_period; > + > + DBG("ssc freq=%d spread=%d period=%d", pll->in.ssc_freq, > + pll->in.ssc_spread, pll->out.ssc_period); > + > + step_size = (u32)pll->vco_current_rate; > + ref = pll->vco_ref_clk_rate; > + ref /= 1000; > + step_size = div_u64(step_size, ref); > + step_size <<= 20; > + step_size = div_u64(step_size, 1000); > + step_size *= pll->in.ssc_spread; > + step_size = div_u64(step_size, 1000); > + step_size *= (pll->in.ssc_adj_period + 1); > + > + rem = 0; > + step_size = div_u64_rem(step_size, ssc_period + 1, &rem); > + if (rem) > + step_size++; > + > + DBG("step_size=%lld", step_size); > + > + step_size &= 0x0ffff; /* take lower 16 bits */ > + > + pll->out.ssc_step_size = step_size; > +} > + > +static void pll_14nm_dec_frac_calc(struct dsi_pll_14nm *pll) > +{ > + struct dsi_pll_input *pin = &pll->in; > + struct dsi_pll_output *pout = &pll->out; > + u64 multiplier = BIT(20); > + u64 dec_start_multiple, dec_start, pll_comp_val; > + u32 duration, div_frac_start; > + u64 vco_clk_rate = pll->vco_current_rate; > + u64 fref = pll->vco_ref_clk_rate; > + > + DBG("vco_clk_rate=%lld ref_clk_rate=%lld", vco_clk_rate, fref); > + > + dec_start_multiple = div_u64(vco_clk_rate * multiplier, fref); > + div_u64_rem(dec_start_multiple, multiplier, &div_frac_start); > + > + dec_start = div_u64(dec_start_multiple, multiplier); > + > + pout->dec_start = (u32)dec_start; > + pout->div_frac_start = div_frac_start; > + > + if (pin->plllock_cnt == 0) > + duration = 1024; > + else if (pin->plllock_cnt == 1) > + duration = 256; > + else if (pin->plllock_cnt == 2) > + duration = 128; > + else > + duration = 32; > + > + pll_comp_val = duration * dec_start_multiple; > + pll_comp_val = div_u64(pll_comp_val, multiplier); > + do_div(pll_comp_val, 10); > + > + pout->plllock_cmp = (u32)pll_comp_val; > + > + pout->pll_txclk_en = 1; > + pout->cmn_ldo_cntrl = 0x3c; > +} > + > +static u32 pll_14nm_kvco_slop(u32 vrate) > +{ > + u32 slop = 0; > + > + if (vrate > VCO_MIN_RATE && vrate <= 1800000000UL) > + slop = 600; > + else if (vrate > 1800000000UL && vrate < 2300000000UL) > + slop = 400; > + else if (vrate > 2300000000UL && vrate < VCO_MAX_RATE) > + slop = 280; > + > + return slop; > +} > + > +static void pll_14nm_calc_vco_count(struct dsi_pll_14nm *pll) > +{ > + struct dsi_pll_input *pin = &pll->in; > + struct dsi_pll_output *pout = &pll->out; > + u64 vco_clk_rate = pll->vco_current_rate; > + u64 fref = pll->vco_ref_clk_rate; > + u64 data; > + u32 cnt; > + > + data = fref * pin->vco_measure_time; > + do_div(data, 1000000); > + data &= 0x03ff; /* 10 bits */ > + data -= 2; > + pout->pll_vco_div_ref = data; > + > + data = div_u64(vco_clk_rate, 1000000); /* unit is Mhz */ > + data *= pin->vco_measure_time; > + do_div(data, 10); > + pout->pll_vco_count = data; > + > + data = fref * pin->kvco_measure_time; > + do_div(data, 1000000); > + data &= 0x03ff; /* 10 bits */ > + data -= 1; > + pout->pll_kvco_div_ref = data; > + > + cnt = pll_14nm_kvco_slop(vco_clk_rate); > + cnt *= 2; > + cnt /= 100; > + cnt *= pin->kvco_measure_time; > + pout->pll_kvco_count = cnt; > + > + pout->pll_misc1 = 16; > + pout->pll_resetsm_cntrl = 48; > + pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3; > + pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer; > + pout->pll_kvco_code = 0; > +} > + > +static void pll_db_commit_ssc(struct dsi_pll_14nm *pll) > +{ > + void __iomem *base = pll->mmio; > + struct dsi_pll_input *pin = &pll->in; > + struct dsi_pll_output *pout = &pll->out; > + u8 data; > + > + data = pin->ssc_adj_period; > + data &= 0x0ff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER1, data); > + data = (pin->ssc_adj_period >> 8); > + data &= 0x03; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER2, data); > + > + data = pout->ssc_period; > + data &= 0x0ff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER1, data); > + data = (pout->ssc_period >> 8); > + data &= 0x0ff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER2, data); > + > + data = pout->ssc_step_size; > + data &= 0x0ff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE1, data); > + data = (pout->ssc_step_size >> 8); > + data &= 0x0ff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE2, data); > + > + data = (pin->ssc_center & 0x01); > + data <<= 1; > + data |= 0x01; /* enable */ > + pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_EN_CENTER, data); > + > + wmb(); /* make sure register committed */ > +} > + > +static void pll_db_commit_common(struct dsi_pll_14nm *pll, > + struct dsi_pll_input *pin, > + struct dsi_pll_output *pout) > +{ > + void __iomem *base = pll->mmio; > + u8 data; > + > + /* confgiure the non frequency dependent pll registers */ > + data = 0; > + pll_write(base + REG_DSI_14nm_PHY_PLL_SYSCLK_EN_RESET, data); > + > + data = pout->pll_txclk_en; > + pll_write(base + REG_DSI_14nm_PHY_PLL_TXCLK_EN, data); > + > + data = pout->pll_resetsm_cntrl; > + pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL, data); > + data = pout->pll_resetsm_cntrl2; > + pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL2, data); > + data = pout->pll_resetsm_cntrl5; > + pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL5, data); > + > + data = pout->pll_vco_div_ref & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF1, data); > + data = (pout->pll_vco_div_ref >> 8) & 0x3; > + pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF2, data); > + > + data = pout->pll_kvco_div_ref & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF1, data); > + data = (pout->pll_kvco_div_ref >> 8) & 0x3; > + pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF2, data); > + > + data = pout->pll_misc1; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_MISC1, data); > + > + data = pin->pll_ie_trim; > + pll_write(base + REG_DSI_14nm_PHY_PLL_IE_TRIM, data); > + > + data = pin->pll_ip_trim; > + pll_write(base + REG_DSI_14nm_PHY_PLL_IP_TRIM, data); > + > + data = pin->pll_cpmset_cur << 3 | pin->pll_cpcset_cur; > + pll_write(base + REG_DSI_14nm_PHY_PLL_CP_SET_CUR, data); > + > + data = pin->pll_icpcset_p << 3 | pin->pll_icpcset_m; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPCSET, data); > + > + data = pin->pll_icpmset_p << 3 | pin->pll_icpcset_m; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPMSET, data); > + > + data = pin->pll_icpmset << 3 | pin->pll_icpcset; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICP_SET, data); > + > + data = pin->pll_lpf_cap2 << 4 | pin->pll_lpf_cap1; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF1, data); > + > + data = pin->pll_iptat_trim; > + pll_write(base + REG_DSI_14nm_PHY_PLL_IPTAT_TRIM, data); > + > + data = pin->pll_c3ctrl | pin->pll_r3ctrl << 4; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_CRCTRL, data); > +} > + > +static void pll_14nm_software_reset(struct dsi_pll_14nm *pll_14nm) > +{ > + void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > + > + /* de assert pll start and apply pll sw reset */ > + > + /* stop pll */ > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0); > + > + /* pll sw reset */ > + pll_write_udelay(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0x20, 10); > + wmb(); /* make sure register committed */ > + > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0); > + wmb(); /* make sure register committed */ > +} > + > +static void pll_db_commit_14nm(struct dsi_pll_14nm *pll, > + struct dsi_pll_input *pin, > + struct dsi_pll_output *pout) > +{ > + void __iomem *base = pll->mmio; > + void __iomem *cmn_base = pll->phy_cmn_mmio; > + u8 data; > + > + DBG("DSI%d PLL", pll->id); > + > + data = pout->cmn_ldo_cntrl; > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_LDO_CNTRL, data); > + > + pll_db_commit_common(pll, pin, pout); > + > + pll_14nm_software_reset(pll); > + > + data = pin->dsiclk_sel; /* set dsiclk_sel = 1 */ > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG1, data); > + > + data = 0xff; /* data, clk, pll normal operation */ > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_0, data); > + > + /* configure the frequency dependent pll registers */ > + data = pout->dec_start; > + pll_write(base + REG_DSI_14nm_PHY_PLL_DEC_START, data); > + > + data = pout->div_frac_start & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1, data); > + data = (pout->div_frac_start >> 8) & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2, data); > + data = (pout->div_frac_start >> 16) & 0xf; > + pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3, data); > + > + data = pout->plllock_cmp & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP1, data); > + > + data = (pout->plllock_cmp >> 8) & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP2, data); > + > + data = (pout->plllock_cmp >> 16) & 0x3; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP3, data); > + > + data = pin->plllock_cnt << 1 | pin->plllock_rng << 3; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP_EN, data); > + > + data = pout->pll_vco_count & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT1, data); > + data = (pout->pll_vco_count >> 8) & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT2, data); > + > + data = pout->pll_kvco_count & 0xff; > + pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT1, data); > + data = (pout->pll_kvco_count >> 8) & 0x3; > + pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT2, data); > + > + data = (pout->pll_postdiv - 1) << 4 | pin->pll_lpf_res1; > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF2_POSTDIV, data); > + > + if (pin->ssc_en) > + pll_db_commit_ssc(pll); > + > + wmb(); /* make sure register committed */ > +} > + > +/* > + * VCO clock Callbacks > + */ > +static int dsi_pll_14nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + struct dsi_pll_input *pin = &pll_14nm->in; > + struct dsi_pll_output *pout = &pll_14nm->out; > + > + DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_14nm->id, rate, > + parent_rate); > + > + pll_14nm->vco_current_rate = rate; > + pll_14nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > + > + dsi_pll_14nm_input_init(pll_14nm); > + > + /* > + * This configures the post divider internal to the VCO. It's > + * fixed to divide by 1 for now. > + * > + * tx_band = pll_postdiv. > + * 0: divided by 1 > + * 1: divided by 2 > + * 2: divided by 4 > + * 3: divided by 8 > + */ > + pout->pll_postdiv = DSI_PLL_DEFAULT_VCO_POSTDIV; > + > + pll_14nm_dec_frac_calc(pll_14nm); > + > + if (pin->ssc_en) > + pll_14nm_ssc_calc(pll_14nm); > + > + pll_14nm_calc_vco_count(pll_14nm); > + > + /* commit the slave DSI PLL registers if we're master. Note that we > + * don't lock the slave PLL. We just ensure that the PLL/PHY > registers > + * of the master and slave are identical > + */ > + if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > + struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > + > + pll_db_commit_14nm(pll_14nm_slave, pin, pout); > + } > + > + pll_db_commit_14nm(pll_14nm, pin, pout); > + > + return 0; > +} > + > +static unsigned long dsi_pll_14nm_vco_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + void __iomem *base = pll_14nm->mmio; > + u64 vco_rate, multiplier = BIT(20); > + u32 div_frac_start; > + u32 dec_start; > + u64 ref_clk = parent_rate; > + > + dec_start = pll_read(base + REG_DSI_14nm_PHY_PLL_DEC_START); > + dec_start &= 0x0ff; > + > + DBG("dec_start = %x", dec_start); > + > + div_frac_start = (pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3) > + & 0xf) << 16; > + div_frac_start |= (pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2) > + & 0xff) << 8; > + div_frac_start |= pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1) > + & 0xff; > + > + DBG("div_frac_start = %x", div_frac_start); > + > + vco_rate = ref_clk * dec_start; > + > + vco_rate += ((ref_clk * div_frac_start) / multiplier); > + > + /* > + * Recalculating the rate from dec_start and frac_start doesn't end > up > + * the rate we originally set. Convert the freq to KHz, round it up > and > + * convert it back to MHz. > + */ > + vco_rate = DIV_ROUND_UP_ULL(vco_rate, 1000) * 1000; > + > + DBG("returning vco rate = %lu", (unsigned long)vco_rate); > + > + return (unsigned long)vco_rate; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_14nm_vco = { > + .round_rate = msm_dsi_pll_helper_clk_round_rate, > + .set_rate = dsi_pll_14nm_vco_set_rate, > + .recalc_rate = dsi_pll_14nm_vco_recalc_rate, > + .prepare = msm_dsi_pll_helper_clk_prepare, > + .unprepare = msm_dsi_pll_helper_clk_unprepare, > +}; > + > +/* > + * N1 and N2 post-divider clock callbacks > + */ > +#define div_mask(width) ((1 << (width)) - 1) > +static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw > *hw, > + unsigned long parent_rate) > +{ > + struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > + struct dsi_pll_14nm *pll_14nm = postdiv->pll; > + void __iomem *base = pll_14nm->phy_cmn_mmio; > + u8 shift = postdiv->shift; > + u8 width = postdiv->width; > + u32 val; > + > + DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, parent_rate); > + > + val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0) >> shift; > + val &= div_mask(width); > + > + return divider_recalc_rate(hw, parent_rate, val, NULL, > + postdiv->flags, width); > +} > + > +static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw, > + unsigned long rate, > + unsigned long *prate) > +{ > + struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > + struct dsi_pll_14nm *pll_14nm = postdiv->pll; > + > + DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, rate); > + > + return divider_round_rate(hw, rate, prate, NULL, > + postdiv->width, > + postdiv->flags); > +} > + > +static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned > long rate, > + unsigned long parent_rate) > +{ > + struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > + struct dsi_pll_14nm *pll_14nm = postdiv->pll; > + void __iomem *base = pll_14nm->phy_cmn_mmio; > + spinlock_t *lock = &pll_14nm->postdiv_lock; > + u8 shift = postdiv->shift; > + u8 width = postdiv->width; > + unsigned int value; > + unsigned long flags = 0; > + u32 val; > + > + DBG("DSI%d PLL parent rate=%lu parent rate %lu", pll_14nm->id, rate, > + parent_rate); > + > + value = divider_get_val(rate, parent_rate, NULL, postdiv->width, > + postdiv->flags); > + > + spin_lock_irqsave(lock, flags); > + > + val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0); > + val &= ~(div_mask(width) << shift); > + > + val |= value << shift; > + pll_write(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val); > + > + /* If we're master in dual DSI mode, then the slave PLL's > post-dividers > + * follow the master's post dividers > + */ > + if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > + struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > + void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio; > + > + pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val); > + } > + > + spin_unlock_irqrestore(lock, flags); > + > + return 0; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_14nm_postdiv = { > + .recalc_rate = dsi_pll_14nm_postdiv_recalc_rate, > + .round_rate = dsi_pll_14nm_postdiv_round_rate, > + .set_rate = dsi_pll_14nm_postdiv_set_rate, > +}; > + > +/* > + * PLL Callbacks > + */ > + > +static int dsi_pll_14nm_enable_seq(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + void __iomem *base = pll_14nm->mmio; > + void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > + bool locked; > + > + DBG(""); > + > + pll_write(base + REG_DSI_14nm_PHY_PLL_VREF_CFG1, 0x10); > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 1); > + > + locked = pll_14nm_poll_for_ready(pll_14nm, POLL_MAX_READS, > + POLL_TIMEOUT_US); > + > + if (unlikely(!locked)) > + DRM_DEV_ERROR(&pll_14nm->pdev->dev, "DSI PLL lock failed\n"); > + else > + DBG("DSI PLL lock success"); > + > + return locked ? 0 : -EINVAL; > +} > + > +static void dsi_pll_14nm_disable_seq(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > + > + DBG(""); > + > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0); > +} > + > +static void dsi_pll_14nm_save_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state; > + void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > + u32 data; > + > + data = pll_read(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0); > + > + cached_state->n1postdiv = data & 0xf; > + cached_state->n2postdiv = (data >> 4) & 0xf; > + > + DBG("DSI%d PLL save state %x %x", pll_14nm->id, > + cached_state->n1postdiv, cached_state->n2postdiv); > + > + cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > +} > + > +static int dsi_pll_14nm_restore_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state; > + void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > + u32 data; > + int ret; > + > + ret = dsi_pll_14nm_vco_set_rate(&pll->clk_hw, > + cached_state->vco_rate, 0); > + if (ret) { > + DRM_DEV_ERROR(&pll_14nm->pdev->dev, > + "restore vco rate failed. ret=%d\n", ret); > + return ret; > + } > + > + data = cached_state->n1postdiv | (cached_state->n2postdiv << 4); > + > + DBG("DSI%d PLL restore state %x %x", pll_14nm->id, > + cached_state->n1postdiv, cached_state->n2postdiv); > + > + pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data); > + > + /* also restore post-dividers for slave DSI PLL */ > + if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > + struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > + void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio; > + > + pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data); > + } > + > + return 0; > +} > + > +static int dsi_pll_14nm_set_usecase(struct msm_dsi_pll *pll, > + enum msm_dsi_phy_usecase uc) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + void __iomem *base = pll_14nm->mmio; > + u32 clkbuflr_en, bandgap = 0; > + > + switch (uc) { > + case MSM_DSI_PHY_STANDALONE: > + clkbuflr_en = 0x1; > + break; > + case MSM_DSI_PHY_MASTER: > + clkbuflr_en = 0x3; > + pll_14nm->slave = pll_14nm_list[(pll_14nm->id + 1) % DSI_MAX]; > + break; > + case MSM_DSI_PHY_SLAVE: > + clkbuflr_en = 0x0; > + bandgap = 0x3; > + break; > + default: > + return -EINVAL; > + } > + > + pll_write(base + REG_DSI_14nm_PHY_PLL_CLKBUFLR_EN, clkbuflr_en); > + if (bandgap) > + pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_BANDGAP, bandgap); > + > + pll_14nm->uc = uc; > + > + return 0; > +} > + > +static int dsi_pll_14nm_get_provider(struct msm_dsi_pll *pll, > + struct clk **byte_clk_provider, > + struct clk **pixel_clk_provider) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + struct clk_hw_onecell_data *hw_data = pll_14nm->hw_data; > + > + if (byte_clk_provider) > + *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > + if (pixel_clk_provider) > + *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > + > + return 0; > +} > + > +static void dsi_pll_14nm_destroy(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > + struct platform_device *pdev = pll_14nm->pdev; > + int num_hws = pll_14nm->num_hws; > + > + of_clk_del_provider(pdev->dev.of_node); > + > + while (num_hws--) > + clk_hw_unregister(pll_14nm->hws[num_hws]); > +} > + > +static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm > *pll_14nm, > + const char *name, > + const char *parent_name, > + unsigned long flags, > + u8 shift) > +{ > + struct dsi_pll_14nm_postdiv *pll_postdiv; > + struct device *dev = &pll_14nm->pdev->dev; > + struct clk_init_data postdiv_init = { > + .parent_names = (const char *[]) { parent_name }, > + .num_parents = 1, > + .name = name, > + .flags = flags, > + .ops = &clk_ops_dsi_pll_14nm_postdiv, > + }; > + int ret; > + > + pll_postdiv = devm_kzalloc(dev, sizeof(*pll_postdiv), GFP_KERNEL); > + if (!pll_postdiv) > + return ERR_PTR(-ENOMEM); > + > + pll_postdiv->pll = pll_14nm; > + pll_postdiv->shift = shift; > + /* both N1 and N2 postdividers are 4 bits wide */ > + pll_postdiv->width = 4; > + /* range of each divider is from 1 to 15 */ > + pll_postdiv->flags = CLK_DIVIDER_ONE_BASED; > + pll_postdiv->hw.init = &postdiv_init; > + > + ret = clk_hw_register(dev, &pll_postdiv->hw); > + if (ret) > + return ERR_PTR(ret); > + > + return &pll_postdiv->hw; > +} > + > +static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm) > +{ > + char clk_name[32], parent[32], vco_name[32]; > + struct clk_init_data vco_init = { > + .parent_names = (const char *[]){ "xo" }, > + .num_parents = 1, > + .name = vco_name, > + .flags = CLK_IGNORE_UNUSED, > + .ops = &clk_ops_dsi_pll_14nm_vco, > + }; > + struct device *dev = &pll_14nm->pdev->dev; > + struct clk_hw **hws = pll_14nm->hws; > + struct clk_hw_onecell_data *hw_data; > + struct clk_hw *hw; > + int num = 0; > + int ret; > + > + DBG("DSI%d", pll_14nm->id); > + > + hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > + NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > + GFP_KERNEL); > + if (!hw_data) > + return -ENOMEM; > + > + snprintf(vco_name, 32, "dsi%dvco_clk", pll_14nm->id); > + pll_14nm->base.clk_hw.init = &vco_init; > + > + ret = clk_hw_register(dev, &pll_14nm->base.clk_hw); > + if (ret) > + return ret; > + > + hws[num++] = &pll_14nm->base.clk_hw; > + > + snprintf(clk_name, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > + snprintf(parent, 32, "dsi%dvco_clk", pll_14nm->id); > + > + /* N1 postdiv, bits 0-3 in REG_DSI_14nm_PHY_CMN_CLK_CFG0 */ > + hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, > + CLK_SET_RATE_PARENT, 0); > + if (IS_ERR(hw)) > + return PTR_ERR(hw); > + > + hws[num++] = hw; > + > + snprintf(clk_name, 32, "dsi%dpllbyte", pll_14nm->id); > + snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > + > + /* DSI Byte clock = VCO_CLK / N1 / 8 */ > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + CLK_SET_RATE_PARENT, 1, 8); > + if (IS_ERR(hw)) > + return PTR_ERR(hw); > + > + hws[num++] = hw; > + hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > + > + snprintf(clk_name, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id); > + snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > + > + /* > + * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider > + * on the way. Don't let it set parent. > + */ > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2); > + if (IS_ERR(hw)) > + return PTR_ERR(hw); > + > + hws[num++] = hw; > + > + snprintf(clk_name, 32, "dsi%dpll", pll_14nm->id); > + snprintf(parent, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id); > + > + /* DSI pixel clock = VCO_CLK / N1 / 2 / N2 > + * This is the output of N2 post-divider, bits 4-7 in > + * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent. > + */ > + hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, 0, 4); > + if (IS_ERR(hw)) > + return PTR_ERR(hw); > + > + hws[num++] = hw; > + hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > + > + pll_14nm->num_hws = num; > + > + hw_data->num = NUM_PROVIDED_CLKS; > + pll_14nm->hw_data = hw_data; > + > + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > + pll_14nm->hw_data); > + if (ret) { > + DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device > *pdev, int id) > +{ > + struct dsi_pll_14nm *pll_14nm; > + struct msm_dsi_pll *pll; > + int ret; > + > + if (!pdev) > + return ERR_PTR(-ENODEV); > + > + pll_14nm = devm_kzalloc(&pdev->dev, sizeof(*pll_14nm), GFP_KERNEL); > + if (!pll_14nm) > + return ERR_PTR(-ENOMEM); > + > + DBG("PLL%d", id); > + > + pll_14nm->pdev = pdev; > + pll_14nm->id = id; > + pll_14nm_list[id] = pll_14nm; > + > + pll_14nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > + if (IS_ERR_OR_NULL(pll_14nm->phy_cmn_mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + pll_14nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > + if (IS_ERR_OR_NULL(pll_14nm->mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + spin_lock_init(&pll_14nm->postdiv_lock); > + > + pll = &pll_14nm->base; > + pll->min_rate = VCO_MIN_RATE; > + pll->max_rate = VCO_MAX_RATE; > + pll->get_provider = dsi_pll_14nm_get_provider; > + pll->destroy = dsi_pll_14nm_destroy; > + pll->disable_seq = dsi_pll_14nm_disable_seq; > + pll->save_state = dsi_pll_14nm_save_state; > + pll->restore_state = dsi_pll_14nm_restore_state; > + pll->set_usecase = dsi_pll_14nm_set_usecase; > + > + pll_14nm->vco_delay = 1; > + > + pll->en_seq_cnt = 1; > + pll->enable_seqs[0] = dsi_pll_14nm_enable_seq; > + > + ret = pll_14nm_register(pll_14nm); > + if (ret) { > + DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > + return ERR_PTR(ret); > + } > + > + return pll; > +} > + > static void dsi_14nm_dphy_set_timing(struct msm_dsi_phy *phy, > struct msm_dsi_dphy_timing *timing, > int lane_idx) > diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c > index 5bf79de0da67..2f502efa4dd5 100644 > --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c > +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c > @@ -3,9 +3,646 @@ > * Copyright (c) 2015, The Linux Foundation. All rights reserved. > */ > > +#include > +#include > + > #include "dsi_phy.h" > +#include "dsi_pll.h" > #include "dsi.xml.h" > > +/* > + * DSI PLL 28nm - clock diagram (eg: DSI0): > + * > + * dsi0analog_postdiv_clk > + * | dsi0indirect_path_div2_clk > + * | | > + * +------+ | +----+ | |\ dsi0byte_mux > + * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ | > + * | +------+ +----+ | m| | +----+ > + * | | u|--o--| /4 |-- > dsi0pllbyte > + * | | x| +----+ > + * o--------------------------| / > + * | |/ > + * | +------+ > + * o----------| DIV3 |------------------------- dsi0pll > + * +------+ > + */ > + > +#define POLL_MAX_READS 10 > +#define POLL_TIMEOUT_US 50 > + > +#define NUM_PROVIDED_CLKS 2 > + > +#define VCO_REF_CLK_RATE 19200000 > +#define VCO_MIN_RATE 350000000 > +#define VCO_MAX_RATE 750000000 > + > +#define DSI_BYTE_PLL_CLK 0 > +#define DSI_PIXEL_PLL_CLK 1 > + > +#define LPFR_LUT_SIZE 10 > +struct lpfr_cfg { > + unsigned long vco_rate; > + u32 resistance; > +}; > + > +/* Loop filter resistance: */ > +static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = { > + { 479500000, 8 }, > + { 480000000, 11 }, > + { 575500000, 8 }, > + { 576000000, 12 }, > + { 610500000, 8 }, > + { 659500000, 9 }, > + { 671500000, 10 }, > + { 672000000, 14 }, > + { 708500000, 10 }, > + { 750000000, 11 }, > +}; > + > +struct pll_28nm_cached_state { > + unsigned long vco_rate; > + u8 postdiv3; > + u8 postdiv1; > + u8 byte_mux; > +}; > + > +struct dsi_pll_28nm { > + struct msm_dsi_pll base; > + > + int id; > + struct platform_device *pdev; > + void __iomem *mmio; > + > + int vco_delay; > + > + /* private clocks: */ > + struct clk *clks[NUM_DSI_CLOCKS_MAX]; > + u32 num_clks; > + > + /* clock-provider: */ > + struct clk *provided_clks[NUM_PROVIDED_CLKS]; > + struct clk_onecell_data clk_data; > + > + struct pll_28nm_cached_state cached_state; > +}; > + > +#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base) > + > +static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, > + u32 nb_tries, u32 timeout_us) > +{ > + bool pll_locked = false; > + u32 val; > + > + while (nb_tries--) { > + val = pll_read(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_STATUS); > + pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY); > + > + if (pll_locked) > + break; > + > + udelay(timeout_us); > + } > + DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > + > + return pll_locked; > +} > + > +static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm) > +{ > + void __iomem *base = pll_28nm->mmio; > + > + /* > + * Add HW recommended delays after toggling the software > + * reset bit off and back on. > + */ > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, > + DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1); > +} > + > +/* > + * Clock Callbacks > + */ > +static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct device *dev = &pll_28nm->pdev->dev; > + void __iomem *base = pll_28nm->mmio; > + unsigned long div_fbx1000, gen_vco_clk; > + u32 refclk_cfg, frac_n_mode, frac_n_value; > + u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3; > + u32 cal_cfg10, cal_cfg11; > + u32 rem; > + int i; > + > + VERB("rate=%lu, parent's=%lu", rate, parent_rate); > + > + /* Force postdiv2 to be div-4 */ > + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3); > + > + /* Configure the Loop filter resistance */ > + for (i = 0; i < LPFR_LUT_SIZE; i++) > + if (rate <= lpfr_lut[i].vco_rate) > + break; > + if (i == LPFR_LUT_SIZE) { > + DRM_DEV_ERROR(dev, "unable to get loop filter resistance. > vco=%lu\n", > + rate); > + return -EINVAL; > + } > + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, > lpfr_lut[i].resistance); > + > + /* Loop filter capacitance values : c1 and c2 */ > + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70); > + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15); > + > + rem = rate % VCO_REF_CLK_RATE; > + if (rem) { > + refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; > + frac_n_mode = 1; > + div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500); > + gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500); > + } else { > + refclk_cfg = 0x0; > + frac_n_mode = 0; > + div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000); > + gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000); > + } > + > + DBG("refclk_cfg = %d", refclk_cfg); > + > + rem = div_fbx1000 % 1000; > + frac_n_value = (rem << 16) / 1000; > + > + DBG("div_fb = %lu", div_fbx1000); > + DBG("frac_n_value = %d", frac_n_value); > + > + DBG("Generated VCO Clock: %lu", gen_vco_clk); > + rem = 0; > + sdm_cfg1 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1); > + sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK; > + if (frac_n_mode) { > + sdm_cfg0 = 0x0; > + sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0); > + sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET( > + (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); > + sdm_cfg3 = frac_n_value >> 8; > + sdm_cfg2 = frac_n_value & 0xff; > + } else { > + sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP; > + sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV( > + (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); > + sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0); > + sdm_cfg2 = 0; > + sdm_cfg3 = 0; > + } > + > + DBG("sdm_cfg0=%d", sdm_cfg0); > + DBG("sdm_cfg1=%d", sdm_cfg1); > + DBG("sdm_cfg2=%d", sdm_cfg2); > + DBG("sdm_cfg3=%d", sdm_cfg3); > + > + cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000)); > + cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000); > + DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11); > + > + pll_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06); > + pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); > + > + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1); > + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2, > + DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); > + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3, > + DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); > + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00); > + > + /* Add hardware recommended delay for correct PLL configuration */ > + if (pll_28nm->vco_delay) > + udelay(pll_28nm->vco_delay); > + > + pll_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg); > + pll_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00); > + pll_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31); > + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff); > + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff); > + pll_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20); > + > + return 0; > +} > + > +static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, > + POLL_TIMEOUT_US); > +} > + > +static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + void __iomem *base = pll_28nm->mmio; > + u32 sdm0, doubler, sdm_byp_div; > + u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; > + u32 ref_clk = VCO_REF_CLK_RATE; > + unsigned long vco_rate; > + > + VERB("parent_rate=%lu", parent_rate); > + > + /* Check to see if the ref clk doubler is enabled */ > + doubler = pll_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) & > + DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; > + ref_clk += (doubler * VCO_REF_CLK_RATE); > + > + /* see if it is integer mode or sdm mode */ > + sdm0 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0); > + if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) { > + /* integer mode */ > + sdm_byp_div = FIELD( > + pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0), > + DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1; > + vco_rate = ref_clk * sdm_byp_div; > + } else { > + /* sdm mode */ > + sdm_dc_off = FIELD( > + pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1), > + DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET); > + DBG("sdm_dc_off = %d", sdm_dc_off); > + sdm2 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2), > + DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0); > + sdm3 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3), > + DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8); > + sdm_freq_seed = (sdm3 << 8) | sdm2; > + DBG("sdm_freq_seed = %d", sdm_freq_seed); > + > + vco_rate = (ref_clk * (sdm_dc_off + 1)) + > + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); > + DBG("vco rate = %lu", vco_rate); > + } > + > + DBG("returning vco rate = %lu", vco_rate); > + > + return vco_rate; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_28nm_vco = { > + .round_rate = msm_dsi_pll_helper_clk_round_rate, > + .set_rate = dsi_pll_28nm_clk_set_rate, > + .recalc_rate = dsi_pll_28nm_clk_recalc_rate, > + .prepare = msm_dsi_pll_helper_clk_prepare, > + .unprepare = msm_dsi_pll_helper_clk_unprepare, > + .is_enabled = dsi_pll_28nm_clk_is_enabled, > +}; > + > +/* > + * PLL Callbacks > + */ > +static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct device *dev = &pll_28nm->pdev->dev; > + void __iomem *base = pll_28nm->mmio; > + u32 max_reads = 5, timeout_us = 100; > + bool locked; > + u32 val; > + int i; > + > + DBG("id=%d", pll_28nm->id); > + > + pll_28nm_software_reset(pll_28nm); > + > + /* > + * PLL power up sequence. > + * Add necessary delays recommended by hardware. > + */ > + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); > + > + for (i = 0; i < 2; i++) { > + /* DSI Uniphy lock detect setting */ > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, > + 0x0c, 100); > + pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); > + > + /* poll for PLL ready status */ > + locked = pll_28nm_poll_for_ready(pll_28nm, > + max_reads, timeout_us); > + if (locked) > + break; > + > + pll_28nm_software_reset(pll_28nm); > + > + /* > + * PLL power up sequence. > + * Add necessary delays recommended by hardware. > + */ > + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250); > + > + val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); > + } > + > + if (unlikely(!locked)) > + DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > + else > + DBG("DSI PLL Lock success"); > + > + return locked ? 0 : -EINVAL; > +} > + > +static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct device *dev = &pll_28nm->pdev->dev; > + void __iomem *base = pll_28nm->mmio; > + bool locked; > + u32 max_reads = 10, timeout_us = 50; > + u32 val; > + > + DBG("id=%d", pll_28nm->id); > + > + pll_28nm_software_reset(pll_28nm); > + > + /* > + * PLL power up sequence. > + * Add necessary delays recommended by hardware. > + */ > + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500); > + > + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > + > + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B | > + DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > + > + /* DSI PLL toggle lock detect setting */ > + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500); > + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512); > + > + locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); > + > + if (unlikely(!locked)) > + DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > + else > + DBG("DSI PLL lock success"); > + > + return locked ? 0 : -EINVAL; > +} > + > +static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + DBG("id=%d", pll_28nm->id); > + pll_write(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00); > +} > + > +static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > + void __iomem *base = pll_28nm->mmio; > + > + cached_state->postdiv3 = > + pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG); > + cached_state->postdiv1 = > + pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG); > + cached_state->byte_mux = pll_read(base + > REG_DSI_28nm_PHY_PLL_VREG_CFG); > + if (dsi_pll_28nm_clk_is_enabled(&pll->clk_hw)) > + cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > + else > + cached_state->vco_rate = 0; > +} > + > +static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > + void __iomem *base = pll_28nm->mmio; > + int ret; > + > + ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw, > + cached_state->vco_rate, 0); > + if (ret) { > + DRM_DEV_ERROR(&pll_28nm->pdev->dev, > + "restore vco rate failed. ret=%d\n", ret); > + return ret; > + } > + > + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, > + cached_state->postdiv3); > + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, > + cached_state->postdiv1); > + pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG, > + cached_state->byte_mux); > + > + return 0; > +} > + > +static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll, > + struct clk **byte_clk_provider, > + struct clk **pixel_clk_provider) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + if (byte_clk_provider) > + *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK]; > + if (pixel_clk_provider) > + *pixel_clk_provider = > + pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK]; > + > + return 0; > +} > + > +static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + int i; > + > + msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev, > + pll_28nm->clks, pll_28nm->num_clks); > + > + for (i = 0; i < NUM_PROVIDED_CLKS; i++) > + pll_28nm->provided_clks[i] = NULL; > + > + pll_28nm->num_clks = 0; > + pll_28nm->clk_data.clks = NULL; > + pll_28nm->clk_data.clk_num = 0; > +} > + > +static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) > +{ > + char clk_name[32], parent1[32], parent2[32], vco_name[32]; > + struct clk_init_data vco_init = { > + .parent_names = (const char *[]){ "xo" }, > + .num_parents = 1, > + .name = vco_name, > + .flags = CLK_IGNORE_UNUSED, > + .ops = &clk_ops_dsi_pll_28nm_vco, > + }; > + struct device *dev = &pll_28nm->pdev->dev; > + struct clk **clks = pll_28nm->clks; > + struct clk **provided_clks = pll_28nm->provided_clks; > + int num = 0; > + int ret; > + > + DBG("%d", pll_28nm->id); > + > + snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); > + pll_28nm->base.clk_hw.init = &vco_init; > + clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw); > + > + snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); > + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > + clks[num++] = clk_register_divider(dev, clk_name, > + parent1, CLK_SET_RATE_PARENT, > + pll_28nm->mmio + > + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, > + 0, 4, 0, NULL); > + > + snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); > + snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); > + clks[num++] = clk_register_fixed_factor(dev, clk_name, > + parent1, CLK_SET_RATE_PARENT, > + 1, 2); > + > + snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); > + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > + clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] = > + clk_register_divider(dev, clk_name, > + parent1, 0, pll_28nm->mmio + > + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, > + 0, 8, 0, NULL); > + > + snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id); > + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > + snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); > + clks[num++] = clk_register_mux(dev, clk_name, > + ((const char *[]){ > + parent1, parent2 > + }), 2, CLK_SET_RATE_PARENT, pll_28nm->mmio + > + REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); > + > + snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); > + snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id); > + clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] = > + clk_register_fixed_factor(dev, clk_name, > + parent1, CLK_SET_RATE_PARENT, 1, 4); > + > + pll_28nm->num_clks = num; > + > + pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS; > + pll_28nm->clk_data.clks = provided_clks; > + > + ret = of_clk_add_provider(dev->of_node, > + of_clk_src_onecell_get, &pll_28nm->clk_data); > + if (ret) { > + DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device > *pdev, > + enum msm_dsi_phy_type type, int id) > +{ > + struct dsi_pll_28nm *pll_28nm; > + struct msm_dsi_pll *pll; > + int ret; > + > + if (!pdev) > + return ERR_PTR(-ENODEV); > + > + pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); > + if (!pll_28nm) > + return ERR_PTR(-ENOMEM); > + > + pll_28nm->pdev = pdev; > + pll_28nm->id = id; > + > + pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > + if (IS_ERR_OR_NULL(pll_28nm->mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__); > + return ERR_PTR(-ENOMEM); > + } > + > + pll = &pll_28nm->base; > + pll->min_rate = VCO_MIN_RATE; > + pll->max_rate = VCO_MAX_RATE; > + pll->get_provider = dsi_pll_28nm_get_provider; > + pll->destroy = dsi_pll_28nm_destroy; > + pll->disable_seq = dsi_pll_28nm_disable_seq; > + pll->save_state = dsi_pll_28nm_save_state; > + pll->restore_state = dsi_pll_28nm_restore_state; > + > + if (type == MSM_DSI_PHY_28NM_HPM) { > + pll_28nm->vco_delay = 1; > + > + pll->en_seq_cnt = 3; > + pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_hpm; > + pll->enable_seqs[1] = dsi_pll_28nm_enable_seq_hpm; > + pll->enable_seqs[2] = dsi_pll_28nm_enable_seq_hpm; > + } else if (type == MSM_DSI_PHY_28NM_LP) { > + pll_28nm->vco_delay = 1000; > + > + pll->en_seq_cnt = 1; > + pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp; > + } else { > + DRM_DEV_ERROR(&pdev->dev, "phy type (%d) is not 28nm\n", type); > + return ERR_PTR(-EINVAL); > + } > + > + ret = pll_28nm_register(pll_28nm); > + if (ret) { > + DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > + return ERR_PTR(ret); > + } > + > + return pll; > +} > + > + > static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, > struct msm_dsi_dphy_timing *timing) > { > diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c > index 5d33de27a0f4..4a40513057e8 100644 > --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c > +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c > @@ -3,11 +3,530 @@ > * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. > */ > > +#include > #include > > #include "dsi_phy.h" > +#include "dsi_pll.h" > #include "dsi.xml.h" > > +/* > + * DSI PLL 28nm (8960/A family) - clock diagram (eg: DSI1): > + * > + * > + * +------+ > + * dsi1vco_clk ----o-----| DIV1 |---dsi1pllbit (not exposed as clock) > + * F * byte_clk | +------+ > + * | bit clock divider (F / 8) > + * | > + * | +------+ > + * o-----| DIV2 |---dsi0pllbyte---o---> To byte RCG > + * | +------+ | (sets parent > rate) > + * | byte clock divider (F) | > + * | | > + * | o---> To esc RCG > + * | (doesn't set > parent rate) > + * | > + * | +------+ > + * o-----| DIV3 |----dsi0pll------o---> To dsi RCG > + * +------+ | (sets parent > rate) > + * dsi clock divider (F * magic) | > + * | > + * o---> To pixel rcg > + * (doesn't set > parent rate) > + */ > + > +#define POLL_MAX_READS 8000 > +#define POLL_TIMEOUT_US 1 > + > +#define NUM_PROVIDED_CLKS 2 > + > +#define VCO_REF_CLK_RATE 27000000 > +#define VCO_MIN_RATE 600000000 > +#define VCO_MAX_RATE 1200000000 > + > +#define DSI_BYTE_PLL_CLK 0 > +#define DSI_PIXEL_PLL_CLK 1 > + > +#define VCO_PREF_DIV_RATIO 27 > + > +struct pll_28nm_cached_state { > + unsigned long vco_rate; > + u8 postdiv3; > + u8 postdiv2; > + u8 postdiv1; > +}; > + > +struct clk_bytediv { > + struct clk_hw hw; > + void __iomem *reg; > +}; > + > +struct dsi_pll_28nm { > + struct msm_dsi_pll base; > + > + int id; > + struct platform_device *pdev; > + void __iomem *mmio; > + > + /* custom byte clock divider */ > + struct clk_bytediv *bytediv; > + > + /* private clocks: */ > + struct clk *clks[NUM_DSI_CLOCKS_MAX]; > + u32 num_clks; > + > + /* clock-provider: */ > + struct clk *provided_clks[NUM_PROVIDED_CLKS]; > + struct clk_onecell_data clk_data; > + > + struct pll_28nm_cached_state cached_state; > +}; > + > +#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base) > + > +static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, > + int nb_tries, int timeout_us) > +{ > + bool pll_locked = false; > + u32 val; > + > + while (nb_tries--) { > + val = pll_read(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_RDY); > + pll_locked = !!(val & DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY); > + > + if (pll_locked) > + break; > + > + udelay(timeout_us); > + } > + DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > + > + return pll_locked; > +} > + > +/* > + * Clock Callbacks > + */ > +static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + void __iomem *base = pll_28nm->mmio; > + u32 val, temp, fb_divider; > + > + DBG("rate=%lu, parent's=%lu", rate, parent_rate); > + > + temp = rate / 10; > + val = VCO_REF_CLK_RATE / 10; > + fb_divider = (temp * VCO_PREF_DIV_RATIO) / val; > + fb_divider = fb_divider / 2 - 1; > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1, > + fb_divider & 0xff); > + > + val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2); > + > + val |= (fb_divider >> 8) & 0x07; > + > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2, > + val); > + > + val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3); > + > + val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f; > + > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3, > + val); > + > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6, > + 0xf); > + > + val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > + val |= 0x7 << 4; > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, > + val); > + > + return 0; > +} > + > +static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, > + POLL_TIMEOUT_US); > +} > + > +static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + void __iomem *base = pll_28nm->mmio; > + unsigned long vco_rate; > + u32 status, fb_divider, temp, ref_divider; > + > + VERB("parent_rate=%lu", parent_rate); > + > + status = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0); > + > + if (status & DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE) { > + fb_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1); > + fb_divider &= 0xff; > + temp = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2) & 0x07; > + fb_divider = (temp << 8) | fb_divider; > + fb_divider += 1; > + > + ref_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3); > + ref_divider &= 0x3f; > + ref_divider += 1; > + > + /* multiply by 2 */ > + vco_rate = (parent_rate / ref_divider) * fb_divider * 2; > + } else { > + vco_rate = 0; > + } > + > + DBG("returning vco rate = %lu", vco_rate); > + > + return vco_rate; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_28nm_vco = { > + .round_rate = msm_dsi_pll_helper_clk_round_rate, > + .set_rate = dsi_pll_28nm_clk_set_rate, > + .recalc_rate = dsi_pll_28nm_clk_recalc_rate, > + .prepare = msm_dsi_pll_helper_clk_prepare, > + .unprepare = msm_dsi_pll_helper_clk_unprepare, > + .is_enabled = dsi_pll_28nm_clk_is_enabled, > +}; > + > +/* > + * Custom byte clock divier clk_ops > + * > + * This clock is the entry point to configuring the PLL. The user (dsi > host) > + * will set this clock's rate to the desired byte clock rate. The VCO > lock > + * frequency is a multiple of the byte clock rate. The multiplication > factor > + * (shown as F in the diagram above) is a function of the byte clock > rate. > + * > + * This custom divider clock ensures that its parent (VCO) is set to > the > + * desired rate, and that the byte clock postdivider (POSTDIV2) is > configured > + * accordingly > + */ > +#define to_clk_bytediv(_hw) container_of(_hw, struct clk_bytediv, hw) > + > +static unsigned long clk_bytediv_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct clk_bytediv *bytediv = to_clk_bytediv(hw); > + unsigned int div; > + > + div = pll_read(bytediv->reg) & 0xff; > + > + return parent_rate / (div + 1); > +} > + > +/* find multiplication factor(wrt byte clock) at which the VCO should > be set */ > +static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate) > +{ > + unsigned long bit_mhz; > + > + /* convert to bit clock in Mhz */ > + bit_mhz = (byte_clk_rate * 8) / 1000000; > + > + if (bit_mhz < 125) > + return 64; > + else if (bit_mhz < 250) > + return 32; > + else if (bit_mhz < 600) > + return 16; > + else > + return 8; > +} > + > +static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long *prate) > +{ > + unsigned long best_parent; > + unsigned int factor; > + > + factor = get_vco_mul_factor(rate); > + > + best_parent = rate * factor; > + *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); > + > + return *prate / factor; > +} > + > +static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct clk_bytediv *bytediv = to_clk_bytediv(hw); > + u32 val; > + unsigned int factor; > + > + factor = get_vco_mul_factor(rate); > + > + val = pll_read(bytediv->reg); > + val |= (factor - 1) & 0xff; > + pll_write(bytediv->reg, val); > + > + return 0; > +} > + > +/* Our special byte clock divider ops */ > +static const struct clk_ops clk_bytediv_ops = { > + .round_rate = clk_bytediv_round_rate, > + .set_rate = clk_bytediv_set_rate, > + .recalc_rate = clk_bytediv_recalc_rate, > +}; > + > +/* > + * PLL Callbacks > + */ > +static int dsi_pll_28nm_enable_seq(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct device *dev = &pll_28nm->pdev->dev; > + void __iomem *base = pll_28nm->mmio; > + bool locked; > + unsigned int bit_div, byte_div; > + int max_reads = 1000, timeout_us = 100; > + u32 val; > + > + DBG("id=%d", pll_28nm->id); > + > + /* > + * before enabling the PLL, configure the bit clock divider since we > + * don't expose it as a clock to the outside world > + * 1: read back the byte clock divider that should already be set > + * 2: divide by 8 to get bit clock divider > + * 3: write it to POSTDIV1 > + */ > + val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9); > + byte_div = val + 1; > + bit_div = byte_div / 8; > + > + val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > + val &= ~0xf; > + val |= (bit_div - 1); > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, val); > + > + /* enable the PLL */ > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, > + DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE); > + > + locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); > + > + if (unlikely(!locked)) > + DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > + else > + DBG("DSI PLL lock success"); > + > + return locked ? 0 : -EINVAL; > +} > + > +static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + DBG("id=%d", pll_28nm->id); > + pll_write(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, 0x00); > +} > + > +static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > + void __iomem *base = pll_28nm->mmio; > + > + cached_state->postdiv3 = > + pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10); > + cached_state->postdiv2 = > + pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9); > + cached_state->postdiv1 = > + pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > + > + cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > +} > + > +static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > + void __iomem *base = pll_28nm->mmio; > + int ret; > + > + ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw, > + cached_state->vco_rate, 0); > + if (ret) { > + DRM_DEV_ERROR(&pll_28nm->pdev->dev, > + "restore vco rate failed. ret=%d\n", ret); > + return ret; > + } > + > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10, > + cached_state->postdiv3); > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9, > + cached_state->postdiv2); > + pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, > + cached_state->postdiv1); > + > + return 0; > +} > + > +static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll, > + struct clk **byte_clk_provider, > + struct clk **pixel_clk_provider) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + if (byte_clk_provider) > + *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK]; > + if (pixel_clk_provider) > + *pixel_clk_provider = > + pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK]; > + > + return 0; > +} > + > +static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > + > + msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev, > + pll_28nm->clks, pll_28nm->num_clks); > +} > + > +static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) > +{ > + char *clk_name, *parent_name, *vco_name; > + struct clk_init_data vco_init = { > + .parent_names = (const char *[]){ "pxo" }, > + .num_parents = 1, > + .flags = CLK_IGNORE_UNUSED, > + .ops = &clk_ops_dsi_pll_28nm_vco, > + }; > + struct device *dev = &pll_28nm->pdev->dev; > + struct clk **clks = pll_28nm->clks; > + struct clk **provided_clks = pll_28nm->provided_clks; > + struct clk_bytediv *bytediv; > + struct clk_init_data bytediv_init = { }; > + int ret, num = 0; > + > + DBG("%d", pll_28nm->id); > + > + bytediv = devm_kzalloc(dev, sizeof(*bytediv), GFP_KERNEL); > + if (!bytediv) > + return -ENOMEM; > + > + vco_name = devm_kzalloc(dev, 32, GFP_KERNEL); > + if (!vco_name) > + return -ENOMEM; > + > + parent_name = devm_kzalloc(dev, 32, GFP_KERNEL); > + if (!parent_name) > + return -ENOMEM; > + > + clk_name = devm_kzalloc(dev, 32, GFP_KERNEL); > + if (!clk_name) > + return -ENOMEM; > + > + pll_28nm->bytediv = bytediv; > + > + snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); > + vco_init.name = vco_name; > + > + pll_28nm->base.clk_hw.init = &vco_init; > + > + clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw); > + > + /* prepare and register bytediv */ > + bytediv->hw.init = &bytediv_init; > + bytediv->reg = pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_9; > + > + snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->id); > + snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); > + > + bytediv_init.name = clk_name; > + bytediv_init.ops = &clk_bytediv_ops; > + bytediv_init.flags = CLK_SET_RATE_PARENT; > + bytediv_init.parent_names = (const char * const *) &parent_name; > + bytediv_init.num_parents = 1; > + > + /* DIV2 */ > + clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] = > + clk_register(dev, &bytediv->hw); > + > + snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); > + /* DIV3 */ > + clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] = > + clk_register_divider(dev, clk_name, > + parent_name, 0, pll_28nm->mmio + > + REG_DSI_28nm_8960_PHY_PLL_CTRL_10, > + 0, 8, 0, NULL); > + > + pll_28nm->num_clks = num; > + > + pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS; > + pll_28nm->clk_data.clks = provided_clks; > + > + ret = of_clk_add_provider(dev->of_node, > + of_clk_src_onecell_get, &pll_28nm->clk_data); > + if (ret) { > + DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device > *pdev, > + int id) > +{ > + struct dsi_pll_28nm *pll_28nm; > + struct msm_dsi_pll *pll; > + int ret; > + > + if (!pdev) > + return ERR_PTR(-ENODEV); > + > + pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); > + if (!pll_28nm) > + return ERR_PTR(-ENOMEM); > + > + pll_28nm->pdev = pdev; > + pll_28nm->id = id + 1; > + > + pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > + if (IS_ERR_OR_NULL(pll_28nm->mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__); > + return ERR_PTR(-ENOMEM); > + } > + > + pll = &pll_28nm->base; > + pll->min_rate = VCO_MIN_RATE; > + pll->max_rate = VCO_MAX_RATE; > + pll->get_provider = dsi_pll_28nm_get_provider; > + pll->destroy = dsi_pll_28nm_destroy; > + pll->disable_seq = dsi_pll_28nm_disable_seq; > + pll->save_state = dsi_pll_28nm_save_state; > + pll->restore_state = dsi_pll_28nm_restore_state; > + > + pll->en_seq_cnt = 1; > + pll->enable_seqs[0] = dsi_pll_28nm_enable_seq; > + > + ret = pll_28nm_register(pll_28nm); > + if (ret) { > + DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > + return ERR_PTR(ret); > + } > + > + return pll; > +} > + > static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy, > struct msm_dsi_dphy_timing *timing) > { > diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c > index cbfeec860e69..f9af9d70b56a 100644 > --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c > +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c > @@ -3,11 +3,916 @@ > * Copyright (c) 2018, The Linux Foundation > */ > > +#include > +#include > #include > > +#include "dsi_pll.h" > #include "dsi_phy.h" > #include "dsi.xml.h" > > +/* > + * DSI PLL 7nm - clock diagram (eg: DSI0): TODO: updated CPHY diagram > + * > + * dsi0_pll_out_div_clk dsi0_pll_bit_clk > + * | | > + * | | > + * +---------+ | +----------+ | +----+ > + * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- > dsi0_phy_pll_out_byteclk > + * +---------+ | +----------+ | +----+ > + * | | > + * | | > dsi0_pll_by_2_bit_clk > + * | | | > + * | | +----+ | |\ > dsi0_pclk_mux > + * | |--| /2 |--o--| \ | > + * | | +----+ | \ > | +---------+ > + * | --------------| > |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk > + * |------------------------------| / > +---------+ > + * | +-----+ | / > + * -----------| /4? |--o----------|/ > + * +-----+ | | > + * | > |dsiclk_sel > + * | > + * > dsi0_pll_post_out_div_clk > + */ > + > +#define DSI_BYTE_PLL_CLK 0 > +#define DSI_PIXEL_PLL_CLK 1 > +#define NUM_PROVIDED_CLKS 2 > + > +#define VCO_REF_CLK_RATE 19200000 > + > +struct dsi_pll_regs { > + u32 pll_prop_gain_rate; > + u32 pll_lockdet_rate; > + u32 decimal_div_start; > + u32 frac_div_start_low; > + u32 frac_div_start_mid; > + u32 frac_div_start_high; > + u32 pll_clock_inverters; > + u32 ssc_stepsize_low; > + u32 ssc_stepsize_high; > + u32 ssc_div_per_low; > + u32 ssc_div_per_high; > + u32 ssc_adjper_low; > + u32 ssc_adjper_high; > + u32 ssc_control; > +}; > + > +struct dsi_pll_config { > + u32 ref_freq; > + bool div_override; > + u32 output_div; > + bool ignore_frac; > + bool disable_prescaler; > + bool enable_ssc; > + bool ssc_center; > + u32 dec_bits; > + u32 frac_bits; > + u32 lock_timer; > + u32 ssc_freq; > + u32 ssc_offset; > + u32 ssc_adj_per; > + u32 thresh_cycles; > + u32 refclk_cycles; > +}; > + > +struct pll_7nm_cached_state { > + unsigned long vco_rate; > + u8 bit_clk_div; > + u8 pix_clk_div; > + u8 pll_out_div; > + u8 pll_mux; > +}; > + > +struct dsi_pll_7nm { > + struct msm_dsi_pll base; > + > + int id; > + struct platform_device *pdev; > + > + void __iomem *phy_cmn_mmio; > + void __iomem *mmio; > + > + u64 vco_ref_clk_rate; > + u64 vco_current_rate; > + > + /* protects REG_DSI_7nm_PHY_CMN_CLK_CFG0 register */ > + spinlock_t postdiv_lock; > + > + int vco_delay; > + struct dsi_pll_config pll_configuration; > + struct dsi_pll_regs reg_setup; > + > + /* private clocks: */ > + struct clk_hw *out_div_clk_hw; > + struct clk_hw *bit_clk_hw; > + struct clk_hw *byte_clk_hw; > + struct clk_hw *by_2_bit_clk_hw; > + struct clk_hw *post_out_div_clk_hw; > + struct clk_hw *pclk_mux_hw; > + struct clk_hw *out_dsiclk_hw; > + > + /* clock-provider: */ > + struct clk_hw_onecell_data *hw_data; > + > + struct pll_7nm_cached_state cached_state; > + > + enum msm_dsi_phy_usecase uc; > + struct dsi_pll_7nm *slave; > +}; > + > +#define to_pll_7nm(x) container_of(x, struct dsi_pll_7nm, base) > + > +/* > + * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > + * mode, where the master PLL's clk_ops needs access the slave's > private data > + */ > +static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX]; > + > +static void dsi_pll_setup_config(struct dsi_pll_7nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + > + config->ref_freq = pll->vco_ref_clk_rate; > + config->output_div = 1; > + config->dec_bits = 8; > + config->frac_bits = 18; > + config->lock_timer = 64; > + config->ssc_freq = 31500; > + config->ssc_offset = 4800; > + config->ssc_adj_per = 2; > + config->thresh_cycles = 32; > + config->refclk_cycles = 256; > + > + config->div_override = false; > + config->ignore_frac = false; > + config->disable_prescaler = false; > + > + /* TODO: ssc enable */ > + config->enable_ssc = false; > + config->ssc_center = 0; > +} > + > +static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + u64 fref = pll->vco_ref_clk_rate; > + u64 pll_freq; > + u64 divider; > + u64 dec, dec_multiple; > + u32 frac; > + u64 multiplier; > + > + pll_freq = pll->vco_current_rate; > + > + if (config->disable_prescaler) > + divider = fref; > + else > + divider = fref * 2; > + > + multiplier = 1 << config->frac_bits; > + dec_multiple = div_u64(pll_freq * multiplier, divider); > + div_u64_rem(dec_multiple, multiplier, &frac); > + > + dec = div_u64(dec_multiple, multiplier); > + > + if (pll->base.type != MSM_DSI_PHY_7NM_V4_1) > + regs->pll_clock_inverters = 0x28; > + else if (pll_freq <= 1000000000ULL) > + regs->pll_clock_inverters = 0xa0; > + else if (pll_freq <= 2500000000ULL) > + regs->pll_clock_inverters = 0x20; > + else if (pll_freq <= 3020000000ULL) > + regs->pll_clock_inverters = 0x00; > + else > + regs->pll_clock_inverters = 0x40; > + > + regs->pll_lockdet_rate = config->lock_timer; > + regs->decimal_div_start = dec; > + regs->frac_div_start_low = (frac & 0xff); > + regs->frac_div_start_mid = (frac & 0xff00) >> 8; > + regs->frac_div_start_high = (frac & 0x30000) >> 16; > +} > + > +#define SSC_CENTER BIT(0) > +#define SSC_EN BIT(1) > + > +static void dsi_pll_calc_ssc(struct dsi_pll_7nm *pll) > +{ > + struct dsi_pll_config *config = &pll->pll_configuration; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + u32 ssc_per; > + u32 ssc_mod; > + u64 ssc_step_size; > + u64 frac; > + > + if (!config->enable_ssc) { > + DBG("SSC not enabled\n"); > + return; > + } > + > + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - > 1; > + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); > + ssc_per -= ssc_mod; > + > + frac = regs->frac_div_start_low | > + (regs->frac_div_start_mid << 8) | > + (regs->frac_div_start_high << 16); > + ssc_step_size = regs->decimal_div_start; > + ssc_step_size *= (1 << config->frac_bits); > + ssc_step_size += frac; > + ssc_step_size *= config->ssc_offset; > + ssc_step_size *= (config->ssc_adj_per + 1); > + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); > + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); > + > + regs->ssc_div_per_low = ssc_per & 0xFF; > + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; > + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); > + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); > + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; > + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; > + > + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; > + > + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", > + regs->decimal_div_start, frac, config->frac_bits); > + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", > + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); > +} > + > +static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll) > +{ > + void __iomem *base = pll->mmio; > + struct dsi_pll_regs *regs = &pll->reg_setup; > + > + if (pll->pll_configuration.enable_ssc) { > + pr_debug("SSC is enabled\n"); > + > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_LOW_1, > + regs->ssc_stepsize_low); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, > + regs->ssc_stepsize_high); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_LOW_1, > + regs->ssc_div_per_low); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_HIGH_1, > + regs->ssc_div_per_high); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_LOW_1, > + regs->ssc_adjper_low); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_HIGH_1, > + regs->ssc_adjper_high); > + pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_CONTROL, > + SSC_EN | regs->ssc_control); > + } > +} > + > +static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) > +{ > + void __iomem *base = pll->mmio; > + u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00; > + > + if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) { > + if (pll->vco_current_rate >= 3100000000ULL) > + analog_controls_five_1 = 0x03; > + > + if (pll->vco_current_rate < 1520000000ULL) > + vco_config_1 = 0x08; > + else if (pll->vco_current_rate < 2990000000ULL) > + vco_config_1 = 0x01; > + } > + > + pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1, > + analog_controls_five_1); > + pll_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1); > + pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE, 0x01); > + pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); > + pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); > + pll_write(base + REG_DSI_7nm_PHY_PLL_DSM_DIVIDER, 0x00); > + pll_write(base + REG_DSI_7nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); > + pll_write(base + REG_DSI_7nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); > + pll_write(base + REG_DSI_7nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, > 0xba); > + pll_write(base + REG_DSI_7nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); > + pll_write(base + REG_DSI_7nm_PHY_PLL_OUTDIV, 0x00); > + pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_OVERRIDE, 0x00); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x0a); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_BAND_SEL_RATE_1, 0xc0); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0x84); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0x82); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, > 0x4c); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x29); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f); > + pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a); > + pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT, > + pll->base.type == MSM_DSI_PHY_7NM_V4_1 ? 0x3f : 0x22); > + > + if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) { > + pll_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22); > + if (pll->slave) > + pll_write(pll->slave->mmio + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, > 0x22); > + } > +} > + > +static void dsi_pll_commit(struct dsi_pll_7nm *pll) > +{ > + void __iomem *base = pll->mmio; > + struct dsi_pll_regs *reg = &pll->reg_setup; > + > + pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); > + pll_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, > reg->decimal_div_start); > + pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1, > reg->frac_div_start_low); > + pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1, > reg->frac_div_start_mid); > + pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1, > reg->frac_div_start_high); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, > reg->pll_lockdet_rate); > + pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); > + pll_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, 0x10); /* TODO: 0x00 > for CPHY */ > + pll_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, > reg->pll_clock_inverters); > +} > + > +static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + > + DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->id, rate, > + parent_rate); > + > + pll_7nm->vco_current_rate = rate; > + pll_7nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > + > + dsi_pll_setup_config(pll_7nm); > + > + dsi_pll_calc_dec_frac(pll_7nm); > + > + dsi_pll_calc_ssc(pll_7nm); > + > + dsi_pll_commit(pll_7nm); > + > + dsi_pll_config_hzindep_reg(pll_7nm); > + > + dsi_pll_ssc_commit(pll_7nm); > + > + /* flush, ensure all register writes are done*/ > + wmb(); > + > + return 0; > +} > + > +static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll) > +{ > + int rc; > + u32 status = 0; > + u32 const delay_us = 100; > + u32 const timeout_us = 5000; > + > + rc = readl_poll_timeout_atomic(pll->mmio + > + REG_DSI_7nm_PHY_PLL_COMMON_STATUS_ONE, > + status, > + ((status & BIT(0)) > 0), > + delay_us, > + timeout_us); > + if (rc) > + pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", > + pll->id, status); > + > + return rc; > +} > + > +static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll) > +{ > + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0); > + > + pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0); > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data & > ~BIT(5)); > + ndelay(250); > +} > + > +static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll) > +{ > + u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0); > + > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data | > BIT(5)); > + pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0xc0); > + ndelay(250); > +} > + > +static void dsi_pll_disable_global_clk(struct dsi_pll_7nm *pll) > +{ > + u32 data; > + > + data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1, data & > ~BIT(5)); > +} > + > +static void dsi_pll_enable_global_clk(struct dsi_pll_7nm *pll) > +{ > + u32 data; > + > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_3, 0x04); > + > + data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1, > + data | BIT(5) | BIT(4)); > +} > + > +static void dsi_pll_phy_dig_reset(struct dsi_pll_7nm *pll) > +{ > + /* > + * Reset the PHY digital domain. This would be needed when > + * coming out of a CX or analog rail power collapse while > + * ensuring that the pads maintain LP00 or LP11 state > + */ > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, > BIT(0)); > + wmb(); /* Ensure that the reset is deasserted */ > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, > 0x0); > + wmb(); /* Ensure that the reset is deasserted */ > +} > + > +static int dsi_pll_7nm_vco_prepare(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + int rc; > + > + dsi_pll_enable_pll_bias(pll_7nm); > + if (pll_7nm->slave) > + dsi_pll_enable_pll_bias(pll_7nm->slave); > + > + /* Start PLL */ > + pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, > 0x01); > + > + /* > + * ensure all PLL configurations are written prior to checking > + * for PLL lock. > + */ > + wmb(); > + > + /* Check for PLL lock */ > + rc = dsi_pll_7nm_lock_status(pll_7nm); > + if (rc) { > + pr_err("PLL(%d) lock failed\n", pll_7nm->id); > + goto error; > + } > + > + pll->pll_on = true; > + > + /* > + * assert power on reset for PHY digital in case the PLL is > + * enabled after CX of analog domain power collapse. This needs > + * to be done before enabling the global clk. > + */ > + dsi_pll_phy_dig_reset(pll_7nm); > + if (pll_7nm->slave) > + dsi_pll_phy_dig_reset(pll_7nm->slave); > + > + dsi_pll_enable_global_clk(pll_7nm); > + if (pll_7nm->slave) > + dsi_pll_enable_global_clk(pll_7nm->slave); > + > +error: > + return rc; > +} > + > +static void dsi_pll_disable_sub(struct dsi_pll_7nm *pll) > +{ > + pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0); > + dsi_pll_disable_pll_bias(pll); > +} > + > +static void dsi_pll_7nm_vco_unprepare(struct clk_hw *hw) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + > + /* > + * To avoid any stray glitches while abruptly powering down the PLL > + * make sure to gate the clock using the clock enable bit before > + * powering down the PLL > + */ > + dsi_pll_disable_global_clk(pll_7nm); > + pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0); > + dsi_pll_disable_sub(pll_7nm); > + if (pll_7nm->slave) { > + dsi_pll_disable_global_clk(pll_7nm->slave); > + dsi_pll_disable_sub(pll_7nm->slave); > + } > + /* flush, ensure all register writes are done */ > + wmb(); > + pll->pll_on = false; > +} > + > +static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + struct dsi_pll_config *config = &pll_7nm->pll_configuration; > + void __iomem *base = pll_7nm->mmio; > + u64 ref_clk = pll_7nm->vco_ref_clk_rate; > + u64 vco_rate = 0x0; > + u64 multiplier; > + u32 frac; > + u32 dec; > + u64 pll_freq, tmp64; > + > + dec = pll_read(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1); > + dec &= 0xff; > + > + frac = pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1); > + frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1) & > + 0xff) << 8); > + frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1) > & > + 0x3) << 16); > + > + /* > + * TODO: > + * 1. Assumes prescaler is disabled > + */ > + multiplier = 1 << config->frac_bits; > + pll_freq = dec * (ref_clk * 2); > + tmp64 = (ref_clk * 2 * frac); > + pll_freq += div_u64(tmp64, multiplier); > + > + vco_rate = pll_freq; > + > + DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", > + pll_7nm->id, (unsigned long)vco_rate, dec, frac); > + > + return (unsigned long)vco_rate; > +} > + > +static const struct clk_ops clk_ops_dsi_pll_7nm_vco = { > + .round_rate = msm_dsi_pll_helper_clk_round_rate, > + .set_rate = dsi_pll_7nm_vco_set_rate, > + .recalc_rate = dsi_pll_7nm_vco_recalc_rate, > + .prepare = dsi_pll_7nm_vco_prepare, > + .unprepare = dsi_pll_7nm_vco_unprepare, > +}; > + > +/* > + * PLL Callbacks > + */ > + > +static void dsi_pll_7nm_save_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + struct pll_7nm_cached_state *cached = &pll_7nm->cached_state; > + void __iomem *phy_base = pll_7nm->phy_cmn_mmio; > + u32 cmn_clk_cfg0, cmn_clk_cfg1; > + > + cached->pll_out_div = pll_read(pll_7nm->mmio + > + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); > + cached->pll_out_div &= 0x3; > + > + cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0); > + cached->bit_clk_div = cmn_clk_cfg0 & 0xf; > + cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; > + > + cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > + cached->pll_mux = cmn_clk_cfg1 & 0x3; > + > + DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", > + pll_7nm->id, cached->pll_out_div, cached->bit_clk_div, > + cached->pix_clk_div, cached->pll_mux); > +} > + > +static int dsi_pll_7nm_restore_state(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + struct pll_7nm_cached_state *cached = &pll_7nm->cached_state; > + void __iomem *phy_base = pll_7nm->phy_cmn_mmio; > + u32 val; > + int ret; > + > + val = pll_read(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); > + val &= ~0x3; > + val |= cached->pll_out_div; > + pll_write(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, val); > + > + pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0, > + cached->bit_clk_div | (cached->pix_clk_div << 4)); > + > + val = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > + val &= ~0x3; > + val |= cached->pll_mux; > + pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, val); > + > + ret = dsi_pll_7nm_vco_set_rate(&pll->clk_hw, > pll_7nm->vco_current_rate, pll_7nm->vco_ref_clk_rate); > + if (ret) { > + DRM_DEV_ERROR(&pll_7nm->pdev->dev, > + "restore vco rate failed. ret=%d\n", ret); > + return ret; > + } > + > + DBG("DSI PLL%d", pll_7nm->id); > + > + return 0; > +} > + > +static int dsi_pll_7nm_set_usecase(struct msm_dsi_pll *pll, > + enum msm_dsi_phy_usecase uc) > +{ > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + void __iomem *base = pll_7nm->phy_cmn_mmio; > + u32 data = 0x0; /* internal PLL */ > + > + DBG("DSI PLL%d", pll_7nm->id); > + > + switch (uc) { > + case MSM_DSI_PHY_STANDALONE: > + break; > + case MSM_DSI_PHY_MASTER: > + pll_7nm->slave = pll_7nm_list[(pll_7nm->id + 1) % DSI_MAX]; > + break; > + case MSM_DSI_PHY_SLAVE: > + data = 0x1; /* external PLL */ > + break; > + default: > + return -EINVAL; > + } > + > + /* set PLL src */ > + pll_write(base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, (data << 2)); > + > + pll_7nm->uc = uc; > + > + return 0; > +} > + > +static int dsi_pll_7nm_get_provider(struct msm_dsi_pll *pll, > + struct clk **byte_clk_provider, > + struct clk **pixel_clk_provider) > +{ > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + struct clk_hw_onecell_data *hw_data = pll_7nm->hw_data; > + > + DBG("DSI PLL%d", pll_7nm->id); > + > + if (byte_clk_provider) > + *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > + if (pixel_clk_provider) > + *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > + > + return 0; > +} > + > +static void dsi_pll_7nm_destroy(struct msm_dsi_pll *pll) > +{ > + struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > + struct device *dev = &pll_7nm->pdev->dev; > + > + DBG("DSI PLL%d", pll_7nm->id); > + of_clk_del_provider(dev->of_node); > + > + clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw); > + clk_hw_unregister_mux(pll_7nm->pclk_mux_hw); > + clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw); > + clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw); > + clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw); > + clk_hw_unregister_divider(pll_7nm->bit_clk_hw); > + clk_hw_unregister_divider(pll_7nm->out_div_clk_hw); > + clk_hw_unregister(&pll_7nm->base.clk_hw); > +} > + > +/* > + * The post dividers and mux clocks are created using the standard > divider and > + * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its > dividers/mux > + * state to follow the master PLL's divider/mux state. Therefore, we > don't > + * require special clock ops that also configure the slave PLL > registers > + */ > +static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm) > +{ > + char clk_name[32], parent[32], vco_name[32]; > + char parent2[32], parent3[32], parent4[32]; > + struct clk_init_data vco_init = { > + .parent_names = (const char *[]){ "bi_tcxo" }, > + .num_parents = 1, > + .name = vco_name, > + .flags = CLK_IGNORE_UNUSED, > + .ops = &clk_ops_dsi_pll_7nm_vco, > + }; > + struct device *dev = &pll_7nm->pdev->dev; > + struct clk_hw_onecell_data *hw_data; > + struct clk_hw *hw; > + int ret; > + > + DBG("DSI%d", pll_7nm->id); > + > + hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > + NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > + GFP_KERNEL); > + if (!hw_data) > + return -ENOMEM; > + > + snprintf(vco_name, 32, "dsi%dvco_clk", pll_7nm->id); > + pll_7nm->base.clk_hw.init = &vco_init; > + > + ret = clk_hw_register(dev, &pll_7nm->base.clk_hw); > + if (ret) > + return ret; > + > + snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > + snprintf(parent, 32, "dsi%dvco_clk", pll_7nm->id); > + > + hw = clk_hw_register_divider(dev, clk_name, > + parent, CLK_SET_RATE_PARENT, > + pll_7nm->mmio + > + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, > + 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_base_clk_hw; > + } > + > + pll_7nm->out_div_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > + > + /* BIT CLK: DIV_CTRL_3_0 */ > + hw = clk_hw_register_divider(dev, clk_name, parent, > + CLK_SET_RATE_PARENT, > + pll_7nm->phy_cmn_mmio + > + REG_DSI_7nm_PHY_CMN_CLK_CFG0, > + 0, 4, CLK_DIVIDER_ONE_BASED, > + &pll_7nm->postdiv_lock); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_out_div_clk_hw; > + } > + > + pll_7nm->bit_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > + > + /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + CLK_SET_RATE_PARENT, 1, 8); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_bit_clk_hw; > + } > + > + pll_7nm->byte_clk_hw = hw; > + hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > + > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + 0, 1, 2); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_byte_clk_hw; > + } > + > + pll_7nm->by_2_bit_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > + > + hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > + 0, 1, 4); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_by_2_bit_clk_hw; > + } > + > + pll_7nm->post_out_div_clk_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > + snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id); > + snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > + snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id); > + > + hw = clk_hw_register_mux(dev, clk_name, > + ((const char *[]){ > + parent, parent2, parent3, parent4 > + }), 4, 0, pll_7nm->phy_cmn_mmio + > + REG_DSI_7nm_PHY_CMN_CLK_CFG1, > + 0, 2, 0, NULL); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_post_out_div_clk_hw; > + } > + > + pll_7nm->pclk_mux_hw = hw; > + > + snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_7nm->id); > + snprintf(parent, 32, "dsi%d_pclk_mux", pll_7nm->id); > + > + /* PIX CLK DIV : DIV_CTRL_7_4*/ > + hw = clk_hw_register_divider(dev, clk_name, parent, > + 0, pll_7nm->phy_cmn_mmio + > + REG_DSI_7nm_PHY_CMN_CLK_CFG0, > + 4, 4, CLK_DIVIDER_ONE_BASED, > + &pll_7nm->postdiv_lock); > + if (IS_ERR(hw)) { > + ret = PTR_ERR(hw); > + goto err_pclk_mux_hw; > + } > + > + pll_7nm->out_dsiclk_hw = hw; > + hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > + > + hw_data->num = NUM_PROVIDED_CLKS; > + pll_7nm->hw_data = hw_data; > + > + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > + pll_7nm->hw_data); > + if (ret) { > + DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > + goto err_dsiclk_hw; > + } > + > + return 0; > + > +err_dsiclk_hw: > + clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw); > +err_pclk_mux_hw: > + clk_hw_unregister_mux(pll_7nm->pclk_mux_hw); > +err_post_out_div_clk_hw: > + clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw); > +err_by_2_bit_clk_hw: > + clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw); > +err_byte_clk_hw: > + clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw); > +err_bit_clk_hw: > + clk_hw_unregister_divider(pll_7nm->bit_clk_hw); > +err_out_div_clk_hw: > + clk_hw_unregister_divider(pll_7nm->out_div_clk_hw); > +err_base_clk_hw: > + clk_hw_unregister(&pll_7nm->base.clk_hw); > + > + return ret; > +} > + > +struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, > + enum msm_dsi_phy_type type, int id) > +{ > + struct dsi_pll_7nm *pll_7nm; > + struct msm_dsi_pll *pll; > + int ret; > + > + pll_7nm = devm_kzalloc(&pdev->dev, sizeof(*pll_7nm), GFP_KERNEL); > + if (!pll_7nm) > + return ERR_PTR(-ENOMEM); > + > + DBG("DSI PLL%d", id); > + > + pll_7nm->pdev = pdev; > + pll_7nm->id = id; > + pll_7nm_list[id] = pll_7nm; > + > + pll_7nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > + if (IS_ERR_OR_NULL(pll_7nm->phy_cmn_mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + pll_7nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > + if (IS_ERR_OR_NULL(pll_7nm->mmio)) { > + DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > + return ERR_PTR(-ENOMEM); > + } > + > + spin_lock_init(&pll_7nm->postdiv_lock); > + > + pll = &pll_7nm->base; > + pll->min_rate = 1000000000UL; > + pll->max_rate = 3500000000UL; > + if (type == MSM_DSI_PHY_7NM_V4_1) { > + pll->min_rate = 600000000UL; > + pll->max_rate = (unsigned long)5000000000ULL; > + /* workaround for max rate overflowing on 32-bit builds: */ > + pll->max_rate = max(pll->max_rate, 0xffffffffUL); > + } > + pll->get_provider = dsi_pll_7nm_get_provider; > + pll->destroy = dsi_pll_7nm_destroy; > + pll->save_state = dsi_pll_7nm_save_state; > + pll->restore_state = dsi_pll_7nm_restore_state; > + pll->set_usecase = dsi_pll_7nm_set_usecase; > + > + pll_7nm->vco_delay = 1; > + > + ret = pll_7nm_register(pll_7nm); > + if (ret) { > + DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > + return ERR_PTR(ret); > + } > + > + /* TODO: Remove this when we have proper display handover support */ > + msm_dsi_pll_save_state(pll); > + > + return pll; > +} > + > static int dsi_phy_hw_v4_0_is_pll_on(struct msm_dsi_phy *phy) > { > void __iomem *base = phy->base; > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c > b/drivers/gpu/drm/msm/dsi/phy/dsi_pll.c > similarity index 100% > rename from drivers/gpu/drm/msm/dsi/pll/dsi_pll.c > rename to drivers/gpu/drm/msm/dsi/phy/dsi_pll.c > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h > b/drivers/gpu/drm/msm/dsi/phy/dsi_pll.h > similarity index 100% > rename from drivers/gpu/drm/msm/dsi/pll/dsi_pll.h > rename to drivers/gpu/drm/msm/dsi/phy/dsi_pll.h > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c > b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c > deleted file mode 100644 > index de3b802ccd3d..000000000000 > --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_10nm.c > +++ /dev/null > @@ -1,881 +0,0 @@ > -/* > - * SPDX-License-Identifier: GPL-2.0 > - * Copyright (c) 2018, The Linux Foundation > - */ > - > -#include > -#include > -#include > - > -#include "dsi_pll.h" > -#include "dsi.xml.h" > - > -/* > - * DSI PLL 10nm - clock diagram (eg: DSI0): > - * > - * dsi0_pll_out_div_clk dsi0_pll_bit_clk > - * | | > - * | | > - * +---------+ | +----------+ | +----+ > - * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- > dsi0_phy_pll_out_byteclk > - * +---------+ | +----------+ | +----+ > - * | | > - * | | > dsi0_pll_by_2_bit_clk > - * | | | > - * | | +----+ | |\ > dsi0_pclk_mux > - * | |--| /2 |--o--| \ | > - * | | +----+ | \ > | +---------+ > - * | --------------| > |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk > - * |------------------------------| / > +---------+ > - * | +-----+ | / > - * -----------| /4? |--o----------|/ > - * +-----+ | | > - * | > |dsiclk_sel > - * | > - * > dsi0_pll_post_out_div_clk > - */ > - > -#define DSI_BYTE_PLL_CLK 0 > -#define DSI_PIXEL_PLL_CLK 1 > -#define NUM_PROVIDED_CLKS 2 > - > -#define VCO_REF_CLK_RATE 19200000 > - > -struct dsi_pll_regs { > - u32 pll_prop_gain_rate; > - u32 pll_lockdet_rate; > - u32 decimal_div_start; > - u32 frac_div_start_low; > - u32 frac_div_start_mid; > - u32 frac_div_start_high; > - u32 pll_clock_inverters; > - u32 ssc_stepsize_low; > - u32 ssc_stepsize_high; > - u32 ssc_div_per_low; > - u32 ssc_div_per_high; > - u32 ssc_adjper_low; > - u32 ssc_adjper_high; > - u32 ssc_control; > -}; > - > -struct dsi_pll_config { > - u32 ref_freq; > - bool div_override; > - u32 output_div; > - bool ignore_frac; > - bool disable_prescaler; > - bool enable_ssc; > - bool ssc_center; > - u32 dec_bits; > - u32 frac_bits; > - u32 lock_timer; > - u32 ssc_freq; > - u32 ssc_offset; > - u32 ssc_adj_per; > - u32 thresh_cycles; > - u32 refclk_cycles; > -}; > - > -struct pll_10nm_cached_state { > - unsigned long vco_rate; > - u8 bit_clk_div; > - u8 pix_clk_div; > - u8 pll_out_div; > - u8 pll_mux; > -}; > - > -struct dsi_pll_10nm { > - struct msm_dsi_pll base; > - > - int id; > - struct platform_device *pdev; > - > - void __iomem *phy_cmn_mmio; > - void __iomem *mmio; > - > - u64 vco_ref_clk_rate; > - u64 vco_current_rate; > - > - /* protects REG_DSI_10nm_PHY_CMN_CLK_CFG0 register */ > - spinlock_t postdiv_lock; > - > - int vco_delay; > - struct dsi_pll_config pll_configuration; > - struct dsi_pll_regs reg_setup; > - > - /* private clocks: */ > - struct clk_hw *out_div_clk_hw; > - struct clk_hw *bit_clk_hw; > - struct clk_hw *byte_clk_hw; > - struct clk_hw *by_2_bit_clk_hw; > - struct clk_hw *post_out_div_clk_hw; > - struct clk_hw *pclk_mux_hw; > - struct clk_hw *out_dsiclk_hw; > - > - /* clock-provider: */ > - struct clk_hw_onecell_data *hw_data; > - > - struct pll_10nm_cached_state cached_state; > - > - enum msm_dsi_phy_usecase uc; > - struct dsi_pll_10nm *slave; > -}; > - > -#define to_pll_10nm(x) container_of(x, struct dsi_pll_10nm, base) > - > -/* > - * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > - * mode, where the master PLL's clk_ops needs access the slave's > private data > - */ > -static struct dsi_pll_10nm *pll_10nm_list[DSI_MAX]; > - > -static void dsi_pll_setup_config(struct dsi_pll_10nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - > - config->ref_freq = pll->vco_ref_clk_rate; > - config->output_div = 1; > - config->dec_bits = 8; > - config->frac_bits = 18; > - config->lock_timer = 64; > - config->ssc_freq = 31500; > - config->ssc_offset = 5000; > - config->ssc_adj_per = 2; > - config->thresh_cycles = 32; > - config->refclk_cycles = 256; > - > - config->div_override = false; > - config->ignore_frac = false; > - config->disable_prescaler = false; > - > - config->enable_ssc = false; > - config->ssc_center = 0; > -} > - > -static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - u64 fref = pll->vco_ref_clk_rate; > - u64 pll_freq; > - u64 divider; > - u64 dec, dec_multiple; > - u32 frac; > - u64 multiplier; > - > - pll_freq = pll->vco_current_rate; > - > - if (config->disable_prescaler) > - divider = fref; > - else > - divider = fref * 2; > - > - multiplier = 1 << config->frac_bits; > - dec_multiple = div_u64(pll_freq * multiplier, divider); > - dec = div_u64_rem(dec_multiple, multiplier, &frac); > - > - if (pll_freq <= 1900000000UL) > - regs->pll_prop_gain_rate = 8; > - else if (pll_freq <= 3000000000UL) > - regs->pll_prop_gain_rate = 10; > - else > - regs->pll_prop_gain_rate = 12; > - if (pll_freq < 1100000000UL) > - regs->pll_clock_inverters = 8; > - else > - regs->pll_clock_inverters = 0; > - > - regs->pll_lockdet_rate = config->lock_timer; > - regs->decimal_div_start = dec; > - regs->frac_div_start_low = (frac & 0xff); > - regs->frac_div_start_mid = (frac & 0xff00) >> 8; > - regs->frac_div_start_high = (frac & 0x30000) >> 16; > -} > - > -#define SSC_CENTER BIT(0) > -#define SSC_EN BIT(1) > - > -static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - u32 ssc_per; > - u32 ssc_mod; > - u64 ssc_step_size; > - u64 frac; > - > - if (!config->enable_ssc) { > - DBG("SSC not enabled\n"); > - return; > - } > - > - ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - > 1; > - ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); > - ssc_per -= ssc_mod; > - > - frac = regs->frac_div_start_low | > - (regs->frac_div_start_mid << 8) | > - (regs->frac_div_start_high << 16); > - ssc_step_size = regs->decimal_div_start; > - ssc_step_size *= (1 << config->frac_bits); > - ssc_step_size += frac; > - ssc_step_size *= config->ssc_offset; > - ssc_step_size *= (config->ssc_adj_per + 1); > - ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); > - ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); > - > - regs->ssc_div_per_low = ssc_per & 0xFF; > - regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; > - regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); > - regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); > - regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; > - regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; > - > - regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; > - > - pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", > - regs->decimal_div_start, frac, config->frac_bits); > - pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", > - ssc_per, (u32)ssc_step_size, config->ssc_adj_per); > -} > - > -static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll) > -{ > - void __iomem *base = pll->mmio; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - > - if (pll->pll_configuration.enable_ssc) { > - pr_debug("SSC is enabled\n"); > - > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_LOW_1, > - regs->ssc_stepsize_low); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, > - regs->ssc_stepsize_high); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_LOW_1, > - regs->ssc_div_per_low); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_PER_HIGH_1, > - regs->ssc_div_per_high); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_LOW_1, > - regs->ssc_adjper_low); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_DIV_ADJPER_HIGH_1, > - regs->ssc_adjper_high); > - pll_write(base + REG_DSI_10nm_PHY_PLL_SSC_CONTROL, > - SSC_EN | regs->ssc_control); > - } > -} > - > -static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll) > -{ > - void __iomem *base = pll->mmio; > - > - pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_ONE, 0x80); > - pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); > - pll_write(base + REG_DSI_10nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); > - pll_write(base + REG_DSI_10nm_PHY_PLL_DSM_DIVIDER, 0x00); > - pll_write(base + REG_DSI_10nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); > - pll_write(base + REG_DSI_10nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); > - pll_write(base + REG_DSI_10nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, > - 0xba); > - pll_write(base + REG_DSI_10nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, > 0x0c); > - pll_write(base + REG_DSI_10nm_PHY_PLL_OUTDIV, 0x00); > - pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_OVERRIDE, 0x00); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x08); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_BAND_SET_RATE_1, 0xc0); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0xfa); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, > - 0x4c); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PFILT, 0x29); > - pll_write(base + REG_DSI_10nm_PHY_PLL_IFILT, 0x3f); > -} > - > -static void dsi_pll_commit(struct dsi_pll_10nm *pll) > -{ > - void __iomem *base = pll->mmio; > - struct dsi_pll_regs *reg = &pll->reg_setup; > - > - pll_write(base + REG_DSI_10nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); > - pll_write(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1, > - reg->decimal_div_start); > - pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1, > - reg->frac_div_start_low); > - pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1, > - reg->frac_div_start_mid); > - pll_write(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1, > - reg->frac_div_start_high); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCKDET_RATE_1, > - reg->pll_lockdet_rate); > - pll_write(base + REG_DSI_10nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); > - pll_write(base + REG_DSI_10nm_PHY_PLL_CMODE, 0x10); > - pll_write(base + REG_DSI_10nm_PHY_PLL_CLOCK_INVERTERS, > - reg->pll_clock_inverters); > -} > - > -static int dsi_pll_10nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - > - DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_10nm->id, rate, > - parent_rate); > - > - pll_10nm->vco_current_rate = rate; > - pll_10nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > - > - dsi_pll_setup_config(pll_10nm); > - > - dsi_pll_calc_dec_frac(pll_10nm); > - > - dsi_pll_calc_ssc(pll_10nm); > - > - dsi_pll_commit(pll_10nm); > - > - dsi_pll_config_hzindep_reg(pll_10nm); > - > - dsi_pll_ssc_commit(pll_10nm); > - > - /* flush, ensure all register writes are done*/ > - wmb(); > - > - return 0; > -} > - > -static int dsi_pll_10nm_lock_status(struct dsi_pll_10nm *pll) > -{ > - struct device *dev = &pll->pdev->dev; > - int rc; > - u32 status = 0; > - u32 const delay_us = 100; > - u32 const timeout_us = 5000; > - > - rc = readl_poll_timeout_atomic(pll->mmio + > - REG_DSI_10nm_PHY_PLL_COMMON_STATUS_ONE, > - status, > - ((status & BIT(0)) > 0), > - delay_us, > - timeout_us); > - if (rc) > - DRM_DEV_ERROR(dev, "DSI PLL(%d) lock failed, status=0x%08x\n", > - pll->id, status); > - > - return rc; > -} > - > -static void dsi_pll_disable_pll_bias(struct dsi_pll_10nm *pll) > -{ > - u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); > - > - pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0); > - pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, > - data & ~BIT(5)); > - ndelay(250); > -} > - > -static void dsi_pll_enable_pll_bias(struct dsi_pll_10nm *pll) > -{ > - u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0); > - > - pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CTRL_0, > - data | BIT(5)); > - pll_write(pll->mmio + REG_DSI_10nm_PHY_PLL_SYSTEM_MUXES, 0xc0); > - ndelay(250); > -} > - > -static void dsi_pll_disable_global_clk(struct dsi_pll_10nm *pll) > -{ > - u32 data; > - > - data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > - pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, > - data & ~BIT(5)); > -} > - > -static void dsi_pll_enable_global_clk(struct dsi_pll_10nm *pll) > -{ > - u32 data; > - > - data = pll_read(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > - pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_CLK_CFG1, > - data | BIT(5)); > -} > - > -static int dsi_pll_10nm_vco_prepare(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct device *dev = &pll_10nm->pdev->dev; > - int rc; > - > - dsi_pll_enable_pll_bias(pll_10nm); > - if (pll_10nm->slave) > - dsi_pll_enable_pll_bias(pll_10nm->slave); > - > - rc = dsi_pll_10nm_vco_set_rate(hw,pll_10nm->vco_current_rate, 0); > - if (rc) { > - DRM_DEV_ERROR(dev, "vco_set_rate failed, rc=%d\n", rc); > - return rc; > - } > - > - /* Start PLL */ > - pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, > - 0x01); > - > - /* > - * ensure all PLL configurations are written prior to checking > - * for PLL lock. > - */ > - wmb(); > - > - /* Check for PLL lock */ > - rc = dsi_pll_10nm_lock_status(pll_10nm); > - if (rc) { > - DRM_DEV_ERROR(dev, "PLL(%d) lock failed\n", pll_10nm->id); > - goto error; > - } > - > - pll->pll_on = true; > - > - dsi_pll_enable_global_clk(pll_10nm); > - if (pll_10nm->slave) > - dsi_pll_enable_global_clk(pll_10nm->slave); > - > - pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, > - 0x01); > - if (pll_10nm->slave) > - pll_write(pll_10nm->slave->phy_cmn_mmio + > - REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0x01); > - > -error: > - return rc; > -} > - > -static void dsi_pll_disable_sub(struct dsi_pll_10nm *pll) > -{ > - pll_write(pll->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_RBUF_CTRL, 0); > - dsi_pll_disable_pll_bias(pll); > -} > - > -static void dsi_pll_10nm_vco_unprepare(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - > - /* > - * To avoid any stray glitches while abruptly powering down the PLL > - * make sure to gate the clock using the clock enable bit before > - * powering down the PLL > - */ > - dsi_pll_disable_global_clk(pll_10nm); > - pll_write(pll_10nm->phy_cmn_mmio + REG_DSI_10nm_PHY_CMN_PLL_CNTRL, > 0); > - dsi_pll_disable_sub(pll_10nm); > - if (pll_10nm->slave) { > - dsi_pll_disable_global_clk(pll_10nm->slave); > - dsi_pll_disable_sub(pll_10nm->slave); > - } > - /* flush, ensure all register writes are done */ > - wmb(); > - pll->pll_on = false; > -} > - > -static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct dsi_pll_config *config = &pll_10nm->pll_configuration; > - void __iomem *base = pll_10nm->mmio; > - u64 ref_clk = pll_10nm->vco_ref_clk_rate; > - u64 vco_rate = 0x0; > - u64 multiplier; > - u32 frac; > - u32 dec; > - u64 pll_freq, tmp64; > - > - dec = pll_read(base + REG_DSI_10nm_PHY_PLL_DECIMAL_DIV_START_1); > - dec &= 0xff; > - > - frac = pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_LOW_1); > - frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_MID_1) > & > - 0xff) << 8); > - frac |= ((pll_read(base + REG_DSI_10nm_PHY_PLL_FRAC_DIV_START_HIGH_1) > & > - 0x3) << 16); > - > - /* > - * TODO: > - * 1. Assumes prescaler is disabled > - */ > - multiplier = 1 << config->frac_bits; > - pll_freq = dec * (ref_clk * 2); > - tmp64 = (ref_clk * 2 * frac); > - pll_freq += div_u64(tmp64, multiplier); > - > - vco_rate = pll_freq; > - > - DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", > - pll_10nm->id, (unsigned long)vco_rate, dec, frac); > - > - return (unsigned long)vco_rate; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_10nm_vco = { > - .round_rate = msm_dsi_pll_helper_clk_round_rate, > - .set_rate = dsi_pll_10nm_vco_set_rate, > - .recalc_rate = dsi_pll_10nm_vco_recalc_rate, > - .prepare = dsi_pll_10nm_vco_prepare, > - .unprepare = dsi_pll_10nm_vco_unprepare, > -}; > - > -/* > - * PLL Callbacks > - */ > - > -static void dsi_pll_10nm_save_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; > - void __iomem *phy_base = pll_10nm->phy_cmn_mmio; > - u32 cmn_clk_cfg0, cmn_clk_cfg1; > - > - cached->pll_out_div = pll_read(pll_10nm->mmio + > - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); > - cached->pll_out_div &= 0x3; > - > - cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0); > - cached->bit_clk_div = cmn_clk_cfg0 & 0xf; > - cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; > - > - cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > - cached->pll_mux = cmn_clk_cfg1 & 0x3; > - > - DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", > - pll_10nm->id, cached->pll_out_div, cached->bit_clk_div, > - cached->pix_clk_div, cached->pll_mux); > -} > - > -static int dsi_pll_10nm_restore_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct pll_10nm_cached_state *cached = &pll_10nm->cached_state; > - void __iomem *phy_base = pll_10nm->phy_cmn_mmio; > - u32 val; > - int ret; > - > - val = pll_read(pll_10nm->mmio + > REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE); > - val &= ~0x3; > - val |= cached->pll_out_div; > - pll_write(pll_10nm->mmio + REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, > val); > - > - pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG0, > - cached->bit_clk_div | (cached->pix_clk_div << 4)); > - > - val = pll_read(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1); > - val &= ~0x3; > - val |= cached->pll_mux; > - pll_write(phy_base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, val); > - > - ret = dsi_pll_10nm_vco_set_rate(&pll->clk_hw, > pll_10nm->vco_current_rate, pll_10nm->vco_ref_clk_rate); > - if (ret) { > - DRM_DEV_ERROR(&pll_10nm->pdev->dev, > - "restore vco rate failed. ret=%d\n", ret); > - return ret; > - } > - > - DBG("DSI PLL%d", pll_10nm->id); > - > - return 0; > -} > - > -static int dsi_pll_10nm_set_usecase(struct msm_dsi_pll *pll, > - enum msm_dsi_phy_usecase uc) > -{ > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - void __iomem *base = pll_10nm->phy_cmn_mmio; > - u32 data = 0x0; /* internal PLL */ > - > - DBG("DSI PLL%d", pll_10nm->id); > - > - switch (uc) { > - case MSM_DSI_PHY_STANDALONE: > - break; > - case MSM_DSI_PHY_MASTER: > - pll_10nm->slave = pll_10nm_list[(pll_10nm->id + 1) % DSI_MAX]; > - break; > - case MSM_DSI_PHY_SLAVE: > - data = 0x1; /* external PLL */ > - break; > - default: > - return -EINVAL; > - } > - > - /* set PLL src */ > - pll_write(base + REG_DSI_10nm_PHY_CMN_CLK_CFG1, (data << 2)); > - > - pll_10nm->uc = uc; > - > - return 0; > -} > - > -static int dsi_pll_10nm_get_provider(struct msm_dsi_pll *pll, > - struct clk **byte_clk_provider, > - struct clk **pixel_clk_provider) > -{ > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct clk_hw_onecell_data *hw_data = pll_10nm->hw_data; > - > - DBG("DSI PLL%d", pll_10nm->id); > - > - if (byte_clk_provider) > - *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > - if (pixel_clk_provider) > - *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > - > - return 0; > -} > - > -static void dsi_pll_10nm_destroy(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_10nm *pll_10nm = to_pll_10nm(pll); > - struct device *dev = &pll_10nm->pdev->dev; > - > - DBG("DSI PLL%d", pll_10nm->id); > - of_clk_del_provider(dev->of_node); > - > - clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); > - clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); > - clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); > - clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); > - clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); > - clk_hw_unregister_divider(pll_10nm->bit_clk_hw); > - clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); > - clk_hw_unregister(&pll_10nm->base.clk_hw); > -} > - > -/* > - * The post dividers and mux clocks are created using the standard > divider and > - * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its > dividers/mux > - * state to follow the master PLL's divider/mux state. Therefore, we > don't > - * require special clock ops that also configure the slave PLL > registers > - */ > -static int pll_10nm_register(struct dsi_pll_10nm *pll_10nm) > -{ > - char clk_name[32], parent[32], vco_name[32]; > - char parent2[32], parent3[32], parent4[32]; > - struct clk_init_data vco_init = { > - .parent_names = (const char *[]){ "xo" }, > - .num_parents = 1, > - .name = vco_name, > - .flags = CLK_IGNORE_UNUSED, > - .ops = &clk_ops_dsi_pll_10nm_vco, > - }; > - struct device *dev = &pll_10nm->pdev->dev; > - struct clk_hw_onecell_data *hw_data; > - struct clk_hw *hw; > - int ret; > - > - DBG("DSI%d", pll_10nm->id); > - > - hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > - NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > - GFP_KERNEL); > - if (!hw_data) > - return -ENOMEM; > - > - snprintf(vco_name, 32, "dsi%dvco_clk", pll_10nm->id); > - pll_10nm->base.clk_hw.init = &vco_init; > - > - ret = clk_hw_register(dev, &pll_10nm->base.clk_hw); > - if (ret) > - return ret; > - > - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > - snprintf(parent, 32, "dsi%dvco_clk", pll_10nm->id); > - > - hw = clk_hw_register_divider(dev, clk_name, > - parent, CLK_SET_RATE_PARENT, > - pll_10nm->mmio + > - REG_DSI_10nm_PHY_PLL_PLL_OUTDIV_RATE, > - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_base_clk_hw; > - } > - > - pll_10nm->out_div_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > - > - /* BIT CLK: DIV_CTRL_3_0 */ > - hw = clk_hw_register_divider(dev, clk_name, parent, > - CLK_SET_RATE_PARENT, > - pll_10nm->phy_cmn_mmio + > - REG_DSI_10nm_PHY_CMN_CLK_CFG0, > - 0, 4, CLK_DIVIDER_ONE_BASED, > - &pll_10nm->postdiv_lock); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_out_div_clk_hw; > - } > - > - pll_10nm->bit_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > - > - /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - CLK_SET_RATE_PARENT, 1, 8); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_bit_clk_hw; > - } > - > - pll_10nm->byte_clk_hw = hw; > - hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > - > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - 0, 1, 2); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_byte_clk_hw; > - } > - > - pll_10nm->by_2_bit_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > - > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - 0, 1, 4); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_by_2_bit_clk_hw; > - } > - > - pll_10nm->post_out_div_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_10nm->id); > - snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_10nm->id); > - snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_10nm->id); > - snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_10nm->id); > - > - hw = clk_hw_register_mux(dev, clk_name, > - ((const char *[]){ > - parent, parent2, parent3, parent4 > - }), 4, 0, pll_10nm->phy_cmn_mmio + > - REG_DSI_10nm_PHY_CMN_CLK_CFG1, > - 0, 2, 0, NULL); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_post_out_div_clk_hw; > - } > - > - pll_10nm->pclk_mux_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_10nm->id); > - snprintf(parent, 32, "dsi%d_pclk_mux", pll_10nm->id); > - > - /* PIX CLK DIV : DIV_CTRL_7_4*/ > - hw = clk_hw_register_divider(dev, clk_name, parent, > - 0, pll_10nm->phy_cmn_mmio + > - REG_DSI_10nm_PHY_CMN_CLK_CFG0, > - 4, 4, CLK_DIVIDER_ONE_BASED, > - &pll_10nm->postdiv_lock); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_pclk_mux_hw; > - } > - > - pll_10nm->out_dsiclk_hw = hw; > - hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > - > - hw_data->num = NUM_PROVIDED_CLKS; > - pll_10nm->hw_data = hw_data; > - > - ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > - pll_10nm->hw_data); > - if (ret) { > - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > - goto err_dsiclk_hw; > - } > - > - return 0; > - > -err_dsiclk_hw: > - clk_hw_unregister_divider(pll_10nm->out_dsiclk_hw); > -err_pclk_mux_hw: > - clk_hw_unregister_mux(pll_10nm->pclk_mux_hw); > -err_post_out_div_clk_hw: > - clk_hw_unregister_fixed_factor(pll_10nm->post_out_div_clk_hw); > -err_by_2_bit_clk_hw: > - clk_hw_unregister_fixed_factor(pll_10nm->by_2_bit_clk_hw); > -err_byte_clk_hw: > - clk_hw_unregister_fixed_factor(pll_10nm->byte_clk_hw); > -err_bit_clk_hw: > - clk_hw_unregister_divider(pll_10nm->bit_clk_hw); > -err_out_div_clk_hw: > - clk_hw_unregister_divider(pll_10nm->out_div_clk_hw); > -err_base_clk_hw: > - clk_hw_unregister(&pll_10nm->base.clk_hw); > - > - return ret; > -} > - > -struct msm_dsi_pll *msm_dsi_pll_10nm_init(struct platform_device > *pdev, int id) > -{ > - struct dsi_pll_10nm *pll_10nm; > - struct msm_dsi_pll *pll; > - int ret; > - > - pll_10nm = devm_kzalloc(&pdev->dev, sizeof(*pll_10nm), GFP_KERNEL); > - if (!pll_10nm) > - return ERR_PTR(-ENOMEM); > - > - DBG("DSI PLL%d", id); > - > - pll_10nm->pdev = pdev; > - pll_10nm->id = id; > - pll_10nm_list[id] = pll_10nm; > - > - pll_10nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > - if (IS_ERR_OR_NULL(pll_10nm->phy_cmn_mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - pll_10nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > - if (IS_ERR_OR_NULL(pll_10nm->mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - spin_lock_init(&pll_10nm->postdiv_lock); > - > - pll = &pll_10nm->base; > - pll->min_rate = 1000000000UL; > - pll->max_rate = 3500000000UL; > - pll->get_provider = dsi_pll_10nm_get_provider; > - pll->destroy = dsi_pll_10nm_destroy; > - pll->save_state = dsi_pll_10nm_save_state; > - pll->restore_state = dsi_pll_10nm_restore_state; > - pll->set_usecase = dsi_pll_10nm_set_usecase; > - > - pll_10nm->vco_delay = 1; > - > - ret = pll_10nm_register(pll_10nm); > - if (ret) { > - DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > - return ERR_PTR(ret); > - } > - > - /* TODO: Remove this when we have proper display handover support */ > - msm_dsi_pll_save_state(pll); > - > - return pll; > -} > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c > b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c > deleted file mode 100644 > index f847376d501e..000000000000 > --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_14nm.c > +++ /dev/null > @@ -1,1096 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-only > -/* > - * Copyright (c) 2016, The Linux Foundation. All rights reserved. > - */ > - > -#include > -#include > - > -#include "dsi_pll.h" > -#include "dsi.xml.h" > - > -/* > - * DSI PLL 14nm - clock diagram (eg: DSI0): > - * > - * dsi0n1_postdiv_clk > - * | > - * | > - * +----+ | +----+ > - * dsi0vco_clk ---| n1 |--o--| /8 |-- dsi0pllbyte > - * +----+ | +----+ > - * | dsi0n1_postdivby2_clk > - * | +----+ | > - * o---| /2 |--o--|\ > - * | +----+ | \ +----+ > - * | | |--| n2 |-- dsi0pll > - * o--------------| / +----+ > - * |/ > - */ > - > -#define POLL_MAX_READS 15 > -#define POLL_TIMEOUT_US 1000 > - > -#define NUM_PROVIDED_CLKS 2 > - > -#define VCO_REF_CLK_RATE 19200000 > -#define VCO_MIN_RATE 1300000000UL > -#define VCO_MAX_RATE 2600000000UL > - > -#define DSI_BYTE_PLL_CLK 0 > -#define DSI_PIXEL_PLL_CLK 1 > - > -#define DSI_PLL_DEFAULT_VCO_POSTDIV 1 > - > -struct dsi_pll_input { > - u32 fref; /* reference clk */ > - u32 fdata; /* bit clock rate */ > - u32 dsiclk_sel; /* Mux configuration (see diagram) */ > - u32 ssc_en; /* SSC enable/disable */ > - u32 ldo_en; > - > - /* fixed params */ > - u32 refclk_dbler_en; > - u32 vco_measure_time; > - u32 kvco_measure_time; > - u32 bandgap_timer; > - u32 pll_wakeup_timer; > - u32 plllock_cnt; > - u32 plllock_rng; > - u32 ssc_center; > - u32 ssc_adj_period; > - u32 ssc_spread; > - u32 ssc_freq; > - u32 pll_ie_trim; > - u32 pll_ip_trim; > - u32 pll_iptat_trim; > - u32 pll_cpcset_cur; > - u32 pll_cpmset_cur; > - > - u32 pll_icpmset; > - u32 pll_icpcset; > - > - u32 pll_icpmset_p; > - u32 pll_icpmset_m; > - > - u32 pll_icpcset_p; > - u32 pll_icpcset_m; > - > - u32 pll_lpf_res1; > - u32 pll_lpf_cap1; > - u32 pll_lpf_cap2; > - u32 pll_c3ctrl; > - u32 pll_r3ctrl; > -}; > - > -struct dsi_pll_output { > - u32 pll_txclk_en; > - u32 dec_start; > - u32 div_frac_start; > - u32 ssc_period; > - u32 ssc_step_size; > - u32 plllock_cmp; > - u32 pll_vco_div_ref; > - u32 pll_vco_count; > - u32 pll_kvco_div_ref; > - u32 pll_kvco_count; > - u32 pll_misc1; > - u32 pll_lpf2_postdiv; > - u32 pll_resetsm_cntrl; > - u32 pll_resetsm_cntrl2; > - u32 pll_resetsm_cntrl5; > - u32 pll_kvco_code; > - > - u32 cmn_clk_cfg0; > - u32 cmn_clk_cfg1; > - u32 cmn_ldo_cntrl; > - > - u32 pll_postdiv; > - u32 fcvo; > -}; > - > -struct pll_14nm_cached_state { > - unsigned long vco_rate; > - u8 n2postdiv; > - u8 n1postdiv; > -}; > - > -struct dsi_pll_14nm { > - struct msm_dsi_pll base; > - > - int id; > - struct platform_device *pdev; > - > - void __iomem *phy_cmn_mmio; > - void __iomem *mmio; > - > - int vco_delay; > - > - struct dsi_pll_input in; > - struct dsi_pll_output out; > - > - /* protects REG_DSI_14nm_PHY_CMN_CLK_CFG0 register */ > - spinlock_t postdiv_lock; > - > - u64 vco_current_rate; > - u64 vco_ref_clk_rate; > - > - /* private clocks: */ > - struct clk_hw *hws[NUM_DSI_CLOCKS_MAX]; > - u32 num_hws; > - > - /* clock-provider: */ > - struct clk_hw_onecell_data *hw_data; > - > - struct pll_14nm_cached_state cached_state; > - > - enum msm_dsi_phy_usecase uc; > - struct dsi_pll_14nm *slave; > -}; > - > -#define to_pll_14nm(x) container_of(x, struct dsi_pll_14nm, base) > - > -/* > - * Private struct for N1/N2 post-divider clocks. These clocks are > similar to > - * the generic clk_divider class of clocks. The only difference is > that it > - * also sets the slave DSI PLL's post-dividers if in Dual DSI mode > - */ > -struct dsi_pll_14nm_postdiv { > - struct clk_hw hw; > - > - /* divider params */ > - u8 shift; > - u8 width; > - u8 flags; /* same flags as used by clk_divider struct */ > - > - struct dsi_pll_14nm *pll; > -}; > - > -#define to_pll_14nm_postdiv(_hw) container_of(_hw, struct > dsi_pll_14nm_postdiv, hw) > - > -/* > - * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > - * mode, where the master PLL's clk_ops needs access the slave's > private data > - */ > -static struct dsi_pll_14nm *pll_14nm_list[DSI_MAX]; > - > -static bool pll_14nm_poll_for_ready(struct dsi_pll_14nm *pll_14nm, > - u32 nb_tries, u32 timeout_us) > -{ > - bool pll_locked = false; > - void __iomem *base = pll_14nm->mmio; > - u32 tries, val; > - > - tries = nb_tries; > - while (tries--) { > - val = pll_read(base + > - REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); > - pll_locked = !!(val & BIT(5)); > - > - if (pll_locked) > - break; > - > - udelay(timeout_us); > - } > - > - if (!pll_locked) { > - tries = nb_tries; > - while (tries--) { > - val = pll_read(base + > - REG_DSI_14nm_PHY_PLL_RESET_SM_READY_STATUS); > - pll_locked = !!(val & BIT(0)); > - > - if (pll_locked) > - break; > - > - udelay(timeout_us); > - } > - } > - > - DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > - > - return pll_locked; > -} > - > -static void dsi_pll_14nm_input_init(struct dsi_pll_14nm *pll) > -{ > - pll->in.fref = pll->vco_ref_clk_rate; > - pll->in.fdata = 0; > - pll->in.dsiclk_sel = 1; /* Use the /2 path in Mux */ > - pll->in.ldo_en = 0; /* disabled for now */ > - > - /* fixed input */ > - pll->in.refclk_dbler_en = 0; > - pll->in.vco_measure_time = 5; > - pll->in.kvco_measure_time = 5; > - pll->in.bandgap_timer = 4; > - pll->in.pll_wakeup_timer = 5; > - pll->in.plllock_cnt = 1; > - pll->in.plllock_rng = 0; > - > - /* > - * SSC is enabled by default. We might need DT props for configuring > - * some SSC params like PPM and center/down spread etc. > - */ > - pll->in.ssc_en = 1; > - pll->in.ssc_center = 0; /* down spread by default */ > - pll->in.ssc_spread = 5; /* PPM / 1000 */ > - pll->in.ssc_freq = 31500; /* default recommended */ > - pll->in.ssc_adj_period = 37; > - > - pll->in.pll_ie_trim = 4; > - pll->in.pll_ip_trim = 4; > - pll->in.pll_cpcset_cur = 1; > - pll->in.pll_cpmset_cur = 1; > - pll->in.pll_icpmset = 4; > - pll->in.pll_icpcset = 4; > - pll->in.pll_icpmset_p = 0; > - pll->in.pll_icpmset_m = 0; > - pll->in.pll_icpcset_p = 0; > - pll->in.pll_icpcset_m = 0; > - pll->in.pll_lpf_res1 = 3; > - pll->in.pll_lpf_cap1 = 11; > - pll->in.pll_lpf_cap2 = 1; > - pll->in.pll_iptat_trim = 7; > - pll->in.pll_c3ctrl = 2; > - pll->in.pll_r3ctrl = 1; > -} > - > -#define CEIL(x, y) (((x) + ((y) - 1)) / (y)) > - > -static void pll_14nm_ssc_calc(struct dsi_pll_14nm *pll) > -{ > - u32 period, ssc_period; > - u32 ref, rem; > - u64 step_size; > - > - DBG("vco=%lld ref=%lld", pll->vco_current_rate, > pll->vco_ref_clk_rate); > - > - ssc_period = pll->in.ssc_freq / 500; > - period = (u32)pll->vco_ref_clk_rate / 1000; > - ssc_period = CEIL(period, ssc_period); > - ssc_period -= 1; > - pll->out.ssc_period = ssc_period; > - > - DBG("ssc freq=%d spread=%d period=%d", pll->in.ssc_freq, > - pll->in.ssc_spread, pll->out.ssc_period); > - > - step_size = (u32)pll->vco_current_rate; > - ref = pll->vco_ref_clk_rate; > - ref /= 1000; > - step_size = div_u64(step_size, ref); > - step_size <<= 20; > - step_size = div_u64(step_size, 1000); > - step_size *= pll->in.ssc_spread; > - step_size = div_u64(step_size, 1000); > - step_size *= (pll->in.ssc_adj_period + 1); > - > - rem = 0; > - step_size = div_u64_rem(step_size, ssc_period + 1, &rem); > - if (rem) > - step_size++; > - > - DBG("step_size=%lld", step_size); > - > - step_size &= 0x0ffff; /* take lower 16 bits */ > - > - pll->out.ssc_step_size = step_size; > -} > - > -static void pll_14nm_dec_frac_calc(struct dsi_pll_14nm *pll) > -{ > - struct dsi_pll_input *pin = &pll->in; > - struct dsi_pll_output *pout = &pll->out; > - u64 multiplier = BIT(20); > - u64 dec_start_multiple, dec_start, pll_comp_val; > - u32 duration, div_frac_start; > - u64 vco_clk_rate = pll->vco_current_rate; > - u64 fref = pll->vco_ref_clk_rate; > - > - DBG("vco_clk_rate=%lld ref_clk_rate=%lld", vco_clk_rate, fref); > - > - dec_start_multiple = div_u64(vco_clk_rate * multiplier, fref); > - div_u64_rem(dec_start_multiple, multiplier, &div_frac_start); > - > - dec_start = div_u64(dec_start_multiple, multiplier); > - > - pout->dec_start = (u32)dec_start; > - pout->div_frac_start = div_frac_start; > - > - if (pin->plllock_cnt == 0) > - duration = 1024; > - else if (pin->plllock_cnt == 1) > - duration = 256; > - else if (pin->plllock_cnt == 2) > - duration = 128; > - else > - duration = 32; > - > - pll_comp_val = duration * dec_start_multiple; > - pll_comp_val = div_u64(pll_comp_val, multiplier); > - do_div(pll_comp_val, 10); > - > - pout->plllock_cmp = (u32)pll_comp_val; > - > - pout->pll_txclk_en = 1; > - pout->cmn_ldo_cntrl = 0x3c; > -} > - > -static u32 pll_14nm_kvco_slop(u32 vrate) > -{ > - u32 slop = 0; > - > - if (vrate > VCO_MIN_RATE && vrate <= 1800000000UL) > - slop = 600; > - else if (vrate > 1800000000UL && vrate < 2300000000UL) > - slop = 400; > - else if (vrate > 2300000000UL && vrate < VCO_MAX_RATE) > - slop = 280; > - > - return slop; > -} > - > -static void pll_14nm_calc_vco_count(struct dsi_pll_14nm *pll) > -{ > - struct dsi_pll_input *pin = &pll->in; > - struct dsi_pll_output *pout = &pll->out; > - u64 vco_clk_rate = pll->vco_current_rate; > - u64 fref = pll->vco_ref_clk_rate; > - u64 data; > - u32 cnt; > - > - data = fref * pin->vco_measure_time; > - do_div(data, 1000000); > - data &= 0x03ff; /* 10 bits */ > - data -= 2; > - pout->pll_vco_div_ref = data; > - > - data = div_u64(vco_clk_rate, 1000000); /* unit is Mhz */ > - data *= pin->vco_measure_time; > - do_div(data, 10); > - pout->pll_vco_count = data; > - > - data = fref * pin->kvco_measure_time; > - do_div(data, 1000000); > - data &= 0x03ff; /* 10 bits */ > - data -= 1; > - pout->pll_kvco_div_ref = data; > - > - cnt = pll_14nm_kvco_slop(vco_clk_rate); > - cnt *= 2; > - cnt /= 100; > - cnt *= pin->kvco_measure_time; > - pout->pll_kvco_count = cnt; > - > - pout->pll_misc1 = 16; > - pout->pll_resetsm_cntrl = 48; > - pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3; > - pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer; > - pout->pll_kvco_code = 0; > -} > - > -static void pll_db_commit_ssc(struct dsi_pll_14nm *pll) > -{ > - void __iomem *base = pll->mmio; > - struct dsi_pll_input *pin = &pll->in; > - struct dsi_pll_output *pout = &pll->out; > - u8 data; > - > - data = pin->ssc_adj_period; > - data &= 0x0ff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER1, data); > - data = (pin->ssc_adj_period >> 8); > - data &= 0x03; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_ADJ_PER2, data); > - > - data = pout->ssc_period; > - data &= 0x0ff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER1, data); > - data = (pout->ssc_period >> 8); > - data &= 0x0ff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_PER2, data); > - > - data = pout->ssc_step_size; > - data &= 0x0ff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE1, data); > - data = (pout->ssc_step_size >> 8); > - data &= 0x0ff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_STEP_SIZE2, data); > - > - data = (pin->ssc_center & 0x01); > - data <<= 1; > - data |= 0x01; /* enable */ > - pll_write(base + REG_DSI_14nm_PHY_PLL_SSC_EN_CENTER, data); > - > - wmb(); /* make sure register committed */ > -} > - > -static void pll_db_commit_common(struct dsi_pll_14nm *pll, > - struct dsi_pll_input *pin, > - struct dsi_pll_output *pout) > -{ > - void __iomem *base = pll->mmio; > - u8 data; > - > - /* confgiure the non frequency dependent pll registers */ > - data = 0; > - pll_write(base + REG_DSI_14nm_PHY_PLL_SYSCLK_EN_RESET, data); > - > - data = pout->pll_txclk_en; > - pll_write(base + REG_DSI_14nm_PHY_PLL_TXCLK_EN, data); > - > - data = pout->pll_resetsm_cntrl; > - pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL, data); > - data = pout->pll_resetsm_cntrl2; > - pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL2, data); > - data = pout->pll_resetsm_cntrl5; > - pll_write(base + REG_DSI_14nm_PHY_PLL_RESETSM_CNTRL5, data); > - > - data = pout->pll_vco_div_ref & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF1, data); > - data = (pout->pll_vco_div_ref >> 8) & 0x3; > - pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_DIV_REF2, data); > - > - data = pout->pll_kvco_div_ref & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF1, data); > - data = (pout->pll_kvco_div_ref >> 8) & 0x3; > - pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_DIV_REF2, data); > - > - data = pout->pll_misc1; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_MISC1, data); > - > - data = pin->pll_ie_trim; > - pll_write(base + REG_DSI_14nm_PHY_PLL_IE_TRIM, data); > - > - data = pin->pll_ip_trim; > - pll_write(base + REG_DSI_14nm_PHY_PLL_IP_TRIM, data); > - > - data = pin->pll_cpmset_cur << 3 | pin->pll_cpcset_cur; > - pll_write(base + REG_DSI_14nm_PHY_PLL_CP_SET_CUR, data); > - > - data = pin->pll_icpcset_p << 3 | pin->pll_icpcset_m; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPCSET, data); > - > - data = pin->pll_icpmset_p << 3 | pin->pll_icpcset_m; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICPMSET, data); > - > - data = pin->pll_icpmset << 3 | pin->pll_icpcset; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_ICP_SET, data); > - > - data = pin->pll_lpf_cap2 << 4 | pin->pll_lpf_cap1; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF1, data); > - > - data = pin->pll_iptat_trim; > - pll_write(base + REG_DSI_14nm_PHY_PLL_IPTAT_TRIM, data); > - > - data = pin->pll_c3ctrl | pin->pll_r3ctrl << 4; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_CRCTRL, data); > -} > - > -static void pll_14nm_software_reset(struct dsi_pll_14nm *pll_14nm) > -{ > - void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > - > - /* de assert pll start and apply pll sw reset */ > - > - /* stop pll */ > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0); > - > - /* pll sw reset */ > - pll_write_udelay(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0x20, 10); > - wmb(); /* make sure register committed */ > - > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_1, 0); > - wmb(); /* make sure register committed */ > -} > - > -static void pll_db_commit_14nm(struct dsi_pll_14nm *pll, > - struct dsi_pll_input *pin, > - struct dsi_pll_output *pout) > -{ > - void __iomem *base = pll->mmio; > - void __iomem *cmn_base = pll->phy_cmn_mmio; > - u8 data; > - > - DBG("DSI%d PLL", pll->id); > - > - data = pout->cmn_ldo_cntrl; > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_LDO_CNTRL, data); > - > - pll_db_commit_common(pll, pin, pout); > - > - pll_14nm_software_reset(pll); > - > - data = pin->dsiclk_sel; /* set dsiclk_sel = 1 */ > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG1, data); > - > - data = 0xff; /* data, clk, pll normal operation */ > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CTRL_0, data); > - > - /* configure the frequency dependent pll registers */ > - data = pout->dec_start; > - pll_write(base + REG_DSI_14nm_PHY_PLL_DEC_START, data); > - > - data = pout->div_frac_start & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1, data); > - data = (pout->div_frac_start >> 8) & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2, data); > - data = (pout->div_frac_start >> 16) & 0xf; > - pll_write(base + REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3, data); > - > - data = pout->plllock_cmp & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP1, data); > - > - data = (pout->plllock_cmp >> 8) & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP2, data); > - > - data = (pout->plllock_cmp >> 16) & 0x3; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP3, data); > - > - data = pin->plllock_cnt << 1 | pin->plllock_rng << 3; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLLLOCK_CMP_EN, data); > - > - data = pout->pll_vco_count & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT1, data); > - data = (pout->pll_vco_count >> 8) & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_VCO_COUNT2, data); > - > - data = pout->pll_kvco_count & 0xff; > - pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT1, data); > - data = (pout->pll_kvco_count >> 8) & 0x3; > - pll_write(base + REG_DSI_14nm_PHY_PLL_KVCO_COUNT2, data); > - > - data = (pout->pll_postdiv - 1) << 4 | pin->pll_lpf_res1; > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_LPF2_POSTDIV, data); > - > - if (pin->ssc_en) > - pll_db_commit_ssc(pll); > - > - wmb(); /* make sure register committed */ > -} > - > -/* > - * VCO clock Callbacks > - */ > -static int dsi_pll_14nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - struct dsi_pll_input *pin = &pll_14nm->in; > - struct dsi_pll_output *pout = &pll_14nm->out; > - > - DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_14nm->id, rate, > - parent_rate); > - > - pll_14nm->vco_current_rate = rate; > - pll_14nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > - > - dsi_pll_14nm_input_init(pll_14nm); > - > - /* > - * This configures the post divider internal to the VCO. It's > - * fixed to divide by 1 for now. > - * > - * tx_band = pll_postdiv. > - * 0: divided by 1 > - * 1: divided by 2 > - * 2: divided by 4 > - * 3: divided by 8 > - */ > - pout->pll_postdiv = DSI_PLL_DEFAULT_VCO_POSTDIV; > - > - pll_14nm_dec_frac_calc(pll_14nm); > - > - if (pin->ssc_en) > - pll_14nm_ssc_calc(pll_14nm); > - > - pll_14nm_calc_vco_count(pll_14nm); > - > - /* commit the slave DSI PLL registers if we're master. Note that we > - * don't lock the slave PLL. We just ensure that the PLL/PHY > registers > - * of the master and slave are identical > - */ > - if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > - struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > - > - pll_db_commit_14nm(pll_14nm_slave, pin, pout); > - } > - > - pll_db_commit_14nm(pll_14nm, pin, pout); > - > - return 0; > -} > - > -static unsigned long dsi_pll_14nm_vco_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - void __iomem *base = pll_14nm->mmio; > - u64 vco_rate, multiplier = BIT(20); > - u32 div_frac_start; > - u32 dec_start; > - u64 ref_clk = parent_rate; > - > - dec_start = pll_read(base + REG_DSI_14nm_PHY_PLL_DEC_START); > - dec_start &= 0x0ff; > - > - DBG("dec_start = %x", dec_start); > - > - div_frac_start = (pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START3) > - & 0xf) << 16; > - div_frac_start |= (pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START2) > - & 0xff) << 8; > - div_frac_start |= pll_read(base + > REG_DSI_14nm_PHY_PLL_DIV_FRAC_START1) > - & 0xff; > - > - DBG("div_frac_start = %x", div_frac_start); > - > - vco_rate = ref_clk * dec_start; > - > - vco_rate += ((ref_clk * div_frac_start) / multiplier); > - > - /* > - * Recalculating the rate from dec_start and frac_start doesn't end > up > - * the rate we originally set. Convert the freq to KHz, round it up > and > - * convert it back to MHz. > - */ > - vco_rate = DIV_ROUND_UP_ULL(vco_rate, 1000) * 1000; > - > - DBG("returning vco rate = %lu", (unsigned long)vco_rate); > - > - return (unsigned long)vco_rate; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_14nm_vco = { > - .round_rate = msm_dsi_pll_helper_clk_round_rate, > - .set_rate = dsi_pll_14nm_vco_set_rate, > - .recalc_rate = dsi_pll_14nm_vco_recalc_rate, > - .prepare = msm_dsi_pll_helper_clk_prepare, > - .unprepare = msm_dsi_pll_helper_clk_unprepare, > -}; > - > -/* > - * N1 and N2 post-divider clock callbacks > - */ > -#define div_mask(width) ((1 << (width)) - 1) > -static unsigned long dsi_pll_14nm_postdiv_recalc_rate(struct clk_hw > *hw, > - unsigned long parent_rate) > -{ > - struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > - struct dsi_pll_14nm *pll_14nm = postdiv->pll; > - void __iomem *base = pll_14nm->phy_cmn_mmio; > - u8 shift = postdiv->shift; > - u8 width = postdiv->width; > - u32 val; > - > - DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, parent_rate); > - > - val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0) >> shift; > - val &= div_mask(width); > - > - return divider_recalc_rate(hw, parent_rate, val, NULL, > - postdiv->flags, width); > -} > - > -static long dsi_pll_14nm_postdiv_round_rate(struct clk_hw *hw, > - unsigned long rate, > - unsigned long *prate) > -{ > - struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > - struct dsi_pll_14nm *pll_14nm = postdiv->pll; > - > - DBG("DSI%d PLL parent rate=%lu", pll_14nm->id, rate); > - > - return divider_round_rate(hw, rate, prate, NULL, > - postdiv->width, > - postdiv->flags); > -} > - > -static int dsi_pll_14nm_postdiv_set_rate(struct clk_hw *hw, unsigned > long rate, > - unsigned long parent_rate) > -{ > - struct dsi_pll_14nm_postdiv *postdiv = to_pll_14nm_postdiv(hw); > - struct dsi_pll_14nm *pll_14nm = postdiv->pll; > - void __iomem *base = pll_14nm->phy_cmn_mmio; > - spinlock_t *lock = &pll_14nm->postdiv_lock; > - u8 shift = postdiv->shift; > - u8 width = postdiv->width; > - unsigned int value; > - unsigned long flags = 0; > - u32 val; > - > - DBG("DSI%d PLL parent rate=%lu parent rate %lu", pll_14nm->id, rate, > - parent_rate); > - > - value = divider_get_val(rate, parent_rate, NULL, postdiv->width, > - postdiv->flags); > - > - spin_lock_irqsave(lock, flags); > - > - val = pll_read(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0); > - val &= ~(div_mask(width) << shift); > - > - val |= value << shift; > - pll_write(base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val); > - > - /* If we're master in dual DSI mode, then the slave PLL's > post-dividers > - * follow the master's post dividers > - */ > - if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > - struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > - void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio; > - > - pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, val); > - } > - > - spin_unlock_irqrestore(lock, flags); > - > - return 0; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_14nm_postdiv = { > - .recalc_rate = dsi_pll_14nm_postdiv_recalc_rate, > - .round_rate = dsi_pll_14nm_postdiv_round_rate, > - .set_rate = dsi_pll_14nm_postdiv_set_rate, > -}; > - > -/* > - * PLL Callbacks > - */ > - > -static int dsi_pll_14nm_enable_seq(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - void __iomem *base = pll_14nm->mmio; > - void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > - bool locked; > - > - DBG(""); > - > - pll_write(base + REG_DSI_14nm_PHY_PLL_VREF_CFG1, 0x10); > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 1); > - > - locked = pll_14nm_poll_for_ready(pll_14nm, POLL_MAX_READS, > - POLL_TIMEOUT_US); > - > - if (unlikely(!locked)) > - DRM_DEV_ERROR(&pll_14nm->pdev->dev, "DSI PLL lock failed\n"); > - else > - DBG("DSI PLL lock success"); > - > - return locked ? 0 : -EINVAL; > -} > - > -static void dsi_pll_14nm_disable_seq(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > - > - DBG(""); > - > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_PLL_CNTRL, 0); > -} > - > -static void dsi_pll_14nm_save_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state; > - void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > - u32 data; > - > - data = pll_read(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0); > - > - cached_state->n1postdiv = data & 0xf; > - cached_state->n2postdiv = (data >> 4) & 0xf; > - > - DBG("DSI%d PLL save state %x %x", pll_14nm->id, > - cached_state->n1postdiv, cached_state->n2postdiv); > - > - cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > -} > - > -static int dsi_pll_14nm_restore_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - struct pll_14nm_cached_state *cached_state = &pll_14nm->cached_state; > - void __iomem *cmn_base = pll_14nm->phy_cmn_mmio; > - u32 data; > - int ret; > - > - ret = dsi_pll_14nm_vco_set_rate(&pll->clk_hw, > - cached_state->vco_rate, 0); > - if (ret) { > - DRM_DEV_ERROR(&pll_14nm->pdev->dev, > - "restore vco rate failed. ret=%d\n", ret); > - return ret; > - } > - > - data = cached_state->n1postdiv | (cached_state->n2postdiv << 4); > - > - DBG("DSI%d PLL restore state %x %x", pll_14nm->id, > - cached_state->n1postdiv, cached_state->n2postdiv); > - > - pll_write(cmn_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data); > - > - /* also restore post-dividers for slave DSI PLL */ > - if (pll_14nm->uc == MSM_DSI_PHY_MASTER) { > - struct dsi_pll_14nm *pll_14nm_slave = pll_14nm->slave; > - void __iomem *slave_base = pll_14nm_slave->phy_cmn_mmio; > - > - pll_write(slave_base + REG_DSI_14nm_PHY_CMN_CLK_CFG0, data); > - } > - > - return 0; > -} > - > -static int dsi_pll_14nm_set_usecase(struct msm_dsi_pll *pll, > - enum msm_dsi_phy_usecase uc) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - void __iomem *base = pll_14nm->mmio; > - u32 clkbuflr_en, bandgap = 0; > - > - switch (uc) { > - case MSM_DSI_PHY_STANDALONE: > - clkbuflr_en = 0x1; > - break; > - case MSM_DSI_PHY_MASTER: > - clkbuflr_en = 0x3; > - pll_14nm->slave = pll_14nm_list[(pll_14nm->id + 1) % DSI_MAX]; > - break; > - case MSM_DSI_PHY_SLAVE: > - clkbuflr_en = 0x0; > - bandgap = 0x3; > - break; > - default: > - return -EINVAL; > - } > - > - pll_write(base + REG_DSI_14nm_PHY_PLL_CLKBUFLR_EN, clkbuflr_en); > - if (bandgap) > - pll_write(base + REG_DSI_14nm_PHY_PLL_PLL_BANDGAP, bandgap); > - > - pll_14nm->uc = uc; > - > - return 0; > -} > - > -static int dsi_pll_14nm_get_provider(struct msm_dsi_pll *pll, > - struct clk **byte_clk_provider, > - struct clk **pixel_clk_provider) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - struct clk_hw_onecell_data *hw_data = pll_14nm->hw_data; > - > - if (byte_clk_provider) > - *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > - if (pixel_clk_provider) > - *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > - > - return 0; > -} > - > -static void dsi_pll_14nm_destroy(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_14nm *pll_14nm = to_pll_14nm(pll); > - struct platform_device *pdev = pll_14nm->pdev; > - int num_hws = pll_14nm->num_hws; > - > - of_clk_del_provider(pdev->dev.of_node); > - > - while (num_hws--) > - clk_hw_unregister(pll_14nm->hws[num_hws]); > -} > - > -static struct clk_hw *pll_14nm_postdiv_register(struct dsi_pll_14nm > *pll_14nm, > - const char *name, > - const char *parent_name, > - unsigned long flags, > - u8 shift) > -{ > - struct dsi_pll_14nm_postdiv *pll_postdiv; > - struct device *dev = &pll_14nm->pdev->dev; > - struct clk_init_data postdiv_init = { > - .parent_names = (const char *[]) { parent_name }, > - .num_parents = 1, > - .name = name, > - .flags = flags, > - .ops = &clk_ops_dsi_pll_14nm_postdiv, > - }; > - int ret; > - > - pll_postdiv = devm_kzalloc(dev, sizeof(*pll_postdiv), GFP_KERNEL); > - if (!pll_postdiv) > - return ERR_PTR(-ENOMEM); > - > - pll_postdiv->pll = pll_14nm; > - pll_postdiv->shift = shift; > - /* both N1 and N2 postdividers are 4 bits wide */ > - pll_postdiv->width = 4; > - /* range of each divider is from 1 to 15 */ > - pll_postdiv->flags = CLK_DIVIDER_ONE_BASED; > - pll_postdiv->hw.init = &postdiv_init; > - > - ret = clk_hw_register(dev, &pll_postdiv->hw); > - if (ret) > - return ERR_PTR(ret); > - > - return &pll_postdiv->hw; > -} > - > -static int pll_14nm_register(struct dsi_pll_14nm *pll_14nm) > -{ > - char clk_name[32], parent[32], vco_name[32]; > - struct clk_init_data vco_init = { > - .parent_names = (const char *[]){ "xo" }, > - .num_parents = 1, > - .name = vco_name, > - .flags = CLK_IGNORE_UNUSED, > - .ops = &clk_ops_dsi_pll_14nm_vco, > - }; > - struct device *dev = &pll_14nm->pdev->dev; > - struct clk_hw **hws = pll_14nm->hws; > - struct clk_hw_onecell_data *hw_data; > - struct clk_hw *hw; > - int num = 0; > - int ret; > - > - DBG("DSI%d", pll_14nm->id); > - > - hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > - NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > - GFP_KERNEL); > - if (!hw_data) > - return -ENOMEM; > - > - snprintf(vco_name, 32, "dsi%dvco_clk", pll_14nm->id); > - pll_14nm->base.clk_hw.init = &vco_init; > - > - ret = clk_hw_register(dev, &pll_14nm->base.clk_hw); > - if (ret) > - return ret; > - > - hws[num++] = &pll_14nm->base.clk_hw; > - > - snprintf(clk_name, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > - snprintf(parent, 32, "dsi%dvco_clk", pll_14nm->id); > - > - /* N1 postdiv, bits 0-3 in REG_DSI_14nm_PHY_CMN_CLK_CFG0 */ > - hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, > - CLK_SET_RATE_PARENT, 0); > - if (IS_ERR(hw)) > - return PTR_ERR(hw); > - > - hws[num++] = hw; > - > - snprintf(clk_name, 32, "dsi%dpllbyte", pll_14nm->id); > - snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > - > - /* DSI Byte clock = VCO_CLK / N1 / 8 */ > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - CLK_SET_RATE_PARENT, 1, 8); > - if (IS_ERR(hw)) > - return PTR_ERR(hw); > - > - hws[num++] = hw; > - hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > - > - snprintf(clk_name, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id); > - snprintf(parent, 32, "dsi%dn1_postdiv_clk", pll_14nm->id); > - > - /* > - * Skip the mux for now, force DSICLK_SEL to 1, Add a /2 divider > - * on the way. Don't let it set parent. > - */ > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, 0, 1, 2); > - if (IS_ERR(hw)) > - return PTR_ERR(hw); > - > - hws[num++] = hw; > - > - snprintf(clk_name, 32, "dsi%dpll", pll_14nm->id); > - snprintf(parent, 32, "dsi%dn1_postdivby2_clk", pll_14nm->id); > - > - /* DSI pixel clock = VCO_CLK / N1 / 2 / N2 > - * This is the output of N2 post-divider, bits 4-7 in > - * REG_DSI_14nm_PHY_CMN_CLK_CFG0. Don't let it set parent. > - */ > - hw = pll_14nm_postdiv_register(pll_14nm, clk_name, parent, 0, 4); > - if (IS_ERR(hw)) > - return PTR_ERR(hw); > - > - hws[num++] = hw; > - hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > - > - pll_14nm->num_hws = num; > - > - hw_data->num = NUM_PROVIDED_CLKS; > - pll_14nm->hw_data = hw_data; > - > - ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > - pll_14nm->hw_data); > - if (ret) { > - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > - return ret; > - } > - > - return 0; > -} > - > -struct msm_dsi_pll *msm_dsi_pll_14nm_init(struct platform_device > *pdev, int id) > -{ > - struct dsi_pll_14nm *pll_14nm; > - struct msm_dsi_pll *pll; > - int ret; > - > - if (!pdev) > - return ERR_PTR(-ENODEV); > - > - pll_14nm = devm_kzalloc(&pdev->dev, sizeof(*pll_14nm), GFP_KERNEL); > - if (!pll_14nm) > - return ERR_PTR(-ENOMEM); > - > - DBG("PLL%d", id); > - > - pll_14nm->pdev = pdev; > - pll_14nm->id = id; > - pll_14nm_list[id] = pll_14nm; > - > - pll_14nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > - if (IS_ERR_OR_NULL(pll_14nm->phy_cmn_mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - pll_14nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > - if (IS_ERR_OR_NULL(pll_14nm->mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - spin_lock_init(&pll_14nm->postdiv_lock); > - > - pll = &pll_14nm->base; > - pll->min_rate = VCO_MIN_RATE; > - pll->max_rate = VCO_MAX_RATE; > - pll->get_provider = dsi_pll_14nm_get_provider; > - pll->destroy = dsi_pll_14nm_destroy; > - pll->disable_seq = dsi_pll_14nm_disable_seq; > - pll->save_state = dsi_pll_14nm_save_state; > - pll->restore_state = dsi_pll_14nm_restore_state; > - pll->set_usecase = dsi_pll_14nm_set_usecase; > - > - pll_14nm->vco_delay = 1; > - > - pll->en_seq_cnt = 1; > - pll->enable_seqs[0] = dsi_pll_14nm_enable_seq; > - > - ret = pll_14nm_register(pll_14nm); > - if (ret) { > - DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > - return ERR_PTR(ret); > - } > - > - return pll; > -} > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c > b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c > deleted file mode 100644 > index 37a1f996a588..000000000000 > --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c > +++ /dev/null > @@ -1,643 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-only > -/* > - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. > - */ > - > -#include > -#include > - > -#include "dsi_pll.h" > -#include "dsi.xml.h" > - > -/* > - * DSI PLL 28nm - clock diagram (eg: DSI0): > - * > - * dsi0analog_postdiv_clk > - * | dsi0indirect_path_div2_clk > - * | | > - * +------+ | +----+ | |\ dsi0byte_mux > - * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ | > - * | +------+ +----+ | m| | +----+ > - * | | u|--o--| /4 |-- > dsi0pllbyte > - * | | x| +----+ > - * o--------------------------| / > - * | |/ > - * | +------+ > - * o----------| DIV3 |------------------------- dsi0pll > - * +------+ > - */ > - > -#define POLL_MAX_READS 10 > -#define POLL_TIMEOUT_US 50 > - > -#define NUM_PROVIDED_CLKS 2 > - > -#define VCO_REF_CLK_RATE 19200000 > -#define VCO_MIN_RATE 350000000 > -#define VCO_MAX_RATE 750000000 > - > -#define DSI_BYTE_PLL_CLK 0 > -#define DSI_PIXEL_PLL_CLK 1 > - > -#define LPFR_LUT_SIZE 10 > -struct lpfr_cfg { > - unsigned long vco_rate; > - u32 resistance; > -}; > - > -/* Loop filter resistance: */ > -static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = { > - { 479500000, 8 }, > - { 480000000, 11 }, > - { 575500000, 8 }, > - { 576000000, 12 }, > - { 610500000, 8 }, > - { 659500000, 9 }, > - { 671500000, 10 }, > - { 672000000, 14 }, > - { 708500000, 10 }, > - { 750000000, 11 }, > -}; > - > -struct pll_28nm_cached_state { > - unsigned long vco_rate; > - u8 postdiv3; > - u8 postdiv1; > - u8 byte_mux; > -}; > - > -struct dsi_pll_28nm { > - struct msm_dsi_pll base; > - > - int id; > - struct platform_device *pdev; > - void __iomem *mmio; > - > - int vco_delay; > - > - /* private clocks: */ > - struct clk *clks[NUM_DSI_CLOCKS_MAX]; > - u32 num_clks; > - > - /* clock-provider: */ > - struct clk *provided_clks[NUM_PROVIDED_CLKS]; > - struct clk_onecell_data clk_data; > - > - struct pll_28nm_cached_state cached_state; > -}; > - > -#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base) > - > -static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, > - u32 nb_tries, u32 timeout_us) > -{ > - bool pll_locked = false; > - u32 val; > - > - while (nb_tries--) { > - val = pll_read(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_STATUS); > - pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY); > - > - if (pll_locked) > - break; > - > - udelay(timeout_us); > - } > - DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > - > - return pll_locked; > -} > - > -static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm) > -{ > - void __iomem *base = pll_28nm->mmio; > - > - /* > - * Add HW recommended delays after toggling the software > - * reset bit off and back on. > - */ > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, > - DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1); > -} > - > -/* > - * Clock Callbacks > - */ > -static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct device *dev = &pll_28nm->pdev->dev; > - void __iomem *base = pll_28nm->mmio; > - unsigned long div_fbx1000, gen_vco_clk; > - u32 refclk_cfg, frac_n_mode, frac_n_value; > - u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3; > - u32 cal_cfg10, cal_cfg11; > - u32 rem; > - int i; > - > - VERB("rate=%lu, parent's=%lu", rate, parent_rate); > - > - /* Force postdiv2 to be div-4 */ > - pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3); > - > - /* Configure the Loop filter resistance */ > - for (i = 0; i < LPFR_LUT_SIZE; i++) > - if (rate <= lpfr_lut[i].vco_rate) > - break; > - if (i == LPFR_LUT_SIZE) { > - DRM_DEV_ERROR(dev, "unable to get loop filter resistance. > vco=%lu\n", > - rate); > - return -EINVAL; > - } > - pll_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, > lpfr_lut[i].resistance); > - > - /* Loop filter capacitance values : c1 and c2 */ > - pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70); > - pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15); > - > - rem = rate % VCO_REF_CLK_RATE; > - if (rem) { > - refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; > - frac_n_mode = 1; > - div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500); > - gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500); > - } else { > - refclk_cfg = 0x0; > - frac_n_mode = 0; > - div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000); > - gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000); > - } > - > - DBG("refclk_cfg = %d", refclk_cfg); > - > - rem = div_fbx1000 % 1000; > - frac_n_value = (rem << 16) / 1000; > - > - DBG("div_fb = %lu", div_fbx1000); > - DBG("frac_n_value = %d", frac_n_value); > - > - DBG("Generated VCO Clock: %lu", gen_vco_clk); > - rem = 0; > - sdm_cfg1 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1); > - sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK; > - if (frac_n_mode) { > - sdm_cfg0 = 0x0; > - sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0); > - sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET( > - (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); > - sdm_cfg3 = frac_n_value >> 8; > - sdm_cfg2 = frac_n_value & 0xff; > - } else { > - sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP; > - sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV( > - (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); > - sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0); > - sdm_cfg2 = 0; > - sdm_cfg3 = 0; > - } > - > - DBG("sdm_cfg0=%d", sdm_cfg0); > - DBG("sdm_cfg1=%d", sdm_cfg1); > - DBG("sdm_cfg2=%d", sdm_cfg2); > - DBG("sdm_cfg3=%d", sdm_cfg3); > - > - cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000)); > - cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000); > - DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11); > - > - pll_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06); > - pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); > - > - pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1); > - pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2, > - DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); > - pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3, > - DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); > - pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00); > - > - /* Add hardware recommended delay for correct PLL configuration */ > - if (pll_28nm->vco_delay) > - udelay(pll_28nm->vco_delay); > - > - pll_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg); > - pll_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00); > - pll_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31); > - pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff); > - pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff); > - pll_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20); > - > - return 0; > -} > - > -static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, > - POLL_TIMEOUT_US); > -} > - > -static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - void __iomem *base = pll_28nm->mmio; > - u32 sdm0, doubler, sdm_byp_div; > - u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; > - u32 ref_clk = VCO_REF_CLK_RATE; > - unsigned long vco_rate; > - > - VERB("parent_rate=%lu", parent_rate); > - > - /* Check to see if the ref clk doubler is enabled */ > - doubler = pll_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) & > - DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; > - ref_clk += (doubler * VCO_REF_CLK_RATE); > - > - /* see if it is integer mode or sdm mode */ > - sdm0 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0); > - if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) { > - /* integer mode */ > - sdm_byp_div = FIELD( > - pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0), > - DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1; > - vco_rate = ref_clk * sdm_byp_div; > - } else { > - /* sdm mode */ > - sdm_dc_off = FIELD( > - pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1), > - DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET); > - DBG("sdm_dc_off = %d", sdm_dc_off); > - sdm2 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2), > - DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0); > - sdm3 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3), > - DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8); > - sdm_freq_seed = (sdm3 << 8) | sdm2; > - DBG("sdm_freq_seed = %d", sdm_freq_seed); > - > - vco_rate = (ref_clk * (sdm_dc_off + 1)) + > - mult_frac(ref_clk, sdm_freq_seed, BIT(16)); > - DBG("vco rate = %lu", vco_rate); > - } > - > - DBG("returning vco rate = %lu", vco_rate); > - > - return vco_rate; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_28nm_vco = { > - .round_rate = msm_dsi_pll_helper_clk_round_rate, > - .set_rate = dsi_pll_28nm_clk_set_rate, > - .recalc_rate = dsi_pll_28nm_clk_recalc_rate, > - .prepare = msm_dsi_pll_helper_clk_prepare, > - .unprepare = msm_dsi_pll_helper_clk_unprepare, > - .is_enabled = dsi_pll_28nm_clk_is_enabled, > -}; > - > -/* > - * PLL Callbacks > - */ > -static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct device *dev = &pll_28nm->pdev->dev; > - void __iomem *base = pll_28nm->mmio; > - u32 max_reads = 5, timeout_us = 100; > - bool locked; > - u32 val; > - int i; > - > - DBG("id=%d", pll_28nm->id); > - > - pll_28nm_software_reset(pll_28nm); > - > - /* > - * PLL power up sequence. > - * Add necessary delays recommended by hardware. > - */ > - val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); > - > - for (i = 0; i < 2; i++) { > - /* DSI Uniphy lock detect setting */ > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, > - 0x0c, 100); > - pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); > - > - /* poll for PLL ready status */ > - locked = pll_28nm_poll_for_ready(pll_28nm, > - max_reads, timeout_us); > - if (locked) > - break; > - > - pll_28nm_software_reset(pll_28nm); > - > - /* > - * PLL power up sequence. > - * Add necessary delays recommended by hardware. > - */ > - val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250); > - > - val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); > - } > - > - if (unlikely(!locked)) > - DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > - else > - DBG("DSI PLL Lock success"); > - > - return locked ? 0 : -EINVAL; > -} > - > -static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct device *dev = &pll_28nm->pdev->dev; > - void __iomem *base = pll_28nm->mmio; > - bool locked; > - u32 max_reads = 10, timeout_us = 50; > - u32 val; > - > - DBG("id=%d", pll_28nm->id); > - > - pll_28nm_software_reset(pll_28nm); > - > - /* > - * PLL power up sequence. > - * Add necessary delays recommended by hardware. > - */ > - pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500); > - > - val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; > - pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; > - pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > - > - val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B | > - DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; > - pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); > - > - /* DSI PLL toggle lock detect setting */ > - pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500); > - pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512); > - > - locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); > - > - if (unlikely(!locked)) > - DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > - else > - DBG("DSI PLL lock success"); > - > - return locked ? 0 : -EINVAL; > -} > - > -static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - DBG("id=%d", pll_28nm->id); > - pll_write(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00); > -} > - > -static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > - void __iomem *base = pll_28nm->mmio; > - > - cached_state->postdiv3 = > - pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG); > - cached_state->postdiv1 = > - pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG); > - cached_state->byte_mux = pll_read(base + > REG_DSI_28nm_PHY_PLL_VREG_CFG); > - if (dsi_pll_28nm_clk_is_enabled(&pll->clk_hw)) > - cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > - else > - cached_state->vco_rate = 0; > -} > - > -static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > - void __iomem *base = pll_28nm->mmio; > - int ret; > - > - ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw, > - cached_state->vco_rate, 0); > - if (ret) { > - DRM_DEV_ERROR(&pll_28nm->pdev->dev, > - "restore vco rate failed. ret=%d\n", ret); > - return ret; > - } > - > - pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, > - cached_state->postdiv3); > - pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, > - cached_state->postdiv1); > - pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG, > - cached_state->byte_mux); > - > - return 0; > -} > - > -static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll, > - struct clk **byte_clk_provider, > - struct clk **pixel_clk_provider) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - if (byte_clk_provider) > - *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK]; > - if (pixel_clk_provider) > - *pixel_clk_provider = > - pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK]; > - > - return 0; > -} > - > -static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - int i; > - > - msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev, > - pll_28nm->clks, pll_28nm->num_clks); > - > - for (i = 0; i < NUM_PROVIDED_CLKS; i++) > - pll_28nm->provided_clks[i] = NULL; > - > - pll_28nm->num_clks = 0; > - pll_28nm->clk_data.clks = NULL; > - pll_28nm->clk_data.clk_num = 0; > -} > - > -static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) > -{ > - char clk_name[32], parent1[32], parent2[32], vco_name[32]; > - struct clk_init_data vco_init = { > - .parent_names = (const char *[]){ "xo" }, > - .num_parents = 1, > - .name = vco_name, > - .flags = CLK_IGNORE_UNUSED, > - .ops = &clk_ops_dsi_pll_28nm_vco, > - }; > - struct device *dev = &pll_28nm->pdev->dev; > - struct clk **clks = pll_28nm->clks; > - struct clk **provided_clks = pll_28nm->provided_clks; > - int num = 0; > - int ret; > - > - DBG("%d", pll_28nm->id); > - > - snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); > - pll_28nm->base.clk_hw.init = &vco_init; > - clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw); > - > - snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); > - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > - clks[num++] = clk_register_divider(dev, clk_name, > - parent1, CLK_SET_RATE_PARENT, > - pll_28nm->mmio + > - REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, > - 0, 4, 0, NULL); > - > - snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); > - snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); > - clks[num++] = clk_register_fixed_factor(dev, clk_name, > - parent1, CLK_SET_RATE_PARENT, > - 1, 2); > - > - snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); > - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > - clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] = > - clk_register_divider(dev, clk_name, > - parent1, 0, pll_28nm->mmio + > - REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, > - 0, 8, 0, NULL); > - > - snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id); > - snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); > - snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); > - clks[num++] = clk_register_mux(dev, clk_name, > - ((const char *[]){ > - parent1, parent2 > - }), 2, CLK_SET_RATE_PARENT, pll_28nm->mmio + > - REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); > - > - snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); > - snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id); > - clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] = > - clk_register_fixed_factor(dev, clk_name, > - parent1, CLK_SET_RATE_PARENT, 1, 4); > - > - pll_28nm->num_clks = num; > - > - pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS; > - pll_28nm->clk_data.clks = provided_clks; > - > - ret = of_clk_add_provider(dev->of_node, > - of_clk_src_onecell_get, &pll_28nm->clk_data); > - if (ret) { > - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > - return ret; > - } > - > - return 0; > -} > - > -struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device > *pdev, > - enum msm_dsi_phy_type type, int id) > -{ > - struct dsi_pll_28nm *pll_28nm; > - struct msm_dsi_pll *pll; > - int ret; > - > - if (!pdev) > - return ERR_PTR(-ENODEV); > - > - pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); > - if (!pll_28nm) > - return ERR_PTR(-ENOMEM); > - > - pll_28nm->pdev = pdev; > - pll_28nm->id = id; > - > - pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > - if (IS_ERR_OR_NULL(pll_28nm->mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__); > - return ERR_PTR(-ENOMEM); > - } > - > - pll = &pll_28nm->base; > - pll->min_rate = VCO_MIN_RATE; > - pll->max_rate = VCO_MAX_RATE; > - pll->get_provider = dsi_pll_28nm_get_provider; > - pll->destroy = dsi_pll_28nm_destroy; > - pll->disable_seq = dsi_pll_28nm_disable_seq; > - pll->save_state = dsi_pll_28nm_save_state; > - pll->restore_state = dsi_pll_28nm_restore_state; > - > - if (type == MSM_DSI_PHY_28NM_HPM) { > - pll_28nm->vco_delay = 1; > - > - pll->en_seq_cnt = 3; > - pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_hpm; > - pll->enable_seqs[1] = dsi_pll_28nm_enable_seq_hpm; > - pll->enable_seqs[2] = dsi_pll_28nm_enable_seq_hpm; > - } else if (type == MSM_DSI_PHY_28NM_LP) { > - pll_28nm->vco_delay = 1000; > - > - pll->en_seq_cnt = 1; > - pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp; > - } else { > - DRM_DEV_ERROR(&pdev->dev, "phy type (%d) is not 28nm\n", type); > - return ERR_PTR(-EINVAL); > - } > - > - ret = pll_28nm_register(pll_28nm); > - if (ret) { > - DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > - return ERR_PTR(ret); > - } > - > - return pll; > -} > - > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c > b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c > deleted file mode 100644 > index a6e7a2525fe0..000000000000 > --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm_8960.c > +++ /dev/null > @@ -1,526 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-only > -/* > - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. > - */ > - > -#include > - > -#include "dsi_pll.h" > -#include "dsi.xml.h" > - > -/* > - * DSI PLL 28nm (8960/A family) - clock diagram (eg: DSI1): > - * > - * > - * +------+ > - * dsi1vco_clk ----o-----| DIV1 |---dsi1pllbit (not exposed as clock) > - * F * byte_clk | +------+ > - * | bit clock divider (F / 8) > - * | > - * | +------+ > - * o-----| DIV2 |---dsi0pllbyte---o---> To byte RCG > - * | +------+ | (sets parent > rate) > - * | byte clock divider (F) | > - * | | > - * | o---> To esc RCG > - * | (doesn't set > parent rate) > - * | > - * | +------+ > - * o-----| DIV3 |----dsi0pll------o---> To dsi RCG > - * +------+ | (sets parent > rate) > - * dsi clock divider (F * magic) | > - * | > - * o---> To pixel rcg > - * (doesn't set > parent rate) > - */ > - > -#define POLL_MAX_READS 8000 > -#define POLL_TIMEOUT_US 1 > - > -#define NUM_PROVIDED_CLKS 2 > - > -#define VCO_REF_CLK_RATE 27000000 > -#define VCO_MIN_RATE 600000000 > -#define VCO_MAX_RATE 1200000000 > - > -#define DSI_BYTE_PLL_CLK 0 > -#define DSI_PIXEL_PLL_CLK 1 > - > -#define VCO_PREF_DIV_RATIO 27 > - > -struct pll_28nm_cached_state { > - unsigned long vco_rate; > - u8 postdiv3; > - u8 postdiv2; > - u8 postdiv1; > -}; > - > -struct clk_bytediv { > - struct clk_hw hw; > - void __iomem *reg; > -}; > - > -struct dsi_pll_28nm { > - struct msm_dsi_pll base; > - > - int id; > - struct platform_device *pdev; > - void __iomem *mmio; > - > - /* custom byte clock divider */ > - struct clk_bytediv *bytediv; > - > - /* private clocks: */ > - struct clk *clks[NUM_DSI_CLOCKS_MAX]; > - u32 num_clks; > - > - /* clock-provider: */ > - struct clk *provided_clks[NUM_PROVIDED_CLKS]; > - struct clk_onecell_data clk_data; > - > - struct pll_28nm_cached_state cached_state; > -}; > - > -#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base) > - > -static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, > - int nb_tries, int timeout_us) > -{ > - bool pll_locked = false; > - u32 val; > - > - while (nb_tries--) { > - val = pll_read(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_RDY); > - pll_locked = !!(val & DSI_28nm_8960_PHY_PLL_RDY_PLL_RDY); > - > - if (pll_locked) > - break; > - > - udelay(timeout_us); > - } > - DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); > - > - return pll_locked; > -} > - > -/* > - * Clock Callbacks > - */ > -static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - void __iomem *base = pll_28nm->mmio; > - u32 val, temp, fb_divider; > - > - DBG("rate=%lu, parent's=%lu", rate, parent_rate); > - > - temp = rate / 10; > - val = VCO_REF_CLK_RATE / 10; > - fb_divider = (temp * VCO_PREF_DIV_RATIO) / val; > - fb_divider = fb_divider / 2 - 1; > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1, > - fb_divider & 0xff); > - > - val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2); > - > - val |= (fb_divider >> 8) & 0x07; > - > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2, > - val); > - > - val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3); > - > - val |= (VCO_PREF_DIV_RATIO - 1) & 0x3f; > - > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3, > - val); > - > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_6, > - 0xf); > - > - val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > - val |= 0x7 << 4; > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, > - val); > - > - return 0; > -} > - > -static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, > - POLL_TIMEOUT_US); > -} > - > -static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - void __iomem *base = pll_28nm->mmio; > - unsigned long vco_rate; > - u32 status, fb_divider, temp, ref_divider; > - > - VERB("parent_rate=%lu", parent_rate); > - > - status = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0); > - > - if (status & DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE) { > - fb_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_1); > - fb_divider &= 0xff; > - temp = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_2) & 0x07; > - fb_divider = (temp << 8) | fb_divider; > - fb_divider += 1; > - > - ref_divider = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_3); > - ref_divider &= 0x3f; > - ref_divider += 1; > - > - /* multiply by 2 */ > - vco_rate = (parent_rate / ref_divider) * fb_divider * 2; > - } else { > - vco_rate = 0; > - } > - > - DBG("returning vco rate = %lu", vco_rate); > - > - return vco_rate; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_28nm_vco = { > - .round_rate = msm_dsi_pll_helper_clk_round_rate, > - .set_rate = dsi_pll_28nm_clk_set_rate, > - .recalc_rate = dsi_pll_28nm_clk_recalc_rate, > - .prepare = msm_dsi_pll_helper_clk_prepare, > - .unprepare = msm_dsi_pll_helper_clk_unprepare, > - .is_enabled = dsi_pll_28nm_clk_is_enabled, > -}; > - > -/* > - * Custom byte clock divier clk_ops > - * > - * This clock is the entry point to configuring the PLL. The user (dsi > host) > - * will set this clock's rate to the desired byte clock rate. The VCO > lock > - * frequency is a multiple of the byte clock rate. The multiplication > factor > - * (shown as F in the diagram above) is a function of the byte clock > rate. > - * > - * This custom divider clock ensures that its parent (VCO) is set to > the > - * desired rate, and that the byte clock postdivider (POSTDIV2) is > configured > - * accordingly > - */ > -#define to_clk_bytediv(_hw) container_of(_hw, struct clk_bytediv, hw) > - > -static unsigned long clk_bytediv_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct clk_bytediv *bytediv = to_clk_bytediv(hw); > - unsigned int div; > - > - div = pll_read(bytediv->reg) & 0xff; > - > - return parent_rate / (div + 1); > -} > - > -/* find multiplication factor(wrt byte clock) at which the VCO should > be set */ > -static unsigned int get_vco_mul_factor(unsigned long byte_clk_rate) > -{ > - unsigned long bit_mhz; > - > - /* convert to bit clock in Mhz */ > - bit_mhz = (byte_clk_rate * 8) / 1000000; > - > - if (bit_mhz < 125) > - return 64; > - else if (bit_mhz < 250) > - return 32; > - else if (bit_mhz < 600) > - return 16; > - else > - return 8; > -} > - > -static long clk_bytediv_round_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long *prate) > -{ > - unsigned long best_parent; > - unsigned int factor; > - > - factor = get_vco_mul_factor(rate); > - > - best_parent = rate * factor; > - *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); > - > - return *prate / factor; > -} > - > -static int clk_bytediv_set_rate(struct clk_hw *hw, unsigned long rate, > - unsigned long parent_rate) > -{ > - struct clk_bytediv *bytediv = to_clk_bytediv(hw); > - u32 val; > - unsigned int factor; > - > - factor = get_vco_mul_factor(rate); > - > - val = pll_read(bytediv->reg); > - val |= (factor - 1) & 0xff; > - pll_write(bytediv->reg, val); > - > - return 0; > -} > - > -/* Our special byte clock divider ops */ > -static const struct clk_ops clk_bytediv_ops = { > - .round_rate = clk_bytediv_round_rate, > - .set_rate = clk_bytediv_set_rate, > - .recalc_rate = clk_bytediv_recalc_rate, > -}; > - > -/* > - * PLL Callbacks > - */ > -static int dsi_pll_28nm_enable_seq(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct device *dev = &pll_28nm->pdev->dev; > - void __iomem *base = pll_28nm->mmio; > - bool locked; > - unsigned int bit_div, byte_div; > - int max_reads = 1000, timeout_us = 100; > - u32 val; > - > - DBG("id=%d", pll_28nm->id); > - > - /* > - * before enabling the PLL, configure the bit clock divider since we > - * don't expose it as a clock to the outside world > - * 1: read back the byte clock divider that should already be set > - * 2: divide by 8 to get bit clock divider > - * 3: write it to POSTDIV1 > - */ > - val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9); > - byte_div = val + 1; > - bit_div = byte_div / 8; > - > - val = pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > - val &= ~0xf; > - val |= (bit_div - 1); > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, val); > - > - /* enable the PLL */ > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, > - DSI_28nm_8960_PHY_PLL_CTRL_0_ENABLE); > - > - locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); > - > - if (unlikely(!locked)) > - DRM_DEV_ERROR(dev, "DSI PLL lock failed\n"); > - else > - DBG("DSI PLL lock success"); > - > - return locked ? 0 : -EINVAL; > -} > - > -static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - DBG("id=%d", pll_28nm->id); > - pll_write(pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_0, 0x00); > -} > - > -static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > - void __iomem *base = pll_28nm->mmio; > - > - cached_state->postdiv3 = > - pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10); > - cached_state->postdiv2 = > - pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9); > - cached_state->postdiv1 = > - pll_read(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8); > - > - cached_state->vco_rate = clk_hw_get_rate(&pll->clk_hw); > -} > - > -static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; > - void __iomem *base = pll_28nm->mmio; > - int ret; > - > - ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw, > - cached_state->vco_rate, 0); > - if (ret) { > - DRM_DEV_ERROR(&pll_28nm->pdev->dev, > - "restore vco rate failed. ret=%d\n", ret); > - return ret; > - } > - > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_10, > - cached_state->postdiv3); > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_9, > - cached_state->postdiv2); > - pll_write(base + REG_DSI_28nm_8960_PHY_PLL_CTRL_8, > - cached_state->postdiv1); > - > - return 0; > -} > - > -static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll, > - struct clk **byte_clk_provider, > - struct clk **pixel_clk_provider) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - if (byte_clk_provider) > - *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK]; > - if (pixel_clk_provider) > - *pixel_clk_provider = > - pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK]; > - > - return 0; > -} > - > -static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); > - > - msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev, > - pll_28nm->clks, pll_28nm->num_clks); > -} > - > -static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) > -{ > - char *clk_name, *parent_name, *vco_name; > - struct clk_init_data vco_init = { > - .parent_names = (const char *[]){ "pxo" }, > - .num_parents = 1, > - .flags = CLK_IGNORE_UNUSED, > - .ops = &clk_ops_dsi_pll_28nm_vco, > - }; > - struct device *dev = &pll_28nm->pdev->dev; > - struct clk **clks = pll_28nm->clks; > - struct clk **provided_clks = pll_28nm->provided_clks; > - struct clk_bytediv *bytediv; > - struct clk_init_data bytediv_init = { }; > - int ret, num = 0; > - > - DBG("%d", pll_28nm->id); > - > - bytediv = devm_kzalloc(dev, sizeof(*bytediv), GFP_KERNEL); > - if (!bytediv) > - return -ENOMEM; > - > - vco_name = devm_kzalloc(dev, 32, GFP_KERNEL); > - if (!vco_name) > - return -ENOMEM; > - > - parent_name = devm_kzalloc(dev, 32, GFP_KERNEL); > - if (!parent_name) > - return -ENOMEM; > - > - clk_name = devm_kzalloc(dev, 32, GFP_KERNEL); > - if (!clk_name) > - return -ENOMEM; > - > - pll_28nm->bytediv = bytediv; > - > - snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); > - vco_init.name = vco_name; > - > - pll_28nm->base.clk_hw.init = &vco_init; > - > - clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw); > - > - /* prepare and register bytediv */ > - bytediv->hw.init = &bytediv_init; > - bytediv->reg = pll_28nm->mmio + REG_DSI_28nm_8960_PHY_PLL_CTRL_9; > - > - snprintf(parent_name, 32, "dsi%dvco_clk", pll_28nm->id); > - snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); > - > - bytediv_init.name = clk_name; > - bytediv_init.ops = &clk_bytediv_ops; > - bytediv_init.flags = CLK_SET_RATE_PARENT; > - bytediv_init.parent_names = (const char * const *) &parent_name; > - bytediv_init.num_parents = 1; > - > - /* DIV2 */ > - clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] = > - clk_register(dev, &bytediv->hw); > - > - snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); > - /* DIV3 */ > - clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] = > - clk_register_divider(dev, clk_name, > - parent_name, 0, pll_28nm->mmio + > - REG_DSI_28nm_8960_PHY_PLL_CTRL_10, > - 0, 8, 0, NULL); > - > - pll_28nm->num_clks = num; > - > - pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS; > - pll_28nm->clk_data.clks = provided_clks; > - > - ret = of_clk_add_provider(dev->of_node, > - of_clk_src_onecell_get, &pll_28nm->clk_data); > - if (ret) { > - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > - return ret; > - } > - > - return 0; > -} > - > -struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device > *pdev, > - int id) > -{ > - struct dsi_pll_28nm *pll_28nm; > - struct msm_dsi_pll *pll; > - int ret; > - > - if (!pdev) > - return ERR_PTR(-ENODEV); > - > - pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); > - if (!pll_28nm) > - return ERR_PTR(-ENOMEM); > - > - pll_28nm->pdev = pdev; > - pll_28nm->id = id + 1; > - > - pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > - if (IS_ERR_OR_NULL(pll_28nm->mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "%s: failed to map pll base\n", __func__); > - return ERR_PTR(-ENOMEM); > - } > - > - pll = &pll_28nm->base; > - pll->min_rate = VCO_MIN_RATE; > - pll->max_rate = VCO_MAX_RATE; > - pll->get_provider = dsi_pll_28nm_get_provider; > - pll->destroy = dsi_pll_28nm_destroy; > - pll->disable_seq = dsi_pll_28nm_disable_seq; > - pll->save_state = dsi_pll_28nm_save_state; > - pll->restore_state = dsi_pll_28nm_restore_state; > - > - pll->en_seq_cnt = 1; > - pll->enable_seqs[0] = dsi_pll_28nm_enable_seq; > - > - ret = pll_28nm_register(pll_28nm); > - if (ret) { > - DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > - return ERR_PTR(ret); > - } > - > - return pll; > -} > diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c > b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c > deleted file mode 100644 > index e29b3bfd63d1..000000000000 > --- a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_7nm.c > +++ /dev/null > @@ -1,913 +0,0 @@ > -/* > - * SPDX-License-Identifier: GPL-2.0 > - * Copyright (c) 2018, The Linux Foundation > - */ > - > -#include > -#include > -#include > - > -#include "dsi_pll.h" > -#include "dsi.xml.h" > - > -/* > - * DSI PLL 7nm - clock diagram (eg: DSI0): TODO: updated CPHY diagram > - * > - * dsi0_pll_out_div_clk dsi0_pll_bit_clk > - * | | > - * | | > - * +---------+ | +----------+ | +----+ > - * dsi0vco_clk ---| out_div |--o--| divl_3_0 |--o--| /8 |-- > dsi0_phy_pll_out_byteclk > - * +---------+ | +----------+ | +----+ > - * | | > - * | | > dsi0_pll_by_2_bit_clk > - * | | | > - * | | +----+ | |\ > dsi0_pclk_mux > - * | |--| /2 |--o--| \ | > - * | | +----+ | \ > | +---------+ > - * | --------------| > |--o--| div_7_4 |-- dsi0_phy_pll_out_dsiclk > - * |------------------------------| / > +---------+ > - * | +-----+ | / > - * -----------| /4? |--o----------|/ > - * +-----+ | | > - * | > |dsiclk_sel > - * | > - * > dsi0_pll_post_out_div_clk > - */ > - > -#define DSI_BYTE_PLL_CLK 0 > -#define DSI_PIXEL_PLL_CLK 1 > -#define NUM_PROVIDED_CLKS 2 > - > -#define VCO_REF_CLK_RATE 19200000 > - > -struct dsi_pll_regs { > - u32 pll_prop_gain_rate; > - u32 pll_lockdet_rate; > - u32 decimal_div_start; > - u32 frac_div_start_low; > - u32 frac_div_start_mid; > - u32 frac_div_start_high; > - u32 pll_clock_inverters; > - u32 ssc_stepsize_low; > - u32 ssc_stepsize_high; > - u32 ssc_div_per_low; > - u32 ssc_div_per_high; > - u32 ssc_adjper_low; > - u32 ssc_adjper_high; > - u32 ssc_control; > -}; > - > -struct dsi_pll_config { > - u32 ref_freq; > - bool div_override; > - u32 output_div; > - bool ignore_frac; > - bool disable_prescaler; > - bool enable_ssc; > - bool ssc_center; > - u32 dec_bits; > - u32 frac_bits; > - u32 lock_timer; > - u32 ssc_freq; > - u32 ssc_offset; > - u32 ssc_adj_per; > - u32 thresh_cycles; > - u32 refclk_cycles; > -}; > - > -struct pll_7nm_cached_state { > - unsigned long vco_rate; > - u8 bit_clk_div; > - u8 pix_clk_div; > - u8 pll_out_div; > - u8 pll_mux; > -}; > - > -struct dsi_pll_7nm { > - struct msm_dsi_pll base; > - > - int id; > - struct platform_device *pdev; > - > - void __iomem *phy_cmn_mmio; > - void __iomem *mmio; > - > - u64 vco_ref_clk_rate; > - u64 vco_current_rate; > - > - /* protects REG_DSI_7nm_PHY_CMN_CLK_CFG0 register */ > - spinlock_t postdiv_lock; > - > - int vco_delay; > - struct dsi_pll_config pll_configuration; > - struct dsi_pll_regs reg_setup; > - > - /* private clocks: */ > - struct clk_hw *out_div_clk_hw; > - struct clk_hw *bit_clk_hw; > - struct clk_hw *byte_clk_hw; > - struct clk_hw *by_2_bit_clk_hw; > - struct clk_hw *post_out_div_clk_hw; > - struct clk_hw *pclk_mux_hw; > - struct clk_hw *out_dsiclk_hw; > - > - /* clock-provider: */ > - struct clk_hw_onecell_data *hw_data; > - > - struct pll_7nm_cached_state cached_state; > - > - enum msm_dsi_phy_usecase uc; > - struct dsi_pll_7nm *slave; > -}; > - > -#define to_pll_7nm(x) container_of(x, struct dsi_pll_7nm, base) > - > -/* > - * Global list of private DSI PLL struct pointers. We need this for > Dual DSI > - * mode, where the master PLL's clk_ops needs access the slave's > private data > - */ > -static struct dsi_pll_7nm *pll_7nm_list[DSI_MAX]; > - > -static void dsi_pll_setup_config(struct dsi_pll_7nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - > - config->ref_freq = pll->vco_ref_clk_rate; > - config->output_div = 1; > - config->dec_bits = 8; > - config->frac_bits = 18; > - config->lock_timer = 64; > - config->ssc_freq = 31500; > - config->ssc_offset = 4800; > - config->ssc_adj_per = 2; > - config->thresh_cycles = 32; > - config->refclk_cycles = 256; > - > - config->div_override = false; > - config->ignore_frac = false; > - config->disable_prescaler = false; > - > - /* TODO: ssc enable */ > - config->enable_ssc = false; > - config->ssc_center = 0; > -} > - > -static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - u64 fref = pll->vco_ref_clk_rate; > - u64 pll_freq; > - u64 divider; > - u64 dec, dec_multiple; > - u32 frac; > - u64 multiplier; > - > - pll_freq = pll->vco_current_rate; > - > - if (config->disable_prescaler) > - divider = fref; > - else > - divider = fref * 2; > - > - multiplier = 1 << config->frac_bits; > - dec_multiple = div_u64(pll_freq * multiplier, divider); > - div_u64_rem(dec_multiple, multiplier, &frac); > - > - dec = div_u64(dec_multiple, multiplier); > - > - if (pll->base.type != MSM_DSI_PHY_7NM_V4_1) > - regs->pll_clock_inverters = 0x28; > - else if (pll_freq <= 1000000000ULL) > - regs->pll_clock_inverters = 0xa0; > - else if (pll_freq <= 2500000000ULL) > - regs->pll_clock_inverters = 0x20; > - else if (pll_freq <= 3020000000ULL) > - regs->pll_clock_inverters = 0x00; > - else > - regs->pll_clock_inverters = 0x40; > - > - regs->pll_lockdet_rate = config->lock_timer; > - regs->decimal_div_start = dec; > - regs->frac_div_start_low = (frac & 0xff); > - regs->frac_div_start_mid = (frac & 0xff00) >> 8; > - regs->frac_div_start_high = (frac & 0x30000) >> 16; > -} > - > -#define SSC_CENTER BIT(0) > -#define SSC_EN BIT(1) > - > -static void dsi_pll_calc_ssc(struct dsi_pll_7nm *pll) > -{ > - struct dsi_pll_config *config = &pll->pll_configuration; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - u32 ssc_per; > - u32 ssc_mod; > - u64 ssc_step_size; > - u64 frac; > - > - if (!config->enable_ssc) { > - DBG("SSC not enabled\n"); > - return; > - } > - > - ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - > 1; > - ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); > - ssc_per -= ssc_mod; > - > - frac = regs->frac_div_start_low | > - (regs->frac_div_start_mid << 8) | > - (regs->frac_div_start_high << 16); > - ssc_step_size = regs->decimal_div_start; > - ssc_step_size *= (1 << config->frac_bits); > - ssc_step_size += frac; > - ssc_step_size *= config->ssc_offset; > - ssc_step_size *= (config->ssc_adj_per + 1); > - ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); > - ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); > - > - regs->ssc_div_per_low = ssc_per & 0xFF; > - regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; > - regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); > - regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); > - regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; > - regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; > - > - regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; > - > - pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", > - regs->decimal_div_start, frac, config->frac_bits); > - pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", > - ssc_per, (u32)ssc_step_size, config->ssc_adj_per); > -} > - > -static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll) > -{ > - void __iomem *base = pll->mmio; > - struct dsi_pll_regs *regs = &pll->reg_setup; > - > - if (pll->pll_configuration.enable_ssc) { > - pr_debug("SSC is enabled\n"); > - > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_LOW_1, > - regs->ssc_stepsize_low); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_STEPSIZE_HIGH_1, > - regs->ssc_stepsize_high); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_LOW_1, > - regs->ssc_div_per_low); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_DIV_PER_HIGH_1, > - regs->ssc_div_per_high); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_LOW_1, > - regs->ssc_adjper_low); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_ADJPER_HIGH_1, > - regs->ssc_adjper_high); > - pll_write(base + REG_DSI_7nm_PHY_PLL_SSC_CONTROL, > - SSC_EN | regs->ssc_control); > - } > -} > - > -static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll) > -{ > - void __iomem *base = pll->mmio; > - u8 analog_controls_five_1 = 0x01, vco_config_1 = 0x00; > - > - if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) { > - if (pll->vco_current_rate >= 3100000000ULL) > - analog_controls_five_1 = 0x03; > - > - if (pll->vco_current_rate < 1520000000ULL) > - vco_config_1 = 0x08; > - else if (pll->vco_current_rate < 2990000000ULL) > - vco_config_1 = 0x01; > - } > - > - pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE_1, > - analog_controls_five_1); > - pll_write(base + REG_DSI_7nm_PHY_PLL_VCO_CONFIG_1, vco_config_1); > - pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_FIVE, 0x01); > - pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_TWO, 0x03); > - pll_write(base + REG_DSI_7nm_PHY_PLL_ANALOG_CONTROLS_THREE, 0x00); > - pll_write(base + REG_DSI_7nm_PHY_PLL_DSM_DIVIDER, 0x00); > - pll_write(base + REG_DSI_7nm_PHY_PLL_FEEDBACK_DIVIDER, 0x4e); > - pll_write(base + REG_DSI_7nm_PHY_PLL_CALIBRATION_SETTINGS, 0x40); > - pll_write(base + REG_DSI_7nm_PHY_PLL_BAND_SEL_CAL_SETTINGS_THREE, > 0xba); > - pll_write(base + REG_DSI_7nm_PHY_PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); > - pll_write(base + REG_DSI_7nm_PHY_PLL_OUTDIV, 0x00); > - pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_OVERRIDE, 0x00); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_PROP_GAIN_RATE_1, 0x0a); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_BAND_SEL_RATE_1, 0xc0); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0x84); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_INT_GAIN_IFILT_BAND_1, > 0x82); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, > 0x4c); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_OVERRIDE, 0x80); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x29); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PFILT, 0x2f); > - pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT, 0x2a); > - pll_write(base + REG_DSI_7nm_PHY_PLL_IFILT, > - pll->base.type == MSM_DSI_PHY_7NM_V4_1 ? 0x3f : 0x22); > - > - if (pll->base.type == MSM_DSI_PHY_7NM_V4_1) { > - pll_write(base + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, 0x22); > - if (pll->slave) > - pll_write(pll->slave->mmio + REG_DSI_7nm_PHY_PLL_PERF_OPTIMIZE, > 0x22); > - } > -} > - > -static void dsi_pll_commit(struct dsi_pll_7nm *pll) > -{ > - void __iomem *base = pll->mmio; > - struct dsi_pll_regs *reg = &pll->reg_setup; > - > - pll_write(base + REG_DSI_7nm_PHY_PLL_CORE_INPUT_OVERRIDE, 0x12); > - pll_write(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1, > reg->decimal_div_start); > - pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1, > reg->frac_div_start_low); > - pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1, > reg->frac_div_start_mid); > - pll_write(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1, > reg->frac_div_start_high); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCKDET_RATE_1, > reg->pll_lockdet_rate); > - pll_write(base + REG_DSI_7nm_PHY_PLL_PLL_LOCK_DELAY, 0x06); > - pll_write(base + REG_DSI_7nm_PHY_PLL_CMODE_1, 0x10); /* TODO: 0x00 > for CPHY */ > - pll_write(base + REG_DSI_7nm_PHY_PLL_CLOCK_INVERTERS, > reg->pll_clock_inverters); > -} > - > -static int dsi_pll_7nm_vco_set_rate(struct clk_hw *hw, unsigned long > rate, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - > - DBG("DSI PLL%d rate=%lu, parent's=%lu", pll_7nm->id, rate, > - parent_rate); > - > - pll_7nm->vco_current_rate = rate; > - pll_7nm->vco_ref_clk_rate = VCO_REF_CLK_RATE; > - > - dsi_pll_setup_config(pll_7nm); > - > - dsi_pll_calc_dec_frac(pll_7nm); > - > - dsi_pll_calc_ssc(pll_7nm); > - > - dsi_pll_commit(pll_7nm); > - > - dsi_pll_config_hzindep_reg(pll_7nm); > - > - dsi_pll_ssc_commit(pll_7nm); > - > - /* flush, ensure all register writes are done*/ > - wmb(); > - > - return 0; > -} > - > -static int dsi_pll_7nm_lock_status(struct dsi_pll_7nm *pll) > -{ > - int rc; > - u32 status = 0; > - u32 const delay_us = 100; > - u32 const timeout_us = 5000; > - > - rc = readl_poll_timeout_atomic(pll->mmio + > - REG_DSI_7nm_PHY_PLL_COMMON_STATUS_ONE, > - status, > - ((status & BIT(0)) > 0), > - delay_us, > - timeout_us); > - if (rc) > - pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", > - pll->id, status); > - > - return rc; > -} > - > -static void dsi_pll_disable_pll_bias(struct dsi_pll_7nm *pll) > -{ > - u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0); > - > - pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0); > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data & > ~BIT(5)); > - ndelay(250); > -} > - > -static void dsi_pll_enable_pll_bias(struct dsi_pll_7nm *pll) > -{ > - u32 data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0); > - > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_0, data | > BIT(5)); > - pll_write(pll->mmio + REG_DSI_7nm_PHY_PLL_SYSTEM_MUXES, 0xc0); > - ndelay(250); > -} > - > -static void dsi_pll_disable_global_clk(struct dsi_pll_7nm *pll) > -{ > - u32 data; > - > - data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1, data & > ~BIT(5)); > -} > - > -static void dsi_pll_enable_global_clk(struct dsi_pll_7nm *pll) > -{ > - u32 data; > - > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CTRL_3, 0x04); > - > - data = pll_read(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_CLK_CFG1, > - data | BIT(5) | BIT(4)); > -} > - > -static void dsi_pll_phy_dig_reset(struct dsi_pll_7nm *pll) > -{ > - /* > - * Reset the PHY digital domain. This would be needed when > - * coming out of a CX or analog rail power collapse while > - * ensuring that the pads maintain LP00 or LP11 state > - */ > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, > BIT(0)); > - wmb(); /* Ensure that the reset is deasserted */ > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_GLBL_DIGTOP_SPARE4, > 0x0); > - wmb(); /* Ensure that the reset is deasserted */ > -} > - > -static int dsi_pll_7nm_vco_prepare(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - int rc; > - > - dsi_pll_enable_pll_bias(pll_7nm); > - if (pll_7nm->slave) > - dsi_pll_enable_pll_bias(pll_7nm->slave); > - > - /* Start PLL */ > - pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, > 0x01); > - > - /* > - * ensure all PLL configurations are written prior to checking > - * for PLL lock. > - */ > - wmb(); > - > - /* Check for PLL lock */ > - rc = dsi_pll_7nm_lock_status(pll_7nm); > - if (rc) { > - pr_err("PLL(%d) lock failed\n", pll_7nm->id); > - goto error; > - } > - > - pll->pll_on = true; > - > - /* > - * assert power on reset for PHY digital in case the PLL is > - * enabled after CX of analog domain power collapse. This needs > - * to be done before enabling the global clk. > - */ > - dsi_pll_phy_dig_reset(pll_7nm); > - if (pll_7nm->slave) > - dsi_pll_phy_dig_reset(pll_7nm->slave); > - > - dsi_pll_enable_global_clk(pll_7nm); > - if (pll_7nm->slave) > - dsi_pll_enable_global_clk(pll_7nm->slave); > - > -error: > - return rc; > -} > - > -static void dsi_pll_disable_sub(struct dsi_pll_7nm *pll) > -{ > - pll_write(pll->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_RBUF_CTRL, 0); > - dsi_pll_disable_pll_bias(pll); > -} > - > -static void dsi_pll_7nm_vco_unprepare(struct clk_hw *hw) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - > - /* > - * To avoid any stray glitches while abruptly powering down the PLL > - * make sure to gate the clock using the clock enable bit before > - * powering down the PLL > - */ > - dsi_pll_disable_global_clk(pll_7nm); > - pll_write(pll_7nm->phy_cmn_mmio + REG_DSI_7nm_PHY_CMN_PLL_CNTRL, 0); > - dsi_pll_disable_sub(pll_7nm); > - if (pll_7nm->slave) { > - dsi_pll_disable_global_clk(pll_7nm->slave); > - dsi_pll_disable_sub(pll_7nm->slave); > - } > - /* flush, ensure all register writes are done */ > - wmb(); > - pll->pll_on = false; > -} > - > -static unsigned long dsi_pll_7nm_vco_recalc_rate(struct clk_hw *hw, > - unsigned long parent_rate) > -{ > - struct msm_dsi_pll *pll = hw_clk_to_pll(hw); > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - struct dsi_pll_config *config = &pll_7nm->pll_configuration; > - void __iomem *base = pll_7nm->mmio; > - u64 ref_clk = pll_7nm->vco_ref_clk_rate; > - u64 vco_rate = 0x0; > - u64 multiplier; > - u32 frac; > - u32 dec; > - u64 pll_freq, tmp64; > - > - dec = pll_read(base + REG_DSI_7nm_PHY_PLL_DECIMAL_DIV_START_1); > - dec &= 0xff; > - > - frac = pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_LOW_1); > - frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_MID_1) & > - 0xff) << 8); > - frac |= ((pll_read(base + REG_DSI_7nm_PHY_PLL_FRAC_DIV_START_HIGH_1) > & > - 0x3) << 16); > - > - /* > - * TODO: > - * 1. Assumes prescaler is disabled > - */ > - multiplier = 1 << config->frac_bits; > - pll_freq = dec * (ref_clk * 2); > - tmp64 = (ref_clk * 2 * frac); > - pll_freq += div_u64(tmp64, multiplier); > - > - vco_rate = pll_freq; > - > - DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x", > - pll_7nm->id, (unsigned long)vco_rate, dec, frac); > - > - return (unsigned long)vco_rate; > -} > - > -static const struct clk_ops clk_ops_dsi_pll_7nm_vco = { > - .round_rate = msm_dsi_pll_helper_clk_round_rate, > - .set_rate = dsi_pll_7nm_vco_set_rate, > - .recalc_rate = dsi_pll_7nm_vco_recalc_rate, > - .prepare = dsi_pll_7nm_vco_prepare, > - .unprepare = dsi_pll_7nm_vco_unprepare, > -}; > - > -/* > - * PLL Callbacks > - */ > - > -static void dsi_pll_7nm_save_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - struct pll_7nm_cached_state *cached = &pll_7nm->cached_state; > - void __iomem *phy_base = pll_7nm->phy_cmn_mmio; > - u32 cmn_clk_cfg0, cmn_clk_cfg1; > - > - cached->pll_out_div = pll_read(pll_7nm->mmio + > - REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); > - cached->pll_out_div &= 0x3; > - > - cmn_clk_cfg0 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0); > - cached->bit_clk_div = cmn_clk_cfg0 & 0xf; > - cached->pix_clk_div = (cmn_clk_cfg0 & 0xf0) >> 4; > - > - cmn_clk_cfg1 = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > - cached->pll_mux = cmn_clk_cfg1 & 0x3; > - > - DBG("DSI PLL%d outdiv %x bit_clk_div %x pix_clk_div %x pll_mux %x", > - pll_7nm->id, cached->pll_out_div, cached->bit_clk_div, > - cached->pix_clk_div, cached->pll_mux); > -} > - > -static int dsi_pll_7nm_restore_state(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - struct pll_7nm_cached_state *cached = &pll_7nm->cached_state; > - void __iomem *phy_base = pll_7nm->phy_cmn_mmio; > - u32 val; > - int ret; > - > - val = pll_read(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE); > - val &= ~0x3; > - val |= cached->pll_out_div; > - pll_write(pll_7nm->mmio + REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, val); > - > - pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG0, > - cached->bit_clk_div | (cached->pix_clk_div << 4)); > - > - val = pll_read(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1); > - val &= ~0x3; > - val |= cached->pll_mux; > - pll_write(phy_base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, val); > - > - ret = dsi_pll_7nm_vco_set_rate(&pll->clk_hw, > pll_7nm->vco_current_rate, pll_7nm->vco_ref_clk_rate); > - if (ret) { > - DRM_DEV_ERROR(&pll_7nm->pdev->dev, > - "restore vco rate failed. ret=%d\n", ret); > - return ret; > - } > - > - DBG("DSI PLL%d", pll_7nm->id); > - > - return 0; > -} > - > -static int dsi_pll_7nm_set_usecase(struct msm_dsi_pll *pll, > - enum msm_dsi_phy_usecase uc) > -{ > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - void __iomem *base = pll_7nm->phy_cmn_mmio; > - u32 data = 0x0; /* internal PLL */ > - > - DBG("DSI PLL%d", pll_7nm->id); > - > - switch (uc) { > - case MSM_DSI_PHY_STANDALONE: > - break; > - case MSM_DSI_PHY_MASTER: > - pll_7nm->slave = pll_7nm_list[(pll_7nm->id + 1) % DSI_MAX]; > - break; > - case MSM_DSI_PHY_SLAVE: > - data = 0x1; /* external PLL */ > - break; > - default: > - return -EINVAL; > - } > - > - /* set PLL src */ > - pll_write(base + REG_DSI_7nm_PHY_CMN_CLK_CFG1, (data << 2)); > - > - pll_7nm->uc = uc; > - > - return 0; > -} > - > -static int dsi_pll_7nm_get_provider(struct msm_dsi_pll *pll, > - struct clk **byte_clk_provider, > - struct clk **pixel_clk_provider) > -{ > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - struct clk_hw_onecell_data *hw_data = pll_7nm->hw_data; > - > - DBG("DSI PLL%d", pll_7nm->id); > - > - if (byte_clk_provider) > - *byte_clk_provider = hw_data->hws[DSI_BYTE_PLL_CLK]->clk; > - if (pixel_clk_provider) > - *pixel_clk_provider = hw_data->hws[DSI_PIXEL_PLL_CLK]->clk; > - > - return 0; > -} > - > -static void dsi_pll_7nm_destroy(struct msm_dsi_pll *pll) > -{ > - struct dsi_pll_7nm *pll_7nm = to_pll_7nm(pll); > - struct device *dev = &pll_7nm->pdev->dev; > - > - DBG("DSI PLL%d", pll_7nm->id); > - of_clk_del_provider(dev->of_node); > - > - clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw); > - clk_hw_unregister_mux(pll_7nm->pclk_mux_hw); > - clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw); > - clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw); > - clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw); > - clk_hw_unregister_divider(pll_7nm->bit_clk_hw); > - clk_hw_unregister_divider(pll_7nm->out_div_clk_hw); > - clk_hw_unregister(&pll_7nm->base.clk_hw); > -} > - > -/* > - * The post dividers and mux clocks are created using the standard > divider and > - * mux API. Unlike the 14nm PHY, the slave PLL doesn't need its > dividers/mux > - * state to follow the master PLL's divider/mux state. Therefore, we > don't > - * require special clock ops that also configure the slave PLL > registers > - */ > -static int pll_7nm_register(struct dsi_pll_7nm *pll_7nm) > -{ > - char clk_name[32], parent[32], vco_name[32]; > - char parent2[32], parent3[32], parent4[32]; > - struct clk_init_data vco_init = { > - .parent_names = (const char *[]){ "bi_tcxo" }, > - .num_parents = 1, > - .name = vco_name, > - .flags = CLK_IGNORE_UNUSED, > - .ops = &clk_ops_dsi_pll_7nm_vco, > - }; > - struct device *dev = &pll_7nm->pdev->dev; > - struct clk_hw_onecell_data *hw_data; > - struct clk_hw *hw; > - int ret; > - > - DBG("DSI%d", pll_7nm->id); > - > - hw_data = devm_kzalloc(dev, sizeof(*hw_data) + > - NUM_PROVIDED_CLKS * sizeof(struct clk_hw *), > - GFP_KERNEL); > - if (!hw_data) > - return -ENOMEM; > - > - snprintf(vco_name, 32, "dsi%dvco_clk", pll_7nm->id); > - pll_7nm->base.clk_hw.init = &vco_init; > - > - ret = clk_hw_register(dev, &pll_7nm->base.clk_hw); > - if (ret) > - return ret; > - > - snprintf(clk_name, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > - snprintf(parent, 32, "dsi%dvco_clk", pll_7nm->id); > - > - hw = clk_hw_register_divider(dev, clk_name, > - parent, CLK_SET_RATE_PARENT, > - pll_7nm->mmio + > - REG_DSI_7nm_PHY_PLL_PLL_OUTDIV_RATE, > - 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_base_clk_hw; > - } > - > - pll_7nm->out_div_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > - > - /* BIT CLK: DIV_CTRL_3_0 */ > - hw = clk_hw_register_divider(dev, clk_name, parent, > - CLK_SET_RATE_PARENT, > - pll_7nm->phy_cmn_mmio + > - REG_DSI_7nm_PHY_CMN_CLK_CFG0, > - 0, 4, CLK_DIVIDER_ONE_BASED, > - &pll_7nm->postdiv_lock); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_out_div_clk_hw; > - } > - > - pll_7nm->bit_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_phy_pll_out_byteclk", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > - > - /* DSI Byte clock = VCO_CLK / OUT_DIV / BIT_DIV / 8 */ > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - CLK_SET_RATE_PARENT, 1, 8); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_bit_clk_hw; > - } > - > - pll_7nm->byte_clk_hw = hw; > - hw_data->hws[DSI_BYTE_PLL_CLK] = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > - > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - 0, 1, 2); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_byte_clk_hw; > - } > - > - pll_7nm->by_2_bit_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > - > - hw = clk_hw_register_fixed_factor(dev, clk_name, parent, > - 0, 1, 4); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_by_2_bit_clk_hw; > - } > - > - pll_7nm->post_out_div_clk_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_pclk_mux", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pll_bit_clk", pll_7nm->id); > - snprintf(parent2, 32, "dsi%d_pll_by_2_bit_clk", pll_7nm->id); > - snprintf(parent3, 32, "dsi%d_pll_out_div_clk", pll_7nm->id); > - snprintf(parent4, 32, "dsi%d_pll_post_out_div_clk", pll_7nm->id); > - > - hw = clk_hw_register_mux(dev, clk_name, > - ((const char *[]){ > - parent, parent2, parent3, parent4 > - }), 4, 0, pll_7nm->phy_cmn_mmio + > - REG_DSI_7nm_PHY_CMN_CLK_CFG1, > - 0, 2, 0, NULL); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_post_out_div_clk_hw; > - } > - > - pll_7nm->pclk_mux_hw = hw; > - > - snprintf(clk_name, 32, "dsi%d_phy_pll_out_dsiclk", pll_7nm->id); > - snprintf(parent, 32, "dsi%d_pclk_mux", pll_7nm->id); > - > - /* PIX CLK DIV : DIV_CTRL_7_4*/ > - hw = clk_hw_register_divider(dev, clk_name, parent, > - 0, pll_7nm->phy_cmn_mmio + > - REG_DSI_7nm_PHY_CMN_CLK_CFG0, > - 4, 4, CLK_DIVIDER_ONE_BASED, > - &pll_7nm->postdiv_lock); > - if (IS_ERR(hw)) { > - ret = PTR_ERR(hw); > - goto err_pclk_mux_hw; > - } > - > - pll_7nm->out_dsiclk_hw = hw; > - hw_data->hws[DSI_PIXEL_PLL_CLK] = hw; > - > - hw_data->num = NUM_PROVIDED_CLKS; > - pll_7nm->hw_data = hw_data; > - > - ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, > - pll_7nm->hw_data); > - if (ret) { > - DRM_DEV_ERROR(dev, "failed to register clk provider: %d\n", ret); > - goto err_dsiclk_hw; > - } > - > - return 0; > - > -err_dsiclk_hw: > - clk_hw_unregister_divider(pll_7nm->out_dsiclk_hw); > -err_pclk_mux_hw: > - clk_hw_unregister_mux(pll_7nm->pclk_mux_hw); > -err_post_out_div_clk_hw: > - clk_hw_unregister_fixed_factor(pll_7nm->post_out_div_clk_hw); > -err_by_2_bit_clk_hw: > - clk_hw_unregister_fixed_factor(pll_7nm->by_2_bit_clk_hw); > -err_byte_clk_hw: > - clk_hw_unregister_fixed_factor(pll_7nm->byte_clk_hw); > -err_bit_clk_hw: > - clk_hw_unregister_divider(pll_7nm->bit_clk_hw); > -err_out_div_clk_hw: > - clk_hw_unregister_divider(pll_7nm->out_div_clk_hw); > -err_base_clk_hw: > - clk_hw_unregister(&pll_7nm->base.clk_hw); > - > - return ret; > -} > - > -struct msm_dsi_pll *msm_dsi_pll_7nm_init(struct platform_device *pdev, > - enum msm_dsi_phy_type type, int id) > -{ > - struct dsi_pll_7nm *pll_7nm; > - struct msm_dsi_pll *pll; > - int ret; > - > - pll_7nm = devm_kzalloc(&pdev->dev, sizeof(*pll_7nm), GFP_KERNEL); > - if (!pll_7nm) > - return ERR_PTR(-ENOMEM); > - > - DBG("DSI PLL%d", id); > - > - pll_7nm->pdev = pdev; > - pll_7nm->id = id; > - pll_7nm_list[id] = pll_7nm; > - > - pll_7nm->phy_cmn_mmio = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); > - if (IS_ERR_OR_NULL(pll_7nm->phy_cmn_mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map CMN PHY base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - pll_7nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); > - if (IS_ERR_OR_NULL(pll_7nm->mmio)) { > - DRM_DEV_ERROR(&pdev->dev, "failed to map PLL base\n"); > - return ERR_PTR(-ENOMEM); > - } > - > - spin_lock_init(&pll_7nm->postdiv_lock); > - > - pll = &pll_7nm->base; > - pll->min_rate = 1000000000UL; > - pll->max_rate = 3500000000UL; > - if (type == MSM_DSI_PHY_7NM_V4_1) { > - pll->min_rate = 600000000UL; > - pll->max_rate = (unsigned long)5000000000ULL; > - /* workaround for max rate overflowing on 32-bit builds: */ > - pll->max_rate = max(pll->max_rate, 0xffffffffUL); > - } > - pll->get_provider = dsi_pll_7nm_get_provider; > - pll->destroy = dsi_pll_7nm_destroy; > - pll->save_state = dsi_pll_7nm_save_state; > - pll->restore_state = dsi_pll_7nm_restore_state; > - pll->set_usecase = dsi_pll_7nm_set_usecase; > - > - pll_7nm->vco_delay = 1; > - > - ret = pll_7nm_register(pll_7nm); > - if (ret) { > - DRM_DEV_ERROR(&pdev->dev, "failed to register PLL: %d\n", ret); > - return ERR_PTR(ret); > - } > - > - /* TODO: Remove this when we have proper display handover support */ > - msm_dsi_pll_save_state(pll); > - > - return pll; > -} _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel