• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/io.h>
4 #include <device/pnp.h>
5 #include <stdint.h>
6 
7 #include "lpc47n207.h"
8 
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.
13  *
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).
17  */
18 typedef struct {
19 	u8 conf_reg;
20 	u8 value;
21 	u8 mask;
22 } uart_conf;
23 
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 */
29 };
30 
try_enabling_LPC47N207_uart(void)31 void try_enabling_LPC47N207_uart(void)
32 {
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;
38 
39 #define CONF_ENABLE    0x55
40 #define CONF_DISABLE   0xaa
41 
42 	for (j = 0; j < ARRAY_SIZE(lpc_ports); j++) {
43 		lpc_port = lpc_ports[j];
44 
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 */
50 		}
51 
52 		do {
53 			/*
54 			 * Registers 12 and 13 hold config address, look for a
55 			 * match.
56 			 */
57 			outb(0x12, lpc_port);
58 			reg_value = inb(lpc_port + 1);
59 			if (reg_value != (lpc_port & 0xff))
60 				break;
61 
62 			outb(0x13, lpc_port);
63 			reg_value = inb(lpc_port + 1);
64 			if (reg_value != (lpc_port >> 8))
65 				break;
66 
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;
70 
71 				conf_item = uart_conf_data + i;
72 
73 				reg = conf_item->conf_reg;
74 				value = conf_item->value;
75 				mask = conf_item->mask;
76 
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);
82 			}
83 		} while (0);
84 		outb(CONF_DISABLE, lpc_port);
85 	}
86 }
87