diff --git a/src/soc/intel/common/block/include/intelblocks/pcr.h b/src/soc/intel/common/block/include/intelblocks/pcr.h new file mode 100644 index 0000000000..cfe0015f70 --- /dev/null +++ b/src/soc/intel/common/block/include/intelblocks/pcr.h @@ -0,0 +1,45 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SOC_INTEL_COMMON_BLOCK_PCR_H +#define SOC_INTEL_COMMON_BLOCK_PCR_H + +/* Port Id lives in bits 23:16 and register offset lives in 15:0 of address. */ +#define PCR_PORTID_SHIFT 16 + +#if !defined(__ACPI__) +#include + +uint32_t pcr_read32(uint8_t pid, uint16_t offset); +uint16_t pcr_read16(uint8_t pid, uint16_t offset); +uint8_t pcr_read8(uint8_t pid, uint16_t offset); +void pcr_write32(uint8_t pid, uint16_t offset, uint32_t indata); +void pcr_write16(uint8_t pid, uint16_t offset, uint16_t indata); +void pcr_write8(uint8_t pid, uint16_t offset, uint8_t indata); +void pcr_rmw32(uint8_t pid, uint16_t offset, uint32_t anddata, + uint32_t ordata); +void pcr_rmw16(uint8_t pid, uint16_t offset, uint16_t anddata, + uint16_t ordata); +void pcr_rmw8(uint8_t pid, uint16_t offset, uint8_t anddata, + uint8_t ordata); +void pcr_or32(uint8_t pid, uint16_t offset, uint32_t ordata); +void pcr_or16(uint8_t pid, uint16_t offset, uint16_t ordata); +void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata); + +/* Get the starting address of the port's registers. */ +void *pcr_reg_address(uint8_t pid, uint16_t offset); +#endif /* if !defined(__ACPI__) */ + +#endif /* SOC_INTEL_COMMON_BLOCK_PCR_H */ diff --git a/src/soc/intel/common/block/pcr/Kconfig b/src/soc/intel/common/block/pcr/Kconfig new file mode 100644 index 0000000000..be038383ab --- /dev/null +++ b/src/soc/intel/common/block/pcr/Kconfig @@ -0,0 +1,14 @@ +config SOC_INTEL_COMMON_BLOCK_PCR + bool + help + Intel Processor common Private configuration registers (PCR) + +config PCR_COMMON_IOSF_1_0 + bool + depends on SOC_INTEL_COMMON_BLOCK_PCR + help + The mapping of addresses via the SBREG_BAR assumes the IOSF-SB + agents are using 32-bit aligned accesses for their configuration + registers. For IOSF versions greater than 1_0, IOSF-SB + agents can use any access (8/16/32 bit aligned) for their + configuration registers diff --git a/src/soc/intel/common/block/pcr/Makefile.inc b/src/soc/intel/common/block/pcr/Makefile.inc new file mode 100644 index 0000000000..c64fe7a57a --- /dev/null +++ b/src/soc/intel/common/block/pcr/Makefile.inc @@ -0,0 +1,4 @@ +bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PCR) += pcr.c +romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PCR) += pcr.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PCR) += pcr.c +smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PCR) += pcr.c diff --git a/src/soc/intel/common/block/pcr/pcr.c b/src/soc/intel/common/block/pcr/pcr.c new file mode 100644 index 0000000000..6560a4b337 --- /dev/null +++ b/src/soc/intel/common/block/pcr/pcr.c @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +static void *__pcr_reg_address(uint8_t pid, uint16_t offset) +{ + uintptr_t reg_addr; + + /* Create an address based off of port id and offset. */ + reg_addr = CONFIG_PCR_BASE_ADDRESS; + reg_addr += ((uintptr_t)pid) << PCR_PORTID_SHIFT; + reg_addr += (uintptr_t)offset; + + return (void *)reg_addr; +} + +void *pcr_reg_address(uint8_t pid, uint16_t offset) +{ + if (IS_ENABLED(CONFIG_PCR_COMMON_IOSF_1_0)) + assert(IS_ALIGNED(offset, sizeof(uint32_t))); + + return __pcr_reg_address(pid, offset); +} + +/* + * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB + * agents are using 32-bit aligned accesses for their configuration + * registers. For IOSF versions greater than 1_0, IOSF-SB + * agents can use any access (8/16/32 bit aligned) for their + * configuration registers + */ +static inline void check_pcr_offset_align(uint16_t offset, size_t size) +{ + const size_t align = IS_ENABLED(CONFIG_PCR_COMMON_IOSF_1_0) ? + sizeof(uint32_t) : size; + + assert(IS_ALIGNED(offset, align)); +} + +uint32_t pcr_read32(uint8_t pid, uint16_t offset) +{ + /* Ensure the PCR offset is corretcly aligned. */ + assert(IS_ALIGNED(offset, sizeof(uint32_t))); + + return read32(__pcr_reg_address(pid, offset)); +} + +uint16_t pcr_read16(uint8_t pid, uint16_t offset) +{ + /* Ensure the PCR offset is corretcly aligned. */ + check_pcr_offset_align(offset, sizeof(uint16_t)); + + return read16(__pcr_reg_address(pid, offset)); +} + +uint8_t pcr_read8(uint8_t pid, uint16_t offset) +{ + /* Ensure the PCR offset is corretcly aligned. */ + check_pcr_offset_align(offset, sizeof(uint8_t)); + + return read8(__pcr_reg_address(pid, offset)); +} + +/* + * After every write one needs to perform a read an innocuous register to + * ensure the writes are completed for certain ports. This is done for + * all ports so that the callers don't need the per-port knowledge for + * each transaction. + */ +static inline void write_completion(uint8_t pid, uint16_t offset) +{ + read32(__pcr_reg_address(pid, ALIGN_DOWN(offset, sizeof(uint32_t)))); +} + +void pcr_write32(uint8_t pid, uint16_t offset, uint32_t indata) +{ + /* Ensure the PCR offset is corretcly aligned. */ + assert(IS_ALIGNED(offset, sizeof(indata))); + + write32(__pcr_reg_address(pid, offset), indata); + /* Ensure the writes complete. */ + write_completion(pid, offset); +} + +void pcr_write16(uint8_t pid, uint16_t offset, uint16_t indata) +{ + /* Ensure the PCR offset is corretcly aligned. */ + check_pcr_offset_align(offset, sizeof(uint16_t)); + + write16(__pcr_reg_address(pid, offset), indata); + /* Ensure the writes complete. */ + write_completion(pid, offset); +} + +void pcr_write8(uint8_t pid, uint16_t offset, uint8_t indata) +{ + /* Ensure the PCR offset is corretcly aligned. */ + check_pcr_offset_align(offset, sizeof(uint8_t)); + + write8(__pcr_reg_address(pid, offset), indata); + /* Ensure the writes complete. */ + write_completion(pid, offset); +} + +void pcr_rmw32(uint8_t pid, uint16_t offset, uint32_t anddata, uint32_t ordata) +{ + uint32_t data32; + + data32 = pcr_read32(pid, offset); + data32 &= anddata; + data32 |= ordata; + pcr_write32(pid, offset, data32); +} + +void pcr_rmw16(uint8_t pid, uint16_t offset, uint16_t anddata, uint16_t ordata) +{ + uint16_t data16; + + data16 = pcr_read16(pid, offset); + data16 &= anddata; + data16 |= ordata; + pcr_write16(pid, offset, data16); +} + +void pcr_rmw8(uint8_t pid, uint16_t offset, uint8_t anddata, uint8_t ordata) +{ + uint8_t data8; + + data8 = pcr_read8(pid, offset); + data8 &= anddata; + data8 |= ordata; + pcr_write8(pid, offset, data8); +} + +void pcr_or32(uint8_t pid, uint16_t offset, uint32_t ordata) +{ + uint32_t data32; + + data32 = pcr_read32(pid, offset); + data32 |= ordata; + pcr_write32(pid, offset, data32); +} + +void pcr_or16(uint8_t pid, uint16_t offset, uint16_t ordata) +{ + uint16_t data16; + + data16 = pcr_read16(pid, offset); + data16 |= ordata; + pcr_write16(pid, offset, data16); +} + +void pcr_or8(uint8_t pid, uint16_t offset, uint8_t ordata) +{ + uint8_t data8; + + data8 = pcr_read8(pid, offset); + data8 |= ordata; + pcr_write8(pid, offset, data8); +}