1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0 265dd74a6SSimon Glass /* 365dd74a6SSimon Glass * From Coreboot src/southbridge/intel/bd82x6x/early_me.c 465dd74a6SSimon Glass * 565dd74a6SSimon Glass * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. 665dd74a6SSimon Glass */ 765dd74a6SSimon Glass 865dd74a6SSimon Glass #include <common.h> 9c02a4242SSimon Glass #include <dm.h> 1065dd74a6SSimon Glass #include <errno.h> 1165dd74a6SSimon Glass #include <asm/pci.h> 1298655f3aSSimon Glass #include <asm/cpu.h> 1365dd74a6SSimon Glass #include <asm/processor.h> 1465dd74a6SSimon Glass #include <asm/arch/me.h> 1565dd74a6SSimon Glass #include <asm/arch/pch.h> 1665dd74a6SSimon Glass #include <asm/io.h> 1765dd74a6SSimon Glass 1865dd74a6SSimon Glass static const char *const me_ack_values[] = { 1965dd74a6SSimon Glass [ME_HFS_ACK_NO_DID] = "No DID Ack received", 2065dd74a6SSimon Glass [ME_HFS_ACK_RESET] = "Non-power cycle reset", 2165dd74a6SSimon Glass [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", 2265dd74a6SSimon Glass [ME_HFS_ACK_S3] = "Go to S3", 2365dd74a6SSimon Glass [ME_HFS_ACK_S4] = "Go to S4", 2465dd74a6SSimon Glass [ME_HFS_ACK_S5] = "Go to S5", 2565dd74a6SSimon Glass [ME_HFS_ACK_GBL_RESET] = "Global Reset", 2665dd74a6SSimon Glass [ME_HFS_ACK_CONTINUE] = "Continue to boot" 2765dd74a6SSimon Glass }; 2865dd74a6SSimon Glass 29c02a4242SSimon Glass int intel_early_me_init(struct udevice *me_dev) 3065dd74a6SSimon Glass { 3165dd74a6SSimon Glass int count; 3265dd74a6SSimon Glass struct me_uma uma; 3365dd74a6SSimon Glass struct me_hfs hfs; 3465dd74a6SSimon Glass 3565dd74a6SSimon Glass debug("Intel ME early init\n"); 3665dd74a6SSimon Glass 3765dd74a6SSimon Glass /* Wait for ME UMA SIZE VALID bit to be set */ 3865dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 39c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 4065dd74a6SSimon Glass if (uma.valid) 4165dd74a6SSimon Glass break; 4265dd74a6SSimon Glass udelay(ME_DELAY); 4365dd74a6SSimon Glass } 4465dd74a6SSimon Glass if (!count) { 4565dd74a6SSimon Glass printf("ERROR: ME is not ready!\n"); 4665dd74a6SSimon Glass return -EBUSY; 4765dd74a6SSimon Glass } 4865dd74a6SSimon Glass 4965dd74a6SSimon Glass /* Check for valid firmware */ 50c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 5165dd74a6SSimon Glass if (hfs.fpt_bad) { 5265dd74a6SSimon Glass printf("WARNING: ME has bad firmware\n"); 5365dd74a6SSimon Glass return -EBADF; 5465dd74a6SSimon Glass } 5565dd74a6SSimon Glass 5665dd74a6SSimon Glass debug("Intel ME firmware is ready\n"); 5765dd74a6SSimon Glass 5865dd74a6SSimon Glass return 0; 5965dd74a6SSimon Glass } 6065dd74a6SSimon Glass 61c02a4242SSimon Glass int intel_early_me_uma_size(struct udevice *me_dev) 6265dd74a6SSimon Glass { 6365dd74a6SSimon Glass struct me_uma uma; 6465dd74a6SSimon Glass 65c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 6665dd74a6SSimon Glass if (uma.valid) { 6765dd74a6SSimon Glass debug("ME: Requested %uMB UMA\n", uma.size); 6865dd74a6SSimon Glass return uma.size; 6965dd74a6SSimon Glass } 7065dd74a6SSimon Glass 7165dd74a6SSimon Glass debug("ME: Invalid UMA size\n"); 7265dd74a6SSimon Glass return -EINVAL; 7365dd74a6SSimon Glass } 7465dd74a6SSimon Glass 75c02a4242SSimon Glass static inline void set_global_reset(struct udevice *dev, int enable) 7665dd74a6SSimon Glass { 7765dd74a6SSimon Glass u32 etr3; 7865dd74a6SSimon Glass 79c02a4242SSimon Glass dm_pci_read_config32(dev, ETR3, &etr3); 8065dd74a6SSimon Glass 8165dd74a6SSimon Glass /* Clear CF9 Without Resume Well Reset Enable */ 8265dd74a6SSimon Glass etr3 &= ~ETR3_CWORWRE; 8365dd74a6SSimon Glass 8465dd74a6SSimon Glass /* CF9GR indicates a Global Reset */ 8565dd74a6SSimon Glass if (enable) 8665dd74a6SSimon Glass etr3 |= ETR3_CF9GR; 8765dd74a6SSimon Glass else 8865dd74a6SSimon Glass etr3 &= ~ETR3_CF9GR; 8965dd74a6SSimon Glass 90c02a4242SSimon Glass dm_pci_write_config32(dev, ETR3, etr3); 9165dd74a6SSimon Glass } 9265dd74a6SSimon Glass 93c02a4242SSimon Glass int intel_early_me_init_done(struct udevice *dev, struct udevice *me_dev, 94c02a4242SSimon Glass uint status) 9565dd74a6SSimon Glass { 9665dd74a6SSimon Glass int count; 9765dd74a6SSimon Glass u32 mebase_l, mebase_h; 9865dd74a6SSimon Glass struct me_hfs hfs; 9965dd74a6SSimon Glass struct me_did did = { 10065dd74a6SSimon Glass .init_done = ME_INIT_DONE, 10165dd74a6SSimon Glass .status = status 10265dd74a6SSimon Glass }; 10365dd74a6SSimon Glass 10465dd74a6SSimon Glass /* MEBASE from MESEG_BASE[35:20] */ 105c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L, &mebase_l); 106c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H, &mebase_h); 10765dd74a6SSimon Glass mebase_h &= 0xf; 10865dd74a6SSimon Glass did.uma_base = (mebase_l >> 20) | (mebase_h << 12); 10965dd74a6SSimon Glass 11065dd74a6SSimon Glass /* Send message to ME */ 11165dd74a6SSimon Glass debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", 11265dd74a6SSimon Glass status, did.uma_base); 11365dd74a6SSimon Glass 114c02a4242SSimon Glass pci_write_dword_ptr(me_dev, &did, PCI_ME_H_GS); 11565dd74a6SSimon Glass 11665dd74a6SSimon Glass /* Must wait for ME acknowledgement */ 11765dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 118c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 11965dd74a6SSimon Glass if (hfs.bios_msg_ack) 12065dd74a6SSimon Glass break; 12165dd74a6SSimon Glass udelay(ME_DELAY); 12265dd74a6SSimon Glass } 12365dd74a6SSimon Glass if (!count) { 12465dd74a6SSimon Glass printf("ERROR: ME failed to respond\n"); 125c02a4242SSimon Glass return -ETIMEDOUT; 12665dd74a6SSimon Glass } 12765dd74a6SSimon Glass 12865dd74a6SSimon Glass /* Return the requested BIOS action */ 12965dd74a6SSimon Glass debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); 13065dd74a6SSimon Glass 13165dd74a6SSimon Glass /* Check status after acknowledgement */ 1328b900a41SSimon Glass intel_me_status(me_dev); 13365dd74a6SSimon Glass 13465dd74a6SSimon Glass switch (hfs.ack_data) { 13565dd74a6SSimon Glass case ME_HFS_ACK_CONTINUE: 13665dd74a6SSimon Glass /* Continue to boot */ 13765dd74a6SSimon Glass return 0; 13865dd74a6SSimon Glass case ME_HFS_ACK_RESET: 13965dd74a6SSimon Glass /* Non-power cycle reset */ 140c02a4242SSimon Glass set_global_reset(dev, 0); 1415021c81fSSimon Glass reset_cpu(0); 14265dd74a6SSimon Glass break; 14365dd74a6SSimon Glass case ME_HFS_ACK_PWR_CYCLE: 14465dd74a6SSimon Glass /* Power cycle reset */ 145c02a4242SSimon Glass set_global_reset(dev, 0); 1465021c81fSSimon Glass x86_full_reset(); 14765dd74a6SSimon Glass break; 14865dd74a6SSimon Glass case ME_HFS_ACK_GBL_RESET: 14965dd74a6SSimon Glass /* Global reset */ 150c02a4242SSimon Glass set_global_reset(dev, 1); 1515021c81fSSimon Glass x86_full_reset(); 15265dd74a6SSimon Glass break; 15365dd74a6SSimon Glass case ME_HFS_ACK_S3: 15465dd74a6SSimon Glass case ME_HFS_ACK_S4: 15565dd74a6SSimon Glass case ME_HFS_ACK_S5: 15665dd74a6SSimon Glass break; 15765dd74a6SSimon Glass } 15865dd74a6SSimon Glass 159c02a4242SSimon Glass return -EINVAL; 16065dd74a6SSimon Glass } 161c02a4242SSimon Glass 162c02a4242SSimon Glass static const struct udevice_id ivybridge_syscon_ids[] = { 16398655f3aSSimon Glass { .compatible = "intel,me", .data = X86_SYSCON_ME }, 164c02a4242SSimon Glass { } 165c02a4242SSimon Glass }; 166c02a4242SSimon Glass 167c02a4242SSimon Glass U_BOOT_DRIVER(syscon_intel_me) = { 168c02a4242SSimon Glass .name = "intel_me_syscon", 169c02a4242SSimon Glass .id = UCLASS_SYSCON, 170c02a4242SSimon Glass .of_match = ivybridge_syscon_ids, 171c02a4242SSimon Glass }; 172