x86: broadwell: Add support for serial I/O devices

Add support for initing the I2C device and ADSP on broadwell. These are
needed for sound to work.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Simon Glass 2019-02-16 20:25:03 -07:00 committed by Bin Meng
parent c692f82240
commit 3f3411ebf8
2 changed files with 192 additions and 0 deletions

View File

@ -20,7 +20,9 @@
#include <asm/arch/pch.h>
#include <asm/arch/pm.h>
#include <asm/arch/rcb.h>
#include <asm/arch/serialio.h>
#include <asm/arch/spi.h>
#include <dm/uclass-internal.h>
#define BIOS_CTRL 0xdc
@ -456,6 +458,111 @@ static void systemagent_init(void)
cpu_set_power_limits(28);
}
/* Enable LTR Auto Mode for D21:F1-F6 */
static void serialio_d21_ltr(u32 bar0)
{
/* 1. Program BAR0 + 808h[2] = 0b */
clrbits_le32(bar0 + SIO_REG_PPR_GEN, SIO_REG_PPR_GEN_LTR_MODE_MASK);
/* 2. Program BAR0 + 804h[1:0] = 00b */
clrbits_le32(bar0 + SIO_REG_PPR_RST, SIO_REG_PPR_RST_ASSERT);
/* 3. Program BAR0 + 804h[1:0] = 11b */
setbits_le32(bar0 + SIO_REG_PPR_RST, SIO_REG_PPR_RST_ASSERT);
/* 4. Program BAR0 + 814h[31:0] = 00000000h */
writel(0, bar0 + SIO_REG_AUTO_LTR);
}
/* Select I2C voltage of 1.8V or 3.3V */
static void serialio_i2c_voltage_sel(u32 bar0, uint voltage)
{
clrsetbits_le32(bar0 + SIO_REG_PPR_GEN, SIO_REG_PPR_GEN_VOLTAGE_MASK,
SIO_REG_PPR_GEN_VOLTAGE(voltage));
}
/* Put Serial IO D21:F0-F6 device into desired mode */
static void serialio_d21_mode(int sio_index, int int_pin, bool acpi_mode)
{
u32 portctrl = SIO_IOBP_PORTCTRL_PM_CAP_PRSNT;
/* Snoop select 1 */
portctrl |= SIO_IOBP_PORTCTRL_SNOOP_SELECT(1);
/* Set interrupt pin */
portctrl |= SIO_IOBP_PORTCTRL_INT_PIN(int_pin);
if (acpi_mode) {
/* Enable ACPI interrupt mode */
portctrl |= SIO_IOBP_PORTCTRL_ACPI_IRQ_EN;
}
pch_iobp_update(SIO_IOBP_PORTCTRLX(sio_index), 0, portctrl);
}
/* Init sequence to be run once, done as part of D21:F0 (SDMA) init */
static void serialio_init_once(bool acpi_mode)
{
if (acpi_mode) {
/* Enable ACPI IRQ for IRQ13, IRQ7, IRQ6, IRQ5 in RCBA */
setbits_le32(RCB_REG(ACPIIRQEN),
1 << 13 | 1 << 7 | 1 << 6 | 1 << 5);
}
/* Program IOBP CB000154h[12,9:8,4:0] = 1001100011111b */
pch_iobp_update(SIO_IOBP_GPIODF, ~0x0000131f, 0x0000131f);
/* Program IOBP CB000180h[5:0] = 111111b (undefined register) */
pch_iobp_update(0xcb000180, ~0x0000003f, 0x0000003f);
}
/**
* pch_serialio_init() - set up serial I/O devices
*
* @return 0 if OK, -ve on error
*/
static int pch_serialio_init(void)
{
struct udevice *dev, *hda;
bool acpi_mode = true;
u32 bar0, bar1;
int ret;
ret = uclass_find_first_device(UCLASS_I2C, &dev);
if (ret)
return ret;
bar0 = dm_pci_read_bar32(dev, 0);
if (!bar0)
return -EINVAL;
bar1 = dm_pci_read_bar32(dev, 1);
if (!bar1)
return -EINVAL;
serialio_init_once(acpi_mode);
serialio_d21_mode(SIO_ID_SDMA, SIO_PIN_INTB, acpi_mode);
serialio_d21_ltr(bar0);
serialio_i2c_voltage_sel(bar0, 1); /* Select 1.8V always */
serialio_d21_mode(SIO_ID_I2C0, SIO_PIN_INTC, acpi_mode);
setbits_le32(bar1 + PCH_PCS, PCH_PCS_PS_D3HOT);
clrbits_le32(bar1 + PCH_PCS, PCH_PCS_PS_D3HOT);
setbits_le32(bar0 + SIO_REG_PPR_CLOCK, SIO_REG_PPR_CLOCK_EN);
/* Manually find the High-definition audio, to turn it off */
ret = dm_pci_bus_find_bdf(PCI_BDF(0, 0x1b, 0), &hda);
if (ret)
return -ENOENT;
dm_pci_clrset_config8(hda, 0x43, 0, 0x6f);
/* Route I/O buffers to ADSP function */
dm_pci_clrset_config8(hda, 0x42, 0, 1 << 7 | 1 << 6);
log_debug("HDA disabled, I/O buffers routed to ADSP\n");
return 0;
}
static int broadwell_pch_init(struct udevice *dev)
{
int ret;
@ -482,6 +589,9 @@ static int broadwell_pch_init(struct udevice *dev)
return ret;
pch_pm_init(dev);
pch_cg_init(dev);
ret = pch_serialio_init();
if (ret)
return ret;
systemagent_init();
return 0;

View File

@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Serial IO defintiions (taken from coreboot file of same name)
*
* Copyright 2019 Google LLC
*/
#ifndef __ARCH_BROADWELL_SERIALIO_H_
#define __ARCH_BROADWELL_SERIALIO_H_
/* Serial IO IOBP Registers */
#define SIO_IOBP_PORTCTRL0 0xcb000000 /* SDIO D23:F0 */
#define SIO_IOBP_PORTCTRL0_ACPI_IRQ_EN BIT(5)
#define SIO_IOBP_PORTCTRL0_PCI_CONF_DIS BIT(4)
#define SIO_IOBP_PORTCTRL1 0xcb000014 /* SDIO D23:F0 */
#define SIO_IOBP_PORTCTRL1_SNOOP_SELECT(x) (((x) & 3) << 13)
#define SIO_IOBP_GPIODF 0xcb000154
#define SIO_IOBP_GPIODF_SDIO_IDLE_DET_EN BIT(4)
#define SIO_IOBP_GPIODF_DMA_IDLE_DET_EN BIT(3)
#define SIO_IOBP_GPIODF_UART_IDLE_DET_EN BIT(2)
#define SIO_IOBP_GPIODF_I2C_IDLE_DET_EN BIT(1)
#define SIO_IOBP_GPIODF_SPI_IDLE_DET_EN BIT(0)
#define SIO_IOBP_GPIODF_UART0_BYTE_ACCESS BIT(10)
#define SIO_IOBP_GPIODF_UART1_BYTE_ACCESS BIT(11)
#define SIO_IOBP_PORTCTRL2 0xcb000240 /* DMA D21:F0 */
#define SIO_IOBP_PORTCTRL3 0xcb000248 /* I2C0 D21:F1 */
#define SIO_IOBP_PORTCTRL4 0xcb000250 /* I2C1 D21:F2 */
#define SIO_IOBP_PORTCTRL5 0xcb000258 /* SPI0 D21:F3 */
#define SIO_IOBP_PORTCTRL6 0xcb000260 /* SPI1 D21:F4 */
#define SIO_IOBP_PORTCTRL7 0xcb000268 /* UART0 D21:F5 */
#define SIO_IOBP_PORTCTRL8 0xcb000270 /* UART1 D21:F6 */
#define SIO_IOBP_PORTCTRLX(x) (0xcb000240 + ((x) * 8))
/* PORTCTRL 2-8 have the same layout */
#define SIO_IOBP_PORTCTRL_ACPI_IRQ_EN BIT(21)
#define SIO_IOBP_PORTCTRL_PCI_CONF_DIS BIT(20)
#define SIO_IOBP_PORTCTRL_SNOOP_SELECT(x) (((x) & 3) << 18)
#define SIO_IOBP_PORTCTRL_INT_PIN(x) (((x) & 0xf) << 2)
#define SIO_IOBP_PORTCTRL_PM_CAP_PRSNT BIT(1)
#define SIO_IOBP_FUNCDIS0 0xce00aa07 /* DMA D21:F0 */
#define SIO_IOBP_FUNCDIS1 0xce00aa47 /* I2C0 D21:F1 */
#define SIO_IOBP_FUNCDIS2 0xce00aa87 /* I2C1 D21:F2 */
#define SIO_IOBP_FUNCDIS3 0xce00aac7 /* SPI0 D21:F3 */
#define SIO_IOBP_FUNCDIS4 0xce00ab07 /* SPI1 D21:F4 */
#define SIO_IOBP_FUNCDIS5 0xce00ab47 /* UART0 D21:F5 */
#define SIO_IOBP_FUNCDIS6 0xce00ab87 /* UART1 D21:F6 */
#define SIO_IOBP_FUNCDIS7 0xce00ae07 /* SDIO D23:F0 */
#define SIO_IOBP_FUNCDIS_DIS BIT(8)
/* Serial IO Devices */
#define SIO_ID_SDMA 0 /* D21:F0 */
#define SIO_ID_I2C0 1 /* D21:F1 */
#define SIO_ID_I2C1 2 /* D21:F2 */
#define SIO_ID_SPI0 3 /* D21:F3 */
#define SIO_ID_SPI1 4 /* D21:F4 */
#define SIO_ID_UART0 5 /* D21:F5 */
#define SIO_ID_UART1 6 /* D21:F6 */
#define SIO_ID_SDIO 7 /* D23:F0 */
#define SIO_REG_PPR_CLOCK 0x800
#define SIO_REG_PPR_CLOCK_EN BIT(0)
#define SIO_REG_PPR_CLOCK_UPDATE BIT(31)
#define SIO_REG_PPR_CLOCK_M_DIV 0x25a
#define SIO_REG_PPR_CLOCK_N_DIV 0x7fff
#define SIO_REG_PPR_RST 0x804
#define SIO_REG_PPR_RST_ASSERT 0x3
#define SIO_REG_PPR_GEN 0x808
#define SIO_REG_PPR_GEN_LTR_MODE_MASK BIT(2)
#define SIO_REG_PPR_GEN_VOLTAGE_MASK BIT(3)
#define SIO_REG_PPR_GEN_VOLTAGE(x) ((x & 1) << 3)
#define SIO_REG_AUTO_LTR 0x814
#define SIO_REG_SDIO_PPR_GEN 0x1008
#define SIO_REG_SDIO_PPR_SW_LTR 0x1010
#define SIO_REG_SDIO_PPR_CMD12 0x3c
#define SIO_REG_SDIO_PPR_CMD12_B30 BIT(30)
#define SIO_PIN_INTA 1 /* IRQ5 in ACPI mode */
#define SIO_PIN_INTB 2 /* IRQ6 in ACPI mode */
#define SIO_PIN_INTC 3 /* IRQ7 in ACPI mode */
#define SIO_PIN_INTD 4 /* IRQ13 in ACPI mode */
#endif /* __ARCH_BROADWELL_SERIALIO_H_ */