1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <arch/io.h>
4 #include <device/device.h>
5 #include <superio/conf_mode.h>
6 #include <acpi/acpigen.h>
7
8 /* Common enter/exit implementations */
9
pnp_enter_conf_mode_55(struct device * dev)10 void pnp_enter_conf_mode_55(struct device *dev)
11 {
12 outb(0x55, dev->path.pnp.port);
13 }
14
pnp_enter_conf_mode_6767(struct device * dev)15 void pnp_enter_conf_mode_6767(struct device *dev)
16 {
17 outb(0x67, dev->path.pnp.port);
18 outb(0x67, dev->path.pnp.port);
19 }
20
pnp_enter_conf_mode_7777(struct device * dev)21 void pnp_enter_conf_mode_7777(struct device *dev)
22 {
23 outb(0x77, dev->path.pnp.port);
24 outb(0x77, dev->path.pnp.port);
25 }
26
pnp_enter_conf_mode_8787(struct device * dev)27 void pnp_enter_conf_mode_8787(struct device *dev)
28 {
29 outb(0x87, dev->path.pnp.port);
30 outb(0x87, dev->path.pnp.port);
31 }
32
pnp_enter_conf_mode_a0a0(struct device * dev)33 void pnp_enter_conf_mode_a0a0(struct device *dev)
34 {
35 outb(0xa0, dev->path.pnp.port);
36 outb(0xa0, dev->path.pnp.port);
37 }
38
pnp_enter_conf_mode_a5a5(struct device * dev)39 void pnp_enter_conf_mode_a5a5(struct device *dev)
40 {
41 outb(0xa5, dev->path.pnp.port);
42 outb(0xa5, dev->path.pnp.port);
43 }
44
pnp_exit_conf_mode_aa(struct device * dev)45 void pnp_exit_conf_mode_aa(struct device *dev)
46 {
47 outb(0xaa, dev->path.pnp.port);
48 }
49
pnp_enter_conf_mode_870155aa(struct device * dev)50 void pnp_enter_conf_mode_870155aa(struct device *dev)
51 {
52 outb(0x87, dev->path.pnp.port);
53 outb(0x01, dev->path.pnp.port);
54 outb(0x55, dev->path.pnp.port);
55
56 if (dev->path.pnp.port == 0x4e)
57 outb(0xaa, dev->path.pnp.port);
58 else
59 outb(0x55, dev->path.pnp.port);
60 }
61
pnp_exit_conf_mode_0202(struct device * dev)62 void pnp_exit_conf_mode_0202(struct device *dev)
63 {
64 pnp_write_config(dev, 0x02, (1 << 1));
65 }
66
67 /* Functions for ACPI */
68 #if CONFIG(HAVE_ACPI_TABLES)
pnp_ssdt_enter_conf_mode_55(struct device * dev,const char * idx,const char * data)69 static void pnp_ssdt_enter_conf_mode_55(struct device *dev, const char *idx, const char *data)
70 {
71 acpigen_write_store();
72 acpigen_write_byte(0x55);
73 acpigen_emit_namestring(idx);
74 }
75
pnp_ssdt_enter_conf_mode_6767(struct device * dev,const char * idx,const char * data)76 static void pnp_ssdt_enter_conf_mode_6767(struct device *dev, const char *idx, const char *data)
77 {
78 acpigen_write_store();
79 acpigen_write_byte(0x67);
80 acpigen_emit_namestring(idx);
81
82 acpigen_write_store();
83 acpigen_write_byte(0x67);
84 acpigen_emit_namestring(idx);
85 }
86
pnp_ssdt_enter_conf_mode_7777(struct device * dev,const char * idx,const char * data)87 static void pnp_ssdt_enter_conf_mode_7777(struct device *dev, const char *idx, const char *data)
88 {
89 acpigen_write_store();
90 acpigen_write_byte(0x77);
91 acpigen_emit_namestring(idx);
92
93 acpigen_write_store();
94 acpigen_write_byte(0x77);
95 acpigen_emit_namestring(idx);
96 }
97
pnp_ssdt_enter_conf_mode_8787(struct device * dev,const char * idx,const char * data)98 static void pnp_ssdt_enter_conf_mode_8787(struct device *dev, const char *idx, const char *data)
99 {
100 acpigen_write_store();
101 acpigen_write_byte(0x87);
102 acpigen_emit_namestring(idx);
103
104 acpigen_write_store();
105 acpigen_write_byte(0x87);
106 acpigen_emit_namestring(idx);
107 }
108
pnp_ssdt_enter_conf_mode_a0a0(struct device * dev,const char * idx,const char * data)109 static void pnp_ssdt_enter_conf_mode_a0a0(struct device *dev, const char *idx, const char *data)
110 {
111 acpigen_write_store();
112 acpigen_write_byte(0xa0);
113 acpigen_emit_namestring(idx);
114
115 acpigen_write_store();
116 acpigen_write_byte(0xa0);
117 acpigen_emit_namestring(idx);
118 }
119
pnp_ssdt_enter_conf_mode_a5a5(struct device * dev,const char * idx,const char * data)120 static void pnp_ssdt_enter_conf_mode_a5a5(struct device *dev, const char *idx, const char *data)
121 {
122 acpigen_write_store();
123 acpigen_write_byte(0xa5);
124 acpigen_emit_namestring(idx);
125
126 acpigen_write_store();
127 acpigen_write_byte(0xa5);
128 acpigen_emit_namestring(idx);
129 }
130
pnp_ssdt_enter_conf_mode_870155aa(struct device * dev,const char * idx,const char * data)131 static void pnp_ssdt_enter_conf_mode_870155aa(struct device *dev,
132 const char *idx, const char *data)
133 {
134 acpigen_write_store();
135 acpigen_write_byte(0x87);
136 acpigen_emit_namestring(idx);
137
138 acpigen_write_store();
139 acpigen_write_byte(0x01);
140 acpigen_emit_namestring(idx);
141
142 acpigen_write_store();
143 acpigen_write_byte(0x55);
144 acpigen_emit_namestring(idx);
145
146 acpigen_write_store();
147 if (dev->path.pnp.port == 0x4e)
148 acpigen_write_byte(0xaa);
149 else
150 acpigen_write_byte(0x55);
151 acpigen_emit_namestring(idx);
152 }
153
pnp_ssdt_exit_conf_mode_aa(struct device * dev,const char * idx,const char * data)154 static void pnp_ssdt_exit_conf_mode_aa(struct device *dev, const char *idx, const char *data)
155 {
156 acpigen_write_store();
157 acpigen_write_byte(0xaa);
158 acpigen_emit_namestring(idx);
159 }
160
pnp_ssdt_exit_conf_mode_0202(struct device * dev,const char * idx,const char * data)161 static void pnp_ssdt_exit_conf_mode_0202(struct device *dev, const char *idx, const char *data)
162 {
163 acpigen_write_store();
164 acpigen_write_byte(0x02);
165 acpigen_emit_namestring(idx);
166
167 acpigen_write_store();
168 acpigen_write_byte(0x02);
169 acpigen_emit_namestring(data);
170 }
171 #endif
172
173 const struct pnp_mode_ops pnp_conf_mode_55_aa = {
174 .enter_conf_mode = pnp_enter_conf_mode_55,
175 .exit_conf_mode = pnp_exit_conf_mode_aa,
176 #if CONFIG(HAVE_ACPI_TABLES)
177 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_55,
178 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
179 #endif
180 };
181
182 const struct pnp_mode_ops pnp_conf_mode_6767_aa = {
183 .enter_conf_mode = pnp_enter_conf_mode_6767,
184 .exit_conf_mode = pnp_exit_conf_mode_aa,
185 #if CONFIG(HAVE_ACPI_TABLES)
186 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_6767,
187 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
188 #endif
189 };
190
191 const struct pnp_mode_ops pnp_conf_mode_7777_aa = {
192 .enter_conf_mode = pnp_enter_conf_mode_7777,
193 .exit_conf_mode = pnp_exit_conf_mode_aa,
194 #if CONFIG(HAVE_ACPI_TABLES)
195 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_7777,
196 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
197 #endif
198 };
199
200 const struct pnp_mode_ops pnp_conf_mode_8787_aa = {
201 .enter_conf_mode = pnp_enter_conf_mode_8787,
202 .exit_conf_mode = pnp_exit_conf_mode_aa,
203 #if CONFIG(HAVE_ACPI_TABLES)
204 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_8787,
205 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
206 #endif
207 };
208
209 const struct pnp_mode_ops pnp_conf_mode_a0a0_aa = {
210 .enter_conf_mode = pnp_enter_conf_mode_a0a0,
211 .exit_conf_mode = pnp_exit_conf_mode_aa,
212 #if CONFIG(HAVE_ACPI_TABLES)
213 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_a0a0,
214 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
215 #endif
216 };
217
218 const struct pnp_mode_ops pnp_conf_mode_a5a5_aa = {
219 .enter_conf_mode = pnp_enter_conf_mode_a5a5,
220 .exit_conf_mode = pnp_exit_conf_mode_aa,
221 #if CONFIG(HAVE_ACPI_TABLES)
222 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_a5a5,
223 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_aa,
224 #endif
225 };
226
227 const struct pnp_mode_ops pnp_conf_mode_870155_aa = {
228 .enter_conf_mode = pnp_enter_conf_mode_870155aa,
229 .exit_conf_mode = pnp_exit_conf_mode_0202,
230 #if CONFIG(HAVE_ACPI_TABLES)
231 .ssdt_enter_conf_mode = pnp_ssdt_enter_conf_mode_870155aa,
232 .ssdt_exit_conf_mode = pnp_ssdt_exit_conf_mode_0202,
233 #endif
234 };
235