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 <dlaurie@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/199807
This commit is contained in:
parent
1050e7d3be
commit
ecebda4eb5
5 changed files with 125 additions and 2 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
85
src/soc/intel/broadwell/romstage/uart.c
Normal file
85
src/soc/intel/broadwell/romstage/uart.c
Normal file
|
|
@ -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 <arch/early_variables.h>
|
||||
#include <arch/io.h>
|
||||
#include <delay.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <reg_script.h>
|
||||
#include <stdint.h>
|
||||
#include <uart8250.h>
|
||||
#include <broadwell/iobp.h>
|
||||
#include <broadwell/serialio.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue