blob: cdbe56b5195ee58a5a4cd1f6fea2e729c8ee53c8 [file] [log] [blame]
Aamir Bohra01d75f42017-03-30 20:12:21 +05301/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2017 Intel Corporation.
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.
14 */
Furquan Shaikha8198eb2017-08-04 16:12:19 -070015
16#include <arch/acpi.h>
Aaron Durbin64031672018-04-21 14:45:32 -060017#include <compiler.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053018#include <device/device.h>
19#include <device/pci.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053020#include <device/pci_def.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053021#include <device/pci_ids.h>
Furquan Shaikha8198eb2017-08-04 16:12:19 -070022#include <device/pci_ops.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053023#include <intelblocks/lpss.h>
24#include <intelblocks/uart.h>
25
Furquan Shaikha8198eb2017-08-04 16:12:19 -070026#define UART_PCI_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
27
Furquan Shaikh3406dd62017-08-04 15:58:26 -070028static void uart_lpss_init(uintptr_t baseaddr)
29{
30 /* Take UART out of reset */
31 lpss_reset_release(baseaddr);
32
33 /* Set M and N divisor inputs and enable clock */
34 lpss_clk_update(baseaddr, CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL,
35 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL);
36}
37
38void uart_common_init(device_t dev, uintptr_t baseaddr)
Aamir Bohra01d75f42017-03-30 20:12:21 +053039{
40 /* Set UART base address */
41 pci_write_config32(dev, PCI_BASE_ADDRESS_0, baseaddr);
42
43 /* Enable memory access and bus master */
Furquan Shaikha8198eb2017-08-04 16:12:19 -070044 pci_write_config32(dev, PCI_COMMAND, UART_PCI_ENABLE);
Aamir Bohra01d75f42017-03-30 20:12:21 +053045
Furquan Shaikh3406dd62017-08-04 15:58:26 -070046 uart_lpss_init(baseaddr);
Furquan Shaikha8198eb2017-08-04 16:12:19 -070047}
Aamir Bohra01d75f42017-03-30 20:12:21 +053048
Aaron Durbin64031672018-04-21 14:45:32 -060049__weak device_t pch_uart_get_debug_controller(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -070050{
51 /*
52 * device_t can either be a pointer to struct device (e.g. ramstage) or
53 * a simple integer (e.g. SMM) depending upon whether __SIMPLE_DEVICE__
54 * is defined for the stage. Thus, the return requires additional
55 * casting to uintptr_t.
56 */
57 return (device_t)(uintptr_t)NULL;
58}
59
60bool uart_debug_controller_is_initialized(void)
61{
62 device_t dev;
63 uintptr_t base;
64
65 dev = pch_uart_get_debug_controller();
66 if (!dev)
67 return false;
68
69 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
70 if (!base)
71 return false;
72
73 if ((pci_read_config32(dev, PCI_COMMAND) & UART_PCI_ENABLE)
74 != UART_PCI_ENABLE)
75 return false;
76
77 return !lpss_is_controller_in_reset(base);
Aamir Bohra01d75f42017-03-30 20:12:21 +053078}
Aamir Bohra83f7bae2017-04-26 19:30:41 +053079
80#if ENV_RAMSTAGE
81
Aaron Durbin64031672018-04-21 14:45:32 -060082__weak void pch_uart_read_resources(struct device *dev)
Aamir Bohra83f7bae2017-04-26 19:30:41 +053083{
84 pci_dev_read_resources(dev);
85}
86
Aaron Durbin64031672018-04-21 14:45:32 -060087__weak bool pch_uart_init_debug_controller_on_resume(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -070088{
89 /* By default, do not initialize controller. */
90 return false;
91}
92
93bool uart_is_debug_controller(struct device *dev)
94{
95 return dev == pch_uart_get_debug_controller();
96}
97
98/*
99 * This is a workaround to enable UART controller for the debug port if:
100 * 1. CONSOLE_SERIAL is not enabled in coreboot, and
101 * 2. This boot is S3 resume, and
102 * 3. SoC wants to initialize debug UART controller.
103 *
104 * This workaround is required because Linux kernel hangs on resume if console
105 * is not enabled in coreboot, but it is enabled in kernel and not suspended.
106 */
107static bool uart_controller_needs_init(struct device *dev)
108{
109 /*
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100110 * If coreboot has CONSOLE_SERIAL enabled, the skip re-initializing
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700111 * controller here.
112 */
113 if (IS_ENABLED(CONFIG_CONSOLE_SERIAL))
114 return false;
115
116 /* If this device does not correspond to debug port, then skip. */
117 if (!uart_is_debug_controller(dev))
118 return false;
119
120 /* Initialize UART controller only on S3 resume. */
121 if (!acpi_is_wakeup_s3())
122 return false;
123
124 /*
125 * Call SoC specific routine to confirm it wants to initialize
126 * controller.
127 */
128 return pch_uart_init_debug_controller_on_resume();
129}
130
131static void uart_common_enable_resources(struct device *dev)
132{
133 pci_dev_enable_resources(dev);
134
135 if (uart_controller_needs_init(dev)) {
136 uintptr_t base;
137
138 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
139 if (base)
140 uart_lpss_init(base);
141 }
142}
143
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530144static struct device_operations device_ops = {
145 .read_resources = &pch_uart_read_resources,
146 .set_resources = &pci_dev_set_resources,
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700147 .enable_resources = &uart_common_enable_resources,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530148 .ops_pci = &pci_dev_ops_pci,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530149};
150
151static const unsigned short pci_device_ids[] = {
152 PCI_DEVICE_ID_INTEL_SPT_UART0,
153 PCI_DEVICE_ID_INTEL_SPT_UART1,
154 PCI_DEVICE_ID_INTEL_SPT_UART2,
V Sowmya7c150472018-01-23 14:44:45 +0530155 PCI_DEVICE_ID_INTEL_SPT_H_UART0,
156 PCI_DEVICE_ID_INTEL_SPT_H_UART1,
157 PCI_DEVICE_ID_INTEL_SPT_H_UART2,
V Sowmyaacc2a482018-01-23 15:27:23 +0530158 PCI_DEVICE_ID_INTEL_KBP_H_UART0,
159 PCI_DEVICE_ID_INTEL_KBP_H_UART1,
160 PCI_DEVICE_ID_INTEL_KBP_H_UART2,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530161 PCI_DEVICE_ID_INTEL_APL_UART0,
162 PCI_DEVICE_ID_INTEL_APL_UART1,
163 PCI_DEVICE_ID_INTEL_APL_UART2,
164 PCI_DEVICE_ID_INTEL_APL_UART3,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700165 PCI_DEVICE_ID_INTEL_CNL_UART0,
166 PCI_DEVICE_ID_INTEL_CNL_UART1,
167 PCI_DEVICE_ID_INTEL_CNL_UART2,
Hannah Williamsf7149652017-05-13 16:18:02 -0700168 PCI_DEVICE_ID_INTEL_GLK_UART0,
169 PCI_DEVICE_ID_INTEL_GLK_UART1,
170 PCI_DEVICE_ID_INTEL_GLK_UART2,
171 PCI_DEVICE_ID_INTEL_GLK_UART3,
172 0,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530173};
174
175static const struct pci_driver pch_uart __pci_driver = {
176 .ops = &device_ops,
177 .vendor = PCI_VENDOR_ID_INTEL,
178 .devices = pci_device_ids,
179};
180#endif /* ENV_RAMSTAGE */