From ecebda4eb5d6fe58473d25c2898ba1a2eac0f39a Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Mon, 5 May 2014 12:42:28 -0500 Subject: [PATCH] broadwell: Add romstage code to configure PCH UART for console The two UARTs built into the haswell/broadwell PCH can be used for standard console output if configured properly. There is a magic bit in the IOBP settings for the UART device that will put it into "byte addressing mode" so it is compatible with standard 16550 UART drivers. When in this mode the linux kernel driver will be unable to talk to the device so it is indicated as disabled via the ACPI driver. Note that this by itself is not enough to get working MMIO UART in coreboot because the current code is heavily tied with the oxpcie driver. I have a separate set of patches to disentangle the generic MMIO UART code from the oxpcie driver but I want to get that series in upstream first. BUG=chrome-os-partner:28234 TEST=None Change-Id: I9e689456aa5017784328d1be33ad072f79db1920 Signed-off-by: Duncan Laurie Reviewed-on: https://chromium-review.googlesource.com/199807 --- src/soc/intel/broadwell/Kconfig | 17 ++++ src/soc/intel/broadwell/broadwell/romstage.h | 1 + src/soc/intel/broadwell/romstage/Makefile.inc | 1 + src/soc/intel/broadwell/romstage/uart.c | 85 +++++++++++++++++++ src/soc/intel/broadwell/serialio.c | 23 ++++- 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 src/soc/intel/broadwell/romstage/uart.c diff --git a/src/soc/intel/broadwell/Kconfig b/src/soc/intel/broadwell/Kconfig index 47b3116be6..987f1f4865 100644 --- a/src/soc/intel/broadwell/Kconfig +++ b/src/soc/intel/broadwell/Kconfig @@ -175,6 +175,23 @@ config MONOTONIC_TIMER_MSR help Provide a monotonic timer using the 24MHz MSR counter. +config INTEL_PCH_UART_CONSOLE + bool "Use Serial IO UART for console" + default n + select HAVE_UART_MEMORY_MAPPED + select CONSOLE_SERIAL8250MEM + depends on !CONFIG_DRIVERS_OXFORD_OXPCIE + +config INTEL_PCH_UART_CONSOLE_NUMBER + hex "Serial IO UART number to use for console" + default "0x0" + depends on INTEL_PCH_UART_CONSOLE + +config TTYS0_BASE + hex + default 0xd6000000 + depends on INTEL_PCH_UART_CONSOLE + config EHCI_BAR hex default 0xd8000000 diff --git a/src/soc/intel/broadwell/broadwell/romstage.h b/src/soc/intel/broadwell/broadwell/romstage.h index d48ec13106..42af8f5cff 100644 --- a/src/soc/intel/broadwell/broadwell/romstage.h +++ b/src/soc/intel/broadwell/broadwell/romstage.h @@ -52,6 +52,7 @@ void set_max_freq(void); void systemagent_early_init(void); void pch_early_init(void); +void pch_uart_init(void); void intel_early_me_status(void); void enable_smbus(void); diff --git a/src/soc/intel/broadwell/romstage/Makefile.inc b/src/soc/intel/broadwell/romstage/Makefile.inc index 98d87a4965..f8a961795b 100644 --- a/src/soc/intel/broadwell/romstage/Makefile.inc +++ b/src/soc/intel/broadwell/romstage/Makefile.inc @@ -10,3 +10,4 @@ romstage-y += smbus.c romstage-y += spi.c romstage-y += stack.c romstage-y += systemagent.c +romstage-$(CONFIG_CONSOLE_SERIAL8250MEM) += uart.c diff --git a/src/soc/intel/broadwell/romstage/uart.c b/src/soc/intel/broadwell/romstage/uart.c new file mode 100644 index 0000000000..8214a8a116 --- /dev/null +++ b/src/soc/intel/broadwell/romstage/uart.c @@ -0,0 +1,85 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const struct reg_script uart_init[] = { + /* Set MMIO BAR */ + REG_PCI_WRITE32(PCI_BASE_ADDRESS_0, CONFIG_TTYS0_BASE), + /* Enable Memory access and Bus Master */ + REG_PCI_OR32(PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER), + /* Initialize LTR */ + REG_MMIO_RMW32(CONFIG_TTYS0_BASE + SIO_REG_PPR_GEN, + ~SIO_REG_PPR_GEN_LTR_MODE_MASK, 0), + REG_MMIO_RMW32(CONFIG_TTYS0_BASE + SIO_REG_PPR_RST, + ~(SIO_REG_PPR_RST_ASSERT), 0), + /* Take UART out of reset */ + REG_MMIO_OR32(CONFIG_TTYS0_BASE + SIO_REG_PPR_RST, + SIO_REG_PPR_RST_ASSERT), + /* Set M and N divisor inputs and enable clock */ + REG_MMIO_WRITE32(CONFIG_TTYS0_BASE + SIO_REG_PPR_CLOCK, + SIO_REG_PPR_CLOCK_EN | SIO_REG_PPR_CLOCK_UPDATE | + (SIO_REG_PPR_CLOCK_N_DIV << 16) | + (SIO_REG_PPR_CLOCK_M_DIV << 1)), + REG_SCRIPT_END +}; + +void pch_uart_init(void) +{ + /* Program IOBP CB000154h[12,9:8,4:0] = 1001100011111b */ + u32 gpiodf = 0x131f; + device_t dev; + + /* Put UART in byte access mode for 16550 compatibility */ + switch (CONFIG_INTEL_PCH_UART_CONSOLE_NUMBER) { + case 0: + dev = PCH_DEV_UART0; + gpiodf |= SIO_IOBP_GPIODF_UART0_BYTE_ACCESS; + break; + case 1: + dev = PCH_DEV_UART1; + gpiodf |= SIO_IOBP_GPIODF_UART1_BYTE_ACCESS; + break; + default: + return; + } + + /* Program IOBP GPIODF */ + pch_iobp_update(SIO_IOBP_GPIODF, ~gpiodf, gpiodf); + + /* Program IOBP CB000180h[5:0] = 111111b (undefined register) */ + pch_iobp_update(0xcb000180, ~0x0000003f, 0x0000003f); + + /* Initialize chipset uart interface */ + reg_script_run_on_dev(dev, uart_init); + + /* + * Perform standard UART initialization + * Divisor 1 is 115200 BAUD + */ + uart8250_mem_init(CONFIG_TTYS0_BASE, 1); +} diff --git a/src/soc/intel/broadwell/serialio.c b/src/soc/intel/broadwell/serialio.c index bbb018f87a..e3ce28a231 100644 --- a/src/soc/intel/broadwell/serialio.c +++ b/src/soc/intel/broadwell/serialio.c @@ -41,6 +41,19 @@ static void serialio_enable_d3hot(struct device *dev) pci_write_config32(dev, PCH_PCS, reg32); } +static int serialio_uart_is_debug(struct device *dev) +{ +#if CONFIG_INTEL_PCH_UART_CONSOLE + switch (dev->path.pci.devfn) { + case PCI_DEVFN(21, 5): /* UART0 */ + return !!(CONFIG_INTEL_PCH_UART_CONSOLE_NUMBER == 0); + case PCI_DEVFN(21, 6): /* UART1 */ + return !!(CONFIG_INTEL_PCH_UART_CONSOLE_NUMBER == 1); + } +#endif + return 0; +} + /* Enable clock in PCI mode */ static void serialio_enable_clock(struct resource *bar0) { @@ -220,13 +233,15 @@ static void serialio_init(struct device *dev) break; case PCI_DEVFN(21, 5): /* UART0 */ sio_index = SIO_ID_UART0; - serialio_d21_ltr(bar0); + if (!serialio_uart_is_debug(dev)) + serialio_d21_ltr(bar0); serialio_d21_mode(sio_index, SIO_PIN_INTD, config->sio_acpi_mode); break; case PCI_DEVFN(21, 6): /* UART1 */ sio_index = SIO_ID_UART1; - serialio_d21_ltr(bar0); + if (!serialio_uart_is_debug(dev)) + serialio_d21_ltr(bar0); serialio_d21_mode(sio_index, SIO_PIN_INTD, config->sio_acpi_mode); break; @@ -252,6 +267,10 @@ static void serialio_init(struct device *dev) /* Save BAR0 and BAR1 to ACPI NVS */ gnvs->dev.bar0[sio_index] = (u32)bar0->base; gnvs->dev.bar1[sio_index] = (u32)bar1->base; + + /* Do not enable UART if it is used as debug port */ + if (!serialio_uart_is_debug(dev)) + gnvs->dev.enable[sio_index] = 1; } }