|
@@ -24,9 +24,13 @@
|
|
#include "hw/irq.h"
|
|
#include "hw/irq.h"
|
|
#include "hw/qdev-properties.h"
|
|
#include "hw/qdev-properties.h"
|
|
#include "hw/ppc/pnv.h"
|
|
#include "hw/ppc/pnv.h"
|
|
|
|
+#include "hw/ppc/pnv_chip.h"
|
|
#include "hw/ppc/pnv_xscom.h"
|
|
#include "hw/ppc/pnv_xscom.h"
|
|
#include "hw/ppc/pnv_occ.h"
|
|
#include "hw/ppc/pnv_occ.h"
|
|
|
|
|
|
|
|
+#define P8_HOMER_OPAL_DATA_OFFSET 0x1F8000
|
|
|
|
+#define P9_HOMER_OPAL_DATA_OFFSET 0x0E2000
|
|
|
|
+
|
|
#define OCB_OCI_OCCMISC 0x4020
|
|
#define OCB_OCI_OCCMISC 0x4020
|
|
#define OCB_OCI_OCCMISC_AND 0x4021
|
|
#define OCB_OCI_OCCMISC_AND 0x4021
|
|
#define OCB_OCI_OCCMISC_OR 0x4022
|
|
#define OCB_OCI_OCCMISC_OR 0x4022
|
|
@@ -166,7 +170,11 @@ const MemoryRegionOps pnv_occ_sram_ops = {
|
|
static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
|
|
static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
{
|
|
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
|
|
PnvOCCClass *poc = PNV_OCC_CLASS(klass);
|
|
|
|
+ DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
|
|
|
|
+ dc->desc = "PowerNV OCC Controller (POWER8)";
|
|
|
|
+ poc->opal_shared_memory_offset = P8_HOMER_OPAL_DATA_OFFSET;
|
|
|
|
+ poc->opal_shared_memory_version = 0x02;
|
|
poc->xscom_size = PNV_XSCOM_OCC_SIZE;
|
|
poc->xscom_size = PNV_XSCOM_OCC_SIZE;
|
|
poc->xscom_ops = &pnv_occ_power8_xscom_ops;
|
|
poc->xscom_ops = &pnv_occ_power8_xscom_ops;
|
|
}
|
|
}
|
|
@@ -239,8 +247,11 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
|
|
dc->desc = "PowerNV OCC Controller (POWER9)";
|
|
dc->desc = "PowerNV OCC Controller (POWER9)";
|
|
|
|
+ poc->opal_shared_memory_offset = P9_HOMER_OPAL_DATA_OFFSET;
|
|
|
|
+ poc->opal_shared_memory_version = 0x90;
|
|
poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
|
|
poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
|
|
poc->xscom_ops = &pnv_occ_power9_xscom_ops;
|
|
poc->xscom_ops = &pnv_occ_power9_xscom_ops;
|
|
|
|
+ assert(!dc->user_creatable);
|
|
}
|
|
}
|
|
|
|
|
|
static const TypeInfo pnv_occ_power9_type_info = {
|
|
static const TypeInfo pnv_occ_power9_type_info = {
|
|
@@ -263,10 +274,19 @@ static const TypeInfo pnv_occ_power10_type_info = {
|
|
.class_init = pnv_occ_power10_class_init,
|
|
.class_init = pnv_occ_power10_class_init,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static bool occ_init_homer_memory(PnvOCC *occ, Error **errp);
|
|
|
|
+
|
|
static void pnv_occ_realize(DeviceState *dev, Error **errp)
|
|
static void pnv_occ_realize(DeviceState *dev, Error **errp)
|
|
{
|
|
{
|
|
PnvOCC *occ = PNV_OCC(dev);
|
|
PnvOCC *occ = PNV_OCC(dev);
|
|
PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
|
PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
|
|
|
+ PnvHomer *homer = occ->homer;
|
|
|
|
+
|
|
|
|
+ assert(homer);
|
|
|
|
+
|
|
|
|
+ if (!occ_init_homer_memory(occ, errp)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
occ->occmisc = 0;
|
|
occ->occmisc = 0;
|
|
|
|
|
|
@@ -282,12 +302,16 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
|
|
qdev_init_gpio_out(dev, &occ->psi_irq, 1);
|
|
qdev_init_gpio_out(dev, &occ->psi_irq, 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static const Property pnv_occ_properties[] = {
|
|
|
|
+ DEFINE_PROP_LINK("homer", PnvOCC, homer, TYPE_PNV_HOMER, PnvHomer *),
|
|
|
|
+};
|
|
|
|
+
|
|
static void pnv_occ_class_init(ObjectClass *klass, void *data)
|
|
static void pnv_occ_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
|
|
dc->realize = pnv_occ_realize;
|
|
dc->realize = pnv_occ_realize;
|
|
- dc->desc = "PowerNV OCC Controller";
|
|
|
|
|
|
+ device_class_set_props(dc, pnv_occ_properties);
|
|
dc->user_creatable = false;
|
|
dc->user_creatable = false;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -309,3 +333,411 @@ static void pnv_occ_register_types(void)
|
|
}
|
|
}
|
|
|
|
|
|
type_init(pnv_occ_register_types);
|
|
type_init(pnv_occ_register_types);
|
|
|
|
+
|
|
|
|
+/* From skiboot/hw/occ.c with tab to space conversion */
|
|
|
|
+/* OCC Communication Area for PStates */
|
|
|
|
+
|
|
|
|
+#define OPAL_DYNAMIC_DATA_OFFSET 0x0B80
|
|
|
|
+/* relative to HOMER_OPAL_DATA_OFFSET */
|
|
|
|
+
|
|
|
|
+#define MAX_PSTATES 256
|
|
|
|
+#define MAX_P8_CORES 12
|
|
|
|
+#define MAX_P9_CORES 24
|
|
|
|
+#define MAX_P10_CORES 32
|
|
|
|
+
|
|
|
|
+#define MAX_OPAL_CMD_DATA_LENGTH 4090
|
|
|
|
+#define MAX_OCC_RSP_DATA_LENGTH 8698
|
|
|
|
+
|
|
|
|
+#define P8_PIR_CORE_MASK 0xFFF8
|
|
|
|
+#define P9_PIR_QUAD_MASK 0xFFF0
|
|
|
|
+#define P10_PIR_CHIP_MASK 0x0000
|
|
|
|
+#define FREQ_MAX_IN_DOMAIN 0
|
|
|
|
+#define FREQ_MOST_RECENTLY_SET 1
|
|
|
|
+
|
|
|
|
+#define u8 uint8_t
|
|
|
|
+#define s8 int8_t
|
|
|
|
+#define u16 uint16_t
|
|
|
|
+#define s16 int16_t
|
|
|
|
+#define u32 uint32_t
|
|
|
|
+#define s32 int32_t
|
|
|
|
+#define u64 uint64_t
|
|
|
|
+#define s64 int64_t
|
|
|
|
+#define __be16 uint16_t
|
|
|
|
+#define __be32 uint32_t
|
|
|
|
+#define __packed QEMU_PACKED
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * OCC-OPAL Shared Memory Region
|
|
|
|
+ *
|
|
|
|
+ * Reference document :
|
|
|
|
+ * https://github.com/open-power/docs/blob/master/occ/OCC_OpenPwr_FW_Interfaces.pdf
|
|
|
|
+ *
|
|
|
|
+ * Supported layout versions:
|
|
|
|
+ * - 0x01, 0x02 : P8
|
|
|
|
+ * https://github.com/open-power/occ/blob/master_p8/src/occ/proc/proc_pstate.h
|
|
|
|
+ *
|
|
|
|
+ * - 0x90 : P9
|
|
|
|
+ * https://github.com/open-power/occ/blob/master/src/occ_405/proc/proc_pstate.h
|
|
|
|
+ * In 0x90 the data is separated into :-
|
|
|
|
+ * -- Static Data (struct occ_pstate_table): Data is written once by OCC
|
|
|
|
+ * -- Dynamic Data (struct occ_dynamic_data): Data is updated at runtime
|
|
|
|
+ *
|
|
|
|
+ * struct occ_pstate_table - Pstate table layout
|
|
|
|
+ * @valid: Indicates if data is valid
|
|
|
|
+ * @version: Layout version [Major/Minor]
|
|
|
|
+ * @v2.throttle: Reason for limiting the max pstate
|
|
|
|
+ * @v9.occ_role: OCC role (Master/Slave)
|
|
|
|
+ * @v#.pstate_min: Minimum pstate ever allowed
|
|
|
|
+ * @v#.pstate_nom: Nominal pstate
|
|
|
|
+ * @v#.pstate_turbo: Maximum turbo pstate
|
|
|
|
+ * @v#.pstate_ultra_turbo: Maximum ultra turbo pstate and the maximum
|
|
|
|
+ * pstate ever allowed
|
|
|
|
+ * @v#.pstates: Pstate-id and frequency list from Pmax to Pmin
|
|
|
|
+ * @v#.pstates.id: Pstate-id
|
|
|
|
+ * @v#.pstates.flags: Pstate-flag(reserved)
|
|
|
|
+ * @v2.pstates.vdd: Voltage Identifier
|
|
|
|
+ * @v2.pstates.vcs: Voltage Identifier
|
|
|
|
+ * @v#.pstates.freq_khz: Frequency in KHz
|
|
|
|
+ * @v#.core_max[1..N]: Max pstate with N active cores
|
|
|
|
+ * @spare/reserved/pad: Unused data
|
|
|
|
+ */
|
|
|
|
+struct occ_pstate_table {
|
|
|
|
+ u8 valid;
|
|
|
|
+ u8 version;
|
|
|
|
+ union __packed {
|
|
|
|
+ struct __packed { /* Version 0x01 and 0x02 */
|
|
|
|
+ u8 throttle;
|
|
|
|
+ s8 pstate_min;
|
|
|
|
+ s8 pstate_nom;
|
|
|
|
+ s8 pstate_turbo;
|
|
|
|
+ s8 pstate_ultra_turbo;
|
|
|
|
+ u8 spare;
|
|
|
|
+ u64 reserved;
|
|
|
|
+ struct __packed {
|
|
|
|
+ s8 id;
|
|
|
|
+ u8 flags;
|
|
|
|
+ u8 vdd;
|
|
|
|
+ u8 vcs;
|
|
|
|
+ __be32 freq_khz;
|
|
|
|
+ } pstates[MAX_PSTATES];
|
|
|
|
+ s8 core_max[MAX_P8_CORES];
|
|
|
|
+ u8 pad[100];
|
|
|
|
+ } v2;
|
|
|
|
+ struct __packed { /* Version 0x90 */
|
|
|
|
+ u8 occ_role;
|
|
|
|
+ u8 pstate_min;
|
|
|
|
+ u8 pstate_nom;
|
|
|
|
+ u8 pstate_turbo;
|
|
|
|
+ u8 pstate_ultra_turbo;
|
|
|
|
+ u8 spare;
|
|
|
|
+ u64 reserved1;
|
|
|
|
+ u64 reserved2;
|
|
|
|
+ struct __packed {
|
|
|
|
+ u8 id;
|
|
|
|
+ u8 flags;
|
|
|
|
+ u16 reserved;
|
|
|
|
+ __be32 freq_khz;
|
|
|
|
+ } pstates[MAX_PSTATES];
|
|
|
|
+ u8 core_max[MAX_P9_CORES];
|
|
|
|
+ u8 pad[56];
|
|
|
|
+ } v9;
|
|
|
|
+ struct __packed { /* Version 0xA0 */
|
|
|
|
+ u8 occ_role;
|
|
|
|
+ u8 pstate_min;
|
|
|
|
+ u8 pstate_fixed_freq;
|
|
|
|
+ u8 pstate_base;
|
|
|
|
+ u8 pstate_ultra_turbo;
|
|
|
|
+ u8 pstate_fmax;
|
|
|
|
+ u8 minor;
|
|
|
|
+ u8 pstate_bottom_throttle;
|
|
|
|
+ u8 spare;
|
|
|
|
+ u8 spare1;
|
|
|
|
+ u32 reserved_32;
|
|
|
|
+ u64 reserved_64;
|
|
|
|
+ struct __packed {
|
|
|
|
+ u8 id;
|
|
|
|
+ u8 valid;
|
|
|
|
+ u16 reserved;
|
|
|
|
+ __be32 freq_khz;
|
|
|
|
+ } pstates[MAX_PSTATES];
|
|
|
|
+ u8 core_max[MAX_P10_CORES];
|
|
|
|
+ u8 pad[48];
|
|
|
|
+ } v10;
|
|
|
|
+ };
|
|
|
|
+} __packed;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * OPAL-OCC Command Response Interface
|
|
|
|
+ *
|
|
|
|
+ * OPAL-OCC Command Buffer
|
|
|
|
+ *
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ * | OPAL | Cmd | OPAL | | Cmd Data | Cmd Data | OPAL |
|
|
|
|
+ * | Cmd | Request | OCC | Reserved | Length | Length | Cmd |
|
|
|
|
+ * | Flags | ID | Cmd | | (MSB) | (LSB) | Data... |
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ * | ….OPAL Command Data up to max of Cmd Data Length 4090 bytes |
|
|
|
|
+ * | |
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ *
|
|
|
|
+ * OPAL Command Flag
|
|
|
|
+ *
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|
|
|
|
+ * | (msb) | | | | | | | (lsb) |
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ * |Cmd | | | | | | | |
|
|
|
|
+ * |Ready | | | | | | | |
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ *
|
|
|
|
+ * struct opal_command_buffer - Defines the layout of OPAL command buffer
|
|
|
|
+ * @flag: Provides general status of the command
|
|
|
|
+ * @request_id: Token to identify request
|
|
|
|
+ * @cmd: Command sent
|
|
|
|
+ * @data_size: Command data length
|
|
|
|
+ * @data: Command specific data
|
|
|
|
+ * @spare: Unused byte
|
|
|
|
+ */
|
|
|
|
+struct opal_command_buffer {
|
|
|
|
+ u8 flag;
|
|
|
|
+ u8 request_id;
|
|
|
|
+ u8 cmd;
|
|
|
|
+ u8 spare;
|
|
|
|
+ __be16 data_size;
|
|
|
|
+ u8 data[MAX_OPAL_CMD_DATA_LENGTH];
|
|
|
|
+} __packed;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * OPAL-OCC Response Buffer
|
|
|
|
+ *
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ * | OCC | Cmd | OPAL | Response | Rsp Data | Rsp Data | OPAL |
|
|
|
|
+ * | Rsp | Request | OCC | Status | Length | Length | Rsp |
|
|
|
|
+ * | Flags | ID | Cmd | | (MSB) | (LSB) | Data... |
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ * | ….OPAL Response Data up to max of Rsp Data Length 8698 bytes |
|
|
|
|
+ * | |
|
|
|
|
+ * ---------------------------------------------------------------------
|
|
|
|
+ *
|
|
|
|
+ * OCC Response Flag
|
|
|
|
+ *
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|
|
|
|
+ * | (msb) | | | | | | | (lsb) |
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ * | | | | | | |OCC in | Rsp |
|
|
|
|
+ * | | | | | | |progress|Ready |
|
|
|
|
+ * -----------------------------------------------------------------
|
|
|
|
+ *
|
|
|
|
+ * struct occ_response_buffer - Defines the layout of OCC response buffer
|
|
|
|
+ * @flag: Provides general status of the response
|
|
|
|
+ * @request_id: Token to identify request
|
|
|
|
+ * @cmd: Command requested
|
|
|
|
+ * @status: Indicates success/failure status of
|
|
|
|
+ * the command
|
|
|
|
+ * @data_size: Response data length
|
|
|
|
+ * @data: Response specific data
|
|
|
|
+ */
|
|
|
|
+struct occ_response_buffer {
|
|
|
|
+ u8 flag;
|
|
|
|
+ u8 request_id;
|
|
|
|
+ u8 cmd;
|
|
|
|
+ u8 status;
|
|
|
|
+ __be16 data_size;
|
|
|
|
+ u8 data[MAX_OCC_RSP_DATA_LENGTH];
|
|
|
|
+} __packed;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * OCC-OPAL Shared Memory Interface Dynamic Data Vx90
|
|
|
|
+ *
|
|
|
|
+ * struct occ_dynamic_data - Contains runtime attributes
|
|
|
|
+ * @occ_state: Current state of OCC
|
|
|
|
+ * @major_version: Major version number
|
|
|
|
+ * @minor_version: Minor version number (backwards compatible)
|
|
|
|
+ * Version 1 indicates GPU presence populated
|
|
|
|
+ * @gpus_present: Bitmask of GPUs present (on systems where GPU
|
|
|
|
+ * presence is detected through APSS)
|
|
|
|
+ * @cpu_throttle: Reason for limiting the max pstate
|
|
|
|
+ * @mem_throttle: Reason for throttling memory
|
|
|
|
+ * @quick_pwr_drop: Indicates if QPD is asserted
|
|
|
|
+ * @pwr_shifting_ratio: Indicates the current percentage of power to
|
|
|
|
+ * take away from the CPU vs GPU when shifting
|
|
|
|
+ * power to maintain a power cap. Value of 100
|
|
|
|
+ * means take all power from CPU.
|
|
|
|
+ * @pwr_cap_type: Indicates type of power cap in effect
|
|
|
|
+ * @hard_min_pwr_cap: Hard minimum system power cap in Watts.
|
|
|
|
+ * Guaranteed unless hardware failure
|
|
|
|
+ * @max_pwr_cap: Maximum allowed system power cap in Watts
|
|
|
|
+ * @cur_pwr_cap: Current system power cap
|
|
|
|
+ * @soft_min_pwr_cap: Soft powercap minimum. OCC may or may not be
|
|
|
|
+ * able to maintain this
|
|
|
|
+ * @spare/reserved: Unused data
|
|
|
|
+ * @cmd: Opal Command Buffer
|
|
|
|
+ * @rsp: OCC Response Buffer
|
|
|
|
+ */
|
|
|
|
+struct occ_dynamic_data {
|
|
|
|
+ u8 occ_state;
|
|
|
|
+ u8 major_version;
|
|
|
|
+ u8 minor_version;
|
|
|
|
+ u8 gpus_present;
|
|
|
|
+ union __packed {
|
|
|
|
+ struct __packed { /* Version 0x90 */
|
|
|
|
+ u8 spare1;
|
|
|
|
+ } v9;
|
|
|
|
+ struct __packed { /* Version 0xA0 */
|
|
|
|
+ u8 wof_enabled;
|
|
|
|
+ } v10;
|
|
|
|
+ };
|
|
|
|
+ u8 cpu_throttle;
|
|
|
|
+ u8 mem_throttle;
|
|
|
|
+ u8 quick_pwr_drop;
|
|
|
|
+ u8 pwr_shifting_ratio;
|
|
|
|
+ u8 pwr_cap_type;
|
|
|
|
+ __be16 hard_min_pwr_cap;
|
|
|
|
+ __be16 max_pwr_cap;
|
|
|
|
+ __be16 cur_pwr_cap;
|
|
|
|
+ __be16 soft_min_pwr_cap;
|
|
|
|
+ u8 pad[110];
|
|
|
|
+ struct opal_command_buffer cmd;
|
|
|
|
+ struct occ_response_buffer rsp;
|
|
|
|
+} __packed;
|
|
|
|
+
|
|
|
|
+enum occ_response_status {
|
|
|
|
+ OCC_RSP_SUCCESS = 0x00,
|
|
|
|
+ OCC_RSP_INVALID_COMMAND = 0x11,
|
|
|
|
+ OCC_RSP_INVALID_CMD_DATA_LENGTH = 0x12,
|
|
|
|
+ OCC_RSP_INVALID_DATA = 0x13,
|
|
|
|
+ OCC_RSP_INTERNAL_ERROR = 0x15,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define OCC_ROLE_SLAVE 0x00
|
|
|
|
+#define OCC_ROLE_MASTER 0x01
|
|
|
|
+
|
|
|
|
+#define OCC_FLAG_RSP_READY 0x01
|
|
|
|
+#define OCC_FLAG_CMD_IN_PROGRESS 0x02
|
|
|
|
+#define OPAL_FLAG_CMD_READY 0x80
|
|
|
|
+
|
|
|
|
+#define PCAP_MAX_POWER_W 100
|
|
|
|
+#define PCAP_SOFT_MIN_POWER_W 20
|
|
|
|
+#define PCAP_HARD_MIN_POWER_W 10
|
|
|
|
+
|
|
|
|
+static bool occ_write_static_data(PnvOCC *occ,
|
|
|
|
+ struct occ_pstate_table *static_data,
|
|
|
|
+ Error **errp)
|
|
|
|
+{
|
|
|
|
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
|
|
|
+ PnvHomer *homer = occ->homer;
|
|
|
|
+ hwaddr static_addr = homer->base + poc->opal_shared_memory_offset;
|
|
|
|
+ MemTxResult ret;
|
|
|
|
+
|
|
|
|
+ ret = address_space_write(&address_space_memory, static_addr,
|
|
|
|
+ MEMTXATTRS_UNSPECIFIED, static_data,
|
|
|
|
+ sizeof(*static_data));
|
|
|
|
+ if (ret != MEMTX_OK) {
|
|
|
|
+ error_setg(errp, "OCC: cannot write OCC-OPAL static data");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool occ_write_dynamic_data(PnvOCC *occ,
|
|
|
|
+ struct occ_dynamic_data *dynamic_data,
|
|
|
|
+ Error **errp)
|
|
|
|
+{
|
|
|
|
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
|
|
|
+ PnvHomer *homer = occ->homer;
|
|
|
|
+ hwaddr static_addr = homer->base + poc->opal_shared_memory_offset;
|
|
|
|
+ hwaddr dynamic_addr = static_addr + OPAL_DYNAMIC_DATA_OFFSET;
|
|
|
|
+ MemTxResult ret;
|
|
|
|
+
|
|
|
|
+ ret = address_space_write(&address_space_memory, dynamic_addr,
|
|
|
|
+ MEMTXATTRS_UNSPECIFIED, dynamic_data,
|
|
|
|
+ sizeof(*dynamic_data));
|
|
|
|
+ if (ret != MEMTX_OK) {
|
|
|
|
+ error_setg(errp, "OCC: cannot write OCC-OPAL dynamic data");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool occ_init_homer_memory(PnvOCC *occ, Error **errp)
|
|
|
|
+{
|
|
|
|
+ PnvOCCClass *poc = PNV_OCC_GET_CLASS(occ);
|
|
|
|
+ PnvHomer *homer = occ->homer;
|
|
|
|
+ PnvChip *chip = homer->chip;
|
|
|
|
+ struct occ_pstate_table static_data;
|
|
|
|
+ struct occ_dynamic_data dynamic_data;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ memset(&static_data, 0, sizeof(static_data));
|
|
|
|
+ static_data.valid = 1;
|
|
|
|
+ static_data.version = poc->opal_shared_memory_version;
|
|
|
|
+ switch (poc->opal_shared_memory_version) {
|
|
|
|
+ case 0x02:
|
|
|
|
+ static_data.v2.throttle = 0;
|
|
|
|
+ static_data.v2.pstate_min = -2;
|
|
|
|
+ static_data.v2.pstate_nom = -1;
|
|
|
|
+ static_data.v2.pstate_turbo = -1;
|
|
|
|
+ static_data.v2.pstate_ultra_turbo = 0;
|
|
|
|
+ static_data.v2.pstates[0].id = 0;
|
|
|
|
+ static_data.v2.pstates[1].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ static_data.v2.pstates[1].id = -1;
|
|
|
|
+ static_data.v2.pstates[1].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ static_data.v2.pstates[2].id = -2;
|
|
|
|
+ static_data.v2.pstates[2].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ for (i = 0; i < chip->nr_cores; i++) {
|
|
|
|
+ static_data.v2.core_max[i] = 1;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case 0x90:
|
|
|
|
+ if (chip->chip_id == 0) {
|
|
|
|
+ static_data.v9.occ_role = OCC_ROLE_MASTER;
|
|
|
|
+ } else {
|
|
|
|
+ static_data.v9.occ_role = OCC_ROLE_SLAVE;
|
|
|
|
+ }
|
|
|
|
+ static_data.v9.pstate_min = 2;
|
|
|
|
+ static_data.v9.pstate_nom = 1;
|
|
|
|
+ static_data.v9.pstate_turbo = 1;
|
|
|
|
+ static_data.v9.pstate_ultra_turbo = 0;
|
|
|
|
+ static_data.v9.pstates[0].id = 0;
|
|
|
|
+ static_data.v9.pstates[0].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ static_data.v9.pstates[1].id = 1;
|
|
|
|
+ static_data.v9.pstates[1].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ static_data.v9.pstates[2].id = 2;
|
|
|
|
+ static_data.v9.pstates[2].freq_khz = cpu_to_be32(3000);
|
|
|
|
+ for (i = 0; i < chip->nr_cores; i++) {
|
|
|
|
+ static_data.v9.core_max[i] = 1;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ g_assert_not_reached();
|
|
|
|
+ }
|
|
|
|
+ if (!occ_write_static_data(occ, &static_data, errp)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memset(&dynamic_data, 0, sizeof(dynamic_data));
|
|
|
|
+ dynamic_data.occ_state = 0x3; /* active */
|
|
|
|
+ dynamic_data.major_version = 0x0;
|
|
|
|
+ dynamic_data.hard_min_pwr_cap = cpu_to_be16(PCAP_HARD_MIN_POWER_W);
|
|
|
|
+ dynamic_data.max_pwr_cap = cpu_to_be16(PCAP_MAX_POWER_W);
|
|
|
|
+ dynamic_data.cur_pwr_cap = cpu_to_be16(PCAP_MAX_POWER_W);
|
|
|
|
+ dynamic_data.soft_min_pwr_cap = cpu_to_be16(PCAP_SOFT_MIN_POWER_W);
|
|
|
|
+ switch (poc->opal_shared_memory_version) {
|
|
|
|
+ case 0x90:
|
|
|
|
+ dynamic_data.minor_version = 0x1;
|
|
|
|
+ break;
|
|
|
|
+ case 0x02:
|
|
|
|
+ dynamic_data.minor_version = 0x0;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ g_assert_not_reached();
|
|
|
|
+ }
|
|
|
|
+ if (!occ_write_dynamic_data(occ, &dynamic_data, errp)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|