uboot/arch/x86/cpu/ivybridge/early_me.c
<<
>>
Prefs
   1/*
   2 * From Coreboot src/southbridge/intel/bd82x6x/early_me.c
   3 *
   4 * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <errno.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
  19static 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
  30int 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
  62int 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
  76static 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
  94int 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                reset_cpu(0);
 143                break;
 144        case ME_HFS_ACK_PWR_CYCLE:
 145                /* Power cycle reset */
 146                set_global_reset(dev, 0);
 147                x86_full_reset();
 148                break;
 149        case ME_HFS_ACK_GBL_RESET:
 150                /* Global reset */
 151                set_global_reset(dev, 1);
 152                x86_full_reset();
 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
 163static const struct udevice_id ivybridge_syscon_ids[] = {
 164        { .compatible = "intel,me", .data = X86_SYSCON_ME },
 165        { }
 166};
 167
 168U_BOOT_DRIVER(syscon_intel_me) = {
 169        .name = "intel_me_syscon",
 170        .id = UCLASS_SYSCON,
 171        .of_match = ivybridge_syscon_ids,
 172};
 173