xref: /aosp_15_r20/external/coreboot/src/northbridge/intel/haswell/early_dmi.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <console/console.h>
4 #include <northbridge/intel/haswell/haswell.h>
5 #include <southbridge/intel/lynxpoint/pch.h>
6 #include <types.h>
7 
dmi_print_link_status(int loglevel)8 static void dmi_print_link_status(int loglevel)
9 {
10 	const uint16_t dmilsts = dmibar_read16(DMILSTS);
11 	printk(loglevel, "DMI: Running at Gen%u x%u\n", dmilsts & 0xf, dmilsts >> 4 & 0x1f);
12 }
13 
14 #define RETRAIN	(1 << 5)
15 
16 #define LTRN	(1 << 11)
17 
dmi_setup_physical_layer(void)18 static void dmi_setup_physical_layer(void)
19 {
20 	/* Program DMI AFE settings, which are needed for DMI to work */
21 	peg_dmi_recipe(false, 0);
22 
23 	/* Additional DMI programming steps */
24 	dmibar_setbits32(0x258, 1 << 29);
25 	dmibar_clrsetbits32(0x208, 0x7ff, 0x6b5);
26 	dmibar_clrsetbits32(0x22c, 0xffff, 0x2020);
27 
28 	/* Write SA reference code version */
29 	dmibar_write32(0x71c, 0x0000000f);
30 	dmibar_write32(0x720, 0x01060200);
31 
32 	/* We also have to bring up the PCH side of the DMI link */
33 	pch_dmi_setup_physical_layer();
34 
35 	/* Write-once settings */
36 	dmibar_clrsetbits32(DMILCAP, 0x3f00f, 2 << 0);
37 
38 	printk(BIOS_DEBUG, "Retraining DMI at Gen2 speeds...\n");
39 	dmi_print_link_status(BIOS_DEBUG);
40 
41 	/* Retrain link */
42 	dmibar_setbits16(DMILCTL, RETRAIN);
43 	do {} while (dmibar_read16(DMILSTS) & LTRN);
44 	dmi_print_link_status(BIOS_DEBUG);
45 
46 	/* Retrain link again for DMI Gen2 speeds */
47 	dmibar_setbits16(DMILCTL, RETRAIN);
48 	do {} while (dmibar_read16(DMILSTS) & LTRN);
49 	dmi_print_link_status(BIOS_INFO);
50 }
51 
52 #define VC_ACTIVE	(1U << 31)
53 
54 #define VCNEGPND	(1 << 1)
55 
56 #define DMI_VC_CFG(vcid, tcmap)	(VC_ACTIVE | ((vcid) << 24) | (tcmap))
57 
dmi_tc_vc_mapping(void)58 static void dmi_tc_vc_mapping(void)
59 {
60 	printk(BIOS_DEBUG, "Programming SA  DMI VC/TC mappings...\n");
61 
62 	if (CONFIG(INTEL_LYNXPOINT_LP))
63 		dmibar_setbits8(0xa78, 1 << 1);
64 
65 	/* Each TC is mapped to one and only one VC */
66 	const u32 vc0 = DMI_VC_CFG(0, (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 0));
67 	const u32 vc1 = DMI_VC_CFG(1, (1 << 1));
68 	const u32 vcp = DMI_VC_CFG(2, (1 << 2));
69 	const u32 vcm = DMI_VC_CFG(7, (1 << 7));
70 	dmibar_write32(DMIVC0RCTL, vc0);
71 	dmibar_write32(DMIVC1RCTL, vc1);
72 	dmibar_write32(DMIVCPRCTL, vcp);
73 	dmibar_write32(DMIVCMRCTL, vcm);
74 
75 	/* Set Extended VC Count (EVCC) to 1 if VC1 is active */
76 	dmibar_clrsetbits8(DMIPVCCAP1, 7, !!(vc1 & VC_ACTIVE));
77 
78 	/*
79 	 * We also have to program the PCH side of the DMI link. Since both ends
80 	 * must use the same Virtual Channel settings, we pass them as arguments.
81 	 */
82 	pch_dmi_tc_vc_mapping(vc0, vc1, vcp, vcm);
83 
84 	printk(BIOS_DEBUG, "Waiting for SA  DMI VC negotiation... ");
85 	do {} while (dmibar_read16(DMIVC0RSTS) & VCNEGPND);
86 	do {} while (dmibar_read16(DMIVC1RSTS) & VCNEGPND);
87 	do {} while (dmibar_read16(DMIVCPRSTS) & VCNEGPND);
88 	do {} while (dmibar_read16(DMIVCMRSTS) & VCNEGPND);
89 	printk(BIOS_DEBUG, "done!\n");
90 }
91 
dmi_early_init(void)92 void dmi_early_init(void)
93 {
94 	dmi_setup_physical_layer();
95 	dmi_tc_vc_mapping();
96 }
97