uboot/arch/x86/cpu/intel_common/intel_opregion.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Writing IntelGraphicsMem table for ACPI
   4 *
   5 * Copyright 2019 Google LLC
   6 * Modified from coreboot src/soc/intel/gma/opregion.c
   7 */
   8
   9#include <common.h>
  10#include <binman.h>
  11#include <bloblist.h>
  12#include <dm.h>
  13#include <spi_flash.h>
  14#include <asm/intel_opregion.h>
  15
  16static char vbt_data[8 << 10];
  17
  18static int locate_vbt(char **vbtp, int *sizep)
  19{
  20        struct binman_entry vbt;
  21        struct udevice *dev;
  22        u32 vbtsig = 0;
  23        int size;
  24        int ret;
  25
  26        ret = binman_entry_find("intel-vbt", &vbt);
  27        if (ret)
  28                return log_msg_ret("find VBT", ret);
  29        ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
  30        if (ret)
  31                return log_msg_ret("find flash", ret);
  32        size = vbt.size;
  33        if (size > sizeof(vbt_data))
  34                return log_msg_ret("vbt", -E2BIG);
  35        ret = spi_flash_read_dm(dev, vbt.image_pos, size, vbt_data);
  36        if (ret)
  37                return log_msg_ret("read", ret);
  38
  39        memcpy(&vbtsig, vbt_data, sizeof(vbtsig));
  40        if (vbtsig != VBT_SIGNATURE) {
  41                log_err("Missing/invalid signature in VBT data file!\n");
  42                return -EINVAL;
  43        }
  44
  45        log_debug("Found a VBT of %u bytes\n", size);
  46        *sizep = size;
  47        *vbtp = vbt_data;
  48
  49        return 0;
  50}
  51
  52/* Write ASLS PCI register and prepare SWSCI register */
  53static int intel_gma_opregion_register(struct udevice *dev, ulong opregion)
  54{
  55        int sci_reg;
  56
  57        if (!device_active(dev))
  58                return -ENOENT;
  59
  60        /*
  61         * Intel BIOS Specification
  62         * Chapter 5.3.7 "Initialise Hardware State"
  63         */
  64        dm_pci_write_config32(dev, ASLS, opregion);
  65
  66        /*
  67         * Atom-based platforms use a combined SMI/SCI register,
  68         * whereas non-Atom platforms use a separate SCI register
  69         */
  70        if (IS_ENABLED(CONFIG_INTEL_GMA_SWSMISCI))
  71                sci_reg = SWSMISCI;
  72        else
  73                sci_reg = SWSCI;
  74
  75        /*
  76         * Intel's Windows driver relies on this:
  77         * Intel BIOS Specification
  78         * Chapter 5.4 "ASL Software SCI Handler"
  79         */
  80        dm_pci_clrset_config16(dev, sci_reg, GSSCIE, SMISCISEL);
  81
  82        return 0;
  83}
  84
  85int intel_gma_init_igd_opregion(struct udevice *dev,
  86                                struct igd_opregion *opregion)
  87{
  88        struct optionrom_vbt *vbt = NULL;
  89        char *vbt_buf;
  90        int vbt_size;
  91        int ret;
  92
  93        ret = locate_vbt(&vbt_buf, &vbt_size);
  94        if (ret) {
  95                log_err("GMA: VBT couldn't be found\n");
  96                return log_msg_ret("find vbt", ret);
  97        }
  98        vbt = (struct optionrom_vbt *)vbt_buf;
  99
 100        memset(opregion, '\0', sizeof(struct igd_opregion));
 101
 102        memcpy(&opregion->header.signature, IGD_OPREGION_SIGNATURE,
 103               sizeof(opregion->header.signature));
 104        memcpy(opregion->header.vbios_version, vbt->coreblock_biosbuild,
 105               ARRAY_SIZE(vbt->coreblock_biosbuild));
 106        /* Extended VBT support */
 107        if (vbt->hdr_vbt_size > sizeof(opregion->vbt.gvd1)) {
 108                struct optionrom_vbt *ext_vbt;
 109
 110                ret = bloblist_ensure_size(BLOBLISTT_INTEL_VBT,
 111                                           vbt->hdr_vbt_size, 0,
 112                                           (void **)&ext_vbt);
 113                if (ret) {
 114                        log_err("GMA: Unable to add Ext VBT to bloblist\n");
 115                        return log_msg_ret("blob", ret);
 116                }
 117
 118                memcpy(ext_vbt, vbt, vbt->hdr_vbt_size);
 119                opregion->mailbox3.rvda = (uintptr_t)ext_vbt;
 120                opregion->mailbox3.rvds = vbt->hdr_vbt_size;
 121        } else {
 122                /* Raw VBT size which can fit in gvd1 */
 123                printf("copy to %p\n", opregion->vbt.gvd1);
 124                memcpy(opregion->vbt.gvd1, vbt, vbt->hdr_vbt_size);
 125        }
 126
 127        /* 8kb */
 128        opregion->header.size = sizeof(struct igd_opregion) / 1024;
 129
 130        /*
 131         * Left-shift version field to accommodate Intel Windows driver quirk
 132         * when not using a VBIOS.
 133         * Required for Legacy boot + NGI, UEFI + NGI, and UEFI + GOP driver.
 134         *
 135         * No adverse effects when using VBIOS or booting Linux.
 136         */
 137        opregion->header.version = IGD_OPREGION_VERSION << 24;
 138
 139        /* We just assume we're mobile for now */
 140        opregion->header.mailboxes = MAILBOXES_MOBILE;
 141
 142        /* Initialise Mailbox 1 */
 143        opregion->mailbox1.clid = 1;
 144
 145        /* Initialise Mailbox 3 */
 146        opregion->mailbox3.bclp = IGD_BACKLIGHT_BRIGHTNESS;
 147        opregion->mailbox3.pfit = IGD_FIELD_VALID | IGD_PFIT_STRETCH;
 148        opregion->mailbox3.pcft = 0; /* should be (IMON << 1) & 0x3e */
 149        opregion->mailbox3.cblv = IGD_FIELD_VALID | IGD_INITIAL_BRIGHTNESS;
 150        opregion->mailbox3.bclm[0] = IGD_WORD_FIELD_VALID + 0x0000;
 151        opregion->mailbox3.bclm[1] = IGD_WORD_FIELD_VALID + 0x0a19;
 152        opregion->mailbox3.bclm[2] = IGD_WORD_FIELD_VALID + 0x1433;
 153        opregion->mailbox3.bclm[3] = IGD_WORD_FIELD_VALID + 0x1e4c;
 154        opregion->mailbox3.bclm[4] = IGD_WORD_FIELD_VALID + 0x2866;
 155        opregion->mailbox3.bclm[5] = IGD_WORD_FIELD_VALID + 0x327f;
 156        opregion->mailbox3.bclm[6] = IGD_WORD_FIELD_VALID + 0x3c99;
 157        opregion->mailbox3.bclm[7] = IGD_WORD_FIELD_VALID + 0x46b2;
 158        opregion->mailbox3.bclm[8] = IGD_WORD_FIELD_VALID + 0x50cc;
 159        opregion->mailbox3.bclm[9] = IGD_WORD_FIELD_VALID + 0x5ae5;
 160        opregion->mailbox3.bclm[10] = IGD_WORD_FIELD_VALID + 0x64ff;
 161
 162        /* Write ASLS PCI register and prepare SWSCI register */
 163        ret = intel_gma_opregion_register(dev, (ulong)opregion);
 164        if (ret)
 165                return log_msg_ret("write asls", ret);
 166
 167        return 0;
 168}
 169