blob: cfb443672723d3e721f486f545a98def21a62591 [file] [log] [blame]
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001/*
2 * Copyright (c) 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 <linux/delay.h>
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -070018#include <drm/drm_dp_helper.h>
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070019
20#include "dp_catalog.h"
Tatenda Chipeperekwa2eb6fa52017-07-12 13:42:11 -070021#include "dp_reg.h"
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070022
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -070023#define DP_GET_MSB(x) (x >> 8)
24#define DP_GET_LSB(x) (x & 0xff)
25
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070026#define dp_read(offset) readl_relaxed((offset))
27#define dp_write(offset, data) writel_relaxed((data), (offset))
28
29#define dp_catalog_get_priv(x) { \
30 struct dp_catalog *dp_catalog; \
31 dp_catalog = container_of(x, struct dp_catalog, x); \
32 catalog = container_of(dp_catalog, struct dp_catalog_private, \
33 dp_catalog); \
34}
35
36#define DP_INTERRUPT_STATUS1 \
37 (DP_INTR_AUX_I2C_DONE| \
38 DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \
39 DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \
40 DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \
41 DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR)
42
43#define DP_INTR_MASK1 (DP_INTERRUPT_STATUS1 << 2)
44
45#define DP_INTERRUPT_STATUS2 \
46 (DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \
47 DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED)
48
49#define DP_INTR_MASK2 (DP_INTERRUPT_STATUS2 << 2)
50
51static u8 const vm_pre_emphasis[4][4] = {
52 {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */
53 {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */
54 {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */
55 {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
56};
57
58/* voltage swing, 0.2v and 1.0v are not support */
59static u8 const vm_voltage_swing[4][4] = {
60 {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */
61 {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */
62 {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
63 {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
64};
65
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -070066/* audio related catalog functions */
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070067struct dp_catalog_private {
68 struct device *dev;
69 struct dp_io *io;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -070070
71 u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX];
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070072 struct dp_catalog dp_catalog;
73};
74
75/* aux related catalog functions */
76static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux)
77{
78 struct dp_catalog_private *catalog;
79 void __iomem *base;
80
81 if (!aux) {
82 pr_err("invalid input\n");
83 goto end;
84 }
85
86 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -070087 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -070088
89 return dp_read(base + DP_AUX_DATA);
90end:
91 return 0;
92}
93
94static int dp_catalog_aux_write_data(struct dp_catalog_aux *aux)
95{
96 int rc = 0;
97 struct dp_catalog_private *catalog;
98 void __iomem *base;
99
100 if (!aux) {
101 pr_err("invalid input\n");
102 rc = -EINVAL;
103 goto end;
104 }
105
106 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700107 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700108
109 dp_write(base + DP_AUX_DATA, aux->data);
110end:
111 return rc;
112}
113
114static int dp_catalog_aux_write_trans(struct dp_catalog_aux *aux)
115{
116 int rc = 0;
117 struct dp_catalog_private *catalog;
118 void __iomem *base;
119
120 if (!aux) {
121 pr_err("invalid input\n");
122 rc = -EINVAL;
123 goto end;
124 }
125
126 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700127 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700128
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700129 dp_write(base + DP_AUX_TRANS_CTRL, aux->data);
130end:
131 return rc;
132}
133
Tatenda Chipeperekwa1a43e702017-09-15 15:45:16 -0700134static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read)
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800135{
136 int rc = 0;
Tatenda Chipeperekwa1a43e702017-09-15 15:45:16 -0700137 u32 data = 0;
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800138 struct dp_catalog_private *catalog;
139 void __iomem *base;
140
141 if (!aux) {
142 pr_err("invalid input\n");
143 rc = -EINVAL;
144 goto end;
145 }
146
147 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700148 base = catalog->io->dp_aux.base;
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800149
Tatenda Chipeperekwa1a43e702017-09-15 15:45:16 -0700150 if (read) {
151 data = dp_read(base + DP_AUX_TRANS_CTRL);
152 data &= ~BIT(9);
153 dp_write(base + DP_AUX_TRANS_CTRL, data);
154 } else {
155 dp_write(base + DP_AUX_TRANS_CTRL, 0);
156 }
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800157end:
158 return rc;
159}
160
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +0530161static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux)
162{
163 struct dp_catalog_private *catalog;
164 void __iomem *phy_base;
165 u32 data = 0;
166
167 if (!aux) {
168 pr_err("invalid input\n");
169 return;
170 }
171
172 dp_catalog_get_priv(aux);
173 phy_base = catalog->io->phy_io.base;
174
175 data = dp_read(phy_base + DP_PHY_AUX_INTERRUPT_STATUS);
176 pr_debug("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data);
177
178 dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
179 wmb(); /* make sure 0x1f is written before next write */
180 dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f);
181 wmb(); /* make sure 0x9f is written before next write */
182 dp_write(phy_base + DP_PHY_AUX_INTERRUPT_CLEAR, 0);
183 wmb(); /* make sure register is cleared */
184}
185
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700186static void dp_catalog_aux_reset(struct dp_catalog_aux *aux)
187{
188 u32 aux_ctrl;
189 struct dp_catalog_private *catalog;
190 void __iomem *base;
191
192 if (!aux) {
193 pr_err("invalid input\n");
194 return;
195 }
196
197 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700198 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700199
200 aux_ctrl = dp_read(base + DP_AUX_CTRL);
201
202 aux_ctrl |= BIT(1);
203 dp_write(base + DP_AUX_CTRL, aux_ctrl);
204 usleep_range(1000, 1010); /* h/w recommended delay */
205
206 aux_ctrl &= ~BIT(1);
207 dp_write(base + DP_AUX_CTRL, aux_ctrl);
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +0530208 wmb(); /* make sure AUX reset is done here */
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700209}
210
211static void dp_catalog_aux_enable(struct dp_catalog_aux *aux, bool enable)
212{
213 u32 aux_ctrl;
214 struct dp_catalog_private *catalog;
215 void __iomem *base;
216
217 if (!aux) {
218 pr_err("invalid input\n");
219 return;
220 }
221
222 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700223 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700224
225 aux_ctrl = dp_read(base + DP_AUX_CTRL);
226
227 if (enable) {
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +0530228 aux_ctrl |= BIT(0);
229 dp_write(base + DP_AUX_CTRL, aux_ctrl);
230 wmb(); /* make sure AUX module is enabled */
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700231 dp_write(base + DP_TIMEOUT_COUNT, 0xffff);
232 dp_write(base + DP_AUX_LIMITS, 0xffff);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700233 } else {
234 aux_ctrl &= ~BIT(0);
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +0530235 dp_write(base + DP_AUX_CTRL, aux_ctrl);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700236 }
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700237}
238
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530239static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
240 struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700241{
242 struct dp_catalog_private *catalog;
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530243 u32 new_index = 0, current_index = 0;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700244
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +0530245 if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) {
246 pr_err("invalid input\n");
247 return;
248 }
249
250 dp_catalog_get_priv(aux);
251
252 current_index = cfg[type].current_index;
253 new_index = (current_index + 1) % cfg[type].cfg_cnt;
254 pr_debug("Updating %s from 0x%08x to 0x%08x\n",
255 dp_phy_aux_config_type_to_string(type),
256 cfg[type].lut[current_index], cfg[type].lut[new_index]);
257
258 dp_write(catalog->io->phy_io.base + cfg[type].offset,
259 cfg[type].lut[new_index]);
260 cfg[type].current_index = new_index;
261}
262
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530263static void dp_catalog_aux_setup(struct dp_catalog_aux *aux,
264 struct dp_aux_cfg *cfg)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700265{
266 struct dp_catalog_private *catalog;
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530267 int i = 0;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700268
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530269 if (!aux || !cfg) {
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700270 pr_err("invalid input\n");
271 return;
272 }
273
274 dp_catalog_get_priv(aux);
275
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800276 dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700277 wmb(); /* make sure PD programming happened */
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700278
279 /* Turn on BIAS current for PHY/PLL */
280 dp_write(catalog->io->dp_pll_io.base +
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -0800281 QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700282
283 /* DP AUX CFG register programming */
Padmanabhan Komanduru20a21db2017-07-10 16:58:59 +0530284 for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
285 pr_debug("%s: offset=0x%08x, value=0x%08x\n",
286 dp_phy_aux_config_type_to_string(i),
287 cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
288 dp_write(catalog->io->phy_io.base + cfg[i].offset,
289 cfg[i].lut[cfg[i].current_index]);
290 }
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700291
292 dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F);
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +0530293 wmb(); /* make sure AUX configuration is done before enabling it */
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700294}
295
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700296static void dp_catalog_aux_get_irq(struct dp_catalog_aux *aux, bool cmd_busy)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700297{
298 u32 ack;
299 struct dp_catalog_private *catalog;
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700300 void __iomem *ahb_base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700301
302 if (!aux) {
303 pr_err("invalid input\n");
304 return;
305 }
306
307 dp_catalog_get_priv(aux);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700308 ahb_base = catalog->io->dp_ahb.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700309
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700310 aux->isr = dp_read(ahb_base + DP_INTR_STATUS);
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700311 aux->isr &= ~DP_INTR_MASK1;
312 ack = aux->isr & DP_INTERRUPT_STATUS1;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700313 ack <<= 1;
314 ack |= DP_INTR_MASK1;
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700315 dp_write(ahb_base + DP_INTR_STATUS, ack);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700316}
317
318/* controller related catalog functions */
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700319static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl)
320{
321 struct dp_catalog_private *catalog;
322 void __iomem *base;
323
324 if (!ctrl) {
325 pr_err("invalid input\n");
326 return -EINVAL;
327 }
328
329 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700330 base = catalog->io->dp_ahb.base;
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -0700331
332 return dp_read(base + DP_HDCP_STATUS);
333}
334
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700335static void dp_catalog_panel_setup_infoframe_sdp(struct dp_catalog_panel *panel)
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700336{
337 struct dp_catalog_private *catalog;
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700338 struct drm_msm_ext_hdr_metadata *hdr;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700339 void __iomem *base;
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700340 u32 header, parity, data;
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800341 u8 buf[SZ_128], off = 0;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700342
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700343 if (!panel) {
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700344 pr_err("invalid input\n");
345 return;
346 }
347
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700348 dp_catalog_get_priv(panel);
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700349 hdr = &panel->hdr_data.hdr_meta;
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700350 base = catalog->io->dp_link.base;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700351
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700352 /* HEADER BYTE 1 */
353 header = panel->hdr_data.vscext_header_byte1;
354 parity = dp_header_get_parity(header);
355 data = ((header << HEADER_BYTE_1_BIT)
356 | (parity << PARITY_BYTE_1_BIT));
357 dp_write(base + MMSS_DP_VSCEXT_0, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800358 memcpy(buf + off, &data, sizeof(data));
359 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700360
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700361 /* HEADER BYTE 2 */
362 header = panel->hdr_data.vscext_header_byte2;
363 parity = dp_header_get_parity(header);
364 data = ((header << HEADER_BYTE_2_BIT)
365 | (parity << PARITY_BYTE_2_BIT));
366 dp_write(base + MMSS_DP_VSCEXT_1, data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700367
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700368 /* HEADER BYTE 3 */
369 header = panel->hdr_data.vscext_header_byte3;
370 parity = dp_header_get_parity(header);
371 data = ((header << HEADER_BYTE_3_BIT)
372 | (parity << PARITY_BYTE_3_BIT));
373 data |= dp_read(base + MMSS_DP_VSCEXT_1);
374 dp_write(base + MMSS_DP_VSCEXT_1, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800375 memcpy(buf + off, &data, sizeof(data));
376 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700377
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700378 data = panel->hdr_data.version;
379 data |= panel->hdr_data.length << 8;
380 data |= hdr->eotf << 16;
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700381 dp_write(base + MMSS_DP_VSCEXT_2, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800382 memcpy(buf + off, &data, sizeof(data));
383 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700384
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700385 data = (DP_GET_LSB(hdr->display_primaries_x[0]) |
386 (DP_GET_MSB(hdr->display_primaries_x[0]) << 8) |
387 (DP_GET_LSB(hdr->display_primaries_y[0]) << 16) |
388 (DP_GET_MSB(hdr->display_primaries_y[0]) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700389 dp_write(base + MMSS_DP_VSCEXT_3, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800390 memcpy(buf + off, &data, sizeof(data));
391 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700392
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700393 data = (DP_GET_LSB(hdr->display_primaries_x[1]) |
394 (DP_GET_MSB(hdr->display_primaries_x[1]) << 8) |
395 (DP_GET_LSB(hdr->display_primaries_y[1]) << 16) |
396 (DP_GET_MSB(hdr->display_primaries_y[1]) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700397 dp_write(base + MMSS_DP_VSCEXT_4, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800398 memcpy(buf + off, &data, sizeof(data));
399 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700400
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700401 data = (DP_GET_LSB(hdr->display_primaries_x[2]) |
402 (DP_GET_MSB(hdr->display_primaries_x[2]) << 8) |
403 (DP_GET_LSB(hdr->display_primaries_y[2]) << 16) |
404 (DP_GET_MSB(hdr->display_primaries_y[2]) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700405 dp_write(base + MMSS_DP_VSCEXT_5, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800406 memcpy(buf + off, &data, sizeof(data));
407 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700408
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700409 data = (DP_GET_LSB(hdr->white_point_x) |
410 (DP_GET_MSB(hdr->white_point_x) << 8) |
411 (DP_GET_LSB(hdr->white_point_y) << 16) |
412 (DP_GET_MSB(hdr->white_point_y) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700413 dp_write(base + MMSS_DP_VSCEXT_6, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800414 memcpy(buf + off, &data, sizeof(data));
415 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700416
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700417 data = (DP_GET_LSB(hdr->max_luminance) |
418 (DP_GET_MSB(hdr->max_luminance) << 8) |
419 (DP_GET_LSB(hdr->min_luminance) << 16) |
420 (DP_GET_MSB(hdr->min_luminance) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700421 dp_write(base + MMSS_DP_VSCEXT_7, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800422 memcpy(buf + off, &data, sizeof(data));
423 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700424
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700425 data = (DP_GET_LSB(hdr->max_content_light_level) |
426 (DP_GET_MSB(hdr->max_content_light_level) << 8) |
427 (DP_GET_LSB(hdr->max_average_light_level) << 16) |
428 (DP_GET_MSB(hdr->max_average_light_level) << 24));
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700429 dp_write(base + MMSS_DP_VSCEXT_8, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800430 memcpy(buf + off, &data, sizeof(data));
431 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700432
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800433 data = 0;
434 dp_write(base + MMSS_DP_VSCEXT_9, data);
435 memcpy(buf + off, &data, sizeof(data));
436 off += sizeof(data);
437
438 print_hex_dump(KERN_DEBUG, "[drm-dp] VSCEXT: ",
439 DUMP_PREFIX_NONE, 16, 4, buf, off, false);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700440}
441
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800442static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel)
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700443{
444 struct dp_catalog_private *catalog;
445 void __iomem *base;
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700446 u32 header, parity, data;
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800447 u8 bpc, off = 0;
448 u8 buf[SZ_128];
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700449
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700450 if (!panel) {
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700451 pr_err("invalid input\n");
452 return;
453 }
454
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700455 dp_catalog_get_priv(panel);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700456 base = catalog->io->dp_link.base;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700457
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700458 /* HEADER BYTE 1 */
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700459 header = panel->hdr_data.vsc_header_byte1;
460 parity = dp_header_get_parity(header);
461 data = ((header << HEADER_BYTE_1_BIT)
462 | (parity << PARITY_BYTE_1_BIT));
463 dp_write(base + MMSS_DP_GENERIC0_0, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800464 memcpy(buf + off, &data, sizeof(data));
465 off += sizeof(data);
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700466
467 /* HEADER BYTE 2 */
468 header = panel->hdr_data.vsc_header_byte2;
469 parity = dp_header_get_parity(header);
470 data = ((header << HEADER_BYTE_2_BIT)
471 | (parity << PARITY_BYTE_2_BIT));
472 dp_write(base + MMSS_DP_GENERIC0_1, data);
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700473
474 /* HEADER BYTE 3 */
475 header = panel->hdr_data.vsc_header_byte3;
476 parity = dp_header_get_parity(header);
477 data = ((header << HEADER_BYTE_3_BIT)
478 | (parity << PARITY_BYTE_3_BIT));
479 data |= dp_read(base + MMSS_DP_GENERIC0_1);
480 dp_write(base + MMSS_DP_GENERIC0_1, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800481 memcpy(buf + off, &data, sizeof(data));
482 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700483
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800484 data = 0;
485 dp_write(base + MMSS_DP_GENERIC0_2, data);
486 memcpy(buf + off, &data, sizeof(data));
487 off += sizeof(data);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700488
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800489 dp_write(base + MMSS_DP_GENERIC0_3, data);
490 memcpy(buf + off, &data, sizeof(data));
491 off += sizeof(data);
492
493 dp_write(base + MMSS_DP_GENERIC0_4, data);
494 memcpy(buf + off, &data, sizeof(data));
495 off += sizeof(data);
496
497 dp_write(base + MMSS_DP_GENERIC0_5, data);
498 memcpy(buf + off, &data, sizeof(data));
499 off += sizeof(data);
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700500
501 switch (panel->hdr_data.bpc) {
502 default:
503 case 10:
504 bpc = BIT(1);
505 break;
506 case 8:
507 bpc = BIT(0);
508 break;
509 case 6:
510 bpc = 0;
511 break;
512 }
513
514 data = (panel->hdr_data.colorimetry & 0xF) |
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700515 ((panel->hdr_data.pixel_encoding & 0xF) << 4) |
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700516 (bpc << 8) |
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700517 ((panel->hdr_data.dynamic_range & 0x1) << 15) |
518 ((panel->hdr_data.content_type & 0x7) << 16);
519
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700520 dp_write(base + MMSS_DP_GENERIC0_6, data);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800521 memcpy(buf + off, &data, sizeof(data));
522 off += sizeof(data);
523
524 data = 0;
525 dp_write(base + MMSS_DP_GENERIC0_7, data);
526 memcpy(buf + off, &data, sizeof(data));
527 off += sizeof(data);
528
529 dp_write(base + MMSS_DP_GENERIC0_8, data);
530 memcpy(buf + off, &data, sizeof(data));
531 off += sizeof(data);
532
533 dp_write(base + MMSS_DP_GENERIC0_9, data);
534 memcpy(buf + off, &data, sizeof(data));
535 off += sizeof(data);
536
537 print_hex_dump(KERN_DEBUG, "[drm-dp] VSC: ",
538 DUMP_PREFIX_NONE, 16, 4, buf, off, false);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700539}
540
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800541static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en)
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700542{
543 struct dp_catalog_private *catalog;
544 void __iomem *base;
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800545 u32 cfg, cfg2, misc;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700546
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700547 if (!panel) {
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700548 pr_err("invalid input\n");
549 return;
550 }
551
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -0700552 dp_catalog_get_priv(panel);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700553 base = catalog->io->dp_link.base;
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700554
555 cfg = dp_read(base + MMSS_DP_SDP_CFG);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700556 cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800557 misc = dp_read(base + DP_MISC1_MISC0);
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700558
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800559 if (en) {
560 /* VSCEXT_SDP_EN, GEN0_SDP_EN */
561 cfg |= BIT(16) | BIT(17);
562 dp_write(base + MMSS_DP_SDP_CFG, cfg);
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700563
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800564 /* EXTN_SDPSIZE GENERIC0_SDPSIZE */
565 cfg2 |= BIT(15) | BIT(16);
566 dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700567
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800568 dp_catalog_panel_setup_vsc_sdp(panel);
569 dp_catalog_panel_setup_infoframe_sdp(panel);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700570
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800571 /* indicates presence of VSC (BIT(6) of MISC1) */
572 misc |= BIT(14);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700573
Ajay Singh Parmar973cab12017-11-15 15:33:33 -0800574 if (panel->hdr_data.hdr_meta.eotf)
575 pr_debug("Enabled\n");
576 else
577 pr_debug("Reset\n");
578 } else {
579 /* VSCEXT_SDP_EN, GEN0_SDP_EN */
580 cfg &= ~BIT(16) & ~BIT(17);
581 dp_write(base + MMSS_DP_SDP_CFG, cfg);
582
583 /* EXTN_SDPSIZE GENERIC0_SDPSIZE */
584 cfg2 &= ~BIT(15) & ~BIT(16);
585 dp_write(base + MMSS_DP_SDP_CFG2, cfg2);
586
587 /* switch back to MSA */
588 misc &= ~BIT(14);
589
590 pr_debug("Disabled\n");
591 }
592
593 dp_write(base + DP_MISC1_MISC0, misc);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700594
Ajay Singh Parmar7e724362017-11-05 00:06:30 -0700595 dp_write(base + MMSS_DP_SDP_CFG3, 0x01);
596 dp_write(base + MMSS_DP_SDP_CFG3, 0x00);
Ajay Singh Parmar059d0e02017-09-13 11:37:40 -0700597}
598
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700599static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl)
600{
601 struct dp_catalog_private *catalog;
602 void __iomem *base;
603
604 if (!ctrl) {
605 pr_err("invalid input\n");
606 return;
607 }
608
609 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700610 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700611
612 dp_write(base + DP_VALID_BOUNDARY, ctrl->valid_boundary);
613 dp_write(base + DP_TU, ctrl->dp_tu);
614 dp_write(base + DP_VALID_BOUNDARY_2, ctrl->valid_boundary2);
615}
616
617static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state)
618{
619 struct dp_catalog_private *catalog;
620 void __iomem *base;
621
622 if (!ctrl) {
623 pr_err("invalid input\n");
624 return;
625 }
626
627 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700628 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700629
630 dp_write(base + DP_STATE_CTRL, state);
631}
632
633static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg)
634{
635 struct dp_catalog_private *catalog;
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700636 void __iomem *link_base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700637
638 if (!ctrl) {
639 pr_err("invalid input\n");
640 return;
641 }
642
643 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700644 link_base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700645
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700646 pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg);
647
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700648 dp_write(link_base + DP_CONFIGURATION_CTRL, cfg);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700649}
650
651static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl)
652{
653 struct dp_catalog_private *catalog;
654 void __iomem *base;
655
656 if (!ctrl) {
657 pr_err("invalid input\n");
658 return;
659 }
660
661 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700662 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700663
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700664 dp_write(base + DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700665}
666
667static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
668 bool enable)
669{
670 u32 mainlink_ctrl;
671 struct dp_catalog_private *catalog;
672 void __iomem *base;
673
674 if (!ctrl) {
675 pr_err("invalid input\n");
676 return;
677 }
678
679 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700680 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700681
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700682 if (enable) {
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700683 dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
684 wmb(); /* make sure mainlink is turned off before reset */
685 dp_write(base + DP_MAINLINK_CTRL, 0x02000002);
686 wmb(); /* make sure mainlink entered reset */
687 dp_write(base + DP_MAINLINK_CTRL, 0x02000000);
688 wmb(); /* make sure mainlink reset done */
689 dp_write(base + DP_MAINLINK_CTRL, 0x02000001);
690 wmb(); /* make sure mainlink turned on */
691 } else {
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700692 mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700693 mainlink_ctrl &= ~BIT(0);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700694 dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700695 }
696}
697
698static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl,
699 u32 cc, u32 tb)
700{
Padmanabhan Komandurue66f9ba2017-10-16 12:49:13 +0530701 u32 misc_val = cc;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700702 struct dp_catalog_private *catalog;
703 void __iomem *base;
704
705 if (!ctrl) {
706 pr_err("invalid input\n");
707 return;
708 }
709
710 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700711 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700712
713 misc_val |= (tb << 5);
714 misc_val |= BIT(0); /* Configure clock to synchronous mode */
715
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700716 pr_debug("misc settings = 0x%x\n", misc_val);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700717 dp_write(base + DP_MISC1_MISC0, misc_val);
718}
719
Ajay Singh Parmara4b06062017-06-23 17:10:36 -0700720static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl,
Aravind Venkateswaran7599a992017-08-10 14:17:57 -0700721 u32 rate, u32 stream_rate_khz,
722 bool fixed_nvid)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700723{
724 u32 pixel_m, pixel_n;
725 u32 mvid, nvid;
Aravind Venkateswaran7599a992017-08-10 14:17:57 -0700726 u64 mvid_calc;
727 u32 const nvid_fixed = 0x8000;
Aravind Venkateswaranc28b7772017-08-18 17:20:18 -0700728 u32 const link_rate_hbr2 = 540000;
729 u32 const link_rate_hbr3 = 810000;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700730 struct dp_catalog_private *catalog;
731 void __iomem *base_cc, *base_ctrl;
732
733 if (!ctrl) {
734 pr_err("invalid input\n");
735 return;
736 }
737
738 dp_catalog_get_priv(ctrl);
Aravind Venkateswaran7599a992017-08-10 14:17:57 -0700739 if (fixed_nvid) {
740 pr_debug("use fixed NVID=0x%x\n", nvid_fixed);
741 nvid = nvid_fixed;
742
743 pr_debug("link rate=%dkbps, stream_rate_khz=%uKhz",
744 rate, stream_rate_khz);
745
746 /*
747 * For intermediate results, use 64 bit arithmetic to avoid
748 * loss of precision.
749 */
750 mvid_calc = (u64) stream_rate_khz * nvid;
751 mvid_calc = div_u64(mvid_calc, rate);
752
753 /*
754 * truncate back to 32 bits as this final divided value will
755 * always be within the range of a 32 bit unsigned int.
756 */
757 mvid = (u32) mvid_calc;
758 } else {
759 base_cc = catalog->io->dp_cc_io.base;
760
761 pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M);
762 pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N);
763 pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
764
765 mvid = (pixel_m & 0xFFFF) * 5;
766 nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
767
768 pr_debug("rate = %d\n", rate);
769
Aravind Venkateswaranc28b7772017-08-18 17:20:18 -0700770 if (link_rate_hbr2 == rate)
Aravind Venkateswaran7599a992017-08-10 14:17:57 -0700771 nvid *= 2;
Aravind Venkateswaranc28b7772017-08-18 17:20:18 -0700772
773 if (link_rate_hbr3 == rate)
774 nvid *= 3;
Aravind Venkateswaran7599a992017-08-10 14:17:57 -0700775 }
776
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700777 base_ctrl = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700778 pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
779 dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid);
780 dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid);
781}
782
783static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl,
784 u32 pattern)
785{
786 int bit, cnt = 10;
787 u32 data;
788 struct dp_catalog_private *catalog;
789 void __iomem *base;
790
791 if (!ctrl) {
792 pr_err("invalid input\n");
793 return;
794 }
795
796 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700797 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700798
799 bit = 1;
800 bit <<= (pattern - 1);
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -0700801 pr_debug("hw: bit=%d train=%d\n", bit, pattern);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700802 dp_write(base + DP_STATE_CTRL, bit);
803
804 bit = 8;
805 bit <<= (pattern - 1);
806
807 while (cnt--) {
808 data = dp_read(base + DP_MAINLINK_READY);
809 if (data & bit)
810 break;
811 }
812
813 if (cnt == 0)
814 pr_err("set link_train=%d failed\n", pattern);
815}
816
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -0700817static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip)
818{
819 struct dp_catalog_private *catalog;
820 void __iomem *base;
821
822 if (!ctrl) {
823 pr_err("invalid input\n");
824 return;
825 }
826
827 dp_catalog_get_priv(ctrl);
828
829 base = catalog->io->usb3_dp_com.base;
830
831 dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a);
832 dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02);
833 dp_write(base + USB3_DP_COM_SW_RESET, 0x01);
834 /* make sure usb3 com phy software reset is done */
835 wmb();
836
837 if (!flip) /* CC1 */
838 dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02);
839 else /* CC2 */
840 dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03);
841
842 dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00);
843 dp_write(base + USB3_DP_COM_SW_RESET, 0x00);
844 /* make sure the software reset is done */
845 wmb();
846
847 dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01);
848 dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00);
849 /* make sure phy is brought out of reset */
850 wmb();
Padmanabhan Komanduru04aa2a72017-11-06 17:59:24 +0530851}
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -0700852
Padmanabhan Komanduru04aa2a72017-11-06 17:59:24 +0530853static void dp_catalog_panel_tpg_cfg(struct dp_catalog_panel *panel,
854 bool enable)
855{
856 struct dp_catalog_private *catalog;
857 void __iomem *base;
858
859 if (!panel) {
860 pr_err("invalid input\n");
861 return;
862 }
863
864 dp_catalog_get_priv(panel);
865 base = catalog->io->dp_p0.base;
866
867 if (!enable) {
868 dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x0);
869 dp_write(base + MMSS_DP_BIST_ENABLE, 0x0);
870 dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x0);
871 wmb(); /* ensure Timing generator is turned off */
872 return;
873 }
874
875 dp_write(base + MMSS_DP_INTF_CONFIG, 0x0);
876 dp_write(base + MMSS_DP_INTF_HSYNC_CTL, panel->hsync_ctl);
877 dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F0, panel->vsync_period *
878 panel->hsync_period);
879 dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, panel->v_sync_width *
880 panel->hsync_period);
881 dp_write(base + MMSS_DP_INTF_VSYNC_PERIOD_F1, 0);
882 dp_write(base + MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0);
883 dp_write(base + MMSS_DP_INTF_DISPLAY_HCTL, panel->display_hctl);
884 dp_write(base + MMSS_DP_INTF_ACTIVE_HCTL, 0);
885 dp_write(base + MMSS_INTF_DISPLAY_V_START_F0, panel->display_v_start);
886 dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F0, panel->display_v_end);
887 dp_write(base + MMSS_INTF_DISPLAY_V_START_F1, 0);
888 dp_write(base + MMSS_DP_INTF_DISPLAY_V_END_F1, 0);
889 dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F0, 0);
890 dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F0, 0);
891 dp_write(base + MMSS_DP_INTF_ACTIVE_V_START_F1, 0);
892 dp_write(base + MMSS_DP_INTF_ACTIVE_V_END_F1, 0);
893 dp_write(base + MMSS_DP_INTF_POLARITY_CTL, 0);
894 wmb(); /* ensure TPG registers are programmed */
895
896 dp_write(base + MMSS_DP_TPG_MAIN_CONTROL, 0x100);
897 dp_write(base + MMSS_DP_TPG_VIDEO_CONFIG, 0x5);
898 wmb(); /* ensure TPG config is programmed */
899 dp_write(base + MMSS_DP_BIST_ENABLE, 0x1);
900 dp_write(base + MMSS_DP_TIMING_ENGINE_EN, 0x1);
901 wmb(); /* ensure Timing generator is turned on */
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -0700902}
903
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700904static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl)
905{
906 u32 sw_reset;
907 struct dp_catalog_private *catalog;
908 void __iomem *base;
909
910 if (!ctrl) {
911 pr_err("invalid input\n");
912 return;
913 }
914
915 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700916 base = catalog->io->dp_ahb.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700917
918 sw_reset = dp_read(base + DP_SW_RESET);
919
920 sw_reset |= BIT(0);
921 dp_write(base + DP_SW_RESET, sw_reset);
922 usleep_range(1000, 1010); /* h/w recommended delay */
923
924 sw_reset &= ~BIT(0);
925 dp_write(base + DP_SW_RESET, sw_reset);
926}
927
928static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl)
929{
930 u32 data;
931 int cnt = 10;
932 struct dp_catalog_private *catalog;
933 void __iomem *base;
934
935 if (!ctrl) {
936 pr_err("invalid input\n");
937 goto end;
938 }
939
940 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700941 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700942
943 while (--cnt) {
944 /* DP_MAINLINK_READY */
945 data = dp_read(base + DP_MAINLINK_READY);
946 if (data & BIT(0))
947 return true;
948
949 usleep_range(1000, 1010); /* 1ms wait before next reg read */
950 }
951 pr_err("mainlink not ready\n");
952end:
953 return false;
954}
955
956static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl,
957 bool enable)
958{
959 struct dp_catalog_private *catalog;
960 void __iomem *base;
961
962 if (!ctrl) {
963 pr_err("invalid input\n");
964 return;
965 }
966
967 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700968 base = catalog->io->dp_ahb.base;
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -0700969
970 if (enable) {
971 dp_write(base + DP_INTR_STATUS, DP_INTR_MASK1);
972 dp_write(base + DP_INTR_STATUS2, DP_INTR_MASK2);
973 } else {
974 dp_write(base + DP_INTR_STATUS, 0x00);
975 dp_write(base + DP_INTR_STATUS2, 0x00);
976 }
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700977}
978
979static void dp_catalog_ctrl_hpd_config(struct dp_catalog_ctrl *ctrl, bool en)
980{
981 struct dp_catalog_private *catalog;
982 void __iomem *base;
983
984 if (!ctrl) {
985 pr_err("invalid input\n");
986 return;
987 }
988
989 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -0700990 base = catalog->io->dp_aux.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -0700991
992 if (en) {
993 u32 reftimer = dp_read(base + DP_DP_HPD_REFTIMER);
994
995 dp_write(base + DP_DP_HPD_INT_ACK, 0xF);
996 dp_write(base + DP_DP_HPD_INT_MASK, 0xF);
997
998 /* Enabling REFTIMER */
999 reftimer |= BIT(16);
1000 dp_write(base + DP_DP_HPD_REFTIMER, 0xF);
1001 /* Enable HPD */
1002 dp_write(base + DP_DP_HPD_CTRL, 0x1);
1003 } else {
1004 /*Disable HPD */
1005 dp_write(base + DP_DP_HPD_CTRL, 0x0);
1006 }
1007}
1008
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001009static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001010{
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001011 u32 ack = 0;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001012 struct dp_catalog_private *catalog;
1013 void __iomem *base;
1014
1015 if (!ctrl) {
1016 pr_err("invalid input\n");
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001017 return;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001018 }
1019
1020 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001021 base = catalog->io->dp_ahb.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001022
Padmanabhan Komanduru15e757d2017-05-24 04:07:31 -07001023 ctrl->isr = dp_read(base + DP_INTR_STATUS2);
1024 ctrl->isr &= ~DP_INTR_MASK2;
1025 ack = ctrl->isr & DP_INTERRUPT_STATUS2;
1026 ack <<= 1;
1027 ack |= DP_INTR_MASK2;
1028 dp_write(base + DP_INTR_STATUS2, ack);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001029}
1030
1031static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl)
1032{
1033 struct dp_catalog_private *catalog;
1034 void __iomem *base;
1035
1036 if (!ctrl) {
1037 pr_err("invalid input\n");
1038 return;
1039 }
1040
1041 dp_catalog_get_priv(ctrl);
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001042 base = catalog->io->dp_ahb.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001043
1044 dp_write(base + DP_PHY_CTRL, 0x5); /* bit 0 & 2 */
1045 usleep_range(1000, 1010); /* h/w recommended delay */
1046 dp_write(base + DP_PHY_CTRL, 0x0);
1047 wmb(); /* make sure PHY reset done */
1048}
1049
1050static void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog_ctrl *ctrl,
1051 bool flipped, u8 ln_cnt)
1052{
1053 u32 info = 0x0;
1054 struct dp_catalog_private *catalog;
1055 u8 orientation = BIT(!!flipped);
1056
1057 if (!ctrl) {
1058 pr_err("invalid input\n");
1059 return;
1060 }
1061
1062 dp_catalog_get_priv(ctrl);
1063
1064 info |= (ln_cnt & 0x0F);
1065 info |= ((orientation & 0x0F) << 4);
1066 pr_debug("Shared Info = 0x%x\n", info);
1067
1068 dp_write(catalog->io->phy_io.base + DP_PHY_SPARE0, info);
1069}
1070
1071static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
1072 u8 v_level, u8 p_level)
1073{
1074 struct dp_catalog_private *catalog;
1075 void __iomem *base0, *base1;
1076 u8 value0, value1;
1077
1078 if (!ctrl) {
1079 pr_err("invalid input\n");
1080 return;
1081 }
1082
1083 dp_catalog_get_priv(ctrl);
1084 base0 = catalog->io->ln_tx0_io.base;
1085 base1 = catalog->io->ln_tx1_io.base;
1086
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001087 pr_debug("hw: v=%d p=%d\n", v_level, p_level);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001088
1089 value0 = vm_voltage_swing[v_level][p_level];
1090 value1 = vm_pre_emphasis[v_level][p_level];
1091
1092 /* program default setting first */
1093 dp_write(base0 + TXn_TX_DRV_LVL, 0x2A);
1094 dp_write(base1 + TXn_TX_DRV_LVL, 0x2A);
1095 dp_write(base0 + TXn_TX_EMP_POST1_LVL, 0x20);
1096 dp_write(base1 + TXn_TX_EMP_POST1_LVL, 0x20);
1097
1098 /* Enable MUX to use Cursor values from these registers */
1099 value0 |= BIT(5);
1100 value1 |= BIT(5);
1101
1102 /* Configure host and panel only if both values are allowed */
1103 if (value0 != 0xFF && value1 != 0xFF) {
1104 dp_write(base0 + TXn_TX_DRV_LVL, value0);
1105 dp_write(base1 + TXn_TX_DRV_LVL, value0);
1106 dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1);
1107 dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1);
1108
Ajay Singh Parmarf63dbc7ab2017-07-02 22:45:28 -07001109 pr_debug("hw: vx_value=0x%x px_value=0x%x\n",
1110 value0, value1);
1111 } else {
1112 pr_err("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
1113 v_level, value0, p_level, value1);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001114 }
1115}
1116
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001117static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl,
1118 u32 pattern)
1119{
1120 struct dp_catalog_private *catalog;
1121 u32 value = 0x0;
1122 void __iomem *base = NULL;
1123
1124 if (!ctrl) {
1125 pr_err("invalid input\n");
1126 return;
1127 }
1128
1129 dp_catalog_get_priv(ctrl);
1130
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001131 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001132
1133 dp_write(base + DP_STATE_CTRL, 0x0);
1134
1135 switch (pattern) {
1136 case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
1137 dp_write(base + DP_STATE_CTRL, 0x1);
1138 break;
1139 case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
1140 value &= ~(1 << 16);
1141 dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
1142 value |= 0xFC;
1143 dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
1144 dp_write(base + DP_MAINLINK_LEVELS, 0x2);
1145 dp_write(base + DP_STATE_CTRL, 0x10);
1146 break;
1147 case DP_TEST_PHY_PATTERN_PRBS7:
1148 dp_write(base + DP_STATE_CTRL, 0x20);
1149 break;
1150 case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
1151 dp_write(base + DP_STATE_CTRL, 0x40);
1152 /* 00111110000011111000001111100000 */
1153 dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
1154 /* 00001111100000111110000011111000 */
1155 dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
1156 /* 1111100000111110 */
1157 dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
1158 break;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001159 case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1:
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001160 value = BIT(16);
1161 dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
1162 value |= 0xFC;
1163 dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
1164 dp_write(base + DP_MAINLINK_LEVELS, 0x2);
1165 dp_write(base + DP_STATE_CTRL, 0x10);
1166 break;
Tatenda Chipeperekwa4e2346e2017-11-03 15:40:02 -07001167 case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3:
1168 dp_write(base + DP_MAINLINK_CTRL, 0x11);
1169 dp_write(base + DP_STATE_CTRL, 0x8);
1170 break;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001171 default:
1172 pr_debug("No valid test pattern requested: 0x%x\n", pattern);
1173 return;
1174 }
1175
1176 /* Make sure the test pattern is programmed in the hardware */
1177 wmb();
1178}
1179
1180static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
1181{
1182 struct dp_catalog_private *catalog;
1183 void __iomem *base = NULL;
1184
1185 if (!ctrl) {
1186 pr_err("invalid input\n");
1187 return 0;
1188 }
1189
1190 dp_catalog_get_priv(ctrl);
1191
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001192 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001193
1194 return dp_read(base + DP_MAINLINK_READY);
1195}
1196
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001197/* panel related catalog functions */
1198static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
1199{
1200 struct dp_catalog_private *catalog;
1201 void __iomem *base;
1202
1203 if (!panel) {
1204 pr_err("invalid input\n");
1205 goto end;
1206 }
1207
1208 dp_catalog_get_priv(panel);
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001209 base = catalog->io->dp_link.base;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001210
1211 dp_write(base + DP_TOTAL_HOR_VER, panel->total);
1212 dp_write(base + DP_START_HOR_VER_FROM_SYNC, panel->sync_start);
1213 dp_write(base + DP_HSYNC_VSYNC_WIDTH_POLARITY, panel->width_blanking);
1214 dp_write(base + DP_ACTIVE_HOR_VER, panel->dp_active);
1215end:
1216 return 0;
1217}
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001218
1219static void dp_catalog_audio_init(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001220{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001221 struct dp_catalog_private *catalog;
1222 static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = {
1223 {
1224 MMSS_DP_AUDIO_STREAM_0,
1225 MMSS_DP_AUDIO_STREAM_1,
1226 MMSS_DP_AUDIO_STREAM_1,
1227 },
1228 {
1229 MMSS_DP_AUDIO_TIMESTAMP_0,
1230 MMSS_DP_AUDIO_TIMESTAMP_1,
1231 MMSS_DP_AUDIO_TIMESTAMP_1,
1232 },
1233 {
1234 MMSS_DP_AUDIO_INFOFRAME_0,
1235 MMSS_DP_AUDIO_INFOFRAME_1,
1236 MMSS_DP_AUDIO_INFOFRAME_1,
1237 },
1238 {
1239 MMSS_DP_AUDIO_COPYMANAGEMENT_0,
1240 MMSS_DP_AUDIO_COPYMANAGEMENT_1,
1241 MMSS_DP_AUDIO_COPYMANAGEMENT_1,
1242 },
1243 {
1244 MMSS_DP_AUDIO_ISRC_0,
1245 MMSS_DP_AUDIO_ISRC_1,
1246 MMSS_DP_AUDIO_ISRC_1,
1247 },
1248 };
1249
1250 if (!audio)
1251 return;
1252
1253 dp_catalog_get_priv(audio);
1254
1255 catalog->audio_map = sdp_map;
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001256}
1257
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001258static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001259{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001260 struct dp_catalog_private *catalog;
1261 void __iomem *base;
1262 u32 sdp_cfg = 0;
1263 u32 sdp_cfg2 = 0;
1264
1265 if (!audio)
1266 return;
1267
1268 dp_catalog_get_priv(audio);
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001269 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001270
Ajay Singh Parmar7e724362017-11-05 00:06:30 -07001271 sdp_cfg = dp_read(base + MMSS_DP_SDP_CFG);
1272
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001273 /* AUDIO_TIMESTAMP_SDP_EN */
1274 sdp_cfg |= BIT(1);
1275 /* AUDIO_STREAM_SDP_EN */
1276 sdp_cfg |= BIT(2);
1277 /* AUDIO_COPY_MANAGEMENT_SDP_EN */
1278 sdp_cfg |= BIT(5);
1279 /* AUDIO_ISRC_SDP_EN */
1280 sdp_cfg |= BIT(6);
1281 /* AUDIO_INFOFRAME_SDP_EN */
1282 sdp_cfg |= BIT(20);
1283
1284 pr_debug("sdp_cfg = 0x%x\n", sdp_cfg);
1285 dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg);
1286
1287 sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
1288 /* IFRM_REGSRC -> Do not use reg values */
1289 sdp_cfg2 &= ~BIT(0);
1290 /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */
1291 sdp_cfg2 &= ~BIT(1);
1292
1293 pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2);
1294 dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001295}
1296
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001297static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001298{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001299 struct dp_catalog_private *catalog;
1300 u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
1301 void __iomem *base;
1302 enum dp_catalog_audio_sdp_type sdp;
1303 enum dp_catalog_audio_header_type header;
1304
1305 if (!audio)
1306 return;
1307
1308 dp_catalog_get_priv(audio);
1309
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001310 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001311 sdp_map = catalog->audio_map;
1312 sdp = audio->sdp_type;
1313 header = audio->sdp_header;
1314
1315 audio->data = dp_read(base + sdp_map[sdp][header]);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001316}
1317
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001318static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001319{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001320 struct dp_catalog_private *catalog;
1321 u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX];
1322 void __iomem *base;
1323 enum dp_catalog_audio_sdp_type sdp;
1324 enum dp_catalog_audio_header_type header;
1325 u32 data;
1326
1327 if (!audio)
1328 return;
1329
1330 dp_catalog_get_priv(audio);
1331
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001332 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001333 sdp_map = catalog->audio_map;
1334 sdp = audio->sdp_type;
1335 header = audio->sdp_header;
1336 data = audio->data;
1337
1338 dp_write(base + sdp_map[sdp][header], data);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001339}
1340
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001341static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001342{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001343 struct dp_catalog_private *catalog;
1344 void __iomem *base;
1345 u32 acr_ctrl, select;
1346
1347 dp_catalog_get_priv(audio);
1348
1349 select = audio->data;
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001350 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001351
1352 acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14);
1353
1354 pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl);
1355
1356 dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001357}
1358
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001359static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001360{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001361 struct dp_catalog_private *catalog;
1362 void __iomem *base;
1363 u32 mainlink_levels, safe_to_exit_level;
1364
1365 dp_catalog_get_priv(audio);
1366
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001367 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001368 safe_to_exit_level = audio->data;
1369
1370 mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS);
1371 mainlink_levels &= 0xFE0;
1372 mainlink_levels |= safe_to_exit_level;
1373
1374 pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n",
1375 mainlink_levels, safe_to_exit_level);
1376
1377 dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels);
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001378}
1379
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001380static void dp_catalog_audio_enable(struct dp_catalog_audio *audio)
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001381{
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001382 struct dp_catalog_private *catalog;
1383 void __iomem *base;
1384 bool enable;
1385 u32 audio_ctrl;
1386
1387 dp_catalog_get_priv(audio);
1388
Samantha Tran45c3e5c2017-10-19 12:51:09 -07001389 base = catalog->io->dp_link.base;
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001390 enable = !!audio->data;
1391
1392 audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG);
1393
1394 if (enable)
1395 audio_ctrl |= BIT(0);
1396 else
1397 audio_ctrl &= ~BIT(0);
1398
1399 pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl);
1400 dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl);
1401
1402 /* make sure audio engine is disabled */
1403 wmb();
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001404}
1405
Padmanabhan Komanduru62a01d02017-11-03 19:44:13 +05301406static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel)
1407{
1408 struct dp_catalog_private *catalog;
1409 void __iomem *base;
1410 u32 value, new_value;
1411 u8 parity_byte;
1412
1413 if (!panel)
1414 return;
1415
1416 dp_catalog_get_priv(panel);
1417 base = catalog->io->dp_link.base;
1418
1419 /* Config header and parity byte 1 */
1420 value = dp_read(base + MMSS_DP_GENERIC1_0);
1421
1422 new_value = 0x83;
1423 parity_byte = dp_header_get_parity(new_value);
1424 value |= ((new_value << HEADER_BYTE_1_BIT)
1425 | (parity_byte << PARITY_BYTE_1_BIT));
1426 pr_debug("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
1427 value, parity_byte);
1428 dp_write(base + MMSS_DP_GENERIC1_0, value);
1429
1430 /* Config header and parity byte 2 */
1431 value = dp_read(base + MMSS_DP_GENERIC1_1);
1432
1433 new_value = 0x1b;
1434 parity_byte = dp_header_get_parity(new_value);
1435 value |= ((new_value << HEADER_BYTE_2_BIT)
1436 | (parity_byte << PARITY_BYTE_2_BIT));
1437 pr_debug("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
1438 value, parity_byte);
1439 dp_write(base + MMSS_DP_GENERIC1_1, value);
1440
1441 /* Config header and parity byte 3 */
1442 value = dp_read(base + MMSS_DP_GENERIC1_1);
1443
1444 new_value = (0x0 | (0x12 << 2));
1445 parity_byte = dp_header_get_parity(new_value);
1446 value |= ((new_value << HEADER_BYTE_3_BIT)
1447 | (parity_byte << PARITY_BYTE_3_BIT));
1448 pr_debug("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
1449 new_value, parity_byte);
1450 dp_write(base + MMSS_DP_GENERIC1_1, value);
1451}
1452
1453static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel)
1454{
1455 struct dp_catalog_private *catalog;
1456 void __iomem *base;
1457 u32 spd_cfg = 0, spd_cfg2 = 0;
1458 u8 *vendor = NULL, *product = NULL;
1459 /*
1460 * Source Device Information
1461 * 00h unknown
1462 * 01h Digital STB
1463 * 02h DVD
1464 * 03h D-VHS
1465 * 04h HDD Video
1466 * 05h DVC
1467 * 06h DSC
1468 * 07h Video CD
1469 * 08h Game
1470 * 09h PC general
1471 * 0ah Bluray-Disc
1472 * 0bh Super Audio CD
1473 * 0ch HD DVD
1474 * 0dh PMP
1475 * 0eh-ffh reserved
1476 */
1477 u32 device_type = 0;
1478
1479 if (!panel)
1480 return;
1481
1482 dp_catalog_get_priv(panel);
1483 base = catalog->io->dp_link.base;
1484
1485 dp_catalog_config_spd_header(panel);
1486
1487 vendor = panel->spd_vendor_name;
1488 product = panel->spd_product_description;
1489
1490 dp_write(base + MMSS_DP_GENERIC1_2, ((vendor[0] & 0x7f) |
1491 ((vendor[1] & 0x7f) << 8) |
1492 ((vendor[2] & 0x7f) << 16) |
1493 ((vendor[3] & 0x7f) << 24)));
1494 dp_write(base + MMSS_DP_GENERIC1_3, ((vendor[4] & 0x7f) |
1495 ((vendor[5] & 0x7f) << 8) |
1496 ((vendor[6] & 0x7f) << 16) |
1497 ((vendor[7] & 0x7f) << 24)));
1498 dp_write(base + MMSS_DP_GENERIC1_4, ((product[0] & 0x7f) |
1499 ((product[1] & 0x7f) << 8) |
1500 ((product[2] & 0x7f) << 16) |
1501 ((product[3] & 0x7f) << 24)));
1502 dp_write(base + MMSS_DP_GENERIC1_5, ((product[4] & 0x7f) |
1503 ((product[5] & 0x7f) << 8) |
1504 ((product[6] & 0x7f) << 16) |
1505 ((product[7] & 0x7f) << 24)));
1506 dp_write(base + MMSS_DP_GENERIC1_6, ((product[8] & 0x7f) |
1507 ((product[9] & 0x7f) << 8) |
1508 ((product[10] & 0x7f) << 16) |
1509 ((product[11] & 0x7f) << 24)));
1510 dp_write(base + MMSS_DP_GENERIC1_7, ((product[12] & 0x7f) |
1511 ((product[13] & 0x7f) << 8) |
1512 ((product[14] & 0x7f) << 16) |
1513 ((product[15] & 0x7f) << 24)));
1514 dp_write(base + MMSS_DP_GENERIC1_8, device_type);
1515 dp_write(base + MMSS_DP_GENERIC1_9, 0x00);
1516
1517 spd_cfg = dp_read(base + MMSS_DP_SDP_CFG);
1518 /* GENERIC1_SDP for SPD Infoframe */
1519 spd_cfg |= BIT(18);
1520 dp_write(base + MMSS_DP_SDP_CFG, spd_cfg);
1521
1522 spd_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2);
1523 /* 28 data bytes for SPD Infoframe with GENERIC1 set */
1524 spd_cfg2 |= BIT(17);
1525 dp_write(base + MMSS_DP_SDP_CFG2, spd_cfg2);
1526
1527 dp_write(base + MMSS_DP_SDP_CFG3, 0x1);
1528 dp_write(base + MMSS_DP_SDP_CFG3, 0x0);
1529}
1530
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001531struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
1532{
1533 int rc = 0;
1534 struct dp_catalog *dp_catalog;
1535 struct dp_catalog_private *catalog;
1536 struct dp_catalog_aux aux = {
1537 .read_data = dp_catalog_aux_read_data,
1538 .write_data = dp_catalog_aux_write_data,
1539 .write_trans = dp_catalog_aux_write_trans,
Tatenda Chipeperekwa35eafc12017-02-17 22:30:34 -08001540 .clear_trans = dp_catalog_aux_clear_trans,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001541 .reset = dp_catalog_aux_reset,
Padmanabhan Komanduru2e9914b2017-08-04 20:51:31 +05301542 .update_aux_cfg = dp_catalog_aux_update_cfg,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001543 .enable = dp_catalog_aux_enable,
1544 .setup = dp_catalog_aux_setup,
1545 .get_irq = dp_catalog_aux_get_irq,
Padmanabhan Komanduruf69e3572017-09-27 20:39:32 +05301546 .clear_hw_interrupts = dp_catalog_aux_clear_hw_interrupts,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001547 };
1548 struct dp_catalog_ctrl ctrl = {
1549 .state_ctrl = dp_catalog_ctrl_state_ctrl,
1550 .config_ctrl = dp_catalog_ctrl_config_ctrl,
1551 .lane_mapping = dp_catalog_ctrl_lane_mapping,
1552 .mainlink_ctrl = dp_catalog_ctrl_mainlink_ctrl,
1553 .config_misc = dp_catalog_ctrl_config_misc,
1554 .config_msa = dp_catalog_ctrl_config_msa,
1555 .set_pattern = dp_catalog_ctrl_set_pattern,
1556 .reset = dp_catalog_ctrl_reset,
Padmanabhan Komandurub6117bd2017-05-11 20:18:40 -07001557 .usb_reset = dp_catalog_ctrl_usb_reset,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001558 .mainlink_ready = dp_catalog_ctrl_mainlink_ready,
1559 .enable_irq = dp_catalog_ctrl_enable_irq,
1560 .hpd_config = dp_catalog_ctrl_hpd_config,
1561 .phy_reset = dp_catalog_ctrl_phy_reset,
1562 .phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg,
1563 .update_vx_px = dp_catalog_ctrl_update_vx_px,
1564 .get_interrupt = dp_catalog_ctrl_get_interrupt,
1565 .update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
Tatenda Chipeperekwa39547362017-07-07 17:44:09 -07001566 .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status,
Tatenda Chipeperekwa8ce1d5f2017-08-07 18:44:21 -07001567 .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern,
1568 .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001569 };
1570 struct dp_catalog_audio audio = {
Tatenda Chipeperekwa758dea02017-04-28 12:26:31 -07001571 .init = dp_catalog_audio_init,
1572 .config_acr = dp_catalog_audio_config_acr,
1573 .enable = dp_catalog_audio_enable,
1574 .config_sdp = dp_catalog_audio_config_sdp,
1575 .set_header = dp_catalog_audio_set_header,
1576 .get_header = dp_catalog_audio_get_header,
1577 .safe_to_exit_level = dp_catalog_audio_safe_to_exit_level,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001578 };
1579 struct dp_catalog_panel panel = {
1580 .timing_cfg = dp_catalog_panel_timing_cfg,
Ajay Singh Parmar9c842d42017-09-21 13:02:05 -07001581 .config_hdr = dp_catalog_panel_config_hdr,
Padmanabhan Komanduru04aa2a72017-11-06 17:59:24 +05301582 .tpg_config = dp_catalog_panel_tpg_cfg,
Padmanabhan Komanduru62a01d02017-11-03 19:44:13 +05301583 .config_spd = dp_catalog_panel_config_spd,
Ajay Singh Parmarbd3097f2017-03-29 15:04:13 -07001584 };
1585
1586 if (!io) {
1587 pr_err("invalid input\n");
1588 rc = -EINVAL;
1589 goto error;
1590 }
1591
1592 catalog = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL);
1593 if (!catalog) {
1594 rc = -ENOMEM;
1595 goto error;
1596 }
1597
1598 catalog->dev = dev;
1599 catalog->io = io;
1600
1601 dp_catalog = &catalog->dp_catalog;
1602
1603 dp_catalog->aux = aux;
1604 dp_catalog->ctrl = ctrl;
1605 dp_catalog->audio = audio;
1606 dp_catalog->panel = panel;
1607
1608 return dp_catalog;
1609error:
1610 return ERR_PTR(rc);
1611}
1612
1613void dp_catalog_put(struct dp_catalog *dp_catalog)
1614{
1615 struct dp_catalog_private *catalog;
1616
1617 if (!dp_catalog)
1618 return;
1619
1620 catalog = container_of(dp_catalog, struct dp_catalog_private,
1621 dp_catalog);
1622
1623 devm_kfree(catalog->dev, catalog);
1624}