xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/pcr/pcr.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #define __SIMPLE_DEVICE__
4 
5 #include <assert.h>
6 #include <commonlib/bsd/helpers.h>
7 #include <console/console.h>
8 #include <device/mmio.h>
9 #include <device/pci_def.h>
10 #include <device/pci_ops.h>
11 #include <device/pci_type.h>
12 #include <intelblocks/pcr.h>
13 #include <soc/pci_devs.h>
14 #include <timer.h>
15 #include <types.h>
16 
17 #if (CONFIG_PCR_BASE_ADDRESS == 0)
18 #error "PCR_BASE_ADDRESS need to be non-zero!"
19 #endif
20 
21 #if !CONFIG(PCR_COMMON_IOSF_1_0)
22 
23 #define PCR_SBI_CMD_TIMEOUT	10 /* 10ms */
24 
25 /* P2SB PCI configuration register */
26 #define P2SB_CR_SBI_ADDR	0xd0
27 #define  P2SB_CR_SBI_DESTID	24
28 #define P2SB_CR_SBI_DATA	0xd4
29 #define P2SB_CR_SBI_STATUS	0xd8
30 /* Bit 15:8 */
31 #define  P2SB_CR_SBI_OPCODE	8
32 #define  P2SB_CR_SBI_OPCODE_MASK	0xFF00
33 /* Bit 7 */
34 #define  P2SB_CR_SBI_POSTED	7
35 #define  P2SB_CR_SBI_POSTED_MASK	0x0080
36 /* Bit 2-1 */
37 #define  P2SB_CR_SBI_STATUS_MASK	0x0006
38 #define  P2SB_CR_SBI_STATUS_SUCCESS	0
39 #define  P2SB_CR_SBI_STATUS_NOT_SUPPORTED	1
40 #define  P2SB_CR_SBI_STATUS_POWERED_DOWN	2
41 #define  P2SB_CR_SBI_STATUS_MULTI_CAST_MIXED	3
42 /* Bit 0 */
43 #define  P2SB_CR_SBI_STATUS_READY	0
44 #define  P2SB_CR_SBI_STATUS_BUSY	1
45 #define P2SB_CR_SBI_ROUTE_IDEN	0xda
46 /* Bit 15-12 */
47 #define  P2SB_CR_SBI_FBE	12
48 #define  P2SB_CR_SBI_FBE_MASK	0xF
49 /* Bit 10-8 */
50 #define  P2SB_CR_SBI_BAR	8
51 #define  P2SB_CR_SBI_MASK	0x7
52 /* Bit 7-0 */
53 #define  P2SB_CR_SBI_FID	0
54 #define  P2SB_CR_SBI_FID_MASK	0xFF
55 #define P2SB_CR_SBI_EXT_ADDR	0xdc
56 #endif
57 
__pcr_reg_address(uint8_t pid,uint16_t offset)58 static void *__pcr_reg_address(uint8_t pid, uint16_t offset)
59 {
60 	uintptr_t reg_addr;
61 
62 	/* Create an address based off of port id and offset. */
63 	reg_addr = CONFIG_PCR_BASE_ADDRESS;
64 	reg_addr += ((uintptr_t)pid) << PCR_PORTID_SHIFT;
65 	reg_addr += (uintptr_t)offset;
66 
67 	return (void *)reg_addr;
68 }
69 
pcr_reg_address(uint8_t pid,uint16_t offset)70 void *pcr_reg_address(uint8_t pid, uint16_t offset)
71 {
72 	if (CONFIG(PCR_COMMON_IOSF_1_0))
73 		assert(IS_ALIGNED(offset, sizeof(uint32_t)));
74 
75 	return __pcr_reg_address(pid, offset);
76 }
77 
78 /*
79  * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
80  * agents are using 32-bit aligned accesses for their configuration
81  * registers. For IOSF versions greater than 1_0, IOSF-SB
82  * agents can use any access (8/16/32 bit aligned) for their
83  * configuration registers
84  */
check_pcr_offset_align(uint16_t offset,size_t size)85 static inline void check_pcr_offset_align(uint16_t offset, size_t size)
86 {
87 	const size_t align = CONFIG(PCR_COMMON_IOSF_1_0) ?
88 					sizeof(uint32_t) : size;
89 
90 	assert(IS_ALIGNED(offset, align));
91 }
92 
pcr_read32(uint8_t pid,uint16_t offset)93 uint32_t pcr_read32(uint8_t pid, uint16_t offset)
94 {
95 	/* Ensure the PCR offset is correctly aligned. */
96 	assert(IS_ALIGNED(offset, sizeof(uint32_t)));
97 
98 	return read32(__pcr_reg_address(pid, offset));
99 }
100 
pcr_read16(uint8_t pid,uint16_t offset)101 uint16_t pcr_read16(uint8_t pid, uint16_t offset)
102 {
103 	/* Ensure the PCR offset is correctly aligned. */
104 	check_pcr_offset_align(offset, sizeof(uint16_t));
105 
106 	return read16(__pcr_reg_address(pid, offset));
107 }
108 
pcr_read8(uint8_t pid,uint16_t offset)109 uint8_t pcr_read8(uint8_t pid, uint16_t offset)
110 {
111 	/* Ensure the PCR offset is correctly aligned. */
112 	check_pcr_offset_align(offset, sizeof(uint8_t));
113 
114 	return read8(__pcr_reg_address(pid, offset));
115 }
116 
117 /*
118  * After every write one needs to perform a read an innocuous register to
119  * ensure the writes are completed for certain ports. This is done for
120  * all ports so that the callers don't need the per-port knowledge for
121  * each transaction.
122  */
write_completion(uint8_t pid,uint16_t offset)123 static inline void write_completion(uint8_t pid, uint16_t offset)
124 {
125 	read32(__pcr_reg_address(pid, ALIGN_DOWN(offset, sizeof(uint32_t))));
126 }
127 
pcr_write32(uint8_t pid,uint16_t offset,uint32_t indata)128 void pcr_write32(uint8_t pid, uint16_t offset, uint32_t indata)
129 {
130 	/* Ensure the PCR offset is correctly aligned. */
131 	assert(IS_ALIGNED(offset, sizeof(indata)));
132 
133 	write32(__pcr_reg_address(pid, offset), indata);
134 	/* Ensure the writes complete. */
135 	write_completion(pid, offset);
136 }
137 
pcr_write16(uint8_t pid,uint16_t offset,uint16_t indata)138 void pcr_write16(uint8_t pid, uint16_t offset, uint16_t indata)
139 {
140 	/* Ensure the PCR offset is correctly aligned. */
141 	check_pcr_offset_align(offset, sizeof(uint16_t));
142 
143 	write16(__pcr_reg_address(pid, offset), indata);
144 	/* Ensure the writes complete. */
145 	write_completion(pid, offset);
146 }
147 
pcr_write8(uint8_t pid,uint16_t offset,uint8_t indata)148 void pcr_write8(uint8_t pid, uint16_t offset, uint8_t indata)
149 {
150 	/* Ensure the PCR offset is correctly aligned. */
151 	check_pcr_offset_align(offset, sizeof(uint8_t));
152 
153 	write8(__pcr_reg_address(pid, offset), indata);
154 	/* Ensure the writes complete. */
155 	write_completion(pid, offset);
156 }
157 
pcr_rmw32(uint8_t pid,uint16_t offset,uint32_t anddata,uint32_t ordata)158 void pcr_rmw32(uint8_t pid, uint16_t offset, uint32_t anddata, uint32_t ordata)
159 {
160 	uint32_t data32;
161 
162 	data32 = pcr_read32(pid, offset);
163 	data32 &= anddata;
164 	data32 |= ordata;
165 	pcr_write32(pid, offset, data32);
166 }
167 
pcr_rmw16(uint8_t pid,uint16_t offset,uint16_t anddata,uint16_t ordata)168 void pcr_rmw16(uint8_t pid, uint16_t offset, uint16_t anddata, uint16_t ordata)
169 {
170 	uint16_t data16;
171 
172 	data16 = pcr_read16(pid, offset);
173 	data16 &= anddata;
174 	data16 |= ordata;
175 	pcr_write16(pid, offset, data16);
176 }
177 
pcr_rmw8(uint8_t pid,uint16_t offset,uint8_t anddata,uint8_t ordata)178 void pcr_rmw8(uint8_t pid, uint16_t offset, uint8_t anddata, uint8_t ordata)
179 {
180 	uint8_t data8;
181 
182 	data8 = pcr_read8(pid, offset);
183 	data8 &= anddata;
184 	data8 |= ordata;
185 	pcr_write8(pid, offset, data8);
186 }
187 
pcr_or32(uint8_t pid,uint16_t offset,uint32_t ordata)188 void pcr_or32(uint8_t pid, uint16_t offset, uint32_t ordata)
189 {
190 	uint32_t data32;
191 
192 	data32 = pcr_read32(pid, offset);
193 	data32 |= ordata;
194 	pcr_write32(pid, offset, data32);
195 }
196 
pcr_or16(uint8_t pid,uint16_t offset,uint16_t ordata)197 void pcr_or16(uint8_t pid, uint16_t offset, uint16_t ordata)
198 {
199 	uint16_t data16;
200 
201 	data16 = pcr_read16(pid, offset);
202 	data16 |= ordata;
203 	pcr_write16(pid, offset, data16);
204 }
205 
pcr_or8(uint8_t pid,uint16_t offset,uint8_t ordata)206 void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata)
207 {
208 	uint8_t data8;
209 
210 	data8 = pcr_read8(pid, offset);
211 	data8 |= ordata;
212 	pcr_write8(pid, offset, data8);
213 }
214 
215 #if !CONFIG(PCR_COMMON_IOSF_1_0)
216 
pcr_wait_for_completion(const pci_devfn_t dev)217 static int pcr_wait_for_completion(const pci_devfn_t dev)
218 {
219 	struct stopwatch sw;
220 
221 	stopwatch_init_msecs_expire(&sw, PCR_SBI_CMD_TIMEOUT);
222 	do {
223 		if ((pci_read_config16(dev, P2SB_CR_SBI_STATUS) &
224 			P2SB_CR_SBI_STATUS_BUSY) == 0)
225 			return 0;
226 	} while (!stopwatch_expired(&sw));
227 
228 	return -1;
229 }
230 
231 /*
232  * API to perform sideband communication
233  *
234  * Input:
235  * struct pcr_sbi_msg
236  * data - read/write for sbi message
237  * response -
238  * 0 - successful
239  * 1 - unsuccessful
240  * 2 - powered down
241  * 3 - multi-cast mixed
242  *
243  * Output:
244  * 0: SBI message is successfully completed
245  * -1: SBI message failure
246  */
pcr_execute_sideband_msg(pci_devfn_t dev,struct pcr_sbi_msg * msg,uint32_t * data,uint8_t * response)247 int pcr_execute_sideband_msg(pci_devfn_t dev, struct pcr_sbi_msg *msg, uint32_t *data,
248 		uint8_t *response)
249 {
250 	uint32_t sbi_data;
251 	uint16_t sbi_status;
252 	uint16_t sbi_rid;
253 
254 	if (!msg || !data || !response) {
255 		printk(BIOS_ERR, "Pointer checked for NULL Fail! "
256 		       "msg = %p \t data = %p \t response = %p\n",
257 		       msg, data, response);
258 		return -1;
259 	}
260 
261 	switch (msg->opcode) {
262 		case MEM_READ:
263 		case MEM_WRITE:
264 		case PCI_CONFIG_READ:
265 		case PCI_CONFIG_WRITE:
266 		case PCR_READ:
267 		case PCR_WRITE:
268 		case GPIO_LOCK_UNLOCK:
269 			break;
270 		default:
271 			printk(BIOS_ERR, "SBI Failure: Wrong Input = %x!\n",
272 					msg->opcode);
273 			return -1;
274 	}
275 
276 	if (pci_read_config16(dev, PCI_VENDOR_ID) == 0xffff) {
277 		printk(BIOS_ERR, "SBI Failure: P2SB device Hidden!\n");
278 		return -1;
279 	}
280 
281 	/*
282 	 * BWG Section 2.2.1
283 	 * 1. Poll P2SB PCI offset D8h[0] = 0b
284 	 * Make sure the previous operation is completed.
285 	 */
286 	if (pcr_wait_for_completion(dev)) {
287 		printk(BIOS_ERR, "SBI Failure: Time Out!\n");
288 		return -1;
289 	}
290 
291 	/* Initial Response status */
292 	*response = P2SB_CR_SBI_STATUS_NOT_SUPPORTED;
293 
294 	/*
295 	 * 2. Write P2SB PCI offset D0h[31:0] with Address
296 	 * and Destination Port ID
297 	 */
298 	pci_write_config32(dev, P2SB_CR_SBI_ADDR,
299 		(msg->pid << P2SB_CR_SBI_DESTID) | msg->offset);
300 
301 	/*
302 	 * 3. Write P2SB PCI offset DCh[31:0] with extended address,
303 	 * which is expected to be 0
304 	 */
305 	pci_write_config32(dev, P2SB_CR_SBI_EXT_ADDR, msg->offset >> 16);
306 
307 	/*
308 	 * 4. Set P2SB PCI offset D8h[15:8] = 00000110b for read
309 	 *    Set P2SB PCI offset D8h[15:8] = 00000111b for write
310 	 *
311 	 * Set SBISTAT[15:8] to the opcode passed in
312 	 * Set SBISTAT[7] to the posted passed in
313 	 */
314 	sbi_status = pci_read_config16(dev, P2SB_CR_SBI_STATUS);
315 	sbi_status &= ~(P2SB_CR_SBI_OPCODE_MASK | P2SB_CR_SBI_POSTED_MASK);
316 	sbi_status |= (msg->opcode << P2SB_CR_SBI_OPCODE) |
317 				(msg->is_posted << P2SB_CR_SBI_POSTED);
318 	pci_write_config16(dev, P2SB_CR_SBI_STATUS, sbi_status);
319 
320 	/*
321 	 * 5. Write P2SB PCI offset DAh[15:0] = F000h
322 	 *
323 	 * Set RID[15:0] = Fbe << 12 | Bar << 8 | Fid
324 	 */
325 	sbi_rid = ((msg->fast_byte_enable & P2SB_CR_SBI_FBE_MASK)
326 					<< P2SB_CR_SBI_FBE) |
327 			((msg->bar & P2SB_CR_SBI_MASK) << P2SB_CR_SBI_BAR) |
328 			(msg->fid & P2SB_CR_SBI_FID_MASK);
329 	pci_write_config16(dev, P2SB_CR_SBI_ROUTE_IDEN, sbi_rid);
330 
331 	switch (msg->opcode) {
332 		case MEM_WRITE:
333 		case PCI_CONFIG_WRITE:
334 		case PCR_WRITE:
335 		case GPIO_LOCK_UNLOCK:
336 			/*
337 			 * 6. Write P2SB PCI offset D4h[31:0] with the
338 			 * intended data accordingly
339 			 */
340 			sbi_data = *data;
341 			pci_write_config32(dev, P2SB_CR_SBI_DATA, sbi_data);
342 			break;
343 		default:
344 			/* 6. Write P2SB PCI offset D4h[31:0] with dummy data */
345 			pci_write_config32(dev, P2SB_CR_SBI_DATA, 0);
346 			break;
347 	}
348 
349 	/*
350 	 * 7. Set P2SB PCI offset D8h[0] = 1b, Poll P2SB PCI offset D8h[0] = 0b
351 	 *
352 	 * Set SBISTAT[0] = 1b, trigger the SBI operation
353 	 */
354 	sbi_status = pci_read_config16(dev, P2SB_CR_SBI_STATUS);
355 	sbi_status |= P2SB_CR_SBI_STATUS_BUSY;
356 	pci_write_config16(dev, P2SB_CR_SBI_STATUS, sbi_status);
357 
358 	/* Poll SBISTAT[0] = 0b, Polling for Busy bit */
359 	if (pcr_wait_for_completion(dev)) {
360 		printk(BIOS_ERR, "SBI Failure: Time Out!\n");
361 		return -1;
362 	}
363 
364 	/*
365 	 * 8. Check if P2SB PCI offset D8h[2:1] = 00b for
366 	 * successful transaction
367 	 */
368 	*response = (sbi_status & P2SB_CR_SBI_STATUS_MASK) >> 1;
369 	if (*response == P2SB_CR_SBI_STATUS_SUCCESS) {
370 		switch (msg->opcode) {
371 		case MEM_READ:
372 		case PCI_CONFIG_READ:
373 		case PCR_READ:
374 			sbi_data = pci_read_config32(dev, P2SB_CR_SBI_DATA);
375 			*data = sbi_data;
376 			break;
377 		default:
378 			break;
379 		}
380 		return 0;
381 	}
382 	printk(BIOS_ERR, "SBI Failure: Transaction Status = %x\n",
383 			*response);
384 	return -1;
385 }
386 #endif
387