Move C labels to start-of-line
[coreboot.git] / src / southbridge / amd / cs5536 / early_smbus.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #include "cs5536.h"
21
22 #define SMBUS_ERROR -1
23 #define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
24 #define SMBUS_WAIT_UNTIL_DONE_TIMEOUT  -3
25 #define SMBUS_TIMEOUT (1000)
26
27 /* initialization for SMBus Controller */
28 static void cs5536_enable_smbus(void)
29 {
30
31         /* Set SCL freq and enable SMB controller */
32         /*outb((0x20 << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2); */
33         outb((0x7F << 1) | SMB_CTRL2_ENABLE, SMBUS_IO_BASE + SMB_CTRL2);
34
35         /* Setup SMBus host controller address to 0xEF */
36         outb((0xEF | SMB_ADD_SAEN), SMBUS_IO_BASE + SMB_ADD);
37
38 }
39
40 static void smbus_delay(void)
41 {
42         /* inb(0x80); */
43 }
44
45 static int smbus_wait(unsigned smbus_io_base)
46 {
47         unsigned long loops = SMBUS_TIMEOUT;
48         unsigned char val;
49
50         do {
51                 smbus_delay();
52                 val = inb(smbus_io_base + SMB_STS);
53                 if ((val & SMB_STS_SDAST) != 0)
54                         break;
55                 if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
56                         /*printk(BIOS_DEBUG, "SMBUS WAIT ERROR %x\n", val); */
57                         return SMBUS_ERROR;
58                 }
59         } while (--loops);
60         return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
61 }
62
63 /* generate a smbus start condition */
64 static int smbus_start_condition(unsigned smbus_io_base)
65 {
66         unsigned char val;
67
68         /* issue a START condition */
69         val = inb(smbus_io_base + SMB_CTRL1);
70         outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
71
72         /* check for bus conflict */
73         val = inb(smbus_io_base + SMB_STS);
74         if ((val & SMB_STS_BER) != 0)
75                 return SMBUS_ERROR;
76
77         return smbus_wait(smbus_io_base);
78 }
79
80 static int smbus_check_stop_condition(unsigned smbus_io_base)
81 {
82         unsigned char val;
83         unsigned long loops;
84         loops = SMBUS_TIMEOUT;
85         /* check for SDA status */
86         do {
87                 smbus_delay();
88                 val = inb(smbus_io_base + SMB_CTRL1);
89                 if ((val & SMB_CTRL1_STOP) == 0) {
90                         break;
91                 }
92                 outb((0x7F << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2);
93         } while (--loops);
94         return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
95 }
96
97 static int smbus_stop_condition(unsigned smbus_io_base)
98 {
99         outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
100         return smbus_wait(smbus_io_base);
101 }
102
103 static int smbus_ack(unsigned smbus_io_base, int state)
104 {
105         unsigned char val = inb(smbus_io_base + SMB_CTRL1);
106
107 /*      if (state) */
108         outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
109 /*      else
110                 outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
111 */
112         return 0;
113 }
114
115 static int smbus_send_slave_address(unsigned smbus_io_base,
116                                     unsigned char device)
117 {
118         unsigned char val;
119
120         /* send the slave address */
121         outb(device, smbus_io_base + SMB_SDA);
122
123         /* check for bus conflict and NACK */
124         val = inb(smbus_io_base + SMB_STS);
125         if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0)) {
126                 /* printk(BIOS_DEBUG, "SEND SLAVE ERROR (%x)\n", val); */
127                 return SMBUS_ERROR;
128         }
129         return smbus_wait(smbus_io_base);
130 }
131
132 static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
133 {
134         unsigned char val;
135
136         /* send the command */
137         outb(command, smbus_io_base + SMB_SDA);
138
139         /* check for bus conflict and NACK */
140         val = inb(smbus_io_base + SMB_STS);
141         if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0))
142                 return SMBUS_ERROR;
143
144         return smbus_wait(smbus_io_base);
145 }
146
147 static unsigned char smbus_get_result(unsigned smbus_io_base)
148 {
149         return inb(smbus_io_base + SMB_SDA);
150 }
151
152 static unsigned char do_smbus_read_byte(unsigned smbus_io_base,
153                                         unsigned char device,
154                                         unsigned char address)
155 {
156         unsigned char error = 0;
157
158         if ((smbus_check_stop_condition(smbus_io_base))) {
159                 error = 1;
160                 goto err;
161         }
162
163         if ((smbus_start_condition(smbus_io_base))) {
164                 error = 2;
165                 goto err;
166         }
167
168         if ((smbus_send_slave_address(smbus_io_base, device << 1))) {
169                 error = 3;
170                 goto err;
171         }
172
173         smbus_ack(smbus_io_base, 1);
174
175         if ((smbus_send_command(smbus_io_base, address))) {
176                 error = 4;
177                 goto err;
178         }
179
180         if ((smbus_start_condition(smbus_io_base))) {
181                 error = 5;
182                 goto err;
183         }
184
185         if ((smbus_send_slave_address(smbus_io_base, (device << 1) | 0x01))) {
186                 error = 6;
187                 goto err;
188         }
189
190         if ((smbus_stop_condition(smbus_io_base))) {
191                 error = 7;
192                 goto err;
193         }
194
195         return smbus_get_result(smbus_io_base);
196
197 err:
198         print_debug("SMBUS READ ERROR:");
199         print_debug_hex8(error);
200         print_debug(" device:");
201         print_debug_hex8(device);
202         print_debug("\n");
203         /* stop, clean up the error, and leave */
204         smbus_stop_condition(smbus_io_base);
205         outb(inb(smbus_io_base + SMB_STS), smbus_io_base + SMB_STS);
206         outb(0x0, smbus_io_base + SMB_STS);
207         return 0xFF;
208 }
209
210 static inline int smbus_read_byte(unsigned device, unsigned address)
211 {
212         return do_smbus_read_byte(SMBUS_IO_BASE, device, address);
213 }