blob: 9941242fd503093cc87a0e848e2e600d41406377 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <console/console.h>
#include <northbridge/intel/haswell/haswell.h>
#include <southbridge/intel/lynxpoint/pch.h>
#include <types.h>
static void dmi_print_link_status(int loglevel)
{
const uint16_t dmilsts = dmibar_read16(DMILSTS);
printk(loglevel, "DMI: Running at Gen%u x%u\n", dmilsts & 0xf, dmilsts >> 4 & 0x1f);
}
#define RETRAIN (1 << 5)
#define LTRN (1 << 11)
static void dmi_setup_physical_layer(void)
{
/* Program DMI AFE settings, which are needed for DMI to work */
peg_dmi_recipe(false, 0);
/* Additional DMI programming steps */
dmibar_setbits32(0x258, 1 << 29);
dmibar_clrsetbits32(0x208, 0x7ff, 0x6b5);
dmibar_clrsetbits32(0x22c, 0xffff, 0x2020);
/* Write SA reference code version */
dmibar_write32(0x71c, 0x0000000f);
dmibar_write32(0x720, 0x01060200);
/* We also have to bring up the PCH side of the DMI link */
pch_dmi_setup_physical_layer();
/* Write-once settings */
dmibar_clrsetbits32(DMILCAP, 0x3f00f, 2 << 0);
printk(BIOS_DEBUG, "Retraining DMI at Gen2 speeds...\n");
dmi_print_link_status(BIOS_DEBUG);
/* Retrain link */
dmibar_setbits16(DMILCTL, RETRAIN);
do {} while (dmibar_read16(DMILSTS) & LTRN);
dmi_print_link_status(BIOS_DEBUG);
/* Retrain link again for DMI Gen2 speeds */
dmibar_setbits16(DMILCTL, RETRAIN);
do {} while (dmibar_read16(DMILSTS) & LTRN);
dmi_print_link_status(BIOS_INFO);
}
#define VC_ACTIVE (1U << 31)
#define VCNEGPND (1 << 1)
#define DMI_VC_CFG(vcid, tcmap) (VC_ACTIVE | ((vcid) << 24) | (tcmap))
static void dmi_tc_vc_mapping(void)
{
printk(BIOS_DEBUG, "Programming SA DMI VC/TC mappings...\n");
if (CONFIG(INTEL_LYNXPOINT_LP))
dmibar_setbits8(0xa78, 1 << 1);
/* Each TC is mapped to one and only one VC */
const u32 vc0 = DMI_VC_CFG(0, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 0));
const u32 vc1 = DMI_VC_CFG(1, (1 << 1));
const u32 vcp = DMI_VC_CFG(2, (1 << 2));
const u32 vcm = DMI_VC_CFG(7, (1 << 7));
dmibar_write32(DMIVC0RCTL, vc0);
dmibar_write32(DMIVC1RCTL, vc1);
dmibar_write32(DMIVCPRCTL, vcp);
dmibar_write32(DMIVCMRCTL, vcm);
/* Set Extended VC Count (EVCC) to 1 if VC1 is active */
dmibar_clrsetbits8(DMIPVCCAP1, 7, !!(vc1 & VC_ACTIVE));
/*
* We also have to program the PCH side of the DMI link. Since both ends
* must use the same Virtual Channel settings, we pass them as arguments.
*/
pch_dmi_tc_vc_mapping(vc0, vc1, vcp, vcm);
printk(BIOS_DEBUG, "Waiting for SA DMI VC negotiation... ");
do {} while (dmibar_read16(DMIVC0RSTS) & VCNEGPND);
do {} while (dmibar_read16(DMIVC1RSTS) & VCNEGPND);
do {} while (dmibar_read16(DMIVCPRSTS) & VCNEGPND);
do {} while (dmibar_read16(DMIVCMRSTS) & VCNEGPND);
printk(BIOS_DEBUG, "done!\n");
}
void dmi_early_init(void)
{
dmi_setup_physical_layer();
dmi_tc_vc_mapping();
}