Loading drivers/devfreq/devfreq_icc.c +61 −14 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014, 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2018-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "devfreq-icc: " fmt Loading @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <trace/events/power.h> #include <linux/platform_device.h> #include <linux/interconnect.h> Loading @@ -28,13 +29,27 @@ /* Has to be ULL to prevent overflow where this macro is used. */ #define MBYTE (1ULL << 20) #define HZ_TO_MBPS(hz, w) (mult_frac(w, hz, MBYTE)) #define MBPS_TO_HZ(mbps, w) (mult_frac(mbps, MBYTE, w)) enum dev_type { STD_MBPS_DEV, L3_HZ_DEV, L3_MBPS_DEV, NUM_DEV_TYPES }; struct devfreq_icc_spec { enum dev_type type; }; struct dev_data { struct icc_path *icc_path; u32 cur_ab; u32 cur_ib; unsigned long gov_ab; bool is_l3; const struct devfreq_icc_spec *spec; unsigned int width; struct devfreq *df; struct devfreq_dev_profile dp; }; Loading @@ -53,7 +68,10 @@ static int set_bw(struct device *dev, u32 new_ib, u32 new_ab) if (d->cur_ib == new_ib && d->cur_ab == new_ab) return 0; if (!d->is_l3) { if (d->spec->type == L3_MBPS_DEV) { icc_ib = MBPS_TO_HZ(new_ib, d->width); icc_ab = MBPS_TO_HZ(new_ab, d->width); } else if (d->spec->type == STD_MBPS_DEV) { icc_ib = Bps_to_icc(new_ib * MBYTE); icc_ab = Bps_to_icc(new_ab * MBYTE); } Loading Loading @@ -101,6 +119,7 @@ static int icc_get_dev_status(struct device *dev, static int populate_l3_opp_table(struct device *dev) { struct dev_data *d = dev_get_drvdata(dev); int idx, ret; u32 data, src, mult, i; unsigned long freq, prev_freq = 0; Loading Loading @@ -139,6 +158,9 @@ static int populate_l3_opp_table(struct device *dev) if (i > 0 && prev_freq == freq) break; if (d->spec->type == L3_MBPS_DEV) dev_pm_opp_add(dev, HZ_TO_MBPS(freq, d->width), 0); else dev_pm_opp_add(dev, freq, 0); l3_freqs[i] = freq; prev_freq = freq; Loading @@ -152,13 +174,18 @@ static int populate_l3_opp_table(struct device *dev) static int copy_l3_opp_table(struct device *dev) { struct dev_data *d = dev_get_drvdata(dev); int idx; for (idx = 0; idx < MAX_L3_ENTRIES; idx++) { if (l3_freqs[idx]) dev_pm_opp_add(dev, l3_freqs[idx], 0); else if (!l3_freqs[idx]) break; if (d->spec->type == L3_MBPS_DEV) dev_pm_opp_add(dev, HZ_TO_MBPS(l3_freqs[idx], d->width), 0); else dev_pm_opp_add(dev, l3_freqs[idx], 0); } if (!idx) { Loading Loading @@ -186,6 +213,12 @@ int devfreq_add_icc(struct device *dev) return -ENOMEM; dev_set_drvdata(dev, d); d->spec = of_device_get_match_data(dev); if (!d->spec) { dev_err(dev, "Unknown device type!\n"); return -ENODEV; } p = &d->dp; p->polling_ms = 50; p->target = icc_target; Loading @@ -200,7 +233,16 @@ int devfreq_add_icc(struct device *dev) } } if (of_device_is_compatible(dev->of_node, "qcom,devfreq-icc-l3")) { if (d->spec->type == L3_MBPS_DEV) { ret = of_property_read_u32(dev->of_node, "qcom,bus-width", &d->width); if (ret < 0 || !d->width) { dev_err(dev, "Missing or invalid bus-width: %d\n", ret); return -EINVAL; } } if (d->spec->type == L3_HZ_DEV || d->spec->type == L3_MBPS_DEV) { mutex_lock(&l3_freqs_lock); if (use_cached_l3_freqs) { mutex_unlock(&l3_freqs_lock); Loading @@ -209,10 +251,8 @@ int devfreq_add_icc(struct device *dev) ret = populate_l3_opp_table(dev); mutex_unlock(&l3_freqs_lock); } d->is_l3 = true; } else { ret = dev_pm_opp_of_add_table(dev); d->is_l3 = false; } if (ret < 0) dev_err(dev, "Couldn't parse OPP table:%d\n", ret); Loading Loading @@ -273,11 +313,18 @@ static int devfreq_icc_remove(struct platform_device *pdev) return devfreq_remove_icc(&pdev->dev); } static const struct devfreq_icc_spec spec[] = { [0] = { STD_MBPS_DEV }, [1] = { L3_HZ_DEV }, [2] = { L3_MBPS_DEV }, }; static const struct of_device_id devfreq_icc_match_table[] = { { .compatible = "qcom,devfreq-icc-l3" }, { .compatible = "qcom,devfreq-icc-llcc" }, { .compatible = "qcom,devfreq-icc-ddr" }, { .compatible = "qcom,devfreq-icc" }, { .compatible = "qcom,devfreq-icc-l3bw", .data = &spec[2] }, { .compatible = "qcom,devfreq-icc-l3", .data = &spec[1] }, { .compatible = "qcom,devfreq-icc-llcc", .data = &spec[0] }, { .compatible = "qcom,devfreq-icc-ddr", .data = &spec[0] }, { .compatible = "qcom,devfreq-icc", .data = &spec[0] }, {} }; Loading Loading
drivers/devfreq/devfreq_icc.c +61 −14 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2014, 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2014, 2018-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "devfreq-icc: " fmt Loading @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <trace/events/power.h> #include <linux/platform_device.h> #include <linux/interconnect.h> Loading @@ -28,13 +29,27 @@ /* Has to be ULL to prevent overflow where this macro is used. */ #define MBYTE (1ULL << 20) #define HZ_TO_MBPS(hz, w) (mult_frac(w, hz, MBYTE)) #define MBPS_TO_HZ(mbps, w) (mult_frac(mbps, MBYTE, w)) enum dev_type { STD_MBPS_DEV, L3_HZ_DEV, L3_MBPS_DEV, NUM_DEV_TYPES }; struct devfreq_icc_spec { enum dev_type type; }; struct dev_data { struct icc_path *icc_path; u32 cur_ab; u32 cur_ib; unsigned long gov_ab; bool is_l3; const struct devfreq_icc_spec *spec; unsigned int width; struct devfreq *df; struct devfreq_dev_profile dp; }; Loading @@ -53,7 +68,10 @@ static int set_bw(struct device *dev, u32 new_ib, u32 new_ab) if (d->cur_ib == new_ib && d->cur_ab == new_ab) return 0; if (!d->is_l3) { if (d->spec->type == L3_MBPS_DEV) { icc_ib = MBPS_TO_HZ(new_ib, d->width); icc_ab = MBPS_TO_HZ(new_ab, d->width); } else if (d->spec->type == STD_MBPS_DEV) { icc_ib = Bps_to_icc(new_ib * MBYTE); icc_ab = Bps_to_icc(new_ab * MBYTE); } Loading Loading @@ -101,6 +119,7 @@ static int icc_get_dev_status(struct device *dev, static int populate_l3_opp_table(struct device *dev) { struct dev_data *d = dev_get_drvdata(dev); int idx, ret; u32 data, src, mult, i; unsigned long freq, prev_freq = 0; Loading Loading @@ -139,6 +158,9 @@ static int populate_l3_opp_table(struct device *dev) if (i > 0 && prev_freq == freq) break; if (d->spec->type == L3_MBPS_DEV) dev_pm_opp_add(dev, HZ_TO_MBPS(freq, d->width), 0); else dev_pm_opp_add(dev, freq, 0); l3_freqs[i] = freq; prev_freq = freq; Loading @@ -152,13 +174,18 @@ static int populate_l3_opp_table(struct device *dev) static int copy_l3_opp_table(struct device *dev) { struct dev_data *d = dev_get_drvdata(dev); int idx; for (idx = 0; idx < MAX_L3_ENTRIES; idx++) { if (l3_freqs[idx]) dev_pm_opp_add(dev, l3_freqs[idx], 0); else if (!l3_freqs[idx]) break; if (d->spec->type == L3_MBPS_DEV) dev_pm_opp_add(dev, HZ_TO_MBPS(l3_freqs[idx], d->width), 0); else dev_pm_opp_add(dev, l3_freqs[idx], 0); } if (!idx) { Loading Loading @@ -186,6 +213,12 @@ int devfreq_add_icc(struct device *dev) return -ENOMEM; dev_set_drvdata(dev, d); d->spec = of_device_get_match_data(dev); if (!d->spec) { dev_err(dev, "Unknown device type!\n"); return -ENODEV; } p = &d->dp; p->polling_ms = 50; p->target = icc_target; Loading @@ -200,7 +233,16 @@ int devfreq_add_icc(struct device *dev) } } if (of_device_is_compatible(dev->of_node, "qcom,devfreq-icc-l3")) { if (d->spec->type == L3_MBPS_DEV) { ret = of_property_read_u32(dev->of_node, "qcom,bus-width", &d->width); if (ret < 0 || !d->width) { dev_err(dev, "Missing or invalid bus-width: %d\n", ret); return -EINVAL; } } if (d->spec->type == L3_HZ_DEV || d->spec->type == L3_MBPS_DEV) { mutex_lock(&l3_freqs_lock); if (use_cached_l3_freqs) { mutex_unlock(&l3_freqs_lock); Loading @@ -209,10 +251,8 @@ int devfreq_add_icc(struct device *dev) ret = populate_l3_opp_table(dev); mutex_unlock(&l3_freqs_lock); } d->is_l3 = true; } else { ret = dev_pm_opp_of_add_table(dev); d->is_l3 = false; } if (ret < 0) dev_err(dev, "Couldn't parse OPP table:%d\n", ret); Loading Loading @@ -273,11 +313,18 @@ static int devfreq_icc_remove(struct platform_device *pdev) return devfreq_remove_icc(&pdev->dev); } static const struct devfreq_icc_spec spec[] = { [0] = { STD_MBPS_DEV }, [1] = { L3_HZ_DEV }, [2] = { L3_MBPS_DEV }, }; static const struct of_device_id devfreq_icc_match_table[] = { { .compatible = "qcom,devfreq-icc-l3" }, { .compatible = "qcom,devfreq-icc-llcc" }, { .compatible = "qcom,devfreq-icc-ddr" }, { .compatible = "qcom,devfreq-icc" }, { .compatible = "qcom,devfreq-icc-l3bw", .data = &spec[2] }, { .compatible = "qcom,devfreq-icc-l3", .data = &spec[1] }, { .compatible = "qcom,devfreq-icc-llcc", .data = &spec[0] }, { .compatible = "qcom,devfreq-icc-ddr", .data = &spec[0] }, { .compatible = "qcom,devfreq-icc", .data = &spec[0] }, {} }; Loading