android_kernel_xiaomi_sm8350/pll/dsi_pll_28hpm.c
Narendra Muppalla 3709853456 Display drivers kernel project initial snapshot
This change brings msm display driver including sde,
dp, dsi, rotator, dsi pll and dp pll from base 4.19 kernel
project. It is first source code snapshot from base kernel project.

Change-Id: Iec864c064ce5ea04e170f24414c728684002f284
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
2019-04-14 22:20:59 -07:00

318 lines
7.4 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/clk/msm-clk-provider.h>
#include <linux/clk/msm-clk.h>
#include <linux/clk/msm-clock-generic.h>
#include <dt-bindings/clock/msm-clocks-8974.h>
#include "pll_drv.h"
#include "dsi_pll.h"
#define VCO_DELAY_USEC 1
static struct clk_div_ops fixed_2div_ops;
static const struct clk_ops byte_mux_clk_ops;
static const struct clk_ops pixel_clk_src_ops;
static const struct clk_ops byte_clk_src_ops;
static const struct clk_ops analog_postdiv_clk_ops;
static struct lpfr_cfg lpfr_lut_struct[] = {
{479500000, 8},
{480000000, 11},
{575500000, 8},
{576000000, 12},
{610500000, 8},
{659500000, 9},
{671500000, 10},
{672000000, 14},
{708500000, 10},
{750000000, 11},
};
static void dsi_pll_software_reset(struct mdss_pll_resources *dsi_pll_res)
{
/*
* Add HW recommended delays after toggling the software
* reset bit off and back on.
*/
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
udelay(1);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
udelay(1);
}
static int vco_set_rate_hpm(struct clk *c, unsigned long rate)
{
int rc;
struct dsi_pll_vco_clk *vco = to_vco_clk(c);
struct mdss_pll_resources *dsi_pll_res = vco->priv;
rc = mdss_pll_resource_enable(dsi_pll_res, true);
if (rc) {
pr_err("Failed to enable mdss dsi pll resources\n");
return rc;
}
rc = vco_set_rate(vco, rate);
mdss_pll_resource_enable(dsi_pll_res, false);
return rc;
}
static int dsi_pll_enable_seq_8974(struct mdss_pll_resources *dsi_pll_res)
{
int i, rc = 0;
int pll_locked;
dsi_pll_software_reset(dsi_pll_res);
/*
* PLL power up sequence.
* Add necessary delays recommeded by hardware.
*/
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
udelay(1);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
udelay(200);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
udelay(500);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
udelay(500);
for (i = 0; i < 2; i++) {
udelay(100);
/* DSI Uniphy lock detect setting */
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0c);
udelay(100);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d);
pll_locked = dsi_pll_lock_status(dsi_pll_res);
if (pll_locked)
break;
dsi_pll_software_reset(dsi_pll_res);
/*
* PLL power up sequence.
* Add necessary delays recommeded by hardware.
*/
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
udelay(1);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
udelay(200);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
udelay(250);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
udelay(200);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
udelay(500);
MDSS_PLL_REG_W(dsi_pll_res->pll_base,
DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
udelay(500);
}
if (!pll_locked) {
pr_err("DSI PLL lock failed\n");
rc = -EINVAL;
} else {
pr_debug("DSI PLL Lock success\n");
}
return rc;
}
/* Op structures */
static const struct clk_ops clk_ops_dsi_vco = {
.set_rate = vco_set_rate_hpm,
.round_rate = vco_round_rate,
.handoff = vco_handoff,
.prepare = vco_prepare,
.unprepare = vco_unprepare,
};
static struct clk_div_ops fixed_4div_ops = {
.set_div = fixed_4div_set_div,
.get_div = fixed_4div_get_div,
};
static struct clk_div_ops analog_postdiv_ops = {
.set_div = analog_set_div,
.get_div = analog_get_div,
};
static struct clk_div_ops digital_postdiv_ops = {
.set_div = digital_set_div,
.get_div = digital_get_div,
};
static struct clk_mux_ops byte_mux_ops = {
.set_mux_sel = set_byte_mux_sel,
.get_mux_sel = get_byte_mux_sel,
};
static struct dsi_pll_vco_clk dsi_vco_clk_8974 = {
.ref_clk_rate = 19200000,
.min_rate = 350000000,
.max_rate = 750000000,
.pll_en_seq_cnt = 3,
.pll_enable_seqs[0] = dsi_pll_enable_seq_8974,
.pll_enable_seqs[1] = dsi_pll_enable_seq_8974,
.pll_enable_seqs[2] = dsi_pll_enable_seq_8974,
.lpfr_lut_size = 10,
.lpfr_lut = lpfr_lut_struct,
.c = {
.dbg_name = "dsi_vco_clk_8974",
.ops = &clk_ops_dsi_vco,
CLK_INIT(dsi_vco_clk_8974.c),
},
};
static struct div_clk analog_postdiv_clk_8974 = {
.data = {
.max_div = 255,
.min_div = 1,
},
.ops = &analog_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
.dbg_name = "analog_postdiv_clk",
.ops = &analog_postdiv_clk_ops,
.flags = CLKFLAG_NO_RATE_CACHE,
CLK_INIT(analog_postdiv_clk_8974.c),
},
};
static struct div_clk indirect_path_div2_clk_8974 = {
.ops = &fixed_2div_ops,
.data = {
.div = 2,
.min_div = 2,
.max_div = 2,
},
.c = {
.parent = &analog_postdiv_clk_8974.c,
.dbg_name = "indirect_path_div2_clk",
.ops = &clk_ops_div,
.flags = CLKFLAG_NO_RATE_CACHE,
CLK_INIT(indirect_path_div2_clk_8974.c),
},
};
static struct div_clk pixel_clk_src_8974 = {
.data = {
.max_div = 255,
.min_div = 1,
},
.ops = &digital_postdiv_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
.dbg_name = "pixel_clk_src_8974",
.ops = &pixel_clk_src_ops,
.flags = CLKFLAG_NO_RATE_CACHE,
CLK_INIT(pixel_clk_src_8974.c),
},
};
static struct mux_clk byte_mux_8974 = {
.num_parents = 2,
.parents = (struct clk_src[]){
{&dsi_vco_clk_8974.c, 0},
{&indirect_path_div2_clk_8974.c, 1},
},
.ops = &byte_mux_ops,
.c = {
.parent = &dsi_vco_clk_8974.c,
.dbg_name = "byte_mux_8974",
.ops = &byte_mux_clk_ops,
CLK_INIT(byte_mux_8974.c),
},
};
static struct div_clk byte_clk_src_8974 = {
.ops = &fixed_4div_ops,
.data = {
.min_div = 4,
.max_div = 4,
},
.c = {
.parent = &byte_mux_8974.c,
.dbg_name = "byte_clk_src_8974",
.ops = &byte_clk_src_ops,
CLK_INIT(byte_clk_src_8974.c),
},
};
static struct clk_lookup mdss_dsi_pllcc_8974[] = {
CLK_LOOKUP_OF("pixel_src", pixel_clk_src_8974,
"fd8c0000.qcom,mmsscc-mdss"),
CLK_LOOKUP_OF("byte_src", byte_clk_src_8974,
"fd8c0000.qcom,mmsscc-mdss"),
};
int dsi_pll_clock_register_hpm(struct platform_device *pdev,
struct mdss_pll_resources *pll_res)
{
int rc;
/* Set client data to mux, div and vco clocks */
byte_clk_src_8974.priv = pll_res;
pixel_clk_src_8974.priv = pll_res;
byte_mux_8974.priv = pll_res;
indirect_path_div2_clk_8974.priv = pll_res;
analog_postdiv_clk_8974.priv = pll_res;
dsi_vco_clk_8974.priv = pll_res;
pll_res->vco_delay = VCO_DELAY_USEC;
/* Set clock source operations */
pixel_clk_src_ops = clk_ops_slave_div;
pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
analog_postdiv_clk_ops = clk_ops_div;
analog_postdiv_clk_ops.prepare = dsi_pll_div_prepare;
byte_clk_src_ops = clk_ops_div;
byte_clk_src_ops.prepare = dsi_pll_div_prepare;
byte_mux_clk_ops = clk_ops_gen_mux;
byte_mux_clk_ops.prepare = dsi_pll_mux_prepare;
if (pll_res->target_id == MDSS_PLL_TARGET_8974) {
rc = of_msm_clock_register(pdev->dev.of_node,
mdss_dsi_pllcc_8974, ARRAY_SIZE(mdss_dsi_pllcc_8974));
if (rc) {
pr_err("Clock register failed\n");
rc = -EPROBE_DEFER;
}
} else {
pr_err("Invalid target ID\n");
rc = -EINVAL;
}
if (!rc)
pr_info("Registered DSI PLL clocks successfully\n");
return rc;
}