blob: 57d9ebedd69152a1169f5828caf2c47fcead47d3 [file] [log] [blame]
Aamir Bohra01d75f42017-03-30 20:12:21 +05301/*
2 * This file is part of the coreboot project.
3 *
Subrata Banikafa07f72018-05-24 12:21:06 +05304 * Copyright (C) 2017-2018 Intel Corporation.
Aamir Bohra01d75f42017-03-30 20:12:21 +05305 *
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>
Subrata Banikafa07f72018-05-24 12:21:06 +053017#include <assert.h>
Subrata Banikafa07f72018-05-24 12:21:06 +053018#include <cbmem.h>
19#include <console/uart.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053020#include <device/device.h>
21#include <device/pci.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053022#include <device/pci_def.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053023#include <device/pci_ids.h>
Furquan Shaikha8198eb2017-08-04 16:12:19 -070024#include <device/pci_ops.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053025#include <intelblocks/lpss.h>
26#include <intelblocks/uart.h>
Subrata Banikafa07f72018-05-24 12:21:06 +053027#include <soc/pci_devs.h>
28#include <soc/iomap.h>
29#include <soc/nvs.h>
30#include <string.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053031
Furquan Shaikha8198eb2017-08-04 16:12:19 -070032#define UART_PCI_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
Subrata Banikafa07f72018-05-24 12:21:06 +053033#define UART_CONSOLE_INVALID_INDEX 0xFF
34
35extern const struct uart_gpio_pad_config uart_gpio_pads[];
36extern const int uart_max_index;
Furquan Shaikha8198eb2017-08-04 16:12:19 -070037
Furquan Shaikh3406dd62017-08-04 15:58:26 -070038static void uart_lpss_init(uintptr_t baseaddr)
39{
40 /* Take UART out of reset */
41 lpss_reset_release(baseaddr);
42
43 /* Set M and N divisor inputs and enable clock */
44 lpss_clk_update(baseaddr, CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL,
45 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL);
46}
47
Subrata Banikafa07f72018-05-24 12:21:06 +053048#if IS_ENABLED(CONFIG_DRIVERS_UART_8250MEM)
49uintptr_t uart_platform_base(int idx)
Aamir Bohra01d75f42017-03-30 20:12:21 +053050{
Subrata Banikafa07f72018-05-24 12:21:06 +053051 /* return Base address for UART console index */
52 return UART_BASE_0_ADDR(idx);
53}
54#endif
55
56static int uart_get_valid_index(void)
57{
58 int index;
59
60 for (index = 0; index < uart_max_index; index++) {
61 if (uart_gpio_pads[index].console_index ==
62 CONFIG_UART_FOR_CONSOLE)
63 return index;
64 }
65 /* For valid index, code should not reach here */
66 return UART_CONSOLE_INVALID_INDEX;
67}
68
69void uart_common_init(struct device *device, uintptr_t baseaddr)
70{
71#if defined(__SIMPLE_DEVICE__)
72 pci_devfn_t dev = (pci_devfn_t)(uintptr_t)device;
73#else
74 struct device *dev = device;
75#endif
76 if (!dev)
77 return;
78
Aamir Bohra01d75f42017-03-30 20:12:21 +053079 /* Set UART base address */
80 pci_write_config32(dev, PCI_BASE_ADDRESS_0, baseaddr);
81
82 /* Enable memory access and bus master */
Furquan Shaikha8198eb2017-08-04 16:12:19 -070083 pci_write_config32(dev, PCI_COMMAND, UART_PCI_ENABLE);
Aamir Bohra01d75f42017-03-30 20:12:21 +053084
Furquan Shaikh3406dd62017-08-04 15:58:26 -070085 uart_lpss_init(baseaddr);
Furquan Shaikha8198eb2017-08-04 16:12:19 -070086}
Aamir Bohra01d75f42017-03-30 20:12:21 +053087
Subrata Banikafa07f72018-05-24 12:21:06 +053088struct device *uart_get_device(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -070089{
90 /*
Nico Hubera96e66a2018-11-11 02:51:14 +010091 * This function will get called even if INTEL_LPSS_UART_FOR_CONSOLE
92 * config option is not selected.
93 * By default return NULL in this case to avoid compilation errors.
Furquan Shaikha8198eb2017-08-04 16:12:19 -070094 */
Nico Hubera96e66a2018-11-11 02:51:14 +010095 if (!IS_ENABLED(CONFIG_INTEL_LPSS_UART_FOR_CONSOLE))
Subrata Banikafa07f72018-05-24 12:21:06 +053096 return NULL;
97
98 int console_index = uart_get_valid_index();
99
100 if (console_index != UART_CONSOLE_INVALID_INDEX)
101 return soc_uart_console_to_device(CONFIG_UART_FOR_CONSOLE);
102 else
103 return NULL;
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700104}
105
Subrata Banikafa07f72018-05-24 12:21:06 +0530106bool uart_is_controller_initialized(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700107{
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700108 uintptr_t base;
109
Subrata Banikafa07f72018-05-24 12:21:06 +0530110#if defined(__SIMPLE_DEVICE__)
111 pci_devfn_t dev = (pci_devfn_t)(uintptr_t)uart_get_device();
112#else
113 struct device *dev = uart_get_device();
114#endif
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700115 if (!dev)
116 return false;
117
118 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
119 if (!base)
120 return false;
121
122 if ((pci_read_config32(dev, PCI_COMMAND) & UART_PCI_ENABLE)
123 != UART_PCI_ENABLE)
124 return false;
125
126 return !lpss_is_controller_in_reset(base);
Aamir Bohra01d75f42017-03-30 20:12:21 +0530127}
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530128
Subrata Banikafa07f72018-05-24 12:21:06 +0530129static void uart_configure_gpio_pads(void)
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530130{
Subrata Banikafa07f72018-05-24 12:21:06 +0530131 int index = uart_get_valid_index();
132
133 if (index != UART_CONSOLE_INVALID_INDEX)
134 gpio_configure_pads(uart_gpio_pads[index].gpios,
135 MAX_GPIO_PAD_PER_UART);
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530136}
137
Subrata Banikafa07f72018-05-24 12:21:06 +0530138void uart_bootblock_init(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700139{
Subrata Banikafa07f72018-05-24 12:21:06 +0530140 /* Program UART BAR0, command, reset and clock register */
141 uart_common_init(uart_get_device(),
142 UART_BASE(CONFIG_UART_FOR_CONSOLE));
143
144 if (!IS_ENABLED(CONFIG_DRIVERS_UART_8250MEM_32))
145 /* Put UART in byte access mode for 16550 compatibility */
146 soc_uart_set_legacy_mode();
147
148 /* Configure the 2 pads per UART. */
149 uart_configure_gpio_pads();
150}
151
152#if ENV_RAMSTAGE
153
154static void uart_read_resources(struct device *dev)
155{
156 pci_dev_read_resources(dev);
157
158 /* Set the configured UART base address for the debug port */
Nico Hubera96e66a2018-11-11 02:51:14 +0100159 if (IS_ENABLED(CONFIG_INTEL_LPSS_UART_FOR_CONSOLE) &&
160 uart_is_debug_controller(dev)) {
Subrata Banikafa07f72018-05-24 12:21:06 +0530161 struct resource *res = find_resource(dev, PCI_BASE_ADDRESS_0);
162 /* Need to set the base and size for the resource allocator. */
163 res->base = UART_BASE(CONFIG_UART_FOR_CONSOLE);
164 res->size = UART_BASE_SIZE;
165 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
166 IORESOURCE_FIXED;
167 }
168}
169
170/*
171 * Check if UART debug port controller needs to be initialized on resume.
172 *
173 * Returns:
174 * true = when SoC wants debug port initialization on resume
175 * false = otherwise
176 */
177static bool pch_uart_init_debug_controller_on_resume(void)
178{
179 global_nvs_t *gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
180
181 if (gnvs)
182 return !!gnvs->uior;
183
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700184 return false;
185}
186
187bool uart_is_debug_controller(struct device *dev)
188{
Subrata Banikafa07f72018-05-24 12:21:06 +0530189 return dev == uart_get_device();
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700190}
191
192/*
193 * This is a workaround to enable UART controller for the debug port if:
194 * 1. CONSOLE_SERIAL is not enabled in coreboot, and
195 * 2. This boot is S3 resume, and
196 * 3. SoC wants to initialize debug UART controller.
197 *
198 * This workaround is required because Linux kernel hangs on resume if console
199 * is not enabled in coreboot, but it is enabled in kernel and not suspended.
200 */
201static bool uart_controller_needs_init(struct device *dev)
202{
203 /*
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100204 * If coreboot has CONSOLE_SERIAL enabled, the skip re-initializing
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700205 * controller here.
206 */
207 if (IS_ENABLED(CONFIG_CONSOLE_SERIAL))
208 return false;
209
210 /* If this device does not correspond to debug port, then skip. */
211 if (!uart_is_debug_controller(dev))
212 return false;
213
214 /* Initialize UART controller only on S3 resume. */
215 if (!acpi_is_wakeup_s3())
216 return false;
217
218 /*
Subrata Banikafa07f72018-05-24 12:21:06 +0530219 * check if SOC wants to initialize UART on resume
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700220 */
221 return pch_uart_init_debug_controller_on_resume();
222}
223
224static void uart_common_enable_resources(struct device *dev)
225{
226 pci_dev_enable_resources(dev);
227
228 if (uart_controller_needs_init(dev)) {
229 uintptr_t base;
230
231 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
232 if (base)
233 uart_lpss_init(base);
234 }
235}
236
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530237static struct device_operations device_ops = {
Elyes HAOUAS1d191272018-11-27 12:23:48 +0100238 .read_resources = uart_read_resources,
239 .set_resources = pci_dev_set_resources,
240 .enable_resources = uart_common_enable_resources,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530241 .ops_pci = &pci_dev_ops_pci,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530242};
243
244static const unsigned short pci_device_ids[] = {
245 PCI_DEVICE_ID_INTEL_SPT_UART0,
246 PCI_DEVICE_ID_INTEL_SPT_UART1,
247 PCI_DEVICE_ID_INTEL_SPT_UART2,
V Sowmya7c150472018-01-23 14:44:45 +0530248 PCI_DEVICE_ID_INTEL_SPT_H_UART0,
249 PCI_DEVICE_ID_INTEL_SPT_H_UART1,
250 PCI_DEVICE_ID_INTEL_SPT_H_UART2,
V Sowmyaacc2a482018-01-23 15:27:23 +0530251 PCI_DEVICE_ID_INTEL_KBP_H_UART0,
252 PCI_DEVICE_ID_INTEL_KBP_H_UART1,
253 PCI_DEVICE_ID_INTEL_KBP_H_UART2,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530254 PCI_DEVICE_ID_INTEL_APL_UART0,
255 PCI_DEVICE_ID_INTEL_APL_UART1,
256 PCI_DEVICE_ID_INTEL_APL_UART2,
257 PCI_DEVICE_ID_INTEL_APL_UART3,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700258 PCI_DEVICE_ID_INTEL_CNL_UART0,
259 PCI_DEVICE_ID_INTEL_CNL_UART1,
260 PCI_DEVICE_ID_INTEL_CNL_UART2,
Hannah Williamsf7149652017-05-13 16:18:02 -0700261 PCI_DEVICE_ID_INTEL_GLK_UART0,
262 PCI_DEVICE_ID_INTEL_GLK_UART1,
263 PCI_DEVICE_ID_INTEL_GLK_UART2,
264 PCI_DEVICE_ID_INTEL_GLK_UART3,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800265 PCI_DEVICE_ID_INTEL_CNP_H_UART0,
266 PCI_DEVICE_ID_INTEL_CNP_H_UART1,
267 PCI_DEVICE_ID_INTEL_CNP_H_UART2,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530268 PCI_DEVICE_ID_INTEL_ICP_UART0,
269 PCI_DEVICE_ID_INTEL_ICP_UART1,
270 PCI_DEVICE_ID_INTEL_ICP_UART2,
Hannah Williamsf7149652017-05-13 16:18:02 -0700271 0,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530272};
273
274static const struct pci_driver pch_uart __pci_driver = {
Subrata Banikafa07f72018-05-24 12:21:06 +0530275 .ops = &device_ops,
276 .vendor = PCI_VENDOR_ID_INTEL,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530277 .devices = pci_device_ids,
278};
279#endif /* ENV_RAMSTAGE */