blob: 4496e9a0e6b59ae03324872bcbbaca4212533c6c [file] [log] [blame]
Ajay Singh Parmar72d57652017-03-25 17:24:07 -07001/*
2 * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
16
17#include "dp_panel.h"
18
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070019enum {
20 DP_LINK_RATE_MULTIPLIER = 27000000,
21};
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070022
23struct dp_panel_private {
24 struct device *dev;
25 struct dp_panel dp_panel;
26 struct dp_aux *aux;
27 struct dp_catalog_panel *catalog;
28};
29
30static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
31{
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070032 int rlen, rc = 0;
33 struct dp_panel_private *panel;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070034 struct drm_dp_link *dp_link;
35 u8 major = 0, minor = 0;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070036
37 if (!dp_panel) {
38 pr_err("invalid input\n");
39 rc = -EINVAL;
40 goto end;
41 }
42
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070043 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070044 dp_link = &dp_panel->dp_link;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070045
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070046 rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
47 dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
48 if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070049 pr_err("dpcd read failed, rlen=%d\n", rlen);
50 rc = -EINVAL;
51 goto end;
52 }
53
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070054 dp_link->revision = dp_panel->dpcd[DP_DPCD_REV];
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070055
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070056 major = (dp_link->revision >> 4) & 0x0f;
57 minor = dp_link->revision & 0x0f;
58 pr_debug("version: %d.%d\n", major, minor);
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070059
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070060 dp_link->rate =
61 drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]);
62 pr_debug("link_rate=%d\n", dp_link->rate);
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070063
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070064 dp_link->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] &
65 DP_MAX_LANE_COUNT_MASK;
66 pr_debug("lane_count=%d\n", dp_link->num_lanes);
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070067
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -070068 if (dp_panel->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)
69 dp_link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070070
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070071end:
72 return rc;
73}
74
Padmanabhan Komandurud5eae9d2017-06-22 19:23:36 +053075static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel)
76{
77 struct dp_panel_private *panel;
78 struct drm_dp_link *dp_link;
79 u32 bpc, bpp, max_data_rate_khz, max_pclk_rate_khz;
80 const u8 num_components = 3;
81
82 if (!dp_panel) {
83 pr_err("invalid input\n");
84 return 0;
85 }
86
87 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
88 dp_link = &dp_panel->dp_link;
89
90 bpc = sde_get_sink_bpc(dp_panel->edid_ctrl);
91 bpp = bpc * num_components;
92
93 max_data_rate_khz = (dp_link->num_lanes * dp_link->rate * 8);
94 max_pclk_rate_khz = max_data_rate_khz / bpp;
95
96 pr_debug("bpp=%d, max_lane_cnt=%d\n", bpp, dp_link->num_lanes);
97 pr_debug("max_data_rate=%dKHz, max_pclk_rate=%dKHz\n",
98 max_data_rate_khz, max_pclk_rate_khz);
99
100 return max_pclk_rate_khz;
101}
102
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700103static int dp_panel_timing_cfg(struct dp_panel *dp_panel)
104{
105 int rc = 0;
106 u32 data, total_ver, total_hor;
107 struct dp_catalog_panel *catalog;
108 struct dp_panel_private *panel;
109 struct dp_panel_info *pinfo;
110
111 if (!dp_panel) {
112 pr_err("invalid input\n");
113 rc = -EINVAL;
114 goto end;
115 }
116
117 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
118 catalog = panel->catalog;
119 pinfo = &panel->dp_panel.pinfo;
120
121 pr_debug("width=%d hporch= %d %d %d\n",
122 pinfo->h_active, pinfo->h_back_porch,
123 pinfo->h_front_porch, pinfo->h_sync_width);
124
125 pr_debug("height=%d vporch= %d %d %d\n",
126 pinfo->v_active, pinfo->v_back_porch,
127 pinfo->v_front_porch, pinfo->v_sync_width);
128
129 total_hor = pinfo->h_active + pinfo->h_back_porch +
130 pinfo->h_front_porch + pinfo->h_sync_width;
131
132 total_ver = pinfo->v_active + pinfo->v_back_porch +
133 pinfo->v_front_porch + pinfo->v_sync_width;
134
135 data = total_ver;
136 data <<= 16;
137 data |= total_hor;
138
139 catalog->total = data;
140
141 data = (pinfo->v_back_porch + pinfo->v_sync_width);
142 data <<= 16;
143 data |= (pinfo->h_back_porch + pinfo->h_sync_width);
144
145 catalog->sync_start = data;
146
147 data = pinfo->v_sync_width;
148 data <<= 16;
149 data |= (pinfo->v_active_low << 31);
150 data |= pinfo->h_sync_width;
151 data |= (pinfo->h_active_low << 15);
152
153 catalog->width_blanking = data;
154
155 data = pinfo->v_active;
156 data <<= 16;
157 data |= pinfo->h_active;
158
159 catalog->dp_active = data;
160
161 panel->catalog->timing_cfg(catalog);
162end:
163 return rc;
164}
165
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700166static int dp_panel_edid_register(struct dp_panel *dp_panel)
167{
168 int rc = 0;
169
170 if (!dp_panel) {
171 pr_err("invalid input\n");
172 rc = -EINVAL;
173 goto end;
174 }
175
176 dp_panel->edid_ctrl = sde_edid_init();
177 if (!dp_panel->edid_ctrl) {
178 pr_err("sde edid init for DP failed\n");
179 rc = -ENOMEM;
180 goto end;
181 }
182end:
183 return rc;
184}
185
186static void dp_panel_edid_deregister(struct dp_panel *dp_panel)
187{
188 if (!dp_panel) {
189 pr_err("invalid input\n");
190 return;
191 }
192
193 sde_edid_deinit((void **)&dp_panel->edid_ctrl);
194}
195
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700196static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
197{
198 int rc = 0;
199 struct dp_panel_private *panel;
200
201 if (!dp_panel) {
202 pr_err("invalid input\n");
203 rc = -EINVAL;
204 goto end;
205 }
206
207 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
208end:
209 return rc;
210}
211
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700212static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700213{
214 const u32 encoding_factx10 = 8;
215 const u32 ln_to_link_ratio = 10;
216 u32 min_link_rate, reminder = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700217 u32 calc_link_rate = 0, lane_cnt, max_rate = 0;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700218 struct dp_panel_private *panel;
219 struct dp_panel_info *pinfo;
220
221 if (!dp_panel) {
222 pr_err("invalid input\n");
223 goto end;
224 }
225
226 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
227
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700228 lane_cnt = dp_panel->dp_link.num_lanes;
229 max_rate = drm_dp_link_rate_to_bw_code(dp_panel->dp_link.rate);
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700230 pinfo = &dp_panel->pinfo;
231
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700232 /*
233 * The max pixel clock supported is 675Mhz. The
234 * current calculations below will make sure
235 * the min_link_rate is within 32 bit limits.
236 * Any changes in the section of code should
237 * consider this limitation.
238 */
239 min_link_rate = (u32)div_u64(pinfo->pixel_clk_khz * 1000,
240 (lane_cnt * encoding_factx10));
241 min_link_rate /= ln_to_link_ratio;
242 min_link_rate = (min_link_rate * pinfo->bpp);
243 min_link_rate = (u32)div_u64_rem(min_link_rate * 10,
244 DP_LINK_RATE_MULTIPLIER, &reminder);
245
246 /*
247 * To avoid any fractional values,
248 * increment the min_link_rate
249 */
250 if (reminder)
251 min_link_rate += 1;
252 pr_debug("min_link_rate = %d\n", min_link_rate);
253
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700254 if (min_link_rate <= DP_LINK_BW_1_62)
255 calc_link_rate = DP_LINK_BW_1_62;
256 else if (min_link_rate <= DP_LINK_BW_2_7)
257 calc_link_rate = DP_LINK_BW_2_7;
258 else if (min_link_rate <= DP_LINK_BW_5_4)
259 calc_link_rate = DP_LINK_BW_5_4;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700260 else if (min_link_rate <= DP_LINK_RATE_810)
261 calc_link_rate = DP_LINK_RATE_810;
262 else {
263 /* Cap the link rate to the max supported rate */
264 pr_debug("link_rate = %d is unsupported\n", min_link_rate);
265 calc_link_rate = DP_LINK_RATE_810;
266 }
267
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700268 if (calc_link_rate > max_rate)
269 calc_link_rate = max_rate;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700270
271 pr_debug("calc_link_rate = 0x%x\n", calc_link_rate);
272end:
273 return calc_link_rate;
274}
275
276struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
277 struct dp_catalog_panel *catalog)
278{
279 int rc = 0;
280 struct dp_panel_private *panel;
281 struct dp_panel *dp_panel;
282
283 if (!dev || !aux || !catalog) {
284 pr_err("invalid input\n");
285 rc = -EINVAL;
286 goto error;
287 }
288
289 panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
290 if (!panel) {
291 rc = -ENOMEM;
292 goto error;
293 }
294
295 panel->dev = dev;
296 panel->aux = aux;
297 panel->catalog = catalog;
298
299 dp_panel = &panel->dp_panel;
300
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700301 dp_panel->sde_edid_register = dp_panel_edid_register;
302 dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700303 dp_panel->init_info = dp_panel_init_panel_info;
304 dp_panel->timing_cfg = dp_panel_timing_cfg;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700305 dp_panel->read_dpcd = dp_panel_read_dpcd;
306 dp_panel->get_link_rate = dp_panel_get_link_rate;
Padmanabhan Komandurud5eae9d2017-06-22 19:23:36 +0530307 dp_panel->get_max_pclk = dp_panel_get_max_pclk;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700308
309 return dp_panel;
310error:
311 return ERR_PTR(rc);
312}
313
314void dp_panel_put(struct dp_panel *dp_panel)
315{
316 struct dp_panel_private *panel;
317
318 if (!dp_panel)
319 return;
320
321 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
322
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700323 devm_kfree(panel->dev, panel);
324}