1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
5 #include <device/i2c_simple.h>
13 #define ANXERROR(format, ...) \
14 printk(BIOS_ERR, "%s: " format, __func__, ##__VA_ARGS__)
15 #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__)
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.
25 static int i2c_access_workaround(uint8_t bus
, uint8_t saddr
)
28 static uint8_t saddr_backup
= 0;
31 if (saddr
== saddr_backup
)
37 case TCPC_INTERFACE_ADDR
:
38 offset
= RSVD_00_ADDR
;
41 offset
= RSVD_D1_ADDR
;
44 offset
= RSVD_60_ADDR
;
47 offset
= RSVD_39_ADDR
;
50 offset
= RSVD_7F_ADDR
;
53 offset
= RSVD_00_ADDR
;
57 ret
= i2c_writeb(bus
, saddr
, offset
, 0x00);
59 ANXERROR("Failed to access %#x:%#x\n", saddr
, offset
);
65 static int anx7625_reg_read(uint8_t bus
, uint8_t saddr
, uint8_t offset
,
70 i2c_access_workaround(bus
, saddr
);
71 ret
= i2c_readb(bus
, saddr
, offset
, val
);
73 ANXERROR("Failed to read i2c reg=%#x:%#x\n", saddr
, offset
);
79 static int anx7625_reg_block_read(uint8_t bus
, uint8_t saddr
, uint8_t reg_addr
,
80 uint8_t len
, uint8_t *buf
)
84 i2c_access_workaround(bus
, saddr
);
85 ret
= i2c_read_bytes(bus
, saddr
, reg_addr
, buf
, len
);
87 ANXERROR("Failed to read i2c block=%#x:%#x[len=%#x]\n", saddr
,
94 static int anx7625_reg_write(uint8_t bus
, uint8_t saddr
, uint8_t reg_addr
,
99 i2c_access_workaround(bus
, saddr
);
100 ret
= i2c_writeb(bus
, saddr
, reg_addr
, reg_val
);
102 ANXERROR("Failed to write i2c id=%#x:%#x\n", saddr
, reg_addr
);
108 static int anx7625_write_or(uint8_t bus
, uint8_t saddr
, uint8_t offset
,
114 ret
= anx7625_reg_read(bus
, saddr
, offset
, &val
);
118 return anx7625_reg_write(bus
, saddr
, offset
, val
| mask
);
121 static int anx7625_write_and(uint8_t bus
, uint8_t saddr
, uint8_t offset
,
127 ret
= anx7625_reg_read(bus
, saddr
, offset
, &val
);
131 return anx7625_reg_write(bus
, saddr
, offset
, val
& mask
);
134 static int wait_aux_op_finish(uint8_t bus
)
140 (anx7625_reg_read(bus
, RX_P0_ADDR
, AP_AUX_CTRL_STATUS
, &val
),
141 !(val
& AP_AUX_CTRL_OP_EN
)), mdelay(2))) {
142 ANXERROR("Timed out waiting aux operation.\n");
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
);
155 static unsigned long gcd(unsigned long a
, unsigned long b
)
170 /* Reduce fraction a/b */
171 static void anx7625_reduction_of_a_fraction(unsigned long *_a
,
174 unsigned long gcd_num
;
175 unsigned long a
= *_a
, b
= *_b
, old_a
, old_b
;
185 while (a
> MAX_UNSIGNED_24BIT
|| b
> MAX_UNSIGNED_24BIT
) {
191 /* Increase a, b to have higher ODFC PLL output frequency accuracy. */
192 while ((a
<< 1) < MAX_UNSIGNED_24BIT
&& (b
<< 1) < MAX_UNSIGNED_24BIT
) {
201 static int anx7625_calculate_m_n(u32 pixelclock
,
202 unsigned long *m
, unsigned long *n
,
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
);
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
);
224 for (post_divider
= 1;
225 pixelclock
< PLL_OUT_FREQ_MIN
/ post_divider
;
229 if (post_divider
> POST_DIVIDER_MAX
) {
230 for (post_divider
= 1;
231 pixelclock
< PLL_OUT_FREQ_ABS_MIN
/ post_divider
;
235 if (post_divider
> POST_DIVIDER_MAX
) {
236 ANXERROR("cannot find property post_divider(%d)\n",
242 /* Patch to improve the accuracy */
243 if (post_divider
== 7) {
244 /* 27,000,000 is not divisible by 7 */
246 } else if (post_divider
== 11) {
247 /* 27,000,000 is not divisible by 11 */
249 } else if (post_divider
== 13 || post_divider
== 14) {
250 /*27,000,000 is not divisible by 13 or 14*/
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
);
261 *n
= XTAL_FRQ
/ post_divider
;
264 anx7625_reduction_of_a_fraction(m
, n
);
269 static int anx7625_odfc_config(uint8_t bus
, uint8_t post_divider
)
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
));
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
,
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
);
288 ret
|= anx7625_write_and(bus
, RX_P1_ADDR
, MIPI_DIGITAL_PLL_7
,
290 ret
|= anx7625_write_or(bus
, RX_P1_ADDR
, MIPI_DIGITAL_PLL_7
,
294 ANXERROR("IO error.\n");
301 static int anx7625_dsi_video_config(uint8_t bus
, struct display_timing
*dt
)
306 uint8_t post_divider
= 0;
308 if (anx7625_calculate_m_n(dt
->pixelclock
* 1000, &m
, &n
,
309 &post_divider
) < 0) {
310 ANXERROR("cannot get property m n value.\n");
314 ANXINFO("compute M(%lu), N(%lu), divider(%d).\n", m
, n
, post_divider
);
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);
322 ret
|= anx7625_write_and(bus
, RX_P1_ADDR
, MIPI_LANE_CTRL_0
, 0xfc);
324 ret
|= anx7625_write_or(bus
, RX_P1_ADDR
, MIPI_LANE_CTRL_0
, 3);
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);
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);
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);
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);
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);
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
,
359 ret
|= anx7625_reg_write(bus
, RX_P2_ADDR
,
360 VERTICAL_FRONT_PORCH
, dt
->vfront_porch
);
362 ret
|= anx7625_reg_write(bus
, RX_P2_ADDR
,
363 VERTICAL_SYNC_WIDTH
, dt
->vsync_len
);
365 ret
|= anx7625_reg_write(bus
, RX_P2_ADDR
,
366 VERTICAL_BACK_PORCH
, dt
->vback_porch
);
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));
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
,
382 ret
|= anx7625_reg_write(bus
, RX_P1_ADDR
, MIPI_DIGITAL_ADJ_1
, dt
->k_val
);
384 ret
|= anx7625_odfc_config(bus
, post_divider
- 1);
387 ANXERROR("mipi dsi setup IO error.\n");
394 static int anx7625_swap_dsi_lane3(uint8_t bus
)
399 /* swap MIPI-DSI data lane 3 P and N */
400 ret
= anx7625_reg_read(bus
, RX_P1_ADDR
, MIPI_SWAP
, &val
);
402 ANXERROR("IO error: access MIPI_SWAP.\n");
406 val
|= (1 << MIPI_SWAP_CH3
);
407 return anx7625_reg_write(bus
, RX_P1_ADDR
, MIPI_SWAP
, val
);
410 static int anx7625_api_dsi_config(uint8_t bus
, struct display_timing
*dt
)
415 /* swap MIPI-DSI data lane 3 P and N */
416 ret
= anx7625_swap_dsi_lane3(bus
);
418 ANXERROR("IO error: swap dsi lane 3 failed.\n");
422 /* DSI clock settings */
423 val
= (0 << MIPI_HS_PWD_CLK
) |
424 (0 << MIPI_HS_RT_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
);
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
439 ret
|= anx7625_reg_write(bus
, RX_P1_ADDR
, MIPI_TIME_HS_PRPR
, 0x10);
441 /* enable DSI mode */
442 ret
|= anx7625_write_or(bus
, RX_P1_ADDR
, MIPI_DIGITAL_PLL_18
,
443 SELECT_DSI
<< MIPI_DPI_SELECT
);
445 ret
|= anx7625_dsi_video_config(bus
, dt
);
447 ANXERROR("dsi video tg config failed\n");
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
));
455 ret
|= anx7625_write_or(bus
, RX_P1_ADDR
, MIPI_DIGITAL_PLL_6
,
456 MIPI_M_NUM_READY
| MIPI_N_NUM_READY
);
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);
465 ANXERROR("IO error: mipi dsi enable init failed.\n");
472 static int anx7625_dsi_config(uint8_t bus
, struct display_timing
*dt
)
476 ANXINFO("config dsi.\n");
479 ret
= anx7625_write_and(bus
, RX_P0_ADDR
, R_DSC_CTRL_0
, ~DSC_EN
);
480 ret
|= anx7625_api_dsi_config(bus
, dt
);
483 ANXERROR("IO error: api dsi config error.\n");
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
);
493 ANXERROR("IO error: enable mipi rx failed.\n");
497 ANXINFO("success to config DSI\n");
501 static int sp_tx_rst_aux(uint8_t bus
)
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
);
510 static int sp_tx_aux_wr(uint8_t bus
, uint8_t offset
)
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
);
521 static int sp_tx_aux_rd(uint8_t bus
, uint8_t len_cmd
)
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
);
531 static int sp_tx_get_edid_block(uint8_t bus
)
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
);
541 ANXERROR("IO error: access AUX BUFF.\n");
545 ANXINFO("EDID Block = %d\n", val
+ 1);
553 static int edid_read(uint8_t bus
, uint8_t offset
, uint8_t *pblock_buf
)
557 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 */
560 ret
= sp_tx_aux_rd(bus
, 0xf1);
564 ANXERROR("edid read failed, reset!\n");
566 if (anx7625_reg_block_read(bus
, RX_P0_ADDR
,
568 MAX_DPCD_BUFFER_SIZE
,
577 static int segments_edid_read(uint8_t bus
, uint8_t segment
, uint8_t *buf
,
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
);
588 ret
|= wait_aux_op_finish(bus
);
589 /* write segment address */
590 ret
|= sp_tx_aux_wr(bus
, segment
);
592 ret
|= anx7625_reg_write(bus
, RX_P0_ADDR
, AP_AUX_ADDR_7_0
, 0x50);
595 ANXERROR("IO error: aux initial failed.\n");
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 */
602 ret
= sp_tx_aux_rd(bus
, 0xf1);
606 ANXERROR("segment read failed, reset!\n");
608 if (anx7625_reg_block_read(bus
, RX_P0_ADDR
,
610 MAX_DPCD_BUFFER_SIZE
,
619 static int sp_tx_edid_read(uint8_t bus
, uint8_t *pedid_blocks_buf
,
622 uint8_t offset
, edid_pos
;
623 int count
, blocks_num
;
624 uint8_t pblock_buf
[MAX_DPCD_BUFFER_SIZE
];
625 int i
, ret
, g_edid_break
= 0;
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);
633 ANXERROR("access aux channel IO error.\n");
637 blocks_num
= sp_tx_get_edid_block(bus
);
647 for (i
= 0; i
< 8; i
++) {
648 offset
= (i
+ count
* 8) * MAX_DPCD_BUFFER_SIZE
;
649 g_edid_break
= !!edid_read(bus
, offset
,
655 if (offset
<= size
- MAX_DPCD_BUFFER_SIZE
)
656 memcpy(&pedid_blocks_buf
[offset
],
658 MAX_DPCD_BUFFER_SIZE
);
664 offset
= (count
== 2) ? 0x00 : 0x80;
666 for (i
= 0; i
< 8; i
++) {
667 edid_pos
= (i
+ count
* 8) *
668 MAX_DPCD_BUFFER_SIZE
;
673 segments_edid_read(bus
, count
/ 2,
675 if (edid_pos
<= size
- MAX_DPCD_BUFFER_SIZE
)
676 memcpy(&pedid_blocks_buf
[edid_pos
],
678 MAX_DPCD_BUFFER_SIZE
);
679 offset
= offset
+ 0x10;
684 die("%s: count should be <= 3", __func__
);
690 } while (blocks_num
>= count
);
692 /* reset aux channel */
698 static void anx7625_disable_pd_protocol(uint8_t bus
)
703 ret
= anx7625_reg_write(bus
, RX_P0_ADDR
, 0x88, 0x40);
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);
710 ANXERROR("Failed to disable PD feature.\n");
712 ANXINFO("Disabled PD feature.\n");
715 #define FLASH_LOAD_STA 0x05
716 #define FLASH_LOAD_STA_CHK (1 << 7)
718 static int anx7625_power_on_init(uint8_t bus
)
721 uint8_t val
, version
, revision
;
723 anx7625_reg_write(bus
, RX_P0_ADDR
, XTAL_FRQ_SEL
, XTAL_FRQ_27M
);
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
);
729 ANXERROR("Failed to load flash\n");
733 if ((val
& FLASH_LOAD_STA_CHK
) != FLASH_LOAD_STA_CHK
) {
737 ANXINFO("Init interface.\n");
739 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
);
748 static void anx7625_start_dp_work(uint8_t bus
)
753 /* not support HDCP */
754 ret
= anx7625_write_and(bus
, RX_P1_ADDR
, 0xee, 0x9f);
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);
763 ret
= anx7625_reg_read(bus
, RX_P1_ADDR
, 0x86, &val
);
767 ANXINFO("Secure OCM version=%02x\n", val
);
770 static int anx7625_hpd_change_detect(uint8_t bus
)
775 ret
= anx7625_reg_read(bus
, RX_P0_ADDR
, SYSTEM_STSTUS
, &status
);
777 ANXERROR("IO error: Failed to clear interrupt status.\n");
781 if (status
& HPD_STATUS
) {
782 anx7625_start_dp_work(bus
);
783 ANXINFO("HPD received 0x7e:0x45=%#x\n", status
);
789 static void anx7625_parse_edid(const struct edid
*edid
,
790 struct display_timing
*dt
)
792 dt
->pixelclock
= edid
->mode
.pixel_clock
;
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
;
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
);
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
812 if (!strncmp(edid
->manufacturer_name
, "IVO", 3)) {
814 ANXINFO("detected IVO panel, use k value 0x3b\n");
817 ANXINFO("set default k value to 0x3d for panel\n");
820 ANXINFO("pixelclock(%d).\n"
821 " hactive(%d), hsync(%d), hfp(%d), hbp(%d)\n"
822 " vactive(%d), vsync(%d), vfp(%d), vbp(%d)\n",
824 dt
->hactive
, dt
->hsync_len
, dt
->hfront_porch
, dt
->hback_porch
,
825 dt
->vactive
, dt
->vsync_len
, dt
->vfront_porch
, dt
->vback_porch
);
828 int anx7625_dp_start(uint8_t bus
, const struct edid
*edid
)
831 struct display_timing dt
;
833 anx7625_parse_edid(edid
, &dt
);
835 ret
= anx7625_dsi_config(bus
, &dt
);
837 ANXERROR("MIPI phy setup error.\n");
841 ANXINFO("MIPI phy setup OK.\n");
845 int anx7625_dp_get_edid(uint8_t bus
, struct edid
*out
)
849 u8 edid
[FOUR_BLOCK_SIZE
];
851 block_num
= sp_tx_edid_read(bus
, edid
, FOUR_BLOCK_SIZE
);
853 ANXERROR("Failed to get eDP EDID.\n");
857 ret
= decode_edid(edid
, (block_num
+ 1) * ONE_BLOCK_SIZE
, out
);
858 if (ret
!= EDID_CONFORMANT
) {
859 ANXERROR("Failed to decode EDID.\n");
866 int anx7625_init(uint8_t bus
)
868 int retry_hpd_change
= 50;
870 if (!retry(3, anx7625_power_on_init(bus
) >= 0)) {
871 ANXERROR("Failed to power on.\n");
875 while (--retry_hpd_change
) {
877 int detected
= anx7625_hpd_change_detect(bus
);
884 ANXERROR("Timed out to detect HPD change on bus %d.\n", bus
);