arch/x86/acpigen: Add OperationRegion & Field method
Add acpigen_write_opregion that generates ACPI AML code for OperationRegion, region name, region space, region length & region size are inputs. Add acpigen_write_field that generates ACPI AML code for Field. Operation region name & field list are inputs. Change-Id: I578834217d39aa3b0d409eb8ba4b5f7a31969fa8 Signed-off-by: Naresh G Solanki <naresh.solanki@intel.com> Reviewed-on: https://review.coreboot.org/17113 Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins)
This commit is contained in:
		
				
					committed by
					
						
						Martin Roth
					
				
			
			
				
	
			
			
			
						parent
						
							463f46eb61
						
					
				
				
					commit
					8535c66873
				
			@@ -351,6 +351,122 @@ void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
 | 
				
			|||||||
	acpigen_emit_byte(pblock_len);
 | 
						acpigen_emit_byte(pblock_len);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Generate ACPI AML code for OperationRegion
 | 
				
			||||||
 | 
					 * Arg0: Pointer to struct opregion opreg = OPREGION(rname, space, offset, len)
 | 
				
			||||||
 | 
					 * where rname is region name, space is region space, offset is region offset &
 | 
				
			||||||
 | 
					 * len is region length.
 | 
				
			||||||
 | 
					 * OperationRegion(regionname, regionspace, regionoffset, regionlength)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void acpigen_write_opregion(struct opregion *opreg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* OpregionOp */
 | 
				
			||||||
 | 
						acpigen_emit_ext_op(OPREGION_OP);
 | 
				
			||||||
 | 
						/* NameString 4 chars only */
 | 
				
			||||||
 | 
						acpigen_emit_simple_namestring(opreg->name);
 | 
				
			||||||
 | 
						/* RegionSpace */
 | 
				
			||||||
 | 
						acpigen_emit_byte(opreg->regionspace);
 | 
				
			||||||
 | 
						/* RegionOffset & RegionLen, it can be byte word or double word */
 | 
				
			||||||
 | 
						acpigen_write_integer(opreg->regionoffset);
 | 
				
			||||||
 | 
						acpigen_write_integer(opreg->regionlen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void acpigen_write_field_offset(uint32_t offset,
 | 
				
			||||||
 | 
									       uint32_t current_bit_pos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t diff_bits;
 | 
				
			||||||
 | 
						uint8_t i, j;
 | 
				
			||||||
 | 
						uint8_t emit[4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (offset < current_bit_pos) {
 | 
				
			||||||
 | 
							printk(BIOS_WARNING, "%s: Cannot move offset backward",
 | 
				
			||||||
 | 
								__func__);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						diff_bits = offset - current_bit_pos;
 | 
				
			||||||
 | 
						/* Upper limit */
 | 
				
			||||||
 | 
						if (diff_bits > 0xFFFFFFF) {
 | 
				
			||||||
 | 
							printk(BIOS_WARNING, "%s: Offset very large to encode",
 | 
				
			||||||
 | 
								__func__);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i = 1;
 | 
				
			||||||
 | 
						if (diff_bits < 0x40) {
 | 
				
			||||||
 | 
							emit[0] = diff_bits & 0x3F;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							emit[0] = diff_bits & 0xF;
 | 
				
			||||||
 | 
							diff_bits >>= 4;
 | 
				
			||||||
 | 
							while (diff_bits) {
 | 
				
			||||||
 | 
								emit[i] = diff_bits & 0xFF;
 | 
				
			||||||
 | 
								i++;
 | 
				
			||||||
 | 
								diff_bits >>= 8;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* Update bit 7:6 : Number of bytes followed by emit[0] */
 | 
				
			||||||
 | 
						emit[0] |= (i - 1) << 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						acpigen_emit_byte(0);
 | 
				
			||||||
 | 
						for (j = 0; j < i; j++)
 | 
				
			||||||
 | 
							acpigen_emit_byte(emit[j]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Generate ACPI AML code for Field
 | 
				
			||||||
 | 
					 * Arg0: region name
 | 
				
			||||||
 | 
					 * Arg1: Pointer to struct fieldlist.
 | 
				
			||||||
 | 
					 * Arg2: no. of entries in Arg1
 | 
				
			||||||
 | 
					 * Arg3: flags which indicate filed access type, lock rule  & update rule.
 | 
				
			||||||
 | 
					 * Example with fieldlist
 | 
				
			||||||
 | 
					 * struct fieldlist l[] = {
 | 
				
			||||||
 | 
					 *	FIELDLIST_OFFSET(0x84),
 | 
				
			||||||
 | 
					 *	FIELDLIST_NAMESTR("PMCS", 2),
 | 
				
			||||||
 | 
					 *	};
 | 
				
			||||||
 | 
					 * acpigen_write_field("UART", l ,ARRAY_SIZE(l), FIELD_ANYACC | FIELD_NOLOCK |
 | 
				
			||||||
 | 
					 *								FIELD_PRESERVE);
 | 
				
			||||||
 | 
					 * Output:
 | 
				
			||||||
 | 
					 * Field (UART, AnyAcc, NoLock, Preserve)
 | 
				
			||||||
 | 
					 *	{
 | 
				
			||||||
 | 
					 *		Offset (0x84),
 | 
				
			||||||
 | 
					 *		PMCS,   2
 | 
				
			||||||
 | 
					 *	}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void acpigen_write_field(const char *name, struct fieldlist *l, size_t count,
 | 
				
			||||||
 | 
								 uint8_t flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint16_t i;
 | 
				
			||||||
 | 
						uint32_t current_bit_pos = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* FieldOp */
 | 
				
			||||||
 | 
						acpigen_emit_ext_op(FIELD_OP);
 | 
				
			||||||
 | 
						/* Package Length */
 | 
				
			||||||
 | 
						acpigen_write_len_f();
 | 
				
			||||||
 | 
						/* NameString 4 chars only */
 | 
				
			||||||
 | 
						acpigen_emit_simple_namestring(name);
 | 
				
			||||||
 | 
						/* Field Flag */
 | 
				
			||||||
 | 
						acpigen_emit_byte(flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < count; i++) {
 | 
				
			||||||
 | 
							switch (l[i].type) {
 | 
				
			||||||
 | 
							case NAME_STRING:
 | 
				
			||||||
 | 
								acpigen_emit_simple_namestring(l[i].name);
 | 
				
			||||||
 | 
								acpigen_emit_byte(l[i].bits);
 | 
				
			||||||
 | 
								current_bit_pos += l[i].bits;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case OFFSET:
 | 
				
			||||||
 | 
								acpigen_write_field_offset(l[i].bits, current_bit_pos);
 | 
				
			||||||
 | 
								current_bit_pos = l[i].bits;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								printk(BIOS_ERR, "%s: Invalid field type 0x%X\n"
 | 
				
			||||||
 | 
									, __func__, l[i].type);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						acpigen_pop_len();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void acpigen_write_empty_PCT(void)
 | 
					void acpigen_write_empty_PCT(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,6 +53,8 @@ enum {
 | 
				
			|||||||
	EXT_OP_PREFIX		= 0x5B,
 | 
						EXT_OP_PREFIX		= 0x5B,
 | 
				
			||||||
	 SLEEP_OP		= 0x22,
 | 
						 SLEEP_OP		= 0x22,
 | 
				
			||||||
	 DEBUG_OP		= 0x31,
 | 
						 DEBUG_OP		= 0x31,
 | 
				
			||||||
 | 
						 OPREGION_OP		= 0x80,
 | 
				
			||||||
 | 
						 FIELD_OP		= 0x81,
 | 
				
			||||||
	 DEVICE_OP		= 0x82,
 | 
						 DEVICE_OP		= 0x82,
 | 
				
			||||||
	 PROCESSOR_OP		= 0x83,
 | 
						 PROCESSOR_OP		= 0x83,
 | 
				
			||||||
	 POWER_RES_OP		= 0x84,
 | 
						 POWER_RES_OP		= 0x84,
 | 
				
			||||||
@@ -84,6 +86,64 @@ enum {
 | 
				
			|||||||
	ONES_OP		= 0xFF,
 | 
						ONES_OP		= 0xFF,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FIELDLIST_OFFSET(X)		{ .type = OFFSET, \
 | 
				
			||||||
 | 
										  .name = "",\
 | 
				
			||||||
 | 
										  .bits = X * 8, \
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					#define FIELDLIST_NAMESTR(X, Y)		{ .type = NAME_STRING, \
 | 
				
			||||||
 | 
										  .name = X, \
 | 
				
			||||||
 | 
										  .bits = Y, \
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FIELD_ANYACC			0
 | 
				
			||||||
 | 
					#define FIELD_BYTEACC			1
 | 
				
			||||||
 | 
					#define FIELD_WORDACC			2
 | 
				
			||||||
 | 
					#define FIELD_DWORDACC			3
 | 
				
			||||||
 | 
					#define FIELD_QWORDACC			4
 | 
				
			||||||
 | 
					#define FIELD_BUFFERACC			5
 | 
				
			||||||
 | 
					#define FIELD_NOLOCK			(0<<4)
 | 
				
			||||||
 | 
					#define FIELD_LOCK			(1<<4)
 | 
				
			||||||
 | 
					#define FIELD_PRESERVE			(0<<5)
 | 
				
			||||||
 | 
					#define FIELD_WRITEASONES		(1<<5)
 | 
				
			||||||
 | 
					#define FIELD_WRITEASZEROS		(2<<5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum field_type {
 | 
				
			||||||
 | 
						OFFSET,
 | 
				
			||||||
 | 
						NAME_STRING,
 | 
				
			||||||
 | 
						FIELD_TYPE_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct fieldlist {
 | 
				
			||||||
 | 
						enum field_type type;
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						u32 bits;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OPREGION(rname, space, offset, len)	{.name = rname, \
 | 
				
			||||||
 | 
											 .regionspace = space, \
 | 
				
			||||||
 | 
											 .regionoffset = offset, \
 | 
				
			||||||
 | 
											 .regionlen = len, \
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum region_space {
 | 
				
			||||||
 | 
						SYSTEMMEMORY,
 | 
				
			||||||
 | 
						SYSTEMIO,
 | 
				
			||||||
 | 
						PCI_CONFIG,
 | 
				
			||||||
 | 
						EMBEDDEDCONTROL,
 | 
				
			||||||
 | 
						SMBUS,
 | 
				
			||||||
 | 
						CMOS,
 | 
				
			||||||
 | 
						PCIBARTARGET,
 | 
				
			||||||
 | 
						IPMI,
 | 
				
			||||||
 | 
						REGION_SPACE_MAX,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct opregion {
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						enum region_space regionspace;
 | 
				
			||||||
 | 
						unsigned long regionoffset;
 | 
				
			||||||
 | 
						unsigned long regionlen;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void acpigen_write_len_f(void);
 | 
					void acpigen_write_len_f(void);
 | 
				
			||||||
void acpigen_pop_len(void);
 | 
					void acpigen_pop_len(void);
 | 
				
			||||||
void acpigen_set_current(char *curr);
 | 
					void acpigen_set_current(char *curr);
 | 
				
			||||||
@@ -175,6 +235,18 @@ void acpigen_write_return_byte(uint8_t arg);
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
void acpigen_write_dsm(const char *uuid, void (*callbacks[])(void *),
 | 
					void acpigen_write_dsm(const char *uuid, void (*callbacks[])(void *),
 | 
				
			||||||
		       size_t count, void *arg);
 | 
							       size_t count, void *arg);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Generate ACPI AML code for OperationRegion
 | 
				
			||||||
 | 
					 * This function takes input region name, region space, region offset & region
 | 
				
			||||||
 | 
					 * length.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void acpigen_write_opregion(struct opregion *opreg);
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Generate ACPI AML code for Field
 | 
				
			||||||
 | 
					 * This function takes input region name, fieldlist, count & flags.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void acpigen_write_field(const char *name, struct fieldlist *l, size_t count,
 | 
				
			||||||
 | 
								 uint8_t flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int get_cst_entries(acpi_cstate_t **);
 | 
					int get_cst_entries(acpi_cstate_t **);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user