diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-06-04 04:40:41 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-06-04 04:40:41 -0400 |
commit | d9fecca2efea004c617e01b9eb7a36ef407e7b28 (patch) | |
tree | 6581aa6dce2733276278297ebf11fabcbf329e6d | |
parent | 5b550c92d704ad4b5f1081c62d515a137d1c4bd2 (diff) | |
parent | 96c1bf68852a1709bb411eafd3edcc59186eb293 (diff) |
Merge branch 'pm-opp'
* pm-opp: (24 commits)
PM / Domains: Drop unused parameter in genpd_allocate_dev_data()
PM / Domains: Drop genpd as in-param for pm_genpd_remove_device()
PM / Domains: Drop __pm_genpd_add_device()
PM / Domains: Drop extern declarations of functions in pm_domain.h
PM / domains: Add perf_state attribute to genpd debugfs
OPP: Allow same OPP table to be used for multiple genpd
PM / Domain: Return 0 on error from of_genpd_opp_to_performance_state()
PM / OPP: Fix shared OPP table support in dev_pm_opp_register_set_opp_helper()
PM / OPP: Fix shared OPP table support in dev_pm_opp_set_regulators()
PM / OPP: Fix shared OPP table support in dev_pm_opp_set_prop_name()
PM / OPP: Fix shared OPP table support in dev_pm_opp_set_supported_hw()
PM / OPP: silence an uninitialized variable warning
PM / OPP: Remove dev_pm_opp_{un}register_get_pstate_helper()
PM / OPP: Get performance state using genpd helper
PM / Domain: Implement of_genpd_opp_to_performance_state()
PM / Domain: Add support to parse domain's OPP table
PM / Domain: Add struct device to genpd
PM / OPP: Implement dev_pm_opp_get_of_node()
PM / OPP: Implement of_dev_pm_opp_find_required_opp()
PM / OPP: Implement dev_pm_opp_of_add_table_indexed()
...
-rw-r--r-- | Documentation/devicetree/bindings/opp/opp.txt | 7 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/power/power_domain.txt | 6 | ||||
-rw-r--r-- | drivers/base/power/domain.c | 167 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 | ||||
-rw-r--r-- | drivers/opp/core.c | 267 | ||||
-rw-r--r-- | drivers/opp/debugfs.c | 15 | ||||
-rw-r--r-- | drivers/opp/of.c | 184 | ||||
-rw-r--r-- | drivers/opp/opp.h | 6 | ||||
-rw-r--r-- | drivers/soc/tegra/pmc.c | 20 | ||||
-rw-r--r-- | include/linux/pm_domain.h | 75 | ||||
-rw-r--r-- | include/linux/pm_opp.h | 27 |
11 files changed, 476 insertions, 300 deletions
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt index 4e4f30288c8b..c396c4c0af92 100644 --- a/Documentation/devicetree/bindings/opp/opp.txt +++ b/Documentation/devicetree/bindings/opp/opp.txt | |||
@@ -82,7 +82,10 @@ This defines voltage-current-frequency combinations along with other related | |||
82 | properties. | 82 | properties. |
83 | 83 | ||
84 | Required properties: | 84 | Required properties: |
85 | - opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. | 85 | - opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. This is a |
86 | required property for all device nodes but devices like power domains. The | ||
87 | power domain nodes must have another (implementation dependent) property which | ||
88 | uniquely identifies the OPP nodes. | ||
86 | 89 | ||
87 | Optional properties: | 90 | Optional properties: |
88 | - opp-microvolt: voltage in micro Volts. | 91 | - opp-microvolt: voltage in micro Volts. |
@@ -159,7 +162,7 @@ Optional properties: | |||
159 | 162 | ||
160 | - status: Marks the node enabled/disabled. | 163 | - status: Marks the node enabled/disabled. |
161 | 164 | ||
162 | - required-opp: This contains phandle to an OPP node in another device's OPP | 165 | - required-opps: This contains phandle to an OPP node in another device's OPP |
163 | table. It may contain an array of phandles, where each phandle points to an | 166 | table. It may contain an array of phandles, where each phandle points to an |
164 | OPP of a different device. It should not contain multiple phandles to the OPP | 167 | OPP of a different device. It should not contain multiple phandles to the OPP |
165 | nodes in the same OPP table. This specifies the minimum required OPP of the | 168 | nodes in the same OPP table. This specifies the minimum required OPP of the |
diff --git a/Documentation/devicetree/bindings/power/power_domain.txt b/Documentation/devicetree/bindings/power/power_domain.txt index f3355313c020..4733f76cbe48 100644 --- a/Documentation/devicetree/bindings/power/power_domain.txt +++ b/Documentation/devicetree/bindings/power/power_domain.txt | |||
@@ -127,7 +127,7 @@ inside a PM domain with index 0 of a power controller represented by a node | |||
127 | with the label "power". | 127 | with the label "power". |
128 | 128 | ||
129 | Optional properties: | 129 | Optional properties: |
130 | - required-opp: This contains phandle to an OPP node in another device's OPP | 130 | - required-opps: This contains phandle to an OPP node in another device's OPP |
131 | table. It may contain an array of phandles, where each phandle points to an | 131 | table. It may contain an array of phandles, where each phandle points to an |
132 | OPP of a different device. It should not contain multiple phandles to the OPP | 132 | OPP of a different device. It should not contain multiple phandles to the OPP |
133 | nodes in the same OPP table. This specifies the minimum required OPP of the | 133 | nodes in the same OPP table. This specifies the minimum required OPP of the |
@@ -175,14 +175,14 @@ Example: | |||
175 | compatible = "foo,i-leak-current"; | 175 | compatible = "foo,i-leak-current"; |
176 | reg = <0x12350000 0x1000>; | 176 | reg = <0x12350000 0x1000>; |
177 | power-domains = <&power 0>; | 177 | power-domains = <&power 0>; |
178 | required-opp = <&domain0_opp_0>; | 178 | required-opps = <&domain0_opp_0>; |
179 | }; | 179 | }; |
180 | 180 | ||
181 | leaky-device1@12350000 { | 181 | leaky-device1@12350000 { |
182 | compatible = "foo,i-leak-current"; | 182 | compatible = "foo,i-leak-current"; |
183 | reg = <0x12350000 0x1000>; | 183 | reg = <0x12350000 0x1000>; |
184 | power-domains = <&power 1>; | 184 | power-domains = <&power 1>; |
185 | required-opp = <&domain1_opp_1>; | 185 | required-opps = <&domain1_opp_1>; |
186 | }; | 186 | }; |
187 | 187 | ||
188 | [1]. Documentation/devicetree/bindings/power/domain-idle-state.txt | 188 | [1]. Documentation/devicetree/bindings/power/domain-idle-state.txt |
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 455ecea6c812..6f403d6fccb2 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/io.h> | 11 | #include <linux/io.h> |
12 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
13 | #include <linux/pm_opp.h> | ||
13 | #include <linux/pm_runtime.h> | 14 | #include <linux/pm_runtime.h> |
14 | #include <linux/pm_domain.h> | 15 | #include <linux/pm_domain.h> |
15 | #include <linux/pm_qos.h> | 16 | #include <linux/pm_qos.h> |
@@ -1315,7 +1316,6 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); | |||
1315 | #endif /* CONFIG_PM_SLEEP */ | 1316 | #endif /* CONFIG_PM_SLEEP */ |
1316 | 1317 | ||
1317 | static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, | 1318 | static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, |
1318 | struct generic_pm_domain *genpd, | ||
1319 | struct gpd_timing_data *td) | 1319 | struct gpd_timing_data *td) |
1320 | { | 1320 | { |
1321 | struct generic_pm_domain_data *gpd_data; | 1321 | struct generic_pm_domain_data *gpd_data; |
@@ -1384,7 +1384,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1384 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) | 1384 | if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)) |
1385 | return -EINVAL; | 1385 | return -EINVAL; |
1386 | 1386 | ||
1387 | gpd_data = genpd_alloc_dev_data(dev, genpd, td); | 1387 | gpd_data = genpd_alloc_dev_data(dev, td); |
1388 | if (IS_ERR(gpd_data)) | 1388 | if (IS_ERR(gpd_data)) |
1389 | return PTR_ERR(gpd_data); | 1389 | return PTR_ERR(gpd_data); |
1390 | 1390 | ||
@@ -1413,23 +1413,21 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | |||
1413 | } | 1413 | } |
1414 | 1414 | ||
1415 | /** | 1415 | /** |
1416 | * __pm_genpd_add_device - Add a device to an I/O PM domain. | 1416 | * pm_genpd_add_device - Add a device to an I/O PM domain. |
1417 | * @genpd: PM domain to add the device to. | 1417 | * @genpd: PM domain to add the device to. |
1418 | * @dev: Device to be added. | 1418 | * @dev: Device to be added. |
1419 | * @td: Set of PM QoS timing parameters to attach to the device. | ||
1420 | */ | 1419 | */ |
1421 | int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, | 1420 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) |
1422 | struct gpd_timing_data *td) | ||
1423 | { | 1421 | { |
1424 | int ret; | 1422 | int ret; |
1425 | 1423 | ||
1426 | mutex_lock(&gpd_list_lock); | 1424 | mutex_lock(&gpd_list_lock); |
1427 | ret = genpd_add_device(genpd, dev, td); | 1425 | ret = genpd_add_device(genpd, dev, NULL); |
1428 | mutex_unlock(&gpd_list_lock); | 1426 | mutex_unlock(&gpd_list_lock); |
1429 | 1427 | ||
1430 | return ret; | 1428 | return ret; |
1431 | } | 1429 | } |
1432 | EXPORT_SYMBOL_GPL(__pm_genpd_add_device); | 1430 | EXPORT_SYMBOL_GPL(pm_genpd_add_device); |
1433 | 1431 | ||
1434 | static int genpd_remove_device(struct generic_pm_domain *genpd, | 1432 | static int genpd_remove_device(struct generic_pm_domain *genpd, |
1435 | struct device *dev) | 1433 | struct device *dev) |
@@ -1476,13 +1474,13 @@ static int genpd_remove_device(struct generic_pm_domain *genpd, | |||
1476 | 1474 | ||
1477 | /** | 1475 | /** |
1478 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. | 1476 | * pm_genpd_remove_device - Remove a device from an I/O PM domain. |
1479 | * @genpd: PM domain to remove the device from. | ||
1480 | * @dev: Device to be removed. | 1477 | * @dev: Device to be removed. |
1481 | */ | 1478 | */ |
1482 | int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 1479 | int pm_genpd_remove_device(struct device *dev) |
1483 | struct device *dev) | ||
1484 | { | 1480 | { |
1485 | if (!genpd || genpd != genpd_lookup_dev(dev)) | 1481 | struct generic_pm_domain *genpd = genpd_lookup_dev(dev); |
1482 | |||
1483 | if (!genpd) | ||
1486 | return -EINVAL; | 1484 | return -EINVAL; |
1487 | 1485 | ||
1488 | return genpd_remove_device(genpd, dev); | 1486 | return genpd_remove_device(genpd, dev); |
@@ -1691,6 +1689,9 @@ int pm_genpd_init(struct generic_pm_domain *genpd, | |||
1691 | return ret; | 1689 | return ret; |
1692 | } | 1690 | } |
1693 | 1691 | ||
1692 | device_initialize(&genpd->dev); | ||
1693 | dev_set_name(&genpd->dev, "%s", genpd->name); | ||
1694 | |||
1694 | mutex_lock(&gpd_list_lock); | 1695 | mutex_lock(&gpd_list_lock); |
1695 | list_add(&genpd->gpd_list_node, &gpd_list); | 1696 | list_add(&genpd->gpd_list_node, &gpd_list); |
1696 | mutex_unlock(&gpd_list_lock); | 1697 | mutex_unlock(&gpd_list_lock); |
@@ -1887,14 +1888,33 @@ int of_genpd_add_provider_simple(struct device_node *np, | |||
1887 | 1888 | ||
1888 | mutex_lock(&gpd_list_lock); | 1889 | mutex_lock(&gpd_list_lock); |
1889 | 1890 | ||
1890 | if (genpd_present(genpd)) { | 1891 | if (!genpd_present(genpd)) |
1891 | ret = genpd_add_provider(np, genpd_xlate_simple, genpd); | 1892 | goto unlock; |
1892 | if (!ret) { | 1893 | |
1893 | genpd->provider = &np->fwnode; | 1894 | genpd->dev.of_node = np; |
1894 | genpd->has_provider = true; | 1895 | |
1896 | /* Parse genpd OPP table */ | ||
1897 | if (genpd->set_performance_state) { | ||
1898 | ret = dev_pm_opp_of_add_table(&genpd->dev); | ||
1899 | if (ret) { | ||
1900 | dev_err(&genpd->dev, "Failed to add OPP table: %d\n", | ||
1901 | ret); | ||
1902 | goto unlock; | ||
1895 | } | 1903 | } |
1896 | } | 1904 | } |
1897 | 1905 | ||
1906 | ret = genpd_add_provider(np, genpd_xlate_simple, genpd); | ||
1907 | if (ret) { | ||
1908 | if (genpd->set_performance_state) | ||
1909 | dev_pm_opp_of_remove_table(&genpd->dev); | ||
1910 | |||
1911 | goto unlock; | ||
1912 | } | ||
1913 | |||
1914 | genpd->provider = &np->fwnode; | ||
1915 | genpd->has_provider = true; | ||
1916 | |||
1917 | unlock: | ||
1898 | mutex_unlock(&gpd_list_lock); | 1918 | mutex_unlock(&gpd_list_lock); |
1899 | 1919 | ||
1900 | return ret; | 1920 | return ret; |
@@ -1909,6 +1929,7 @@ EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple); | |||
1909 | int of_genpd_add_provider_onecell(struct device_node *np, | 1929 | int of_genpd_add_provider_onecell(struct device_node *np, |
1910 | struct genpd_onecell_data *data) | 1930 | struct genpd_onecell_data *data) |
1911 | { | 1931 | { |
1932 | struct generic_pm_domain *genpd; | ||
1912 | unsigned int i; | 1933 | unsigned int i; |
1913 | int ret = -EINVAL; | 1934 | int ret = -EINVAL; |
1914 | 1935 | ||
@@ -1921,13 +1942,27 @@ int of_genpd_add_provider_onecell(struct device_node *np, | |||
1921 | data->xlate = genpd_xlate_onecell; | 1942 | data->xlate = genpd_xlate_onecell; |
1922 | 1943 | ||
1923 | for (i = 0; i < data->num_domains; i++) { | 1944 | for (i = 0; i < data->num_domains; i++) { |
1924 | if (!data->domains[i]) | 1945 | genpd = data->domains[i]; |
1946 | |||
1947 | if (!genpd) | ||
1925 | continue; | 1948 | continue; |
1926 | if (!genpd_present(data->domains[i])) | 1949 | if (!genpd_present(genpd)) |
1927 | goto error; | 1950 | goto error; |
1928 | 1951 | ||
1929 | data->domains[i]->provider = &np->fwnode; | 1952 | genpd->dev.of_node = np; |
1930 | data->domains[i]->has_provider = true; | 1953 | |
1954 | /* Parse genpd OPP table */ | ||
1955 | if (genpd->set_performance_state) { | ||
1956 | ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i); | ||
1957 | if (ret) { | ||
1958 | dev_err(&genpd->dev, "Failed to add OPP table for index %d: %d\n", | ||
1959 | i, ret); | ||
1960 | goto error; | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | genpd->provider = &np->fwnode; | ||
1965 | genpd->has_provider = true; | ||
1931 | } | 1966 | } |
1932 | 1967 | ||
1933 | ret = genpd_add_provider(np, data->xlate, data); | 1968 | ret = genpd_add_provider(np, data->xlate, data); |
@@ -1940,10 +1975,16 @@ int of_genpd_add_provider_onecell(struct device_node *np, | |||
1940 | 1975 | ||
1941 | error: | 1976 | error: |
1942 | while (i--) { | 1977 | while (i--) { |
1943 | if (!data->domains[i]) | 1978 | genpd = data->domains[i]; |
1979 | |||
1980 | if (!genpd) | ||
1944 | continue; | 1981 | continue; |
1945 | data->domains[i]->provider = NULL; | 1982 | |
1946 | data->domains[i]->has_provider = false; | 1983 | genpd->provider = NULL; |
1984 | genpd->has_provider = false; | ||
1985 | |||
1986 | if (genpd->set_performance_state) | ||
1987 | dev_pm_opp_of_remove_table(&genpd->dev); | ||
1947 | } | 1988 | } |
1948 | 1989 | ||
1949 | mutex_unlock(&gpd_list_lock); | 1990 | mutex_unlock(&gpd_list_lock); |
@@ -1970,10 +2011,17 @@ void of_genpd_del_provider(struct device_node *np) | |||
1970 | * provider, set the 'has_provider' to false | 2011 | * provider, set the 'has_provider' to false |
1971 | * so that the PM domain can be safely removed. | 2012 | * so that the PM domain can be safely removed. |
1972 | */ | 2013 | */ |
1973 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) | 2014 | list_for_each_entry(gpd, &gpd_list, gpd_list_node) { |
1974 | if (gpd->provider == &np->fwnode) | 2015 | if (gpd->provider == &np->fwnode) { |
1975 | gpd->has_provider = false; | 2016 | gpd->has_provider = false; |
1976 | 2017 | ||
2018 | if (!gpd->set_performance_state) | ||
2019 | continue; | ||
2020 | |||
2021 | dev_pm_opp_of_remove_table(&gpd->dev); | ||
2022 | } | ||
2023 | } | ||
2024 | |||
1977 | list_del(&cp->link); | 2025 | list_del(&cp->link); |
1978 | of_node_put(cp->node); | 2026 | of_node_put(cp->node); |
1979 | kfree(cp); | 2027 | kfree(cp); |
@@ -2346,6 +2394,55 @@ int of_genpd_parse_idle_states(struct device_node *dn, | |||
2346 | } | 2394 | } |
2347 | EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states); | 2395 | EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states); |
2348 | 2396 | ||
2397 | /** | ||
2398 | * of_genpd_opp_to_performance_state- Gets performance state of device's | ||
2399 | * power domain corresponding to a DT node's "required-opps" property. | ||
2400 | * | ||
2401 | * @dev: Device for which the performance-state needs to be found. | ||
2402 | * @opp_node: DT node where the "required-opps" property is present. This can be | ||
2403 | * the device node itself (if it doesn't have an OPP table) or a node | ||
2404 | * within the OPP table of a device (if device has an OPP table). | ||
2405 | * @state: Pointer to return performance state. | ||
2406 | * | ||
2407 | * Returns performance state corresponding to the "required-opps" property of | ||
2408 | * a DT node. This calls platform specific genpd->opp_to_performance_state() | ||
2409 | * callback to translate power domain OPP to performance state. | ||
2410 | * | ||
2411 | * Returns performance state on success and 0 on failure. | ||
2412 | */ | ||
2413 | unsigned int of_genpd_opp_to_performance_state(struct device *dev, | ||
2414 | struct device_node *opp_node) | ||
2415 | { | ||
2416 | struct generic_pm_domain *genpd; | ||
2417 | struct dev_pm_opp *opp; | ||
2418 | int state = 0; | ||
2419 | |||
2420 | genpd = dev_to_genpd(dev); | ||
2421 | if (IS_ERR(genpd)) | ||
2422 | return 0; | ||
2423 | |||
2424 | if (unlikely(!genpd->set_performance_state)) | ||
2425 | return 0; | ||
2426 | |||
2427 | genpd_lock(genpd); | ||
2428 | |||
2429 | opp = of_dev_pm_opp_find_required_opp(&genpd->dev, opp_node); | ||
2430 | if (IS_ERR(opp)) { | ||
2431 | dev_err(dev, "Failed to find required OPP: %ld\n", | ||
2432 | PTR_ERR(opp)); | ||
2433 | goto unlock; | ||
2434 | } | ||
2435 | |||
2436 | state = genpd->opp_to_performance_state(genpd, opp); | ||
2437 | dev_pm_opp_put(opp); | ||
2438 | |||
2439 | unlock: | ||
2440 | genpd_unlock(genpd); | ||
2441 | |||
2442 | return state; | ||
2443 | } | ||
2444 | EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state); | ||
2445 | |||
2349 | #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ | 2446 | #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ |
2350 | 2447 | ||
2351 | 2448 | ||
@@ -2613,6 +2710,19 @@ static int genpd_devices_show(struct seq_file *s, void *data) | |||
2613 | return ret; | 2710 | return ret; |
2614 | } | 2711 | } |
2615 | 2712 | ||
2713 | static int genpd_perf_state_show(struct seq_file *s, void *data) | ||
2714 | { | ||
2715 | struct generic_pm_domain *genpd = s->private; | ||
2716 | |||
2717 | if (genpd_lock_interruptible(genpd)) | ||
2718 | return -ERESTARTSYS; | ||
2719 | |||
2720 | seq_printf(s, "%u\n", genpd->performance_state); | ||
2721 | |||
2722 | genpd_unlock(genpd); | ||
2723 | return 0; | ||
2724 | } | ||
2725 | |||
2616 | #define define_genpd_open_function(name) \ | 2726 | #define define_genpd_open_function(name) \ |
2617 | static int genpd_##name##_open(struct inode *inode, struct file *file) \ | 2727 | static int genpd_##name##_open(struct inode *inode, struct file *file) \ |
2618 | { \ | 2728 | { \ |
@@ -2626,6 +2736,7 @@ define_genpd_open_function(idle_states); | |||
2626 | define_genpd_open_function(active_time); | 2736 | define_genpd_open_function(active_time); |
2627 | define_genpd_open_function(total_idle_time); | 2737 | define_genpd_open_function(total_idle_time); |
2628 | define_genpd_open_function(devices); | 2738 | define_genpd_open_function(devices); |
2739 | define_genpd_open_function(perf_state); | ||
2629 | 2740 | ||
2630 | #define define_genpd_debugfs_fops(name) \ | 2741 | #define define_genpd_debugfs_fops(name) \ |
2631 | static const struct file_operations genpd_##name##_fops = { \ | 2742 | static const struct file_operations genpd_##name##_fops = { \ |
@@ -2642,6 +2753,7 @@ define_genpd_debugfs_fops(idle_states); | |||
2642 | define_genpd_debugfs_fops(active_time); | 2753 | define_genpd_debugfs_fops(active_time); |
2643 | define_genpd_debugfs_fops(total_idle_time); | 2754 | define_genpd_debugfs_fops(total_idle_time); |
2644 | define_genpd_debugfs_fops(devices); | 2755 | define_genpd_debugfs_fops(devices); |
2756 | define_genpd_debugfs_fops(perf_state); | ||
2645 | 2757 | ||
2646 | static int __init genpd_debug_init(void) | 2758 | static int __init genpd_debug_init(void) |
2647 | { | 2759 | { |
@@ -2675,6 +2787,9 @@ static int __init genpd_debug_init(void) | |||
2675 | d, genpd, &genpd_total_idle_time_fops); | 2787 | d, genpd, &genpd_total_idle_time_fops); |
2676 | debugfs_create_file("devices", 0444, | 2788 | debugfs_create_file("devices", 0444, |
2677 | d, genpd, &genpd_devices_fops); | 2789 | d, genpd, &genpd_devices_fops); |
2790 | if (genpd->set_performance_state) | ||
2791 | debugfs_create_file("perf_state", 0444, | ||
2792 | d, genpd, &genpd_perf_state_fops); | ||
2678 | } | 2793 | } |
2679 | 2794 | ||
2680 | return 0; | 2795 | return 0; |
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index a29362f9ef41..12558044acd4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | |||
@@ -513,7 +513,7 @@ static int acp_hw_fini(void *handle) | |||
513 | if (adev->acp.acp_genpd) { | 513 | if (adev->acp.acp_genpd) { |
514 | for (i = 0; i < ACP_DEVS ; i++) { | 514 | for (i = 0; i < ACP_DEVS ; i++) { |
515 | dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); | 515 | dev = get_mfd_cell_dev(adev->acp.acp_cell[i].name, i); |
516 | ret = pm_genpd_remove_device(&adev->acp.acp_genpd->gpd, dev); | 516 | ret = pm_genpd_remove_device(dev); |
517 | /* If removal fails, dont giveup and try rest */ | 517 | /* If removal fails, dont giveup and try rest */ |
518 | if (ret) | 518 | if (ret) |
519 | dev_err(dev, "remove dev from genpd failed\n"); | 519 | dev_err(dev, "remove dev from genpd failed\n"); |
diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 92fa94a6dcc1..ab2f3fead6b1 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c | |||
@@ -33,8 +33,6 @@ LIST_HEAD(opp_tables); | |||
33 | /* Lock to allow exclusive modification to the device and opp lists */ | 33 | /* Lock to allow exclusive modification to the device and opp lists */ |
34 | DEFINE_MUTEX(opp_table_lock); | 34 | DEFINE_MUTEX(opp_table_lock); |
35 | 35 | ||
36 | static void dev_pm_opp_get(struct dev_pm_opp *opp); | ||
37 | |||
38 | static struct opp_device *_find_opp_dev(const struct device *dev, | 36 | static struct opp_device *_find_opp_dev(const struct device *dev, |
39 | struct opp_table *opp_table) | 37 | struct opp_table *opp_table) |
40 | { | 38 | { |
@@ -281,6 +279,23 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev) | |||
281 | } | 279 | } |
282 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); | 280 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); |
283 | 281 | ||
282 | int _get_opp_count(struct opp_table *opp_table) | ||
283 | { | ||
284 | struct dev_pm_opp *opp; | ||
285 | int count = 0; | ||
286 | |||
287 | mutex_lock(&opp_table->lock); | ||
288 | |||
289 | list_for_each_entry(opp, &opp_table->opp_list, node) { | ||
290 | if (opp->available) | ||
291 | count++; | ||
292 | } | ||
293 | |||
294 | mutex_unlock(&opp_table->lock); | ||
295 | |||
296 | return count; | ||
297 | } | ||
298 | |||
284 | /** | 299 | /** |
285 | * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table | 300 | * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table |
286 | * @dev: device for which we do this operation | 301 | * @dev: device for which we do this operation |
@@ -291,25 +306,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); | |||
291 | int dev_pm_opp_get_opp_count(struct device *dev) | 306 | int dev_pm_opp_get_opp_count(struct device *dev) |
292 | { | 307 | { |
293 | struct opp_table *opp_table; | 308 | struct opp_table *opp_table; |
294 | struct dev_pm_opp *temp_opp; | 309 | int count; |
295 | int count = 0; | ||
296 | 310 | ||
297 | opp_table = _find_opp_table(dev); | 311 | opp_table = _find_opp_table(dev); |
298 | if (IS_ERR(opp_table)) { | 312 | if (IS_ERR(opp_table)) { |
299 | count = PTR_ERR(opp_table); | 313 | count = PTR_ERR(opp_table); |
300 | dev_dbg(dev, "%s: OPP table not found (%d)\n", | 314 | dev_dbg(dev, "%s: OPP table not found (%d)\n", |
301 | __func__, count); | 315 | __func__, count); |
302 | return count; | 316 | return 0; |
303 | } | ||
304 | |||
305 | mutex_lock(&opp_table->lock); | ||
306 | |||
307 | list_for_each_entry(temp_opp, &opp_table->opp_list, node) { | ||
308 | if (temp_opp->available) | ||
309 | count++; | ||
310 | } | 317 | } |
311 | 318 | ||
312 | mutex_unlock(&opp_table->lock); | 319 | count = _get_opp_count(opp_table); |
313 | dev_pm_opp_put_opp_table(opp_table); | 320 | dev_pm_opp_put_opp_table(opp_table); |
314 | 321 | ||
315 | return count; | 322 | return count; |
@@ -892,7 +899,7 @@ static void _opp_kref_release(struct kref *kref) | |||
892 | dev_pm_opp_put_opp_table(opp_table); | 899 | dev_pm_opp_put_opp_table(opp_table); |
893 | } | 900 | } |
894 | 901 | ||
895 | static void dev_pm_opp_get(struct dev_pm_opp *opp) | 902 | void dev_pm_opp_get(struct dev_pm_opp *opp) |
896 | { | 903 | { |
897 | kref_get(&opp->kref); | 904 | kref_get(&opp->kref); |
898 | } | 905 | } |
@@ -985,22 +992,11 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, | |||
985 | return true; | 992 | return true; |
986 | } | 993 | } |
987 | 994 | ||
988 | /* | 995 | static int _opp_is_duplicate(struct device *dev, struct dev_pm_opp *new_opp, |
989 | * Returns: | 996 | struct opp_table *opp_table, |
990 | * 0: On success. And appropriate error message for duplicate OPPs. | 997 | struct list_head **head) |
991 | * -EBUSY: For OPP with same freq/volt and is available. The callers of | ||
992 | * _opp_add() must return 0 if they receive -EBUSY from it. This is to make | ||
993 | * sure we don't print error messages unnecessarily if different parts of | ||
994 | * kernel try to initialize the OPP table. | ||
995 | * -EEXIST: For OPP with same freq but different volt or is unavailable. This | ||
996 | * should be considered an error by the callers of _opp_add(). | ||
997 | */ | ||
998 | int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | ||
999 | struct opp_table *opp_table) | ||
1000 | { | 998 | { |
1001 | struct dev_pm_opp *opp; | 999 | struct dev_pm_opp *opp; |
1002 | struct list_head *head; | ||
1003 | int ret; | ||
1004 | 1000 | ||
1005 | /* | 1001 | /* |
1006 | * Insert new OPP in order of increasing frequency and discard if | 1002 | * Insert new OPP in order of increasing frequency and discard if |
@@ -1010,17 +1006,14 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
1010 | * loop, don't replace it with head otherwise it will become an infinite | 1006 | * loop, don't replace it with head otherwise it will become an infinite |
1011 | * loop. | 1007 | * loop. |
1012 | */ | 1008 | */ |
1013 | mutex_lock(&opp_table->lock); | ||
1014 | head = &opp_table->opp_list; | ||
1015 | |||
1016 | list_for_each_entry(opp, &opp_table->opp_list, node) { | 1009 | list_for_each_entry(opp, &opp_table->opp_list, node) { |
1017 | if (new_opp->rate > opp->rate) { | 1010 | if (new_opp->rate > opp->rate) { |
1018 | head = &opp->node; | 1011 | *head = &opp->node; |
1019 | continue; | 1012 | continue; |
1020 | } | 1013 | } |
1021 | 1014 | ||
1022 | if (new_opp->rate < opp->rate) | 1015 | if (new_opp->rate < opp->rate) |
1023 | break; | 1016 | return 0; |
1024 | 1017 | ||
1025 | /* Duplicate OPPs */ | 1018 | /* Duplicate OPPs */ |
1026 | dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", | 1019 | dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", |
@@ -1029,15 +1022,39 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
1029 | new_opp->supplies[0].u_volt, new_opp->available); | 1022 | new_opp->supplies[0].u_volt, new_opp->available); |
1030 | 1023 | ||
1031 | /* Should we compare voltages for all regulators here ? */ | 1024 | /* Should we compare voltages for all regulators here ? */ |
1032 | ret = opp->available && | 1025 | return opp->available && |
1033 | new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; | 1026 | new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; |
1034 | |||
1035 | mutex_unlock(&opp_table->lock); | ||
1036 | return ret; | ||
1037 | } | 1027 | } |
1038 | 1028 | ||
1039 | if (opp_table->get_pstate) | 1029 | return 0; |
1040 | new_opp->pstate = opp_table->get_pstate(dev, new_opp->rate); | 1030 | } |
1031 | |||
1032 | /* | ||
1033 | * Returns: | ||
1034 | * 0: On success. And appropriate error message for duplicate OPPs. | ||
1035 | * -EBUSY: For OPP with same freq/volt and is available. The callers of | ||
1036 | * _opp_add() must return 0 if they receive -EBUSY from it. This is to make | ||
1037 | * sure we don't print error messages unnecessarily if different parts of | ||
1038 | * kernel try to initialize the OPP table. | ||
1039 | * -EEXIST: For OPP with same freq but different volt or is unavailable. This | ||
1040 | * should be considered an error by the callers of _opp_add(). | ||
1041 | */ | ||
1042 | int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | ||
1043 | struct opp_table *opp_table, bool rate_not_available) | ||
1044 | { | ||
1045 | struct list_head *head; | ||
1046 | int ret; | ||
1047 | |||
1048 | mutex_lock(&opp_table->lock); | ||
1049 | head = &opp_table->opp_list; | ||
1050 | |||
1051 | if (likely(!rate_not_available)) { | ||
1052 | ret = _opp_is_duplicate(dev, new_opp, opp_table, &head); | ||
1053 | if (ret) { | ||
1054 | mutex_unlock(&opp_table->lock); | ||
1055 | return ret; | ||
1056 | } | ||
1057 | } | ||
1041 | 1058 | ||
1042 | list_add(&new_opp->node, head); | 1059 | list_add(&new_opp->node, head); |
1043 | mutex_unlock(&opp_table->lock); | 1060 | mutex_unlock(&opp_table->lock); |
@@ -1104,7 +1121,7 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev, | |||
1104 | new_opp->available = true; | 1121 | new_opp->available = true; |
1105 | new_opp->dynamic = dynamic; | 1122 | new_opp->dynamic = dynamic; |
1106 | 1123 | ||
1107 | ret = _opp_add(dev, new_opp, opp_table); | 1124 | ret = _opp_add(dev, new_opp, opp_table, false); |
1108 | if (ret) { | 1125 | if (ret) { |
1109 | /* Don't return error for duplicate OPPs */ | 1126 | /* Don't return error for duplicate OPPs */ |
1110 | if (ret == -EBUSY) | 1127 | if (ret == -EBUSY) |
@@ -1140,7 +1157,6 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, | |||
1140 | const u32 *versions, unsigned int count) | 1157 | const u32 *versions, unsigned int count) |
1141 | { | 1158 | { |
1142 | struct opp_table *opp_table; | 1159 | struct opp_table *opp_table; |
1143 | int ret; | ||
1144 | 1160 | ||
1145 | opp_table = dev_pm_opp_get_opp_table(dev); | 1161 | opp_table = dev_pm_opp_get_opp_table(dev); |
1146 | if (!opp_table) | 1162 | if (!opp_table) |
@@ -1149,29 +1165,20 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, | |||
1149 | /* Make sure there are no concurrent readers while updating opp_table */ | 1165 | /* Make sure there are no concurrent readers while updating opp_table */ |
1150 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1166 | WARN_ON(!list_empty(&opp_table->opp_list)); |
1151 | 1167 | ||
1152 | /* Do we already have a version hierarchy associated with opp_table? */ | 1168 | /* Another CPU that shares the OPP table has set the property ? */ |
1153 | if (opp_table->supported_hw) { | 1169 | if (opp_table->supported_hw) |
1154 | dev_err(dev, "%s: Already have supported hardware list\n", | 1170 | return opp_table; |
1155 | __func__); | ||
1156 | ret = -EBUSY; | ||
1157 | goto err; | ||
1158 | } | ||
1159 | 1171 | ||
1160 | opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions), | 1172 | opp_table->supported_hw = kmemdup(versions, count * sizeof(*versions), |
1161 | GFP_KERNEL); | 1173 | GFP_KERNEL); |
1162 | if (!opp_table->supported_hw) { | 1174 | if (!opp_table->supported_hw) { |
1163 | ret = -ENOMEM; | 1175 | dev_pm_opp_put_opp_table(opp_table); |
1164 | goto err; | 1176 | return ERR_PTR(-ENOMEM); |
1165 | } | 1177 | } |
1166 | 1178 | ||
1167 | opp_table->supported_hw_count = count; | 1179 | opp_table->supported_hw_count = count; |
1168 | 1180 | ||
1169 | return opp_table; | 1181 | return opp_table; |
1170 | |||
1171 | err: | ||
1172 | dev_pm_opp_put_opp_table(opp_table); | ||
1173 | |||
1174 | return ERR_PTR(ret); | ||
1175 | } | 1182 | } |
1176 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); | 1183 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); |
1177 | 1184 | ||
@@ -1188,12 +1195,6 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) | |||
1188 | /* Make sure there are no concurrent readers while updating opp_table */ | 1195 | /* Make sure there are no concurrent readers while updating opp_table */ |
1189 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1196 | WARN_ON(!list_empty(&opp_table->opp_list)); |
1190 | 1197 | ||
1191 | if (!opp_table->supported_hw) { | ||
1192 | pr_err("%s: Doesn't have supported hardware list\n", | ||
1193 | __func__); | ||
1194 | return; | ||
1195 | } | ||
1196 | |||
1197 | kfree(opp_table->supported_hw); | 1198 | kfree(opp_table->supported_hw); |
1198 | opp_table->supported_hw = NULL; | 1199 | opp_table->supported_hw = NULL; |
1199 | opp_table->supported_hw_count = 0; | 1200 | opp_table->supported_hw_count = 0; |
@@ -1215,7 +1216,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); | |||
1215 | struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) | 1216 | struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) |
1216 | { | 1217 | { |
1217 | struct opp_table *opp_table; | 1218 | struct opp_table *opp_table; |
1218 | int ret; | ||
1219 | 1219 | ||
1220 | opp_table = dev_pm_opp_get_opp_table(dev); | 1220 | opp_table = dev_pm_opp_get_opp_table(dev); |
1221 | if (!opp_table) | 1221 | if (!opp_table) |
@@ -1224,26 +1224,17 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) | |||
1224 | /* Make sure there are no concurrent readers while updating opp_table */ | 1224 | /* Make sure there are no concurrent readers while updating opp_table */ |
1225 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1225 | WARN_ON(!list_empty(&opp_table->opp_list)); |
1226 | 1226 | ||
1227 | /* Do we already have a prop-name associated with opp_table? */ | 1227 | /* Another CPU that shares the OPP table has set the property ? */ |
1228 | if (opp_table->prop_name) { | 1228 | if (opp_table->prop_name) |
1229 | dev_err(dev, "%s: Already have prop-name %s\n", __func__, | 1229 | return opp_table; |
1230 | opp_table->prop_name); | ||
1231 | ret = -EBUSY; | ||
1232 | goto err; | ||
1233 | } | ||
1234 | 1230 | ||
1235 | opp_table->prop_name = kstrdup(name, GFP_KERNEL); | 1231 | opp_table->prop_name = kstrdup(name, GFP_KERNEL); |
1236 | if (!opp_table->prop_name) { | 1232 | if (!opp_table->prop_name) { |
1237 | ret = -ENOMEM; | 1233 | dev_pm_opp_put_opp_table(opp_table); |
1238 | goto err; | 1234 | return ERR_PTR(-ENOMEM); |
1239 | } | 1235 | } |
1240 | 1236 | ||
1241 | return opp_table; | 1237 | return opp_table; |
1242 | |||
1243 | err: | ||
1244 | dev_pm_opp_put_opp_table(opp_table); | ||
1245 | |||
1246 | return ERR_PTR(ret); | ||
1247 | } | 1238 | } |
1248 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); | 1239 | EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); |
1249 | 1240 | ||
@@ -1260,11 +1251,6 @@ void dev_pm_opp_put_prop_name(struct opp_table *opp_table) | |||
1260 | /* Make sure there are no concurrent readers while updating opp_table */ | 1251 | /* Make sure there are no concurrent readers while updating opp_table */ |
1261 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1252 | WARN_ON(!list_empty(&opp_table->opp_list)); |
1262 | 1253 | ||
1263 | if (!opp_table->prop_name) { | ||
1264 | pr_err("%s: Doesn't have a prop-name\n", __func__); | ||
1265 | return; | ||
1266 | } | ||
1267 | |||
1268 | kfree(opp_table->prop_name); | 1254 | kfree(opp_table->prop_name); |
1269 | opp_table->prop_name = NULL; | 1255 | opp_table->prop_name = NULL; |
1270 | 1256 | ||
@@ -1334,11 +1320,9 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, | |||
1334 | goto err; | 1320 | goto err; |
1335 | } | 1321 | } |
1336 | 1322 | ||
1337 | /* Already have regulators set */ | 1323 | /* Another CPU that shares the OPP table has set the regulators ? */ |
1338 | if (opp_table->regulators) { | 1324 | if (opp_table->regulators) |
1339 | ret = -EBUSY; | 1325 | return opp_table; |
1340 | goto err; | ||
1341 | } | ||
1342 | 1326 | ||
1343 | opp_table->regulators = kmalloc_array(count, | 1327 | opp_table->regulators = kmalloc_array(count, |
1344 | sizeof(*opp_table->regulators), | 1328 | sizeof(*opp_table->regulators), |
@@ -1392,10 +1376,8 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) | |||
1392 | { | 1376 | { |
1393 | int i; | 1377 | int i; |
1394 | 1378 | ||
1395 | if (!opp_table->regulators) { | 1379 | if (!opp_table->regulators) |
1396 | pr_err("%s: Doesn't have regulators set\n", __func__); | 1380 | goto put_opp_table; |
1397 | return; | ||
1398 | } | ||
1399 | 1381 | ||
1400 | /* Make sure there are no concurrent readers while updating opp_table */ | 1382 | /* Make sure there are no concurrent readers while updating opp_table */ |
1401 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1383 | WARN_ON(!list_empty(&opp_table->opp_list)); |
@@ -1409,6 +1391,7 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) | |||
1409 | opp_table->regulators = NULL; | 1391 | opp_table->regulators = NULL; |
1410 | opp_table->regulator_count = 0; | 1392 | opp_table->regulator_count = 0; |
1411 | 1393 | ||
1394 | put_opp_table: | ||
1412 | dev_pm_opp_put_opp_table(opp_table); | 1395 | dev_pm_opp_put_opp_table(opp_table); |
1413 | } | 1396 | } |
1414 | EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); | 1397 | EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); |
@@ -1494,7 +1477,6 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, | |||
1494 | int (*set_opp)(struct dev_pm_set_opp_data *data)) | 1477 | int (*set_opp)(struct dev_pm_set_opp_data *data)) |
1495 | { | 1478 | { |
1496 | struct opp_table *opp_table; | 1479 | struct opp_table *opp_table; |
1497 | int ret; | ||
1498 | 1480 | ||
1499 | if (!set_opp) | 1481 | if (!set_opp) |
1500 | return ERR_PTR(-EINVAL); | 1482 | return ERR_PTR(-EINVAL); |
@@ -1505,24 +1487,15 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, | |||
1505 | 1487 | ||
1506 | /* This should be called before OPPs are initialized */ | 1488 | /* This should be called before OPPs are initialized */ |
1507 | if (WARN_ON(!list_empty(&opp_table->opp_list))) { | 1489 | if (WARN_ON(!list_empty(&opp_table->opp_list))) { |
1508 | ret = -EBUSY; | 1490 | dev_pm_opp_put_opp_table(opp_table); |
1509 | goto err; | 1491 | return ERR_PTR(-EBUSY); |
1510 | } | ||
1511 | |||
1512 | /* Already have custom set_opp helper */ | ||
1513 | if (WARN_ON(opp_table->set_opp)) { | ||
1514 | ret = -EBUSY; | ||
1515 | goto err; | ||
1516 | } | 1492 | } |
1517 | 1493 | ||
1518 | opp_table->set_opp = set_opp; | 1494 | /* Another CPU that shares the OPP table has set the helper ? */ |
1495 | if (!opp_table->set_opp) | ||
1496 | opp_table->set_opp = set_opp; | ||
1519 | 1497 | ||
1520 | return opp_table; | 1498 | return opp_table; |
1521 | |||
1522 | err: | ||
1523 | dev_pm_opp_put_opp_table(opp_table); | ||
1524 | |||
1525 | return ERR_PTR(ret); | ||
1526 | } | 1499 | } |
1527 | EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); | 1500 | EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); |
1528 | 1501 | ||
@@ -1535,97 +1508,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); | |||
1535 | */ | 1508 | */ |
1536 | void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) | 1509 | void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) |
1537 | { | 1510 | { |
1538 | if (!opp_table->set_opp) { | ||
1539 | pr_err("%s: Doesn't have custom set_opp helper set\n", | ||
1540 | __func__); | ||
1541 | return; | ||
1542 | } | ||
1543 | |||
1544 | /* Make sure there are no concurrent readers while updating opp_table */ | 1511 | /* Make sure there are no concurrent readers while updating opp_table */ |
1545 | WARN_ON(!list_empty(&opp_table->opp_list)); | 1512 | WARN_ON(!list_empty(&opp_table->opp_list)); |
1546 | 1513 | ||
1547 | opp_table->set_opp = NULL; | 1514 | opp_table->set_opp = NULL; |
1548 | |||
1549 | dev_pm_opp_put_opp_table(opp_table); | 1515 | dev_pm_opp_put_opp_table(opp_table); |
1550 | } | 1516 | } |
1551 | EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper); | 1517 | EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper); |
1552 | 1518 | ||
1553 | /** | 1519 | /** |
1554 | * dev_pm_opp_register_get_pstate_helper() - Register get_pstate() helper. | ||
1555 | * @dev: Device for which the helper is getting registered. | ||
1556 | * @get_pstate: Helper. | ||
1557 | * | ||
1558 | * TODO: Remove this callback after the same information is available via Device | ||
1559 | * Tree. | ||
1560 | * | ||
1561 | * This allows a platform to initialize the performance states of individual | ||
1562 | * OPPs for its devices, until we get similar information directly from DT. | ||
1563 | * | ||
1564 | * This must be called before the OPPs are initialized for the device. | ||
1565 | */ | ||
1566 | struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev, | ||
1567 | int (*get_pstate)(struct device *dev, unsigned long rate)) | ||
1568 | { | ||
1569 | struct opp_table *opp_table; | ||
1570 | int ret; | ||
1571 | |||
1572 | if (!get_pstate) | ||
1573 | return ERR_PTR(-EINVAL); | ||
1574 | |||
1575 | opp_table = dev_pm_opp_get_opp_table(dev); | ||
1576 | if (!opp_table) | ||
1577 | return ERR_PTR(-ENOMEM); | ||
1578 | |||
1579 | /* This should be called before OPPs are initialized */ | ||
1580 | if (WARN_ON(!list_empty(&opp_table->opp_list))) { | ||
1581 | ret = -EBUSY; | ||
1582 | goto err; | ||
1583 | } | ||
1584 | |||
1585 | /* Already have genpd_performance_state set */ | ||
1586 | if (WARN_ON(opp_table->genpd_performance_state)) { | ||
1587 | ret = -EBUSY; | ||
1588 | goto err; | ||
1589 | } | ||
1590 | |||
1591 | opp_table->genpd_performance_state = true; | ||
1592 | opp_table->get_pstate = get_pstate; | ||
1593 | |||
1594 | return opp_table; | ||
1595 | |||
1596 | err: | ||
1597 | dev_pm_opp_put_opp_table(opp_table); | ||
1598 | |||
1599 | return ERR_PTR(ret); | ||
1600 | } | ||
1601 | EXPORT_SYMBOL_GPL(dev_pm_opp_register_get_pstate_helper); | ||
1602 | |||
1603 | /** | ||
1604 | * dev_pm_opp_unregister_get_pstate_helper() - Releases resources blocked for | ||
1605 | * get_pstate() helper | ||
1606 | * @opp_table: OPP table returned from dev_pm_opp_register_get_pstate_helper(). | ||
1607 | * | ||
1608 | * Release resources blocked for platform specific get_pstate() helper. | ||
1609 | */ | ||
1610 | void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table) | ||
1611 | { | ||
1612 | if (!opp_table->genpd_performance_state) { | ||
1613 | pr_err("%s: Doesn't have performance states set\n", | ||
1614 | __func__); | ||
1615 | return; | ||
1616 | } | ||
1617 | |||
1618 | /* Make sure there are no concurrent readers while updating opp_table */ | ||
1619 | WARN_ON(!list_empty(&opp_table->opp_list)); | ||
1620 | |||
1621 | opp_table->genpd_performance_state = false; | ||
1622 | opp_table->get_pstate = NULL; | ||
1623 | |||
1624 | dev_pm_opp_put_opp_table(opp_table); | ||
1625 | } | ||
1626 | EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_get_pstate_helper); | ||
1627 | |||
1628 | /** | ||
1629 | * dev_pm_opp_add() - Add an OPP table from a table definitions | 1520 | * dev_pm_opp_add() - Add an OPP table from a table definitions |
1630 | * @dev: device for which we do this operation | 1521 | * @dev: device for which we do this operation |
1631 | * @freq: Frequency in Hz for this OPP | 1522 | * @freq: Frequency in Hz for this OPP |
diff --git a/drivers/opp/debugfs.c b/drivers/opp/debugfs.c index b03c03576a62..e6828e5f81b0 100644 --- a/drivers/opp/debugfs.c +++ b/drivers/opp/debugfs.c | |||
@@ -77,10 +77,21 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) | |||
77 | { | 77 | { |
78 | struct dentry *pdentry = opp_table->dentry; | 78 | struct dentry *pdentry = opp_table->dentry; |
79 | struct dentry *d; | 79 | struct dentry *d; |
80 | unsigned long id; | ||
80 | char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ | 81 | char name[25]; /* 20 chars for 64 bit value + 5 (opp:\0) */ |
81 | 82 | ||
82 | /* Rate is unique to each OPP, use it to give opp-name */ | 83 | /* |
83 | snprintf(name, sizeof(name), "opp:%lu", opp->rate); | 84 | * Get directory name for OPP. |
85 | * | ||
86 | * - Normally rate is unique to each OPP, use it to get unique opp-name. | ||
87 | * - For some devices rate isn't available, use index instead. | ||
88 | */ | ||
89 | if (likely(opp->rate)) | ||
90 | id = opp->rate; | ||
91 | else | ||
92 | id = _get_opp_count(opp_table); | ||
93 | |||
94 | snprintf(name, sizeof(name), "opp:%lu", id); | ||
84 | 95 | ||
85 | /* Create per-opp directory */ | 96 | /* Create per-opp directory */ |
86 | d = debugfs_create_dir(name, pdentry); | 97 | d = debugfs_create_dir(name, pdentry); |
diff --git a/drivers/opp/of.c b/drivers/opp/of.c index cb716aa2f44b..7af0ddec936b 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/of_device.h> | 19 | #include <linux/of_device.h> |
20 | #include <linux/pm_domain.h> | ||
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <linux/export.h> | 22 | #include <linux/export.h> |
22 | 23 | ||
@@ -250,20 +251,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); | |||
250 | 251 | ||
251 | /* Returns opp descriptor node for a device node, caller must | 252 | /* Returns opp descriptor node for a device node, caller must |
252 | * do of_node_put() */ | 253 | * do of_node_put() */ |
253 | static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np) | 254 | static struct device_node *_opp_of_get_opp_desc_node(struct device_node *np, |
255 | int index) | ||
254 | { | 256 | { |
255 | /* | 257 | /* "operating-points-v2" can be an array for power domain providers */ |
256 | * There should be only ONE phandle present in "operating-points-v2" | 258 | return of_parse_phandle(np, "operating-points-v2", index); |
257 | * property. | ||
258 | */ | ||
259 | |||
260 | return of_parse_phandle(np, "operating-points-v2", 0); | ||
261 | } | 259 | } |
262 | 260 | ||
263 | /* Returns opp descriptor node for a device, caller must do of_node_put() */ | 261 | /* Returns opp descriptor node for a device, caller must do of_node_put() */ |
264 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) | 262 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) |
265 | { | 263 | { |
266 | return _opp_of_get_opp_desc_node(dev->of_node); | 264 | return _opp_of_get_opp_desc_node(dev->of_node, 0); |
267 | } | 265 | } |
268 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); | 266 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); |
269 | 267 | ||
@@ -289,9 +287,10 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, | |||
289 | struct device_node *np) | 287 | struct device_node *np) |
290 | { | 288 | { |
291 | struct dev_pm_opp *new_opp; | 289 | struct dev_pm_opp *new_opp; |
292 | u64 rate; | 290 | u64 rate = 0; |
293 | u32 val; | 291 | u32 val; |
294 | int ret; | 292 | int ret; |
293 | bool rate_not_available = false; | ||
295 | 294 | ||
296 | new_opp = _opp_allocate(opp_table); | 295 | new_opp = _opp_allocate(opp_table); |
297 | if (!new_opp) | 296 | if (!new_opp) |
@@ -299,8 +298,21 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, | |||
299 | 298 | ||
300 | ret = of_property_read_u64(np, "opp-hz", &rate); | 299 | ret = of_property_read_u64(np, "opp-hz", &rate); |
301 | if (ret < 0) { | 300 | if (ret < 0) { |
302 | dev_err(dev, "%s: opp-hz not found\n", __func__); | 301 | /* "opp-hz" is optional for devices like power domains. */ |
303 | goto free_opp; | 302 | if (!of_find_property(dev->of_node, "#power-domain-cells", |
303 | NULL)) { | ||
304 | dev_err(dev, "%s: opp-hz not found\n", __func__); | ||
305 | goto free_opp; | ||
306 | } | ||
307 | |||
308 | rate_not_available = true; | ||
309 | } else { | ||
310 | /* | ||
311 | * Rate is defined as an unsigned long in clk API, and so | ||
312 | * casting explicitly to its type. Must be fixed once rate is 64 | ||
313 | * bit guaranteed in clk API. | ||
314 | */ | ||
315 | new_opp->rate = (unsigned long)rate; | ||
304 | } | 316 | } |
305 | 317 | ||
306 | /* Check if the OPP supports hardware's hierarchy of versions or not */ | 318 | /* Check if the OPP supports hardware's hierarchy of versions or not */ |
@@ -309,12 +321,6 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, | |||
309 | goto free_opp; | 321 | goto free_opp; |
310 | } | 322 | } |
311 | 323 | ||
312 | /* | ||
313 | * Rate is defined as an unsigned long in clk API, and so casting | ||
314 | * explicitly to its type. Must be fixed once rate is 64 bit | ||
315 | * guaranteed in clk API. | ||
316 | */ | ||
317 | new_opp->rate = (unsigned long)rate; | ||
318 | new_opp->turbo = of_property_read_bool(np, "turbo-mode"); | 324 | new_opp->turbo = of_property_read_bool(np, "turbo-mode"); |
319 | 325 | ||
320 | new_opp->np = np; | 326 | new_opp->np = np; |
@@ -324,11 +330,13 @@ static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, | |||
324 | if (!of_property_read_u32(np, "clock-latency-ns", &val)) | 330 | if (!of_property_read_u32(np, "clock-latency-ns", &val)) |
325 | new_opp->clock_latency_ns = val; | 331 | new_opp->clock_latency_ns = val; |
326 | 332 | ||
333 | new_opp->pstate = of_genpd_opp_to_performance_state(dev, np); | ||
334 | |||
327 | ret = opp_parse_supplies(new_opp, dev, opp_table); | 335 | ret = opp_parse_supplies(new_opp, dev, opp_table); |
328 | if (ret) | 336 | if (ret) |
329 | goto free_opp; | 337 | goto free_opp; |
330 | 338 | ||
331 | ret = _opp_add(dev, new_opp, opp_table); | 339 | ret = _opp_add(dev, new_opp, opp_table, rate_not_available); |
332 | if (ret) { | 340 | if (ret) { |
333 | /* Don't return error for duplicate OPPs */ | 341 | /* Don't return error for duplicate OPPs */ |
334 | if (ret == -EBUSY) | 342 | if (ret == -EBUSY) |
@@ -374,7 +382,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) | |||
374 | { | 382 | { |
375 | struct device_node *np; | 383 | struct device_node *np; |
376 | struct opp_table *opp_table; | 384 | struct opp_table *opp_table; |
377 | int ret = 0, count = 0; | 385 | int ret = 0, count = 0, pstate_count = 0; |
386 | struct dev_pm_opp *opp; | ||
378 | 387 | ||
379 | opp_table = _managed_opp(opp_np); | 388 | opp_table = _managed_opp(opp_np); |
380 | if (opp_table) { | 389 | if (opp_table) { |
@@ -408,6 +417,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) | |||
408 | goto put_opp_table; | 417 | goto put_opp_table; |
409 | } | 418 | } |
410 | 419 | ||
420 | list_for_each_entry(opp, &opp_table->opp_list, node) | ||
421 | pstate_count += !!opp->pstate; | ||
422 | |||
423 | /* Either all or none of the nodes shall have performance state set */ | ||
424 | if (pstate_count && pstate_count != count) { | ||
425 | dev_err(dev, "Not all nodes have performance state set (%d: %d)\n", | ||
426 | count, pstate_count); | ||
427 | ret = -ENOENT; | ||
428 | goto put_opp_table; | ||
429 | } | ||
430 | |||
431 | if (pstate_count) | ||
432 | opp_table->genpd_performance_state = true; | ||
433 | |||
411 | opp_table->np = opp_np; | 434 | opp_table->np = opp_np; |
412 | if (of_property_read_bool(opp_np, "opp-shared")) | 435 | if (of_property_read_bool(opp_np, "opp-shared")) |
413 | opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; | 436 | opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; |
@@ -509,6 +532,54 @@ int dev_pm_opp_of_add_table(struct device *dev) | |||
509 | } | 532 | } |
510 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); | 533 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); |
511 | 534 | ||
535 | /** | ||
536 | * dev_pm_opp_of_add_table_indexed() - Initialize indexed opp table from device tree | ||
537 | * @dev: device pointer used to lookup OPP table. | ||
538 | * @index: Index number. | ||
539 | * | ||
540 | * Register the initial OPP table with the OPP library for given device only | ||
541 | * using the "operating-points-v2" property. | ||
542 | * | ||
543 | * Return: | ||
544 | * 0 On success OR | ||
545 | * Duplicate OPPs (both freq and volt are same) and opp->available | ||
546 | * -EEXIST Freq are same and volt are different OR | ||
547 | * Duplicate OPPs (both freq and volt are same) and !opp->available | ||
548 | * -ENOMEM Memory allocation failure | ||
549 | * -ENODEV when 'operating-points' property is not found or is invalid data | ||
550 | * in device node. | ||
551 | * -ENODATA when empty 'operating-points' property is found | ||
552 | * -EINVAL when invalid entries are found in opp-v2 table | ||
553 | */ | ||
554 | int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) | ||
555 | { | ||
556 | struct device_node *opp_np; | ||
557 | int ret, count; | ||
558 | |||
559 | again: | ||
560 | opp_np = _opp_of_get_opp_desc_node(dev->of_node, index); | ||
561 | if (!opp_np) { | ||
562 | /* | ||
563 | * If only one phandle is present, then the same OPP table | ||
564 | * applies for all index requests. | ||
565 | */ | ||
566 | count = of_count_phandle_with_args(dev->of_node, | ||
567 | "operating-points-v2", NULL); | ||
568 | if (count == 1 && index) { | ||
569 | index = 0; | ||
570 | goto again; | ||
571 | } | ||
572 | |||
573 | return -ENODEV; | ||
574 | } | ||
575 | |||
576 | ret = _of_add_opp_table_v2(dev, opp_np); | ||
577 | of_node_put(opp_np); | ||
578 | |||
579 | return ret; | ||
580 | } | ||
581 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); | ||
582 | |||
512 | /* CPU device specific helpers */ | 583 | /* CPU device specific helpers */ |
513 | 584 | ||
514 | /** | 585 | /** |
@@ -613,7 +684,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, | |||
613 | } | 684 | } |
614 | 685 | ||
615 | /* Get OPP descriptor node */ | 686 | /* Get OPP descriptor node */ |
616 | tmp_np = _opp_of_get_opp_desc_node(cpu_np); | 687 | tmp_np = _opp_of_get_opp_desc_node(cpu_np, 0); |
617 | of_node_put(cpu_np); | 688 | of_node_put(cpu_np); |
618 | if (!tmp_np) { | 689 | if (!tmp_np) { |
619 | pr_err("%pOF: Couldn't find opp node\n", cpu_np); | 690 | pr_err("%pOF: Couldn't find opp node\n", cpu_np); |
@@ -633,3 +704,76 @@ put_cpu_node: | |||
633 | return ret; | 704 | return ret; |
634 | } | 705 | } |
635 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus); | 706 | EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus); |
707 | |||
708 | /** | ||
709 | * of_dev_pm_opp_find_required_opp() - Search for required OPP. | ||
710 | * @dev: The device whose OPP node is referenced by the 'np' DT node. | ||
711 | * @np: Node that contains the "required-opps" property. | ||
712 | * | ||
713 | * Returns the OPP of the device 'dev', whose phandle is present in the "np" | ||
714 | * node. Although the "required-opps" property supports having multiple | ||
715 | * phandles, this helper routine only parses the very first phandle in the list. | ||
716 | * | ||
717 | * Return: Matching opp, else returns ERR_PTR in case of error and should be | ||
718 | * handled using IS_ERR. | ||
719 | * | ||
720 | * The callers are required to call dev_pm_opp_put() for the returned OPP after | ||
721 | * use. | ||
722 | */ | ||
723 | struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, | ||
724 | struct device_node *np) | ||
725 | { | ||
726 | struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ENODEV); | ||
727 | struct device_node *required_np; | ||
728 | struct opp_table *opp_table; | ||
729 | |||
730 | opp_table = _find_opp_table(dev); | ||
731 | if (IS_ERR(opp_table)) | ||
732 | return ERR_CAST(opp_table); | ||
733 | |||
734 | required_np = of_parse_phandle(np, "required-opps", 0); | ||
735 | if (unlikely(!required_np)) { | ||
736 | dev_err(dev, "Unable to parse required-opps\n"); | ||
737 | goto put_opp_table; | ||
738 | } | ||
739 | |||
740 | mutex_lock(&opp_table->lock); | ||
741 | |||
742 | list_for_each_entry(temp_opp, &opp_table->opp_list, node) { | ||
743 | if (temp_opp->available && temp_opp->np == required_np) { | ||
744 | opp = temp_opp; | ||
745 | |||
746 | /* Increment the reference count of OPP */ | ||
747 | dev_pm_opp_get(opp); | ||
748 | break; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | mutex_unlock(&opp_table->lock); | ||
753 | |||
754 | of_node_put(required_np); | ||
755 | put_opp_table: | ||
756 | dev_pm_opp_put_opp_table(opp_table); | ||
757 | |||
758 | return opp; | ||
759 | } | ||
760 | EXPORT_SYMBOL_GPL(of_dev_pm_opp_find_required_opp); | ||
761 | |||
762 | /** | ||
763 | * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp | ||
764 | * @opp: opp for which DT node has to be returned for | ||
765 | * | ||
766 | * Return: DT node corresponding to the opp, else 0 on success. | ||
767 | * | ||
768 | * The caller needs to put the node with of_node_put() after using it. | ||
769 | */ | ||
770 | struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) | ||
771 | { | ||
772 | if (IS_ERR_OR_NULL(opp)) { | ||
773 | pr_err("%s: Invalid parameters\n", __func__); | ||
774 | return NULL; | ||
775 | } | ||
776 | |||
777 | return of_node_get(opp->np); | ||
778 | } | ||
779 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node); | ||
diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 4d00061648a3..7c540fd063b2 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h | |||
@@ -140,7 +140,6 @@ enum opp_table_access { | |||
140 | * @genpd_performance_state: Device's power domain support performance state. | 140 | * @genpd_performance_state: Device's power domain support performance state. |
141 | * @set_opp: Platform specific set_opp callback | 141 | * @set_opp: Platform specific set_opp callback |
142 | * @set_opp_data: Data to be passed to set_opp callback | 142 | * @set_opp_data: Data to be passed to set_opp callback |
143 | * @get_pstate: Platform specific get_pstate callback | ||
144 | * @dentry: debugfs dentry pointer of the real device directory (not links). | 143 | * @dentry: debugfs dentry pointer of the real device directory (not links). |
145 | * @dentry_name: Name of the real dentry. | 144 | * @dentry_name: Name of the real dentry. |
146 | * | 145 | * |
@@ -178,7 +177,6 @@ struct opp_table { | |||
178 | 177 | ||
179 | int (*set_opp)(struct dev_pm_set_opp_data *data); | 178 | int (*set_opp)(struct dev_pm_set_opp_data *data); |
180 | struct dev_pm_set_opp_data *set_opp_data; | 179 | struct dev_pm_set_opp_data *set_opp_data; |
181 | int (*get_pstate)(struct device *dev, unsigned long rate); | ||
182 | 180 | ||
183 | #ifdef CONFIG_DEBUG_FS | 181 | #ifdef CONFIG_DEBUG_FS |
184 | struct dentry *dentry; | 182 | struct dentry *dentry; |
@@ -187,14 +185,16 @@ struct opp_table { | |||
187 | }; | 185 | }; |
188 | 186 | ||
189 | /* Routines internal to opp core */ | 187 | /* Routines internal to opp core */ |
188 | void dev_pm_opp_get(struct dev_pm_opp *opp); | ||
190 | void _get_opp_table_kref(struct opp_table *opp_table); | 189 | void _get_opp_table_kref(struct opp_table *opp_table); |
190 | int _get_opp_count(struct opp_table *opp_table); | ||
191 | struct opp_table *_find_opp_table(struct device *dev); | 191 | struct opp_table *_find_opp_table(struct device *dev); |
192 | struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); | 192 | struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); |
193 | void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); | 193 | void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); |
194 | void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); | 194 | void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); |
195 | struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); | 195 | struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); |
196 | void _opp_free(struct dev_pm_opp *opp); | 196 | void _opp_free(struct dev_pm_opp *opp); |
197 | int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); | 197 | int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available); |
198 | int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); | 198 | int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); |
199 | void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); | 199 | void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); |
200 | struct opp_table *_add_opp_table(struct device *dev); | 200 | struct opp_table *_add_opp_table(struct device *dev); |
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d9fcdb592b39..3e3d12ce4587 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c | |||
@@ -559,22 +559,28 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping); | |||
559 | int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, | 559 | int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, |
560 | struct reset_control *rst) | 560 | struct reset_control *rst) |
561 | { | 561 | { |
562 | struct tegra_powergate pg; | 562 | struct tegra_powergate *pg; |
563 | int err; | 563 | int err; |
564 | 564 | ||
565 | if (!tegra_powergate_is_available(id)) | 565 | if (!tegra_powergate_is_available(id)) |
566 | return -EINVAL; | 566 | return -EINVAL; |
567 | 567 | ||
568 | pg.id = id; | 568 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); |
569 | pg.clks = &clk; | 569 | if (!pg) |
570 | pg.num_clks = 1; | 570 | return -ENOMEM; |
571 | pg.reset = rst; | ||
572 | pg.pmc = pmc; | ||
573 | 571 | ||
574 | err = tegra_powergate_power_up(&pg, false); | 572 | pg->id = id; |
573 | pg->clks = &clk; | ||
574 | pg->num_clks = 1; | ||
575 | pg->reset = rst; | ||
576 | pg->pmc = pmc; | ||
577 | |||
578 | err = tegra_powergate_power_up(pg, false); | ||
575 | if (err) | 579 | if (err) |
576 | pr_err("failed to turn on partition %d: %d\n", id, err); | 580 | pr_err("failed to turn on partition %d: %d\n", id, err); |
577 | 581 | ||
582 | kfree(pg); | ||
583 | |||
578 | return err; | 584 | return err; |
579 | } | 585 | } |
580 | EXPORT_SYMBOL(tegra_powergate_sequence_power_up); | 586 | EXPORT_SYMBOL(tegra_powergate_sequence_power_up); |
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index ab1854863a8c..42e0d649e653 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h | |||
@@ -47,8 +47,10 @@ struct genpd_power_state { | |||
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct genpd_lock_ops; | 49 | struct genpd_lock_ops; |
50 | struct dev_pm_opp; | ||
50 | 51 | ||
51 | struct generic_pm_domain { | 52 | struct generic_pm_domain { |
53 | struct device dev; | ||
52 | struct dev_pm_domain domain; /* PM domain operations */ | 54 | struct dev_pm_domain domain; /* PM domain operations */ |
53 | struct list_head gpd_list_node; /* Node in the global PM domains list */ | 55 | struct list_head gpd_list_node; /* Node in the global PM domains list */ |
54 | struct list_head master_links; /* Links with PM domain as a master */ | 56 | struct list_head master_links; /* Links with PM domain as a master */ |
@@ -67,6 +69,8 @@ struct generic_pm_domain { | |||
67 | unsigned int performance_state; /* Aggregated max performance state */ | 69 | unsigned int performance_state; /* Aggregated max performance state */ |
68 | int (*power_off)(struct generic_pm_domain *domain); | 70 | int (*power_off)(struct generic_pm_domain *domain); |
69 | int (*power_on)(struct generic_pm_domain *domain); | 71 | int (*power_on)(struct generic_pm_domain *domain); |
72 | unsigned int (*opp_to_performance_state)(struct generic_pm_domain *genpd, | ||
73 | struct dev_pm_opp *opp); | ||
70 | int (*set_performance_state)(struct generic_pm_domain *genpd, | 74 | int (*set_performance_state)(struct generic_pm_domain *genpd, |
71 | unsigned int state); | 75 | unsigned int state); |
72 | struct gpd_dev_ops dev_ops; | 76 | struct gpd_dev_ops dev_ops; |
@@ -139,21 +143,16 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) | |||
139 | return to_gpd_data(dev->power.subsys_data->domain_data); | 143 | return to_gpd_data(dev->power.subsys_data->domain_data); |
140 | } | 144 | } |
141 | 145 | ||
142 | extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, | 146 | int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev); |
143 | struct device *dev, | 147 | int pm_genpd_remove_device(struct device *dev); |
144 | struct gpd_timing_data *td); | 148 | int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, |
145 | 149 | struct generic_pm_domain *new_subdomain); | |
146 | extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 150 | int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, |
147 | struct device *dev); | 151 | struct generic_pm_domain *target); |
148 | extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, | 152 | int pm_genpd_init(struct generic_pm_domain *genpd, |
149 | struct generic_pm_domain *new_subdomain); | 153 | struct dev_power_governor *gov, bool is_off); |
150 | extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, | 154 | int pm_genpd_remove(struct generic_pm_domain *genpd); |
151 | struct generic_pm_domain *target); | 155 | int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state); |
152 | extern int pm_genpd_init(struct generic_pm_domain *genpd, | ||
153 | struct dev_power_governor *gov, bool is_off); | ||
154 | extern int pm_genpd_remove(struct generic_pm_domain *genpd); | ||
155 | extern int dev_pm_genpd_set_performance_state(struct device *dev, | ||
156 | unsigned int state); | ||
157 | 156 | ||
158 | extern struct dev_power_governor simple_qos_governor; | 157 | extern struct dev_power_governor simple_qos_governor; |
159 | extern struct dev_power_governor pm_domain_always_on_gov; | 158 | extern struct dev_power_governor pm_domain_always_on_gov; |
@@ -163,14 +162,12 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) | |||
163 | { | 162 | { |
164 | return ERR_PTR(-ENOSYS); | 163 | return ERR_PTR(-ENOSYS); |
165 | } | 164 | } |
166 | static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, | 165 | static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, |
167 | struct device *dev, | 166 | struct device *dev) |
168 | struct gpd_timing_data *td) | ||
169 | { | 167 | { |
170 | return -ENOSYS; | 168 | return -ENOSYS; |
171 | } | 169 | } |
172 | static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, | 170 | static inline int pm_genpd_remove_device(struct device *dev) |
173 | struct device *dev) | ||
174 | { | 171 | { |
175 | return -ENOSYS; | 172 | return -ENOSYS; |
176 | } | 173 | } |
@@ -204,15 +201,9 @@ static inline int dev_pm_genpd_set_performance_state(struct device *dev, | |||
204 | #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) | 201 | #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) |
205 | #endif | 202 | #endif |
206 | 203 | ||
207 | static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, | ||
208 | struct device *dev) | ||
209 | { | ||
210 | return __pm_genpd_add_device(genpd, dev, NULL); | ||
211 | } | ||
212 | |||
213 | #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP | 204 | #ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP |
214 | extern void pm_genpd_syscore_poweroff(struct device *dev); | 205 | void pm_genpd_syscore_poweroff(struct device *dev); |
215 | extern void pm_genpd_syscore_poweron(struct device *dev); | 206 | void pm_genpd_syscore_poweron(struct device *dev); |
216 | #else | 207 | #else |
217 | static inline void pm_genpd_syscore_poweroff(struct device *dev) {} | 208 | static inline void pm_genpd_syscore_poweroff(struct device *dev) {} |
218 | static inline void pm_genpd_syscore_poweron(struct device *dev) {} | 209 | static inline void pm_genpd_syscore_poweron(struct device *dev) {} |
@@ -236,13 +227,14 @@ int of_genpd_add_provider_simple(struct device_node *np, | |||
236 | int of_genpd_add_provider_onecell(struct device_node *np, | 227 | int of_genpd_add_provider_onecell(struct device_node *np, |
237 | struct genpd_onecell_data *data); | 228 | struct genpd_onecell_data *data); |
238 | void of_genpd_del_provider(struct device_node *np); | 229 | void of_genpd_del_provider(struct device_node *np); |
239 | extern int of_genpd_add_device(struct of_phandle_args *args, | 230 | int of_genpd_add_device(struct of_phandle_args *args, struct device *dev); |
240 | struct device *dev); | 231 | int of_genpd_add_subdomain(struct of_phandle_args *parent, |
241 | extern int of_genpd_add_subdomain(struct of_phandle_args *parent, | 232 | struct of_phandle_args *new_subdomain); |
242 | struct of_phandle_args *new_subdomain); | 233 | struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); |
243 | extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); | 234 | int of_genpd_parse_idle_states(struct device_node *dn, |
244 | extern int of_genpd_parse_idle_states(struct device_node *dn, | 235 | struct genpd_power_state **states, int *n); |
245 | struct genpd_power_state **states, int *n); | 236 | unsigned int of_genpd_opp_to_performance_state(struct device *dev, |
237 | struct device_node *opp_node); | ||
246 | 238 | ||
247 | int genpd_dev_pm_attach(struct device *dev); | 239 | int genpd_dev_pm_attach(struct device *dev); |
248 | #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ | 240 | #else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ |
@@ -278,6 +270,13 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn, | |||
278 | return -ENODEV; | 270 | return -ENODEV; |
279 | } | 271 | } |
280 | 272 | ||
273 | static inline unsigned int | ||
274 | of_genpd_opp_to_performance_state(struct device *dev, | ||
275 | struct device_node *opp_node) | ||
276 | { | ||
277 | return -ENODEV; | ||
278 | } | ||
279 | |||
281 | static inline int genpd_dev_pm_attach(struct device *dev) | 280 | static inline int genpd_dev_pm_attach(struct device *dev) |
282 | { | 281 | { |
283 | return 0; | 282 | return 0; |
@@ -291,9 +290,9 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) | |||
291 | #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ | 290 | #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ |
292 | 291 | ||
293 | #ifdef CONFIG_PM | 292 | #ifdef CONFIG_PM |
294 | extern int dev_pm_domain_attach(struct device *dev, bool power_on); | 293 | int dev_pm_domain_attach(struct device *dev, bool power_on); |
295 | extern void dev_pm_domain_detach(struct device *dev, bool power_off); | 294 | void dev_pm_domain_detach(struct device *dev, bool power_off); |
296 | extern void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); | 295 | void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); |
297 | #else | 296 | #else |
298 | static inline int dev_pm_domain_attach(struct device *dev, bool power_on) | 297 | static inline int dev_pm_domain_attach(struct device *dev, bool power_on) |
299 | { | 298 | { |
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 6c2d2e88f066..099b31960dec 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h | |||
@@ -125,8 +125,6 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name); | |||
125 | void dev_pm_opp_put_clkname(struct opp_table *opp_table); | 125 | void dev_pm_opp_put_clkname(struct opp_table *opp_table); |
126 | struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); | 126 | struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); |
127 | void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); | 127 | void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); |
128 | struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev, int (*get_pstate)(struct device *dev, unsigned long rate)); | ||
129 | void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table); | ||
130 | int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); | 128 | int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); |
131 | int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); | 129 | int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); |
132 | int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); | 130 | int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); |
@@ -247,14 +245,6 @@ static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device | |||
247 | 245 | ||
248 | static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {} | 246 | static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {} |
249 | 247 | ||
250 | static inline struct opp_table *dev_pm_opp_register_get_pstate_helper(struct device *dev, | ||
251 | int (*get_pstate)(struct device *dev, unsigned long rate)) | ||
252 | { | ||
253 | return ERR_PTR(-ENOTSUPP); | ||
254 | } | ||
255 | |||
256 | static inline void dev_pm_opp_unregister_get_pstate_helper(struct opp_table *opp_table) {} | ||
257 | |||
258 | static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) | 248 | static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) |
259 | { | 249 | { |
260 | return ERR_PTR(-ENOTSUPP); | 250 | return ERR_PTR(-ENOTSUPP); |
@@ -303,17 +293,25 @@ static inline void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask | |||
303 | 293 | ||
304 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) | 294 | #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) |
305 | int dev_pm_opp_of_add_table(struct device *dev); | 295 | int dev_pm_opp_of_add_table(struct device *dev); |
296 | int dev_pm_opp_of_add_table_indexed(struct device *dev, int index); | ||
306 | void dev_pm_opp_of_remove_table(struct device *dev); | 297 | void dev_pm_opp_of_remove_table(struct device *dev); |
307 | int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); | 298 | int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); |
308 | void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask); | 299 | void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask); |
309 | int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); | 300 | int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); |
310 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev); | 301 | struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev); |
302 | struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, struct device_node *np); | ||
303 | struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp); | ||
311 | #else | 304 | #else |
312 | static inline int dev_pm_opp_of_add_table(struct device *dev) | 305 | static inline int dev_pm_opp_of_add_table(struct device *dev) |
313 | { | 306 | { |
314 | return -ENOTSUPP; | 307 | return -ENOTSUPP; |
315 | } | 308 | } |
316 | 309 | ||
310 | static inline int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) | ||
311 | { | ||
312 | return -ENOTSUPP; | ||
313 | } | ||
314 | |||
317 | static inline void dev_pm_opp_of_remove_table(struct device *dev) | 315 | static inline void dev_pm_opp_of_remove_table(struct device *dev) |
318 | { | 316 | { |
319 | } | 317 | } |
@@ -336,6 +334,15 @@ static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device | |||
336 | { | 334 | { |
337 | return NULL; | 335 | return NULL; |
338 | } | 336 | } |
337 | |||
338 | static inline struct dev_pm_opp *of_dev_pm_opp_find_required_opp(struct device *dev, struct device_node *np) | ||
339 | { | ||
340 | return NULL; | ||
341 | } | ||
342 | static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) | ||
343 | { | ||
344 | return NULL; | ||
345 | } | ||
339 | #endif | 346 | #endif |
340 | 347 | ||
341 | #endif /* __LINUX_OPP_H__ */ | 348 | #endif /* __LINUX_OPP_H__ */ |