blob: d3bc0717f206cf2e25ae79d88686bf457f1b362b [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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; either version 2 of
* the License, or (at your option) any later version.
*
* 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.
*/
#include <arch/msr.h>
#include <libpayload.h>
#include "base/init_funcs.h"
#include "base/list.h"
#include "drivers/bus/i2c/cros_ec_tunnel.h"
#include "drivers/bus/i2c/designware.h"
#include "drivers/bus/i2c/i2c.h"
#include "drivers/ec/cros/lpc.h"
#include "drivers/ec/anx3429/anx3429.h"
#include "drivers/ec/ps8751/ps8751.h"
#include "drivers/gpio/kern.h"
#include "drivers/gpio/sysinfo.h"
#include "drivers/power/fch.h"
#include "drivers/soc/stoneyridge.h"
#include "drivers/sound/gpio_i2s.h"
#include "drivers/sound/gpio_amp.h"
#include "drivers/sound/route.h"
#include "drivers/storage/ahci.h"
#include "drivers/storage/blockdev.h"
#include "drivers/storage/sdhci.h"
#include "drivers/storage/bayhub.h"
#include "drivers/tpm/cr50_i2c.h"
#include "drivers/tpm/tpm.h"
#include "drivers/video/display.h"
#include "drivers/bus/usb/usb.h"
#include "pci.h"
#include "vboot/util/flag.h"
#define HW_CONFIG_REG 0xc0010015
#define HW_CONFIG_CPBDIS (1 << 25)
#define EMMC_SD_CLOCK_MIN 400000
#define EMMC_CLOCK_MAX 200000000
#define SD_CLOCK_MAX 52000000
#define DA7219_I2C_ADDR 0x1a
#define DA7219_DAI_CLK_MODE 0x2b
#define DAI_CLK_EN 0x80
/* cr50's interrupt in attached to GPIO_9 */
#define CR50_INT 9
#define BH720_PCI_VID 0x1217
#define BH720_PCI_DID 0x8620
#define GPIO_BACKLIGHT 133
/* GMMx1475C ACP_BT_UART_PAD_SEL */
#define GMMx1475C 0x1475c
#define EC_USB_PD_PORT_ANX3429 0
#define EC_I2C_PORT_ANX3429 1
#define EC_USB_PD_PORT_PS8751 1
#define EC_I2C_PORT_PS8751 2
int is_barla_alc5682(uint32_t id);
static int cr50_irq_status(void)
{
static KernGpio *tpm_gpio;
if (!tpm_gpio)
tpm_gpio = new_kern_fch_gpio_latched(CR50_INT);
return gpio_get(&tpm_gpio->ops);
}
/*
* Force reset GMMx1475C ACP_BT_UART_PAD_SEL to 0 to enable bit-banging the
* BT_I2S pins as GPIO. This reset happens on reboot and entering G3, but NOT
* in S5.
*/
static void audio_bt_i2s_setup(void)
{
/* D1F0x24 == Graphics Memory Mapped Registers Base Address */
uintptr_t gmm_base = pci_read_config32(PCI_DEV(0, 0x1, 0), 0x24);
gmm_base &= 0xfffffff0;
write32((void *)gmm_base + GMMx1475C, 0x00);
}
static int (*gpio_i2s_play)(struct SoundOps *me, uint32_t msec,
uint32_t frequency);
static int amd_gpio_i2s_play(struct SoundOps *me, uint32_t msec,
uint32_t frequency)
{
int ret;
uint64_t cur;
cur = _rdmsr(HW_CONFIG_REG);
/* Disable Core Boost while bit-banging I2S */
_wrmsr(HW_CONFIG_REG, cur | HW_CONFIG_CPBDIS);
ret = gpio_i2s_play(me, msec, frequency);
/* Restore previous Core Boost setting */
_wrmsr(HW_CONFIG_REG, cur);
return ret;
}
static void audio_setup(uint32_t skuid)
{
if (!is_barla_alc5682(skuid)) {
/* Setup da7219 on I2C0 */
DesignwareI2c *i2c0 = new_designware_i2c(AP_I2C0_ADDR, 400000,
AP_I2C_CLK_MHZ);
/* Clear DAI_CLK_MODE.dai_clk_en to set BCLK/WCLK pins as inputs */
int ret = i2c_clear_bits(&i2c0->ops, DA7219_I2C_ADDR,
DA7219_DAI_CLK_MODE, DAI_CLK_EN);
/*
* If we cannot clear DAI_CLK_EN, we may be fighting with it for
* control of BCLK/WCLK, so skip audio initialization.
*/
if (ret < 0) {
printf("Failed to clear dai_clk_en (%d), skipping bit-bang i2s config\n",
ret);
return;
}
}
audio_bt_i2s_setup();
KernGpio *i2s_bclk = new_kern_fch_gpio_output(140, 0);
KernGpio *i2s_lrclk = new_kern_fch_gpio_output(144, 0);
KernGpio *i2s2_data = new_kern_fch_gpio_output(143, 0);
GpioI2s *i2s = new_gpio_i2s(
&i2s_bclk->ops, /* I2S Bit Clock GPIO */
&i2s_lrclk->ops, /* I2S Frame Sync GPIO */
&i2s2_data->ops, /* I2S Data GPIO */
24000, /* Sample rate, measured */
2, /* Channels */
0x1FFF, /* Volume */
0); /* BCLK sync */
SoundRoute *sound_route = new_sound_route(&i2s->ops);
/*
* Override gpio_i2s play() op with our own that disbles CPU boost
* before GPIO bit-banging I2S.
*/
gpio_i2s_play = i2s->ops.play;
i2s->ops.play = amd_gpio_i2s_play;
KernGpio *spk_pa_en = new_kern_fch_gpio_output(119, 0);
GpioAmpCodec *speaker_amp = new_gpio_amp_codec(&spk_pa_en->ops);
list_insert_after(&speaker_amp->component.list_node,
&sound_route->components);
/* Disable BCLK buffer for GPIO beep */
new_kern_fch_gpio_output(135, 0);
sound_set_ops(&sound_route->ops);
}
static int grunt_backlight_update(DisplayOps *me, uint8_t enable)
{
/* Backlight signal is active low */
static KernGpio *backlight;
if (!backlight)
backlight = new_kern_fch_gpio_output(GPIO_BACKLIGHT, !enable);
else
backlight->ops.set(&backlight->ops, !enable);
return 0;
}
static DisplayOps grunt_display_ops = {
.backlight_update = &grunt_backlight_update,
};
int is_treeya(uint32_t id)
{
if ((id < 0xa0) || (id > 0xaf))
return 0;
else
return 1;
}
int is_nuwani(uint32_t id)
{
if ((id < 0xd0) || (id > 0xdf))
return 0;
else
return 1;
}
int is_barla_alc5682(uint32_t id)
{
switch(id) {
case 0x2c:
case 0x2d:
case 0x2e:
case 0x2f:
return 1;
default:
return 0;
}
}
static int board_setup(void)
{
CrosECTunnelI2c *cros_ec_i2c_tunnel;
sysinfo_install_flags(NULL);
CrosEcLpcBus *cros_ec_lpc_bus =
new_cros_ec_lpc_bus(CROS_EC_LPC_BUS_GENERIC);
CrosEc *cros_ec = new_cros_ec(&cros_ec_lpc_bus->ops, NULL);
register_vboot_ec(&cros_ec->vboot);
flag_replace(FLAG_LIDSW, cros_ec_lid_switch_flag());
flag_replace(FLAG_PWRSW, cros_ec_power_btn_flag());
/* programmables downstream from the EC */
cros_ec_i2c_tunnel =
new_cros_ec_tunnel_i2c(cros_ec, EC_I2C_PORT_PS8751);
Ps8751 *ps8751 = new_ps8751(cros_ec_i2c_tunnel, EC_USB_PD_PORT_PS8751);
register_vboot_auxfw(&ps8751->fw_ops);
/* Treeya variant use anx3447 which do not have on board OCM and does
* not support firmware update. Treeya && Treeya360 sku id range is:
* 0xa0 - 0xaf. Nuwani and Nuwani360 sku id range is: 0xd0 - 0xdf
*/
if (!is_treeya(lib_sysinfo.sku_id) && !is_nuwani(lib_sysinfo.sku_id)) {
cros_ec_i2c_tunnel =
new_cros_ec_tunnel_i2c(cros_ec, EC_I2C_PORT_ANX3429);
Anx3429 *anx3429 =
new_anx3429(cros_ec_i2c_tunnel, EC_USB_PD_PORT_ANX3429);
register_vboot_auxfw(&anx3429->fw_ops);
}
audio_setup(lib_sysinfo.sku_id);
SdhciHost *emmc = NULL;
/* The proto version of Grunt has the FT4's SDHCI pins wired up to
* the eMMC part. All other versions of Grunt (are planned to) use
* the BH720 SDHCI controller for EMMC and use the FT4 SDHCI pins for
* the SD connector.
*/
if (lib_sysinfo.board_id > 0) {
pcidev_t pci_dev;
if (pci_find_device(BH720_PCI_VID, BH720_PCI_DID, &pci_dev)) {
emmc = new_bayhub_sdhci_host(
pci_dev, 0, EMMC_SD_CLOCK_MIN, EMMC_CLOCK_MAX);
emmc->name = "eMMC";
// TODO(b/168211204): Remove this quirk
emmc->quirks |= SDHCI_QUIRK_CLEAR_TRANSFER_BEFORE_CMD;
} else {
printf("Failed to find BH720 with VID/DID %04x:%04x\n",
BH720_PCI_VID, BH720_PCI_DID);
}
SdhciHost *sd;
sd = new_pci_sdhci_host(PCI_DEV(0, 0x14, 7),
SDHCI_PLATFORM_REMOVABLE,
EMMC_SD_CLOCK_MIN, SD_CLOCK_MAX);
sd->name = "SD";
sd->quirks |= SDHCI_QUIRK_CLEAR_TRANSFER_BEFORE_CMD;
list_insert_after(&sd->mmc_ctrlr.ctrlr.list_node,
&removable_block_dev_controllers);
} else {
emmc = new_pci_sdhci_host(PCI_DEV(0, 0x14, 7),
SDHCI_PLATFORM_NO_EMMC_HS200,
EMMC_SD_CLOCK_MIN, EMMC_CLOCK_MAX);
emmc->quirks |= SDHCI_QUIRK_CLEAR_TRANSFER_BEFORE_CMD;
}
if (emmc) {
list_insert_after(&emmc->mmc_ctrlr.ctrlr.list_node,
&fixed_block_dev_controllers);
}
/* Setup h1 on I2C1 */
DesignwareI2c *i2c_h1 = new_designware_i2c(
AP_I2C1_ADDR, 400000, AP_I2C_CLK_MHZ);
tpm_set_ops(&new_cr50_i2c(&i2c_h1->ops, 0x50,
&cr50_irq_status)->base.ops);
power_set_ops(&kern_power_ops);
display_set_ops(&grunt_display_ops);
return 0;
}
INIT_FUNC(board_setup);