1 /* 2 * From Coreboot src/southbridge/intel/bd82x6x/early_me.c 3 * 4 * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. 5 * 6 * SPDX-License-Identifier: GPL-2.0 7 */ 8 9 #include <common.h> 10 #include <errno.h> 11 #include <asm/pci.h> 12 #include <asm/processor.h> 13 #include <asm/arch/me.h> 14 #include <asm/arch/pch.h> 15 #include <asm/io.h> 16 17 static const char *const me_ack_values[] = { 18 [ME_HFS_ACK_NO_DID] = "No DID Ack received", 19 [ME_HFS_ACK_RESET] = "Non-power cycle reset", 20 [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", 21 [ME_HFS_ACK_S3] = "Go to S3", 22 [ME_HFS_ACK_S4] = "Go to S4", 23 [ME_HFS_ACK_S5] = "Go to S5", 24 [ME_HFS_ACK_GBL_RESET] = "Global Reset", 25 [ME_HFS_ACK_CONTINUE] = "Continue to boot" 26 }; 27 28 static inline void pci_read_dword_ptr(void *ptr, int offset) 29 { 30 u32 dword; 31 32 dword = pci_read_config32(PCH_ME_DEV, offset); 33 memcpy(ptr, &dword, sizeof(dword)); 34 } 35 36 static inline void pci_write_dword_ptr(void *ptr, int offset) 37 { 38 u32 dword = 0; 39 memcpy(&dword, ptr, sizeof(dword)); 40 pci_write_config32(PCH_ME_DEV, offset, dword); 41 } 42 43 void intel_early_me_status(void) 44 { 45 struct me_hfs hfs; 46 struct me_gmes gmes; 47 48 pci_read_dword_ptr(&hfs, PCI_ME_HFS); 49 pci_read_dword_ptr(&gmes, PCI_ME_GMES); 50 51 intel_me_status(&hfs, &gmes); 52 } 53 54 int intel_early_me_init(void) 55 { 56 int count; 57 struct me_uma uma; 58 struct me_hfs hfs; 59 60 debug("Intel ME early init\n"); 61 62 /* Wait for ME UMA SIZE VALID bit to be set */ 63 for (count = ME_RETRY; count > 0; --count) { 64 pci_read_dword_ptr(&uma, PCI_ME_UMA); 65 if (uma.valid) 66 break; 67 udelay(ME_DELAY); 68 } 69 if (!count) { 70 printf("ERROR: ME is not ready!\n"); 71 return -EBUSY; 72 } 73 74 /* Check for valid firmware */ 75 pci_read_dword_ptr(&hfs, PCI_ME_HFS); 76 if (hfs.fpt_bad) { 77 printf("WARNING: ME has bad firmware\n"); 78 return -EBADF; 79 } 80 81 debug("Intel ME firmware is ready\n"); 82 83 return 0; 84 } 85 86 int intel_early_me_uma_size(void) 87 { 88 struct me_uma uma; 89 90 pci_read_dword_ptr(&uma, PCI_ME_UMA); 91 if (uma.valid) { 92 debug("ME: Requested %uMB UMA\n", uma.size); 93 return uma.size; 94 } 95 96 debug("ME: Invalid UMA size\n"); 97 return -EINVAL; 98 } 99 100 static inline void set_global_reset(int enable) 101 { 102 u32 etr3; 103 104 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); 105 106 /* Clear CF9 Without Resume Well Reset Enable */ 107 etr3 &= ~ETR3_CWORWRE; 108 109 /* CF9GR indicates a Global Reset */ 110 if (enable) 111 etr3 |= ETR3_CF9GR; 112 else 113 etr3 &= ~ETR3_CF9GR; 114 115 pci_write_config32(PCH_LPC_DEV, ETR3, etr3); 116 } 117 118 int intel_early_me_init_done(u8 status) 119 { 120 u8 reset; 121 int count; 122 u32 mebase_l, mebase_h; 123 struct me_hfs hfs; 124 struct me_did did = { 125 .init_done = ME_INIT_DONE, 126 .status = status 127 }; 128 129 /* MEBASE from MESEG_BASE[35:20] */ 130 mebase_l = pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L); 131 mebase_h = pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H); 132 mebase_h &= 0xf; 133 did.uma_base = (mebase_l >> 20) | (mebase_h << 12); 134 135 /* Send message to ME */ 136 debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", 137 status, did.uma_base); 138 139 pci_write_dword_ptr(&did, PCI_ME_H_GS); 140 141 /* Must wait for ME acknowledgement */ 142 for (count = ME_RETRY; count > 0; --count) { 143 pci_read_dword_ptr(&hfs, PCI_ME_HFS); 144 if (hfs.bios_msg_ack) 145 break; 146 udelay(ME_DELAY); 147 } 148 if (!count) { 149 printf("ERROR: ME failed to respond\n"); 150 return -1; 151 } 152 153 /* Return the requested BIOS action */ 154 debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); 155 156 /* Check status after acknowledgement */ 157 intel_early_me_status(); 158 159 reset = 0; 160 switch (hfs.ack_data) { 161 case ME_HFS_ACK_CONTINUE: 162 /* Continue to boot */ 163 return 0; 164 case ME_HFS_ACK_RESET: 165 /* Non-power cycle reset */ 166 set_global_reset(0); 167 reset = 0x06; 168 break; 169 case ME_HFS_ACK_PWR_CYCLE: 170 /* Power cycle reset */ 171 set_global_reset(0); 172 reset = 0x0e; 173 break; 174 case ME_HFS_ACK_GBL_RESET: 175 /* Global reset */ 176 set_global_reset(1); 177 reset = 0x0e; 178 break; 179 case ME_HFS_ACK_S3: 180 case ME_HFS_ACK_S4: 181 case ME_HFS_ACK_S5: 182 break; 183 } 184 185 /* Perform the requested reset */ 186 if (reset) { 187 outb(reset, 0xcf9); 188 cpu_hlt(); 189 } 190 return -1; 191 } 192