cpu/x86/smm/pci_resource_store: Store DEV/VEN ID
[coreboot2.git] / src / superio / smsc / lpc47n207 / early_serial.c
blob41d7860c1f9f9baba2f576462904066ae31bbc4b
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/io.h>
4 #include <device/pnp.h>
5 #include <stdint.h>
7 #include "lpc47n207.h"
9 /*
10 * This code tries to discover the SMSC LPC47N207 superio chip which can be
11 * connected over an LPC dongle. The chip could be bootstrap mapped to one of
12 * four LPC addresses: 0x2e, 0x4e, 0x162e, and 0x164e.
14 * Initializing the UART requires accesses to a few control registers. This
15 * structure includes the register offset and the value to write (along with
16 * the mask).
18 typedef struct {
19 u8 conf_reg;
20 u8 value;
21 u8 mask;
22 } uart_conf;
24 /* All regs/values to write to initialize the LPC47N207 UART */
25 static const uart_conf uart_conf_data [] = {
26 {2, (1 << 3), (1 << 3)}, /* cr02, enable Primary UART power */
27 {0xc, (1 << 6), (1 << 6)}, /* cr0c, enable Primary UART high speed */
28 {0x24, (CONFIG_TTYS0_BASE >> 3) << 1, 0xff}, /* cr24, base addr */
31 void try_enabling_LPC47N207_uart(void)
33 u8 reg_value;
34 const uart_conf* conf_item;
35 u16 lpc_ports[] = {0x2e, 0x4e, 0x162e, 0x164e};
36 u16 lpc_port;
37 int i, j;
39 #define CONF_ENABLE 0x55
40 #define CONF_DISABLE 0xaa
42 for (j = 0; j < ARRAY_SIZE(lpc_ports); j++) {
43 lpc_port = lpc_ports[j];
45 /* enable CONFIG mode */
46 outb(CONF_ENABLE, lpc_port);
47 reg_value = inb(lpc_port);
48 if (reg_value != CONF_ENABLE) {
49 continue; /* There is no LPC device at this address */
52 do {
54 * Registers 12 and 13 hold config address, look for a
55 * match.
57 outb(0x12, lpc_port);
58 reg_value = inb(lpc_port + 1);
59 if (reg_value != (lpc_port & 0xff))
60 break;
62 outb(0x13, lpc_port);
63 reg_value = inb(lpc_port + 1);
64 if (reg_value != (lpc_port >> 8))
65 break;
67 /* This must be the SMSC LPC 47N207, enable the UART. */
68 for (i = 0; i < ARRAY_SIZE(uart_conf_data); i++) {
69 u8 reg, value, mask;
71 conf_item = uart_conf_data + i;
73 reg = conf_item->conf_reg;
74 value = conf_item->value;
75 mask = conf_item->mask;
77 outb(reg, lpc_port);
78 reg_value = inb(lpc_port + 1);
79 reg_value &= ~mask;
80 reg_value |= (value & mask);
81 outb(reg_value, lpc_port + 1);
83 } while (0);
84 outb(CONF_DISABLE, lpc_port);