coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
generic.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <device/device.h>
4 #include <device/pnp.h>
5 #include <acpi/acpigen.h>
6 #include <console/console.h>
7 
8 static void generic_set_resources(struct device *dev)
9 {
10  struct resource *res;
11 
12  if (!dev)
13  return;
14 
15  if (dev->link_list)
17 
18  for (res = dev->resource_list; res; res = res->next) {
19  if (!(res->flags & IORESOURCE_ASSIGNED))
20  continue;
21 
22  res->flags |= IORESOURCE_STORED;
23  report_resource_stored(dev, res, "");
24  }
25 }
26 
27 static void generic_read_resources(struct device *dev)
28 {
29  struct resource *res = new_resource(dev, 0);
30  res->base = dev->path.pnp.port;
31  res->size = 2;
33 }
34 
35 #if CONFIG(HAVE_ACPI_TABLES)
36 static void generic_ssdt(const struct device *dev)
37 {
38  const char *scope = acpi_device_scope(dev);
39  const char *name = acpi_device_name(dev);
40 
41  if (!scope || !name) {
42  printk(BIOS_ERR, "%s: Missing ACPI path/scope\n", dev_path(dev));
43  return;
44  }
45 
46  /* Device */
47  acpigen_write_scope(scope);
49 
50  printk(BIOS_DEBUG, "%s.%s: %s\n", scope, name, dev_path(dev));
51 
52  acpigen_write_name_string("_HID", "PNP0C02");
53  acpigen_write_name_string("_DDN", dev_name(dev));
54 
55  /* OperationRegion("IOID", SYSTEMIO, port, 2) */
56  struct opregion opreg = OPREGION("IOID", SYSTEMIO, dev->path.pnp.port, 2);
57  acpigen_write_opregion(&opreg);
58 
59  struct fieldlist l[] = {
61  FIELDLIST_NAMESTR("INDX", 8),
62  FIELDLIST_NAMESTR("DATA", 8),
63  };
64 
65  /* Field (IOID, AnyAcc, NoLock, Preserve)
66  * {
67  * Offset (0),
68  * INDX, 8,
69  * DATA, 8,
70  * } */
73 
74  struct fieldlist i[] = {
75  FIELDLIST_OFFSET(0x07),
76  FIELDLIST_NAMESTR("LDN", 8),
77  FIELDLIST_OFFSET(0x21),
78  FIELDLIST_NAMESTR("SCF1", 8),
79  FIELDLIST_NAMESTR("SCF2", 8),
80  FIELDLIST_NAMESTR("SCF3", 8),
81  FIELDLIST_NAMESTR("SCF4", 8),
82  FIELDLIST_NAMESTR("SCF5", 8),
83  FIELDLIST_NAMESTR("SCF6", 8),
84  FIELDLIST_NAMESTR("SCF7", 8),
85  FIELDLIST_OFFSET(0x29),
86  FIELDLIST_NAMESTR("CKCF", 8),
87  FIELDLIST_OFFSET(0x2F),
88  FIELDLIST_NAMESTR("SCFF", 8),
89  FIELDLIST_OFFSET(0x30),
90  FIELDLIST_NAMESTR("ACT0", 1),
91  FIELDLIST_NAMESTR("ACT1", 1),
92  FIELDLIST_NAMESTR("ACT2", 1),
93  FIELDLIST_NAMESTR("ACT3", 1),
94  FIELDLIST_NAMESTR("ACT4", 1),
95  FIELDLIST_NAMESTR("ACT5", 1),
96  FIELDLIST_NAMESTR("ACT6", 1),
97  FIELDLIST_NAMESTR("ACT7", 1),
98  FIELDLIST_OFFSET(0x60),
99  FIELDLIST_NAMESTR("IOH0", 8),
100  FIELDLIST_NAMESTR("IOL0", 8),
101  FIELDLIST_NAMESTR("IOH1", 8),
102  FIELDLIST_NAMESTR("IOL1", 8),
103  FIELDLIST_NAMESTR("IOH2", 8),
104  FIELDLIST_NAMESTR("IOL2", 8),
105  FIELDLIST_NAMESTR("IOH3", 8),
106  FIELDLIST_NAMESTR("IOL3", 8),
107  FIELDLIST_OFFSET(0x70),
108  /* Interrupt level 0 (IRQ number) */
109  FIELDLIST_NAMESTR("ITL0", 4),
110  FIELDLIST_OFFSET(0x71),
111  /* Interrupt type 0 */
112  FIELDLIST_NAMESTR("ITT0", 2),
113  FIELDLIST_OFFSET(0x72),
114  /* Interrupt level 1 (IRQ number) */
115  FIELDLIST_NAMESTR("ITL1", 4),
116  FIELDLIST_OFFSET(0x73),
117  /* Interrupt type 1 */
118  FIELDLIST_NAMESTR("ITT1", 2),
119  FIELDLIST_OFFSET(0x74),
120  FIELDLIST_NAMESTR("DMCH", 8),
121  FIELDLIST_OFFSET(0xE0),
122  FIELDLIST_NAMESTR("RGE0", 8),
123  FIELDLIST_NAMESTR("RGE1", 8),
124  FIELDLIST_NAMESTR("RGE2", 8),
125  FIELDLIST_NAMESTR("RGE3", 8),
126  FIELDLIST_NAMESTR("RGE4", 8),
127  FIELDLIST_NAMESTR("RGE5", 8),
128  FIELDLIST_NAMESTR("RGE6", 8),
129  FIELDLIST_NAMESTR("RGE7", 8),
130  FIELDLIST_NAMESTR("RGE8", 8),
131  FIELDLIST_NAMESTR("RGE9", 8),
132  FIELDLIST_NAMESTR("RGEA", 8),
133  FIELDLIST_OFFSET(0xF0),
134  FIELDLIST_NAMESTR("OPT0", 8),
135  FIELDLIST_NAMESTR("OPT1", 8),
136  FIELDLIST_NAMESTR("OPT2", 8),
137  FIELDLIST_NAMESTR("OPT3", 8),
138  FIELDLIST_NAMESTR("OPT4", 8),
139  FIELDLIST_NAMESTR("OPT5", 8),
140  FIELDLIST_NAMESTR("OPT6", 8),
141  FIELDLIST_NAMESTR("OPT7", 8),
142  FIELDLIST_NAMESTR("OPT8", 8),
143  FIELDLIST_NAMESTR("OPT9", 8),
144  };
145 
146  acpigen_write_indexfield("INDX", "DATA", i, ARRAY_SIZE(i), FIELD_BYTEACC |
148 
149  const char *mutex = "MTX0";
150 
151  acpigen_write_mutex(mutex, 0);
152  /* Backup LDN */
153  acpigen_write_name_integer("BLDN", 0);
154 
155  /* Acquire mutex - Enter config mode */
156  acpigen_write_method("AMTX", 0);
157  {
158  acpigen_write_acquire(mutex, 0xffff);
159 
160  /* Pick one of the children as the generic SIO doesn't have config mode */
161  if (dev->link_list && dev->link_list->children)
162  pnp_ssdt_enter_conf_mode(dev->link_list->children, "^INDX", "^DATA");
163 
164  /* Backup LDN */
166  acpigen_emit_namestring("^LDN");
167  acpigen_emit_namestring("^BLDN");
168  }
169  acpigen_pop_len(); /* Method */
170 
171  /* Release mutex - Exit config mode */
172  acpigen_write_method("RMTX", 0);
173  {
174  /* Restore LDN */
176  acpigen_emit_namestring("^BLDN");
177  acpigen_emit_namestring("^LDN");
178 
179  /* Pick one of the children as the generic SIO doesn't have config mode */
180  if (dev->link_list && dev->link_list->children)
181  pnp_ssdt_exit_conf_mode(dev->link_list->children, "^INDX", "^DATA");
182 
183  acpigen_write_release(mutex);
184  }
185  acpigen_pop_len(); /* Method */
186 
187  /* Select a LDN */
188  acpigen_write_method("SLDN", 1);
189  {
190  /* Local0 = Arg0 & 0xff */
192  acpigen_write_integer(0xff);
195 
196  /* LDN = LOCAL0_OP */
199  acpigen_emit_namestring("^LDN");
200  }
201  acpigen_pop_len(); /* Method */
202 
203  /* Disable a LDN/VLDN */
204  acpigen_write_method("DLDN", 1);
205  {
206  /* AMTX() */
207  acpigen_emit_namestring("AMTX");
208 
209  /* SLDN (Local0) */
210  acpigen_emit_namestring("SLDN");
212 
213  /* Local0 = Arg0 >> 8 */
218 
219  /* Local0 = Local0 & 0x7 */
224 
225  for (int j = 0; j < 8; j++) {
226  char act[6] = "^ACT0";
227  act[4] += j;
228 
229  /* If (Local0 == j) { */
231 
232  /* ACT[j] = 0 */
236 
237  acpigen_pop_len(); /* } */
238  }
239 
240  /* RMTX() */
241  acpigen_emit_namestring("RMTX");
242  }
243  acpigen_pop_len(); /* Method */
244 
245  /* Query LDN enable state. Returns 1 if LDN/VLDN is enabled. */
246  acpigen_write_method("QLDN", 1);
247  {
248  acpigen_emit_namestring("AMTX");
249 
250  /* SLDN (Local0) */
251  acpigen_emit_namestring("SLDN");
253 
254  /* Local0 = Arg0 >> 8 */
259 
260  /* Local0 = Local0 & 0x7 */
265 
266  for (int j = 0; j < 8; j++) {
267  char act[6] = "^ACT0";
268  act[4] += j;
269  /* If (Local0 == j) { */
271 
272  /* Local1 = ACT[j] */
276 
277  acpigen_pop_len(); /* } */
278  }
279 
280  /* RMTX() */
281  acpigen_emit_namestring("RMTX");
282 
283  /* Return (Local1) */
286  }
287  acpigen_pop_len(); /* Method */
288 
289  acpigen_pop_len(); /* Device */
290  acpigen_pop_len(); /* Scope */
291 }
292 
293 static const char *generic_acpi_name(const struct device *dev)
294 {
295  return "SIO0";
296 }
297 #endif
298 
299 static struct device_operations ops = {
301  .set_resources = generic_set_resources,
302  .scan_bus = scan_static_bus,
303 #if CONFIG(HAVE_ACPI_TABLES)
304  .acpi_fill_ssdt = generic_ssdt,
305  .acpi_name = generic_acpi_name,
306 #endif
307 };
308 
309 static void enable_dev(struct device *dev)
310 {
311  if (dev->path.type != DEVICE_PATH_PNP)
312  printk(BIOS_ERR, "%s: Unsupported device type\n", dev_path(dev));
313  else if (!dev->path.pnp.port)
314  printk(BIOS_ERR, "%s: Base address not set\n", dev_path(dev));
315  else
316  dev->ops = &ops;
317 
318 }
319 
321  CHIP_NAME("Generic Super I/O")
322  .enable_dev = enable_dev,
323 };
const char * acpi_device_name(const struct device *dev)
Definition: device.c:49
const char * acpi_device_scope(const struct device *dev)
Definition: device.c:158
void acpigen_emit_namestring(const char *namepath)
Definition: acpigen.c:275
void acpigen_write_store(void)
Definition: acpigen.c:1333
void acpigen_write_integer(uint64_t data)
Definition: acpigen.c:136
void acpigen_pop_len(void)
Definition: acpigen.c:37
void acpigen_write_scope(const char *name)
Definition: acpigen.c:326
void acpigen_write_acquire(const char *name, const uint16_t val)
Definition: acpigen.c:474
void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val)
Definition: acpigen.c:1472
void acpigen_write_name_integer(const char *name, uint64_t val)
Definition: acpigen.c:170
void acpigen_emit_byte(unsigned char b)
Definition: acpigen.c:61
void acpigen_write_indexfield(const char *idx, const char *data, struct fieldlist *l, size_t count, uint8_t flags)
Definition: acpigen.c:627
void acpigen_write_release(const char *name)
Definition: acpigen.c:483
void acpigen_write_field(const char *name, const struct fieldlist *l, size_t count, uint8_t flags)
Definition: acpigen.c:569
void acpigen_write_device(const char *name)
Definition: acpigen.c:769
void acpigen_write_mutex(const char *name, const uint8_t flags)
Definition: acpigen.c:465
void acpigen_write_opregion(const struct opregion *opreg)
Definition: acpigen.c:447
void acpigen_write_method(const char *name, int nargs)
Definition: acpigen.c:758
void acpigen_write_name_string(const char *name, const char *string)
Definition: acpigen.c:176
const char * name
Definition: mmu.c:92
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define printk(level,...)
Definition: stdlib.h:16
void assign_resources(struct bus *bus)
Assign the computed resources to the devices on the bus.
Definition: device.c:268
struct resource * new_resource(struct device *dev, unsigned int index)
See if a resource structure already exists for a given index and if not allocate one.
Definition: device_util.c:346
void report_resource_stored(struct device *dev, const struct resource *resource, const char *comment)
Print the resource that was just stored.
Definition: device_util.c:508
const char * dev_path(const struct device *dev)
Definition: device_util.c:149
#define FIELD_NOLOCK
Definition: acpigen.h:172
@ ARG0_OP
Definition: acpigen.h:89
@ LOCAL1_OP
Definition: acpigen.h:82
@ LOCAL0_OP
Definition: acpigen.h:81
@ RETURN_OP
Definition: acpigen.h:146
@ ZERO_OP
Definition: acpigen.h:30
@ AND_OP
Definition: acpigen.h:107
@ SHIFT_RIGHT_OP
Definition: acpigen.h:106
@ SYSTEMIO
Definition: acpigen.h:199
#define FIELD_BYTEACC
Definition: acpigen.h:167
#define FIELDLIST_OFFSET(X)
Definition: acpigen.h:153
#define OPREGION(rname, space, offset, len)
Definition: acpigen.h:191
#define FIELDLIST_NAMESTR(X, Y)
Definition: acpigen.h:157
#define FIELD_PRESERVE
Definition: acpigen.h:174
#define CHIP_NAME(X)
Definition: device.h:32
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
const char * dev_name
@ DEVICE_PATH_PNP
Definition: path.h:10
#define IORESOURCE_STORED
Definition: resource.h:32
#define IORESOURCE_ASSIGNED
Definition: resource.h:34
#define IORESOURCE_IO
Definition: resource.h:9
#define IORESOURCE_FIXED
Definition: resource.h:36
void scan_static_bus(struct device *bus)
Definition: root_device.c:89
DEVTREE_CONST struct device * children
Definition: device.h:79
void(* read_resources)(struct device *dev)
Definition: device.h:39
struct pnp_path pnp
Definition: path.h:117
enum device_path_type type
Definition: path.h:114
Definition: device.h:107
struct device_path path
Definition: device.h:115
struct device_operations * ops
Definition: device.h:143
DEVTREE_CONST struct bus * link_list
Definition: device.h:139
DEVTREE_CONST struct resource * resource_list
Definition: device.h:134
const char * name
Definition: acpigen.h:214
unsigned int port
Definition: path.h:58
unsigned long flags
Definition: resource.h:49
resource_t base
Definition: resource.h:45
resource_t size
Definition: resource.h:46
DEVTREE_CONST struct resource * next
Definition: resource.h:48
struct chip_operations superio_common_ops
Definition: generic.c:320
static void enable_dev(struct device *dev)
Definition: generic.c:309
static void generic_set_resources(struct device *dev)
Definition: generic.c:8
static struct device_operations ops
Definition: generic.c:299
static void generic_read_resources(struct device *dev)
Definition: generic.c:27