summaryrefslogtreecommitdiff
path: root/src/southbridge/amd/cs5535/cs5535_smbus.h
blob: 9cf55ba29c71e190a0abc788d4eff701d2d569cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//#include <device/smbus_def.h>
#define SMBUS_ERROR -1
#define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
#define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3

#define	SMB_SDA		0x00
#define SMB_STS		0x01
#define SMB_CTRL_STS	0x02
#define	SMB_CTRL1	0x03
#define SMB_ADD		0x04
#define SMB_CTRL2	0x05
#define	SMB_CTRL3	0x06

#define SMB_STS_SLVSTP	(0x01 << 7)
#define SMB_STS_SDAST	(0x01 << 6)
#define	SMB_STS_BER	(0x01 << 5)
#define SMB_STS_NEGACK	(0x01 << 4)
#define	SMB_STS_STASTR	(0x01 << 3)
#define SMB_STS_NMATCH	(0x01 << 2)
#define	SMB_STS_MASTER	(0x01 << 1)
#define SMB_STS_XMIT	(0x01 << 0)

#define	SMB_CSTS_TGSCL	(0x01 << 5)
#define SMB_CSTS_TSDA	(0x01 << 4)
#define	SMB_CSTS_GCMTCH	(0x01 << 3)
#define SMB_CSTS_MATCH	(0x01 << 2)
#define	SMB_CSTS_BB	(0x01 << 1)
#define SMB_CSTS_BUSY	(0x01 << 0)

#define	SMB_CTRL1_STASTRE (0x01 << 7)
#define SMB_CTRL1_NMINTE  (0x01 << 6)
#define	SMB_CTRL1_GCMEN   (0x01 << 5)
#define SMB_CTRL1_ACK     (0x01 << 4)
#define	SMB_CTRL1_RSVD    (0x01 << 3)
#define SMB_CTRL1_INTEN   (0x01 << 2)
#define	SMB_CTRL1_STOP    (0x01 << 1)
#define SMB_CTRL1_START   (0x01 << 0)

#define	SMB_ADD_SAEN	  (0x01 << 7)

#define	SMB_CTRL2_ENABLE  0x01

#define SMBUS_TIMEOUT (100*1000*10)
#define SMBUS_STATUS_MASK 0xfbff

#define SMBUS_IO_BASE 0x6000

static void smbus_delay(void)
{
    	outb(0x80, 0x80);
}

/* generate a smbus start condition */
static int smbus_start_condition(unsigned smbus_io_base)
{
	unsigned char val;
	unsigned long loops;
	loops = SMBUS_TIMEOUT;

	/* issue a START condition */
	val = inb(smbus_io_base + SMB_CTRL1);
	outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);

	/* check for bus conflict */
	val = inb(smbus_io_base + SMB_STS);
	if ((val & SMB_STS_BER) != 0)
		return SMBUS_ERROR;

	/* check for SDA status */
	do {
		smbus_delay();
		val = inw(smbus_io_base + SMB_STS);
		if ((val & SMB_STS_SDAST) != 0) {
			break;
		}
	} while(--loops);
	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
}

static int smbus_check_stop_condition(unsigned smbus_io_base)
{
	unsigned char val;
	unsigned long loops;
	loops = SMBUS_TIMEOUT;
	/* check for SDA status */
	do {
		smbus_delay();
		val = inw(smbus_io_base + SMB_CTRL1);
		if ((val & SMB_CTRL1_STOP) == 0) {
			break;
		}
	} while(--loops);
	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
}

static int smbus_stop_condition(unsigned smbus_io_base)
{
	unsigned char val;
	val = inb(smbus_io_base + SMB_CTRL1);
	outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
}

static int smbus_send_slave_address(unsigned smbus_io_base, unsigned char device)
{
	unsigned char val;
	unsigned long loops;
	loops = SMBUS_TIMEOUT;
                        
	/* send the slave address */
	outb(device, smbus_io_base + SMB_SDA);

	/* check for bus conflict and NACK */
	val = inb(smbus_io_base + SMB_STS);
	if (((val & SMB_STS_BER)    != 0) ||
	    ((val & SMB_STS_NEGACK) != 0))
		return SMBUS_ERROR;

	/* check for SDA status */
	do {
		smbus_delay();
		val = inw(smbus_io_base + SMB_STS);
		if ((val & SMB_STS_SDAST) != 0) {
			break;
		}
	} while(--loops);
	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;	
}

static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
{
        unsigned char val;
	unsigned long loops;
	loops = SMBUS_TIMEOUT;

	/* send the command */
	outb(command, smbus_io_base + SMB_SDA);

	/* check for bus conflict and NACK */
	val = inb(smbus_io_base + SMB_STS);
	if (((val & SMB_STS_BER)    != 0) ||
	    ((val & SMB_STS_NEGACK) != 0))
		return SMBUS_ERROR;

	/* check for SDA status */
	do {
		smbus_delay();
		val = inw(smbus_io_base + SMB_STS);
		if ((val & SMB_STS_SDAST) != 0) {
			break;
		}
	} while(--loops);
	return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;	
}

static unsigned char do_smbus_read_byte(unsigned smbus_io_base, unsigned char device, unsigned char address)
{
	unsigned char val, val1;

	smbus_check_stop_condition(smbus_io_base);

	smbus_start_condition(smbus_io_base);

	smbus_send_slave_address(smbus_io_base, device);

	smbus_send_command(smbus_io_base, address);

	smbus_start_condition(smbus_io_base);

	smbus_send_slave_address(smbus_io_base, device | 0x01);

	/* send NACK to slave */
	val = inb(smbus_io_base + SMB_CTRL1);
	outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);

	val = inb(smbus_io_base + SMB_SDA);

	//smbus_stop_condition(smbus_io_base);

	return val;
}