165dd74a6SSimon Glass /* 265dd74a6SSimon Glass * From Coreboot src/southbridge/intel/bd82x6x/early_me.c 365dd74a6SSimon Glass * 465dd74a6SSimon Glass * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. 565dd74a6SSimon Glass * 665dd74a6SSimon Glass * SPDX-License-Identifier: GPL-2.0 765dd74a6SSimon Glass */ 865dd74a6SSimon Glass 965dd74a6SSimon Glass #include <common.h> 1065dd74a6SSimon Glass #include <errno.h> 1165dd74a6SSimon Glass #include <asm/pci.h> 1265dd74a6SSimon Glass #include <asm/processor.h> 1365dd74a6SSimon Glass #include <asm/arch/me.h> 1465dd74a6SSimon Glass #include <asm/arch/pch.h> 1565dd74a6SSimon Glass #include <asm/io.h> 1665dd74a6SSimon Glass 1765dd74a6SSimon Glass static const char *const me_ack_values[] = { 1865dd74a6SSimon Glass [ME_HFS_ACK_NO_DID] = "No DID Ack received", 1965dd74a6SSimon Glass [ME_HFS_ACK_RESET] = "Non-power cycle reset", 2065dd74a6SSimon Glass [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", 2165dd74a6SSimon Glass [ME_HFS_ACK_S3] = "Go to S3", 2265dd74a6SSimon Glass [ME_HFS_ACK_S4] = "Go to S4", 2365dd74a6SSimon Glass [ME_HFS_ACK_S5] = "Go to S5", 2465dd74a6SSimon Glass [ME_HFS_ACK_GBL_RESET] = "Global Reset", 2565dd74a6SSimon Glass [ME_HFS_ACK_CONTINUE] = "Continue to boot" 2665dd74a6SSimon Glass }; 2765dd74a6SSimon Glass 2865dd74a6SSimon Glass static inline void pci_read_dword_ptr(void *ptr, int offset) 2965dd74a6SSimon Glass { 3065dd74a6SSimon Glass u32 dword; 3165dd74a6SSimon Glass 3231f57c28SSimon Glass dword = x86_pci_read_config32(PCH_ME_DEV, offset); 3365dd74a6SSimon Glass memcpy(ptr, &dword, sizeof(dword)); 3465dd74a6SSimon Glass } 3565dd74a6SSimon Glass 3665dd74a6SSimon Glass static inline void pci_write_dword_ptr(void *ptr, int offset) 3765dd74a6SSimon Glass { 3865dd74a6SSimon Glass u32 dword = 0; 3965dd74a6SSimon Glass memcpy(&dword, ptr, sizeof(dword)); 4031f57c28SSimon Glass x86_pci_write_config32(PCH_ME_DEV, offset, dword); 4165dd74a6SSimon Glass } 4265dd74a6SSimon Glass 4365dd74a6SSimon Glass void intel_early_me_status(void) 4465dd74a6SSimon Glass { 4565dd74a6SSimon Glass struct me_hfs hfs; 4665dd74a6SSimon Glass struct me_gmes gmes; 4765dd74a6SSimon Glass 4865dd74a6SSimon Glass pci_read_dword_ptr(&hfs, PCI_ME_HFS); 4965dd74a6SSimon Glass pci_read_dword_ptr(&gmes, PCI_ME_GMES); 5065dd74a6SSimon Glass 5165dd74a6SSimon Glass intel_me_status(&hfs, &gmes); 5265dd74a6SSimon Glass } 5365dd74a6SSimon Glass 5465dd74a6SSimon Glass int intel_early_me_init(void) 5565dd74a6SSimon Glass { 5665dd74a6SSimon Glass int count; 5765dd74a6SSimon Glass struct me_uma uma; 5865dd74a6SSimon Glass struct me_hfs hfs; 5965dd74a6SSimon Glass 6065dd74a6SSimon Glass debug("Intel ME early init\n"); 6165dd74a6SSimon Glass 6265dd74a6SSimon Glass /* Wait for ME UMA SIZE VALID bit to be set */ 6365dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 6465dd74a6SSimon Glass pci_read_dword_ptr(&uma, PCI_ME_UMA); 6565dd74a6SSimon Glass if (uma.valid) 6665dd74a6SSimon Glass break; 6765dd74a6SSimon Glass udelay(ME_DELAY); 6865dd74a6SSimon Glass } 6965dd74a6SSimon Glass if (!count) { 7065dd74a6SSimon Glass printf("ERROR: ME is not ready!\n"); 7165dd74a6SSimon Glass return -EBUSY; 7265dd74a6SSimon Glass } 7365dd74a6SSimon Glass 7465dd74a6SSimon Glass /* Check for valid firmware */ 7565dd74a6SSimon Glass pci_read_dword_ptr(&hfs, PCI_ME_HFS); 7665dd74a6SSimon Glass if (hfs.fpt_bad) { 7765dd74a6SSimon Glass printf("WARNING: ME has bad firmware\n"); 7865dd74a6SSimon Glass return -EBADF; 7965dd74a6SSimon Glass } 8065dd74a6SSimon Glass 8165dd74a6SSimon Glass debug("Intel ME firmware is ready\n"); 8265dd74a6SSimon Glass 8365dd74a6SSimon Glass return 0; 8465dd74a6SSimon Glass } 8565dd74a6SSimon Glass 8665dd74a6SSimon Glass int intel_early_me_uma_size(void) 8765dd74a6SSimon Glass { 8865dd74a6SSimon Glass struct me_uma uma; 8965dd74a6SSimon Glass 9065dd74a6SSimon Glass pci_read_dword_ptr(&uma, PCI_ME_UMA); 9165dd74a6SSimon Glass if (uma.valid) { 9265dd74a6SSimon Glass debug("ME: Requested %uMB UMA\n", uma.size); 9365dd74a6SSimon Glass return uma.size; 9465dd74a6SSimon Glass } 9565dd74a6SSimon Glass 9665dd74a6SSimon Glass debug("ME: Invalid UMA size\n"); 9765dd74a6SSimon Glass return -EINVAL; 9865dd74a6SSimon Glass } 9965dd74a6SSimon Glass 10065dd74a6SSimon Glass static inline void set_global_reset(int enable) 10165dd74a6SSimon Glass { 10265dd74a6SSimon Glass u32 etr3; 10365dd74a6SSimon Glass 10431f57c28SSimon Glass etr3 = x86_pci_read_config32(PCH_LPC_DEV, ETR3); 10565dd74a6SSimon Glass 10665dd74a6SSimon Glass /* Clear CF9 Without Resume Well Reset Enable */ 10765dd74a6SSimon Glass etr3 &= ~ETR3_CWORWRE; 10865dd74a6SSimon Glass 10965dd74a6SSimon Glass /* CF9GR indicates a Global Reset */ 11065dd74a6SSimon Glass if (enable) 11165dd74a6SSimon Glass etr3 |= ETR3_CF9GR; 11265dd74a6SSimon Glass else 11365dd74a6SSimon Glass etr3 &= ~ETR3_CF9GR; 11465dd74a6SSimon Glass 11531f57c28SSimon Glass x86_pci_write_config32(PCH_LPC_DEV, ETR3, etr3); 11665dd74a6SSimon Glass } 11765dd74a6SSimon Glass 11865dd74a6SSimon Glass int intel_early_me_init_done(u8 status) 11965dd74a6SSimon Glass { 12065dd74a6SSimon Glass int count; 12165dd74a6SSimon Glass u32 mebase_l, mebase_h; 12265dd74a6SSimon Glass struct me_hfs hfs; 12365dd74a6SSimon Glass struct me_did did = { 12465dd74a6SSimon Glass .init_done = ME_INIT_DONE, 12565dd74a6SSimon Glass .status = status 12665dd74a6SSimon Glass }; 12765dd74a6SSimon Glass 12865dd74a6SSimon Glass /* MEBASE from MESEG_BASE[35:20] */ 12931f57c28SSimon Glass mebase_l = x86_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L); 13031f57c28SSimon Glass mebase_h = x86_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H); 13165dd74a6SSimon Glass mebase_h &= 0xf; 13265dd74a6SSimon Glass did.uma_base = (mebase_l >> 20) | (mebase_h << 12); 13365dd74a6SSimon Glass 13465dd74a6SSimon Glass /* Send message to ME */ 13565dd74a6SSimon Glass debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", 13665dd74a6SSimon Glass status, did.uma_base); 13765dd74a6SSimon Glass 13865dd74a6SSimon Glass pci_write_dword_ptr(&did, PCI_ME_H_GS); 13965dd74a6SSimon Glass 14065dd74a6SSimon Glass /* Must wait for ME acknowledgement */ 14165dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 14265dd74a6SSimon Glass pci_read_dword_ptr(&hfs, PCI_ME_HFS); 14365dd74a6SSimon Glass if (hfs.bios_msg_ack) 14465dd74a6SSimon Glass break; 14565dd74a6SSimon Glass udelay(ME_DELAY); 14665dd74a6SSimon Glass } 14765dd74a6SSimon Glass if (!count) { 14865dd74a6SSimon Glass printf("ERROR: ME failed to respond\n"); 14965dd74a6SSimon Glass return -1; 15065dd74a6SSimon Glass } 15165dd74a6SSimon Glass 15265dd74a6SSimon Glass /* Return the requested BIOS action */ 15365dd74a6SSimon Glass debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); 15465dd74a6SSimon Glass 15565dd74a6SSimon Glass /* Check status after acknowledgement */ 15665dd74a6SSimon Glass intel_early_me_status(); 15765dd74a6SSimon Glass 15865dd74a6SSimon Glass switch (hfs.ack_data) { 15965dd74a6SSimon Glass case ME_HFS_ACK_CONTINUE: 16065dd74a6SSimon Glass /* Continue to boot */ 16165dd74a6SSimon Glass return 0; 16265dd74a6SSimon Glass case ME_HFS_ACK_RESET: 16365dd74a6SSimon Glass /* Non-power cycle reset */ 16465dd74a6SSimon Glass set_global_reset(0); 165*5021c81fSSimon Glass reset_cpu(0); 16665dd74a6SSimon Glass break; 16765dd74a6SSimon Glass case ME_HFS_ACK_PWR_CYCLE: 16865dd74a6SSimon Glass /* Power cycle reset */ 16965dd74a6SSimon Glass set_global_reset(0); 170*5021c81fSSimon Glass x86_full_reset(); 17165dd74a6SSimon Glass break; 17265dd74a6SSimon Glass case ME_HFS_ACK_GBL_RESET: 17365dd74a6SSimon Glass /* Global reset */ 17465dd74a6SSimon Glass set_global_reset(1); 175*5021c81fSSimon Glass x86_full_reset(); 17665dd74a6SSimon Glass break; 17765dd74a6SSimon Glass case ME_HFS_ACK_S3: 17865dd74a6SSimon Glass case ME_HFS_ACK_S4: 17965dd74a6SSimon Glass case ME_HFS_ACK_S5: 18065dd74a6SSimon Glass break; 18165dd74a6SSimon Glass } 18265dd74a6SSimon Glass 18365dd74a6SSimon Glass return -1; 18465dd74a6SSimon Glass } 185