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