blob: e3a511131f0b38f1ab6636e0bfa96f820e528f72 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Jitao Shi542919f2019-09-26 10:22:08 +08002
3#include <console/console.h>
4#include <delay.h>
5#include <device/i2c_simple.h>
6#include <edid.h>
7#include <gpio.h>
Jitao Shi542919f2019-09-26 10:22:08 +08008#include <string.h>
Yu-Ping Wu734a7772021-11-25 16:28:13 +08009#include <types.h>
Jitao Shi542919f2019-09-26 10:22:08 +080010
11#include "anx7625.h"
12
13#define ANXERROR(format, ...) \
Julius Wernere9665952022-01-21 17:06:20 -080014 printk(BIOS_ERR, "%s: " format, __func__, ##__VA_ARGS__)
Jitao Shi542919f2019-09-26 10:22:08 +080015#define ANXINFO(format, ...) \
16 printk(BIOS_INFO, "%s: " format, __func__, ##__VA_ARGS__)
17#define ANXDEBUG(format, ...) \
18 printk(BIOS_DEBUG, "%s: " format, __func__, ##__VA_ARGS__)
19
20/*
21 * There is a sync issue while accessing I2C register between AP(CPU) and
22 * internal firmware(OCM). To avoid the race condition, AP should access the
23 * reserved slave address before slave address changes.
24 */
25static int i2c_access_workaround(uint8_t bus, uint8_t saddr)
26{
27 uint8_t offset;
28 static uint8_t saddr_backup = 0;
29 int ret = 0;
30
31 if (saddr == saddr_backup)
32 return ret;
33
34 saddr_backup = saddr;
35
36 switch (saddr) {
37 case TCPC_INTERFACE_ADDR:
38 offset = RSVD_00_ADDR;
39 break;
40 case TX_P0_ADDR:
41 offset = RSVD_D1_ADDR;
42 break;
43 case TX_P1_ADDR:
44 offset = RSVD_60_ADDR;
45 break;
46 case RX_P0_ADDR:
47 offset = RSVD_39_ADDR;
48 break;
49 case RX_P1_ADDR:
50 offset = RSVD_7F_ADDR;
51 break;
52 default:
53 offset = RSVD_00_ADDR;
54 break;
55 }
56
57 ret = i2c_writeb(bus, saddr, offset, 0x00);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +080058 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +080059 ANXERROR("Failed to access %#x:%#x\n", saddr, offset);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +080060 return ret;
61 }
62 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +080063}
64
65static int anx7625_reg_read(uint8_t bus, uint8_t saddr, uint8_t offset,
66 uint8_t *val)
67{
68 int ret;
69
70 i2c_access_workaround(bus, saddr);
71 ret = i2c_readb(bus, saddr, offset, val);
72 if (ret < 0) {
73 ANXERROR("Failed to read i2c reg=%#x:%#x\n", saddr, offset);
74 return ret;
75 }
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +080076 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +080077}
78
79static int anx7625_reg_block_read(uint8_t bus, uint8_t saddr, uint8_t reg_addr,
80 uint8_t len, uint8_t *buf)
81{
82 int ret;
83
84 i2c_access_workaround(bus, saddr);
85 ret = i2c_read_bytes(bus, saddr, reg_addr, buf, len);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +080086 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +080087 ANXERROR("Failed to read i2c block=%#x:%#x[len=%#x]\n", saddr,
88 reg_addr, len);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +080089 return ret;
90 }
91 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +080092}
93
94static int anx7625_reg_write(uint8_t bus, uint8_t saddr, uint8_t reg_addr,
95 uint8_t reg_val)
96{
97 int ret;
98
99 i2c_access_workaround(bus, saddr);
100 ret = i2c_writeb(bus, saddr, reg_addr, reg_val);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800101 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800102 ANXERROR("Failed to write i2c id=%#x:%#x\n", saddr, reg_addr);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800103 return ret;
104 }
105 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800106}
107
108static int anx7625_write_or(uint8_t bus, uint8_t saddr, uint8_t offset,
109 uint8_t mask)
110{
111 uint8_t val;
112 int ret;
113
114 ret = anx7625_reg_read(bus, saddr, offset, &val);
115 if (ret < 0)
116 return ret;
117
118 return anx7625_reg_write(bus, saddr, offset, val | mask);
119}
120
121static int anx7625_write_and(uint8_t bus, uint8_t saddr, uint8_t offset,
122 uint8_t mask)
123{
124 int ret;
125 uint8_t val;
126
127 ret = anx7625_reg_read(bus, saddr, offset, &val);
128 if (ret < 0)
129 return ret;
130
131 return anx7625_reg_write(bus, saddr, offset, val & mask);
132}
133
134static int wait_aux_op_finish(uint8_t bus)
135{
136 uint8_t val;
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800137 int ret;
Jitao Shi542919f2019-09-26 10:22:08 +0800138
Yu-Ping Wu734a7772021-11-25 16:28:13 +0800139 if (!retry(150,
140 (anx7625_reg_read(bus, RX_P0_ADDR, AP_AUX_CTRL_STATUS, &val),
141 !(val & AP_AUX_CTRL_OP_EN)), mdelay(2))) {
Jitao Shi542919f2019-09-26 10:22:08 +0800142 ANXERROR("Timed out waiting aux operation.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800143 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800144 }
145
146 ret = anx7625_reg_read(bus, RX_P0_ADDR, AP_AUX_CTRL_STATUS, &val);
147 if (ret < 0 || val & 0x0F) {
148 ANXDEBUG("aux status %02x\n", val);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800149 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800150 }
151
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800152 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800153}
154
155static unsigned long gcd(unsigned long a, unsigned long b)
156{
157 if (a == 0)
158 return b;
159
160 while (b != 0) {
161 if (a > b)
162 a = a - b;
163 else
164 b = b - a;
165 }
166
167 return a;
168}
169
170/* Reduce fraction a/b */
171static void anx7625_reduction_of_a_fraction(unsigned long *_a,
172 unsigned long *_b)
173{
174 unsigned long gcd_num;
175 unsigned long a = *_a, b = *_b, old_a, old_b;
176 u32 denom = 1;
177
178 gcd_num = gcd(a, b);
179 a /= gcd_num;
180 b /= gcd_num;
181
182 old_a = a;
183 old_b = b;
184
185 while (a > MAX_UNSIGNED_24BIT || b > MAX_UNSIGNED_24BIT) {
186 denom++;
187 a = old_a / denom;
188 b = old_b / denom;
189 }
190
191 /* Increase a, b to have higher ODFC PLL output frequency accuracy. */
192 while ((a << 1) < MAX_UNSIGNED_24BIT && (b << 1) < MAX_UNSIGNED_24BIT) {
193 a <<= 1;
194 b <<= 1;
195 }
196
197 *_a = a;
198 *_b = b;
199}
200
201static int anx7625_calculate_m_n(u32 pixelclock,
202 unsigned long *m, unsigned long *n,
203 uint8_t *pd)
204{
205 uint8_t post_divider = *pd;
206 if (pixelclock > PLL_OUT_FREQ_ABS_MAX / POST_DIVIDER_MIN) {
207 /* pixel clock frequency is too high */
208 ANXERROR("pixelclock %u higher than %lu, "
209 "output may be unstable\n",
210 pixelclock, PLL_OUT_FREQ_ABS_MAX / POST_DIVIDER_MIN);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800211 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800212 }
213
214 if (pixelclock < PLL_OUT_FREQ_ABS_MIN / POST_DIVIDER_MAX) {
215 /* pixel clock frequency is too low */
216 ANXERROR("pixelclock %u lower than %lu, "
217 "output may be unstable\n",
218 pixelclock, PLL_OUT_FREQ_ABS_MIN / POST_DIVIDER_MAX);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800219 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800220 }
221
222 post_divider = 1;
223
224 for (post_divider = 1;
225 pixelclock < PLL_OUT_FREQ_MIN / post_divider;
226 post_divider++)
227 ;
228
229 if (post_divider > POST_DIVIDER_MAX) {
230 for (post_divider = 1;
231 pixelclock < PLL_OUT_FREQ_ABS_MIN / post_divider;
232 post_divider++)
233 ;
234
235 if (post_divider > POST_DIVIDER_MAX) {
236 ANXERROR("cannot find property post_divider(%d)\n",
237 post_divider);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800238 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800239 }
240 }
241
242 /* Patch to improve the accuracy */
243 if (post_divider == 7) {
244 /* 27,000,000 is not divisible by 7 */
245 post_divider = 8;
246 } else if (post_divider == 11) {
247 /* 27,000,000 is not divisible by 11 */
248 post_divider = 12;
249 } else if (post_divider == 13 || post_divider == 14) {
250 /*27,000,000 is not divisible by 13 or 14*/
251 post_divider = 15;
252 }
253
254 if (pixelclock * post_divider > PLL_OUT_FREQ_ABS_MAX) {
255 ANXINFO("act clock(%u) large than maximum(%lu)\n",
256 pixelclock * post_divider, PLL_OUT_FREQ_ABS_MAX);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800257 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800258 }
259
Jitao Shif68cc812020-01-14 21:23:44 +0800260 *m = pixelclock;
Jitao Shi542919f2019-09-26 10:22:08 +0800261 *n = XTAL_FRQ / post_divider;
262 *pd = post_divider;
263
264 anx7625_reduction_of_a_fraction(m, n);
265
266 return 0;
267}
268
269static int anx7625_odfc_config(uint8_t bus, uint8_t post_divider)
270{
271 int ret;
272
273 /* config input reference clock frequency 27MHz/19.2MHz */
274 ret = anx7625_write_and(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_16,
275 ~(REF_CLK_27000kHz << MIPI_FREF_D_IND));
276 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_16,
277 (REF_CLK_27000kHz << MIPI_FREF_D_IND));
278 /* post divider */
279 ret |= anx7625_write_and(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_8, 0x0f);
280 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_8,
281 post_divider << 4);
282
283 /* add patch for MIS2-125 (5pcs ANX7625 fail ATE MBIST test) */
284 ret |= anx7625_write_and(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_7,
285 ~MIPI_PLL_VCO_TUNE_REG_VAL);
286
287 /* reset ODFC PLL */
288 ret |= anx7625_write_and(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_7,
289 ~MIPI_PLL_RESET_N);
290 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_7,
291 MIPI_PLL_RESET_N);
292
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800293 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800294 ANXERROR("IO error.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800295 return ret;
296 }
Jitao Shi542919f2019-09-26 10:22:08 +0800297
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800298 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800299}
300
301static int anx7625_dsi_video_config(uint8_t bus, struct display_timing *dt)
302{
303 unsigned long m, n;
304 u16 htotal;
305 int ret;
306 uint8_t post_divider = 0;
307
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800308 if (anx7625_calculate_m_n(dt->pixelclock * 1000, &m, &n,
309 &post_divider) < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800310 ANXERROR("cannot get property m n value.\n");
311 return -1;
312 }
313
314 ANXINFO("compute M(%lu), N(%lu), divider(%d).\n", m, n, post_divider);
315
316 /* configure pixel clock */
317 ret = anx7625_reg_write(bus, RX_P0_ADDR, PIXEL_CLOCK_L,
318 (dt->pixelclock / 1000) & 0xFF);
319 ret |= anx7625_reg_write(bus, RX_P0_ADDR, PIXEL_CLOCK_H,
320 (dt->pixelclock / 1000) >> 8);
321 /* lane count */
322 ret |= anx7625_write_and(bus, RX_P1_ADDR, MIPI_LANE_CTRL_0, 0xfc);
323
324 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_LANE_CTRL_0, 3);
325
326 /* Htotal */
327 htotal = dt->hactive + dt->hfront_porch +
328 dt->hback_porch + dt->hsync_len;
329 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
330 HORIZONTAL_TOTAL_PIXELS_L, htotal & 0xFF);
331 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
332 HORIZONTAL_TOTAL_PIXELS_H, htotal >> 8);
333 /* Hactive */
334 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
335 HORIZONTAL_ACTIVE_PIXELS_L, dt->hactive & 0xFF);
336 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
337 HORIZONTAL_ACTIVE_PIXELS_H, dt->hactive >> 8);
338 /* HFP */
339 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
340 HORIZONTAL_FRONT_PORCH_L, dt->hfront_porch);
341 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
342 HORIZONTAL_FRONT_PORCH_H,
343 dt->hfront_porch >> 8);
344 /* HWS */
345 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
346 HORIZONTAL_SYNC_WIDTH_L, dt->hsync_len);
347 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
348 HORIZONTAL_SYNC_WIDTH_H, dt->hsync_len >> 8);
349 /* HBP */
350 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
351 HORIZONTAL_BACK_PORCH_L, dt->hback_porch);
352 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
353 HORIZONTAL_BACK_PORCH_H, dt->hback_porch >> 8);
354 /* Vactive */
355 ret |= anx7625_reg_write(bus, RX_P2_ADDR, ACTIVE_LINES_L, dt->vactive);
356 ret |= anx7625_reg_write(bus, RX_P2_ADDR, ACTIVE_LINES_H,
357 dt->vactive >> 8);
358 /* VFP */
359 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
360 VERTICAL_FRONT_PORCH, dt->vfront_porch);
361 /* VWS */
362 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
363 VERTICAL_SYNC_WIDTH, dt->vsync_len);
364 /* VBP */
365 ret |= anx7625_reg_write(bus, RX_P2_ADDR,
366 VERTICAL_BACK_PORCH, dt->vback_porch);
367 /* M value */
368 ret |= anx7625_reg_write(bus, RX_P1_ADDR,
369 MIPI_PLL_M_NUM_23_16, (m >> 16) & 0xff);
370 ret |= anx7625_reg_write(bus, RX_P1_ADDR,
371 MIPI_PLL_M_NUM_15_8, (m >> 8) & 0xff);
372 ret |= anx7625_reg_write(bus, RX_P1_ADDR,
373 MIPI_PLL_M_NUM_7_0, (m & 0xff));
374 /* N value */
375 ret |= anx7625_reg_write(bus, RX_P1_ADDR,
376 MIPI_PLL_N_NUM_23_16, (n >> 16) & 0xff);
377 ret |= anx7625_reg_write(bus, RX_P1_ADDR,
378 MIPI_PLL_N_NUM_15_8, (n >> 8) & 0xff);
379 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_PLL_N_NUM_7_0,
380 (n & 0xff));
381 /* diff */
Xin Ji48ae1112021-09-03 11:11:44 +0800382 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_DIGITAL_ADJ_1, dt->k_val);
Jitao Shi542919f2019-09-26 10:22:08 +0800383
384 ret |= anx7625_odfc_config(bus, post_divider - 1);
385
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800386 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800387 ANXERROR("mipi dsi setup IO error.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800388 return ret;
389 }
Jitao Shi542919f2019-09-26 10:22:08 +0800390
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800391 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800392}
393
394static int anx7625_swap_dsi_lane3(uint8_t bus)
395{
396 int ret;
397 uint8_t val;
398
399 /* swap MIPI-DSI data lane 3 P and N */
400 ret = anx7625_reg_read(bus, RX_P1_ADDR, MIPI_SWAP, &val);
401 if (ret < 0) {
402 ANXERROR("IO error: access MIPI_SWAP.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800403 return ret;
Jitao Shi542919f2019-09-26 10:22:08 +0800404 }
405
406 val |= (1 << MIPI_SWAP_CH3);
407 return anx7625_reg_write(bus, RX_P1_ADDR, MIPI_SWAP, val);
408}
409
410static int anx7625_api_dsi_config(uint8_t bus, struct display_timing *dt)
411
412{
413 int val, ret;
414
415 /* swap MIPI-DSI data lane 3 P and N */
416 ret = anx7625_swap_dsi_lane3(bus);
417 if (ret < 0) {
418 ANXERROR("IO error: swap dsi lane 3 failed.\n");
419 return ret;
420 }
421
422 /* DSI clock settings */
423 val = (0 << MIPI_HS_PWD_CLK) |
424 (0 << MIPI_HS_RT_CLK) |
425 (0 << MIPI_PD_CLK) |
426 (1 << MIPI_CLK_RT_MANUAL_PD_EN) |
427 (1 << MIPI_CLK_HS_MANUAL_PD_EN) |
428 (0 << MIPI_CLK_DET_DET_BYPASS) |
429 (0 << MIPI_CLK_MISS_CTRL) |
430 (0 << MIPI_PD_LPTX_CH_MANUAL_PD_EN);
431 ret = anx7625_reg_write(bus, RX_P1_ADDR, MIPI_PHY_CONTROL_3, val);
432
433 /*
434 * Decreased HS prepare tg delay from 160ns to 80ns work with
435 * a) Dragon board 810 series (Qualcomm AP)
436 * b) Moving Pixel DSI source (PG3A pattern generator +
437 * P332 D-PHY Probe) default D-PHY tg 5ns/step
438 */
439 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_TIME_HS_PRPR, 0x10);
440
441 /* enable DSI mode */
442 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_18,
443 SELECT_DSI << MIPI_DPI_SELECT);
444
445 ret |= anx7625_dsi_video_config(bus, dt);
446 if (ret < 0) {
447 ANXERROR("dsi video tg config failed\n");
448 return ret;
449 }
450
451 /* toggle m, n ready */
452 ret = anx7625_write_and(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_6,
453 ~(MIPI_M_NUM_READY | MIPI_N_NUM_READY));
454 mdelay(1);
455 ret |= anx7625_write_or(bus, RX_P1_ADDR, MIPI_DIGITAL_PLL_6,
456 MIPI_M_NUM_READY | MIPI_N_NUM_READY);
457
458 /* configure integer stable register */
459 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_VIDEO_STABLE_CNT, 0x02);
460 /* power on MIPI RX */
461 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_LANE_CTRL_10, 0x00);
462 ret |= anx7625_reg_write(bus, RX_P1_ADDR, MIPI_LANE_CTRL_10, 0x80);
463
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800464 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800465 ANXERROR("IO error: mipi dsi enable init failed.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800466 return ret;
467 }
Jitao Shi542919f2019-09-26 10:22:08 +0800468
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800469 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800470}
471
472static int anx7625_dsi_config(uint8_t bus, struct display_timing *dt)
473{
474 int ret;
475
476 ANXINFO("config dsi.\n");
477
478 /* DSC disable */
479 ret = anx7625_write_and(bus, RX_P0_ADDR, R_DSC_CTRL_0, ~DSC_EN);
480 ret |= anx7625_api_dsi_config(bus, dt);
481
482 if (ret < 0) {
483 ANXERROR("IO error: api dsi config error.\n");
484 return ret;
485 }
486
487 /* set MIPI RX EN */
488 ret = anx7625_write_or(bus, RX_P0_ADDR, AP_AV_STATUS, AP_MIPI_RX_EN);
489 /* clear mute flag */
490 ret |= anx7625_write_and(bus, RX_P0_ADDR, AP_AV_STATUS, ~AP_MIPI_MUTE);
491
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800492 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800493 ANXERROR("IO error: enable mipi rx failed.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800494 return ret;
495 }
Jitao Shi542919f2019-09-26 10:22:08 +0800496
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800497 ANXINFO("success to config DSI\n");
498 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800499}
500
501static int sp_tx_rst_aux(uint8_t bus)
502{
503 int ret;
504
505 ret = anx7625_write_or(bus, TX_P2_ADDR, RST_CTRL2, AUX_RST);
506 ret |= anx7625_write_and(bus, TX_P2_ADDR, RST_CTRL2, ~AUX_RST);
507 return ret;
508}
509
510static int sp_tx_aux_wr(uint8_t bus, uint8_t offset)
511{
512 int ret;
513
514 ret = anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_BUFF_START, offset);
515 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_COMMAND, 0x04);
516 ret |= anx7625_write_or(bus, RX_P0_ADDR,
517 AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
518 return ret | wait_aux_op_finish(bus);
519}
520
521static int sp_tx_aux_rd(uint8_t bus, uint8_t len_cmd)
522{
523 int ret;
524
525 ret = anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_COMMAND, len_cmd);
526 ret |= anx7625_write_or(bus, RX_P0_ADDR,
527 AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
528 return ret | wait_aux_op_finish(bus);
529}
530
531static int sp_tx_get_edid_block(uint8_t bus)
532{
533 int ret;
534 uint8_t val = 0;
535
536 sp_tx_aux_wr(bus, 0x7e);
537 sp_tx_aux_rd(bus, 0x01);
538 ret = anx7625_reg_read(bus, RX_P0_ADDR, AP_AUX_BUFF_START, &val);
539
540 if (ret < 0) {
541 ANXERROR("IO error: access AUX BUFF.\n");
542 return -1;
543 }
544
545 ANXINFO("EDID Block = %d\n", val + 1);
546
547 if (val > 3)
548 val = 1;
549
550 return val;
551}
552
553static int edid_read(uint8_t bus, uint8_t offset, uint8_t *pblock_buf)
554{
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800555 int ret, cnt;
Jitao Shi542919f2019-09-26 10:22:08 +0800556
Jitao Shi542919f2019-09-26 10:22:08 +0800557 for (cnt = 0; cnt < 3; cnt++) {
558 sp_tx_aux_wr(bus, offset);
559 /* set I2C read com 0x01 mot = 0 and read 16 bytes */
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800560 ret = sp_tx_aux_rd(bus, 0xf1);
Jitao Shi542919f2019-09-26 10:22:08 +0800561
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800562 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800563 sp_tx_rst_aux(bus);
564 ANXERROR("edid read failed, reset!\n");
Jitao Shi542919f2019-09-26 10:22:08 +0800565 } else {
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800566 if (anx7625_reg_block_read(bus, RX_P0_ADDR,
567 AP_AUX_BUFF_START,
568 MAX_DPCD_BUFFER_SIZE,
569 pblock_buf) >= 0)
570 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800571 }
572 }
573
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800574 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800575}
576
577static int segments_edid_read(uint8_t bus, uint8_t segment, uint8_t *buf,
578 uint8_t offset)
579{
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800580 int ret, cnt;
Jitao Shi542919f2019-09-26 10:22:08 +0800581
582 /* write address only */
583 ret = anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_ADDR_7_0, 0x30);
584 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_COMMAND, 0x04);
585 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_CTRL_STATUS,
586 AP_AUX_CTRL_ADDRONLY | AP_AUX_CTRL_OP_EN);
587
588 ret |= wait_aux_op_finish(bus);
589 /* write segment address */
590 ret |= sp_tx_aux_wr(bus, segment);
591 /* data read */
592 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_ADDR_7_0, 0x50);
593
594 if (ret < 0) {
595 ANXERROR("IO error: aux initial failed.\n");
596 return ret;
597 }
598
599 for (cnt = 0; cnt < 3; cnt++) {
600 sp_tx_aux_wr(bus, offset);
601 /* set I2C read com 0x01 mot = 0 and read 16 bytes */
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800602 ret = sp_tx_aux_rd(bus, 0xf1);
Jitao Shi542919f2019-09-26 10:22:08 +0800603
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800604 if (ret < 0) {
605 sp_tx_rst_aux(bus);
Jitao Shi542919f2019-09-26 10:22:08 +0800606 ANXERROR("segment read failed, reset!\n");
Jitao Shi542919f2019-09-26 10:22:08 +0800607 } else {
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800608 if (anx7625_reg_block_read(bus, RX_P0_ADDR,
609 AP_AUX_BUFF_START,
610 MAX_DPCD_BUFFER_SIZE,
611 buf) >= 0)
612 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800613 }
614 }
615
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800616 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800617}
618
619static int sp_tx_edid_read(uint8_t bus, uint8_t *pedid_blocks_buf,
620 uint32_t size)
621{
622 uint8_t offset, edid_pos;
623 int count, blocks_num;
624 uint8_t pblock_buf[MAX_DPCD_BUFFER_SIZE];
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800625 int i, ret, g_edid_break = 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800626
627 /* address initial */
628 ret = anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_ADDR_7_0, 0x50);
629 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AUX_ADDR_15_8, 0);
630 ret |= anx7625_write_and(bus, RX_P0_ADDR, AP_AUX_ADDR_19_16, 0xf0);
631
632 if (ret < 0) {
633 ANXERROR("access aux channel IO error.\n");
634 return -1;
635 }
636
637 blocks_num = sp_tx_get_edid_block(bus);
638 if (blocks_num < 0)
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800639 return -1;
Jitao Shi542919f2019-09-26 10:22:08 +0800640
641 count = 0;
642
643 do {
644 switch (count) {
645 case 0:
646 case 1:
647 for (i = 0; i < 8; i++) {
648 offset = (i + count * 8) * MAX_DPCD_BUFFER_SIZE;
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800649 g_edid_break = !!edid_read(bus, offset,
650 pblock_buf);
Jitao Shi542919f2019-09-26 10:22:08 +0800651
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800652 if (g_edid_break)
Jitao Shi542919f2019-09-26 10:22:08 +0800653 break;
654
655 if (offset <= size - MAX_DPCD_BUFFER_SIZE)
656 memcpy(&pedid_blocks_buf[offset],
657 pblock_buf,
658 MAX_DPCD_BUFFER_SIZE);
659 }
660
661 break;
662 case 2:
663 case 3:
664 offset = (count == 2) ? 0x00 : 0x80;
665
666 for (i = 0; i < 8; i++) {
667 edid_pos = (i + count * 8) *
668 MAX_DPCD_BUFFER_SIZE;
669
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800670 if (g_edid_break)
Jitao Shi542919f2019-09-26 10:22:08 +0800671 break;
672
673 segments_edid_read(bus, count / 2,
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800674 pblock_buf, offset);
Jitao Shi542919f2019-09-26 10:22:08 +0800675 if (edid_pos <= size - MAX_DPCD_BUFFER_SIZE)
676 memcpy(&pedid_blocks_buf[edid_pos],
677 pblock_buf,
678 MAX_DPCD_BUFFER_SIZE);
679 offset = offset + 0x10;
680 }
681
682 break;
683 default:
684 die("%s: count should be <= 3", __func__);
685 break;
686 }
687
688 count++;
689
690 } while (blocks_num >= count);
691
692 /* reset aux channel */
693 sp_tx_rst_aux(bus);
694
695 return blocks_num;
696}
697
698static void anx7625_disable_pd_protocol(uint8_t bus)
699{
700 int ret;
701
702 /* reset main ocm */
703 ret = anx7625_reg_write(bus, RX_P0_ADDR, 0x88, 0x40);
704 /* Disable PD */
705 ret |= anx7625_reg_write(bus, RX_P0_ADDR, AP_AV_STATUS, AP_DISABLE_PD);
706 /* release main ocm */
707 ret |= anx7625_reg_write(bus, RX_P0_ADDR, 0x88, 0x00);
708
709 if (ret < 0)
710 ANXERROR("Failed to disable PD feature.\n");
711 else
712 ANXINFO("Disabled PD feature.\n");
713}
714
715#define FLASH_LOAD_STA 0x05
716#define FLASH_LOAD_STA_CHK (1 << 7)
717
718static int anx7625_power_on_init(uint8_t bus)
719{
720 int i, ret;
721 uint8_t val, version, revision;
722
723 anx7625_reg_write(bus, RX_P0_ADDR, XTAL_FRQ_SEL, XTAL_FRQ_27M);
724
725 for (i = 0; i < OCM_LOADING_TIME; i++) {
726 /* check interface */
727 ret = anx7625_reg_read(bus, RX_P0_ADDR, FLASH_LOAD_STA, &val);
728 if (ret < 0) {
729 ANXERROR("Failed to load flash\n");
730 return ret;
731 }
732
733 if ((val & FLASH_LOAD_STA_CHK) != FLASH_LOAD_STA_CHK) {
734 mdelay(1);
735 continue;
736 }
737 ANXINFO("Init interface.\n");
738
Jitao Shi542919f2019-09-26 10:22:08 +0800739 anx7625_disable_pd_protocol(bus);
740 anx7625_reg_read(bus, RX_P0_ADDR, OCM_FW_VERSION, &version);
741 anx7625_reg_read(bus, RX_P0_ADDR, OCM_FW_REVERSION, &revision);
742 ANXINFO("Firmware: ver %#02x, rev %#02x.\n", version, revision);
743 return 0;
744 }
745 return -1;
746}
747
748static void anx7625_start_dp_work(uint8_t bus)
749{
750 int ret;
751 uint8_t val;
752
753 /* not support HDCP */
754 ret = anx7625_write_and(bus, RX_P1_ADDR, 0xee, 0x9f);
755
756 /* try auth flag */
757 ret |= anx7625_write_or(bus, RX_P1_ADDR, 0xec, 0x10);
758 /* interrupt for DRM */
759 ret |= anx7625_write_or(bus, RX_P1_ADDR, 0xff, 0x01);
760 if (ret < 0)
761 return;
762
763 ret = anx7625_reg_read(bus, RX_P1_ADDR, 0x86, &val);
764 if (ret < 0)
765 return;
766
767 ANXINFO("Secure OCM version=%02x\n", val);
768}
769
770static int anx7625_hpd_change_detect(uint8_t bus)
771{
772 int ret;
773 uint8_t status;
774
775 ret = anx7625_reg_read(bus, RX_P0_ADDR, SYSTEM_STSTUS, &status);
776 if (ret < 0) {
777 ANXERROR("IO error: Failed to clear interrupt status.\n");
778 return ret;
779 }
780
781 if (status & HPD_STATUS) {
782 anx7625_start_dp_work(bus);
783 ANXINFO("HPD received 0x7e:0x45=%#x\n", status);
784 return 1;
785 }
786 return 0;
787}
788
789static void anx7625_parse_edid(const struct edid *edid,
790 struct display_timing *dt)
791{
792 dt->pixelclock = edid->mode.pixel_clock;
793
794 dt->hactive = edid->mode.ha;
795 dt->hsync_len = edid->mode.hspw;
796 dt->hback_porch = (edid->mode.hbl - edid->mode.hso -
797 edid->mode.hborder - edid->mode.hspw);
798 dt->hfront_porch = edid->mode.hso - edid->mode.hborder;
799
800 dt->vactive = edid->mode.va;
801 dt->vsync_len = edid->mode.vspw;
802 dt->vfront_porch = edid->mode.vso - edid->mode.vborder;
803 dt->vback_porch = (edid->mode.vbl - edid->mode.vso -
804 edid->mode.vspw - edid->mode.vborder);
805
Xin Ji48ae1112021-09-03 11:11:44 +0800806 /*
807 * The k_val is a ratio to match MIPI input and DP output video clocks.
808 * Most panels can follow the default value (0x3d).
809 * IVO panels have smaller variation than DP CTS spec and need smaller
810 * k_val (0x3b).
811 */
812 if (!strncmp(edid->manufacturer_name, "IVO", 3)) {
813 dt->k_val = 0x3b;
814 ANXINFO("detected IVO panel, use k value 0x3b\n");
815 } else {
816 dt->k_val = 0x3d;
817 ANXINFO("set default k value to 0x3d for panel\n");
818 }
819
Jitao Shi542919f2019-09-26 10:22:08 +0800820 ANXINFO("pixelclock(%d).\n"
821 " hactive(%d), hsync(%d), hfp(%d), hbp(%d)\n"
822 " vactive(%d), vsync(%d), vfp(%d), vbp(%d)\n",
823 dt->pixelclock,
824 dt->hactive, dt->hsync_len, dt->hfront_porch, dt->hback_porch,
825 dt->vactive, dt->vsync_len, dt->vfront_porch, dt->vback_porch);
826}
827
828int anx7625_dp_start(uint8_t bus, const struct edid *edid)
829{
830 int ret;
831 struct display_timing dt;
832
833 anx7625_parse_edid(edid, &dt);
834
835 ret = anx7625_dsi_config(bus, &dt);
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800836 if (ret < 0) {
Jitao Shi542919f2019-09-26 10:22:08 +0800837 ANXERROR("MIPI phy setup error.\n");
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800838 return ret;
839 }
Jitao Shi542919f2019-09-26 10:22:08 +0800840
Yu-Ping Wu0c9b1de2021-11-25 14:31:21 +0800841 ANXINFO("MIPI phy setup OK.\n");
842 return 0;
Jitao Shi542919f2019-09-26 10:22:08 +0800843}
844
845int anx7625_dp_get_edid(uint8_t bus, struct edid *out)
846{
847 int block_num;
848 int ret;
849 u8 edid[FOUR_BLOCK_SIZE];
850
851 block_num = sp_tx_edid_read(bus, edid, FOUR_BLOCK_SIZE);
852 if (block_num < 0) {
853 ANXERROR("Failed to get eDP EDID.\n");
854 return -1;
855 }
856
857 ret = decode_edid(edid, (block_num + 1) * ONE_BLOCK_SIZE, out);
858 if (ret != EDID_CONFORMANT) {
859 ANXERROR("Failed to decode EDID.\n");
860 return -1;
861 }
862
863 return 0;
864}
865
866int anx7625_init(uint8_t bus)
867{
868 int retry_hpd_change = 50;
Jitao Shi542919f2019-09-26 10:22:08 +0800869
Yu-Ping Wu734a7772021-11-25 16:28:13 +0800870 if (!retry(3, anx7625_power_on_init(bus) >= 0)) {
Jitao Shi542919f2019-09-26 10:22:08 +0800871 ANXERROR("Failed to power on.\n");
872 return -1;
873 }
874
875 while (--retry_hpd_change) {
876 mdelay(10);
877 int detected = anx7625_hpd_change_detect(bus);
878 if (detected < 0)
879 return -1;
880 if (detected > 0)
881 return 0;
882 }
883
884 ANXERROR("Timed out to detect HPD change on bus %d.\n", bus);
885 return -1;
886}