@@ -2251,6 +2251,107 @@ int of_genpd_parse_idle_states(struct device_node *dn,
}
EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
+/* Power domain performance state management helpers */
+static const struct of_device_id performance_state_match[] = {
+ { .compatible = "domain-performance-state", },
+ { }
+};
+
+static int genpd_parse_performance_state(struct genpd_performance_state *state,
+ struct device_node *np)
+{
+ int ret;
+
+ ret = of_property_read_u32(np, "reg", &state->performance_state);
+ if (ret) {
+ pr_err(" * %s missing reg property\n", np->full_name);
+ return ret;
+ }
+
+ ret = of_property_read_variable_u32_array(np, "domain-microvolt",
+ &state->u_volt, 1, 3);
+ if (ret >= 0)
+ return 0;
+
+ /* Property not found */
+ if (ret == -EINVAL)
+ return 0;
+
+ pr_err(" * %s Invalid domain-microvolt property\n", np->full_name);
+ return ret;
+}
+
+/**
+ * of_genpd_parse_performance_states: Return array of performance states for the
+ * genpd.
+ *
+ * @dn: The genpd device node
+ * @states: The pointer to which the state array will be saved.
+ * @n: The count of elements in the array returned from this function.
+ *
+ * Returns the device performance states parsed from the OF node. The memory for
+ * the states is allocated by this function and is the responsibility of the
+ * caller to free the memory after use.
+ */
+int of_genpd_parse_performance_states(struct device_node *dn,
+ struct genpd_performance_state **states, int *n)
+{
+ struct genpd_performance_state *st;
+ struct device_node *perf_np, *np;
+ int i = 0, ret, count;
+
+ perf_np = of_get_child_by_name(dn, "performance-states");
+ if (!perf_np) {
+ pr_err("performance-states node not found in %s node\n",
+ dn->full_name);
+ return -ENODEV;
+ }
+
+ if (!of_match_node(performance_state_match, perf_np)) {
+ pr_err("performance-states node found in %s node isn't compatible\n",
+ dn->full_name);
+ ret = -EINVAL;
+ goto put_node;
+ }
+
+ count = of_get_child_count(perf_np);
+ if (count <= 0) {
+ pr_err("performance-states node found in %s node doesn't have any child nodes\n",
+ dn->full_name);
+ ret = -EINVAL;
+ goto put_node;
+ }
+
+ st = kcalloc(count, sizeof(*st), GFP_KERNEL);
+ if (!st) {
+ ret = -ENOMEM;
+ goto put_node;
+ }
+
+ for_each_available_child_of_node(perf_np, np) {
+ ret = genpd_parse_performance_state(&st[i++], np);
+ if (ret) {
+ pr_err("Parsing of performance state node %s failed with err %d\n",
+ np->full_name, ret);
+ goto free_st;
+ }
+ }
+
+ of_node_put(perf_np);
+ *n = count;
+ *states = st;
+
+ return 0;
+
+free_st:
+ kfree(st);
+put_node:
+ of_node_put(perf_np);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_genpd_parse_performance_states);
+
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
@@ -44,6 +44,13 @@ struct genpd_power_state {
struct fwnode_handle *fwnode;
};
+struct genpd_performance_state {
+ unsigned int performance_state;
+ unsigned int u_volt;
+ unsigned int u_volt_min;
+ unsigned int u_volt_max;
+};
+
struct genpd_lock_ops;
struct generic_pm_domain {
@@ -226,6 +233,8 @@ extern int of_genpd_add_subdomain(struct of_phandle_args *parent,
extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
extern int of_genpd_parse_idle_states(struct device_node *dn,
struct genpd_power_state **states, int *n);
+extern int of_genpd_parse_performance_states(struct device_node *dn,
+ struct genpd_performance_state **states, int *n);
int genpd_dev_pm_attach(struct device *dev);
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
@@ -261,6 +270,12 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,
return -ENODEV;
}
+static inline int of_genpd_parse_performance_states(struct device_node *dn,
+ struct genpd_performance_state **states, int *n)
+{
+ return -ENODEV;
+}
+
static inline int genpd_dev_pm_attach(struct device *dev)
{
return -ENODEV;