blob: d6638c771be933dc2baf11dafafaf87cc7313ffb [file] [log] [blame]
Chandan Uddaraju16128f32016-02-22 16:43:23 -08001/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
2 *
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
19 +-------------------+
20 | dp_vco_clk |
21 | (DP PLL/VCO) |
22 +---------+---------+
23 |
24 |
25 v
26 +----------+-----------+
27 | hsclk_divsel_clk_src |
28 +----------+-----------+
29 |
30 |
31 v
32 +------------<------------|------------>-------------+
33 | | |
34 | | |
35+----------v----------+ +----------v----------+ +----------v----------+
36|vco_divided_clk_src | | dp_link_2x_clk | | dp_link_2x_clk |
37| (aux_clk_ops) | | | | |
38v----------+----------v | divsel_five | | divsel_ten |
39 | +----------+----------+ +----------+----------+
40 | | |
41 v v v
42 | +--------------------+ |
43 Input to MMSSCC block | | | |
44 for DP pixel clock +--> dp_link_2x_clk_mux <--+
45 | |
46 +----------+---------+
47 |
48 v
49 Input to MMSSCC block
50 for link clk, crypto clk
51 and interface clock
52
53
54 ******************************************************************************
55 */
56
57#define pr_fmt(fmt) "%s: " fmt, __func__
58
59#include <linux/kernel.h>
60#include <linux/err.h>
61#include <linux/delay.h>
62#include <linux/clk/msm-clk-provider.h>
63#include <linux/clk/msm-clk.h>
64#include <linux/clk/msm-clock-generic.h>
65#include <dt-bindings/clock/msm-clocks-8998.h>
66
67#include "mdss-pll.h"
68#include "mdss-dp-pll.h"
69#include "mdss-dp-pll-8998.h"
70
71static const struct clk_ops clk_ops_gen_mux_dp;
72static const struct clk_ops clk_ops_hsclk_divsel_clk_src_c;
73static const struct clk_ops clk_ops_vco_divided_clk_src_c;
74static const struct clk_ops clk_ops_link_2x_clk_div_c;
75
76static struct clk_div_ops hsclk_divsel_ops = {
77 .set_div = hsclk_divsel_set_div,
78 .get_div = hsclk_divsel_get_div,
79};
80
81static struct clk_div_ops link2xclk_divsel_ops = {
82 .set_div = link2xclk_divsel_set_div,
83 .get_div = link2xclk_divsel_get_div,
84};
85
86static struct clk_div_ops vco_divided_clk_ops = {
87 .set_div = vco_divided_clk_set_div,
88 .get_div = vco_divided_clk_get_div,
89};
90
91static const struct clk_ops dp_8998_vco_clk_ops = {
92 .set_rate = dp_vco_set_rate,
93 .round_rate = dp_vco_round_rate,
94 .prepare = dp_vco_prepare,
95 .unprepare = dp_vco_unprepare,
96 .handoff = dp_vco_handoff,
97};
98
99static struct clk_mux_ops mdss_mux_ops = {
100 .set_mux_sel = mdss_set_mux_sel,
101 .get_mux_sel = mdss_get_mux_sel,
102};
103
104static struct dp_pll_vco_clk dp_vco_clk = {
105 .min_rate = DP_VCO_RATE_8100MHz,
106 .max_rate = DP_VCO_RATE_10800MHz,
107 .c = {
108 .dbg_name = "dp_vco_clk",
109 .ops = &dp_8998_vco_clk_ops,
110 .flags = CLKFLAG_NO_RATE_CACHE,
111 CLK_INIT(dp_vco_clk.c),
112 },
113};
114
115static struct div_clk hsclk_divsel_clk_src = {
116 .data = {
117 .min_div = 2,
118 .max_div = 3,
119 },
120 .ops = &hsclk_divsel_ops,
121 .c = {
122 .parent = &dp_vco_clk.c,
123 .dbg_name = "hsclk_divsel_clk_src",
124 .ops = &clk_ops_hsclk_divsel_clk_src_c,
125 .flags = CLKFLAG_NO_RATE_CACHE,
126 CLK_INIT(hsclk_divsel_clk_src.c),
127 },
128};
129
130static struct div_clk dp_link_2x_clk_divsel_five = {
131 .data = {
132 .div = 5,
133 .min_div = 5,
134 .max_div = 5,
135 },
136 .ops = &link2xclk_divsel_ops,
137 .c = {
138 .parent = &hsclk_divsel_clk_src.c,
139 .dbg_name = "dp_link_2x_clk_divsel_five",
140 .ops = &clk_ops_link_2x_clk_div_c,
141 .flags = CLKFLAG_NO_RATE_CACHE,
142 CLK_INIT(dp_link_2x_clk_divsel_five.c),
143 },
144};
145
146static struct div_clk dp_link_2x_clk_divsel_ten = {
147 .data = {
148 .div = 10,
149 .min_div = 10,
150 .max_div = 10,
151 },
152 .ops = &link2xclk_divsel_ops,
153 .c = {
154 .parent = &hsclk_divsel_clk_src.c,
155 .dbg_name = "dp_link_2x_clk_divsel_ten",
156 .ops = &clk_ops_link_2x_clk_div_c,
157 .flags = CLKFLAG_NO_RATE_CACHE,
158 CLK_INIT(dp_link_2x_clk_divsel_ten.c),
159 },
160};
161
162static struct mux_clk dp_link_2x_clk_mux = {
163 .num_parents = 2,
164 .parents = (struct clk_src[]) {
165 {&dp_link_2x_clk_divsel_five.c, 0},
166 {&dp_link_2x_clk_divsel_ten.c, 1},
167 },
168 .ops = &mdss_mux_ops,
169 .c = {
170 .parent = &dp_link_2x_clk_divsel_five.c,
171 .dbg_name = "dp_link_2x_clk_mux",
172 .ops = &clk_ops_gen_mux_dp,
173 .flags = CLKFLAG_NO_RATE_CACHE,
174 CLK_INIT(dp_link_2x_clk_mux.c),
175 }
176};
177
178static struct div_clk vco_divided_clk_src = {
179 .data = {
180 .div = 4,
181 .min_div = 4,
182 .max_div = 4,
183 },
184 .ops = &vco_divided_clk_ops,
185 .c = {
186 .parent = &hsclk_divsel_clk_src.c,
187 .dbg_name = "vco_divided_clk",
188 .ops = &clk_ops_vco_divided_clk_src_c,
189 .flags = CLKFLAG_NO_RATE_CACHE,
190 CLK_INIT(vco_divided_clk_src.c),
191 },
192};
193
194static struct clk_lookup dp_pllcc_8998[] = {
195 CLK_LIST(dp_vco_clk),
196 CLK_LIST(hsclk_divsel_clk_src),
197 CLK_LIST(dp_link_2x_clk_divsel_five),
198 CLK_LIST(dp_link_2x_clk_divsel_ten),
199 CLK_LIST(dp_link_2x_clk_mux),
200 CLK_LIST(vco_divided_clk_src),
201};
202
203int dp_pll_clock_register_8998(struct platform_device *pdev,
204 struct mdss_pll_resources *pll_res)
205{
206 int rc = -ENOTSUPP;
207
208 if (!pll_res || !pll_res->pll_base || !pll_res->phy_base) {
209 DEV_ERR("%s: Invalid input parameters\n", __func__);
210 return -EINVAL;
211 }
212
213 /* Set client data for vco, mux and div clocks */
214 dp_vco_clk.priv = pll_res;
215 hsclk_divsel_clk_src.priv = pll_res;
216 dp_link_2x_clk_mux.priv = pll_res;
217 vco_divided_clk_src.priv = pll_res;
218 dp_link_2x_clk_divsel_five.priv = pll_res;
219 dp_link_2x_clk_divsel_ten.priv = pll_res;
220
221 clk_ops_gen_mux_dp = clk_ops_gen_mux;
222 clk_ops_gen_mux_dp.round_rate = parent_round_rate;
223 clk_ops_gen_mux_dp.set_rate = parent_set_rate;
224
225 clk_ops_hsclk_divsel_clk_src_c = clk_ops_div;
226 clk_ops_hsclk_divsel_clk_src_c.prepare = mdss_pll_div_prepare;
227
228 clk_ops_link_2x_clk_div_c = clk_ops_div;
229 clk_ops_link_2x_clk_div_c.prepare = mdss_pll_div_prepare;
230
231 /*
232 * Set the ops for the divider in the pixel clock tree to the
233 * slave_div to ensure that a set rate on this divider clock will not
234 * be propagated to it's parent. This is needed ensure that when we set
235 * the rate for pixel clock, the vco is not reconfigured
236 */
237 clk_ops_vco_divided_clk_src_c = clk_ops_slave_div;
238 clk_ops_vco_divided_clk_src_c.prepare = mdss_pll_div_prepare;
239
240 /* We can select different clock ops for future versions */
241 dp_vco_clk.c.ops = &dp_8998_vco_clk_ops;
242
243 rc = of_msm_clock_register(pdev->dev.of_node, dp_pllcc_8998,
244 ARRAY_SIZE(dp_pllcc_8998));
245 if (rc) {
246 DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc);
247 rc = -EPROBE_DEFER;
248 } else {
249 DEV_DBG("%s SUCCESS\n", __func__);
250 }
251
252 return rc;
253}