123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- // 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 <dt-bindings/clock/mdss-28nm-pll-clk.h>
- #include "pll_drv.h"
- #include "dsi_pll.h"
- #include "dsi_pll_28nm.h"
- #define VCO_DELAY_USEC 1000
- enum {
- DSI_PLL_0,
- DSI_PLL_1,
- DSI_PLL_MAX
- };
- 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_sw_reset(struct mdss_pll_resources *rsc)
- {
- /*
- * DSI PLL software reset. Add HW recommended delays after toggling
- * the software reset bit off and back on.
- */
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
- ndelay(500);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
- }
- static void dsi_pll_toggle_lock_detect(
- struct mdss_pll_resources *rsc)
- {
- /* DSI PLL toggle lock detect setting */
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x04);
- ndelay(500);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
- udelay(512);
- }
- static int dsi_pll_check_lock_status(
- struct mdss_pll_resources *rsc)
- {
- int rc = 0;
- rc = dsi_pll_lock_status(rsc);
- if (rc)
- pr_debug("PLL Locked\n");
- else
- pr_err("PLL failed to lock\n");
- return rc;
- }
- static int dsi_pll_enable_seq_gf2(struct mdss_pll_resources *rsc)
- {
- int pll_locked = 0;
- dsi_pll_sw_reset(rsc);
- /*
- * GF PART 2 PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x04);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
- udelay(3);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(500);
- dsi_pll_toggle_lock_detect(rsc);
- pll_locked = dsi_pll_check_lock_status(rsc);
- return pll_locked ? 0 : -EINVAL;
- }
- static int dsi_pll_enable_seq_gf1(struct mdss_pll_resources *rsc)
- {
- int pll_locked = 0;
- dsi_pll_sw_reset(rsc);
- /*
- * GF PART 1 PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x14);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
- udelay(3);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(500);
- dsi_pll_toggle_lock_detect(rsc);
- pll_locked = dsi_pll_check_lock_status(rsc);
- return pll_locked ? 0 : -EINVAL;
- }
- static int dsi_pll_enable_seq_tsmc(struct mdss_pll_resources *rsc)
- {
- int pll_locked = 0;
- dsi_pll_sw_reset(rsc);
- /*
- * TSMC PLL power up sequence.
- * Add necessary delays recommended by hardware.
- */
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
- MDSS_PLL_REG_W(rsc->pll_base,
- DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
- udelay(500);
- dsi_pll_toggle_lock_detect(rsc);
- pll_locked = dsi_pll_check_lock_status(rsc);
- return pll_locked ? 0 : -EINVAL;
- }
- static struct regmap_config dsi_pll_28lpm_config = {
- .reg_bits = 32,
- .reg_stride = 4,
- .val_bits = 32,
- .max_register = 0xF4,
- };
- static struct regmap_bus analog_postdiv_regmap_bus = {
- .reg_write = analog_postdiv_reg_write,
- .reg_read = analog_postdiv_reg_read,
- };
- static struct regmap_bus byteclk_src_mux_regmap_bus = {
- .reg_write = byteclk_mux_write_sel,
- .reg_read = byteclk_mux_read_sel,
- };
- static struct regmap_bus pclk_src_regmap_bus = {
- .reg_write = pixel_clk_set_div,
- .reg_read = pixel_clk_get_div,
- };
- static const struct clk_ops clk_ops_vco_28lpm = {
- .recalc_rate = vco_28nm_recalc_rate,
- .set_rate = vco_28nm_set_rate,
- .round_rate = vco_28nm_round_rate,
- .prepare = vco_28nm_prepare,
- .unprepare = vco_28nm_unprepare,
- };
- static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
- .ref_clk_rate = 19200000UL,
- .min_rate = 350000000UL,
- .max_rate = 750000000UL,
- .pll_en_seq_cnt = 9,
- .pll_enable_seqs[0] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[1] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[2] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[3] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[4] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[5] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[6] = dsi_pll_enable_seq_gf2,
- .pll_enable_seqs[7] = dsi_pll_enable_seq_gf2,
- .pll_enable_seqs[8] = dsi_pll_enable_seq_gf2,
- .lpfr_lut_size = 10,
- .lpfr_lut = lpfr_lut_struct,
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_vco_clk",
- .parent_names = (const char *[]){"cxo"},
- .num_parents = 1,
- .ops = &clk_ops_vco_28lpm,
- .flags = CLK_GET_RATE_NOCACHE,
- },
- };
- static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
- .ref_clk_rate = 19200000UL,
- .min_rate = 350000000UL,
- .max_rate = 750000000UL,
- .pll_en_seq_cnt = 9,
- .pll_enable_seqs[0] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[1] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[2] = dsi_pll_enable_seq_tsmc,
- .pll_enable_seqs[3] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[4] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[5] = dsi_pll_enable_seq_gf1,
- .pll_enable_seqs[6] = dsi_pll_enable_seq_gf2,
- .pll_enable_seqs[7] = dsi_pll_enable_seq_gf2,
- .pll_enable_seqs[8] = dsi_pll_enable_seq_gf2,
- .lpfr_lut_size = 10,
- .lpfr_lut = lpfr_lut_struct,
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_vco_clk",
- .parent_names = (const char *[]){"cxo"},
- .num_parents = 1,
- .ops = &clk_ops_vco_28lpm,
- .flags = CLK_GET_RATE_NOCACHE,
- },
- };
- static struct clk_regmap_div dsi0pll_analog_postdiv = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
- .shift = 0,
- .width = 4,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_analog_postdiv",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_regmap_div_ops,
- },
- },
- };
- static struct clk_regmap_div dsi1pll_analog_postdiv = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
- .shift = 0,
- .width = 4,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_analog_postdiv",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_regmap_div_ops,
- },
- },
- };
- static struct clk_fixed_factor dsi0pll_indirect_path_src = {
- .div = 2,
- .mult = 1,
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_indirect_path_src",
- .parent_names = (const char *[]){"dsi0pll_analog_postdiv"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_fixed_factor_ops,
- },
- };
- static struct clk_fixed_factor dsi1pll_indirect_path_src = {
- .div = 2,
- .mult = 1,
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_indirect_path_src",
- .parent_names = (const char *[]){"dsi1pll_analog_postdiv"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_fixed_factor_ops,
- },
- };
- static struct clk_regmap_mux dsi0pll_byteclk_src_mux = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG,
- .shift = 1,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_byteclk_src_mux",
- .parent_names = (const char *[]){
- "dsi0pll_vco_clk",
- "dsi0pll_indirect_path_src"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_regmap_mux_closest_ops,
- },
- },
- };
- static struct clk_regmap_mux dsi1pll_byteclk_src_mux = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG,
- .shift = 1,
- .width = 1,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_byteclk_src_mux",
- .parent_names = (const char *[]){
- "dsi1pll_vco_clk",
- "dsi1pll_indirect_path_src"},
- .num_parents = 2,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_regmap_mux_closest_ops,
- },
- },
- };
- static struct clk_fixed_factor dsi0pll_byteclk_src = {
- .div = 4,
- .mult = 1,
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_byteclk_src",
- .parent_names = (const char *[]){
- "dsi0pll_byteclk_src_mux"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_fixed_factor_ops,
- },
- };
- static struct clk_fixed_factor dsi1pll_byteclk_src = {
- .div = 4,
- .mult = 1,
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_byteclk_src",
- .parent_names = (const char *[]){
- "dsi1pll_byteclk_src_mux"},
- .num_parents = 1,
- .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
- .ops = &clk_fixed_factor_ops,
- },
- };
- static struct clk_regmap_div dsi0pll_pclk_src = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
- .shift = 0,
- .width = 8,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi0pll_pclk_src",
- .parent_names = (const char *[]){"dsi0pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
- },
- };
- static struct clk_regmap_div dsi1pll_pclk_src = {
- .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
- .shift = 0,
- .width = 8,
- .clkr = {
- .hw.init = &(struct clk_init_data){
- .name = "dsi1pll_pclk_src",
- .parent_names = (const char *[]){"dsi1pll_vco_clk"},
- .num_parents = 1,
- .flags = CLK_GET_RATE_NOCACHE,
- .ops = &clk_regmap_div_ops,
- },
- },
- };
- static struct clk_hw *mdss_dsi_pllcc_28lpm[] = {
- [VCO_CLK_0] = &dsi0pll_vco_clk.hw,
- [ANALOG_POSTDIV_0_CLK] = &dsi0pll_analog_postdiv.clkr.hw,
- [INDIRECT_PATH_SRC_0_CLK] = &dsi0pll_indirect_path_src.hw,
- [BYTECLK_SRC_MUX_0_CLK] = &dsi0pll_byteclk_src_mux.clkr.hw,
- [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw,
- [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw,
- [VCO_CLK_1] = &dsi1pll_vco_clk.hw,
- [ANALOG_POSTDIV_1_CLK] = &dsi1pll_analog_postdiv.clkr.hw,
- [INDIRECT_PATH_SRC_1_CLK] = &dsi1pll_indirect_path_src.hw,
- [BYTECLK_SRC_MUX_1_CLK] = &dsi1pll_byteclk_src_mux.clkr.hw,
- [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw,
- [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw,
- };
- int dsi_pll_clock_register_28lpm(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res)
- {
- int rc = 0, ndx, i;
- struct clk *clk;
- struct clk_onecell_data *clk_data;
- int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_28lpm);
- struct regmap *rmap;
- int const ssc_freq_min = 30000; /* min. recommended freq. value */
- int const ssc_freq_max = 33000; /* max. recommended freq. value */
- int const ssc_ppm_max = 5000; /* max. recommended ppm */
- ndx = pll_res->index;
- if (ndx >= DSI_PLL_MAX) {
- pr_err("pll index(%d) NOT supported\n", ndx);
- return -EINVAL;
- }
- pll_res->vco_delay = VCO_DELAY_USEC;
- if (pll_res->ssc_en) {
- if (!pll_res->ssc_freq || (pll_res->ssc_freq < ssc_freq_min) ||
- (pll_res->ssc_freq > ssc_freq_max)) {
- pll_res->ssc_freq = ssc_freq_min;
- pr_debug("SSC frequency out of recommended range. Set to default=%d\n",
- pll_res->ssc_freq);
- }
- if (!pll_res->ssc_ppm || (pll_res->ssc_ppm > ssc_ppm_max)) {
- pll_res->ssc_ppm = ssc_ppm_max;
- pr_debug("SSC PPM out of recommended range. Set to default=%d\n",
- pll_res->ssc_ppm);
- }
- }
- clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data),
- GFP_KERNEL);
- if (!clk_data)
- return -ENOMEM;
- clk_data->clks = devm_kcalloc(&pdev->dev, num_clks,
- sizeof(struct clk *), GFP_KERNEL);
- if (!clk_data->clks)
- return -ENOMEM;
- clk_data->clk_num = num_clks;
- /* Establish client data */
- if (ndx == 0) {
- rmap = devm_regmap_init(&pdev->dev, &byteclk_src_mux_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi0pll_byteclk_src_mux.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &analog_postdiv_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi0pll_analog_postdiv.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi0pll_pclk_src.clkr.regmap = rmap;
- dsi0pll_vco_clk.priv = pll_res;
- for (i = VCO_CLK_0; i <= PCLK_SRC_0_CLK; i++) {
- clk = devm_clk_register(&pdev->dev,
- mdss_dsi_pllcc_28lpm[i]);
- if (IS_ERR(clk)) {
- pr_err("clk registration failed for DSI clock:%d\n",
- pll_res->index);
- rc = -EINVAL;
- goto clk_register_fail;
- }
- clk_data->clks[i] = clk;
- }
- rc = of_clk_add_provider(pdev->dev.of_node,
- of_clk_src_onecell_get, clk_data);
- } else {
- rmap = devm_regmap_init(&pdev->dev, &byteclk_src_mux_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi1pll_byteclk_src_mux.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &analog_postdiv_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi1pll_analog_postdiv.clkr.regmap = rmap;
- rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus,
- pll_res, &dsi_pll_28lpm_config);
- if (IS_ERR(rmap)) {
- pr_err("regmap init failed for DSI clock:%d\n",
- pll_res->index);
- return -EINVAL;
- }
- dsi1pll_pclk_src.clkr.regmap = rmap;
- dsi1pll_vco_clk.priv = pll_res;
- for (i = VCO_CLK_1; i <= PCLK_SRC_1_CLK; i++) {
- clk = devm_clk_register(&pdev->dev,
- mdss_dsi_pllcc_28lpm[i]);
- if (IS_ERR(clk)) {
- pr_err("clk registration failed for DSI clock:%d\n",
- pll_res->index);
- rc = -EINVAL;
- goto clk_register_fail;
- }
- clk_data->clks[i] = clk;
- }
- rc = of_clk_add_provider(pdev->dev.of_node,
- of_clk_src_onecell_get, clk_data);
- }
- if (!rc) {
- pr_info("Registered DSI PLL ndx=%d, clocks successfully\n",
- ndx);
- return rc;
- }
- clk_register_fail:
- return rc;
- }
|