xref: /aosp_15_r20/external/coreboot/src/soc/qualcomm/sc7280/display/edp_aux.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <device/mmio.h>
4 #include <console/console.h>
5 #include <edid.h>
6 #include <timer.h>
7 #include <types.h>
8 #include <soc/display/edp_aux.h>
9 #include <soc/display/edp_reg.h>
10 
11 #define AUX_CMD_FIFO_LEN		144
12 #define AUX_CMD_NATIVE_MAX		16
13 #define AUX_CMD_I2C_MAX			128
14 #define AUX_INTR_I2C_DONE		BIT(0)
15 #define AUX_INTR_WRONG_ADDR		BIT(1)
16 #define AUX_INTR_CONSECUTIVE_TIMEOUT	BIT(2)
17 #define AUX_INTR_CONSECUTIVE_NACK_DEFER	BIT(3)
18 #define AUX_INTR_WRONG_RD_DATA_CNT	BIT(4)
19 #define AUX_INTR_NACK_I2C		BIT(5)
20 #define AUX_INTR_DEFER_I2C		BIT(6)
21 #define AUX_INTR_DPPHY_AUX_ERR		BIT(7)
22 #define EDP_AUX_INTERRUPT		(AUX_INTR_I2C_DONE | AUX_INTR_WRONG_ADDR | \
23 					AUX_INTR_CONSECUTIVE_TIMEOUT | \
24 					AUX_INTR_CONSECUTIVE_NACK_DEFER | \
25 					AUX_INTR_WRONG_RD_DATA_CNT | AUX_INTR_DEFER_I2C | \
26 					AUX_INTR_NACK_I2C | AUX_INTR_DPPHY_AUX_ERR)
27 
edp_wait_for_aux_done(void)28 static void edp_wait_for_aux_done(void)
29 {
30 	u32 intr_status = 0;
31 
32 	if (!wait_ms(100, read32(&edp_auxclk->status) & EDP_AUX_INTERRUPT)) {
33 		printk(BIOS_ERR, "AUX SEND not acknowledged\n");
34 		return;
35 	}
36 
37 	intr_status = read32(&edp_auxclk->status);
38 	if (!(intr_status & AUX_INTR_I2C_DONE)) {
39 		printk(BIOS_ERR, "AUX command failed, status = %#x\n", intr_status);
40 		return;
41 	}
42 
43 	write32(&edp_ahbclk->interrupt_status, 0x0);
44 }
45 
edp_msg_fifo_tx(unsigned int address,u8 request,void * buffer,size_t size)46 static int edp_msg_fifo_tx(unsigned int address, u8 request, void *buffer, size_t size)
47 {
48 	u32 data[4];
49 	u32 reg, len;
50 	bool native = (request == DP_AUX_NATIVE_WRITE) || (request == DP_AUX_NATIVE_READ);
51 	bool read = (request == DP_AUX_I2C_READ) || (request == DP_AUX_NATIVE_READ);
52 	u8 *msgdata = buffer;
53 	int i;
54 
55 	if (read)
56 		len = 4;
57 	else
58 		len = size + 4;
59 
60 	/*
61 	 * cmd fifo only has depth of 144 bytes
62 	 */
63 	if (len > AUX_CMD_FIFO_LEN)
64 		return -1;
65 
66 	/* Pack cmd and write to HW */
67 	data[0] = (address >> 16) & 0xf;	/* addr[19:16] */
68 	if (read)
69 		data[0] |=  AUX_CMD_READ;		/* R/W */
70 
71 	data[1] = (address >> 8) & 0xff;	/* addr[15:8] */
72 	data[2] = address & 0xff;		/* addr[7:0] */
73 	data[3] = (size - 1) & 0xff;		/* len[7:0] */
74 
75 	for (i = 0; i < len; i++) {
76 		reg = (i < 4) ? data[i] : msgdata[i - 4];
77 		reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
78 		if (i == 0)
79 			reg |= EDP_AUX_DATA_INDEX_WRITE;
80 		write32(&edp_auxclk->aux_data, reg);
81 	}
82 
83 	/* clear old aux transaction control */
84 	write32(&edp_auxclk->aux_trans_ctrl, 0);
85 	reg = RX_STOP_ERR | RX_DEC_ERR | RX_SYNC_ERR | RX_ALIGN_ERR | TX_REQ_ERR;
86 	write32(&edp_phy->aux_interrupt_clr, reg);
87 	write32(&edp_phy->aux_interrupt_clr, reg | GLOBE_REQ_CLR);
88 	write32(&edp_phy->aux_interrupt_clr, 0x0);
89 
90 	reg = 0; /* Transaction number is always 1 */
91 	if (!native) /* i2c */
92 		reg |= EDP_AUX_TRANS_CTRL_I2C | EDP_AUX_TRANS_CTRL_NO_SEND_ADDR |
93 			EDP_AUX_TRANS_CTRL_NO_SEND_STOP;
94 
95 	reg |= EDP_AUX_TRANS_CTRL_GO;
96 	write32(&edp_auxclk->aux_trans_ctrl, reg);
97 	edp_wait_for_aux_done();
98 
99 	return 0;
100 }
101 
edp_msg_fifo_rx(void * buffer,size_t size)102 static int edp_msg_fifo_rx(void *buffer, size_t size)
103 {
104 	u32 data;
105 	u8 *dp;
106 	int i;
107 	u32 len = size;
108 
109 	clrbits32(&edp_auxclk->aux_trans_ctrl, EDP_AUX_TRANS_CTRL_GO);
110 	write32(&edp_auxclk->aux_data,
111 		EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
112 
113 	dp = buffer;
114 
115 	/* discard first byte */
116 	data = read32(&edp_auxclk->aux_data);
117 	for (i = 0; i < len; i++) {
118 		data = read32(&edp_auxclk->aux_data);
119 		dp[i] = (u8)((data >> 8) & 0xff);
120 	}
121 
122 	return 0;
123 }
124 
edp_aux_transfer(unsigned int address,u8 request,void * buffer,size_t size)125 ssize_t edp_aux_transfer(unsigned int address, u8 request, void *buffer, size_t size)
126 {
127 	ssize_t ret;
128 	bool native = (request == DP_AUX_NATIVE_WRITE) || (request == DP_AUX_NATIVE_READ);
129 	bool read = (request == DP_AUX_I2C_READ) || (request == DP_AUX_NATIVE_READ);
130 
131 	/* Ignore address only message */
132 	if ((size == 0) || (buffer == NULL)) {
133 		printk(BIOS_ERR, "%s: invalid size or buffer\n", __func__);
134 		return size;
135 	}
136 
137 	/* msg sanity check */
138 	if ((native && (size > AUX_CMD_NATIVE_MAX)) ||
139 		(size > AUX_CMD_I2C_MAX)) {
140 		printk(BIOS_ERR, "%s: invalid msg: size(%zu), request(%x)\n",
141 		       __func__, size, request);
142 		return -1;
143 	}
144 
145 	ret = edp_msg_fifo_tx(address, request, buffer, size);
146 	if (ret < 0) {
147 		printk(BIOS_ERR, "edp aux transfer tx failed\n");
148 		return ret;
149 	}
150 
151 	if (read) {
152 		ret = edp_msg_fifo_rx(buffer, size);
153 		if (ret < 0) {
154 			printk(BIOS_ERR, "edp aux transfer rx failed\n");
155 			return ret;
156 		}
157 	}
158 
159 	/* Return requested size for success or retry */
160 	ret = size;
161 
162 	return ret;
163 }
164 
edp_read_edid(struct edid * out)165 int edp_read_edid(struct edid *out)
166 {
167 	int err;
168 	u8 edid[EDID_LENGTH * 2];
169 	int edid_size = EDID_LENGTH;
170 
171 	uint8_t reg_addr = 0;
172 	err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_WRITE, &reg_addr, 1);
173 	if (err > 0)
174 		err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_READ, edid, EDID_LENGTH);
175 
176 	if (err < EDID_LENGTH) {
177 		printk(BIOS_ERR, "Failed to read EDID. :%d\n", err);
178 		return err;
179 	}
180 
181 	if (edid[EDID_EXTENSION_FLAG]) {
182 		printk(BIOS_ERR, " read EDID ext block.\n");
183 		edid_size += EDID_LENGTH;
184 		reg_addr = EDID_LENGTH;
185 		err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_WRITE, &reg_addr, 1);
186 		if (err > 0)
187 			err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_READ,
188 					       &edid[EDID_LENGTH], EDID_LENGTH);
189 
190 		if (err < EDID_LENGTH) {
191 			printk(BIOS_ERR, "Failed to read EDID ext block.\n");
192 			return err;
193 		}
194 	}
195 
196 	if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
197 		printk(BIOS_ERR, "Failed to decode EDID.\n");
198 		return CB_ERR;
199 	}
200 
201 
202 	return CB_SUCCESS;
203 }
204 
edp_aux_ctrl(int enable)205 void edp_aux_ctrl(int enable)
206 {
207 	u32 data;
208 	data = read32(&edp_auxclk->aux_ctrl);
209 
210 	if (!enable) {
211 		data &= ~EDP_AUX_CTRL_ENABLE;
212 		write32(&edp_auxclk->aux_ctrl, data);
213 		return;
214 	}
215 
216 	data |= EDP_AUX_CTRL_RESET;
217 	write32(&edp_auxclk->aux_ctrl, data);
218 
219 	data &= ~EDP_AUX_CTRL_RESET;
220 	write32(&edp_auxclk->aux_ctrl, data);
221 
222 	write32(&edp_auxclk->timeout_count, 0xffff);
223 	write32(&edp_auxclk->aux_limits, 0xffff);
224 
225 	data |= EDP_AUX_CTRL_ENABLE;
226 	write32(&edp_auxclk->aux_ctrl, data);
227 }
228