blob: 976a3451e4a2ddef3c0f0e2fb7ab51ceb91de636 [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
Ajay Singh Parmar72d57652017-03-25 17:24:07 -070075static int dp_panel_timing_cfg(struct dp_panel *dp_panel)
76{
77 int rc = 0;
78 u32 data, total_ver, total_hor;
79 struct dp_catalog_panel *catalog;
80 struct dp_panel_private *panel;
81 struct dp_panel_info *pinfo;
82
83 if (!dp_panel) {
84 pr_err("invalid input\n");
85 rc = -EINVAL;
86 goto end;
87 }
88
89 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
90 catalog = panel->catalog;
91 pinfo = &panel->dp_panel.pinfo;
92
93 pr_debug("width=%d hporch= %d %d %d\n",
94 pinfo->h_active, pinfo->h_back_porch,
95 pinfo->h_front_porch, pinfo->h_sync_width);
96
97 pr_debug("height=%d vporch= %d %d %d\n",
98 pinfo->v_active, pinfo->v_back_porch,
99 pinfo->v_front_porch, pinfo->v_sync_width);
100
101 total_hor = pinfo->h_active + pinfo->h_back_porch +
102 pinfo->h_front_porch + pinfo->h_sync_width;
103
104 total_ver = pinfo->v_active + pinfo->v_back_porch +
105 pinfo->v_front_porch + pinfo->v_sync_width;
106
107 data = total_ver;
108 data <<= 16;
109 data |= total_hor;
110
111 catalog->total = data;
112
113 data = (pinfo->v_back_porch + pinfo->v_sync_width);
114 data <<= 16;
115 data |= (pinfo->h_back_porch + pinfo->h_sync_width);
116
117 catalog->sync_start = data;
118
119 data = pinfo->v_sync_width;
120 data <<= 16;
121 data |= (pinfo->v_active_low << 31);
122 data |= pinfo->h_sync_width;
123 data |= (pinfo->h_active_low << 15);
124
125 catalog->width_blanking = data;
126
127 data = pinfo->v_active;
128 data <<= 16;
129 data |= pinfo->h_active;
130
131 catalog->dp_active = data;
132
133 panel->catalog->timing_cfg(catalog);
134end:
135 return rc;
136}
137
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700138static int dp_panel_edid_register(struct dp_panel *dp_panel)
139{
140 int rc = 0;
141
142 if (!dp_panel) {
143 pr_err("invalid input\n");
144 rc = -EINVAL;
145 goto end;
146 }
147
148 dp_panel->edid_ctrl = sde_edid_init();
149 if (!dp_panel->edid_ctrl) {
150 pr_err("sde edid init for DP failed\n");
151 rc = -ENOMEM;
152 goto end;
153 }
154end:
155 return rc;
156}
157
158static void dp_panel_edid_deregister(struct dp_panel *dp_panel)
159{
160 if (!dp_panel) {
161 pr_err("invalid input\n");
162 return;
163 }
164
165 sde_edid_deinit((void **)&dp_panel->edid_ctrl);
166}
167
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700168static int dp_panel_init_panel_info(struct dp_panel *dp_panel)
169{
170 int rc = 0;
171 struct dp_panel_private *panel;
172
173 if (!dp_panel) {
174 pr_err("invalid input\n");
175 rc = -EINVAL;
176 goto end;
177 }
178
179 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
180end:
181 return rc;
182}
183
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700184static u32 dp_panel_get_link_rate(struct dp_panel *dp_panel)
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700185{
186 const u32 encoding_factx10 = 8;
187 const u32 ln_to_link_ratio = 10;
188 u32 min_link_rate, reminder = 0;
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700189 u32 calc_link_rate = 0, lane_cnt, max_rate = 0;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700190 struct dp_panel_private *panel;
191 struct dp_panel_info *pinfo;
192
193 if (!dp_panel) {
194 pr_err("invalid input\n");
195 goto end;
196 }
197
198 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
199
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700200 lane_cnt = dp_panel->dp_link.num_lanes;
201 max_rate = drm_dp_link_rate_to_bw_code(dp_panel->dp_link.rate);
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700202 pinfo = &dp_panel->pinfo;
203
204 pinfo->bpp = 24;
205
206 /*
207 * The max pixel clock supported is 675Mhz. The
208 * current calculations below will make sure
209 * the min_link_rate is within 32 bit limits.
210 * Any changes in the section of code should
211 * consider this limitation.
212 */
213 min_link_rate = (u32)div_u64(pinfo->pixel_clk_khz * 1000,
214 (lane_cnt * encoding_factx10));
215 min_link_rate /= ln_to_link_ratio;
216 min_link_rate = (min_link_rate * pinfo->bpp);
217 min_link_rate = (u32)div_u64_rem(min_link_rate * 10,
218 DP_LINK_RATE_MULTIPLIER, &reminder);
219
220 /*
221 * To avoid any fractional values,
222 * increment the min_link_rate
223 */
224 if (reminder)
225 min_link_rate += 1;
226 pr_debug("min_link_rate = %d\n", min_link_rate);
227
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700228 if (min_link_rate <= DP_LINK_BW_1_62)
229 calc_link_rate = DP_LINK_BW_1_62;
230 else if (min_link_rate <= DP_LINK_BW_2_7)
231 calc_link_rate = DP_LINK_BW_2_7;
232 else if (min_link_rate <= DP_LINK_BW_5_4)
233 calc_link_rate = DP_LINK_BW_5_4;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700234 else if (min_link_rate <= DP_LINK_RATE_810)
235 calc_link_rate = DP_LINK_RATE_810;
236 else {
237 /* Cap the link rate to the max supported rate */
238 pr_debug("link_rate = %d is unsupported\n", min_link_rate);
239 calc_link_rate = DP_LINK_RATE_810;
240 }
241
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700242 if (calc_link_rate > max_rate)
243 calc_link_rate = max_rate;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700244
245 pr_debug("calc_link_rate = 0x%x\n", calc_link_rate);
246end:
247 return calc_link_rate;
248}
249
250struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
251 struct dp_catalog_panel *catalog)
252{
253 int rc = 0;
254 struct dp_panel_private *panel;
255 struct dp_panel *dp_panel;
256
257 if (!dev || !aux || !catalog) {
258 pr_err("invalid input\n");
259 rc = -EINVAL;
260 goto error;
261 }
262
263 panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
264 if (!panel) {
265 rc = -ENOMEM;
266 goto error;
267 }
268
269 panel->dev = dev;
270 panel->aux = aux;
271 panel->catalog = catalog;
272
273 dp_panel = &panel->dp_panel;
274
Padmanabhan Komandurud84b38b2017-05-24 04:24:57 -0700275 dp_panel->sde_edid_register = dp_panel_edid_register;
276 dp_panel->sde_edid_deregister = dp_panel_edid_deregister;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700277 dp_panel->init_info = dp_panel_init_panel_info;
278 dp_panel->timing_cfg = dp_panel_timing_cfg;
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700279 dp_panel->read_dpcd = dp_panel_read_dpcd;
280 dp_panel->get_link_rate = dp_panel_get_link_rate;
281
282 return dp_panel;
283error:
284 return ERR_PTR(rc);
285}
286
287void dp_panel_put(struct dp_panel *dp_panel)
288{
289 struct dp_panel_private *panel;
290
291 if (!dp_panel)
292 return;
293
294 panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
295
Ajay Singh Parmar72d57652017-03-25 17:24:07 -0700296 devm_kfree(panel->dev, panel);
297}