Merge "clk: qcom: Porting display clocks from msm folder to qcom folder"
This commit is contained in:
commit
c7b518b18b
11 changed files with 5900 additions and 0 deletions
6
drivers/clk/qcom/mdss/Kconfig
Normal file
6
drivers/clk/qcom/mdss/Kconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
config MSM_MDSS_PLL
|
||||
bool "MDSS pll programming"
|
||||
---help---
|
||||
It provides support for DSI, eDP and HDMI interface pll programming on MDSS
|
||||
hardware. It also handles the pll specific resources and turn them on/off when
|
||||
mdss pll client tries to enable/disable pll clocks.
|
5
drivers/clk/qcom/mdss/Makefile
Normal file
5
drivers/clk/qcom/mdss/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll-util.o
|
||||
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-pll.o
|
||||
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o
|
||||
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o
|
||||
obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o
|
1137
drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c
Normal file
1137
drivers/clk/qcom/mdss/mdss-dsi-pll-8996-util.c
Normal file
File diff suppressed because it is too large
Load diff
566
drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c
Normal file
566
drivers/clk/qcom/mdss/mdss-dsi-pll-8996.c
Normal file
|
@ -0,0 +1,566 @@
|
|||
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#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/workqueue.h>
|
||||
#include <linux/clk/msm-clock-generic.h>
|
||||
#include <dt-bindings/clock/msm-clocks-8996.h>
|
||||
|
||||
#include "mdss-pll.h"
|
||||
#include "mdss-dsi-pll.h"
|
||||
#include "mdss-dsi-pll-8996.h"
|
||||
|
||||
#define VCO_DELAY_USEC 1
|
||||
|
||||
static struct dsi_pll_db pll_db[DSI_PLL_NUM];
|
||||
|
||||
static struct clk_ops n2_clk_src_ops;
|
||||
static struct clk_ops shadow_n2_clk_src_ops;
|
||||
static struct clk_ops byte_clk_src_ops;
|
||||
static struct clk_ops post_n1_div_clk_src_ops;
|
||||
static struct clk_ops shadow_post_n1_div_clk_src_ops;
|
||||
|
||||
static struct clk_ops clk_ops_gen_mux_dsi;
|
||||
|
||||
/* Op structures */
|
||||
static struct clk_ops clk_ops_dsi_vco = {
|
||||
.set_rate = pll_vco_set_rate_8996,
|
||||
.round_rate = pll_vco_round_rate_8996,
|
||||
.handoff = pll_vco_handoff_8996,
|
||||
.prepare = pll_vco_prepare_8996,
|
||||
.unprepare = pll_vco_unprepare_8996,
|
||||
};
|
||||
|
||||
static struct clk_div_ops post_n1_div_ops = {
|
||||
.set_div = post_n1_div_set_div,
|
||||
.get_div = post_n1_div_get_div,
|
||||
};
|
||||
|
||||
static struct clk_div_ops n2_div_ops = { /* hr_oclk3 */
|
||||
.set_div = n2_div_set_div,
|
||||
.get_div = n2_div_get_div,
|
||||
};
|
||||
|
||||
static struct clk_mux_ops mdss_byte_mux_ops = {
|
||||
.set_mux_sel = set_mdss_byte_mux_sel_8996,
|
||||
.get_mux_sel = get_mdss_byte_mux_sel_8996,
|
||||
};
|
||||
|
||||
static struct clk_mux_ops mdss_pixel_mux_ops = {
|
||||
.set_mux_sel = set_mdss_pixel_mux_sel_8996,
|
||||
.get_mux_sel = get_mdss_pixel_mux_sel_8996,
|
||||
};
|
||||
|
||||
/* Shadow ops for dynamic refresh */
|
||||
static struct clk_ops clk_ops_shadow_dsi_vco = {
|
||||
.set_rate = shadow_pll_vco_set_rate_8996,
|
||||
.round_rate = pll_vco_round_rate_8996,
|
||||
.handoff = shadow_pll_vco_handoff_8996,
|
||||
};
|
||||
|
||||
static struct clk_div_ops shadow_post_n1_div_ops = {
|
||||
.set_div = post_n1_div_set_div,
|
||||
};
|
||||
|
||||
static struct clk_div_ops shadow_n2_div_ops = {
|
||||
.set_div = shadow_n2_div_set_div,
|
||||
};
|
||||
|
||||
static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
|
||||
.ref_clk_rate = 19200000UL,
|
||||
.min_rate = 1300000000UL,
|
||||
.max_rate = 2600000000UL,
|
||||
.pll_en_seq_cnt = 1,
|
||||
.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
|
||||
.c = {
|
||||
.dbg_name = "dsi0pll_vco_clk_8996",
|
||||
.ops = &clk_ops_dsi_vco,
|
||||
CLK_INIT(dsi0pll_vco_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = {
|
||||
.ref_clk_rate = 19200000u,
|
||||
.min_rate = 1300000000u,
|
||||
.max_rate = 2600000000u,
|
||||
.c = {
|
||||
.dbg_name = "dsi0pll_shadow_vco_clk",
|
||||
.ops = &clk_ops_shadow_dsi_vco,
|
||||
CLK_INIT(dsi0pll_shadow_vco_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
|
||||
.ref_clk_rate = 19200000UL,
|
||||
.min_rate = 1300000000UL,
|
||||
.max_rate = 2600000000UL,
|
||||
.pll_en_seq_cnt = 1,
|
||||
.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
|
||||
.c = {
|
||||
.dbg_name = "dsi1pll_vco_clk_8996",
|
||||
.ops = &clk_ops_dsi_vco,
|
||||
CLK_INIT(dsi1pll_vco_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = {
|
||||
.ref_clk_rate = 19200000u,
|
||||
.min_rate = 1300000000u,
|
||||
.max_rate = 2600000000u,
|
||||
.pll_en_seq_cnt = 1,
|
||||
.pll_enable_seqs[0] = dsi_pll_enable_seq_8996,
|
||||
.c = {
|
||||
.dbg_name = "dsi1pll_shadow_vco_clk",
|
||||
.ops = &clk_ops_shadow_dsi_vco,
|
||||
CLK_INIT(dsi1pll_shadow_vco_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_post_n1_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &post_n1_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_vco_clk.c,
|
||||
.dbg_name = "dsi0pll_post_n1_div_clk",
|
||||
.ops = &post_n1_div_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_post_n1_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_shadow_post_n1_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &shadow_post_n1_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_shadow_vco_clk.c,
|
||||
.dbg_name = "dsi0pll_shadow_post_n1_div_clk",
|
||||
.ops = &shadow_post_n1_div_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_post_n1_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &post_n1_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_vco_clk.c,
|
||||
.dbg_name = "dsi1pll_post_n1_div_clk",
|
||||
.ops = &post_n1_div_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_post_n1_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_shadow_post_n1_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &shadow_post_n1_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_shadow_vco_clk.c,
|
||||
.dbg_name = "dsi1pll_shadow_post_n1_div_clk",
|
||||
.ops = &shadow_post_n1_div_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_n2_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &n2_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi0pll_n2_div_clk",
|
||||
.ops = &n2_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_n2_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_shadow_n2_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &shadow_n2_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_shadow_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi0pll_shadow_n2_div_clk",
|
||||
.ops = &shadow_n2_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_shadow_n2_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_n2_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &n2_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi1pll_n2_div_clk",
|
||||
.ops = &n2_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_n2_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_shadow_n2_div_clk = {
|
||||
.data = {
|
||||
.max_div = 15,
|
||||
.min_div = 1,
|
||||
},
|
||||
.ops = &shadow_n2_div_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_shadow_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi1pll_shadow_n2_div_clk",
|
||||
.ops = &shadow_n2_clk_src_ops,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_shadow_n2_div_clk.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_pixel_clk_src = {
|
||||
.data = {
|
||||
.div = 2,
|
||||
.min_div = 2,
|
||||
.max_div = 2,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi0pll_n2_div_clk.c,
|
||||
.dbg_name = "dsi0pll_pixel_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_pixel_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_shadow_pixel_clk_src = {
|
||||
.data = {
|
||||
.div = 2,
|
||||
.min_div = 2,
|
||||
.max_div = 2,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi0pll_shadow_n2_div_clk.c,
|
||||
.dbg_name = "dsi0pll_shadow_pixel_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_shadow_pixel_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_pixel_clk_src = {
|
||||
.data = {
|
||||
.div = 2,
|
||||
.min_div = 2,
|
||||
.max_div = 2,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi1pll_n2_div_clk.c,
|
||||
.dbg_name = "dsi1pll_pixel_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_pixel_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_shadow_pixel_clk_src = {
|
||||
.data = {
|
||||
.div = 2,
|
||||
.min_div = 2,
|
||||
.max_div = 2,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi1pll_shadow_n2_div_clk.c,
|
||||
.dbg_name = "dsi1pll_shadow_pixel_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_shadow_pixel_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct mux_clk dsi0pll_pixel_clk_mux = {
|
||||
.num_parents = 2,
|
||||
.parents = (struct clk_src[]) {
|
||||
{&dsi0pll_pixel_clk_src.c, 0},
|
||||
{&dsi0pll_shadow_pixel_clk_src.c, 1},
|
||||
},
|
||||
.ops = &mdss_pixel_mux_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_pixel_clk_src.c,
|
||||
.dbg_name = "dsi0pll_pixel_clk_mux",
|
||||
.ops = &clk_ops_gen_mux_dsi,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_pixel_clk_mux.c),
|
||||
}
|
||||
};
|
||||
|
||||
static struct mux_clk dsi1pll_pixel_clk_mux = {
|
||||
.num_parents = 2,
|
||||
.parents = (struct clk_src[]) {
|
||||
{&dsi1pll_pixel_clk_src.c, 0},
|
||||
{&dsi1pll_shadow_pixel_clk_src.c, 1},
|
||||
},
|
||||
.ops = &mdss_pixel_mux_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_pixel_clk_src.c,
|
||||
.dbg_name = "dsi1pll_pixel_clk_mux",
|
||||
.ops = &clk_ops_gen_mux_dsi,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_pixel_clk_mux.c),
|
||||
}
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_byte_clk_src = {
|
||||
.data = {
|
||||
.div = 8,
|
||||
.min_div = 8,
|
||||
.max_div = 8,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi0pll_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi0pll_byte_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
CLK_INIT(dsi0pll_byte_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi0pll_shadow_byte_clk_src = {
|
||||
.data = {
|
||||
.div = 8,
|
||||
.min_div = 8,
|
||||
.max_div = 8,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi0pll_shadow_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi0pll_shadow_byte_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
CLK_INIT(dsi0pll_shadow_byte_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_byte_clk_src = {
|
||||
.data = {
|
||||
.div = 8,
|
||||
.min_div = 8,
|
||||
.max_div = 8,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi1pll_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi1pll_byte_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
CLK_INIT(dsi1pll_byte_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct div_clk dsi1pll_shadow_byte_clk_src = {
|
||||
.data = {
|
||||
.div = 8,
|
||||
.min_div = 8,
|
||||
.max_div = 8,
|
||||
},
|
||||
.c = {
|
||||
.parent = &dsi1pll_shadow_post_n1_div_clk.c,
|
||||
.dbg_name = "dsi1pll_shadow_byte_clk_src",
|
||||
.ops = &clk_ops_div,
|
||||
CLK_INIT(dsi1pll_shadow_byte_clk_src.c),
|
||||
},
|
||||
};
|
||||
|
||||
static struct mux_clk dsi0pll_byte_clk_mux = {
|
||||
.num_parents = 2,
|
||||
.parents = (struct clk_src[]) {
|
||||
{&dsi0pll_byte_clk_src.c, 0},
|
||||
{&dsi0pll_shadow_byte_clk_src.c, 1},
|
||||
},
|
||||
.ops = &mdss_byte_mux_ops,
|
||||
.c = {
|
||||
.parent = &dsi0pll_byte_clk_src.c,
|
||||
.dbg_name = "dsi0pll_byte_clk_mux",
|
||||
.ops = &clk_ops_gen_mux_dsi,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi0pll_byte_clk_mux.c),
|
||||
}
|
||||
};
|
||||
static struct mux_clk dsi1pll_byte_clk_mux = {
|
||||
.num_parents = 2,
|
||||
.parents = (struct clk_src[]) {
|
||||
{&dsi1pll_byte_clk_src.c, 0},
|
||||
{&dsi1pll_shadow_byte_clk_src.c, 1},
|
||||
},
|
||||
.ops = &mdss_byte_mux_ops,
|
||||
.c = {
|
||||
.parent = &dsi1pll_byte_clk_src.c,
|
||||
.dbg_name = "dsi1pll_byte_clk_mux",
|
||||
.ops = &clk_ops_gen_mux_dsi,
|
||||
.flags = CLKFLAG_NO_RATE_CACHE,
|
||||
CLK_INIT(dsi1pll_byte_clk_mux.c),
|
||||
}
|
||||
};
|
||||
|
||||
static struct clk_lookup mdss_dsi_pllcc_8996[] = {
|
||||
CLK_LIST(dsi0pll_byte_clk_mux),
|
||||
CLK_LIST(dsi0pll_byte_clk_src),
|
||||
CLK_LIST(dsi0pll_pixel_clk_mux),
|
||||
CLK_LIST(dsi0pll_pixel_clk_src),
|
||||
CLK_LIST(dsi0pll_n2_div_clk),
|
||||
CLK_LIST(dsi0pll_post_n1_div_clk),
|
||||
CLK_LIST(dsi0pll_vco_clk),
|
||||
CLK_LIST(dsi0pll_shadow_byte_clk_src),
|
||||
CLK_LIST(dsi0pll_shadow_pixel_clk_src),
|
||||
CLK_LIST(dsi0pll_shadow_n2_div_clk),
|
||||
CLK_LIST(dsi0pll_shadow_post_n1_div_clk),
|
||||
CLK_LIST(dsi0pll_shadow_vco_clk),
|
||||
};
|
||||
|
||||
static struct clk_lookup mdss_dsi_pllcc_8996_1[] = {
|
||||
CLK_LIST(dsi1pll_byte_clk_mux),
|
||||
CLK_LIST(dsi1pll_byte_clk_src),
|
||||
CLK_LIST(dsi1pll_pixel_clk_mux),
|
||||
CLK_LIST(dsi1pll_pixel_clk_src),
|
||||
CLK_LIST(dsi1pll_n2_div_clk),
|
||||
CLK_LIST(dsi1pll_post_n1_div_clk),
|
||||
CLK_LIST(dsi1pll_vco_clk),
|
||||
CLK_LIST(dsi1pll_shadow_byte_clk_src),
|
||||
CLK_LIST(dsi1pll_shadow_pixel_clk_src),
|
||||
CLK_LIST(dsi1pll_shadow_n2_div_clk),
|
||||
CLK_LIST(dsi1pll_shadow_post_n1_div_clk),
|
||||
CLK_LIST(dsi1pll_shadow_vco_clk),
|
||||
};
|
||||
|
||||
int dsi_pll_clock_register_8996(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc = 0, ndx;
|
||||
int const ssc_freq_default = 31500; /* default h/w recommended value */
|
||||
int const ssc_ppm_default = 5000; /* default h/w recommended value */
|
||||
struct dsi_pll_db *pdb;
|
||||
|
||||
if (!pdev || !pdev->dev.of_node) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pll_res || !pll_res->pll_base) {
|
||||
pr_err("Invalid PLL resources\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
if (pll_res->index >= DSI_PLL_NUM) {
|
||||
pr_err("pll ndx=%d is NOT supported\n", pll_res->index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ndx = pll_res->index;
|
||||
pdb = &pll_db[ndx];
|
||||
pll_res->priv = pdb;
|
||||
pdb->pll = pll_res;
|
||||
ndx++;
|
||||
ndx %= DSI_PLL_NUM;
|
||||
pdb->next = &pll_db[ndx];
|
||||
|
||||
/* Set clock source operations */
|
||||
|
||||
/* hr_oclk3, pixel */
|
||||
n2_clk_src_ops = clk_ops_slave_div;
|
||||
n2_clk_src_ops.prepare = mdss_pll_div_prepare;
|
||||
|
||||
shadow_n2_clk_src_ops = clk_ops_slave_div;
|
||||
|
||||
/* hr_ockl2, byte, vco pll */
|
||||
post_n1_div_clk_src_ops = clk_ops_div;
|
||||
post_n1_div_clk_src_ops.prepare = mdss_pll_div_prepare;
|
||||
|
||||
shadow_post_n1_div_clk_src_ops = clk_ops_div;
|
||||
|
||||
byte_clk_src_ops = clk_ops_div;
|
||||
byte_clk_src_ops.prepare = mdss_pll_div_prepare;
|
||||
|
||||
clk_ops_gen_mux_dsi = clk_ops_gen_mux;
|
||||
clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
|
||||
clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
|
||||
|
||||
if (pll_res->ssc_en) {
|
||||
if (!pll_res->ssc_freq)
|
||||
pll_res->ssc_freq = ssc_freq_default;
|
||||
if (!pll_res->ssc_ppm)
|
||||
pll_res->ssc_ppm = ssc_ppm_default;
|
||||
}
|
||||
|
||||
/* Set client data to mux, div and vco clocks. */
|
||||
if (pll_res->index == DSI_PLL_1) {
|
||||
dsi1pll_byte_clk_src.priv = pll_res;
|
||||
dsi1pll_pixel_clk_src.priv = pll_res;
|
||||
dsi1pll_post_n1_div_clk.priv = pll_res;
|
||||
dsi1pll_n2_div_clk.priv = pll_res;
|
||||
dsi1pll_vco_clk.priv = pll_res;
|
||||
|
||||
dsi1pll_shadow_byte_clk_src.priv = pll_res;
|
||||
dsi1pll_shadow_pixel_clk_src.priv = pll_res;
|
||||
dsi1pll_shadow_post_n1_div_clk.priv = pll_res;
|
||||
dsi1pll_shadow_n2_div_clk.priv = pll_res;
|
||||
dsi1pll_shadow_vco_clk.priv = pll_res;
|
||||
|
||||
pll_res->vco_delay = VCO_DELAY_USEC;
|
||||
rc = of_msm_clock_register(pdev->dev.of_node,
|
||||
mdss_dsi_pllcc_8996_1,
|
||||
ARRAY_SIZE(mdss_dsi_pllcc_8996_1));
|
||||
} else {
|
||||
dsi0pll_byte_clk_src.priv = pll_res;
|
||||
dsi0pll_pixel_clk_src.priv = pll_res;
|
||||
dsi0pll_post_n1_div_clk.priv = pll_res;
|
||||
dsi0pll_n2_div_clk.priv = pll_res;
|
||||
dsi0pll_vco_clk.priv = pll_res;
|
||||
|
||||
dsi0pll_shadow_byte_clk_src.priv = pll_res;
|
||||
dsi0pll_shadow_pixel_clk_src.priv = pll_res;
|
||||
dsi0pll_shadow_post_n1_div_clk.priv = pll_res;
|
||||
dsi0pll_shadow_n2_div_clk.priv = pll_res;
|
||||
dsi0pll_shadow_vco_clk.priv = pll_res;
|
||||
|
||||
pll_res->vco_delay = VCO_DELAY_USEC;
|
||||
rc = of_msm_clock_register(pdev->dev.of_node,
|
||||
mdss_dsi_pllcc_8996,
|
||||
ARRAY_SIZE(mdss_dsi_pllcc_8996));
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
pr_info("Registered DSI PLL ndx=%d clocks successfully\n",
|
||||
pll_res->index);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
221
drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h
Normal file
221
drivers/clk/qcom/mdss/mdss-dsi-pll-8996.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef MDSS_DSI_PLL_8996_H
|
||||
#define MDSS_DSI_PLL_8996_H
|
||||
|
||||
#define DSIPHY_CMN_CLK_CFG0 0x0010
|
||||
#define DSIPHY_CMN_CLK_CFG1 0x0014
|
||||
#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
|
||||
|
||||
#define DSIPHY_CMN_PLL_CNTRL 0x0048
|
||||
#define DSIPHY_CMN_CTRL_0 0x001c
|
||||
#define DSIPHY_CMN_CTRL_1 0x0020
|
||||
|
||||
#define DSIPHY_CMN_LDO_CNTRL 0x004c
|
||||
|
||||
#define DSIPHY_PLL_IE_TRIM 0x0400
|
||||
#define DSIPHY_PLL_IP_TRIM 0x0404
|
||||
|
||||
#define DSIPHY_PLL_IPTAT_TRIM 0x0410
|
||||
|
||||
#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
|
||||
|
||||
#define DSIPHY_PLL_SYSCLK_EN_RESET 0x0428
|
||||
#define DSIPHY_PLL_RESETSM_CNTRL 0x042c
|
||||
#define DSIPHY_PLL_RESETSM_CNTRL2 0x0430
|
||||
#define DSIPHY_PLL_RESETSM_CNTRL3 0x0434
|
||||
#define DSIPHY_PLL_RESETSM_CNTRL4 0x0438
|
||||
#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
|
||||
#define DSIPHY_PLL_KVCO_DIV_REF1 0x0440
|
||||
#define DSIPHY_PLL_KVCO_DIV_REF2 0x0444
|
||||
#define DSIPHY_PLL_KVCO_COUNT1 0x0448
|
||||
#define DSIPHY_PLL_KVCO_COUNT2 0x044c
|
||||
#define DSIPHY_PLL_VREF_CFG1 0x045c
|
||||
|
||||
#define DSIPHY_PLL_KVCO_CODE 0x0458
|
||||
|
||||
#define DSIPHY_PLL_VCO_DIV_REF1 0x046c
|
||||
#define DSIPHY_PLL_VCO_DIV_REF2 0x0470
|
||||
#define DSIPHY_PLL_VCO_COUNT1 0x0474
|
||||
#define DSIPHY_PLL_VCO_COUNT2 0x0478
|
||||
#define DSIPHY_PLL_PLLLOCK_CMP1 0x047c
|
||||
#define DSIPHY_PLL_PLLLOCK_CMP2 0x0480
|
||||
#define DSIPHY_PLL_PLLLOCK_CMP3 0x0484
|
||||
#define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488
|
||||
#define DSIPHY_PLL_PLL_VCO_TUNE 0x048C
|
||||
#define DSIPHY_PLL_DEC_START 0x0490
|
||||
#define DSIPHY_PLL_SSC_EN_CENTER 0x0494
|
||||
#define DSIPHY_PLL_SSC_ADJ_PER1 0x0498
|
||||
#define DSIPHY_PLL_SSC_ADJ_PER2 0x049c
|
||||
#define DSIPHY_PLL_SSC_PER1 0x04a0
|
||||
#define DSIPHY_PLL_SSC_PER2 0x04a4
|
||||
#define DSIPHY_PLL_SSC_STEP_SIZE1 0x04a8
|
||||
#define DSIPHY_PLL_SSC_STEP_SIZE2 0x04ac
|
||||
#define DSIPHY_PLL_DIV_FRAC_START1 0x04b4
|
||||
#define DSIPHY_PLL_DIV_FRAC_START2 0x04b8
|
||||
#define DSIPHY_PLL_DIV_FRAC_START3 0x04bc
|
||||
#define DSIPHY_PLL_TXCLK_EN 0x04c0
|
||||
#define DSIPHY_PLL_PLL_CRCTRL 0x04c4
|
||||
|
||||
#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc
|
||||
|
||||
#define DSIPHY_PLL_PLL_MISC1 0x04e8
|
||||
|
||||
#define DSIPHY_PLL_CP_SET_CUR 0x04f0
|
||||
#define DSIPHY_PLL_PLL_ICPMSET 0x04f4
|
||||
#define DSIPHY_PLL_PLL_ICPCSET 0x04f8
|
||||
#define DSIPHY_PLL_PLL_ICP_SET 0x04fc
|
||||
#define DSIPHY_PLL_PLL_LPF1 0x0500
|
||||
#define DSIPHY_PLL_PLL_LPF2_POSTDIV 0x0504
|
||||
#define DSIPHY_PLL_PLL_BANDGAP 0x0508
|
||||
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 0x050
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 0x060
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 0x064
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 0x068
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 0x06C
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 0x070
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 0x074
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 0x078
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 0x07C
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 0x080
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 0x084
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 0x088
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR 0x094
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 0x098
|
||||
|
||||
struct dsi_pll_input {
|
||||
u32 fref; /* 19.2 Mhz, reference clk */
|
||||
u32 fdata; /* bit clock rate */
|
||||
u32 dsiclk_sel; /* 1, reg: 0x0014 */
|
||||
u32 n2div; /* 1, reg: 0x0010, bit 4-7 */
|
||||
u32 ssc_en; /* 1, reg: 0x0494, bit 0 */
|
||||
u32 ldo_en; /* 0, reg: 0x004c, bit 0 */
|
||||
|
||||
/* fixed */
|
||||
u32 refclk_dbler_en; /* 0, reg: 0x04c0, bit 1 */
|
||||
u32 vco_measure_time; /* 5, unknown */
|
||||
u32 kvco_measure_time; /* 5, unknown */
|
||||
u32 bandgap_timer; /* 4, reg: 0x0430, bit 3 - 5 */
|
||||
u32 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */
|
||||
u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */
|
||||
u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */
|
||||
u32 ssc_center; /* 0, reg: 0x0494, bit 1 */
|
||||
u32 ssc_adj_period; /* 37, reg: 0x498, bit 0 - 9 */
|
||||
u32 ssc_spread; /* 0.005 */
|
||||
u32 ssc_freq; /* unknown */
|
||||
u32 pll_ie_trim; /* 4, reg: 0x0400 */
|
||||
u32 pll_ip_trim; /* 4, reg: 0x0404 */
|
||||
u32 pll_iptat_trim; /* reg: 0x0410 */
|
||||
u32 pll_cpcset_cur; /* 1, reg: 0x04f0, bit 0 - 2 */
|
||||
u32 pll_cpmset_cur; /* 1, reg: 0x04f0, bit 3 - 5 */
|
||||
|
||||
u32 pll_icpmset; /* 4, reg: 0x04fc, bit 3 - 5 */
|
||||
u32 pll_icpcset; /* 4, reg: 0x04fc, bit 0 - 2 */
|
||||
|
||||
u32 pll_icpmset_p; /* 0, reg: 0x04f4, bit 0 - 2 */
|
||||
u32 pll_icpmset_m; /* 0, reg: 0x04f4, bit 3 - 5 */
|
||||
|
||||
u32 pll_icpcset_p; /* 0, reg: 0x04f8, bit 0 - 2 */
|
||||
u32 pll_icpcset_m; /* 0, reg: 0x04f8, bit 3 - 5 */
|
||||
|
||||
u32 pll_lpf_res1; /* 3, reg: 0x0504, bit 0 - 3 */
|
||||
u32 pll_lpf_cap1; /* 11, reg: 0x0500, bit 0 - 3 */
|
||||
u32 pll_lpf_cap2; /* 1, reg: 0x0500, bit 4 - 7 */
|
||||
u32 pll_c3ctrl; /* 2, reg: 0x04c4 */
|
||||
u32 pll_r3ctrl; /* 1, reg: 0x04c4 */
|
||||
};
|
||||
|
||||
struct dsi_pll_output {
|
||||
u32 pll_txclk_en; /* reg: 0x04c0 */
|
||||
u32 dec_start; /* reg: 0x0490 */
|
||||
u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */
|
||||
u32 ssc_period; /* reg: 0x04a0, 0x04a4 */
|
||||
u32 ssc_step_size; /* reg: 0x04a8, 0x04ac */
|
||||
u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */
|
||||
u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */
|
||||
u32 pll_vco_count; /* reg: 0x0474, 0x0478 */
|
||||
u32 pll_kvco_div_ref; /* reg: 0x0440, 0x0444 */
|
||||
u32 pll_kvco_count; /* reg: 0x0448, 0x044c */
|
||||
u32 pll_misc1; /* reg: 0x04e8 */
|
||||
u32 pll_lpf2_postdiv; /* reg: 0x0504 */
|
||||
u32 pll_resetsm_cntrl; /* reg: 0x042c */
|
||||
u32 pll_resetsm_cntrl2; /* reg: 0x0430 */
|
||||
u32 pll_resetsm_cntrl5; /* reg: 0x043c */
|
||||
u32 pll_kvco_code; /* reg: 0x0458 */
|
||||
|
||||
u32 cmn_clk_cfg0; /* reg: 0x0010 */
|
||||
u32 cmn_clk_cfg1; /* reg: 0x0014 */
|
||||
u32 cmn_ldo_cntrl; /* reg: 0x004c */
|
||||
|
||||
u32 pll_postdiv; /* vco */
|
||||
u32 pll_n1div; /* vco */
|
||||
u32 pll_n2div; /* hr_oclk3, pixel */
|
||||
u32 fcvo;
|
||||
};
|
||||
|
||||
enum {
|
||||
DSI_PLL_0,
|
||||
DSI_PLL_1,
|
||||
DSI_PLL_NUM
|
||||
};
|
||||
|
||||
struct dsi_pll_db {
|
||||
struct dsi_pll_db *next;
|
||||
struct mdss_pll_resources *pll;
|
||||
struct dsi_pll_input in;
|
||||
struct dsi_pll_output out;
|
||||
int source_setup_done;
|
||||
};
|
||||
|
||||
enum {
|
||||
PLL_OUTPUT_NONE,
|
||||
PLL_OUTPUT_RIGHT,
|
||||
PLL_OUTPUT_LEFT,
|
||||
PLL_OUTPUT_BOTH
|
||||
};
|
||||
|
||||
enum {
|
||||
PLL_SOURCE_FROM_LEFT,
|
||||
PLL_SOURCE_FROM_RIGHT
|
||||
};
|
||||
|
||||
enum {
|
||||
PLL_UNKNOWN,
|
||||
PLL_STANDALONE,
|
||||
PLL_SLAVE,
|
||||
PLL_MASTER
|
||||
};
|
||||
|
||||
int pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
|
||||
long pll_vco_round_rate_8996(struct clk *c, unsigned long rate);
|
||||
enum handoff pll_vco_handoff_8996(struct clk *c);
|
||||
enum handoff shadow_pll_vco_handoff_8996(struct clk *c);
|
||||
int shadow_post_n1_div_set_div(struct div_clk *clk, int div);
|
||||
int shadow_post_n1_div_get_div(struct div_clk *clk);
|
||||
int shadow_n2_div_set_div(struct div_clk *clk, int div);
|
||||
int shadow_n2_div_get_div(struct div_clk *clk);
|
||||
int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate);
|
||||
int pll_vco_prepare_8996(struct clk *c);
|
||||
void pll_vco_unprepare_8996(struct clk *c);
|
||||
int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel);
|
||||
int get_mdss_byte_mux_sel_8996(struct mux_clk *clk);
|
||||
int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel);
|
||||
int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk);
|
||||
int post_n1_div_set_div(struct div_clk *clk, int div);
|
||||
int post_n1_div_get_div(struct div_clk *clk);
|
||||
int n2_div_set_div(struct div_clk *clk, int div);
|
||||
int n2_div_get_div(struct div_clk *clk);
|
||||
int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll);
|
||||
|
||||
#endif /* MDSS_DSI_PLL_8996_H */
|
110
drivers/clk/qcom/mdss/mdss-dsi-pll.h
Normal file
110
drivers/clk/qcom/mdss/mdss-dsi-pll.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MDSS_DSI_PLL_H
|
||||
#define __MDSS_DSI_PLL_H
|
||||
|
||||
#define MAX_DSI_PLL_EN_SEQS 10
|
||||
|
||||
#define DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x0020)
|
||||
#define DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x0064)
|
||||
#define DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x0068)
|
||||
#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x0070)
|
||||
|
||||
/* Register offsets for 20nm PHY PLL */
|
||||
#define MMSS_DSI_PHY_PLL_PLL_CNTRL (0x0014)
|
||||
#define MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN (0x002C)
|
||||
#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN (0x009C)
|
||||
|
||||
struct lpfr_cfg {
|
||||
unsigned long vco_rate;
|
||||
u32 r;
|
||||
};
|
||||
|
||||
struct dsi_pll_vco_clk {
|
||||
unsigned long ref_clk_rate;
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
u32 pll_en_seq_cnt;
|
||||
struct lpfr_cfg *lpfr_lut;
|
||||
u32 lpfr_lut_size;
|
||||
void *priv;
|
||||
|
||||
struct clk c;
|
||||
|
||||
int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])
|
||||
(struct mdss_pll_resources *dsi_pll_Res);
|
||||
};
|
||||
|
||||
static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
|
||||
{
|
||||
return container_of(clk, struct dsi_pll_vco_clk, c);
|
||||
}
|
||||
|
||||
int dsi_pll_clock_register_hpm(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
int dsi_pll_clock_register_20nm(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
int dsi_pll_clock_register_lpm(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
int dsi_pll_clock_register_8996(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
int dsi_pll_clock_register_cobalt(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int set_byte_mux_sel(struct mux_clk *clk, int sel);
|
||||
int get_byte_mux_sel(struct mux_clk *clk);
|
||||
int dsi_pll_mux_prepare(struct clk *c);
|
||||
int fixed_4div_set_div(struct div_clk *clk, int div);
|
||||
int fixed_4div_get_div(struct div_clk *clk);
|
||||
int digital_set_div(struct div_clk *clk, int div);
|
||||
int digital_get_div(struct div_clk *clk);
|
||||
int analog_set_div(struct div_clk *clk, int div);
|
||||
int analog_get_div(struct div_clk *clk);
|
||||
int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
|
||||
int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
|
||||
unsigned long vco_get_rate(struct clk *c);
|
||||
long vco_round_rate(struct clk *c, unsigned long rate);
|
||||
enum handoff vco_handoff(struct clk *c);
|
||||
int vco_prepare(struct clk *c);
|
||||
void vco_unprepare(struct clk *c);
|
||||
|
||||
/* APIs for 20nm PHY PLL */
|
||||
int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
|
||||
int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco,
|
||||
unsigned long rate);
|
||||
long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate);
|
||||
enum handoff pll_20nm_vco_handoff(struct clk *c);
|
||||
int pll_20nm_vco_prepare(struct clk *c);
|
||||
void pll_20nm_vco_unprepare(struct clk *c);
|
||||
int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res);
|
||||
|
||||
int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
|
||||
int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel);
|
||||
int get_bypass_lp_div_mux_sel(struct mux_clk *clk);
|
||||
int fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
|
||||
int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div);
|
||||
int fixed_hr_oclk2_get_div(struct div_clk *clk);
|
||||
int hr_oclk3_set_div(struct div_clk *clk, int div);
|
||||
int shadow_hr_oclk3_set_div(struct div_clk *clk, int div);
|
||||
int hr_oclk3_get_div(struct div_clk *clk);
|
||||
int ndiv_set_div(struct div_clk *clk, int div);
|
||||
int shadow_ndiv_set_div(struct div_clk *clk, int div);
|
||||
int ndiv_get_div(struct div_clk *clk);
|
||||
void __dsi_pll_disable(void __iomem *pll_base);
|
||||
|
||||
int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel);
|
||||
int get_mdss_pixel_mux_sel(struct mux_clk *clk);
|
||||
int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel);
|
||||
int get_mdss_byte_mux_sel(struct mux_clk *clk);
|
||||
|
||||
#endif
|
2686
drivers/clk/qcom/mdss/mdss-hdmi-pll-8996.c
Normal file
2686
drivers/clk/qcom/mdss/mdss-hdmi-pll-8996.c
Normal file
File diff suppressed because it is too large
Load diff
61
drivers/clk/qcom/mdss/mdss-hdmi-pll.h
Normal file
61
drivers/clk/qcom/mdss/mdss-hdmi-pll.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MDSS_HDMI_PLL_H
|
||||
#define __MDSS_HDMI_PLL_H
|
||||
|
||||
struct hdmi_pll_cfg {
|
||||
unsigned long vco_rate;
|
||||
u32 reg;
|
||||
};
|
||||
|
||||
struct hdmi_pll_vco_clk {
|
||||
unsigned long rate; /* current vco rate */
|
||||
unsigned long min_rate; /* min vco rate */
|
||||
unsigned long max_rate; /* max vco rate */
|
||||
bool rate_set;
|
||||
struct hdmi_pll_cfg *ip_seti;
|
||||
struct hdmi_pll_cfg *cp_seti;
|
||||
struct hdmi_pll_cfg *ip_setp;
|
||||
struct hdmi_pll_cfg *cp_setp;
|
||||
struct hdmi_pll_cfg *crctrl;
|
||||
void *priv;
|
||||
|
||||
struct clk c;
|
||||
};
|
||||
|
||||
static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk)
|
||||
{
|
||||
return container_of(clk, struct hdmi_pll_vco_clk, c);
|
||||
}
|
||||
|
||||
int hdmi_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_20nm_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
|
||||
int hdmi_cobalt_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
#endif
|
438
drivers/clk/qcom/mdss/mdss-pll-util.c
Normal file
438
drivers/clk/qcom/mdss/mdss-pll-util.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/clk/msm-clock-generic.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/memblock.h>
|
||||
|
||||
#include "mdss-pll.h"
|
||||
|
||||
int mdss_pll_util_resource_init(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
rc = msm_dss_config_vreg(&pdev->dev,
|
||||
mp->vreg_config, mp->num_vreg, 1);
|
||||
if (rc) {
|
||||
pr_err("Vreg config failed rc=%d\n", rc);
|
||||
goto vreg_err;
|
||||
}
|
||||
|
||||
rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
pr_err("Clock get failed rc=%d\n", rc);
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
clk_err:
|
||||
msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
|
||||
vreg_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name
|
||||
*@pll_res: Pointer to the PLL resource
|
||||
*@name: Regulator name as specified in the pll dtsi
|
||||
*
|
||||
* This is a helper function to retrieve the regulator information
|
||||
* for each pll resource.
|
||||
*/
|
||||
struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
|
||||
, char *name)
|
||||
{
|
||||
|
||||
struct dss_vreg *regulator = NULL;
|
||||
int i;
|
||||
|
||||
if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) {
|
||||
pr_err("%s Invalid PLL resource\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
regulator = pll_res->mp.vreg_config;
|
||||
|
||||
for (i = 0; i < pll_res->mp.num_vreg; i++) {
|
||||
if (!strcmp(name, regulator->vreg_name)) {
|
||||
pr_debug("Found regulator match for %s\n", name);
|
||||
break;
|
||||
}
|
||||
regulator++;
|
||||
}
|
||||
|
||||
error:
|
||||
return regulator;
|
||||
}
|
||||
|
||||
void mdss_pll_util_resource_deinit(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
msm_dss_put_clk(mp->clk_config, mp->num_clk);
|
||||
|
||||
msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
|
||||
}
|
||||
|
||||
void mdss_pll_util_resource_release(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
devm_kfree(&pdev->dev, mp->clk_config);
|
||||
devm_kfree(&pdev->dev, mp->vreg_config);
|
||||
mp->num_vreg = 0;
|
||||
mp->num_clk = 0;
|
||||
}
|
||||
|
||||
int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
|
||||
bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
if (enable) {
|
||||
rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
|
||||
if (rc) {
|
||||
pr_err("Failed to enable vregs rc=%d\n", rc);
|
||||
goto vreg_err;
|
||||
}
|
||||
|
||||
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
pr_err("Failed to set clock rate rc=%d\n", rc);
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
|
||||
if (rc) {
|
||||
pr_err("clock enable failed rc:%d\n", rc);
|
||||
goto clk_err;
|
||||
}
|
||||
} else {
|
||||
msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
|
||||
|
||||
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
clk_err:
|
||||
msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
|
||||
vreg_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_util_parse_dt_supply(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int i = 0, rc = 0;
|
||||
u32 tmp = 0;
|
||||
struct device_node *of_node = NULL, *supply_root_node = NULL;
|
||||
struct device_node *supply_node = NULL;
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
of_node = pdev->dev.of_node;
|
||||
|
||||
mp->num_vreg = 0;
|
||||
supply_root_node = of_get_child_by_name(of_node,
|
||||
"qcom,platform-supply-entries");
|
||||
if (!supply_root_node) {
|
||||
pr_err("no supply entry present\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
for_each_child_of_node(supply_root_node, supply_node) {
|
||||
mp->num_vreg++;
|
||||
}
|
||||
|
||||
if (mp->num_vreg == 0) {
|
||||
pr_debug("no vreg\n");
|
||||
return rc;
|
||||
}
|
||||
pr_debug("vreg found. count=%d\n", mp->num_vreg);
|
||||
|
||||
mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct dss_vreg) *
|
||||
mp->num_vreg, GFP_KERNEL);
|
||||
if (!mp->vreg_config) {
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
|
||||
for_each_child_of_node(supply_root_node, supply_node) {
|
||||
|
||||
const char *st = NULL;
|
||||
|
||||
rc = of_property_read_string(supply_node,
|
||||
"qcom,supply-name", &st);
|
||||
if (rc) {
|
||||
pr_err(":error reading name. rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
strlcpy(mp->vreg_config[i].vreg_name, st,
|
||||
sizeof(mp->vreg_config[i].vreg_name));
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-min-voltage", &tmp);
|
||||
if (rc) {
|
||||
pr_err(": error reading min volt. rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].min_voltage = tmp;
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-max-voltage", &tmp);
|
||||
if (rc) {
|
||||
pr_err(": error reading max volt. rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].max_voltage = tmp;
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-enable-load", &tmp);
|
||||
if (rc) {
|
||||
pr_err(": error reading enable load. rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].enable_load = tmp;
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-disable-load", &tmp);
|
||||
if (rc) {
|
||||
pr_err(": error reading disable load. rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].disable_load = tmp;
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-pre-on-sleep", &tmp);
|
||||
if (rc)
|
||||
pr_debug("error reading supply pre sleep value. rc=%d\n",
|
||||
rc);
|
||||
|
||||
mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-pre-off-sleep", &tmp);
|
||||
if (rc)
|
||||
pr_debug("error reading supply pre sleep value. rc=%d\n",
|
||||
rc);
|
||||
|
||||
mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-post-on-sleep", &tmp);
|
||||
if (rc)
|
||||
pr_debug("error reading supply post sleep value. rc=%d\n",
|
||||
rc);
|
||||
|
||||
mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
|
||||
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-post-off-sleep", &tmp);
|
||||
if (rc)
|
||||
pr_debug("error reading supply post sleep value. rc=%d\n",
|
||||
rc);
|
||||
|
||||
mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
|
||||
|
||||
pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
|
||||
mp->vreg_config[i].vreg_name,
|
||||
mp->vreg_config[i].min_voltage,
|
||||
mp->vreg_config[i].max_voltage,
|
||||
mp->vreg_config[i].enable_load,
|
||||
mp->vreg_config[i].disable_load,
|
||||
mp->vreg_config[i].pre_on_sleep,
|
||||
mp->vreg_config[i].post_on_sleep,
|
||||
mp->vreg_config[i].pre_off_sleep,
|
||||
mp->vreg_config[i].post_off_sleep);
|
||||
++i;
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
error:
|
||||
if (mp->vreg_config) {
|
||||
devm_kfree(&pdev->dev, mp->vreg_config);
|
||||
mp->vreg_config = NULL;
|
||||
mp->num_vreg = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_util_parse_dt_clock(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
u32 i = 0, rc = 0;
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
const char *clock_name;
|
||||
u32 clock_rate;
|
||||
|
||||
mp->num_clk = of_property_count_strings(pdev->dev.of_node,
|
||||
"clock-names");
|
||||
if (mp->num_clk <= 0) {
|
||||
pr_err("clocks are not defined\n");
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
mp->clk_config = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct dss_clk) * mp->num_clk, GFP_KERNEL);
|
||||
if (!mp->clk_config) {
|
||||
rc = -ENOMEM;
|
||||
mp->num_clk = 0;
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
for (i = 0; i < mp->num_clk; i++) {
|
||||
of_property_read_string_index(pdev->dev.of_node, "clock-names",
|
||||
i, &clock_name);
|
||||
strlcpy(mp->clk_config[i].clk_name, clock_name,
|
||||
sizeof(mp->clk_config[i].clk_name));
|
||||
|
||||
of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
|
||||
i, &clock_rate);
|
||||
mp->clk_config[i].rate = clock_rate;
|
||||
|
||||
if (!clock_rate)
|
||||
mp->clk_config[i].type = DSS_CLK_AHB;
|
||||
else
|
||||
mp->clk_config[i].type = DSS_CLK_PCLK;
|
||||
}
|
||||
|
||||
clk_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void mdss_pll_free_bootmem(u32 mem_addr, u32 size)
|
||||
{
|
||||
unsigned long pfn_start, pfn_end, pfn_idx;
|
||||
|
||||
pfn_start = mem_addr >> PAGE_SHIFT;
|
||||
pfn_end = (mem_addr + size) >> PAGE_SHIFT;
|
||||
for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++)
|
||||
free_reserved_page(pfn_to_page(pfn_idx));
|
||||
}
|
||||
|
||||
static int mdss_pll_util_parse_dt_dfps(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc = 0;
|
||||
struct device_node *pnode;
|
||||
const u32 *addr;
|
||||
struct vm_struct *area;
|
||||
u64 size;
|
||||
u32 offsets[2];
|
||||
unsigned long virt_add;
|
||||
|
||||
pnode = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
|
||||
if (IS_ERR_OR_NULL(pnode)) {
|
||||
rc = PTR_ERR(pnode);
|
||||
goto pnode_err;
|
||||
}
|
||||
|
||||
addr = of_get_address(pnode, 0, &size, NULL);
|
||||
if (!addr) {
|
||||
pr_err("failed to parse the dfps memory address\n");
|
||||
rc = -EINVAL;
|
||||
goto pnode_err;
|
||||
}
|
||||
/* maintain compatibility for 32/64 bit */
|
||||
offsets[0] = (u32) of_read_ulong(addr, 2);
|
||||
offsets[1] = (u32) size;
|
||||
|
||||
area = get_vm_area(offsets[1], VM_IOREMAP);
|
||||
if (!area) {
|
||||
rc = -ENOMEM;
|
||||
goto dfps_mem_err;
|
||||
}
|
||||
|
||||
virt_add = (unsigned long)area->addr;
|
||||
rc = ioremap_page_range(virt_add, (virt_add + offsets[1]),
|
||||
offsets[0], PAGE_KERNEL);
|
||||
if (rc) {
|
||||
rc = -ENOMEM;
|
||||
goto ioremap_err;
|
||||
}
|
||||
|
||||
pll_res->dfps = kzalloc(sizeof(struct dfps_info), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(pll_res->dfps)) {
|
||||
rc = PTR_ERR(pll_res->dfps);
|
||||
pr_err("couldn't allocate dfps kernel memory\n");
|
||||
goto addr_err;
|
||||
}
|
||||
|
||||
/* memcopy complete dfps structure from kernel virtual memory */
|
||||
memcpy_fromio(pll_res->dfps, area->addr, sizeof(struct dfps_info));
|
||||
|
||||
addr_err:
|
||||
if (virt_add)
|
||||
unmap_kernel_range(virt_add, (unsigned long) size);
|
||||
ioremap_err:
|
||||
if (area)
|
||||
vfree(area->addr);
|
||||
dfps_mem_err:
|
||||
/* free the dfps memory here */
|
||||
memblock_free(offsets[0], offsets[1]);
|
||||
mdss_pll_free_bootmem(offsets[0], offsets[1]);
|
||||
pnode_err:
|
||||
if (pnode)
|
||||
of_node_put(pnode);
|
||||
|
||||
dma_release_declared_memory(&pdev->dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mdss_pll_util_resource_parse(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp = &pll_res->mp;
|
||||
|
||||
rc = mdss_pll_util_parse_dt_supply(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("vreg parsing failed rc=%d\n", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = mdss_pll_util_parse_dt_clock(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("clock name parsing failed rc=%d", rc);
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
if (mdss_pll_util_parse_dt_dfps(pdev, pll_res))
|
||||
pr_err("dfps not enabled!\n");
|
||||
|
||||
return rc;
|
||||
|
||||
clk_err:
|
||||
devm_kfree(&pdev->dev, mp->vreg_config);
|
||||
mp->num_vreg = 0;
|
||||
end:
|
||||
return rc;
|
||||
}
|
437
drivers/clk/qcom/mdss/mdss-pll.c
Normal file
437
drivers/clk/qcom/mdss/mdss-pll.c
Normal file
|
@ -0,0 +1,437 @@
|
|||
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/clk/msm-clock-generic.h>
|
||||
|
||||
#include "mdss-pll.h"
|
||||
#include "mdss-dsi-pll.h"
|
||||
#include "mdss-hdmi-pll.h"
|
||||
#include "mdss-dp-pll.h"
|
||||
|
||||
int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
int changed = 0;
|
||||
|
||||
if (!pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't turn off resources during handoff or add more than
|
||||
* 1 refcount.
|
||||
*/
|
||||
if (pll_res->handoff_resources &&
|
||||
(!enable || (enable & pll_res->resource_enable))) {
|
||||
pr_debug("Do not turn on/off pll resources during handoff case\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if (pll_res->resource_ref_cnt == 0)
|
||||
changed++;
|
||||
pll_res->resource_ref_cnt++;
|
||||
} else {
|
||||
if (pll_res->resource_ref_cnt) {
|
||||
pll_res->resource_ref_cnt--;
|
||||
if (pll_res->resource_ref_cnt == 0)
|
||||
changed++;
|
||||
} else {
|
||||
pr_err("PLL Resources already OFF\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
rc = mdss_pll_util_resource_enable(pll_res, enable);
|
||||
if (rc)
|
||||
pr_err("Resource update failed rc=%d\n", rc);
|
||||
else
|
||||
pll_res->resource_enable = enable;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_resource_init(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
if (!pdev || !pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mdss_pll_util_resource_init(pdev, pll_res);
|
||||
}
|
||||
|
||||
static void mdss_pll_resource_deinit(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
if (!pdev || !pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdss_pll_util_resource_deinit(pdev, pll_res);
|
||||
}
|
||||
|
||||
static void mdss_pll_resource_release(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
if (!pdev || !pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mdss_pll_util_resource_release(pdev, pll_res);
|
||||
}
|
||||
|
||||
static int mdss_pll_resource_parse(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc = 0;
|
||||
const char *compatible_stream;
|
||||
|
||||
if (!pdev || !pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = mdss_pll_util_resource_parse(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("Failed to parse the resources rc=%d\n", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
compatible_stream = of_get_property(pdev->dev.of_node,
|
||||
"compatible", NULL);
|
||||
if (!compatible_stream) {
|
||||
pr_err("Failed to parse the compatible stream\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996")) {
|
||||
pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
|
||||
pll_res->target_id = MDSS_PLL_TARGET_8996;
|
||||
pll_res->revision = 1;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996_v2")) {
|
||||
pll_res->pll_interface_type = MDSS_DSI_PLL_8996;
|
||||
pll_res->target_id = MDSS_PLL_TARGET_8996;
|
||||
pll_res->revision = 2;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_cobalt")) {
|
||||
pll_res->pll_interface_type = MDSS_DSI_PLL_COBALT;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_cobalt")) {
|
||||
pll_res->pll_interface_type = MDSS_DP_PLL_COBALT;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996")) {
|
||||
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v2")) {
|
||||
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V2;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8996_v3")) {
|
||||
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3;
|
||||
} else if (!strcmp(compatible_stream,
|
||||
"qcom,mdss_hdmi_pll_8996_v3_1p8")) {
|
||||
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3_1_8;
|
||||
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_cobalt")) {
|
||||
pll_res->pll_interface_type = MDSS_HDMI_PLL_COBALT;
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
err:
|
||||
mdss_pll_resource_release(pdev, pll_res);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_clock_register(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!pdev || !pll_res) {
|
||||
pr_err("Invalid input parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (pll_res->pll_interface_type) {
|
||||
case MDSS_DSI_PLL_8996:
|
||||
rc = dsi_pll_clock_register_8996(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_DSI_PLL_COBALT:
|
||||
rc = dsi_pll_clock_register_cobalt(pdev, pll_res);
|
||||
case MDSS_DP_PLL_COBALT:
|
||||
rc = dp_pll_clock_register_cobalt(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_HDMI_PLL_8996:
|
||||
rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_HDMI_PLL_8996_V2:
|
||||
rc = hdmi_8996_v2_pll_clock_register(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_HDMI_PLL_8996_V3:
|
||||
rc = hdmi_8996_v3_pll_clock_register(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_HDMI_PLL_8996_V3_1_8:
|
||||
rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_HDMI_PLL_COBALT:
|
||||
rc = hdmi_cobalt_pll_clock_register(pdev, pll_res);
|
||||
break;
|
||||
case MDSS_UNKNOWN_PLL:
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
pr_err("Pll ndx=%d clock register failed rc=%d\n",
|
||||
pll_res->index, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
const char *label;
|
||||
struct resource *pll_base_reg;
|
||||
struct resource *phy_base_reg;
|
||||
struct resource *dynamic_pll_base_reg;
|
||||
struct resource *gdsc_base_reg;
|
||||
struct mdss_pll_resources *pll_res;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
pr_err("MDSS pll driver only supports device tree probe\n");
|
||||
rc = -ENOTSUPP;
|
||||
goto error;
|
||||
}
|
||||
|
||||
label = of_get_property(pdev->dev.of_node, "label", NULL);
|
||||
if (!label)
|
||||
pr_info("%d: MDSS pll label not specified\n", __LINE__);
|
||||
else
|
||||
pr_info("MDSS pll label = %s\n", label);
|
||||
|
||||
pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources),
|
||||
GFP_KERNEL);
|
||||
if (!pll_res) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
platform_set_drvdata(pdev, pll_res);
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
|
||||
&pll_res->index);
|
||||
if (rc) {
|
||||
pr_err("Unable to get the cell-index rc=%d\n", rc);
|
||||
pll_res->index = 0;
|
||||
}
|
||||
|
||||
pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,dsi-pll-ssc-en");
|
||||
|
||||
if (pll_res->ssc_en) {
|
||||
pr_info("%s: label=%s PLL SSC enabled\n", __func__, label);
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node,
|
||||
"qcom,ssc-frequency-hz", &pll_res->ssc_freq);
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node,
|
||||
"qcom,ssc-ppm", &pll_res->ssc_ppm);
|
||||
|
||||
pll_res->ssc_center = false;
|
||||
|
||||
label = of_get_property(pdev->dev.of_node,
|
||||
"qcom,dsi-pll-ssc-mode", NULL);
|
||||
|
||||
if (label && !strcmp(label, "center-spread"))
|
||||
pll_res->ssc_center = true;
|
||||
}
|
||||
|
||||
pll_base_reg = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "pll_base");
|
||||
if (!pll_base_reg) {
|
||||
pr_err("Unable to get the pll base resources\n");
|
||||
rc = -ENOMEM;
|
||||
goto io_error;
|
||||
}
|
||||
|
||||
pll_res->pll_base = ioremap(pll_base_reg->start,
|
||||
resource_size(pll_base_reg));
|
||||
if (!pll_res->pll_base) {
|
||||
pr_err("Unable to remap pll base resources\n");
|
||||
rc = -ENOMEM;
|
||||
goto io_error;
|
||||
}
|
||||
|
||||
pr_debug("%s: ndx=%d base=%p\n", __func__,
|
||||
pll_res->index, pll_res->pll_base);
|
||||
|
||||
rc = mdss_pll_resource_parse(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("Pll resource parsing from dt failed rc=%d\n", rc);
|
||||
goto res_parse_error;
|
||||
}
|
||||
|
||||
phy_base_reg = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "phy_base");
|
||||
if (phy_base_reg) {
|
||||
pll_res->phy_base = ioremap(phy_base_reg->start,
|
||||
resource_size(phy_base_reg));
|
||||
if (!pll_res->phy_base) {
|
||||
pr_err("Unable to remap pll phy base resources\n");
|
||||
rc = -ENOMEM;
|
||||
goto phy_io_error;
|
||||
}
|
||||
}
|
||||
|
||||
dynamic_pll_base_reg = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "dynamic_pll_base");
|
||||
if (dynamic_pll_base_reg) {
|
||||
pll_res->dyn_pll_base = ioremap(dynamic_pll_base_reg->start,
|
||||
resource_size(dynamic_pll_base_reg));
|
||||
if (!pll_res->dyn_pll_base) {
|
||||
pr_err("Unable to remap dynamic pll base resources\n");
|
||||
rc = -ENOMEM;
|
||||
goto dyn_pll_io_error;
|
||||
}
|
||||
}
|
||||
|
||||
gdsc_base_reg = platform_get_resource_byname(pdev,
|
||||
IORESOURCE_MEM, "gdsc_base");
|
||||
if (!gdsc_base_reg) {
|
||||
pr_err("Unable to get the gdsc base resource\n");
|
||||
rc = -ENOMEM;
|
||||
goto gdsc_io_error;
|
||||
}
|
||||
pll_res->gdsc_base = ioremap(gdsc_base_reg->start,
|
||||
resource_size(gdsc_base_reg));
|
||||
if (!pll_res->gdsc_base) {
|
||||
pr_err("Unable to remap gdsc base resources\n");
|
||||
rc = -ENOMEM;
|
||||
goto gdsc_io_error;
|
||||
}
|
||||
|
||||
rc = mdss_pll_resource_init(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("Pll ndx=%d resource init failed rc=%d\n",
|
||||
pll_res->index, rc);
|
||||
goto res_init_error;
|
||||
}
|
||||
|
||||
rc = mdss_pll_clock_register(pdev, pll_res);
|
||||
if (rc) {
|
||||
pr_err("Pll ndx=%d clock register failed rc=%d\n",
|
||||
pll_res->index, rc);
|
||||
goto clock_register_error;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
clock_register_error:
|
||||
mdss_pll_resource_deinit(pdev, pll_res);
|
||||
res_init_error:
|
||||
if (pll_res->gdsc_base)
|
||||
iounmap(pll_res->gdsc_base);
|
||||
gdsc_io_error:
|
||||
if (pll_res->dyn_pll_base)
|
||||
iounmap(pll_res->dyn_pll_base);
|
||||
dyn_pll_io_error:
|
||||
if (pll_res->phy_base)
|
||||
iounmap(pll_res->phy_base);
|
||||
phy_io_error:
|
||||
mdss_pll_resource_release(pdev, pll_res);
|
||||
res_parse_error:
|
||||
iounmap(pll_res->pll_base);
|
||||
io_error:
|
||||
devm_kfree(&pdev->dev, pll_res);
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mdss_pll_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mdss_pll_resources *pll_res;
|
||||
|
||||
pll_res = platform_get_drvdata(pdev);
|
||||
if (!pll_res) {
|
||||
pr_err("Invalid PLL resource data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mdss_pll_resource_deinit(pdev, pll_res);
|
||||
if (pll_res->phy_base)
|
||||
iounmap(pll_res->phy_base);
|
||||
if (pll_res->gdsc_base)
|
||||
iounmap(pll_res->gdsc_base);
|
||||
mdss_pll_resource_release(pdev, pll_res);
|
||||
iounmap(pll_res->pll_base);
|
||||
devm_kfree(&pdev->dev, pll_res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mdss_pll_dt_match[] = {
|
||||
{.compatible = "qcom,mdss_dsi_pll_8996"},
|
||||
{.compatible = "qcom,mdss_dsi_pll_8996_v2"},
|
||||
{.compatible = "qcom,mdss_dsi_pll_cobalt"},
|
||||
{.compatible = "qcom,mdss_hdmi_pll_8996"},
|
||||
{.compatible = "qcom,mdss_hdmi_pll_8996_v2"},
|
||||
{.compatible = "qcom,mdss_hdmi_pll_8996_v3"},
|
||||
{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
|
||||
{.compatible = "qcom,mdss_dp_pll_cobalt"},
|
||||
{.compatible = "qcom,mdss_hdmi_pll_cobalt"},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mdss_clock_dt_match);
|
||||
|
||||
static struct platform_driver mdss_pll_driver = {
|
||||
.probe = mdss_pll_probe,
|
||||
.remove = mdss_pll_remove,
|
||||
.driver = {
|
||||
.name = "mdss_pll",
|
||||
.of_match_table = mdss_pll_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mdss_pll_driver_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = platform_driver_register(&mdss_pll_driver);
|
||||
if (rc)
|
||||
pr_err("mdss_register_pll_driver() failed!\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
subsys_initcall(mdss_pll_driver_init);
|
||||
|
||||
static void __exit mdss_pll_driver_deinit(void)
|
||||
{
|
||||
platform_driver_unregister(&mdss_pll_driver);
|
||||
}
|
||||
module_exit(mdss_pll_driver_deinit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("mdss pll driver");
|
233
drivers/clk/qcom/mdss/mdss-pll.h
Normal file
233
drivers/clk/qcom/mdss/mdss-pll.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __MDSS_PLL_H
|
||||
#define __MDSS_PLL_H
|
||||
|
||||
#include <linux/mdss_io_util.h>
|
||||
#include <linux/clk/msm-clock-generic.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define MDSS_PLL_REG_W(base, offset, data) \
|
||||
writel_relaxed((data), (base) + (offset))
|
||||
#define MDSS_PLL_REG_R(base, offset) readl_relaxed((base) + (offset))
|
||||
|
||||
#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
|
||||
(((data1) << 24) | ((((addr1) / 4) & 0xFF) << 16) | \
|
||||
((data0) << 8) | (((addr0) / 4) & 0xFF))
|
||||
|
||||
#define MDSS_DYN_PLL_REG_W(base, offset, addr0, addr1, data0, data1) \
|
||||
writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
|
||||
(base) + (offset))
|
||||
|
||||
enum {
|
||||
MDSS_DSI_PLL_8996,
|
||||
MDSS_DSI_PLL_COBALT,
|
||||
MDSS_DP_PLL_COBALT,
|
||||
MDSS_HDMI_PLL_8996,
|
||||
MDSS_HDMI_PLL_8996_V2,
|
||||
MDSS_HDMI_PLL_8996_V3,
|
||||
MDSS_HDMI_PLL_8996_V3_1_8,
|
||||
MDSS_HDMI_PLL_COBALT,
|
||||
MDSS_UNKNOWN_PLL,
|
||||
};
|
||||
|
||||
enum {
|
||||
MDSS_PLL_TARGET_8996,
|
||||
};
|
||||
|
||||
#define DFPS_MAX_NUM_OF_FRAME_RATES 20
|
||||
|
||||
struct dfps_panel_info {
|
||||
uint32_t enabled;
|
||||
uint32_t frame_rate_cnt;
|
||||
uint32_t frame_rate[DFPS_MAX_NUM_OF_FRAME_RATES]; /* hz */
|
||||
};
|
||||
|
||||
struct dfps_pll_codes {
|
||||
uint32_t pll_codes_1;
|
||||
uint32_t pll_codes_2;
|
||||
};
|
||||
|
||||
struct dfps_codes_info {
|
||||
uint32_t is_valid;
|
||||
uint32_t frame_rate; /* hz */
|
||||
uint32_t clk_rate; /* hz */
|
||||
struct dfps_pll_codes pll_codes;
|
||||
};
|
||||
|
||||
struct dfps_info {
|
||||
struct dfps_panel_info panel_dfps;
|
||||
struct dfps_codes_info codes_dfps[DFPS_MAX_NUM_OF_FRAME_RATES];
|
||||
void *dfps_fb_base;
|
||||
};
|
||||
|
||||
struct mdss_pll_resources {
|
||||
|
||||
/* Pll specific resources like GPIO, power supply, clocks, etc*/
|
||||
struct dss_module_power mp;
|
||||
|
||||
/*
|
||||
* dsi/edp/hmdi plls' base register, phy, gdsc and dynamic refresh
|
||||
* register mapping
|
||||
*/
|
||||
void __iomem *pll_base;
|
||||
void __iomem *phy_base;
|
||||
void __iomem *gdsc_base;
|
||||
void __iomem *dyn_pll_base;
|
||||
|
||||
bool is_init_locked;
|
||||
s64 vco_current_rate;
|
||||
s64 vco_locking_rate;
|
||||
s64 vco_ref_clk_rate;
|
||||
|
||||
/*
|
||||
* Certain pll's needs to update the same vco rate after resume in
|
||||
* suspend/resume scenario. Cached the vco rate for such plls.
|
||||
*/
|
||||
unsigned long vco_cached_rate;
|
||||
|
||||
/* dsi/edp/hmdi pll interface type */
|
||||
u32 pll_interface_type;
|
||||
|
||||
/*
|
||||
* Target ID. Used in pll_register API for valid target check before
|
||||
* registering the PLL clocks.
|
||||
*/
|
||||
u32 target_id;
|
||||
|
||||
/* HW recommended delay during configuration of vco clock rate */
|
||||
u32 vco_delay;
|
||||
|
||||
/* Ref-count of the PLL resources */
|
||||
u32 resource_ref_cnt;
|
||||
|
||||
/*
|
||||
* Keep track to resource status to avoid updating same status for the
|
||||
* pll from different paths
|
||||
*/
|
||||
bool resource_enable;
|
||||
|
||||
/*
|
||||
* Certain plls' do not allow vco rate update if it is on. Keep track of
|
||||
* status for them to turn on/off after set rate success.
|
||||
*/
|
||||
bool pll_on;
|
||||
|
||||
/*
|
||||
* handoff_status is true of pll is already enabled by bootloader with
|
||||
* continuous splash enable case. Clock API will call the handoff API
|
||||
* to enable the status. It is disabled if continuous splash
|
||||
* feature is disabled.
|
||||
*/
|
||||
bool handoff_resources;
|
||||
|
||||
/*
|
||||
* caching the pll trim codes in the case of dynamic refresh
|
||||
*/
|
||||
int cache_pll_trim_codes[2];
|
||||
|
||||
/*
|
||||
* for maintaining the status of saving trim codes
|
||||
*/
|
||||
bool reg_upd;
|
||||
|
||||
/*
|
||||
* Notifier callback for MDSS gdsc regulator events
|
||||
*/
|
||||
struct notifier_block gdsc_cb;
|
||||
|
||||
/*
|
||||
* Worker function to call PLL off event
|
||||
*/
|
||||
struct work_struct pll_off;
|
||||
|
||||
/*
|
||||
* PLL index if multiple index are available. Eg. in case of
|
||||
* DSI we have 2 plls.
|
||||
*/
|
||||
uint32_t index;
|
||||
|
||||
bool ssc_en; /* share pll with master */
|
||||
bool ssc_center; /* default is down spread */
|
||||
u32 ssc_freq;
|
||||
u32 ssc_ppm;
|
||||
|
||||
struct mdss_pll_resources *slave;
|
||||
|
||||
/*
|
||||
* target pll revision information
|
||||
*/
|
||||
int revision;
|
||||
|
||||
void *priv;
|
||||
|
||||
/*
|
||||
* dynamic refresh pll codes stored in this structure
|
||||
*/
|
||||
struct dfps_info *dfps;
|
||||
|
||||
};
|
||||
|
||||
struct mdss_pll_vco_calc {
|
||||
s32 div_frac_start1;
|
||||
s32 div_frac_start2;
|
||||
s32 div_frac_start3;
|
||||
s64 dec_start1;
|
||||
s64 dec_start2;
|
||||
s64 pll_plllock_cmp1;
|
||||
s64 pll_plllock_cmp2;
|
||||
s64 pll_plllock_cmp3;
|
||||
};
|
||||
|
||||
static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res)
|
||||
{
|
||||
if (!pll_res->gdsc_base) {
|
||||
WARN(1, "gdsc_base register is not defined\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
|
||||
(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
|
||||
}
|
||||
|
||||
static inline int mdss_pll_div_prepare(struct clk *c)
|
||||
{
|
||||
struct div_clk *div = to_div_clk(c);
|
||||
/* Restore the divider's value */
|
||||
return div->ops->set_div(div, div->data.div);
|
||||
}
|
||||
|
||||
static inline int mdss_set_mux_sel(struct mux_clk *clk, int sel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mdss_get_mux_sel(struct mux_clk *clk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable);
|
||||
int mdss_pll_util_resource_init(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
void mdss_pll_util_resource_deinit(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
void mdss_pll_util_resource_release(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res,
|
||||
bool enable);
|
||||
int mdss_pll_util_resource_parse(struct platform_device *pdev,
|
||||
struct mdss_pll_resources *pll_res);
|
||||
struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res
|
||||
, char *name);
|
||||
#endif
|
Loading…
Add table
Reference in a new issue