161 lines
3.1 KiB
C
161 lines
3.1 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Copyright © 2024 Intel Corporation
|
|
*/
|
|
|
|
#include "i915_drv.h"
|
|
#include "i915_reg.h"
|
|
|
|
#include "intel_rom.h"
|
|
#include "intel_uncore.h"
|
|
|
|
struct intel_rom {
|
|
/* for PCI ROM */
|
|
struct pci_dev *pdev;
|
|
void __iomem *oprom;
|
|
|
|
/* for SPI */
|
|
struct intel_uncore *uncore;
|
|
loff_t offset;
|
|
|
|
size_t size;
|
|
|
|
u32 (*read32)(struct intel_rom *rom, loff_t offset);
|
|
u16 (*read16)(struct intel_rom *rom, loff_t offset);
|
|
void (*read_block)(struct intel_rom *rom, void *data, loff_t offset, size_t size);
|
|
void (*free)(struct intel_rom *rom);
|
|
};
|
|
|
|
static u32 spi_read32(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
intel_uncore_write(rom->uncore, PRIMARY_SPI_ADDRESS,
|
|
rom->offset + offset);
|
|
|
|
return intel_uncore_read(rom->uncore, PRIMARY_SPI_TRIGGER);
|
|
}
|
|
|
|
static u16 spi_read16(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
return spi_read32(rom, offset) & 0xffff;
|
|
}
|
|
|
|
struct intel_rom *intel_rom_spi(struct drm_i915_private *i915)
|
|
{
|
|
struct intel_rom *rom;
|
|
u32 static_region;
|
|
|
|
rom = kzalloc(sizeof(*rom), GFP_KERNEL);
|
|
if (!rom)
|
|
return NULL;
|
|
|
|
rom->uncore = &i915->uncore;
|
|
|
|
static_region = intel_uncore_read(rom->uncore, SPI_STATIC_REGIONS);
|
|
static_region &= OPTIONROM_SPI_REGIONID_MASK;
|
|
intel_uncore_write(rom->uncore, PRIMARY_SPI_REGIONID, static_region);
|
|
|
|
rom->offset = intel_uncore_read(rom->uncore, OROM_OFFSET) & OROM_OFFSET_MASK;
|
|
|
|
rom->size = 0x200000;
|
|
|
|
rom->read32 = spi_read32;
|
|
rom->read16 = spi_read16;
|
|
|
|
return rom;
|
|
}
|
|
|
|
static u32 pci_read32(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
return ioread32(rom->oprom + offset);
|
|
}
|
|
|
|
static u16 pci_read16(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
return ioread16(rom->oprom + offset);
|
|
}
|
|
|
|
static void pci_read_block(struct intel_rom *rom, void *data,
|
|
loff_t offset, size_t size)
|
|
{
|
|
memcpy_fromio(data, rom->oprom + offset, size);
|
|
}
|
|
|
|
static void pci_free(struct intel_rom *rom)
|
|
{
|
|
pci_unmap_rom(rom->pdev, rom->oprom);
|
|
}
|
|
|
|
struct intel_rom *intel_rom_pci(struct drm_i915_private *i915)
|
|
{
|
|
struct intel_rom *rom;
|
|
|
|
rom = kzalloc(sizeof(*rom), GFP_KERNEL);
|
|
if (!rom)
|
|
return NULL;
|
|
|
|
rom->pdev = to_pci_dev(i915->drm.dev);
|
|
|
|
rom->oprom = pci_map_rom(rom->pdev, &rom->size);
|
|
if (!rom->oprom) {
|
|
kfree(rom);
|
|
return NULL;
|
|
}
|
|
|
|
rom->read32 = pci_read32;
|
|
rom->read16 = pci_read16;
|
|
rom->read_block = pci_read_block;
|
|
rom->free = pci_free;
|
|
|
|
return rom;
|
|
}
|
|
|
|
u32 intel_rom_read32(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
return rom->read32(rom, offset);
|
|
}
|
|
|
|
u16 intel_rom_read16(struct intel_rom *rom, loff_t offset)
|
|
{
|
|
return rom->read16(rom, offset);
|
|
}
|
|
|
|
void intel_rom_read_block(struct intel_rom *rom, void *data,
|
|
loff_t offset, size_t size)
|
|
{
|
|
u32 *ptr = data;
|
|
loff_t index;
|
|
|
|
if (rom->read_block) {
|
|
rom->read_block(rom, data, offset, size);
|
|
return;
|
|
}
|
|
|
|
for (index = 0; index < size; index += 4)
|
|
*ptr++ = rom->read32(rom, offset + index);
|
|
}
|
|
|
|
loff_t intel_rom_find(struct intel_rom *rom, u32 needle)
|
|
{
|
|
loff_t offset;
|
|
|
|
for (offset = 0; offset < rom->size; offset += 4) {
|
|
if (rom->read32(rom, offset) == needle)
|
|
return offset;
|
|
}
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
size_t intel_rom_size(struct intel_rom *rom)
|
|
{
|
|
return rom->size;
|
|
}
|
|
|
|
void intel_rom_free(struct intel_rom *rom)
|
|
{
|
|
if (rom && rom->free)
|
|
rom->free(rom);
|
|
|
|
kfree(rom);
|
|
}
|