183d290c5STom 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> 11*b37b7b20SBin Meng #include <sysreset.h> 1265dd74a6SSimon Glass #include <asm/pci.h> 1398655f3aSSimon Glass #include <asm/cpu.h> 1465dd74a6SSimon Glass #include <asm/processor.h> 1565dd74a6SSimon Glass #include <asm/arch/me.h> 1665dd74a6SSimon Glass #include <asm/arch/pch.h> 1765dd74a6SSimon Glass #include <asm/io.h> 1865dd74a6SSimon Glass 1965dd74a6SSimon Glass static const char *const me_ack_values[] = { 2065dd74a6SSimon Glass [ME_HFS_ACK_NO_DID] = "No DID Ack received", 2165dd74a6SSimon Glass [ME_HFS_ACK_RESET] = "Non-power cycle reset", 2265dd74a6SSimon Glass [ME_HFS_ACK_PWR_CYCLE] = "Power cycle reset", 2365dd74a6SSimon Glass [ME_HFS_ACK_S3] = "Go to S3", 2465dd74a6SSimon Glass [ME_HFS_ACK_S4] = "Go to S4", 2565dd74a6SSimon Glass [ME_HFS_ACK_S5] = "Go to S5", 2665dd74a6SSimon Glass [ME_HFS_ACK_GBL_RESET] = "Global Reset", 2765dd74a6SSimon Glass [ME_HFS_ACK_CONTINUE] = "Continue to boot" 2865dd74a6SSimon Glass }; 2965dd74a6SSimon Glass 30c02a4242SSimon Glass int intel_early_me_init(struct udevice *me_dev) 3165dd74a6SSimon Glass { 3265dd74a6SSimon Glass int count; 3365dd74a6SSimon Glass struct me_uma uma; 3465dd74a6SSimon Glass struct me_hfs hfs; 3565dd74a6SSimon Glass 3665dd74a6SSimon Glass debug("Intel ME early init\n"); 3765dd74a6SSimon Glass 3865dd74a6SSimon Glass /* Wait for ME UMA SIZE VALID bit to be set */ 3965dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 40c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 4165dd74a6SSimon Glass if (uma.valid) 4265dd74a6SSimon Glass break; 4365dd74a6SSimon Glass udelay(ME_DELAY); 4465dd74a6SSimon Glass } 4565dd74a6SSimon Glass if (!count) { 4665dd74a6SSimon Glass printf("ERROR: ME is not ready!\n"); 4765dd74a6SSimon Glass return -EBUSY; 4865dd74a6SSimon Glass } 4965dd74a6SSimon Glass 5065dd74a6SSimon Glass /* Check for valid firmware */ 51c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 5265dd74a6SSimon Glass if (hfs.fpt_bad) { 5365dd74a6SSimon Glass printf("WARNING: ME has bad firmware\n"); 5465dd74a6SSimon Glass return -EBADF; 5565dd74a6SSimon Glass } 5665dd74a6SSimon Glass 5765dd74a6SSimon Glass debug("Intel ME firmware is ready\n"); 5865dd74a6SSimon Glass 5965dd74a6SSimon Glass return 0; 6065dd74a6SSimon Glass } 6165dd74a6SSimon Glass 62c02a4242SSimon Glass int intel_early_me_uma_size(struct udevice *me_dev) 6365dd74a6SSimon Glass { 6465dd74a6SSimon Glass struct me_uma uma; 6565dd74a6SSimon Glass 66c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 6765dd74a6SSimon Glass if (uma.valid) { 6865dd74a6SSimon Glass debug("ME: Requested %uMB UMA\n", uma.size); 6965dd74a6SSimon Glass return uma.size; 7065dd74a6SSimon Glass } 7165dd74a6SSimon Glass 7265dd74a6SSimon Glass debug("ME: Invalid UMA size\n"); 7365dd74a6SSimon Glass return -EINVAL; 7465dd74a6SSimon Glass } 7565dd74a6SSimon Glass 76c02a4242SSimon Glass static inline void set_global_reset(struct udevice *dev, int enable) 7765dd74a6SSimon Glass { 7865dd74a6SSimon Glass u32 etr3; 7965dd74a6SSimon Glass 80c02a4242SSimon Glass dm_pci_read_config32(dev, ETR3, &etr3); 8165dd74a6SSimon Glass 8265dd74a6SSimon Glass /* Clear CF9 Without Resume Well Reset Enable */ 8365dd74a6SSimon Glass etr3 &= ~ETR3_CWORWRE; 8465dd74a6SSimon Glass 8565dd74a6SSimon Glass /* CF9GR indicates a Global Reset */ 8665dd74a6SSimon Glass if (enable) 8765dd74a6SSimon Glass etr3 |= ETR3_CF9GR; 8865dd74a6SSimon Glass else 8965dd74a6SSimon Glass etr3 &= ~ETR3_CF9GR; 9065dd74a6SSimon Glass 91c02a4242SSimon Glass dm_pci_write_config32(dev, ETR3, etr3); 9265dd74a6SSimon Glass } 9365dd74a6SSimon Glass 94c02a4242SSimon Glass int intel_early_me_init_done(struct udevice *dev, struct udevice *me_dev, 95c02a4242SSimon Glass uint status) 9665dd74a6SSimon Glass { 9765dd74a6SSimon Glass int count; 9865dd74a6SSimon Glass u32 mebase_l, mebase_h; 9965dd74a6SSimon Glass struct me_hfs hfs; 10065dd74a6SSimon Glass struct me_did did = { 10165dd74a6SSimon Glass .init_done = ME_INIT_DONE, 10265dd74a6SSimon Glass .status = status 10365dd74a6SSimon Glass }; 10465dd74a6SSimon Glass 10565dd74a6SSimon Glass /* MEBASE from MESEG_BASE[35:20] */ 106c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L, &mebase_l); 107c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H, &mebase_h); 10865dd74a6SSimon Glass mebase_h &= 0xf; 10965dd74a6SSimon Glass did.uma_base = (mebase_l >> 20) | (mebase_h << 12); 11065dd74a6SSimon Glass 11165dd74a6SSimon Glass /* Send message to ME */ 11265dd74a6SSimon Glass debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", 11365dd74a6SSimon Glass status, did.uma_base); 11465dd74a6SSimon Glass 115c02a4242SSimon Glass pci_write_dword_ptr(me_dev, &did, PCI_ME_H_GS); 11665dd74a6SSimon Glass 11765dd74a6SSimon Glass /* Must wait for ME acknowledgement */ 11865dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 119c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 12065dd74a6SSimon Glass if (hfs.bios_msg_ack) 12165dd74a6SSimon Glass break; 12265dd74a6SSimon Glass udelay(ME_DELAY); 12365dd74a6SSimon Glass } 12465dd74a6SSimon Glass if (!count) { 12565dd74a6SSimon Glass printf("ERROR: ME failed to respond\n"); 126c02a4242SSimon Glass return -ETIMEDOUT; 12765dd74a6SSimon Glass } 12865dd74a6SSimon Glass 12965dd74a6SSimon Glass /* Return the requested BIOS action */ 13065dd74a6SSimon Glass debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); 13165dd74a6SSimon Glass 13265dd74a6SSimon Glass /* Check status after acknowledgement */ 1338b900a41SSimon Glass intel_me_status(me_dev); 13465dd74a6SSimon Glass 13565dd74a6SSimon Glass switch (hfs.ack_data) { 13665dd74a6SSimon Glass case ME_HFS_ACK_CONTINUE: 13765dd74a6SSimon Glass /* Continue to boot */ 13865dd74a6SSimon Glass return 0; 13965dd74a6SSimon Glass case ME_HFS_ACK_RESET: 14065dd74a6SSimon Glass /* Non-power cycle reset */ 141c02a4242SSimon Glass set_global_reset(dev, 0); 142*b37b7b20SBin Meng sysreset_walk_halt(SYSRESET_COLD); 14365dd74a6SSimon Glass break; 14465dd74a6SSimon Glass case ME_HFS_ACK_PWR_CYCLE: 14565dd74a6SSimon Glass /* Power cycle reset */ 146c02a4242SSimon Glass set_global_reset(dev, 0); 147*b37b7b20SBin Meng sysreset_walk_halt(SYSRESET_COLD); 14865dd74a6SSimon Glass break; 14965dd74a6SSimon Glass case ME_HFS_ACK_GBL_RESET: 15065dd74a6SSimon Glass /* Global reset */ 151c02a4242SSimon Glass set_global_reset(dev, 1); 152*b37b7b20SBin Meng sysreset_walk_halt(SYSRESET_COLD); 15365dd74a6SSimon Glass break; 15465dd74a6SSimon Glass case ME_HFS_ACK_S3: 15565dd74a6SSimon Glass case ME_HFS_ACK_S4: 15665dd74a6SSimon Glass case ME_HFS_ACK_S5: 15765dd74a6SSimon Glass break; 15865dd74a6SSimon Glass } 15965dd74a6SSimon Glass 160c02a4242SSimon Glass return -EINVAL; 16165dd74a6SSimon Glass } 162c02a4242SSimon Glass 163c02a4242SSimon Glass static const struct udevice_id ivybridge_syscon_ids[] = { 16498655f3aSSimon Glass { .compatible = "intel,me", .data = X86_SYSCON_ME }, 165c02a4242SSimon Glass { } 166c02a4242SSimon Glass }; 167c02a4242SSimon Glass 168c02a4242SSimon Glass U_BOOT_DRIVER(syscon_intel_me) = { 169c02a4242SSimon Glass .name = "intel_me_syscon", 170c02a4242SSimon Glass .id = UCLASS_SYSCON, 171c02a4242SSimon Glass .of_match = ivybridge_syscon_ids, 172c02a4242SSimon Glass }; 173