PM / devfreq: exynos: Remove unused exynos4/5 busfreq driver
This patch removes the unused exynos4/5 busfreq driver. Instead, generic exynos-bus frequency driver support the all Exynos SoCs. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Acked-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
This commit is contained in:
parent
38279cac36
commit
bfcd620487
|
@ -90,28 +90,6 @@ config ARM_EXYNOS_BUS_DEVFREQ
|
||||||
and adjusts the operating frequencies and voltages with OPP support.
|
and adjusts the operating frequencies and voltages with OPP support.
|
||||||
This does not yet operate with optimal voltages.
|
This does not yet operate with optimal voltages.
|
||||||
|
|
||||||
config ARM_EXYNOS4_BUS_DEVFREQ
|
|
||||||
bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
|
|
||||||
depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
|
|
||||||
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
|
||||||
select PM_OPP
|
|
||||||
help
|
|
||||||
This adds the DEVFREQ driver for Exynos4210 memory bus (vdd_int)
|
|
||||||
and Exynos4212/4412 memory interface and bus (vdd_mif + vdd_int).
|
|
||||||
It reads PPMU counters of memory controllers and adjusts
|
|
||||||
the operating frequencies and voltages with OPP support.
|
|
||||||
This does not yet operate with optimal voltages.
|
|
||||||
|
|
||||||
config ARM_EXYNOS5_BUS_DEVFREQ
|
|
||||||
tristate "ARM Exynos5250 Bus DEVFREQ Driver"
|
|
||||||
depends on SOC_EXYNOS5250
|
|
||||||
select DEVFREQ_GOV_SIMPLE_ONDEMAND
|
|
||||||
select PM_OPP
|
|
||||||
help
|
|
||||||
This adds the DEVFREQ driver for Exynos5250 bus interface (vdd_int).
|
|
||||||
It reads PPMU counters of memory controllers and adjusts the
|
|
||||||
operating frequencies and voltages with OPP support.
|
|
||||||
|
|
||||||
config ARM_TEGRA_DEVFREQ
|
config ARM_TEGRA_DEVFREQ
|
||||||
tristate "Tegra DEVFREQ Driver"
|
tristate "Tegra DEVFREQ Driver"
|
||||||
depends on ARCH_TEGRA_124_SOC
|
depends on ARCH_TEGRA_124_SOC
|
||||||
|
|
|
@ -8,8 +8,6 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
|
||||||
|
|
||||||
# DEVFREQ Drivers
|
# DEVFREQ Drivers
|
||||||
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
|
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
|
||||||
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/
|
|
||||||
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/
|
|
||||||
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o
|
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o
|
||||||
|
|
||||||
# DEVFREQ Event Drivers
|
# DEVFREQ Event Drivers
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Exynos DEVFREQ Drivers
|
|
||||||
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos_ppmu.o exynos4_bus.o
|
|
||||||
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
|
||||||
* http://www.samsung.com/
|
|
||||||
*
|
|
||||||
* EXYNOS4 BUS header
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DEVFREQ_EXYNOS4_BUS_H
|
|
||||||
#define __DEVFREQ_EXYNOS4_BUS_H __FILE__
|
|
||||||
|
|
||||||
#include <mach/map.h>
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_LEFTBUS (S5P_VA_CMU + 0x04500)
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_LEFTBUS (S5P_VA_CMU + 0x04600)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_RIGHTBUS (S5P_VA_CMU + 0x08500)
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_RIGHTBUS (S5P_VA_CMU + 0x08600)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_TOP (S5P_VA_CMU + 0x0C510)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM (S5P_VA_CMU + 0x0C520)
|
|
||||||
#define EXYNOS4_CLKDIV_MFC (S5P_VA_CMU + 0x0C528)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_TOP (S5P_VA_CMU + 0x0C610)
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_MFC (S5P_VA_CMU + 0x0C628)
|
|
||||||
|
|
||||||
#define EXYNOS4210_CLKGATE_IP_IMAGE (S5P_VA_CMU + 0x0C930)
|
|
||||||
#define EXYNOS4212_CLKGATE_IP_IMAGE (S5P_VA_CMU + 0x04930)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0 (S5P_VA_CMU + 0x10500)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1 (S5P_VA_CMU + 0x10504)
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_DMC0 (S5P_VA_CMU + 0x10600)
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_DMC1 (S5P_VA_CMU + 0x10604)
|
|
||||||
|
|
||||||
#define EXYNOS4_DMC_PAUSE_CTRL (S5P_VA_CMU + 0x11094)
|
|
||||||
#define EXYNOS4_DMC_PAUSE_ENABLE (1 << 0)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_ACP_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_ACP_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_ACP_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT (4)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT (8)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DPHY_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMC_SHIFT (12)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMC_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_DMC_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT (16)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMCD_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT (20)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_DMCP_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT (24)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_COPY2_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT (28)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC0_CORETI_MASK (0x7 << EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK (0xf << EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_C2C_SHIFT (4)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_C2C_MASK (0x7 << EXYNOS4_CLKDIV_DMC1_C2C_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_PWI_SHIFT (8)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_PWI_MASK (0xf << EXYNOS4_CLKDIV_DMC1_PWI_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT (12)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK (0x7 << EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT (16)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_DVSEM_MASK (0x7f << EXYNOS4_CLKDIV_DMC1_DVSEM_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_DPM_SHIFT (24)
|
|
||||||
#define EXYNOS4_CLKDIV_DMC1_DPM_MASK (0x7f << EXYNOS4_CLKDIV_DMC1_DPM_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_MFC_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_MFC_MASK (0x7 << EXYNOS4_CLKDIV_MFC_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK200_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT (4)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK100_MASK (0xF << EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT (8)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK160_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT (12)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK133_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT (16)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ONENAND_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT (20)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT (24)
|
|
||||||
#define EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_MASK (0x7 << EXYNOS4_CLKDIV_TOP_ACLK400_MCUISP_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_BUS_GDLR_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_BUS_GDLR_MASK (0x7 << EXYNOS4_CLKDIV_BUS_GDLR_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_BUS_GPLR_SHIFT (4)
|
|
||||||
#define EXYNOS4_CLKDIV_BUS_GPLR_MASK (0x7 << EXYNOS4_CLKDIV_BUS_GPLR_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC0_MASK (0xf << EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT (4)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC1_MASK (0xf << EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT (8)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC2_MASK (0xf << EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT (12)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM_FIMC3_MASK (0xf << EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_CAM1 (S5P_VA_CMU + 0x0C568)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_STAT_CAM1 (S5P_VA_CMU + 0x0C668)
|
|
||||||
|
|
||||||
#define EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT (0)
|
|
||||||
#define EXYNOS4_CLKDIV_CAM1_JPEG_MASK (0xf << EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT)
|
|
||||||
|
|
||||||
#endif /* __DEVFREQ_EXYNOS4_BUS_H */
|
|
|
@ -1,431 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
||||||
* http://www.samsung.com/
|
|
||||||
*
|
|
||||||
* EXYNOS5 INT clock frequency scaling support using DEVFREQ framework
|
|
||||||
* Based on work done by Jonghwan Choi <jhbird.choi@samsung.com>
|
|
||||||
* Support for only EXYNOS5250 is present.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/devfreq.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/pm_opp.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/suspend.h>
|
|
||||||
#include <linux/clk.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/pm_qos.h>
|
|
||||||
#include <linux/regulator/consumer.h>
|
|
||||||
#include <linux/of_address.h>
|
|
||||||
#include <linux/of_platform.h>
|
|
||||||
|
|
||||||
#include "exynos_ppmu.h"
|
|
||||||
|
|
||||||
#define MAX_SAFEVOLT 1100000 /* 1.10V */
|
|
||||||
/* Assume that the bus is saturated if the utilization is 25% */
|
|
||||||
#define INT_BUS_SATURATION_RATIO 25
|
|
||||||
|
|
||||||
enum int_level_idx {
|
|
||||||
LV_0,
|
|
||||||
LV_1,
|
|
||||||
LV_2,
|
|
||||||
LV_3,
|
|
||||||
LV_4,
|
|
||||||
_LV_END
|
|
||||||
};
|
|
||||||
|
|
||||||
enum exynos_ppmu_list {
|
|
||||||
PPMU_RIGHT,
|
|
||||||
PPMU_END,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct busfreq_data_int {
|
|
||||||
struct device *dev;
|
|
||||||
struct devfreq *devfreq;
|
|
||||||
struct regulator *vdd_int;
|
|
||||||
struct busfreq_ppmu_data ppmu_data;
|
|
||||||
unsigned long curr_freq;
|
|
||||||
bool disabled;
|
|
||||||
|
|
||||||
struct notifier_block pm_notifier;
|
|
||||||
struct mutex lock;
|
|
||||||
struct pm_qos_request int_req;
|
|
||||||
struct clk *int_clk;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct int_bus_opp_table {
|
|
||||||
unsigned int idx;
|
|
||||||
unsigned long clk;
|
|
||||||
unsigned long volt;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct int_bus_opp_table exynos5_int_opp_table[] = {
|
|
||||||
{LV_0, 266000, 1025000},
|
|
||||||
{LV_1, 200000, 1025000},
|
|
||||||
{LV_2, 160000, 1025000},
|
|
||||||
{LV_3, 133000, 1025000},
|
|
||||||
{LV_4, 100000, 1025000},
|
|
||||||
{0, 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int exynos5_int_setvolt(struct busfreq_data_int *data,
|
|
||||||
unsigned long volt)
|
|
||||||
{
|
|
||||||
return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
|
|
||||||
u32 flags)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
struct platform_device *pdev = container_of(dev, struct platform_device,
|
|
||||||
dev);
|
|
||||||
struct busfreq_data_int *data = platform_get_drvdata(pdev);
|
|
||||||
struct dev_pm_opp *opp;
|
|
||||||
unsigned long old_freq, freq;
|
|
||||||
unsigned long volt;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(dev, _freq, flags);
|
|
||||||
if (IS_ERR(opp)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(dev, "%s: Invalid OPP.\n", __func__);
|
|
||||||
return PTR_ERR(opp);
|
|
||||||
}
|
|
||||||
|
|
||||||
freq = dev_pm_opp_get_freq(opp);
|
|
||||||
volt = dev_pm_opp_get_voltage(opp);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
old_freq = data->curr_freq;
|
|
||||||
|
|
||||||
if (old_freq == freq)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dev_dbg(dev, "targeting %lukHz %luuV\n", freq, volt);
|
|
||||||
|
|
||||||
mutex_lock(&data->lock);
|
|
||||||
|
|
||||||
if (data->disabled)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (freq > exynos5_int_opp_table[0].clk)
|
|
||||||
pm_qos_update_request(&data->int_req, freq * 16 / 1000);
|
|
||||||
else
|
|
||||||
pm_qos_update_request(&data->int_req, -1);
|
|
||||||
|
|
||||||
if (old_freq < freq)
|
|
||||||
err = exynos5_int_setvolt(data, volt);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
err = clk_set_rate(data->int_clk, freq * 1000);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (old_freq > freq)
|
|
||||||
err = exynos5_int_setvolt(data, volt);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
data->curr_freq = freq;
|
|
||||||
out:
|
|
||||||
mutex_unlock(&data->lock);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos5_int_get_dev_status(struct device *dev,
|
|
||||||
struct devfreq_dev_status *stat)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = container_of(dev, struct platform_device,
|
|
||||||
dev);
|
|
||||||
struct busfreq_data_int *data = platform_get_drvdata(pdev);
|
|
||||||
struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
|
|
||||||
int busier_dmc;
|
|
||||||
|
|
||||||
exynos_read_ppmu(ppmu_data);
|
|
||||||
busier_dmc = exynos_get_busier_ppmu(ppmu_data);
|
|
||||||
|
|
||||||
stat->current_frequency = data->curr_freq;
|
|
||||||
|
|
||||||
/* Number of cycles spent on memory access */
|
|
||||||
stat->busy_time = ppmu_data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
|
|
||||||
stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
|
|
||||||
stat->total_time = ppmu_data->ppmu[busier_dmc].ccnt;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
|
|
||||||
.initial_freq = 160000,
|
|
||||||
.polling_ms = 100,
|
|
||||||
.target = exynos5_busfreq_int_target,
|
|
||||||
.get_dev_status = exynos5_int_get_dev_status,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int exynos5250_init_int_tables(struct busfreq_data_int *data)
|
|
||||||
{
|
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
for (i = LV_0; i < _LV_END; i++) {
|
|
||||||
err = dev_pm_opp_add(data->dev, exynos5_int_opp_table[i].clk,
|
|
||||||
exynos5_int_opp_table[i].volt);
|
|
||||||
if (err) {
|
|
||||||
dev_err(data->dev, "Cannot add opp entries.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
|
|
||||||
unsigned long event, void *ptr)
|
|
||||||
{
|
|
||||||
struct busfreq_data_int *data = container_of(this,
|
|
||||||
struct busfreq_data_int, pm_notifier);
|
|
||||||
struct dev_pm_opp *opp;
|
|
||||||
unsigned long maxfreq = ULONG_MAX;
|
|
||||||
unsigned long freq;
|
|
||||||
unsigned long volt;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
switch (event) {
|
|
||||||
case PM_SUSPEND_PREPARE:
|
|
||||||
/* Set Fastest and Deactivate DVFS */
|
|
||||||
mutex_lock(&data->lock);
|
|
||||||
|
|
||||||
data->disabled = true;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
|
|
||||||
if (IS_ERR(opp)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
err = PTR_ERR(opp);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
freq = dev_pm_opp_get_freq(opp);
|
|
||||||
volt = dev_pm_opp_get_voltage(opp);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
err = exynos5_int_setvolt(data, volt);
|
|
||||||
if (err)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
err = clk_set_rate(data->int_clk, freq * 1000);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
data->curr_freq = freq;
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&data->lock);
|
|
||||||
if (err)
|
|
||||||
return NOTIFY_BAD;
|
|
||||||
return NOTIFY_OK;
|
|
||||||
case PM_POST_RESTORE:
|
|
||||||
case PM_POST_SUSPEND:
|
|
||||||
/* Reactivate */
|
|
||||||
mutex_lock(&data->lock);
|
|
||||||
data->disabled = false;
|
|
||||||
mutex_unlock(&data->lock);
|
|
||||||
return NOTIFY_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos5_busfreq_int_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct busfreq_data_int *data;
|
|
||||||
struct busfreq_ppmu_data *ppmu_data;
|
|
||||||
struct dev_pm_opp *opp;
|
|
||||||
struct device *dev = &pdev->dev;
|
|
||||||
struct device_node *np;
|
|
||||||
unsigned long initial_freq;
|
|
||||||
unsigned long initial_volt;
|
|
||||||
int err = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (data == NULL) {
|
|
||||||
dev_err(dev, "Cannot allocate memory.\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ppmu_data = &data->ppmu_data;
|
|
||||||
ppmu_data->ppmu_end = PPMU_END;
|
|
||||||
ppmu_data->ppmu = devm_kzalloc(dev,
|
|
||||||
sizeof(struct exynos_ppmu) * PPMU_END,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!ppmu_data->ppmu) {
|
|
||||||
dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
|
|
||||||
if (np == NULL) {
|
|
||||||
pr_err("Unable to find PPMU node\n");
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ppmu_data->ppmu_end; i++) {
|
|
||||||
/* map PPMU memory region */
|
|
||||||
ppmu_data->ppmu[i].hw_base = of_iomap(np, i);
|
|
||||||
if (ppmu_data->ppmu[i].hw_base == NULL) {
|
|
||||||
dev_err(&pdev->dev, "failed to map memory region\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event;
|
|
||||||
data->dev = dev;
|
|
||||||
mutex_init(&data->lock);
|
|
||||||
|
|
||||||
err = exynos5250_init_int_tables(data);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
data->vdd_int = devm_regulator_get(dev, "vdd_int");
|
|
||||||
if (IS_ERR(data->vdd_int)) {
|
|
||||||
dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
|
|
||||||
return PTR_ERR(data->vdd_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
data->int_clk = devm_clk_get(dev, "int_clk");
|
|
||||||
if (IS_ERR(data->int_clk)) {
|
|
||||||
dev_err(dev, "Cannot get clock \"int_clk\"\n");
|
|
||||||
return PTR_ERR(data->int_clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_floor(dev,
|
|
||||||
&exynos5_devfreq_int_profile.initial_freq);
|
|
||||||
if (IS_ERR(opp)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(dev, "Invalid initial frequency %lu kHz.\n",
|
|
||||||
exynos5_devfreq_int_profile.initial_freq);
|
|
||||||
return PTR_ERR(opp);
|
|
||||||
}
|
|
||||||
initial_freq = dev_pm_opp_get_freq(opp);
|
|
||||||
initial_volt = dev_pm_opp_get_voltage(opp);
|
|
||||||
rcu_read_unlock();
|
|
||||||
data->curr_freq = initial_freq;
|
|
||||||
|
|
||||||
err = clk_set_rate(data->int_clk, initial_freq * 1000);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Failed to set initial frequency\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = exynos5_int_setvolt(data, initial_volt);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, data);
|
|
||||||
|
|
||||||
busfreq_mon_reset(ppmu_data);
|
|
||||||
|
|
||||||
data->devfreq = devm_devfreq_add_device(dev, &exynos5_devfreq_int_profile,
|
|
||||||
"simple_ondemand", NULL);
|
|
||||||
if (IS_ERR(data->devfreq))
|
|
||||||
return PTR_ERR(data->devfreq);
|
|
||||||
|
|
||||||
err = devm_devfreq_register_opp_notifier(dev, data->devfreq);
|
|
||||||
if (err < 0) {
|
|
||||||
dev_err(dev, "Failed to register opp notifier\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = register_pm_notifier(&data->pm_notifier);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "Failed to setup pm notifier\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Add a new QOS class for int/mif bus */
|
|
||||||
pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos5_busfreq_int_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct busfreq_data_int *data = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
pm_qos_remove_request(&data->int_req);
|
|
||||||
unregister_pm_notifier(&data->pm_notifier);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static int exynos5_busfreq_int_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = container_of(dev, struct platform_device,
|
|
||||||
dev);
|
|
||||||
struct busfreq_data_int *data = platform_get_drvdata(pdev);
|
|
||||||
struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
|
|
||||||
|
|
||||||
busfreq_mon_reset(ppmu_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static const struct dev_pm_ops exynos5_busfreq_int_pm = {
|
|
||||||
.resume = exynos5_busfreq_int_resume,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
static SIMPLE_DEV_PM_OPS(exynos5_busfreq_int_pm_ops, NULL,
|
|
||||||
exynos5_busfreq_int_resume);
|
|
||||||
|
|
||||||
/* platform device pointer for exynos5 devfreq device. */
|
|
||||||
static struct platform_device *exynos5_devfreq_pdev;
|
|
||||||
|
|
||||||
static struct platform_driver exynos5_busfreq_int_driver = {
|
|
||||||
.probe = exynos5_busfreq_int_probe,
|
|
||||||
.remove = exynos5_busfreq_int_remove,
|
|
||||||
.driver = {
|
|
||||||
.name = "exynos5-bus-int",
|
|
||||||
.pm = &exynos5_busfreq_int_pm_ops,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init exynos5_busfreq_int_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = platform_driver_register(&exynos5_busfreq_int_driver);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
exynos5_devfreq_pdev =
|
|
||||||
platform_device_register_simple("exynos5-bus-int", -1, NULL, 0);
|
|
||||||
if (IS_ERR(exynos5_devfreq_pdev)) {
|
|
||||||
ret = PTR_ERR(exynos5_devfreq_pdev);
|
|
||||||
goto out1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
out1:
|
|
||||||
platform_driver_unregister(&exynos5_busfreq_int_driver);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
late_initcall(exynos5_busfreq_int_init);
|
|
||||||
|
|
||||||
static void __exit exynos5_busfreq_int_exit(void)
|
|
||||||
{
|
|
||||||
platform_device_unregister(exynos5_devfreq_pdev);
|
|
||||||
platform_driver_unregister(&exynos5_busfreq_int_driver);
|
|
||||||
}
|
|
||||||
module_exit(exynos5_busfreq_int_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");
|
|
|
@ -1,119 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
||||||
* http://www.samsung.com/
|
|
||||||
*
|
|
||||||
* EXYNOS - PPMU support
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
|
|
||||||
#include "exynos_ppmu.h"
|
|
||||||
|
|
||||||
void exynos_ppmu_reset(void __iomem *ppmu_base)
|
|
||||||
{
|
|
||||||
__raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, ppmu_base);
|
|
||||||
__raw_writel(PPMU_ENABLE_CYCLE |
|
|
||||||
PPMU_ENABLE_COUNT0 |
|
|
||||||
PPMU_ENABLE_COUNT1 |
|
|
||||||
PPMU_ENABLE_COUNT2 |
|
|
||||||
PPMU_ENABLE_COUNT3,
|
|
||||||
ppmu_base + PPMU_CNTENS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
|
|
||||||
unsigned int evt)
|
|
||||||
{
|
|
||||||
__raw_writel(evt, ppmu_base + PPMU_BEVTSEL(ch));
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_ppmu_start(void __iomem *ppmu_base)
|
|
||||||
{
|
|
||||||
__raw_writel(PPMU_ENABLE, ppmu_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_ppmu_stop(void __iomem *ppmu_base)
|
|
||||||
{
|
|
||||||
__raw_writel(PPMU_DISABLE, ppmu_base);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch)
|
|
||||||
{
|
|
||||||
unsigned int total;
|
|
||||||
|
|
||||||
if (ch == PPMU_PMNCNT3)
|
|
||||||
total = ((__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
|
|
||||||
__raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
|
|
||||||
else
|
|
||||||
total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ppmu_data->ppmu_end; i++) {
|
|
||||||
void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
|
|
||||||
|
|
||||||
/* Reset the performance and cycle counters */
|
|
||||||
exynos_ppmu_reset(ppmu_base);
|
|
||||||
|
|
||||||
/* Setup count registers to monitor read/write transactions */
|
|
||||||
ppmu_data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
|
|
||||||
exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
|
|
||||||
ppmu_data->ppmu[i].event[PPMU_PMNCNT3]);
|
|
||||||
|
|
||||||
exynos_ppmu_start(ppmu_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(busfreq_mon_reset);
|
|
||||||
|
|
||||||
void exynos_read_ppmu(struct busfreq_ppmu_data *ppmu_data)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < ppmu_data->ppmu_end; i++) {
|
|
||||||
void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
|
|
||||||
|
|
||||||
exynos_ppmu_stop(ppmu_base);
|
|
||||||
|
|
||||||
/* Update local data from PPMU */
|
|
||||||
ppmu_data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
|
|
||||||
|
|
||||||
for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
|
|
||||||
if (ppmu_data->ppmu[i].event[j] == 0)
|
|
||||||
ppmu_data->ppmu[i].count[j] = 0;
|
|
||||||
else
|
|
||||||
ppmu_data->ppmu[i].count[j] =
|
|
||||||
exynos_ppmu_read(ppmu_base, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
busfreq_mon_reset(ppmu_data);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(exynos_read_ppmu);
|
|
||||||
|
|
||||||
int exynos_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data)
|
|
||||||
{
|
|
||||||
unsigned int count = 0;
|
|
||||||
int i, j, busy = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ppmu_data->ppmu_end; i++) {
|
|
||||||
for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
|
|
||||||
if (ppmu_data->ppmu[i].count[j] > count) {
|
|
||||||
count = ppmu_data->ppmu[i].count[j];
|
|
||||||
busy = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return busy;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(exynos_get_busier_ppmu);
|
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
||||||
* http://www.samsung.com/
|
|
||||||
*
|
|
||||||
* EXYNOS PPMU header
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __DEVFREQ_EXYNOS_PPMU_H
|
|
||||||
#define __DEVFREQ_EXYNOS_PPMU_H __FILE__
|
|
||||||
|
|
||||||
#include <linux/ktime.h>
|
|
||||||
|
|
||||||
/* For PPMU Control */
|
|
||||||
#define PPMU_ENABLE BIT(0)
|
|
||||||
#define PPMU_DISABLE 0x0
|
|
||||||
#define PPMU_CYCLE_RESET BIT(1)
|
|
||||||
#define PPMU_COUNTER_RESET BIT(2)
|
|
||||||
|
|
||||||
#define PPMU_ENABLE_COUNT0 BIT(0)
|
|
||||||
#define PPMU_ENABLE_COUNT1 BIT(1)
|
|
||||||
#define PPMU_ENABLE_COUNT2 BIT(2)
|
|
||||||
#define PPMU_ENABLE_COUNT3 BIT(3)
|
|
||||||
#define PPMU_ENABLE_CYCLE BIT(31)
|
|
||||||
|
|
||||||
#define PPMU_CNTENS 0x10
|
|
||||||
#define PPMU_FLAG 0x50
|
|
||||||
#define PPMU_CCNT_OVERFLOW BIT(31)
|
|
||||||
#define PPMU_CCNT 0x100
|
|
||||||
|
|
||||||
#define PPMU_PMCNT0 0x110
|
|
||||||
#define PPMU_PMCNT_OFFSET 0x10
|
|
||||||
#define PMCNT_OFFSET(x) (PPMU_PMCNT0 + (PPMU_PMCNT_OFFSET * x))
|
|
||||||
|
|
||||||
#define PPMU_BEVT0SEL 0x1000
|
|
||||||
#define PPMU_BEVTSEL_OFFSET 0x100
|
|
||||||
#define PPMU_BEVTSEL(x) (PPMU_BEVT0SEL + (ch * PPMU_BEVTSEL_OFFSET))
|
|
||||||
|
|
||||||
/* For Event Selection */
|
|
||||||
#define RD_DATA_COUNT 0x5
|
|
||||||
#define WR_DATA_COUNT 0x6
|
|
||||||
#define RDWR_DATA_COUNT 0x7
|
|
||||||
|
|
||||||
enum ppmu_counter {
|
|
||||||
PPMU_PMNCNT0,
|
|
||||||
PPMU_PMCCNT1,
|
|
||||||
PPMU_PMNCNT2,
|
|
||||||
PPMU_PMNCNT3,
|
|
||||||
PPMU_PMNCNT_MAX,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bus_opp_table {
|
|
||||||
unsigned int idx;
|
|
||||||
unsigned long clk;
|
|
||||||
unsigned long volt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct exynos_ppmu {
|
|
||||||
void __iomem *hw_base;
|
|
||||||
unsigned int ccnt;
|
|
||||||
unsigned int event[PPMU_PMNCNT_MAX];
|
|
||||||
unsigned int count[PPMU_PMNCNT_MAX];
|
|
||||||
unsigned long long ns;
|
|
||||||
ktime_t reset_time;
|
|
||||||
bool ccnt_overflow;
|
|
||||||
bool count_overflow[PPMU_PMNCNT_MAX];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct busfreq_ppmu_data {
|
|
||||||
struct exynos_ppmu *ppmu;
|
|
||||||
int ppmu_end;
|
|
||||||
};
|
|
||||||
|
|
||||||
void exynos_ppmu_reset(void __iomem *ppmu_base);
|
|
||||||
void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
|
|
||||||
unsigned int evt);
|
|
||||||
void exynos_ppmu_start(void __iomem *ppmu_base);
|
|
||||||
void exynos_ppmu_stop(void __iomem *ppmu_base);
|
|
||||||
unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch);
|
|
||||||
void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data);
|
|
||||||
void exynos_read_ppmu(struct busfreq_ppmu_data *ppmu_data);
|
|
||||||
int exynos_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data);
|
|
||||||
#endif /* __DEVFREQ_EXYNOS_PPMU_H */
|
|
Loading…
Reference in New Issue