diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-01-31 07:18:06 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-01-31 07:18:06 -0500 |
| commit | 23b017a623a0bd19c24e6c1c41fe587c644e9dbc (patch) | |
| tree | beb477ac919f1a2911bd43681f310354bd0045a8 /drivers/devfreq | |
| parent | 566cf877a1fcb6d6dc0126b076aad062054c2637 (diff) | |
| parent | 4585fbcb5331fc910b7e553ad3efd0dd7b320d14 (diff) | |
Merge tag 'pullreq_20170131' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq into pm-devfreq
Pull devfreq changes for v4.11 from MyungJoo Ham.
* tag 'pullreq_20170131' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq:
PM / devfreq: Modify the device name as devfreq(X) for sysfs
PM / devfreq: Simplify the sysfs name of devfreq-event device
PM / devfreq: Remove unnecessary separate _remove_devfreq()
PM / devfreq: Fix wrong trans_stat of passive devfreq device
PM / devfreq: Fix available_governor sysfs
PM / devfreq: exynos-ppmu: Show the registred device for ppmu device
PM / devfreq: Fix the wrong description for userspace governor
PM / devfreq: Fix the checkpatch warnings
PM / devfreq: exynos-bus: Print the real clock rate of bus
PM / devfreq: exynos-ppmu: Use the regmap interface to handle the registers
PM / devfreq: exynos-bus: Add the detailed correlation for Exynos5433
PM / devfreq: Don't delete sysfs group twice
Diffstat (limited to 'drivers/devfreq')
| -rw-r--r-- | drivers/devfreq/devfreq-event.c | 4 | ||||
| -rw-r--r-- | drivers/devfreq/devfreq.c | 74 | ||||
| -rw-r--r-- | drivers/devfreq/event/exynos-ppmu.c | 329 | ||||
| -rw-r--r-- | drivers/devfreq/exynos-bus.c | 8 | ||||
| -rw-r--r-- | drivers/devfreq/governor.h | 2 | ||||
| -rw-r--r-- | drivers/devfreq/governor_passive.c | 6 | ||||
| -rw-r--r-- | drivers/devfreq/governor_userspace.c | 11 |
7 files changed, 308 insertions, 126 deletions
diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c index 9aea2c7ecbe6..8648b32ebc89 100644 --- a/drivers/devfreq/devfreq-event.c +++ b/drivers/devfreq/devfreq-event.c | |||
| @@ -306,7 +306,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, | |||
| 306 | struct devfreq_event_desc *desc) | 306 | struct devfreq_event_desc *desc) |
| 307 | { | 307 | { |
| 308 | struct devfreq_event_dev *edev; | 308 | struct devfreq_event_dev *edev; |
| 309 | static atomic_t event_no = ATOMIC_INIT(0); | 309 | static atomic_t event_no = ATOMIC_INIT(-1); |
| 310 | int ret; | 310 | int ret; |
| 311 | 311 | ||
| 312 | if (!dev || !desc) | 312 | if (!dev || !desc) |
| @@ -329,7 +329,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, | |||
| 329 | edev->dev.class = devfreq_event_class; | 329 | edev->dev.class = devfreq_event_class; |
| 330 | edev->dev.release = devfreq_event_release_edev; | 330 | edev->dev.release = devfreq_event_release_edev; |
| 331 | 331 | ||
| 332 | dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1); | 332 | dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); |
| 333 | ret = device_register(&edev->dev); | 333 | ret = device_register(&edev->dev); |
| 334 | if (ret < 0) { | 334 | if (ret < 0) { |
| 335 | put_device(&edev->dev); | 335 | put_device(&edev->dev); |
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 47206a21bb90..4aa72b5ed660 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c | |||
| @@ -130,7 +130,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq) | |||
| 130 | * @devfreq: the devfreq instance | 130 | * @devfreq: the devfreq instance |
| 131 | * @freq: the update target frequency | 131 | * @freq: the update target frequency |
| 132 | */ | 132 | */ |
| 133 | static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) | 133 | int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) |
| 134 | { | 134 | { |
| 135 | int lev, prev_lev, ret = 0; | 135 | int lev, prev_lev, ret = 0; |
| 136 | unsigned long cur_time; | 136 | unsigned long cur_time; |
| @@ -166,6 +166,7 @@ out: | |||
| 166 | devfreq->last_stat_updated = cur_time; | 166 | devfreq->last_stat_updated = cur_time; |
| 167 | return ret; | 167 | return ret; |
| 168 | } | 168 | } |
| 169 | EXPORT_SYMBOL(devfreq_update_status); | ||
| 169 | 170 | ||
| 170 | /** | 171 | /** |
| 171 | * find_devfreq_governor() - find devfreq governor from name | 172 | * find_devfreq_governor() - find devfreq governor from name |
| @@ -474,11 +475,15 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, | |||
| 474 | } | 475 | } |
| 475 | 476 | ||
| 476 | /** | 477 | /** |
| 477 | * _remove_devfreq() - Remove devfreq from the list and release its resources. | 478 | * devfreq_dev_release() - Callback for struct device to release the device. |
| 478 | * @devfreq: the devfreq struct | 479 | * @dev: the devfreq device |
| 480 | * | ||
| 481 | * Remove devfreq from the list and release its resources. | ||
| 479 | */ | 482 | */ |
| 480 | static void _remove_devfreq(struct devfreq *devfreq) | 483 | static void devfreq_dev_release(struct device *dev) |
| 481 | { | 484 | { |
| 485 | struct devfreq *devfreq = to_devfreq(dev); | ||
| 486 | |||
| 482 | mutex_lock(&devfreq_list_lock); | 487 | mutex_lock(&devfreq_list_lock); |
| 483 | if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { | 488 | if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { |
| 484 | mutex_unlock(&devfreq_list_lock); | 489 | mutex_unlock(&devfreq_list_lock); |
| @@ -500,19 +505,6 @@ static void _remove_devfreq(struct devfreq *devfreq) | |||
| 500 | } | 505 | } |
| 501 | 506 | ||
| 502 | /** | 507 | /** |
| 503 | * devfreq_dev_release() - Callback for struct device to release the device. | ||
| 504 | * @dev: the devfreq device | ||
| 505 | * | ||
| 506 | * This calls _remove_devfreq() if _remove_devfreq() is not called. | ||
| 507 | */ | ||
| 508 | static void devfreq_dev_release(struct device *dev) | ||
| 509 | { | ||
| 510 | struct devfreq *devfreq = to_devfreq(dev); | ||
| 511 | |||
| 512 | _remove_devfreq(devfreq); | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 516 | * devfreq_add_device() - Add devfreq feature to the device | 508 | * devfreq_add_device() - Add devfreq feature to the device |
| 517 | * @dev: the device to add devfreq feature. | 509 | * @dev: the device to add devfreq feature. |
| 518 | * @profile: device-specific profile to run devfreq. | 510 | * @profile: device-specific profile to run devfreq. |
| @@ -527,6 +519,7 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 527 | { | 519 | { |
| 528 | struct devfreq *devfreq; | 520 | struct devfreq *devfreq; |
| 529 | struct devfreq_governor *governor; | 521 | struct devfreq_governor *governor; |
| 522 | static atomic_t devfreq_no = ATOMIC_INIT(-1); | ||
| 530 | int err = 0; | 523 | int err = 0; |
| 531 | 524 | ||
| 532 | if (!dev || !profile || !governor_name) { | 525 | if (!dev || !profile || !governor_name) { |
| @@ -538,15 +531,14 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 538 | devfreq = find_device_devfreq(dev); | 531 | devfreq = find_device_devfreq(dev); |
| 539 | mutex_unlock(&devfreq_list_lock); | 532 | mutex_unlock(&devfreq_list_lock); |
| 540 | if (!IS_ERR(devfreq)) { | 533 | if (!IS_ERR(devfreq)) { |
| 541 | dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); | 534 | dev_err(dev, "%s: Unable to create devfreq for the device.\n", |
| 535 | __func__); | ||
| 542 | err = -EINVAL; | 536 | err = -EINVAL; |
| 543 | goto err_out; | 537 | goto err_out; |
| 544 | } | 538 | } |
| 545 | 539 | ||
| 546 | devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL); | 540 | devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL); |
| 547 | if (!devfreq) { | 541 | if (!devfreq) { |
| 548 | dev_err(dev, "%s: Unable to create devfreq for the device\n", | ||
| 549 | __func__); | ||
| 550 | err = -ENOMEM; | 542 | err = -ENOMEM; |
| 551 | goto err_out; | 543 | goto err_out; |
| 552 | } | 544 | } |
| @@ -569,18 +561,21 @@ struct devfreq *devfreq_add_device(struct device *dev, | |||
| 569 | mutex_lock(&devfreq->lock); | 561 | mutex_lock(&devfreq->lock); |
| 570 | } | 562 | } |
| 571 | 563 | ||
| 572 | dev_set_name(&devfreq->dev, "%s", dev_name(dev)); | 564 | dev_set_name(&devfreq->dev, "devfreq%d", |
| 565 | atomic_inc_return(&devfreq_no)); | ||
| 573 | err = device_register(&devfreq->dev); | 566 | err = device_register(&devfreq->dev); |
| 574 | if (err) { | 567 | if (err) { |
| 575 | mutex_unlock(&devfreq->lock); | 568 | mutex_unlock(&devfreq->lock); |
| 576 | goto err_out; | 569 | goto err_out; |
| 577 | } | 570 | } |
| 578 | 571 | ||
| 579 | devfreq->trans_table = devm_kzalloc(&devfreq->dev, sizeof(unsigned int) * | 572 | devfreq->trans_table = devm_kzalloc(&devfreq->dev, |
| 573 | sizeof(unsigned int) * | ||
| 580 | devfreq->profile->max_state * | 574 | devfreq->profile->max_state * |
| 581 | devfreq->profile->max_state, | 575 | devfreq->profile->max_state, |
| 582 | GFP_KERNEL); | 576 | GFP_KERNEL); |
| 583 | devfreq->time_in_state = devm_kzalloc(&devfreq->dev, sizeof(unsigned long) * | 577 | devfreq->time_in_state = devm_kzalloc(&devfreq->dev, |
| 578 | sizeof(unsigned long) * | ||
| 584 | devfreq->profile->max_state, | 579 | devfreq->profile->max_state, |
| 585 | GFP_KERNEL); | 580 | GFP_KERNEL); |
| 586 | devfreq->last_stat_updated = jiffies; | 581 | devfreq->last_stat_updated = jiffies; |
| @@ -939,6 +934,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, | |||
| 939 | if (df->governor == governor) { | 934 | if (df->governor == governor) { |
| 940 | ret = 0; | 935 | ret = 0; |
| 941 | goto out; | 936 | goto out; |
| 937 | } else if (df->governor->immutable || governor->immutable) { | ||
| 938 | ret = -EINVAL; | ||
| 939 | goto out; | ||
| 942 | } | 940 | } |
| 943 | 941 | ||
| 944 | if (df->governor) { | 942 | if (df->governor) { |
| @@ -968,13 +966,33 @@ static ssize_t available_governors_show(struct device *d, | |||
| 968 | struct device_attribute *attr, | 966 | struct device_attribute *attr, |
| 969 | char *buf) | 967 | char *buf) |
| 970 | { | 968 | { |
| 971 | struct devfreq_governor *tmp_governor; | 969 | struct devfreq *df = to_devfreq(d); |
| 972 | ssize_t count = 0; | 970 | ssize_t count = 0; |
| 973 | 971 | ||
| 974 | mutex_lock(&devfreq_list_lock); | 972 | mutex_lock(&devfreq_list_lock); |
| 975 | list_for_each_entry(tmp_governor, &devfreq_governor_list, node) | 973 | |
| 976 | count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), | 974 | /* |
| 977 | "%s ", tmp_governor->name); | 975 | * The devfreq with immutable governor (e.g., passive) shows |
| 976 | * only own governor. | ||
| 977 | */ | ||
| 978 | if (df->governor->immutable) { | ||
| 979 | count = scnprintf(&buf[count], DEVFREQ_NAME_LEN, | ||
| 980 | "%s ", df->governor_name); | ||
| 981 | /* | ||
| 982 | * The devfreq device shows the registered governor except for | ||
| 983 | * immutable governors such as passive governor . | ||
| 984 | */ | ||
| 985 | } else { | ||
| 986 | struct devfreq_governor *governor; | ||
| 987 | |||
| 988 | list_for_each_entry(governor, &devfreq_governor_list, node) { | ||
| 989 | if (governor->immutable) | ||
| 990 | continue; | ||
| 991 | count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), | ||
| 992 | "%s ", governor->name); | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 978 | mutex_unlock(&devfreq_list_lock); | 996 | mutex_unlock(&devfreq_list_lock); |
| 979 | 997 | ||
| 980 | /* Truncate the trailing space */ | 998 | /* Truncate the trailing space */ |
| @@ -995,7 +1013,7 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr, | |||
| 995 | 1013 | ||
| 996 | if (devfreq->profile->get_cur_freq && | 1014 | if (devfreq->profile->get_cur_freq && |
| 997 | !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) | 1015 | !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) |
| 998 | return sprintf(buf, "%lu\n", freq); | 1016 | return sprintf(buf, "%lu\n", freq); |
| 999 | 1017 | ||
| 1000 | return sprintf(buf, "%lu\n", devfreq->previous_freq); | 1018 | return sprintf(buf, "%lu\n", devfreq->previous_freq); |
| 1001 | } | 1019 | } |
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 107eb91a9415..9b7350935b73 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c | |||
| @@ -17,13 +17,13 @@ | |||
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/regmap.h> | ||
| 20 | #include <linux/suspend.h> | 21 | #include <linux/suspend.h> |
| 21 | #include <linux/devfreq-event.h> | 22 | #include <linux/devfreq-event.h> |
| 22 | 23 | ||
| 23 | #include "exynos-ppmu.h" | 24 | #include "exynos-ppmu.h" |
| 24 | 25 | ||
| 25 | struct exynos_ppmu_data { | 26 | struct exynos_ppmu_data { |
| 26 | void __iomem *base; | ||
| 27 | struct clk *clk; | 27 | struct clk *clk; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| @@ -33,6 +33,7 @@ struct exynos_ppmu { | |||
| 33 | unsigned int num_events; | 33 | unsigned int num_events; |
| 34 | 34 | ||
| 35 | struct device *dev; | 35 | struct device *dev; |
| 36 | struct regmap *regmap; | ||
| 36 | 37 | ||
| 37 | struct exynos_ppmu_data ppmu; | 38 | struct exynos_ppmu_data ppmu; |
| 38 | }; | 39 | }; |
| @@ -107,20 +108,28 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) | |||
| 107 | static int exynos_ppmu_disable(struct devfreq_event_dev *edev) | 108 | static int exynos_ppmu_disable(struct devfreq_event_dev *edev) |
| 108 | { | 109 | { |
| 109 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 110 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 111 | int ret; | ||
| 110 | u32 pmnc; | 112 | u32 pmnc; |
| 111 | 113 | ||
| 112 | /* Disable all counters */ | 114 | /* Disable all counters */ |
| 113 | __raw_writel(PPMU_CCNT_MASK | | 115 | ret = regmap_write(info->regmap, PPMU_CNTENC, |
| 114 | PPMU_PMCNT0_MASK | | 116 | PPMU_CCNT_MASK | |
| 115 | PPMU_PMCNT1_MASK | | 117 | PPMU_PMCNT0_MASK | |
| 116 | PPMU_PMCNT2_MASK | | 118 | PPMU_PMCNT1_MASK | |
| 117 | PPMU_PMCNT3_MASK, | 119 | PPMU_PMCNT2_MASK | |
| 118 | info->ppmu.base + PPMU_CNTENC); | 120 | PPMU_PMCNT3_MASK); |
| 121 | if (ret < 0) | ||
| 122 | return ret; | ||
| 119 | 123 | ||
| 120 | /* Disable PPMU */ | 124 | /* Disable PPMU */ |
| 121 | pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); | 125 | ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); |
| 126 | if (ret < 0) | ||
| 127 | return ret; | ||
| 128 | |||
| 122 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; | 129 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; |
| 123 | __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); | 130 | ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); |
| 131 | if (ret < 0) | ||
| 132 | return ret; | ||
| 124 | 133 | ||
| 125 | return 0; | 134 | return 0; |
| 126 | } | 135 | } |
| @@ -129,29 +138,42 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) | |||
| 129 | { | 138 | { |
| 130 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 139 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 131 | int id = exynos_ppmu_find_ppmu_id(edev); | 140 | int id = exynos_ppmu_find_ppmu_id(edev); |
| 141 | int ret; | ||
| 132 | u32 pmnc, cntens; | 142 | u32 pmnc, cntens; |
| 133 | 143 | ||
| 134 | if (id < 0) | 144 | if (id < 0) |
| 135 | return id; | 145 | return id; |
| 136 | 146 | ||
| 137 | /* Enable specific counter */ | 147 | /* Enable specific counter */ |
| 138 | cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); | 148 | ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens); |
| 149 | if (ret < 0) | ||
| 150 | return ret; | ||
| 151 | |||
| 139 | cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); | 152 | cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); |
| 140 | __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); | 153 | ret = regmap_write(info->regmap, PPMU_CNTENS, cntens); |
| 154 | if (ret < 0) | ||
| 155 | return ret; | ||
| 141 | 156 | ||
| 142 | /* Set the event of Read/Write data count */ | 157 | /* Set the event of Read/Write data count */ |
| 143 | __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, | 158 | ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id), |
| 144 | info->ppmu.base + PPMU_BEVTxSEL(id)); | 159 | PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT); |
| 160 | if (ret < 0) | ||
| 161 | return ret; | ||
| 145 | 162 | ||
| 146 | /* Reset cycle counter/performance counter and enable PPMU */ | 163 | /* Reset cycle counter/performance counter and enable PPMU */ |
| 147 | pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); | 164 | ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); |
| 165 | if (ret < 0) | ||
| 166 | return ret; | ||
| 167 | |||
| 148 | pmnc &= ~(PPMU_PMNC_ENABLE_MASK | 168 | pmnc &= ~(PPMU_PMNC_ENABLE_MASK |
| 149 | | PPMU_PMNC_COUNTER_RESET_MASK | 169 | | PPMU_PMNC_COUNTER_RESET_MASK |
| 150 | | PPMU_PMNC_CC_RESET_MASK); | 170 | | PPMU_PMNC_CC_RESET_MASK); |
| 151 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); | 171 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); |
| 152 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); | 172 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); |
| 153 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); | 173 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); |
| 154 | __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); | 174 | ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); |
| 175 | if (ret < 0) | ||
| 176 | return ret; | ||
| 155 | 177 | ||
| 156 | return 0; | 178 | return 0; |
| 157 | } | 179 | } |
| @@ -161,40 +183,64 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, | |||
| 161 | { | 183 | { |
| 162 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 184 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 163 | int id = exynos_ppmu_find_ppmu_id(edev); | 185 | int id = exynos_ppmu_find_ppmu_id(edev); |
| 164 | u32 pmnc, cntenc; | 186 | unsigned int total_count, load_count; |
| 187 | unsigned int pmcnt3_high, pmcnt3_low; | ||
| 188 | unsigned int pmnc, cntenc; | ||
| 189 | int ret; | ||
| 165 | 190 | ||
| 166 | if (id < 0) | 191 | if (id < 0) |
| 167 | return -EINVAL; | 192 | return -EINVAL; |
| 168 | 193 | ||
| 169 | /* Disable PPMU */ | 194 | /* Disable PPMU */ |
| 170 | pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); | 195 | ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); |
| 196 | if (ret < 0) | ||
| 197 | return ret; | ||
| 198 | |||
| 171 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; | 199 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; |
| 172 | __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); | 200 | ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); |
| 201 | if (ret < 0) | ||
| 202 | return ret; | ||
| 173 | 203 | ||
| 174 | /* Read cycle count */ | 204 | /* Read cycle count */ |
| 175 | edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); | 205 | ret = regmap_read(info->regmap, PPMU_CCNT, &total_count); |
| 206 | if (ret < 0) | ||
| 207 | return ret; | ||
| 208 | edata->total_count = total_count; | ||
| 176 | 209 | ||
| 177 | /* Read performance count */ | 210 | /* Read performance count */ |
| 178 | switch (id) { | 211 | switch (id) { |
| 179 | case PPMU_PMNCNT0: | 212 | case PPMU_PMNCNT0: |
| 180 | case PPMU_PMNCNT1: | 213 | case PPMU_PMNCNT1: |
| 181 | case PPMU_PMNCNT2: | 214 | case PPMU_PMNCNT2: |
| 182 | edata->load_count | 215 | ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count); |
| 183 | = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); | 216 | if (ret < 0) |
| 217 | return ret; | ||
| 218 | edata->load_count = load_count; | ||
| 184 | break; | 219 | break; |
| 185 | case PPMU_PMNCNT3: | 220 | case PPMU_PMNCNT3: |
| 186 | edata->load_count = | 221 | ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high); |
| 187 | ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) | 222 | if (ret < 0) |
| 188 | | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); | 223 | return ret; |
| 224 | |||
| 225 | ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low); | ||
| 226 | if (ret < 0) | ||
| 227 | return ret; | ||
| 228 | |||
| 229 | edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low); | ||
| 189 | break; | 230 | break; |
| 190 | default: | 231 | default: |
| 191 | return -EINVAL; | 232 | return -EINVAL; |
| 192 | } | 233 | } |
| 193 | 234 | ||
| 194 | /* Disable specific counter */ | 235 | /* Disable specific counter */ |
| 195 | cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); | 236 | ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc); |
| 237 | if (ret < 0) | ||
| 238 | return ret; | ||
| 239 | |||
| 196 | cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); | 240 | cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); |
| 197 | __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); | 241 | ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc); |
| 242 | if (ret < 0) | ||
| 243 | return ret; | ||
| 198 | 244 | ||
| 199 | dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, | 245 | dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, |
| 200 | edata->load_count, edata->total_count); | 246 | edata->load_count, edata->total_count); |
| @@ -214,36 +260,93 @@ static const struct devfreq_event_ops exynos_ppmu_ops = { | |||
| 214 | static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) | 260 | static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) |
| 215 | { | 261 | { |
| 216 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 262 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 263 | int ret; | ||
| 217 | u32 pmnc, clear; | 264 | u32 pmnc, clear; |
| 218 | 265 | ||
| 219 | /* Disable all counters */ | 266 | /* Disable all counters */ |
| 220 | clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK | 267 | clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK |
| 221 | | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); | 268 | | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); |
| 269 | ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear); | ||
| 270 | if (ret < 0) | ||
| 271 | return ret; | ||
| 272 | |||
| 273 | ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear); | ||
| 274 | if (ret < 0) | ||
| 275 | return ret; | ||
| 276 | |||
| 277 | ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear); | ||
| 278 | if (ret < 0) | ||
| 279 | return ret; | ||
| 280 | |||
| 281 | ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear); | ||
| 282 | if (ret < 0) | ||
| 283 | return ret; | ||
| 284 | |||
| 285 | ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0); | ||
| 286 | if (ret < 0) | ||
| 287 | return ret; | ||
| 288 | |||
| 289 | ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0); | ||
| 290 | if (ret < 0) | ||
| 291 | return ret; | ||
| 292 | |||
| 293 | ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0); | ||
| 294 | if (ret < 0) | ||
| 295 | return ret; | ||
| 296 | |||
| 297 | ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0); | ||
| 298 | if (ret < 0) | ||
| 299 | return ret; | ||
| 300 | |||
| 301 | ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0); | ||
| 302 | if (ret < 0) | ||
| 303 | return ret; | ||
| 304 | |||
| 305 | ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0); | ||
| 306 | if (ret < 0) | ||
| 307 | return ret; | ||
| 308 | |||
| 309 | ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0); | ||
| 310 | if (ret < 0) | ||
| 311 | return ret; | ||
| 222 | 312 | ||
| 223 | __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); | 313 | ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0); |
| 224 | __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); | 314 | if (ret < 0) |
| 225 | __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); | 315 | return ret; |
| 226 | __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); | 316 | |
| 227 | 317 | ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0); | |
| 228 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); | 318 | if (ret < 0) |
| 229 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); | 319 | return ret; |
| 230 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); | 320 | |
| 231 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); | 321 | ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0); |
| 232 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); | 322 | if (ret < 0) |
| 233 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); | 323 | return ret; |
| 234 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); | 324 | |
| 235 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); | 325 | ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0); |
| 236 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); | 326 | if (ret < 0) |
| 237 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); | 327 | return ret; |
| 238 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); | 328 | |
| 239 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); | 329 | ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0); |
| 240 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); | 330 | if (ret < 0) |
| 241 | __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); | 331 | return ret; |
| 332 | |||
| 333 | ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0); | ||
| 334 | if (ret < 0) | ||
| 335 | return ret; | ||
| 336 | |||
| 337 | ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0); | ||
| 338 | if (ret < 0) | ||
| 339 | return ret; | ||
| 242 | 340 | ||
| 243 | /* Disable PPMU */ | 341 | /* Disable PPMU */ |
| 244 | pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); | 342 | ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); |
| 343 | if (ret < 0) | ||
| 344 | return ret; | ||
| 345 | |||
| 245 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; | 346 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; |
| 246 | __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); | 347 | ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); |
| 348 | if (ret < 0) | ||
| 349 | return ret; | ||
| 247 | 350 | ||
| 248 | return 0; | 351 | return 0; |
| 249 | } | 352 | } |
| @@ -251,30 +354,43 @@ static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) | |||
| 251 | static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) | 354 | static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) |
| 252 | { | 355 | { |
| 253 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 356 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 357 | unsigned int pmnc, cntens; | ||
| 254 | int id = exynos_ppmu_find_ppmu_id(edev); | 358 | int id = exynos_ppmu_find_ppmu_id(edev); |
| 255 | u32 pmnc, cntens; | 359 | int ret; |
| 256 | 360 | ||
| 257 | /* Enable all counters */ | 361 | /* Enable all counters */ |
| 258 | cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); | 362 | ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens); |
| 363 | if (ret < 0) | ||
| 364 | return ret; | ||
| 365 | |||
| 259 | cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); | 366 | cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); |
| 260 | __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); | 367 | ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens); |
| 368 | if (ret < 0) | ||
| 369 | return ret; | ||
| 261 | 370 | ||
| 262 | /* Set the event of Read/Write data count */ | 371 | /* Set the event of Read/Write data count */ |
| 263 | switch (id) { | 372 | switch (id) { |
| 264 | case PPMU_PMNCNT0: | 373 | case PPMU_PMNCNT0: |
| 265 | case PPMU_PMNCNT1: | 374 | case PPMU_PMNCNT1: |
| 266 | case PPMU_PMNCNT2: | 375 | case PPMU_PMNCNT2: |
| 267 | __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, | 376 | ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), |
| 268 | info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); | 377 | PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT); |
| 378 | if (ret < 0) | ||
| 379 | return ret; | ||
| 269 | break; | 380 | break; |
| 270 | case PPMU_PMNCNT3: | 381 | case PPMU_PMNCNT3: |
| 271 | __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, | 382 | ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), |
| 272 | info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); | 383 | PPMU_V2_EVT3_RW_DATA_CNT); |
| 384 | if (ret < 0) | ||
| 385 | return ret; | ||
| 273 | break; | 386 | break; |
| 274 | } | 387 | } |
| 275 | 388 | ||
| 276 | /* Reset cycle counter/performance counter and enable PPMU */ | 389 | /* Reset cycle counter/performance counter and enable PPMU */ |
| 277 | pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); | 390 | ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); |
| 391 | if (ret < 0) | ||
| 392 | return ret; | ||
| 393 | |||
| 278 | pmnc &= ~(PPMU_PMNC_ENABLE_MASK | 394 | pmnc &= ~(PPMU_PMNC_ENABLE_MASK |
| 279 | | PPMU_PMNC_COUNTER_RESET_MASK | 395 | | PPMU_PMNC_COUNTER_RESET_MASK |
| 280 | | PPMU_PMNC_CC_RESET_MASK | 396 | | PPMU_PMNC_CC_RESET_MASK |
| @@ -284,7 +400,10 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) | |||
| 284 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); | 400 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); |
| 285 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); | 401 | pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); |
| 286 | pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); | 402 | pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); |
| 287 | __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); | 403 | |
| 404 | ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); | ||
| 405 | if (ret < 0) | ||
| 406 | return ret; | ||
| 288 | 407 | ||
| 289 | return 0; | 408 | return 0; |
| 290 | } | 409 | } |
| @@ -294,37 +413,61 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, | |||
| 294 | { | 413 | { |
| 295 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); | 414 | struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); |
| 296 | int id = exynos_ppmu_find_ppmu_id(edev); | 415 | int id = exynos_ppmu_find_ppmu_id(edev); |
| 297 | u32 pmnc, cntenc; | 416 | int ret; |
| 298 | u32 pmcnt_high, pmcnt_low; | 417 | unsigned int pmnc, cntenc; |
| 299 | u64 load_count = 0; | 418 | unsigned int pmcnt_high, pmcnt_low; |
| 419 | unsigned int total_count, count; | ||
| 420 | unsigned long load_count = 0; | ||
| 300 | 421 | ||
| 301 | /* Disable PPMU */ | 422 | /* Disable PPMU */ |
| 302 | pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); | 423 | ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); |
| 424 | if (ret < 0) | ||
| 425 | return ret; | ||
| 426 | |||
| 303 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; | 427 | pmnc &= ~PPMU_PMNC_ENABLE_MASK; |
| 304 | __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); | 428 | ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); |
| 429 | if (ret < 0) | ||
| 430 | return ret; | ||
| 305 | 431 | ||
| 306 | /* Read cycle count and performance count */ | 432 | /* Read cycle count and performance count */ |
| 307 | edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); | 433 | ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count); |
| 434 | if (ret < 0) | ||
| 435 | return ret; | ||
| 436 | edata->total_count = total_count; | ||
| 308 | 437 | ||
| 309 | switch (id) { | 438 | switch (id) { |
| 310 | case PPMU_PMNCNT0: | 439 | case PPMU_PMNCNT0: |
| 311 | case PPMU_PMNCNT1: | 440 | case PPMU_PMNCNT1: |
| 312 | case PPMU_PMNCNT2: | 441 | case PPMU_PMNCNT2: |
| 313 | load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); | 442 | ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count); |
| 443 | if (ret < 0) | ||
| 444 | return ret; | ||
| 445 | load_count = count; | ||
| 314 | break; | 446 | break; |
| 315 | case PPMU_PMNCNT3: | 447 | case PPMU_PMNCNT3: |
| 316 | pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); | 448 | ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH, |
| 317 | pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); | 449 | &pmcnt_high); |
| 318 | load_count = ((u64)((pmcnt_high & 0xff)) << 32) | 450 | if (ret < 0) |
| 319 | + (u64)pmcnt_low; | 451 | return ret; |
| 452 | |||
| 453 | ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low); | ||
| 454 | if (ret < 0) | ||
| 455 | return ret; | ||
| 456 | |||
| 457 | load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low; | ||
| 320 | break; | 458 | break; |
| 321 | } | 459 | } |
| 322 | edata->load_count = load_count; | 460 | edata->load_count = load_count; |
| 323 | 461 | ||
| 324 | /* Disable all counters */ | 462 | /* Disable all counters */ |
| 325 | cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); | 463 | ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc); |
| 464 | if (ret < 0) | ||
| 465 | return 0; | ||
| 466 | |||
| 326 | cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); | 467 | cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); |
| 327 | __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); | 468 | ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc); |
| 469 | if (ret < 0) | ||
| 470 | return ret; | ||
| 328 | 471 | ||
| 329 | dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, | 472 | dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, |
| 330 | edata->load_count, edata->total_count); | 473 | edata->load_count, edata->total_count); |
| @@ -411,10 +554,19 @@ static int of_get_devfreq_events(struct device_node *np, | |||
| 411 | return 0; | 554 | return 0; |
| 412 | } | 555 | } |
| 413 | 556 | ||
| 414 | static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) | 557 | static struct regmap_config exynos_ppmu_regmap_config = { |
| 558 | .reg_bits = 32, | ||
| 559 | .val_bits = 32, | ||
| 560 | .reg_stride = 4, | ||
| 561 | }; | ||
| 562 | |||
| 563 | static int exynos_ppmu_parse_dt(struct platform_device *pdev, | ||
| 564 | struct exynos_ppmu *info) | ||
| 415 | { | 565 | { |
| 416 | struct device *dev = info->dev; | 566 | struct device *dev = info->dev; |
| 417 | struct device_node *np = dev->of_node; | 567 | struct device_node *np = dev->of_node; |
| 568 | struct resource *res; | ||
| 569 | void __iomem *base; | ||
| 418 | int ret = 0; | 570 | int ret = 0; |
| 419 | 571 | ||
| 420 | if (!np) { | 572 | if (!np) { |
| @@ -423,10 +575,17 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) | |||
| 423 | } | 575 | } |
| 424 | 576 | ||
| 425 | /* Maps the memory mapped IO to control PPMU register */ | 577 | /* Maps the memory mapped IO to control PPMU register */ |
| 426 | info->ppmu.base = of_iomap(np, 0); | 578 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 427 | if (IS_ERR_OR_NULL(info->ppmu.base)) { | 579 | base = devm_ioremap_resource(dev, res); |
| 428 | dev_err(dev, "failed to map memory region\n"); | 580 | if (IS_ERR(base)) |
| 429 | return -ENOMEM; | 581 | return PTR_ERR(base); |
| 582 | |||
| 583 | exynos_ppmu_regmap_config.max_register = resource_size(res) - 4; | ||
| 584 | info->regmap = devm_regmap_init_mmio(dev, base, | ||
| 585 | &exynos_ppmu_regmap_config); | ||
| 586 | if (IS_ERR(info->regmap)) { | ||
| 587 | dev_err(dev, "failed to initialize regmap\n"); | ||
| 588 | return PTR_ERR(info->regmap); | ||
| 430 | } | 589 | } |
| 431 | 590 | ||
| 432 | info->ppmu.clk = devm_clk_get(dev, "ppmu"); | 591 | info->ppmu.clk = devm_clk_get(dev, "ppmu"); |
| @@ -438,15 +597,10 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) | |||
| 438 | ret = of_get_devfreq_events(np, info); | 597 | ret = of_get_devfreq_events(np, info); |
| 439 | if (ret < 0) { | 598 | if (ret < 0) { |
| 440 | dev_err(dev, "failed to parse exynos ppmu dt node\n"); | 599 | dev_err(dev, "failed to parse exynos ppmu dt node\n"); |
| 441 | goto err; | 600 | return ret; |
| 442 | } | 601 | } |
| 443 | 602 | ||
| 444 | return 0; | 603 | return 0; |
| 445 | |||
| 446 | err: | ||
| 447 | iounmap(info->ppmu.base); | ||
| 448 | |||
| 449 | return ret; | ||
| 450 | } | 604 | } |
| 451 | 605 | ||
| 452 | static int exynos_ppmu_probe(struct platform_device *pdev) | 606 | static int exynos_ppmu_probe(struct platform_device *pdev) |
| @@ -463,7 +617,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) | |||
| 463 | info->dev = &pdev->dev; | 617 | info->dev = &pdev->dev; |
| 464 | 618 | ||
| 465 | /* Parse dt data to get resource */ | 619 | /* Parse dt data to get resource */ |
| 466 | ret = exynos_ppmu_parse_dt(info); | 620 | ret = exynos_ppmu_parse_dt(pdev, info); |
| 467 | if (ret < 0) { | 621 | if (ret < 0) { |
| 468 | dev_err(&pdev->dev, | 622 | dev_err(&pdev->dev, |
| 469 | "failed to parse devicetree for resource\n"); | 623 | "failed to parse devicetree for resource\n"); |
| @@ -476,8 +630,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) | |||
| 476 | if (!info->edev) { | 630 | if (!info->edev) { |
| 477 | dev_err(&pdev->dev, | 631 | dev_err(&pdev->dev, |
| 478 | "failed to allocate memory devfreq-event devices\n"); | 632 | "failed to allocate memory devfreq-event devices\n"); |
| 479 | ret = -ENOMEM; | 633 | return -ENOMEM; |
| 480 | goto err; | ||
| 481 | } | 634 | } |
| 482 | edev = info->edev; | 635 | edev = info->edev; |
| 483 | platform_set_drvdata(pdev, info); | 636 | platform_set_drvdata(pdev, info); |
| @@ -488,17 +641,16 @@ static int exynos_ppmu_probe(struct platform_device *pdev) | |||
| 488 | ret = PTR_ERR(edev[i]); | 641 | ret = PTR_ERR(edev[i]); |
| 489 | dev_err(&pdev->dev, | 642 | dev_err(&pdev->dev, |
| 490 | "failed to add devfreq-event device\n"); | 643 | "failed to add devfreq-event device\n"); |
| 491 | goto err; | 644 | return PTR_ERR(edev[i]); |
| 492 | } | 645 | } |
| 646 | |||
| 647 | pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n", | ||
| 648 | dev_name(&pdev->dev), desc[i].name); | ||
| 493 | } | 649 | } |
| 494 | 650 | ||
| 495 | clk_prepare_enable(info->ppmu.clk); | 651 | clk_prepare_enable(info->ppmu.clk); |
| 496 | 652 | ||
| 497 | return 0; | 653 | return 0; |
| 498 | err: | ||
| 499 | iounmap(info->ppmu.base); | ||
| 500 | |||
| 501 | return ret; | ||
| 502 | } | 654 | } |
| 503 | 655 | ||
| 504 | static int exynos_ppmu_remove(struct platform_device *pdev) | 656 | static int exynos_ppmu_remove(struct platform_device *pdev) |
| @@ -506,7 +658,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev) | |||
| 506 | struct exynos_ppmu *info = platform_get_drvdata(pdev); | 658 | struct exynos_ppmu *info = platform_get_drvdata(pdev); |
| 507 | 659 | ||
| 508 | clk_disable_unprepare(info->ppmu.clk); | 660 | clk_disable_unprepare(info->ppmu.clk); |
| 509 | iounmap(info->ppmu.base); | ||
| 510 | 661 | ||
| 511 | return 0; | 662 | return 0; |
| 512 | } | 663 | } |
diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c index 9af86f46fbec..e0d1f4ac1740 100644 --- a/drivers/devfreq/exynos-bus.c +++ b/drivers/devfreq/exynos-bus.c | |||
| @@ -147,8 +147,8 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) | |||
| 147 | } | 147 | } |
| 148 | bus->curr_freq = new_freq; | 148 | bus->curr_freq = new_freq; |
| 149 | 149 | ||
| 150 | dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", | 150 | dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", |
| 151 | old_freq/1000, new_freq/1000); | 151 | old_freq, new_freq, clk_get_rate(bus->clk)); |
| 152 | out: | 152 | out: |
| 153 | mutex_unlock(&bus->lock); | 153 | mutex_unlock(&bus->lock); |
| 154 | 154 | ||
| @@ -241,8 +241,8 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq, | |||
| 241 | *freq = new_freq; | 241 | *freq = new_freq; |
| 242 | bus->curr_freq = new_freq; | 242 | bus->curr_freq = new_freq; |
| 243 | 243 | ||
| 244 | dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", | 244 | dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", |
| 245 | old_freq/1000, new_freq/1000); | 245 | old_freq, new_freq, clk_get_rate(bus->clk)); |
| 246 | out: | 246 | out: |
| 247 | mutex_unlock(&bus->lock); | 247 | mutex_unlock(&bus->lock); |
| 248 | 248 | ||
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index fad7d6321978..71576b8bdfef 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h | |||
| @@ -38,4 +38,6 @@ extern void devfreq_interval_update(struct devfreq *devfreq, | |||
| 38 | extern int devfreq_add_governor(struct devfreq_governor *governor); | 38 | extern int devfreq_add_governor(struct devfreq_governor *governor); |
| 39 | extern int devfreq_remove_governor(struct devfreq_governor *governor); | 39 | extern int devfreq_remove_governor(struct devfreq_governor *governor); |
| 40 | 40 | ||
| 41 | extern int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); | ||
| 42 | |||
| 41 | #endif /* _GOVERNOR_H */ | 43 | #endif /* _GOVERNOR_H */ |
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c index 9ef46e2592c4..5be96b2249e7 100644 --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c | |||
| @@ -112,6 +112,11 @@ static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq) | |||
| 112 | if (ret < 0) | 112 | if (ret < 0) |
| 113 | goto out; | 113 | goto out; |
| 114 | 114 | ||
| 115 | if (devfreq->profile->freq_table | ||
| 116 | && (devfreq_update_status(devfreq, freq))) | ||
| 117 | dev_err(&devfreq->dev, | ||
| 118 | "Couldn't update frequency transition information.\n"); | ||
| 119 | |||
| 115 | devfreq->previous_freq = freq; | 120 | devfreq->previous_freq = freq; |
| 116 | 121 | ||
| 117 | out: | 122 | out: |
| @@ -179,6 +184,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq, | |||
| 179 | 184 | ||
| 180 | static struct devfreq_governor devfreq_passive = { | 185 | static struct devfreq_governor devfreq_passive = { |
| 181 | .name = "passive", | 186 | .name = "passive", |
| 187 | .immutable = 1, | ||
| 182 | .get_target_freq = devfreq_passive_get_target_freq, | 188 | .get_target_freq = devfreq_passive_get_target_freq, |
| 183 | .event_handler = devfreq_passive_event_handler, | 189 | .event_handler = devfreq_passive_event_handler, |
| 184 | }; | 190 | }; |
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 35de6e83c1fe..176976068bcd 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/drivers/devfreq/governor_simpleondemand.c | 2 | * linux/drivers/devfreq/governor_userspace.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Samsung Electronics | 4 | * Copyright (C) 2011 Samsung Electronics |
| 5 | * MyungJoo Ham <myungjoo.ham@samsung.com> | 5 | * MyungJoo Ham <myungjoo.ham@samsung.com> |
| @@ -50,7 +50,6 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr, | |||
| 50 | unsigned long wanted; | 50 | unsigned long wanted; |
| 51 | int err = 0; | 51 | int err = 0; |
| 52 | 52 | ||
| 53 | |||
| 54 | mutex_lock(&devfreq->lock); | 53 | mutex_lock(&devfreq->lock); |
| 55 | data = devfreq->data; | 54 | data = devfreq->data; |
| 56 | 55 | ||
| @@ -112,7 +111,13 @@ out: | |||
| 112 | 111 | ||
| 113 | static void userspace_exit(struct devfreq *devfreq) | 112 | static void userspace_exit(struct devfreq *devfreq) |
| 114 | { | 113 | { |
| 115 | sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); | 114 | /* |
| 115 | * Remove the sysfs entry, unless this is being called after | ||
| 116 | * device_del(), which should have done this already via kobject_del(). | ||
| 117 | */ | ||
| 118 | if (devfreq->dev.kobj.sd) | ||
| 119 | sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); | ||
| 120 | |||
| 116 | kfree(devfreq->data); | 121 | kfree(devfreq->data); |
| 117 | devfreq->data = NULL; | 122 | devfreq->data = NULL; |
| 118 | } | 123 | } |
