1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2024 Intel Corporation
4 */
5
6 #include <linux/pci.h>
7
8 #include <drm/drm_device.h>
9
10 #include "i915_reg.h"
11
12 #include "intel_rom.h"
13 #include "intel_uncore.h"
14
15 struct intel_rom {
16 /* for PCI ROM */
17 struct pci_dev *pdev;
18 void __iomem *oprom;
19
20 /* for SPI */
21 struct intel_uncore *uncore;
22 loff_t offset;
23
24 size_t size;
25
26 u32 (*read32)(struct intel_rom *rom, loff_t offset);
27 u16 (*read16)(struct intel_rom *rom, loff_t offset);
28 void (*read_block)(struct intel_rom *rom, void *data, loff_t offset, size_t size);
29 void (*free)(struct intel_rom *rom);
30 };
31
spi_read32(struct intel_rom * rom,loff_t offset)32 static u32 spi_read32(struct intel_rom *rom, loff_t offset)
33 {
34 intel_uncore_write(rom->uncore, PRIMARY_SPI_ADDRESS,
35 rom->offset + offset);
36
37 return intel_uncore_read(rom->uncore, PRIMARY_SPI_TRIGGER);
38 }
39
spi_read16(struct intel_rom * rom,loff_t offset)40 static u16 spi_read16(struct intel_rom *rom, loff_t offset)
41 {
42 return spi_read32(rom, offset) & 0xffff;
43 }
44
intel_rom_spi(struct drm_device * drm)45 struct intel_rom *intel_rom_spi(struct drm_device *drm)
46 {
47 struct intel_rom *rom;
48 u32 static_region;
49
50 rom = kzalloc_obj(*rom);
51 if (!rom)
52 return NULL;
53
54 rom->uncore = to_intel_uncore(drm);
55
56 static_region = intel_uncore_read(rom->uncore, SPI_STATIC_REGIONS);
57 static_region &= OPTIONROM_SPI_REGIONID_MASK;
58 intel_uncore_write(rom->uncore, PRIMARY_SPI_REGIONID, static_region);
59
60 rom->offset = intel_uncore_read(rom->uncore, OROM_OFFSET) & OROM_OFFSET_MASK;
61
62 rom->size = 0x200000;
63
64 rom->read32 = spi_read32;
65 rom->read16 = spi_read16;
66
67 return rom;
68 }
69
pci_read32(struct intel_rom * rom,loff_t offset)70 static u32 pci_read32(struct intel_rom *rom, loff_t offset)
71 {
72 return ioread32(rom->oprom + offset);
73 }
74
pci_read16(struct intel_rom * rom,loff_t offset)75 static u16 pci_read16(struct intel_rom *rom, loff_t offset)
76 {
77 return ioread16(rom->oprom + offset);
78 }
79
pci_read_block(struct intel_rom * rom,void * data,loff_t offset,size_t size)80 static void pci_read_block(struct intel_rom *rom, void *data,
81 loff_t offset, size_t size)
82 {
83 memcpy_fromio(data, rom->oprom + offset, size);
84 }
85
pci_free(struct intel_rom * rom)86 static void pci_free(struct intel_rom *rom)
87 {
88 pci_unmap_rom(rom->pdev, rom->oprom);
89 }
90
intel_rom_pci(struct drm_device * drm)91 struct intel_rom *intel_rom_pci(struct drm_device *drm)
92 {
93 struct intel_rom *rom;
94
95 rom = kzalloc_obj(*rom);
96 if (!rom)
97 return NULL;
98
99 rom->pdev = to_pci_dev(drm->dev);
100
101 rom->oprom = pci_map_rom(rom->pdev, &rom->size);
102 if (!rom->oprom) {
103 kfree(rom);
104 return NULL;
105 }
106
107 rom->read32 = pci_read32;
108 rom->read16 = pci_read16;
109 rom->read_block = pci_read_block;
110 rom->free = pci_free;
111
112 return rom;
113 }
114
intel_rom_read32(struct intel_rom * rom,loff_t offset)115 u32 intel_rom_read32(struct intel_rom *rom, loff_t offset)
116 {
117 return rom->read32(rom, offset);
118 }
119
intel_rom_read16(struct intel_rom * rom,loff_t offset)120 u16 intel_rom_read16(struct intel_rom *rom, loff_t offset)
121 {
122 return rom->read16(rom, offset);
123 }
124
intel_rom_read_block(struct intel_rom * rom,void * data,loff_t offset,size_t size)125 void intel_rom_read_block(struct intel_rom *rom, void *data,
126 loff_t offset, size_t size)
127 {
128 u32 *ptr = data;
129 loff_t index;
130
131 if (rom->read_block) {
132 rom->read_block(rom, data, offset, size);
133 return;
134 }
135
136 for (index = 0; index < size; index += 4)
137 *ptr++ = rom->read32(rom, offset + index);
138 }
139
intel_rom_find(struct intel_rom * rom,u32 needle)140 loff_t intel_rom_find(struct intel_rom *rom, u32 needle)
141 {
142 loff_t offset;
143
144 for (offset = 0; offset < rom->size; offset += 4) {
145 if (rom->read32(rom, offset) == needle)
146 return offset;
147 }
148
149 return -ENOENT;
150 }
151
intel_rom_size(struct intel_rom * rom)152 size_t intel_rom_size(struct intel_rom *rom)
153 {
154 return rom->size;
155 }
156
intel_rom_free(struct intel_rom * rom)157 void intel_rom_free(struct intel_rom *rom)
158 {
159 if (rom && rom->free)
160 rom->free(rom);
161
162 kfree(rom);
163 }
164