1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
// 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);
}
|