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> 10c02a4242SSimon Glass #include <dm.h> 1165dd74a6SSimon Glass #include <errno.h> 1265dd74a6SSimon Glass #include <asm/pci.h> 13*98655f3aSSimon 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 static inline void pci_read_dword_ptr(struct udevice *me_dev, void *ptr, 31c02a4242SSimon Glass int offset) 3265dd74a6SSimon Glass { 3365dd74a6SSimon Glass u32 dword; 3465dd74a6SSimon Glass 35c02a4242SSimon Glass dm_pci_read_config32(me_dev, offset, &dword); 3665dd74a6SSimon Glass memcpy(ptr, &dword, sizeof(dword)); 3765dd74a6SSimon Glass } 3865dd74a6SSimon Glass 39c02a4242SSimon Glass static inline void pci_write_dword_ptr(struct udevice *me_dev, void *ptr, 40c02a4242SSimon Glass int offset) 4165dd74a6SSimon Glass { 4265dd74a6SSimon Glass u32 dword = 0; 43c02a4242SSimon Glass 4465dd74a6SSimon Glass memcpy(&dword, ptr, sizeof(dword)); 45c02a4242SSimon Glass dm_pci_write_config32(me_dev, offset, dword); 4665dd74a6SSimon Glass } 4765dd74a6SSimon Glass 48c02a4242SSimon Glass void intel_early_me_status(struct udevice *me_dev) 4965dd74a6SSimon Glass { 5065dd74a6SSimon Glass struct me_hfs hfs; 5165dd74a6SSimon Glass struct me_gmes gmes; 5265dd74a6SSimon Glass 53c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 54c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &gmes, PCI_ME_GMES); 5565dd74a6SSimon Glass 5665dd74a6SSimon Glass intel_me_status(&hfs, &gmes); 5765dd74a6SSimon Glass } 5865dd74a6SSimon Glass 59c02a4242SSimon Glass int intel_early_me_init(struct udevice *me_dev) 6065dd74a6SSimon Glass { 6165dd74a6SSimon Glass int count; 6265dd74a6SSimon Glass struct me_uma uma; 6365dd74a6SSimon Glass struct me_hfs hfs; 6465dd74a6SSimon Glass 6565dd74a6SSimon Glass debug("Intel ME early init\n"); 6665dd74a6SSimon Glass 6765dd74a6SSimon Glass /* Wait for ME UMA SIZE VALID bit to be set */ 6865dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 69c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 7065dd74a6SSimon Glass if (uma.valid) 7165dd74a6SSimon Glass break; 7265dd74a6SSimon Glass udelay(ME_DELAY); 7365dd74a6SSimon Glass } 7465dd74a6SSimon Glass if (!count) { 7565dd74a6SSimon Glass printf("ERROR: ME is not ready!\n"); 7665dd74a6SSimon Glass return -EBUSY; 7765dd74a6SSimon Glass } 7865dd74a6SSimon Glass 7965dd74a6SSimon Glass /* Check for valid firmware */ 80c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 8165dd74a6SSimon Glass if (hfs.fpt_bad) { 8265dd74a6SSimon Glass printf("WARNING: ME has bad firmware\n"); 8365dd74a6SSimon Glass return -EBADF; 8465dd74a6SSimon Glass } 8565dd74a6SSimon Glass 8665dd74a6SSimon Glass debug("Intel ME firmware is ready\n"); 8765dd74a6SSimon Glass 8865dd74a6SSimon Glass return 0; 8965dd74a6SSimon Glass } 9065dd74a6SSimon Glass 91c02a4242SSimon Glass int intel_early_me_uma_size(struct udevice *me_dev) 9265dd74a6SSimon Glass { 9365dd74a6SSimon Glass struct me_uma uma; 9465dd74a6SSimon Glass 95c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &uma, PCI_ME_UMA); 9665dd74a6SSimon Glass if (uma.valid) { 9765dd74a6SSimon Glass debug("ME: Requested %uMB UMA\n", uma.size); 9865dd74a6SSimon Glass return uma.size; 9965dd74a6SSimon Glass } 10065dd74a6SSimon Glass 10165dd74a6SSimon Glass debug("ME: Invalid UMA size\n"); 10265dd74a6SSimon Glass return -EINVAL; 10365dd74a6SSimon Glass } 10465dd74a6SSimon Glass 105c02a4242SSimon Glass static inline void set_global_reset(struct udevice *dev, int enable) 10665dd74a6SSimon Glass { 10765dd74a6SSimon Glass u32 etr3; 10865dd74a6SSimon Glass 109c02a4242SSimon Glass dm_pci_read_config32(dev, ETR3, &etr3); 11065dd74a6SSimon Glass 11165dd74a6SSimon Glass /* Clear CF9 Without Resume Well Reset Enable */ 11265dd74a6SSimon Glass etr3 &= ~ETR3_CWORWRE; 11365dd74a6SSimon Glass 11465dd74a6SSimon Glass /* CF9GR indicates a Global Reset */ 11565dd74a6SSimon Glass if (enable) 11665dd74a6SSimon Glass etr3 |= ETR3_CF9GR; 11765dd74a6SSimon Glass else 11865dd74a6SSimon Glass etr3 &= ~ETR3_CF9GR; 11965dd74a6SSimon Glass 120c02a4242SSimon Glass dm_pci_write_config32(dev, ETR3, etr3); 12165dd74a6SSimon Glass } 12265dd74a6SSimon Glass 123c02a4242SSimon Glass int intel_early_me_init_done(struct udevice *dev, struct udevice *me_dev, 124c02a4242SSimon Glass uint status) 12565dd74a6SSimon Glass { 12665dd74a6SSimon Glass int count; 12765dd74a6SSimon Glass u32 mebase_l, mebase_h; 12865dd74a6SSimon Glass struct me_hfs hfs; 12965dd74a6SSimon Glass struct me_did did = { 13065dd74a6SSimon Glass .init_done = ME_INIT_DONE, 13165dd74a6SSimon Glass .status = status 13265dd74a6SSimon Glass }; 13365dd74a6SSimon Glass 13465dd74a6SSimon Glass /* MEBASE from MESEG_BASE[35:20] */ 135c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_L, &mebase_l); 136c02a4242SSimon Glass dm_pci_read_config32(PCH_DEV, PCI_CPU_MEBASE_H, &mebase_h); 13765dd74a6SSimon Glass mebase_h &= 0xf; 13865dd74a6SSimon Glass did.uma_base = (mebase_l >> 20) | (mebase_h << 12); 13965dd74a6SSimon Glass 14065dd74a6SSimon Glass /* Send message to ME */ 14165dd74a6SSimon Glass debug("ME: Sending Init Done with status: %d, UMA base: 0x%04x\n", 14265dd74a6SSimon Glass status, did.uma_base); 14365dd74a6SSimon Glass 144c02a4242SSimon Glass pci_write_dword_ptr(me_dev, &did, PCI_ME_H_GS); 14565dd74a6SSimon Glass 14665dd74a6SSimon Glass /* Must wait for ME acknowledgement */ 14765dd74a6SSimon Glass for (count = ME_RETRY; count > 0; --count) { 148c02a4242SSimon Glass pci_read_dword_ptr(me_dev, &hfs, PCI_ME_HFS); 14965dd74a6SSimon Glass if (hfs.bios_msg_ack) 15065dd74a6SSimon Glass break; 15165dd74a6SSimon Glass udelay(ME_DELAY); 15265dd74a6SSimon Glass } 15365dd74a6SSimon Glass if (!count) { 15465dd74a6SSimon Glass printf("ERROR: ME failed to respond\n"); 155c02a4242SSimon Glass return -ETIMEDOUT; 15665dd74a6SSimon Glass } 15765dd74a6SSimon Glass 15865dd74a6SSimon Glass /* Return the requested BIOS action */ 15965dd74a6SSimon Glass debug("ME: Requested BIOS Action: %s\n", me_ack_values[hfs.ack_data]); 16065dd74a6SSimon Glass 16165dd74a6SSimon Glass /* Check status after acknowledgement */ 162c02a4242SSimon Glass intel_early_me_status(me_dev); 16365dd74a6SSimon Glass 16465dd74a6SSimon Glass switch (hfs.ack_data) { 16565dd74a6SSimon Glass case ME_HFS_ACK_CONTINUE: 16665dd74a6SSimon Glass /* Continue to boot */ 16765dd74a6SSimon Glass return 0; 16865dd74a6SSimon Glass case ME_HFS_ACK_RESET: 16965dd74a6SSimon Glass /* Non-power cycle reset */ 170c02a4242SSimon Glass set_global_reset(dev, 0); 1715021c81fSSimon Glass reset_cpu(0); 17265dd74a6SSimon Glass break; 17365dd74a6SSimon Glass case ME_HFS_ACK_PWR_CYCLE: 17465dd74a6SSimon Glass /* Power cycle reset */ 175c02a4242SSimon Glass set_global_reset(dev, 0); 1765021c81fSSimon Glass x86_full_reset(); 17765dd74a6SSimon Glass break; 17865dd74a6SSimon Glass case ME_HFS_ACK_GBL_RESET: 17965dd74a6SSimon Glass /* Global reset */ 180c02a4242SSimon Glass set_global_reset(dev, 1); 1815021c81fSSimon Glass x86_full_reset(); 18265dd74a6SSimon Glass break; 18365dd74a6SSimon Glass case ME_HFS_ACK_S3: 18465dd74a6SSimon Glass case ME_HFS_ACK_S4: 18565dd74a6SSimon Glass case ME_HFS_ACK_S5: 18665dd74a6SSimon Glass break; 18765dd74a6SSimon Glass } 18865dd74a6SSimon Glass 189c02a4242SSimon Glass return -EINVAL; 19065dd74a6SSimon Glass } 191c02a4242SSimon Glass 192c02a4242SSimon Glass static const struct udevice_id ivybridge_syscon_ids[] = { 193*98655f3aSSimon Glass { .compatible = "intel,me", .data = X86_SYSCON_ME }, 194c02a4242SSimon Glass { } 195c02a4242SSimon Glass }; 196c02a4242SSimon Glass 197c02a4242SSimon Glass U_BOOT_DRIVER(syscon_intel_me) = { 198c02a4242SSimon Glass .name = "intel_me_syscon", 199c02a4242SSimon Glass .id = UCLASS_SYSCON, 200c02a4242SSimon Glass .of_match = ivybridge_syscon_ids, 201c02a4242SSimon Glass }; 202