+ * Currently only SLPC action status in GuC is meaningful as Host
+ * can query only overridden parameters and that are fetched from
+ * Host-GuC SLPC shared data.
+ */
+ if (output && !ret) {
+ output[0] = header.value = I915_READ(SOFT_SCRATCH(1));
+ ret = header.status;
+ }
+
intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains);
mutex_unlock(&guc->send_mutex);
return ret;
}
+int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action,
u32 len)
+{
+ return __intel_guc_send_mmio(guc, action, len, NULL);
+}
+
int intel_guc_sample_forcewake(struct intel_guc *guc)
{
struct drm_i915_private *dev_priv = guc_to_i915(guc);
diff --git a/drivers/gpu/drm/i915/intel_guc.h
b/drivers/gpu/drm/i915/intel_guc.h
index b835d30..c27d2dd 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -132,6 +132,8 @@ struct intel_guc {
int intel_guc_send_nop(struct intel_guc *guc, const u32 *action, u32
len);
void gen8_guc_raise_irq(struct intel_guc *guc);
void intel_guc_init_send_regs(struct intel_guc *guc);
+int __intel_guc_send_mmio(struct intel_guc *guc, const u32 *action,
u32 len,
+ u32 *output);
int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action,
u32 len);
int intel_guc_sample_forcewake(struct intel_guc *guc);
int intel_guc_runtime_suspend(struct intel_guc *guc);
diff --git a/drivers/gpu/drm/i915/intel_slpc.c
b/drivers/gpu/drm/i915/intel_slpc.c
index 73e7bf5..f47d81e 100644
--- a/drivers/gpu/drm/i915/intel_slpc.c
+++ b/drivers/gpu/drm/i915/intel_slpc.c
@@ -132,6 +132,191 @@ int slpc_mem_task_control(struct
slpc_shared_data *data, u64 val,
return ret;
}
+static void host2guc_slpc(struct intel_slpc *slpc,
+ struct slpc_event_input *input, u32 len)
+{
+ struct intel_guc *guc = slpc_to_guc(slpc);
+ u32 *data;
+ u32 output[SLPC_EVENT_MAX_OUTPUT_ARGS];
+ int ret = 0;
+
+ /*
+ * We have only 15 scratch registers for communication.
+ * the first we will use for the event ID in input and
+ * output data. Event processing status will be present
+ * in SOFT_SCRATCH(1) register.
+ */
+ BUILD_BUG_ON(SLPC_EVENT_MAX_INPUT_ARGS > 14);
+ BUILD_BUG_ON(SLPC_EVENT_MAX_OUTPUT_ARGS < 1);
+ BUILD_BUG_ON(SLPC_EVENT_MAX_OUTPUT_ARGS > 14);
+
+ data = (u32 *) input;
+ data[0] = INTEL_GUC_ACTION_SLPC_REQUEST;
+ ret = __intel_guc_send_mmio(guc, data, len, output);
+
+ if (ret)
+ DRM_ERROR("event 0x%x status %d\n",
+ ((output[0] & 0xFF00) >> 8), ret);
+}
+
+static void host2guc_slpc_set_param(struct intel_slpc *slpc,
+ u32 id, u32 value)
+{
+ struct slpc_event_input data = {0};
+
+ data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_SET, 2);
+ data.args[0] = id;
+ data.args[1] = value;
+
+ host2guc_slpc(slpc, &data, 4);
+}
+
+static void host2guc_slpc_unset_param(struct intel_slpc *slpc,
+ u32 id)
+{
+ struct slpc_event_input data = {0};
+
+ data.header.value = SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1);
+ data.args[0] = id;
+
+ host2guc_slpc(slpc, &data, 3);
+}
+
+void intel_slpc_set_param(struct intel_slpc *slpc,
+ u32 id,
+ u32 value)
+{
+ struct page *page;
+ struct slpc_shared_data *data = NULL;
+
+ WARN_ON(id >= SLPC_MAX_PARAM);
+
+ if (!slpc->vma)
+ return;
+
+ page = i915_vma_first_page(slpc->vma);
+ data = kmap_atomic(page);
+ slpc_mem_set_param(data, id, value);
+ kunmap_atomic(data);
+
+ host2guc_slpc_set_param(slpc, id, value);
+}
+
+void intel_slpc_unset_param(struct intel_slpc *slpc,
+ u32 id)
+{
+ struct page *page;
+ struct slpc_shared_data *data = NULL;
+
+ WARN_ON(id >= SLPC_MAX_PARAM);
+
+ if (!slpc->vma)
+ return;
+
+ page = i915_vma_first_page(slpc->vma);
+ data = kmap_atomic(page);
+ slpc_mem_unset_param(data, id);
+ kunmap_atomic(data);
+
+ host2guc_slpc_unset_param(slpc, id);
+}
+
+void intel_slpc_get_param(struct intel_slpc *slpc,
+ u32 id,
+ int *overriding, u32 *value)
+{
+ struct page *page;
+ struct slpc_shared_data *data = NULL;
+ u32 bits;
+
+ WARN_ON(id >= SLPC_MAX_PARAM);
+
+ if (!slpc->vma)
+ return;
+
+ page = i915_vma_first_page(slpc->vma);
+ data = kmap_atomic(page);
+ if (overriding) {
+ bits = data->override_parameters_set_bits[id >> 5];
+ *overriding = (0 != (bits & (1 << (id % 32))));
+ }
+ if (value)
+ *value = data->override_parameters_values[id];
+
+ kunmap_atomic(data);
+}
+
+int intel_slpc_task_control(struct intel_slpc *slpc, u64 val,
+ u32 enable_id, u32 disable_id)
+{
+ struct drm_i915_private *dev_priv = slpc_to_i915(slpc);
+ int ret = 0;
+
+ if (!slpc->active)
+ return -ENODEV;
+
+ intel_runtime_pm_get(dev_priv);
+
+ if (val == SLPC_PARAM_TASK_DEFAULT) {
+ /* set default */
+ intel_slpc_unset_param(slpc, enable_id);
+ intel_slpc_unset_param(slpc, disable_id);
+ } else if (val == SLPC_PARAM_TASK_ENABLED) {
+ /* set enable */
+ intel_slpc_set_param(slpc, enable_id, 1);
+ intel_slpc_unset_param(slpc, disable_id);
+ } else if (val == SLPC_PARAM_TASK_DISABLED) {
+ /* set disable */
+ intel_slpc_set_param(slpc, disable_id, 1);
+ intel_slpc_unset_param(slpc, enable_id);
+ } else {
+ ret = -EINVAL;
+ }
+
+ intel_slpc_enable(slpc);
+ intel_runtime_pm_put(dev_priv);
+
+ return ret;
+}
+
+int intel_slpc_task_status(struct intel_slpc *slpc, u64 *val,
+ u32 enable_id, u32 disable_id)
+{
+ int override_enable, override_disable;
+ u32 value_enable, value_disable;
+ int ret = 0;
+
+ if (!slpc->active) {
+ ret = -ENODEV;
+ } else if (val) {
+ intel_slpc_get_param(slpc, enable_id, &override_enable,
+ &value_enable);
+ intel_slpc_get_param(slpc, disable_id, &override_disable,
+ &value_disable);
+
+ /*
+ * Set the output value:
+ * 0: default
+ * 1: enabled
+ * 2: disabled
+ * 3: unknown (should not happen)
+ */
+ if (override_disable && (value_disable == 1))
+ *val = SLPC_PARAM_TASK_DISABLED;
+ else if (override_enable && (value_enable == 1))
+ *val = SLPC_PARAM_TASK_ENABLED;
+ else if (!override_enable && !override_disable)
+ *val = SLPC_PARAM_TASK_DEFAULT;
+ else
+ *val = SLPC_PARAM_TASK_UNKNOWN;
+
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static void slpc_shared_data_init(struct intel_slpc *slpc)
{
struct drm_i915_private *dev_priv = slpc_to_i915(slpc);
diff --git a/drivers/gpu/drm/i915/intel_slpc.h
b/drivers/gpu/drm/i915/intel_slpc.h
index 9312b2f..0ff17f0 100644
--- a/drivers/gpu/drm/i915/intel_slpc.h
+++ b/drivers/gpu/drm/i915/intel_slpc.h
@@ -247,6 +247,14 @@ struct slpc_param {
#define SLPC_PARAM_TASK_UNKNOWN 3
/* intel_slpc.c */
+void intel_slpc_set_param(struct intel_slpc *slpc, u32 id, u32 value);
+void intel_slpc_unset_param(struct intel_slpc *slpc, u32 id);
+void intel_slpc_get_param(struct intel_slpc *slpc, u32 id,
+ int *overriding, u32 *value);
+int intel_slpc_task_control(struct intel_slpc *slpc, u64 val,
+ u32 enable_id, u32 disable_id);
+int intel_slpc_task_status(struct intel_slpc *slpc, u64 *val,
+ u32 enable_id, u32 disable_id);
void intel_slpc_init(struct intel_slpc *slpc);
void intel_slpc_cleanup(struct intel_slpc *slpc);
void intel_slpc_enable(struct intel_slpc *slpc);