blob: 6a49d156395e1d5b102487c66ddf28af7a3a2ec8 [file] [log] [blame]
Chandan Uddaraju6b300412016-05-10 19:00:14 -07001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Chandan Uddaraju16128f32016-02-22 16:43:23 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14/*
15 ***************************************************************************
16 ******** Display Port PLL driver block diagram for branch clocks **********
17 ***************************************************************************
18
Chandan Uddarajue95883b2016-08-08 09:56:03 -070019 +--------------------------+
20 | DP_VCO_CLK |
21 | |
22 | +-------------------+ |
23 | | (DP PLL/VCO) | |
24 | +---------+---------+ |
25 | v |
26 | +----------+-----------+ |
27 | | hsclk_divsel_clk_src | |
28 | +----------+-----------+ |
29 +--------------------------+
Chandan Uddaraju16128f32016-02-22 16:43:23 -080030 |
31 v
32 +------------<------------|------------>-------------+
33 | | |
Chandan Uddaraju16128f32016-02-22 16:43:23 -080034+----------v----------+ +----------v----------+ +----------v----------+
Chandan Uddarajue95883b2016-08-08 09:56:03 -070035| dp_link_2x_clk | | vco_divided_clk_src | | vco_divided_clk_src |
36| divsel_five | | | | |
37v----------+----------v | divsel_two | | divsel_four |
Chandan Uddaraju16128f32016-02-22 16:43:23 -080038 | +----------+----------+ +----------+----------+
39 | | |
40 v v v
Chandan Uddarajue95883b2016-08-08 09:56:03 -070041 | +---------------------+ |
42 Input to MMSSCC block | | (aux_clk_ops) | |
43 for link clk, crypto clk +--> vco_divided_clk <-+
44 and interface clock | _src_mux |
45 +----------+----------+
Chandan Uddaraju16128f32016-02-22 16:43:23 -080046 |
47 v
48 Input to MMSSCC block
Chandan Uddarajue95883b2016-08-08 09:56:03 -070049 for DP pixel clock
Chandan Uddaraju16128f32016-02-22 16:43:23 -080050
51 ******************************************************************************
52 */
53
54#define pr_fmt(fmt) "%s: " fmt, __func__
55
56#include <linux/kernel.h>
57#include <linux/err.h>
58#include <linux/delay.h>
59#include <linux/clk/msm-clk-provider.h>
60#include <linux/clk/msm-clk.h>
61#include <linux/clk/msm-clock-generic.h>
62#include <dt-bindings/clock/msm-clocks-8998.h>
63
64#include "mdss-pll.h"
65#include "mdss-dp-pll.h"
66#include "mdss-dp-pll-8998.h"
67
Chandan Uddaraju16128f32016-02-22 16:43:23 -080068static const struct clk_ops clk_ops_vco_divided_clk_src_c;
69static const struct clk_ops clk_ops_link_2x_clk_div_c;
Chandan Uddarajue95883b2016-08-08 09:56:03 -070070static const struct clk_ops clk_ops_gen_mux_dp;
Chandan Uddaraju16128f32016-02-22 16:43:23 -080071
72static struct clk_div_ops link2xclk_divsel_ops = {
73 .set_div = link2xclk_divsel_set_div,
74 .get_div = link2xclk_divsel_get_div,
75};
76
77static struct clk_div_ops vco_divided_clk_ops = {
78 .set_div = vco_divided_clk_set_div,
79 .get_div = vco_divided_clk_get_div,
80};
81
82static const struct clk_ops dp_8998_vco_clk_ops = {
83 .set_rate = dp_vco_set_rate,
84 .round_rate = dp_vco_round_rate,
85 .prepare = dp_vco_prepare,
86 .unprepare = dp_vco_unprepare,
87 .handoff = dp_vco_handoff,
88};
89
90static struct clk_mux_ops mdss_mux_ops = {
91 .set_mux_sel = mdss_set_mux_sel,
92 .get_mux_sel = mdss_get_mux_sel,
93};
94
95static struct dp_pll_vco_clk dp_vco_clk = {
Padmanabhan Komanduruaeb94eb2016-08-31 18:24:05 +053096 .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
97 .max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000,
Chandan Uddaraju16128f32016-02-22 16:43:23 -080098 .c = {
99 .dbg_name = "dp_vco_clk",
100 .ops = &dp_8998_vco_clk_ops,
101 .flags = CLKFLAG_NO_RATE_CACHE,
102 CLK_INIT(dp_vco_clk.c),
103 },
104};
105
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800106static struct div_clk dp_link_2x_clk_divsel_five = {
107 .data = {
108 .div = 5,
109 .min_div = 5,
110 .max_div = 5,
111 },
112 .ops = &link2xclk_divsel_ops,
113 .c = {
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700114 .parent = &dp_vco_clk.c,
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800115 .dbg_name = "dp_link_2x_clk_divsel_five",
116 .ops = &clk_ops_link_2x_clk_div_c,
117 .flags = CLKFLAG_NO_RATE_CACHE,
118 CLK_INIT(dp_link_2x_clk_divsel_five.c),
119 },
120};
121
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700122static struct div_clk vco_divsel_four_clk_src = {
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800123 .data = {
124 .div = 4,
125 .min_div = 4,
126 .max_div = 4,
127 },
128 .ops = &vco_divided_clk_ops,
129 .c = {
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700130 .parent = &dp_vco_clk.c,
131 .dbg_name = "vco_divsel_four_clk_src",
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800132 .ops = &clk_ops_vco_divided_clk_src_c,
133 .flags = CLKFLAG_NO_RATE_CACHE,
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700134 CLK_INIT(vco_divsel_four_clk_src.c),
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800135 },
136};
137
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700138static struct div_clk vco_divsel_two_clk_src = {
139 .data = {
140 .div = 2,
141 .min_div = 2,
142 .max_div = 2,
143 },
144 .ops = &vco_divided_clk_ops,
145 .c = {
146 .parent = &dp_vco_clk.c,
147 .dbg_name = "vco_divsel_two_clk_src",
148 .ops = &clk_ops_vco_divided_clk_src_c,
149 .flags = CLKFLAG_NO_RATE_CACHE,
150 CLK_INIT(vco_divsel_two_clk_src.c),
151 },
152};
153
154static struct mux_clk vco_divided_clk_src_mux = {
155 .num_parents = 2,
156 .parents = (struct clk_src[]) {
157 {&vco_divsel_two_clk_src.c, 0},
158 {&vco_divsel_four_clk_src.c, 1},
159 },
160 .ops = &mdss_mux_ops,
161 .c = {
162 .parent = &vco_divsel_two_clk_src.c,
163 .dbg_name = "vco_divided_clk_src_mux",
164 .ops = &clk_ops_gen_mux_dp,
165 .flags = CLKFLAG_NO_RATE_CACHE,
166 CLK_INIT(vco_divided_clk_src_mux.c),
167 }
168};
169
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800170static struct clk_lookup dp_pllcc_8998[] = {
171 CLK_LIST(dp_vco_clk),
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800172 CLK_LIST(dp_link_2x_clk_divsel_five),
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700173 CLK_LIST(vco_divsel_four_clk_src),
174 CLK_LIST(vco_divsel_two_clk_src),
175 CLK_LIST(vco_divided_clk_src_mux),
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800176};
177
178int dp_pll_clock_register_8998(struct platform_device *pdev,
179 struct mdss_pll_resources *pll_res)
180{
181 int rc = -ENOTSUPP;
182
183 if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) {
184 DEV_ERR("%s: Invalid input parameters\n", __func__);
185 return -EINVAL;
186 }
187
188 /* Set client data for vco, mux and div clocks */
189 dp_vco_clk.priv = pll_res;
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700190 vco_divided_clk_src_mux.priv = pll_res;
191 vco_divsel_two_clk_src.priv = pll_res;
192 vco_divsel_four_clk_src.priv = pll_res;
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800193 dp_link_2x_clk_divsel_five.priv = pll_res;
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800194
195 clk_ops_link_2x_clk_div_c = clk_ops_div;
196 clk_ops_link_2x_clk_div_c.prepare = mdss_pll_div_prepare;
197
198 /*
199 * Set the ops for the divider in the pixel clock tree to the
200 * slave_div to ensure that a set rate on this divider clock will not
201 * be propagated to it's parent. This is needed ensure that when we set
202 * the rate for pixel clock, the vco is not reconfigured
203 */
204 clk_ops_vco_divided_clk_src_c = clk_ops_slave_div;
205 clk_ops_vco_divided_clk_src_c.prepare = mdss_pll_div_prepare;
Chandan Uddaraju601c3a92016-05-11 11:46:49 -0700206 clk_ops_vco_divided_clk_src_c.handoff = vco_divided_clk_handoff;
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800207
Chandan Uddarajue95883b2016-08-08 09:56:03 -0700208 clk_ops_gen_mux_dp = clk_ops_gen_mux;
209 clk_ops_gen_mux_dp.get_rate = parent_get_rate;
210
Chandan Uddaraju16128f32016-02-22 16:43:23 -0800211 /* We can select different clock ops for future versions */
212 dp_vco_clk.c.ops = &dp_8998_vco_clk_ops;
213
214 rc = of_msm_clock_register(pdev->dev.of_node, dp_pllcc_8998,
215 ARRAY_SIZE(dp_pllcc_8998));
216 if (rc) {
217 DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
218 rc = -EPROBE_DEFER;
219 } else {
220 DEV_DBG("%s SUCCESS\n", __func__);
221 }
222
223 return rc;
224}