diff options
| author | Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> | 2014-03-21 13:31:44 -0400 |
|---|---|---|
| committer | MyungJoo Ham <myungjoo.ham@samsung.com> | 2014-05-24 04:56:40 -0400 |
| commit | f4145270894ba3e4edc120d8940f515a2cd75b4c (patch) | |
| tree | aa74694e8351d40162cd34a8a8e6c659b1b31097 /drivers/devfreq | |
| parent | ba778b374d55945a190f01f7a741c9657ae5f519 (diff) | |
PM / devfreq: exynos4: introduce struct busfreq_ppmu_data
This is a preparation for making more PPMU code common for
EXYNOS devfreq drivers.
There should be no functional changes caused by this patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/devfreq')
| -rw-r--r-- | drivers/devfreq/exynos/exynos4_bus.c | 74 |
1 files changed, 46 insertions, 28 deletions
diff --git a/drivers/devfreq/exynos/exynos4_bus.c b/drivers/devfreq/exynos/exynos4_bus.c index 228c658c0e8c..d99ef9e80517 100644 --- a/drivers/devfreq/exynos/exynos4_bus.c +++ b/drivers/devfreq/exynos/exynos4_bus.c | |||
| @@ -75,6 +75,11 @@ struct busfreq_opp_info { | |||
| 75 | unsigned long volt; | 75 | unsigned long volt; |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | struct busfreq_ppmu_data { | ||
| 79 | struct exynos_ppmu *ppmu; | ||
| 80 | int ppmu_end; | ||
| 81 | }; | ||
| 82 | |||
| 78 | struct busfreq_data { | 83 | struct busfreq_data { |
| 79 | enum exynos4_busf_type type; | 84 | enum exynos4_busf_type type; |
| 80 | struct device *dev; | 85 | struct device *dev; |
| @@ -83,7 +88,7 @@ struct busfreq_data { | |||
| 83 | struct regulator *vdd_int; | 88 | struct regulator *vdd_int; |
| 84 | struct regulator *vdd_mif; /* Exynos4412/4212 only */ | 89 | struct regulator *vdd_mif; /* Exynos4412/4212 only */ |
| 85 | struct busfreq_opp_info curr_oppinfo; | 90 | struct busfreq_opp_info curr_oppinfo; |
| 86 | struct exynos_ppmu ppmu[PPMU_END]; | 91 | struct busfreq_ppmu_data ppmu_data; |
| 87 | 92 | ||
| 88 | struct notifier_block pm_notifier; | 93 | struct notifier_block pm_notifier; |
| 89 | struct mutex lock; | 94 | struct mutex lock; |
| @@ -510,47 +515,47 @@ static int exynos4x12_set_busclk(struct busfreq_data *data, | |||
| 510 | return 0; | 515 | return 0; |
| 511 | } | 516 | } |
| 512 | 517 | ||
| 513 | static void busfreq_mon_reset(struct busfreq_data *data) | 518 | static void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data) |
| 514 | { | 519 | { |
| 515 | unsigned int i; | 520 | unsigned int i; |
| 516 | 521 | ||
| 517 | for (i = 0; i < PPMU_END; i++) { | 522 | for (i = 0; i < ppmu_data->ppmu_end; i++) { |
| 518 | void __iomem *ppmu_base = data->ppmu[i].hw_base; | 523 | void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base; |
| 519 | 524 | ||
| 520 | /* Reset the performance and cycle counters */ | 525 | /* Reset the performance and cycle counters */ |
| 521 | exynos_ppmu_reset(ppmu_base); | 526 | exynos_ppmu_reset(ppmu_base); |
| 522 | 527 | ||
| 523 | /* Setup count registers to monitor read/write transactions */ | 528 | /* Setup count registers to monitor read/write transactions */ |
| 524 | data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT; | 529 | ppmu_data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT; |
| 525 | exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3, | 530 | exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3, |
| 526 | data->ppmu[i].event[PPMU_PMNCNT3]); | 531 | ppmu_data->ppmu[i].event[PPMU_PMNCNT3]); |
| 527 | 532 | ||
| 528 | exynos_ppmu_start(ppmu_base); | 533 | exynos_ppmu_start(ppmu_base); |
| 529 | } | 534 | } |
| 530 | } | 535 | } |
| 531 | 536 | ||
| 532 | static void exynos4_read_ppmu(struct busfreq_data *data) | 537 | static void exynos4_read_ppmu(struct busfreq_ppmu_data *ppmu_data) |
| 533 | { | 538 | { |
| 534 | int i, j; | 539 | int i, j; |
| 535 | 540 | ||
| 536 | for (i = 0; i < PPMU_END; i++) { | 541 | for (i = 0; i < ppmu_data->ppmu_end; i++) { |
| 537 | void __iomem *ppmu_base = data->ppmu[i].hw_base; | 542 | void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base; |
| 538 | 543 | ||
| 539 | exynos_ppmu_stop(ppmu_base); | 544 | exynos_ppmu_stop(ppmu_base); |
| 540 | 545 | ||
| 541 | /* Update local data from PPMU */ | 546 | /* Update local data from PPMU */ |
| 542 | data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT); | 547 | ppmu_data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT); |
| 543 | 548 | ||
| 544 | for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) { | 549 | for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) { |
| 545 | if (data->ppmu[i].event[j] == 0) | 550 | if (ppmu_data->ppmu[i].event[j] == 0) |
| 546 | data->ppmu[i].count[j] = 0; | 551 | ppmu_data->ppmu[i].count[j] = 0; |
| 547 | else | 552 | else |
| 548 | data->ppmu[i].count[j] = | 553 | ppmu_data->ppmu[i].count[j] = |
| 549 | exynos_ppmu_read(ppmu_base, j); | 554 | exynos_ppmu_read(ppmu_base, j); |
| 550 | } | 555 | } |
| 551 | } | 556 | } |
| 552 | 557 | ||
| 553 | busfreq_mon_reset(data); | 558 | busfreq_mon_reset(ppmu_data); |
| 554 | } | 559 | } |
| 555 | 560 | ||
| 556 | static int exynos4x12_get_intspec(unsigned long mifclk) | 561 | static int exynos4x12_get_intspec(unsigned long mifclk) |
| @@ -676,16 +681,16 @@ out: | |||
| 676 | return err; | 681 | return err; |
| 677 | } | 682 | } |
| 678 | 683 | ||
| 679 | static int exynos4_get_busier_ppmu(struct busfreq_data *data) | 684 | static int exynos4_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data) |
| 680 | { | 685 | { |
| 681 | int i, j; | 686 | int i, j; |
| 682 | int busy = 0; | 687 | int busy = 0; |
| 683 | unsigned int temp = 0; | 688 | unsigned int temp = 0; |
| 684 | 689 | ||
| 685 | for (i = 0; i < PPMU_END; i++) { | 690 | for (i = 0; i < ppmu_data->ppmu_end; i++) { |
| 686 | for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) { | 691 | for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) { |
| 687 | if (data->ppmu[i].count[j] > temp) { | 692 | if (ppmu_data->ppmu[i].count[j] > temp) { |
| 688 | temp = data->ppmu[i].count[j]; | 693 | temp = ppmu_data->ppmu[i].count[j]; |
| 689 | busy = i; | 694 | busy = i; |
| 690 | } | 695 | } |
| 691 | } | 696 | } |
| @@ -698,20 +703,21 @@ static int exynos4_bus_get_dev_status(struct device *dev, | |||
| 698 | struct devfreq_dev_status *stat) | 703 | struct devfreq_dev_status *stat) |
| 699 | { | 704 | { |
| 700 | struct busfreq_data *data = dev_get_drvdata(dev); | 705 | struct busfreq_data *data = dev_get_drvdata(dev); |
| 706 | struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data; | ||
| 701 | int busier; | 707 | int busier; |
| 702 | 708 | ||
| 703 | exynos4_read_ppmu(data); | 709 | exynos4_read_ppmu(ppmu_data); |
| 704 | busier = exynos4_get_busier_ppmu(data); | 710 | busier = exynos4_get_busier_ppmu(ppmu_data); |
| 705 | stat->current_frequency = data->curr_oppinfo.rate; | 711 | stat->current_frequency = data->curr_oppinfo.rate; |
| 706 | 712 | ||
| 707 | /* Number of cycles spent on memory access */ | 713 | /* Number of cycles spent on memory access */ |
| 708 | stat->busy_time = data->ppmu[busier].count[PPMU_PMNCNT3]; | 714 | stat->busy_time = ppmu_data->ppmu[busier].count[PPMU_PMNCNT3]; |
| 709 | stat->busy_time *= 100 / BUS_SATURATION_RATIO; | 715 | stat->busy_time *= 100 / BUS_SATURATION_RATIO; |
| 710 | stat->total_time = data->ppmu[busier].ccnt; | 716 | stat->total_time = ppmu_data->ppmu[busier].ccnt; |
| 711 | 717 | ||
| 712 | /* If the counters have overflown, retry */ | 718 | /* If the counters have overflown, retry */ |
| 713 | if (data->ppmu[busier].ccnt_overflow || | 719 | if (ppmu_data->ppmu[busier].ccnt_overflow || |
| 714 | data->ppmu[busier].count_overflow[0]) | 720 | ppmu_data->ppmu[busier].count_overflow[0]) |
| 715 | return -EAGAIN; | 721 | return -EAGAIN; |
| 716 | 722 | ||
| 717 | return 0; | 723 | return 0; |
| @@ -966,6 +972,7 @@ unlock: | |||
| 966 | static int exynos4_busfreq_probe(struct platform_device *pdev) | 972 | static int exynos4_busfreq_probe(struct platform_device *pdev) |
| 967 | { | 973 | { |
| 968 | struct busfreq_data *data; | 974 | struct busfreq_data *data; |
| 975 | struct busfreq_ppmu_data *ppmu_data; | ||
| 969 | struct dev_pm_opp *opp; | 976 | struct dev_pm_opp *opp; |
| 970 | struct device *dev = &pdev->dev; | 977 | struct device *dev = &pdev->dev; |
| 971 | int err = 0; | 978 | int err = 0; |
| @@ -976,9 +983,19 @@ static int exynos4_busfreq_probe(struct platform_device *pdev) | |||
| 976 | return -ENOMEM; | 983 | return -ENOMEM; |
| 977 | } | 984 | } |
| 978 | 985 | ||
| 986 | ppmu_data = &data->ppmu_data; | ||
| 987 | ppmu_data->ppmu_end = PPMU_END; | ||
| 988 | ppmu_data->ppmu = devm_kzalloc(dev, | ||
| 989 | sizeof(struct exynos_ppmu) * PPMU_END, | ||
| 990 | GFP_KERNEL); | ||
| 991 | if (!ppmu_data->ppmu) { | ||
| 992 | dev_err(dev, "Failed to allocate memory for exynos_ppmu\n"); | ||
| 993 | return -ENOMEM; | ||
| 994 | } | ||
| 995 | |||
| 979 | data->type = pdev->id_entry->driver_data; | 996 | data->type = pdev->id_entry->driver_data; |
| 980 | data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0; | 997 | ppmu_data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0; |
| 981 | data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1; | 998 | ppmu_data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1; |
| 982 | data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event; | 999 | data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event; |
| 983 | data->dev = dev; | 1000 | data->dev = dev; |
| 984 | mutex_init(&data->lock); | 1001 | mutex_init(&data->lock); |
| @@ -1037,7 +1054,7 @@ static int exynos4_busfreq_probe(struct platform_device *pdev) | |||
| 1037 | * Start PPMU (Performance Profiling Monitoring Unit) to check | 1054 | * Start PPMU (Performance Profiling Monitoring Unit) to check |
| 1038 | * utilization of each IP in the Exynos4 SoC. | 1055 | * utilization of each IP in the Exynos4 SoC. |
| 1039 | */ | 1056 | */ |
| 1040 | busfreq_mon_reset(data); | 1057 | busfreq_mon_reset(ppmu_data); |
| 1041 | 1058 | ||
| 1042 | /* Register opp_notifier for Exynos4 busfreq */ | 1059 | /* Register opp_notifier for Exynos4 busfreq */ |
| 1043 | err = devfreq_register_opp_notifier(dev, data->devfreq); | 1060 | err = devfreq_register_opp_notifier(dev, data->devfreq); |
| @@ -1081,8 +1098,9 @@ static int exynos4_busfreq_remove(struct platform_device *pdev) | |||
| 1081 | static int exynos4_busfreq_resume(struct device *dev) | 1098 | static int exynos4_busfreq_resume(struct device *dev) |
| 1082 | { | 1099 | { |
| 1083 | struct busfreq_data *data = dev_get_drvdata(dev); | 1100 | struct busfreq_data *data = dev_get_drvdata(dev); |
| 1101 | struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data; | ||
| 1084 | 1102 | ||
| 1085 | busfreq_mon_reset(data); | 1103 | busfreq_mon_reset(ppmu_data); |
| 1086 | return 0; | 1104 | return 0; |
| 1087 | } | 1105 | } |
| 1088 | #endif | 1106 | #endif |
