Merge commit 'ac4040955b1669f0aac5937f623d6587d5210679' into upstream-merge
[qemu-kvm/amd-iommu.git] / hw / pm_smbus.c
blob6ef6b9ed5826413d6b2984adf1864b1acb92c9df
1 /*
2 * PC SMBus implementation
3 * splitted from acpi.c
5 * Copyright (c) 2006 Fabrice Bellard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License version 2 as published by the Free Software Foundation.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
20 #include "hw.h"
21 #include "pc.h"
22 #include "pm_smbus.h"
23 #include "pci.h"
24 #include "qemu-timer.h"
25 #include "sysemu.h"
26 #include "i2c.h"
27 #include "smbus.h"
28 #include "kvm.h"
30 /* no save/load? */
32 #define SMBHSTSTS 0x00
33 #define SMBHSTCNT 0x02
34 #define SMBHSTCMD 0x03
35 #define SMBHSTADD 0x04
36 #define SMBHSTDAT0 0x05
37 #define SMBHSTDAT1 0x06
38 #define SMBBLKDAT 0x07
40 static void smb_transaction(PMSMBus *s)
42 uint8_t prot = (s->smb_ctl >> 2) & 0x07;
43 uint8_t read = s->smb_addr & 0x01;
44 uint8_t cmd = s->smb_cmd;
45 uint8_t addr = s->smb_addr >> 1;
46 i2c_bus *bus = s->smbus;
48 #ifdef DEBUG
49 printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
50 #endif
51 switch(prot) {
52 case 0x0:
53 smbus_quick_command(bus, addr, read);
54 break;
55 case 0x1:
56 if (read) {
57 s->smb_data0 = smbus_receive_byte(bus, addr);
58 } else {
59 smbus_send_byte(bus, addr, cmd);
61 break;
62 case 0x2:
63 if (read) {
64 s->smb_data0 = smbus_read_byte(bus, addr, cmd);
65 } else {
66 smbus_write_byte(bus, addr, cmd, s->smb_data0);
68 break;
69 case 0x3:
70 if (read) {
71 uint16_t val;
72 val = smbus_read_word(bus, addr, cmd);
73 s->smb_data0 = val;
74 s->smb_data1 = val >> 8;
75 } else {
76 smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
78 break;
79 case 0x5:
80 if (read) {
81 s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
82 } else {
83 smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
85 break;
86 default:
87 goto error;
89 return;
91 error:
92 s->smb_stat |= 0x04;
95 void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
97 PMSMBus *s = opaque;
98 addr &= 0x3f;
99 #ifdef DEBUG
100 printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
101 #endif
102 switch(addr) {
103 case SMBHSTSTS:
104 s->smb_stat = 0;
105 s->smb_index = 0;
106 break;
107 case SMBHSTCNT:
108 s->smb_ctl = val;
109 if (val & 0x40)
110 smb_transaction(s);
111 break;
112 case SMBHSTCMD:
113 s->smb_cmd = val;
114 break;
115 case SMBHSTADD:
116 s->smb_addr = val;
117 break;
118 case SMBHSTDAT0:
119 s->smb_data0 = val;
120 break;
121 case SMBHSTDAT1:
122 s->smb_data1 = val;
123 break;
124 case SMBBLKDAT:
125 s->smb_data[s->smb_index++] = val;
126 if (s->smb_index > 31)
127 s->smb_index = 0;
128 break;
129 default:
130 break;
134 uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
136 PMSMBus *s = opaque;
137 uint32_t val;
139 addr &= 0x3f;
140 switch(addr) {
141 case SMBHSTSTS:
142 val = s->smb_stat;
143 break;
144 case SMBHSTCNT:
145 s->smb_index = 0;
146 val = s->smb_ctl & 0x1f;
147 break;
148 case SMBHSTCMD:
149 val = s->smb_cmd;
150 break;
151 case SMBHSTADD:
152 val = s->smb_addr;
153 break;
154 case SMBHSTDAT0:
155 val = s->smb_data0;
156 break;
157 case SMBHSTDAT1:
158 val = s->smb_data1;
159 break;
160 case SMBBLKDAT:
161 val = s->smb_data[s->smb_index++];
162 if (s->smb_index > 31)
163 s->smb_index = 0;
164 break;
165 default:
166 val = 0;
167 break;
169 #ifdef DEBUG
170 printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
171 #endif
172 return val;
175 void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
177 smb->smbus = i2c_init_bus(parent, "i2c");