blob: 364835dd0f05bf4a350faec4193eaf3f9a79bb1e [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 <cbmem.h>
18#include <console/uart.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053019#include <device/device.h>
20#include <device/pci.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053021#include <device/pci_def.h>
Aamir Bohra83f7bae2017-04-26 19:30:41 +053022#include <device/pci_ids.h>
Furquan Shaikha8198eb2017-08-04 16:12:19 -070023#include <device/pci_ops.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053024#include <intelblocks/lpss.h>
25#include <intelblocks/uart.h>
Subrata Banikafa07f72018-05-24 12:21:06 +053026#include <soc/pci_devs.h>
27#include <soc/iomap.h>
28#include <soc/nvs.h>
Aamir Bohra01d75f42017-03-30 20:12:21 +053029
Furquan Shaikha8198eb2017-08-04 16:12:19 -070030#define UART_PCI_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)
Subrata Banikafa07f72018-05-24 12:21:06 +053031#define UART_CONSOLE_INVALID_INDEX 0xFF
32
33extern const struct uart_gpio_pad_config uart_gpio_pads[];
34extern const int uart_max_index;
Furquan Shaikha8198eb2017-08-04 16:12:19 -070035
Usha P5e59a822019-08-09 18:42:00 +053036static void uart_lpss_init(const struct device *dev, uintptr_t baseaddr)
Furquan Shaikh3406dd62017-08-04 15:58:26 -070037{
Usha P5e59a822019-08-09 18:42:00 +053038 /* Ensure controller is in D0 state */
39 lpss_set_power_state(dev, STATE_D0);
40
Furquan Shaikh3406dd62017-08-04 15:58:26 -070041 /* Take UART out of reset */
42 lpss_reset_release(baseaddr);
43
44 /* Set M and N divisor inputs and enable clock */
45 lpss_clk_update(baseaddr, CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_M_VAL,
46 CONFIG_SOC_INTEL_COMMON_LPSS_UART_CLK_N_VAL);
47}
48
Nico Huber62ddc492019-05-29 18:39:31 +020049#if CONFIG(INTEL_LPSS_UART_FOR_CONSOLE)
Subrata Banikafa07f72018-05-24 12:21:06 +053050uintptr_t uart_platform_base(int idx)
Aamir Bohra01d75f42017-03-30 20:12:21 +053051{
Nico Huberce8eebd2019-05-29 18:33:35 +020052 if (idx == CONFIG_UART_FOR_CONSOLE)
Nico Huber99954182019-05-29 23:33:06 +020053 return CONFIG_CONSOLE_UART_BASE_ADDRESS;
Nico Huberce8eebd2019-05-29 18:33:35 +020054 return 0;
Subrata Banikafa07f72018-05-24 12:21:06 +053055}
56#endif
57
58static int uart_get_valid_index(void)
59{
60 int index;
61
62 for (index = 0; index < uart_max_index; index++) {
63 if (uart_gpio_pads[index].console_index ==
64 CONFIG_UART_FOR_CONSOLE)
65 return index;
66 }
67 /* For valid index, code should not reach here */
68 return UART_CONSOLE_INVALID_INDEX;
69}
70
Aamir Bohra17cfba62019-07-25 20:56:54 +053071void uart_common_init(const struct device *device, uintptr_t baseaddr)
Subrata Banikafa07f72018-05-24 12:21:06 +053072{
73#if defined(__SIMPLE_DEVICE__)
Aamir Bohra17cfba62019-07-25 20:56:54 +053074 pci_devfn_t dev = PCI_BDF(device);
Subrata Banikafa07f72018-05-24 12:21:06 +053075#else
Aamir Bohra17cfba62019-07-25 20:56:54 +053076 const struct device *dev = device;
Subrata Banikafa07f72018-05-24 12:21:06 +053077#endif
Subrata Banikafa07f72018-05-24 12:21:06 +053078
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
Usha P5e59a822019-08-09 18:42:00 +053085 uart_lpss_init(device, baseaddr);
Furquan Shaikha8198eb2017-08-04 16:12:19 -070086}
Aamir Bohra01d75f42017-03-30 20:12:21 +053087
Aamir Bohra17cfba62019-07-25 20:56:54 +053088const struct 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 */
Julius Wernercd49cce2019-03-05 16:53:33 -080095 if (!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;
Aamir Bohra17cfba62019-07-25 20:56:54 +0530109 const struct device *dev_uart = uart_get_device();
110
111 if (!dev_uart)
112 return false;
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700113
Subrata Banikafa07f72018-05-24 12:21:06 +0530114#if defined(__SIMPLE_DEVICE__)
Aamir Bohra17cfba62019-07-25 20:56:54 +0530115 pci_devfn_t dev = PCI_BDF(dev_uart);
Subrata Banikafa07f72018-05-24 12:21:06 +0530116#else
Aamir Bohra17cfba62019-07-25 20:56:54 +0530117 const struct device *dev = dev_uart;
Subrata Banikafa07f72018-05-24 12:21:06 +0530118#endif
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700119
120 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
121 if (!base)
122 return false;
123
124 if ((pci_read_config32(dev, PCI_COMMAND) & UART_PCI_ENABLE)
125 != UART_PCI_ENABLE)
126 return false;
127
128 return !lpss_is_controller_in_reset(base);
Aamir Bohra01d75f42017-03-30 20:12:21 +0530129}
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530130
Subrata Banikafa07f72018-05-24 12:21:06 +0530131static void uart_configure_gpio_pads(void)
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530132{
Subrata Banikafa07f72018-05-24 12:21:06 +0530133 int index = uart_get_valid_index();
134
135 if (index != UART_CONSOLE_INVALID_INDEX)
136 gpio_configure_pads(uart_gpio_pads[index].gpios,
137 MAX_GPIO_PAD_PER_UART);
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530138}
139
Subrata Banikafa07f72018-05-24 12:21:06 +0530140void uart_bootblock_init(void)
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700141{
Aamir Bohra17cfba62019-07-25 20:56:54 +0530142 const struct device *dev_uart;
143
144 dev_uart = uart_get_device();
145
146 if (!dev_uart)
147 return;
148
Subrata Banikafa07f72018-05-24 12:21:06 +0530149 /* Program UART BAR0, command, reset and clock register */
Aamir Bohra17cfba62019-07-25 20:56:54 +0530150 uart_common_init(dev_uart, CONFIG_CONSOLE_UART_BASE_ADDRESS);
Subrata Banikafa07f72018-05-24 12:21:06 +0530151
Subrata Banikafa07f72018-05-24 12:21:06 +0530152 /* Configure the 2 pads per UART. */
153 uart_configure_gpio_pads();
154}
155
156#if ENV_RAMSTAGE
157
158static void uart_read_resources(struct device *dev)
159{
160 pci_dev_read_resources(dev);
161
162 /* Set the configured UART base address for the debug port */
Julius Wernercd49cce2019-03-05 16:53:33 -0800163 if (CONFIG(INTEL_LPSS_UART_FOR_CONSOLE) &&
Nico Hubera96e66a2018-11-11 02:51:14 +0100164 uart_is_debug_controller(dev)) {
Subrata Banikafa07f72018-05-24 12:21:06 +0530165 struct resource *res = find_resource(dev, PCI_BASE_ADDRESS_0);
166 /* Need to set the base and size for the resource allocator. */
Nico Huber99954182019-05-29 23:33:06 +0200167 res->base = CONFIG_CONSOLE_UART_BASE_ADDRESS;
168 res->size = 0x1000;
Subrata Banikafa07f72018-05-24 12:21:06 +0530169 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED |
170 IORESOURCE_FIXED;
171 }
172}
173
174/*
175 * Check if UART debug port controller needs to be initialized on resume.
176 *
177 * Returns:
178 * true = when SoC wants debug port initialization on resume
179 * false = otherwise
180 */
181static bool pch_uart_init_debug_controller_on_resume(void)
182{
183 global_nvs_t *gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
184
185 if (gnvs)
186 return !!gnvs->uior;
187
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700188 return false;
189}
190
191bool uart_is_debug_controller(struct device *dev)
192{
Subrata Banikafa07f72018-05-24 12:21:06 +0530193 return dev == uart_get_device();
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700194}
195
196/*
197 * This is a workaround to enable UART controller for the debug port if:
198 * 1. CONSOLE_SERIAL is not enabled in coreboot, and
199 * 2. This boot is S3 resume, and
200 * 3. SoC wants to initialize debug UART controller.
201 *
202 * This workaround is required because Linux kernel hangs on resume if console
203 * is not enabled in coreboot, but it is enabled in kernel and not suspended.
204 */
205static bool uart_controller_needs_init(struct device *dev)
206{
207 /*
Jonathan Neuschäfer5268b762018-02-12 12:24:25 +0100208 * If coreboot has CONSOLE_SERIAL enabled, the skip re-initializing
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700209 * controller here.
210 */
Julius Wernercd49cce2019-03-05 16:53:33 -0800211 if (CONFIG(CONSOLE_SERIAL))
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700212 return false;
213
214 /* If this device does not correspond to debug port, then skip. */
215 if (!uart_is_debug_controller(dev))
216 return false;
217
218 /* Initialize UART controller only on S3 resume. */
219 if (!acpi_is_wakeup_s3())
220 return false;
221
222 /*
Subrata Banikafa07f72018-05-24 12:21:06 +0530223 * check if SOC wants to initialize UART on resume
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700224 */
225 return pch_uart_init_debug_controller_on_resume();
226}
227
228static void uart_common_enable_resources(struct device *dev)
229{
230 pci_dev_enable_resources(dev);
231
232 if (uart_controller_needs_init(dev)) {
233 uintptr_t base;
234
235 base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & ~0xFFF;
236 if (base)
Usha P5e59a822019-08-09 18:42:00 +0530237 uart_lpss_init(dev, base);
Furquan Shaikha8198eb2017-08-04 16:12:19 -0700238 }
239}
240
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530241static struct device_operations device_ops = {
Elyes HAOUAS1d191272018-11-27 12:23:48 +0100242 .read_resources = uart_read_resources,
243 .set_resources = pci_dev_set_resources,
244 .enable_resources = uart_common_enable_resources,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530245 .ops_pci = &pci_dev_ops_pci,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530246};
247
248static const unsigned short pci_device_ids[] = {
249 PCI_DEVICE_ID_INTEL_SPT_UART0,
250 PCI_DEVICE_ID_INTEL_SPT_UART1,
251 PCI_DEVICE_ID_INTEL_SPT_UART2,
V Sowmya7c150472018-01-23 14:44:45 +0530252 PCI_DEVICE_ID_INTEL_SPT_H_UART0,
253 PCI_DEVICE_ID_INTEL_SPT_H_UART1,
254 PCI_DEVICE_ID_INTEL_SPT_H_UART2,
V Sowmyaacc2a482018-01-23 15:27:23 +0530255 PCI_DEVICE_ID_INTEL_KBP_H_UART0,
256 PCI_DEVICE_ID_INTEL_KBP_H_UART1,
257 PCI_DEVICE_ID_INTEL_KBP_H_UART2,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530258 PCI_DEVICE_ID_INTEL_APL_UART0,
259 PCI_DEVICE_ID_INTEL_APL_UART1,
260 PCI_DEVICE_ID_INTEL_APL_UART2,
261 PCI_DEVICE_ID_INTEL_APL_UART3,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700262 PCI_DEVICE_ID_INTEL_CNL_UART0,
263 PCI_DEVICE_ID_INTEL_CNL_UART1,
264 PCI_DEVICE_ID_INTEL_CNL_UART2,
Hannah Williamsf7149652017-05-13 16:18:02 -0700265 PCI_DEVICE_ID_INTEL_GLK_UART0,
266 PCI_DEVICE_ID_INTEL_GLK_UART1,
267 PCI_DEVICE_ID_INTEL_GLK_UART2,
268 PCI_DEVICE_ID_INTEL_GLK_UART3,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800269 PCI_DEVICE_ID_INTEL_CNP_H_UART0,
270 PCI_DEVICE_ID_INTEL_CNP_H_UART1,
271 PCI_DEVICE_ID_INTEL_CNP_H_UART2,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530272 PCI_DEVICE_ID_INTEL_ICP_UART0,
273 PCI_DEVICE_ID_INTEL_ICP_UART1,
274 PCI_DEVICE_ID_INTEL_ICP_UART2,
Ronak Kanabarda7ffb482019-02-05 01:51:13 +0530275 PCI_DEVICE_ID_INTEL_CMP_UART0,
276 PCI_DEVICE_ID_INTEL_CMP_UART1,
277 PCI_DEVICE_ID_INTEL_CMP_UART2,
Hannah Williamsf7149652017-05-13 16:18:02 -0700278 0,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530279};
280
281static const struct pci_driver pch_uart __pci_driver = {
Subrata Banikafa07f72018-05-24 12:21:06 +0530282 .ops = &device_ops,
283 .vendor = PCI_VENDOR_ID_INTEL,
Aamir Bohra83f7bae2017-04-26 19:30:41 +0530284 .devices = pci_device_ids,
285};
286#endif /* ENV_RAMSTAGE */