blob: 53b0a13977b262a019b15fac4b6ef8030b7c02a8 [file] [log] [blame]
Frank Vibrans63e62b02011-02-14 18:38:14 +00001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 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 as published by
8 * the Free Software Foundation; version 2 of the License.
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.
Frank Vibrans63e62b02011-02-14 18:38:14 +000014 */
15
16
17#include <arch/io.h>
18#include "smbus.h"
Kerry Shefeed3292011-08-18 18:03:44 +080019#include <console/console.h> /* printk */
Frank Vibrans63e62b02011-02-14 18:38:14 +000020
Frank Vibrans63e62b02011-02-14 18:38:14 +000021static int smbus_wait_until_ready(u32 smbus_io_base)
22{
23 u32 loops;
24
25 loops = SMBUS_TIMEOUT;
26 do {
27 u8 val;
28 val = inb(smbus_io_base + SMBHSTSTAT);
29 val &= 0x1f;
30 if (val == 0) { /* ready now */
31 return 0;
32 }
33 outb(val, smbus_io_base + SMBHSTSTAT);
34 } while (--loops);
35
36 return -2; /* time out */
37}
38
39static int smbus_wait_until_done(u32 smbus_io_base)
40{
41 u32 loops;
42
43 loops = SMBUS_TIMEOUT;
44 do {
45 u8 val;
46
47 val = inb(smbus_io_base + SMBHSTSTAT);
48 val &= 0x1f; /* mask off reserved bits */
49 if (val & 0x1c) {
50 return -5; /* error */
51 }
52 if (val == 0x02) {
53 outb(val, smbus_io_base + SMBHSTSTAT); /* clear status */
54 return 0;
55 }
56 } while (--loops);
57
58 return -3; /* timeout */
59}
60
61int do_smbus_recv_byte(u32 smbus_io_base, u32 device)
62{
63 u8 byte;
64
65 if (smbus_wait_until_ready(smbus_io_base) < 0) {
Elyes HAOUASba28e8d2016-08-31 19:22:16 +020066 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_recv_byte - smbus not ready.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +000067 return -2; /* not ready */
68 }
69
Kerry Shefeed3292011-08-18 18:03:44 +080070 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_recv_byte - Start.\n");
Jonathan Neuschäfer70903772017-09-23 21:39:02 +020071 /* set the device I'm talking to */
Frank Vibrans63e62b02011-02-14 18:38:14 +000072 outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
73
74 byte = inb(smbus_io_base + SMBHSTCTRL);
75 byte &= 0xe3; /* Clear [4:2] */
76 byte |= (1 << 2) | (1 << 6); /* Byte data read/write command, start the command */
77 outb(byte, smbus_io_base + SMBHSTCTRL);
78
79 /* poll for transaction completion */
80 if (smbus_wait_until_done(smbus_io_base) < 0) {
81 return -3; /* timeout or error */
82 }
83
84 /* read results of transaction */
85 byte = inb(smbus_io_base + SMBHSTCMD);
86
Kerry Shefeed3292011-08-18 18:03:44 +080087 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_recv_byte - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +000088 return byte;
89}
90
91int do_smbus_send_byte(u32 smbus_io_base, u32 device, u8 val)
92{
93 u8 byte;
94
95 if (smbus_wait_until_ready(smbus_io_base) < 0) {
Elyes HAOUASba28e8d2016-08-31 19:22:16 +020096 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_send_byte - smbus not ready.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +000097 return -2; /* not ready */
98 }
99
Kerry Shefeed3292011-08-18 18:03:44 +0800100 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_send_byte - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000101 /* set the command... */
102 outb(val, smbus_io_base + SMBHSTCMD);
103
Jonathan Neuschäfer70903772017-09-23 21:39:02 +0200104 /* set the device I'm talking to */
Frank Vibrans63e62b02011-02-14 18:38:14 +0000105 outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
106
107 byte = inb(smbus_io_base + SMBHSTCTRL);
108 byte &= 0xe3; /* Clear [4:2] */
109 byte |= (1 << 2) | (1 << 6); /* Byte data read/write command, start the command */
110 outb(byte, smbus_io_base + SMBHSTCTRL);
111
112 /* poll for transaction completion */
113 if (smbus_wait_until_done(smbus_io_base) < 0) {
114 return -3; /* timeout or error */
115 }
116
Kerry Shefeed3292011-08-18 18:03:44 +0800117 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_send_byte - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000118 return 0;
119}
120
121int do_smbus_read_byte(u32 smbus_io_base, u32 device, u32 address)
122{
123 u8 byte;
124
125 if (smbus_wait_until_ready(smbus_io_base) < 0) {
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200126 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_read_byte - smbus not ready.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000127 return -2; /* not ready */
128 }
129
Kerry Shefeed3292011-08-18 18:03:44 +0800130 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_read_byte - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000131 /* set the command/address... */
132 outb(address & 0xff, smbus_io_base + SMBHSTCMD);
133
Jonathan Neuschäfer70903772017-09-23 21:39:02 +0200134 /* set the device I'm talking to */
Frank Vibrans63e62b02011-02-14 18:38:14 +0000135 outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
136
137 byte = inb(smbus_io_base + SMBHSTCTRL);
138 byte &= 0xe3; /* Clear [4:2] */
139 byte |= (1 << 3) | (1 << 6); /* Byte data read/write command, start the command */
140 outb(byte, smbus_io_base + SMBHSTCTRL);
141
142 /* poll for transaction completion */
143 if (smbus_wait_until_done(smbus_io_base) < 0) {
144 return -3; /* timeout or error */
145 }
146
147 /* read results of transaction */
148 byte = inb(smbus_io_base + SMBHSTDAT0);
149
Kerry Shefeed3292011-08-18 18:03:44 +0800150 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_read_byte - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000151 return byte;
152}
153
154int do_smbus_write_byte(u32 smbus_io_base, u32 device, u32 address, u8 val)
155{
156 u8 byte;
157
158 if (smbus_wait_until_ready(smbus_io_base) < 0) {
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200159 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_write_byte - smbus not ready.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000160 return -2; /* not ready */
161 }
162
Kerry Shefeed3292011-08-18 18:03:44 +0800163 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_write_byte - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000164 /* set the command/address... */
165 outb(address & 0xff, smbus_io_base + SMBHSTCMD);
166
Jonathan Neuschäfer70903772017-09-23 21:39:02 +0200167 /* set the device I'm talking to */
Frank Vibrans63e62b02011-02-14 18:38:14 +0000168 outb(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
169
170 /* output value */
171 outb(val, smbus_io_base + SMBHSTDAT0);
172
173 byte = inb(smbus_io_base + SMBHSTCTRL);
174 byte &= 0xe3; /* Clear [4:2] */
175 byte |= (1 << 3) | (1 << 6); /* Byte data read/write command, start the command */
176 outb(byte, smbus_io_base + SMBHSTCTRL);
177
178 /* poll for transaction completion */
179 if (smbus_wait_until_done(smbus_io_base) < 0) {
180 return -3; /* timeout or error */
181 }
182
Kerry Shefeed3292011-08-18 18:03:44 +0800183 printk(BIOS_DEBUG, "SB800 - Smbus.c - do_smbus_write_byte - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000184 return 0;
185}
186
187void alink_ab_indx(u32 reg_space, u32 reg_addr, u32 mask, u32 val)
188{
189 u32 tmp;
190
Kerry Shefeed3292011-08-18 18:03:44 +0800191 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_ab_indx - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000192 outl((reg_space & 0x7) << 29 | reg_addr, AB_INDX);
193 tmp = inl(AB_DATA);
194 /* rpr 4.2
195 * For certain revisions of the chip, the ABCFG registers,
196 * with an address of 0x100NN (where 'N' is any hexadecimal
197 * number), require an extra programming step.*/
198 outl(0, AB_INDX);
199
200 tmp &= ~mask;
201 tmp |= val;
202
203 /* printk(BIOS_DEBUG, "about write %x, index=%x", tmp, (reg_space&0x3)<<29 | reg_addr); */
Martin Roth3c3a50c2014-12-16 20:50:26 -0700204 outl((reg_space & 0x7) << 29 | reg_addr, AB_INDX); /* probably we don't have to do it again. */
Frank Vibrans63e62b02011-02-14 18:38:14 +0000205 outl(tmp, AB_DATA);
206 outl(0, AB_INDX);
Kerry Shefeed3292011-08-18 18:03:44 +0800207 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_ab_indx - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000208}
209
210void alink_rc_indx(u32 reg_space, u32 reg_addr, u32 port, u32 mask, u32 val)
211{
212 u32 tmp;
213
Kerry Shefeed3292011-08-18 18:03:44 +0800214 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_rc_indx - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000215 outl((reg_space & 0x7) << 29 | (port & 3) << 24 | reg_addr, AB_INDX);
216 tmp = inl(AB_DATA);
217 /* rpr 4.2
218 * For certain revisions of the chip, the ABCFG registers,
219 * with an address of 0x100NN (where 'N' is any hexadecimal
220 * number), require an extra programming step.*/
221 outl(0, AB_INDX);
222
223 tmp &= ~mask;
224 tmp |= val;
225
226 //printk(BIOS_DEBUG, "about write %x, index=%x", tmp, (reg_space&0x3)<<29 | (port&3) << 24 | reg_addr);
Martin Roth3c3a50c2014-12-16 20:50:26 -0700227 outl((reg_space & 0x7) << 29 | (port & 3) << 24 | reg_addr, AB_INDX); /* probably we don't have to do it again. */
Frank Vibrans63e62b02011-02-14 18:38:14 +0000228 outl(tmp, AB_DATA);
229 outl(0, AB_INDX);
Kerry Shefeed3292011-08-18 18:03:44 +0800230 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_rc_indx - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000231}
232
233/* space = 0: AX_INDXC, AX_DATAC
234 * space = 1: AX_INDXP, AX_DATAP
235 */
236void alink_ax_indx(u32 space /*c or p? */ , u32 axindc, u32 mask, u32 val)
237{
238 u32 tmp;
239
Kerry Shefeed3292011-08-18 18:03:44 +0800240 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_ax_indx - Start.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000241 /* read axindc to tmp */
242 outl(space << 29 | space << 3 | 0x30, AB_INDX);
243 outl(axindc, AB_DATA);
244 outl(0, AB_INDX);
245 outl(space << 29 | space << 3 | 0x34, AB_INDX);
246 tmp = inl(AB_DATA);
247 outl(0, AB_INDX);
248
249 tmp &= ~mask;
250 tmp |= val;
251
252 /* write tmp */
253 outl(space << 29 | space << 3 | 0x30, AB_INDX);
254 outl(axindc, AB_DATA);
255 outl(0, AB_INDX);
256 outl(space << 29 | space << 3 | 0x34, AB_INDX);
257 outl(tmp, AB_DATA);
258 outl(0, AB_INDX);
Kerry Shefeed3292011-08-18 18:03:44 +0800259 printk(BIOS_DEBUG, "SB800 - Smbus.c - alink_ax_indx - End.\n");
Frank Vibrans63e62b02011-02-14 18:38:14 +0000260}