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