blob: b8d3960654eb23f4a9b558c97f438d8fda9fba68 [file] [log] [blame]
Stefan Reinauer81986002012-03-30 15:06:04 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Stefan Reinauer81986002012-03-30 15:06:04 -070014 */
15
Edward O'Callaghand76ac632015-01-04 17:21:52 +110016#include <arch/io.h>
17#include <device/pnp.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include "lpc47n207.h"
21
Stefan Reinauer81986002012-03-30 15:06:04 -070022/*
23 * This code tries to discover the SMSC LPC47N207 superio chip which can be
24 * connected over an LPC dongle. The chip could be bootstrap mapped to one of
25 * four LPC addresses: 0x2e, 0x4e, 0x162e, and 0x164e.
26 *
27 * Initializing the UART requires accesses to a few control registers. This
28 * structure includes the register offset and the value to write (along with
29 * the mask).
30 */
31typedef struct {
32 u8 conf_reg;
33 u8 value;
34 u8 mask;
35} uart_conf;
36
37/* All regs/values to write to initialize the LPC47N207 UART */
38static const uart_conf uart_conf_data [] = {
39 {2, (1 << 3), (1 << 3)}, /* cr02, enable Primary UART power */
40 {0xc, (1 << 6), (1 << 6)}, /* cr0c, enable Primary UART high speed */
41 {0x24, (CONFIG_TTYS0_BASE >> 3) << 1, 0xff}, /* cr24, base addr */
42};
43
44void try_enabling_LPC47N207_uart(void)
45{
46 u8 reg_value;
47 const uart_conf* conf_item;
48 u16 lpc_ports[] = {0x2e, 0x4e, 0x162e, 0x164e};
49 u16 lpc_port;
50 int i, j;
51
52#define CONFIG_ENABLE 0x55
53#define CONFIG_DISABLE 0xaa
54
55 for (j = 0; j < ARRAY_SIZE(lpc_ports); j++) {
56 lpc_port = lpc_ports[j];
57
58 /* enable CONFIG mode */
59 outb(CONFIG_ENABLE, lpc_port);
Elyes HAOUAScf139502016-09-16 20:32:00 +020060 reg_value = inb(lpc_port);
Stefan Reinauer81986002012-03-30 15:06:04 -070061 if (reg_value != CONFIG_ENABLE) {
62 continue; /* There is no LPC device at this address */
63 }
64
65 do {
66 /*
67 * Registers 12 and 13 hold config address, look for a
68 * match.
69 */
70 outb(0x12, lpc_port);
Elyes HAOUAScf139502016-09-16 20:32:00 +020071 reg_value = inb(lpc_port + 1);
Stefan Reinauer81986002012-03-30 15:06:04 -070072 if (reg_value != (lpc_port & 0xff))
73 break;
74
75 outb(0x13, lpc_port);
Elyes HAOUAScf139502016-09-16 20:32:00 +020076 reg_value = inb(lpc_port + 1);
Stefan Reinauer81986002012-03-30 15:06:04 -070077 if (reg_value != (lpc_port >> 8))
78 break;
79
80 /* This must be the SMSC LPC 47N207, enable the UART. */
81 for (i = 0; i < ARRAY_SIZE(uart_conf_data); i++) {
82 u8 reg, value, mask;
83
84 conf_item = uart_conf_data + i;
85
86 reg = conf_item->conf_reg;
87 value = conf_item->value;
88 mask = conf_item->mask;
89
90 outb(reg, lpc_port);
91 reg_value = inb(lpc_port + 1);
92 reg_value &= ~mask;
93 reg_value |= (value & mask);
94 outb(reg_value, lpc_port + 1);
95 }
96 } while (0);
97 outb(CONFIG_DISABLE, lpc_port);
98 }
99}