Angel Pons | 567ece4 | 2022-05-06 21:56:48 +0200 | [diff] [blame] | 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 | |
| 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 | |
| 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 | |
| 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 | |
| 92 | void dmi_early_init(void) |
| 93 | { |
| 94 | dmi_setup_physical_layer(); |
| 95 | dmi_tc_vc_mapping(); |
| 96 | } |