xref: /aosp_15_r20/external/coreboot/src/drivers/aspeed/common/ast_i2c.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Copied from Linux drivers/gpu/drm/ast/ast_mode.c
4  */
5 #include <delay.h>
6 #include <device/i2c_simple.h>
7 
8 #include "ast_drv.h"
9 
10 static struct ast_private *ast;
11 
12 #define _GET_INDEX_REG(x) ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, (x))
13 #define ASPEED_BUS 0
14 
get_clock(unsigned int bus)15 static int get_clock(unsigned int bus)
16 {
17 	uint32_t val, val2, count, pass;
18 
19 	count = 0;
20 	pass = 0;
21 	val = (_GET_INDEX_REG(0x10) >> 4) & 0x01;
22 	do {
23 		val2 = (_GET_INDEX_REG(0x10) >> 4) & 0x01;
24 		if (val == val2) {
25 			pass++;
26 		} else {
27 			pass = 0;
28 			val = (_GET_INDEX_REG(0x10) >> 4) & 0x01;
29 		}
30 	} while ((pass < 5) && (count++ < 0x10000));
31 
32 	return val & 1 ? 1 : 0;
33 }
34 
get_data(unsigned int bus)35 static int get_data(unsigned int bus)
36 {
37 	uint32_t val, val2, count, pass;
38 
39 	count = 0;
40 	pass = 0;
41 	val = (_GET_INDEX_REG(0x20) >> 5) & 0x01;
42 	do {
43 		val2 = (_GET_INDEX_REG(0x20) >> 5) & 0x01;
44 		if (val == val2) {
45 			pass++;
46 		} else {
47 			pass = 0;
48 			val = (_GET_INDEX_REG(0x20) >> 5) & 0x01;
49 		}
50 	} while ((pass < 5) && (count++ < 0x10000));
51 
52 	return val & 1 ? 1 : 0;
53 }
54 
set_clock(unsigned int bus,int clock)55 static void set_clock(unsigned int bus, int clock)
56 {
57 	int i;
58 	u8 ujcrb7, jtemp;
59 
60 	for (i = 0; i < 0x10000; i++) {
61 		ujcrb7 = ((clock & 0x01) ? 0 : 1);
62 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, ujcrb7);
63 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
64 		if (ujcrb7 == jtemp)
65 			break;
66 	}
67 }
68 
set_data(unsigned int bus,int data)69 static void set_data(unsigned int bus, int data)
70 {
71 	int i;
72 	u8 ujcrb7, jtemp;
73 
74 	for (i = 0; i < 0x10000; i++) {
75 		ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
76 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, ujcrb7);
77 		jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
78 		if (ujcrb7 == jtemp)
79 			break;
80 	}
81 }
82 
83 static struct software_i2c_ops ast_ops = {
84 	.set_sda = set_data,
85 	.set_scl = set_clock,
86 	.get_sda = get_data,
87 	.get_scl = get_clock,
88 };
89 
ast_software_i2c_read(struct ast_private * ast_priv,uint8_t edid[128])90 int ast_software_i2c_read(struct ast_private *ast_priv, uint8_t edid[128])
91 {
92 	struct software_i2c_ops *backup;
93 	int ret;
94 
95 	backup = software_i2c[ASPEED_BUS];
96 
97 	software_i2c[ASPEED_BUS] = &ast_ops;
98 
99 	ast = ast_priv;
100 
101 	/* Ast POST pulled SDA and SCL low, recover the bus to a known state */
102 	set_clock(ASPEED_BUS, 1);
103 	set_data(ASPEED_BUS, 1);
104 
105 	udelay(100);
106 
107 	/* Need to reset internal EEPROM counter to 0 */
108 	ret = i2c_read_bytes(ASPEED_BUS, 0x50, 0, edid, 128);
109 
110 	software_i2c[ASPEED_BUS] = backup;
111 
112 	return ret;
113 }
114