Merge tag 'PR_4.7_20160503' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx...
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 4 May 2016 20:50:47 +0000 (22:50 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 4 May 2016 20:50:47 +0000 (22:50 +0200)
Pull devfreq material for v4.7 from MyungJoo Ham.

"Updates:

- Passive governor: for SoC subsystems that may either
  have an independent voltage rail or have a parent subsystem
  or collegue subsystem sharing a voltage rail, when there
  is a parent of a collegue that is going to be the owner
  of the voltage rail, the dependent subsystem may use the
  passive governor.

- Consolidated exynos bus/mem-if driver: now we have a single
  driver that supports (almost) all Exynos SoC's bus/mem-if subsystems.

- New devfreq drivers included: Exynos NoC probe"

* tag 'PR_4.7_20160503' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq:
  PM / devfreq: style/typo fixes
  PM / devfreq: exynos: Add the detailed correlation for Exynos5422 bus
  PM / devfreq: event: Find the instance of devfreq-event device by using phandle
  PM / devfreq: event: Add new Exynos NoC probe driver
  MAINTAINERS: Add samsung bus frequency driver entry
  PM / devfreq: exynos: Remove unused exynos4/5 busfreq driver
  PM / devfreq: exynos: Add the detailed correlation between sub-blocks and power line
  PM / devfreq: exynos: Update documentation for bus devices using passive governor
  PM / devfreq: exynos: Add support of bus frequency of sub-blocks using passive governor
  PM / devfreq: Add new passive governor
  PM / devfreq: Add new DEVFREQ_TRANSITION_NOTIFIER notifier
  PM / devfreq: Add devfreq_get_devfreq_by_phandle()
  PM / devfreq: exynos: Add documentation for generic exynos bus frequency driver
  PM / devfreq: exynos: Add generic exynos bus frequency driver

20 files changed:
Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/devfreq/exynos-bus.txt [new file with mode: 0644]
MAINTAINERS
drivers/devfreq/Kconfig
drivers/devfreq/Makefile
drivers/devfreq/devfreq-event.c
drivers/devfreq/devfreq.c
drivers/devfreq/event/Kconfig
drivers/devfreq/event/Makefile
drivers/devfreq/event/exynos-nocp.c [new file with mode: 0644]
drivers/devfreq/event/exynos-nocp.h [new file with mode: 0644]
drivers/devfreq/exynos-bus.c [new file with mode: 0644]
drivers/devfreq/exynos/Makefile [deleted file]
drivers/devfreq/exynos/exynos4_bus.c [deleted file]
drivers/devfreq/exynos/exynos4_bus.h [deleted file]
drivers/devfreq/exynos/exynos5_bus.c [deleted file]
drivers/devfreq/exynos/exynos_ppmu.c [deleted file]
drivers/devfreq/exynos/exynos_ppmu.h [deleted file]
drivers/devfreq/governor_passive.c [new file with mode: 0644]
include/linux/devfreq.h

diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-nocp.txt
new file mode 100644 (file)
index 0000000..fd459f0
--- /dev/null
@@ -0,0 +1,26 @@
+
+* Samsung Exynos NoC (Network on Chip) Probe device
+
+The Samsung Exynos542x SoC has NoC (Network on Chip) Probe for NoC bus.
+NoC provides the primitive values to get the performance data. The packets
+that the Network on Chip (NoC) probes detects are transported over
+the network infrastructure to observer units. You can configure probes to
+capture packets with header or data on the data request response network,
+or as traffic debug or statistic collectors. Exynos542x bus has multiple
+NoC probes to provide bandwidth information about behavior of the SoC
+that you can use while analyzing system performance.
+
+Required properties:
+- compatible: Should be "samsung,exynos5420-nocp"
+- reg: physical base address of each NoC Probe and length of memory mapped region.
+
+Optional properties:
+- clock-names : the name of clock used by the NoC Probe, "nocp"
+- clocks : phandles for clock specified in "clock-names" property
+
+Example : NoC Probe nodes in Device Tree are listed below.
+
+       nocp_mem0_0: nocp@10CA1000 {
+               compatible = "samsung,exynos5420-nocp";
+               reg = <0x10CA1000 0x200>;
+       };
diff --git a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
new file mode 100644 (file)
index 0000000..d3ec8e6
--- /dev/null
@@ -0,0 +1,409 @@
+* Generic Exynos Bus frequency device
+
+The Samsung Exynos SoC has many buses for data transfer between DRAM
+and sub-blocks in SoC. Most Exynos SoCs share the common architecture
+for buses. Generally, each bus of Exynos SoC includes a source clock
+and a power line, which are able to change the clock frequency
+of the bus in runtime. To monitor the usage of each bus in runtime,
+the driver uses the PPMU (Platform Performance Monitoring Unit), which
+is able to measure the current load of sub-blocks.
+
+The Exynos SoC includes the various sub-blocks which have the each AXI bus.
+The each AXI bus has the owned source clock but, has not the only owned
+power line. The power line might be shared among one more sub-blocks.
+So, we can divide into two type of device as the role of each sub-block.
+There are two type of bus devices as following:
+- parent bus device
+- passive bus device
+
+Basically, parent and passive bus device share the same power line.
+The parent bus device can only change the voltage of shared power line
+and the rest bus devices (passive bus device) depend on the decision of
+the parent bus device. If there are three blocks which share the VDD_xxx
+power line, Only one block should be parent device and then the rest blocks
+should depend on the parent device as passive device.
+
+       VDD_xxx |--- A block (parent)
+               |--- B block (passive)
+               |--- C block (passive)
+
+There are a little different composition among Exynos SoC because each Exynos
+SoC has different sub-blocks. Therefore, such difference should be specified
+in devicetree file instead of each device driver. In result, this driver
+is able to support the bus frequency for all Exynos SoCs.
+
+Required properties for all bus devices:
+- compatible: Should be "samsung,exynos-bus".
+- clock-names : the name of clock used by the bus, "bus".
+- clocks : phandles for clock specified in "clock-names" property.
+- operating-points-v2: the OPP table including frequency/voltage information
+  to support DVFS (Dynamic Voltage/Frequency Scaling) feature.
+
+Required properties only for parent bus device:
+- vdd-supply: the regulator to provide the buses with the voltage.
+- devfreq-events: the devfreq-event device to monitor the current utilization
+  of buses.
+
+Required properties only for passive bus device:
+- devfreq: the parent bus device.
+
+Optional properties only for parent bus device:
+- exynos,saturation-ratio: the percentage value which is used to calibrate
+                       the performance count against total cycle count.
+- exynos,voltage-tolerance: the percentage value for bus voltage tolerance
+                       which is used to calculate the max voltage.
+
+Detailed correlation between sub-blocks and power line according to Exynos SoC:
+- In case of Exynos3250, there are two power line as following:
+       VDD_MIF |--- DMC
+
+       VDD_INT |--- LEFTBUS (parent device)
+               |--- PERIL
+               |--- MFC
+               |--- G3D
+               |--- RIGHTBUS
+               |--- PERIR
+               |--- FSYS
+               |--- LCD0
+               |--- PERIR
+               |--- ISP
+               |--- CAM
+
+- In case of Exynos4210, there is one power line as following:
+       VDD_INT |--- DMC (parent device)
+               |--- LEFTBUS
+               |--- PERIL
+               |--- MFC(L)
+               |--- G3D
+               |--- TV
+               |--- LCD0
+               |--- RIGHTBUS
+               |--- PERIR
+               |--- MFC(R)
+               |--- CAM
+               |--- FSYS
+               |--- GPS
+               |--- LCD0
+               |--- LCD1
+
+- In case of Exynos4x12, there are two power line as following:
+       VDD_MIF |--- DMC
+
+       VDD_INT |--- LEFTBUS (parent device)
+               |--- PERIL
+               |--- MFC(L)
+               |--- G3D
+               |--- TV
+               |--- IMAGE
+               |--- RIGHTBUS
+               |--- PERIR
+               |--- MFC(R)
+               |--- CAM
+               |--- FSYS
+               |--- GPS
+               |--- LCD0
+               |--- ISP
+
+- In case of Exynos5422, there are two power line as following:
+       VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
+               |--- DREX 1
+
+       VDD_INT |--- NoC_Core (parent device)
+               |--- G2D
+               |--- G3D
+               |--- DISP1
+               |--- NoC_WCORE
+               |--- GSCL
+               |--- MSCL
+               |--- ISP
+               |--- MFC
+               |--- GEN
+               |--- PERIS
+               |--- PERIC
+               |--- FSYS
+               |--- FSYS2
+
+Example1:
+       Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
+       power line (regulator). The MIF (Memory Interface) AXI bus is used to
+       transfer data between DRAM and CPU and uses the VDD_MIF regulator.
+
+       - MIF (Memory Interface) block
+       : VDD_MIF |--- DMC (Dynamic Memory Controller)
+
+       - INT (Internal) block
+       : VDD_INT |--- LEFTBUS (parent device)
+                 |--- PERIL
+                 |--- MFC
+                 |--- G3D
+                 |--- RIGHTBUS
+                 |--- FSYS
+                 |--- LCD0
+                 |--- PERIR
+                 |--- ISP
+                 |--- CAM
+
+       - MIF bus's frequency/voltage table
+       -----------------------
+       |Lv| Freq   | Voltage |
+       -----------------------
+       |L1| 50000  |800000   |
+       |L2| 100000 |800000   |
+       |L3| 134000 |800000   |
+       |L4| 200000 |825000   |
+       |L5| 400000 |875000   |
+       -----------------------
+
+       - INT bus's frequency/voltage table
+       ----------------------------------------------------------
+       |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP    |PERIL  ||VDD_INT |
+       | name|       |LCD0    |       |       |       ||        |
+       |     |       |FSYS    |       |       |       ||        |
+       |     |       |MFC     |       |       |       ||        |
+       ----------------------------------------------------------
+       |Mode |*parent|passive |passive|passive|passive||        |
+       ----------------------------------------------------------
+       |Lv   |Frequency                               ||Voltage |
+       ----------------------------------------------------------
+       |L1   |50000  |50000   |50000  |50000  |50000  ||900000  |
+       |L2   |80000  |80000   |80000  |80000  |80000  ||900000  |
+       |L3   |100000 |100000  |100000 |100000 |100000 ||1000000 |
+       |L4   |134000 |134000  |200000 |200000 |       ||1000000 |
+       |L5   |200000 |200000  |400000 |300000 |       ||1000000 |
+       ----------------------------------------------------------
+
+Example2 :
+       The bus of DMC (Dynamic Memory Controller) block in exynos3250.dtsi
+       is listed below:
+
+       bus_dmc: bus_dmc {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu_dmc CLK_DIV_DMC>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_dmc_opp_table>;
+               status = "disabled";
+       };
+
+       bus_dmc_opp_table: opp_table1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+                       opp-microvolt = <800000>;
+               };
+               opp@100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       opp-microvolt = <800000>;
+               };
+               opp@134000000 {
+                       opp-hz = /bits/ 64 <134000000>;
+                       opp-microvolt = <800000>;
+               };
+               opp@200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+                       opp-microvolt = <825000>;
+               };
+               opp@400000000 {
+                       opp-hz = /bits/ 64 <400000000>;
+                       opp-microvolt = <875000>;
+               };
+       };
+
+       bus_leftbus: bus_leftbus {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_GDL>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_leftbus_opp_table>;
+               status = "disabled";
+       };
+
+       bus_rightbus: bus_rightbus {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_GDR>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_leftbus_opp_table>;
+               status = "disabled";
+       };
+
+       bus_lcd0: bus_lcd0 {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_ACLK_160>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_leftbus_opp_table>;
+               status = "disabled";
+       };
+
+       bus_fsys: bus_fsys {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_ACLK_200>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_leftbus_opp_table>;
+               status = "disabled";
+       };
+
+       bus_mcuisp: bus_mcuisp {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_ACLK_400_MCUISP>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_mcuisp_opp_table>;
+               status = "disabled";
+       };
+
+       bus_isp: bus_isp {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_ACLK_266>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_isp_opp_table>;
+               status = "disabled";
+       };
+
+       bus_peril: bus_peril {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_DIV_ACLK_100>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_peril_opp_table>;
+               status = "disabled";
+       };
+
+       bus_mfc: bus_mfc {
+               compatible = "samsung,exynos-bus";
+               clocks = <&cmu CLK_SCLK_MFC>;
+               clock-names = "bus";
+               operating-points-v2 = <&bus_leftbus_opp_table>;
+               status = "disabled";
+       };
+
+       bus_leftbus_opp_table: opp_table1 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+                       opp-microvolt = <900000>;
+               };
+               opp@80000000 {
+                       opp-hz = /bits/ 64 <80000000>;
+                       opp-microvolt = <900000>;
+               };
+               opp@100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+                       opp-microvolt = <1000000>;
+               };
+               opp@134000000 {
+                       opp-hz = /bits/ 64 <134000000>;
+                       opp-microvolt = <1000000>;
+               };
+               opp@200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+                       opp-microvolt = <1000000>;
+               };
+       };
+
+       bus_mcuisp_opp_table: opp_table2 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+               };
+               opp@80000000 {
+                       opp-hz = /bits/ 64 <80000000>;
+               };
+               opp@100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+               };
+               opp@200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+               };
+               opp@400000000 {
+                       opp-hz = /bits/ 64 <400000000>;
+               };
+       };
+
+       bus_isp_opp_table: opp_table3 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+               };
+               opp@80000000 {
+                       opp-hz = /bits/ 64 <80000000>;
+               };
+               opp@100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+               };
+               opp@200000000 {
+                       opp-hz = /bits/ 64 <200000000>;
+               };
+               opp@300000000 {
+                       opp-hz = /bits/ 64 <300000000>;
+               };
+       };
+
+       bus_peril_opp_table: opp_table4 {
+               compatible = "operating-points-v2";
+               opp-shared;
+
+               opp@50000000 {
+                       opp-hz = /bits/ 64 <50000000>;
+               };
+               opp@80000000 {
+                       opp-hz = /bits/ 64 <80000000>;
+               };
+               opp@100000000 {
+                       opp-hz = /bits/ 64 <100000000>;
+               };
+       };
+
+
+       Usage case to handle the frequency and voltage of bus on runtime
+       in exynos3250-rinato.dts is listed below:
+
+       &bus_dmc {
+               devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
+               vdd-supply = <&buck1_reg>;      /* VDD_MIF */
+               status = "okay";
+       };
+
+       &bus_leftbus {
+               devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
+               vdd-supply = <&buck3_reg>;
+               status = "okay";
+       };
+
+       &bus_rightbus {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_lcd0 {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_fsys {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_mcuisp {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_isp {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_peril {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
+
+       &bus_mfc {
+               devfreq = <&bus_leftbus>;
+               status = "okay";
+       };
index 42e65d1..7e9da3a 100644 (file)
@@ -3539,6 +3539,15 @@ F:       drivers/devfreq/devfreq-event.c
 F:     include/linux/devfreq-event.h
 F:     Documentation/devicetree/bindings/devfreq/event/
 
+BUS FREQUENCY DRIVER FOR SAMSUNG EXYNOS
+M:     Chanwoo Choi <cw00.choi@samsung.com>
+L:     linux-pm@vger.kernel.org
+L:     linux-samsung-soc@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq.git
+S:     Maintained
+F:     drivers/devfreq/exynos-bus.c
+F:     Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+
 DEVICE NUMBER REGISTRY
 M:     Torben Mathiasen <device@lanana.org>
 W:     http://lanana.org/docs/device-list/index.html
index 4de78c5..78dac0e 100644 (file)
@@ -64,30 +64,32 @@ config DEVFREQ_GOV_USERSPACE
          Otherwise, the governor does not change the frequency
          given at the initialization.
 
+config DEVFREQ_GOV_PASSIVE
+       tristate "Passive"
+       help
+         Sets the frequency based on the frequency of its parent devfreq
+         device. This governor does not change the frequency by itself
+         through sysfs entries. The passive governor recommends that
+         devfreq device uses the OPP table to get the frequency/voltage.
+
 comment "DEVFREQ Drivers"
 
-config ARM_EXYNOS4_BUS_DEVFREQ
-       bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
-       depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
+config ARM_EXYNOS_BUS_DEVFREQ
+       bool "ARM EXYNOS Generic Memory Bus DEVFREQ Driver"
+       depends on ARCH_EXYNOS
        select DEVFREQ_GOV_SIMPLE_ONDEMAND
+       select DEVFREQ_GOV_PASSIVE
+       select DEVFREQ_EVENT_EXYNOS_PPMU
+       select PM_DEVFREQ_EVENT
        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 adds the common DEVFREQ driver for Exynos Memory bus. Exynos
+         Memory bus has one more group of memory bus (e.g, MIF and INT block).
+         Each memory bus group could contain many memoby bus block. It reads
+         PPMU counters of memory controllers by using DEVFREQ-event device
+         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
        tristate "Tegra DEVFREQ Driver"
        depends on ARCH_TEGRA_124_SOC
index 5134f9e..09f11d9 100644 (file)
@@ -4,10 +4,10 @@ obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)     += governor_simpleondemand.o
 obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)  += governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)    += governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)    += governor_userspace.o
+obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)      += governor_passive.o
 
 # DEVFREQ Drivers
-obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)  += exynos/
-obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)  += exynos/
+obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)   += exynos-bus.o
 obj-$(CONFIG_ARM_TEGRA_DEVFREQ)                += tegra-devfreq.o
 
 # DEVFREQ Event Drivers
index 38bf144..39b048e 100644 (file)
@@ -234,6 +234,11 @@ struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
                return ERR_PTR(-ENODEV);
 
        mutex_lock(&devfreq_event_list_lock);
+       list_for_each_entry(edev, &devfreq_event_list, node) {
+               if (edev->dev.parent && edev->dev.parent->of_node == node)
+                       goto out;
+       }
+
        list_for_each_entry(edev, &devfreq_event_list, node) {
                if (!strcmp(edev->desc->name, node->name))
                        goto out;
index 984c5e9..1d6c803 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/list.h>
 #include <linux/printk.h>
 #include <linux/hrtimer.h>
+#include <linux/of.h>
 #include "governor.h"
 
 static struct class *devfreq_class;
@@ -188,6 +189,29 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
        return ERR_PTR(-ENODEV);
 }
 
+static int devfreq_notify_transition(struct devfreq *devfreq,
+               struct devfreq_freqs *freqs, unsigned int state)
+{
+       if (!devfreq)
+               return -EINVAL;
+
+       switch (state) {
+       case DEVFREQ_PRECHANGE:
+               srcu_notifier_call_chain(&devfreq->transition_notifier_list,
+                               DEVFREQ_PRECHANGE, freqs);
+               break;
+
+       case DEVFREQ_POSTCHANGE:
+               srcu_notifier_call_chain(&devfreq->transition_notifier_list,
+                               DEVFREQ_POSTCHANGE, freqs);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* Load monitoring helper functions for governors use */
 
 /**
@@ -199,7 +223,8 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
  */
 int update_devfreq(struct devfreq *devfreq)
 {
-       unsigned long freq;
+       struct devfreq_freqs freqs;
+       unsigned long freq, cur_freq;
        int err = 0;
        u32 flags = 0;
 
@@ -233,10 +258,22 @@ int update_devfreq(struct devfreq *devfreq)
                flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
        }
 
+       if (devfreq->profile->get_cur_freq)
+               devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq);
+       else
+               cur_freq = devfreq->previous_freq;
+
+       freqs.old = cur_freq;
+       freqs.new = freq;
+       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_PRECHANGE);
+
        err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
        if (err)
                return err;
 
+       freqs.new = freq;
+       devfreq_notify_transition(devfreq, &freqs, DEVFREQ_POSTCHANGE);
+
        if (devfreq->profile->freq_table)
                if (devfreq_update_status(devfreq, freq))
                        dev_err(&devfreq->dev,
@@ -541,6 +578,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
                goto err_out;
        }
 
+       srcu_init_notifier_head(&devfreq->transition_notifier_list);
+
        mutex_unlock(&devfreq->lock);
 
        mutex_lock(&devfreq_list_lock);
@@ -639,6 +678,49 @@ struct devfreq *devm_devfreq_add_device(struct device *dev,
 }
 EXPORT_SYMBOL(devm_devfreq_add_device);
 
+#ifdef CONFIG_OF
+/*
+ * devfreq_get_devfreq_by_phandle - Get the devfreq device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of devfreq
+ *
+ * return the instance of devfreq device
+ */
+struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
+{
+       struct device_node *node;
+       struct devfreq *devfreq;
+
+       if (!dev)
+               return ERR_PTR(-EINVAL);
+
+       if (!dev->of_node)
+               return ERR_PTR(-EINVAL);
+
+       node = of_parse_phandle(dev->of_node, "devfreq", index);
+       if (!node)
+               return ERR_PTR(-ENODEV);
+
+       mutex_lock(&devfreq_list_lock);
+       list_for_each_entry(devfreq, &devfreq_list, node) {
+               if (devfreq->dev.parent
+                       && devfreq->dev.parent->of_node == node) {
+                       mutex_unlock(&devfreq_list_lock);
+                       return devfreq;
+               }
+       }
+       mutex_unlock(&devfreq_list_lock);
+
+       return ERR_PTR(-EPROBE_DEFER);
+}
+#else
+struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_OF */
+EXPORT_SYMBOL_GPL(devfreq_get_devfreq_by_phandle);
+
 /**
  * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
  * @dev:       the device to add devfreq feature.
@@ -1266,6 +1348,129 @@ void devm_devfreq_unregister_opp_notifier(struct device *dev,
 }
 EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
 
+/**
+ * devfreq_register_notifier() - Register a driver with devfreq
+ * @devfreq:   The devfreq object.
+ * @nb:                The notifier block to register.
+ * @list:      DEVFREQ_TRANSITION_NOTIFIER.
+ */
+int devfreq_register_notifier(struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+       int ret = 0;
+
+       if (!devfreq)
+               return -EINVAL;
+
+       switch (list) {
+       case DEVFREQ_TRANSITION_NOTIFIER:
+               ret = srcu_notifier_chain_register(
+                               &devfreq->transition_notifier_list, nb);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(devfreq_register_notifier);
+
+/*
+ * devfreq_unregister_notifier() - Unregister a driver with devfreq
+ * @devfreq:   The devfreq object.
+ * @nb:                The notifier block to be unregistered.
+ * @list:      DEVFREQ_TRANSITION_NOTIFIER.
+ */
+int devfreq_unregister_notifier(struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+       int ret = 0;
+
+       if (!devfreq)
+               return -EINVAL;
+
+       switch (list) {
+       case DEVFREQ_TRANSITION_NOTIFIER:
+               ret = srcu_notifier_chain_unregister(
+                               &devfreq->transition_notifier_list, nb);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(devfreq_unregister_notifier);
+
+struct devfreq_notifier_devres {
+       struct devfreq *devfreq;
+       struct notifier_block *nb;
+       unsigned int list;
+};
+
+static void devm_devfreq_notifier_release(struct device *dev, void *res)
+{
+       struct devfreq_notifier_devres *this = res;
+
+       devfreq_unregister_notifier(this->devfreq, this->nb, this->list);
+}
+
+/**
+ * devm_devfreq_register_notifier()
+       - Resource-managed devfreq_register_notifier()
+ * @dev:       The devfreq user device. (parent of devfreq)
+ * @devfreq:   The devfreq object.
+ * @nb:                The notifier block to be unregistered.
+ * @list:      DEVFREQ_TRANSITION_NOTIFIER.
+ */
+int devm_devfreq_register_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+       struct devfreq_notifier_devres *ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_devfreq_notifier_release, sizeof(*ptr),
+                               GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = devfreq_register_notifier(devfreq, nb, list);
+       if (ret) {
+               devres_free(ptr);
+               return ret;
+       }
+
+       ptr->devfreq = devfreq;
+       ptr->nb = nb;
+       ptr->list = list;
+       devres_add(dev, ptr);
+
+       return 0;
+}
+EXPORT_SYMBOL(devm_devfreq_register_notifier);
+
+/**
+ * devm_devfreq_unregister_notifier()
+       - Resource-managed devfreq_unregister_notifier()
+ * @dev:       The devfreq user device. (parent of devfreq)
+ * @devfreq:   The devfreq object.
+ * @nb:                The notifier block to be unregistered.
+ * @list:      DEVFREQ_TRANSITION_NOTIFIER.
+ */
+void devm_devfreq_unregister_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+       WARN_ON(devres_release(dev, devm_devfreq_notifier_release,
+                              devm_devfreq_dev_match, devfreq));
+}
+EXPORT_SYMBOL(devm_devfreq_unregister_notifier);
+
 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
 MODULE_DESCRIPTION("devfreq class support");
 MODULE_LICENSE("GPL");
index a11720a..1e8b4f4 100644 (file)
@@ -13,6 +13,14 @@ menuconfig PM_DEVFREQ_EVENT
 
 if PM_DEVFREQ_EVENT
 
+config DEVFREQ_EVENT_EXYNOS_NOCP
+       bool "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver"
+       depends on ARCH_EXYNOS
+       select PM_OPP
+       help
+         This add the devfreq-event driver for Exynos SoC. It provides NoC
+         (Network on Chip) Probe counters to measure the bandwidth of AXI bus.
+
 config DEVFREQ_EVENT_EXYNOS_PPMU
        bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
        depends on ARCH_EXYNOS
index be146ea..3d6afd3 100644 (file)
@@ -1,2 +1,4 @@
 # Exynos DEVFREQ Event Drivers
+
+obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP) += exynos-nocp.o
 obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c
new file mode 100644 (file)
index 0000000..6b6a5f3
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * 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/clk.h>
+#include <linux/module.h>
+#include <linux/devfreq-event.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "exynos-nocp.h"
+
+struct exynos_nocp {
+       struct devfreq_event_dev *edev;
+       struct devfreq_event_desc desc;
+
+       struct device *dev;
+
+       struct regmap *regmap;
+       struct clk *clk;
+};
+
+/*
+ * The devfreq-event ops structure for nocp probe.
+ */
+static int exynos_nocp_set_event(struct devfreq_event_dev *edev)
+{
+       struct exynos_nocp *nocp = devfreq_event_get_drvdata(edev);
+       int ret;
+
+       /* Disable NoC probe */
+       ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
+                               NOCP_MAIN_CTL_STATEN_MASK, 0);
+       if (ret < 0) {
+               dev_err(nocp->dev, "failed to disable the NoC probe device\n");
+               return ret;
+       }
+
+       /* Set a statistics dump period to 0 */
+       ret = regmap_write(nocp->regmap, NOCP_STAT_PERIOD, 0x0);
+       if (ret < 0)
+               goto out;
+
+       /* Set the IntEvent fields of *_SRC */
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_0_SRC,
+                               NOCP_CNT_SRC_INTEVENT_MASK,
+                               NOCP_CNT_SRC_INTEVENT_BYTE_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_1_SRC,
+                               NOCP_CNT_SRC_INTEVENT_MASK,
+                               NOCP_CNT_SRC_INTEVENT_CHAIN_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_2_SRC,
+                               NOCP_CNT_SRC_INTEVENT_MASK,
+                               NOCP_CNT_SRC_INTEVENT_CYCLE_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_3_SRC,
+                               NOCP_CNT_SRC_INTEVENT_MASK,
+                               NOCP_CNT_SRC_INTEVENT_CHAIN_MASK);
+       if (ret < 0)
+               goto out;
+
+
+       /* Set an alarm with a max/min value of 0 to generate StatALARM */
+       ret = regmap_write(nocp->regmap, NOCP_STAT_ALARM_MIN, 0x0);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_write(nocp->regmap, NOCP_STAT_ALARM_MAX, 0x0);
+       if (ret < 0)
+               goto out;
+
+       /* Set AlarmMode */
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_0_ALARM_MODE,
+                               NOCP_CNT_ALARM_MODE_MASK,
+                               NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_1_ALARM_MODE,
+                               NOCP_CNT_ALARM_MODE_MASK,
+                               NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_2_ALARM_MODE,
+                               NOCP_CNT_ALARM_MODE_MASK,
+                               NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_update_bits(nocp->regmap, NOCP_COUNTERS_3_ALARM_MODE,
+                               NOCP_CNT_ALARM_MODE_MASK,
+                               NOCP_CNT_ALARM_MODE_MIN_MAX_MASK);
+       if (ret < 0)
+               goto out;
+
+       /* Enable the measurements by setting AlarmEn and StatEn */
+       ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
+                       NOCP_MAIN_CTL_STATEN_MASK | NOCP_MAIN_CTL_ALARMEN_MASK,
+                       NOCP_MAIN_CTL_STATEN_MASK | NOCP_MAIN_CTL_ALARMEN_MASK);
+       if (ret < 0)
+               goto out;
+
+       /* Set GlobalEN */
+       ret = regmap_update_bits(nocp->regmap, NOCP_CFG_CTL,
+                               NOCP_CFG_CTL_GLOBALEN_MASK,
+                               NOCP_CFG_CTL_GLOBALEN_MASK);
+       if (ret < 0)
+               goto out;
+
+       /* Enable NoC probe */
+       ret = regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
+                               NOCP_MAIN_CTL_STATEN_MASK,
+                               NOCP_MAIN_CTL_STATEN_MASK);
+       if (ret < 0)
+               goto out;
+
+       return 0;
+
+out:
+       /* Reset NoC probe */
+       if (regmap_update_bits(nocp->regmap, NOCP_MAIN_CTL,
+                               NOCP_MAIN_CTL_STATEN_MASK, 0)) {
+               dev_err(nocp->dev, "Failed to reset NoC probe device\n");
+       }
+
+       return ret;
+}
+
+static int exynos_nocp_get_event(struct devfreq_event_dev *edev,
+                               struct devfreq_event_data *edata)
+{
+       struct exynos_nocp *nocp = devfreq_event_get_drvdata(edev);
+       unsigned int counter[4];
+       int ret;
+
+       /* Read cycle count */
+       ret = regmap_read(nocp->regmap, NOCP_COUNTERS_0_VAL, &counter[0]);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_read(nocp->regmap, NOCP_COUNTERS_1_VAL, &counter[1]);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_read(nocp->regmap, NOCP_COUNTERS_2_VAL, &counter[2]);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_read(nocp->regmap, NOCP_COUNTERS_3_VAL, &counter[3]);
+       if (ret < 0)
+               goto out;
+
+       edata->load_count = ((counter[1] << 16) | counter[0]);
+       edata->total_count = ((counter[3] << 16) | counter[2]);
+
+       dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
+                                       edata->load_count, edata->total_count);
+
+       return 0;
+
+out:
+       edata->load_count = 0;
+       edata->total_count = 0;
+
+       dev_err(nocp->dev, "Failed to read the counter of NoC probe device\n");
+
+       return ret;
+}
+
+static const struct devfreq_event_ops exynos_nocp_ops = {
+       .set_event = exynos_nocp_set_event,
+       .get_event = exynos_nocp_get_event,
+};
+
+static const struct of_device_id exynos_nocp_id_match[] = {
+       { .compatible = "samsung,exynos5420-nocp", },
+       { /* sentinel */ },
+};
+
+static struct regmap_config exynos_nocp_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = NOCP_COUNTERS_3_VAL,
+};
+
+static int exynos_nocp_parse_dt(struct platform_device *pdev,
+                               struct exynos_nocp *nocp)
+{
+       struct device *dev = nocp->dev;
+       struct device_node *np = dev->of_node;
+       struct resource *res;
+       void __iomem *base;
+
+       if (!np) {
+               dev_err(dev, "failed to find devicetree node\n");
+               return -EINVAL;
+       }
+
+       nocp->clk = devm_clk_get(dev, "nocp");
+       if (IS_ERR(nocp->clk))
+               nocp->clk = NULL;
+
+       /* Maps the memory mapped IO to control nocp register */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (IS_ERR(res))
+               return PTR_ERR(res);
+
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       exynos_nocp_regmap_config.max_register = resource_size(res) - 4;
+
+       nocp->regmap = devm_regmap_init_mmio(dev, base,
+                                       &exynos_nocp_regmap_config);
+       if (IS_ERR(nocp->regmap)) {
+               dev_err(dev, "failed to initialize regmap\n");
+               return PTR_ERR(nocp->regmap);
+       }
+
+       return 0;
+}
+
+static int exynos_nocp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct exynos_nocp *nocp;
+       int ret;
+
+       nocp = devm_kzalloc(&pdev->dev, sizeof(*nocp), GFP_KERNEL);
+       if (!nocp)
+               return -ENOMEM;
+
+       nocp->dev = &pdev->dev;
+
+       /* Parse dt data to get resource */
+       ret = exynos_nocp_parse_dt(pdev, nocp);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "failed to parse devicetree for resource\n");
+               return ret;
+       }
+
+       /* Add devfreq-event device to measure the bandwidth of NoC */
+       nocp->desc.ops = &exynos_nocp_ops;
+       nocp->desc.driver_data = nocp;
+       nocp->desc.name = np->full_name;
+       nocp->edev = devm_devfreq_event_add_edev(&pdev->dev, &nocp->desc);
+       if (IS_ERR(nocp->edev)) {
+               dev_err(&pdev->dev,
+                       "failed to add devfreq-event device\n");
+               return PTR_ERR(nocp->edev);
+       }
+       platform_set_drvdata(pdev, nocp);
+
+       clk_prepare_enable(nocp->clk);
+
+       pr_info("exynos-nocp: new NoC Probe device registered: %s\n",
+                       dev_name(dev));
+
+       return 0;
+}
+
+static int exynos_nocp_remove(struct platform_device *pdev)
+{
+       struct exynos_nocp *nocp = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(nocp->clk);
+
+       return 0;
+}
+
+static struct platform_driver exynos_nocp_driver = {
+       .probe  = exynos_nocp_probe,
+       .remove = exynos_nocp_remove,
+       .driver = {
+               .name   = "exynos-nocp",
+               .of_match_table = exynos_nocp_id_match,
+       },
+};
+module_platform_driver(exynos_nocp_driver);
+
+MODULE_DESCRIPTION("Exynos NoC (Network on Chip) Probe driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/event/exynos-nocp.h b/drivers/devfreq/event/exynos-nocp.h
new file mode 100644 (file)
index 0000000..28564db
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * exynos-nocp.h - EXYNOS NoC (Network on Chip) Probe header file
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * 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 __EXYNOS_NOCP_H__
+#define __EXYNOS_NOCP_H__
+
+enum nocp_reg {
+       NOCP_ID_REVISION_ID             = 0x04,
+       NOCP_MAIN_CTL                   = 0x08,
+       NOCP_CFG_CTL                    = 0x0C,
+
+       NOCP_STAT_PERIOD                = 0x24,
+       NOCP_STAT_GO                    = 0x28,
+       NOCP_STAT_ALARM_MIN             = 0x2C,
+       NOCP_STAT_ALARM_MAX             = 0x30,
+       NOCP_STAT_ALARM_STATUS          = 0x34,
+       NOCP_STAT_ALARM_CLR             = 0x38,
+
+       NOCP_COUNTERS_0_SRC             = 0x138,
+       NOCP_COUNTERS_0_ALARM_MODE      = 0x13C,
+       NOCP_COUNTERS_0_VAL             = 0x140,
+
+       NOCP_COUNTERS_1_SRC             = 0x14C,
+       NOCP_COUNTERS_1_ALARM_MODE      = 0x150,
+       NOCP_COUNTERS_1_VAL             = 0x154,
+
+       NOCP_COUNTERS_2_SRC             = 0x160,
+       NOCP_COUNTERS_2_ALARM_MODE      = 0x164,
+       NOCP_COUNTERS_2_VAL             = 0x168,
+
+       NOCP_COUNTERS_3_SRC             = 0x174,
+       NOCP_COUNTERS_3_ALARM_MODE      = 0x178,
+       NOCP_COUNTERS_3_VAL             = 0x17C,
+};
+
+/* NOCP_MAIN_CTL register */
+#define NOCP_MAIN_CTL_ERREN_MASK               BIT(0)
+#define NOCP_MAIN_CTL_TRACEEN_MASK             BIT(1)
+#define NOCP_MAIN_CTL_PAYLOADEN_MASK           BIT(2)
+#define NOCP_MAIN_CTL_STATEN_MASK              BIT(3)
+#define NOCP_MAIN_CTL_ALARMEN_MASK             BIT(4)
+#define NOCP_MAIN_CTL_STATCONDDUMP_MASK        BIT(5)
+#define NOCP_MAIN_CTL_INTRUSIVEMODE_MASK       BIT(6)
+
+/* NOCP_CFG_CTL register */
+#define NOCP_CFG_CTL_GLOBALEN_MASK             BIT(0)
+#define NOCP_CFG_CTL_ACTIVE_MASK               BIT(1)
+
+/* NOCP_COUNTERS_x_SRC register */
+#define NOCP_CNT_SRC_INTEVENT_SHIFT            0
+#define NOCP_CNT_SRC_INTEVENT_MASK             (0x1F << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_OFF_MASK         (0x0 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_CYCLE_MASK       (0x1 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_IDLE_MASK                (0x2 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_XFER_MASK                (0x3 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_BUSY_MASK                (0x4 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_WAIT_MASK                (0x5 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_PKT_MASK         (0x6 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_BYTE_MASK                (0x8 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+#define NOCP_CNT_SRC_INTEVENT_CHAIN_MASK       (0x10 << NOCP_CNT_SRC_INTEVENT_SHIFT)
+
+/* NOCP_COUNTERS_x_ALARM_MODE register */
+#define NOCP_CNT_ALARM_MODE_SHIFT              0
+#define NOCP_CNT_ALARM_MODE_MASK               (0x3 << NOCP_CNT_ALARM_MODE_SHIFT)
+#define NOCP_CNT_ALARM_MODE_OFF_MASK           (0x0 << NOCP_CNT_ALARM_MODE_SHIFT)
+#define NOCP_CNT_ALARM_MODE_MIN_MASK           (0x1 << NOCP_CNT_ALARM_MODE_SHIFT)
+#define NOCP_CNT_ALARM_MODE_MAX_MASK           (0x2 << NOCP_CNT_ALARM_MODE_SHIFT)
+#define NOCP_CNT_ALARM_MODE_MIN_MAX_MASK       (0x3 << NOCP_CNT_ALARM_MODE_SHIFT)
+
+#endif /* __EXYNOS_NOCP_H__ */
diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c
new file mode 100644 (file)
index 0000000..2363d0a
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Generic Exynos Bus frequency driver with DEVFREQ Framework
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This driver support Exynos Bus frequency feature by using
+ * DEVFREQ framework and is based on drivers/devfreq/exynos/exynos4_bus.c.
+ *
+ * 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/clk.h>
+#include <linux/devfreq.h>
+#include <linux/devfreq-event.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#define DEFAULT_SATURATION_RATIO       40
+#define DEFAULT_VOLTAGE_TOLERANCE      2
+
+struct exynos_bus {
+       struct device *dev;
+
+       struct devfreq *devfreq;
+       struct devfreq_event_dev **edev;
+       unsigned int edev_count;
+       struct mutex lock;
+
+       struct dev_pm_opp *curr_opp;
+
+       struct regulator *regulator;
+       struct clk *clk;
+       unsigned int voltage_tolerance;
+       unsigned int ratio;
+};
+
+/*
+ * Control the devfreq-event device to get the current state of bus
+ */
+#define exynos_bus_ops_edev(ops)                               \
+static int exynos_bus_##ops(struct exynos_bus *bus)            \
+{                                                              \
+       int i, ret;                                             \
+                                                               \
+       for (i = 0; i < bus->edev_count; i++) {                 \
+               if (!bus->edev[i])                              \
+                       continue;                               \
+               ret = devfreq_event_##ops(bus->edev[i]);        \
+               if (ret < 0)                                    \
+                       return ret;                             \
+       }                                                       \
+                                                               \
+       return 0;                                               \
+}
+exynos_bus_ops_edev(enable_edev);
+exynos_bus_ops_edev(disable_edev);
+exynos_bus_ops_edev(set_event);
+
+static int exynos_bus_get_event(struct exynos_bus *bus,
+                               struct devfreq_event_data *edata)
+{
+       struct devfreq_event_data event_data;
+       unsigned long load_count = 0, total_count = 0;
+       int i, ret = 0;
+
+       for (i = 0; i < bus->edev_count; i++) {
+               if (!bus->edev[i])
+                       continue;
+
+               ret = devfreq_event_get_event(bus->edev[i], &event_data);
+               if (ret < 0)
+                       return ret;
+
+               if (i == 0 || event_data.load_count > load_count) {
+                       load_count = event_data.load_count;
+                       total_count = event_data.total_count;
+               }
+       }
+
+       edata->load_count = load_count;
+       edata->total_count = total_count;
+
+       return ret;
+}
+
+/*
+ * Must necessary function for devfreq simple-ondemand governor
+ */
+static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       struct dev_pm_opp *new_opp;
+       unsigned long old_freq, new_freq, old_volt, new_volt, tol;
+       int ret = 0;
+
+       /* Get new opp-bus instance according to new bus clock */
+       rcu_read_lock();
+       new_opp = devfreq_recommended_opp(dev, freq, flags);
+       if (IS_ERR(new_opp)) {
+               dev_err(dev, "failed to get recommended opp instance\n");
+               rcu_read_unlock();
+               return PTR_ERR(new_opp);
+       }
+
+       new_freq = dev_pm_opp_get_freq(new_opp);
+       new_volt = dev_pm_opp_get_voltage(new_opp);
+       old_freq = dev_pm_opp_get_freq(bus->curr_opp);
+       old_volt = dev_pm_opp_get_voltage(bus->curr_opp);
+       rcu_read_unlock();
+
+       if (old_freq == new_freq)
+               return 0;
+       tol = new_volt * bus->voltage_tolerance / 100;
+
+       /* Change voltage and frequency according to new OPP level */
+       mutex_lock(&bus->lock);
+
+       if (old_freq < new_freq) {
+               ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol);
+               if (ret < 0) {
+                       dev_err(bus->dev, "failed to set voltage\n");
+                       goto out;
+               }
+       }
+
+       ret = clk_set_rate(bus->clk, new_freq);
+       if (ret < 0) {
+               dev_err(dev, "failed to change clock of bus\n");
+               clk_set_rate(bus->clk, old_freq);
+               goto out;
+       }
+
+       if (old_freq > new_freq) {
+               ret = regulator_set_voltage_tol(bus->regulator, new_volt, tol);
+               if (ret < 0) {
+                       dev_err(bus->dev, "failed to set voltage\n");
+                       goto out;
+               }
+       }
+       bus->curr_opp = new_opp;
+
+       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
+                       old_freq/1000, new_freq/1000);
+out:
+       mutex_unlock(&bus->lock);
+
+       return ret;
+}
+
+static int exynos_bus_get_dev_status(struct device *dev,
+                                    struct devfreq_dev_status *stat)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       struct devfreq_event_data edata;
+       int ret;
+
+       rcu_read_lock();
+       stat->current_frequency = dev_pm_opp_get_freq(bus->curr_opp);
+       rcu_read_unlock();
+
+       ret = exynos_bus_get_event(bus, &edata);
+       if (ret < 0) {
+               stat->total_time = stat->busy_time = 0;
+               goto err;
+       }
+
+       stat->busy_time = (edata.load_count * 100) / bus->ratio;
+       stat->total_time = edata.total_count;
+
+       dev_dbg(dev, "Usage of devfreq-event : %lu/%lu\n", stat->busy_time,
+                                                       stat->total_time);
+
+err:
+       ret = exynos_bus_set_event(bus);
+       if (ret < 0) {
+               dev_err(dev, "failed to set event to devfreq-event devices\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static void exynos_bus_exit(struct device *dev)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       int ret;
+
+       ret = exynos_bus_disable_edev(bus);
+       if (ret < 0)
+               dev_warn(dev, "failed to disable the devfreq-event devices\n");
+
+       if (bus->regulator)
+               regulator_disable(bus->regulator);
+
+       dev_pm_opp_of_remove_table(dev);
+       clk_disable_unprepare(bus->clk);
+}
+
+/*
+ * Must necessary function for devfreq passive governor
+ */
+static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
+                                       u32 flags)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       struct dev_pm_opp *new_opp;
+       unsigned long old_freq, new_freq;
+       int ret = 0;
+
+       /* Get new opp-bus instance according to new bus clock */
+       rcu_read_lock();
+       new_opp = devfreq_recommended_opp(dev, freq, flags);
+       if (IS_ERR(new_opp)) {
+               dev_err(dev, "failed to get recommended opp instance\n");
+               rcu_read_unlock();
+               return PTR_ERR(new_opp);
+       }
+
+       new_freq = dev_pm_opp_get_freq(new_opp);
+       old_freq = dev_pm_opp_get_freq(bus->curr_opp);
+       rcu_read_unlock();
+
+       if (old_freq == new_freq)
+               return 0;
+
+       /* Change the frequency according to new OPP level */
+       mutex_lock(&bus->lock);
+
+       ret = clk_set_rate(bus->clk, new_freq);
+       if (ret < 0) {
+               dev_err(dev, "failed to set the clock of bus\n");
+               goto out;
+       }
+
+       *freq = new_freq;
+       bus->curr_opp = new_opp;
+
+       dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
+                       old_freq/1000, new_freq/1000);
+out:
+       mutex_unlock(&bus->lock);
+
+       return ret;
+}
+
+static void exynos_bus_passive_exit(struct device *dev)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+
+       dev_pm_opp_of_remove_table(dev);
+       clk_disable_unprepare(bus->clk);
+}
+
+static int exynos_bus_parent_parse_of(struct device_node *np,
+                                       struct exynos_bus *bus)
+{
+       struct device *dev = bus->dev;
+       int i, ret, count, size;
+
+       /* Get the regulator to provide each bus with the power */
+       bus->regulator = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(bus->regulator)) {
+               dev_err(dev, "failed to get VDD regulator\n");
+               return PTR_ERR(bus->regulator);
+       }
+
+       ret = regulator_enable(bus->regulator);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable VDD regulator\n");
+               return ret;
+       }
+
+       /*
+        * Get the devfreq-event devices to get the current utilization of
+        * buses. This raw data will be used in devfreq ondemand governor.
+        */
+       count = devfreq_event_get_edev_count(dev);
+       if (count < 0) {
+               dev_err(dev, "failed to get the count of devfreq-event dev\n");
+               ret = count;
+               goto err_regulator;
+       }
+       bus->edev_count = count;
+
+       size = sizeof(*bus->edev) * count;
+       bus->edev = devm_kzalloc(dev, size, GFP_KERNEL);
+       if (!bus->edev) {
+               ret = -ENOMEM;
+               goto err_regulator;
+       }
+
+       for (i = 0; i < count; i++) {
+               bus->edev[i] = devfreq_event_get_edev_by_phandle(dev, i);
+               if (IS_ERR(bus->edev[i])) {
+                       ret = -EPROBE_DEFER;
+                       goto err_regulator;
+               }
+       }
+
+       /*
+        * Optionally, Get the saturation ratio according to Exynos SoC
+        * When measuring the utilization of each AXI bus with devfreq-event
+        * devices, the measured real cycle might be much lower than the
+        * total cycle of bus during sampling rate. In result, the devfreq
+        * simple-ondemand governor might not decide to change the current
+        * frequency due to too utilization (= real cycle/total cycle).
+        * So, this property is used to adjust the utilization when calculating
+        * the busy_time in exynos_bus_get_dev_status().
+        */
+       if (of_property_read_u32(np, "exynos,saturation-ratio", &bus->ratio))
+               bus->ratio = DEFAULT_SATURATION_RATIO;
+
+       if (of_property_read_u32(np, "exynos,voltage-tolerance",
+                                       &bus->voltage_tolerance))
+               bus->voltage_tolerance = DEFAULT_VOLTAGE_TOLERANCE;
+
+       return 0;
+
+err_regulator:
+       regulator_disable(bus->regulator);
+
+       return ret;
+}
+
+static int exynos_bus_parse_of(struct device_node *np,
+                             struct exynos_bus *bus)
+{
+       struct device *dev = bus->dev;
+       unsigned long rate;
+       int ret;
+
+       /* Get the clock to provide each bus with source clock */
+       bus->clk = devm_clk_get(dev, "bus");
+       if (IS_ERR(bus->clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               return PTR_ERR(bus->clk);
+       }
+
+       ret = clk_prepare_enable(bus->clk);
+       if (ret < 0) {
+               dev_err(dev, "failed to get enable clock\n");
+               return ret;
+       }
+
+       /* Get the freq and voltage from OPP table to scale the bus freq */
+       rcu_read_lock();
+       ret = dev_pm_opp_of_add_table(dev);
+       if (ret < 0) {
+               dev_err(dev, "failed to get OPP table\n");
+               rcu_read_unlock();
+               goto err_clk;
+       }
+
+       rate = clk_get_rate(bus->clk);
+       bus->curr_opp = devfreq_recommended_opp(dev, &rate, 0);
+       if (IS_ERR(bus->curr_opp)) {
+               dev_err(dev, "failed to find dev_pm_opp\n");
+               rcu_read_unlock();
+               ret = PTR_ERR(bus->curr_opp);
+               goto err_opp;
+       }
+       rcu_read_unlock();
+
+       return 0;
+
+err_opp:
+       dev_pm_opp_of_remove_table(dev);
+err_clk:
+       clk_disable_unprepare(bus->clk);
+
+       return ret;
+}
+
+static int exynos_bus_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct devfreq_dev_profile *profile;
+       struct devfreq_simple_ondemand_data *ondemand_data;
+       struct devfreq_passive_data *passive_data;
+       struct devfreq *parent_devfreq;
+       struct exynos_bus *bus;
+       int ret, max_state;
+       unsigned long min_freq, max_freq;
+
+       if (!np) {
+               dev_err(dev, "failed to find devicetree node\n");
+               return -EINVAL;
+       }
+
+       bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+       if (!bus)
+               return -ENOMEM;
+       mutex_init(&bus->lock);
+       bus->dev = &pdev->dev;
+       platform_set_drvdata(pdev, bus);
+
+       /* Parse the device-tree to get the resource information */
+       ret = exynos_bus_parse_of(np, bus);
+       if (ret < 0)
+               goto err;
+
+       profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
+       if (!profile) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       if (of_parse_phandle(dev->of_node, "devfreq", 0))
+               goto passive;
+       else
+               ret = exynos_bus_parent_parse_of(np, bus);
+
+       if (ret < 0)
+               goto err;
+
+       /* Initialize the struct profile and governor data for parent device */
+       profile->polling_ms = 50;
+       profile->target = exynos_bus_target;
+       profile->get_dev_status = exynos_bus_get_dev_status;
+       profile->exit = exynos_bus_exit;
+
+       ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);
+       if (!ondemand_data) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       ondemand_data->upthreshold = 40;
+       ondemand_data->downdifferential = 5;
+
+       /* Add devfreq device to monitor and handle the exynos bus */
+       bus->devfreq = devm_devfreq_add_device(dev, profile, "simple_ondemand",
+                                               ondemand_data);
+       if (IS_ERR(bus->devfreq)) {
+               dev_err(dev, "failed to add devfreq device\n");
+               ret = PTR_ERR(bus->devfreq);
+               goto err;
+       }
+
+       /* Register opp_notifier to catch the change of OPP  */
+       ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);
+       if (ret < 0) {
+               dev_err(dev, "failed to register opp notifier\n");
+               goto err;
+       }
+
+       /*
+        * Enable devfreq-event to get raw data which is used to determine
+        * current bus load.
+        */
+       ret = exynos_bus_enable_edev(bus);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable devfreq-event devices\n");
+               goto err;
+       }
+
+       ret = exynos_bus_set_event(bus);
+       if (ret < 0) {
+               dev_err(dev, "failed to set event to devfreq-event devices\n");
+               goto err;
+       }
+
+       goto out;
+passive:
+       /* Initialize the struct profile and governor data for passive device */
+       profile->target = exynos_bus_passive_target;
+       profile->exit = exynos_bus_passive_exit;
+
+       /* Get the instance of parent devfreq device */
+       parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
+       if (IS_ERR(parent_devfreq)) {
+               ret = -EPROBE_DEFER;
+               goto err;
+       }
+
+       passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
+       if (!passive_data) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       passive_data->parent = parent_devfreq;
+
+       /* Add devfreq device for exynos bus with passive governor */
+       bus->devfreq = devm_devfreq_add_device(dev, profile, "passive",
+                                               passive_data);
+       if (IS_ERR(bus->devfreq)) {
+               dev_err(dev,
+                       "failed to add devfreq dev with passive governor\n");
+               ret = -EPROBE_DEFER;
+               goto err;
+       }
+
+out:
+       max_state = bus->devfreq->profile->max_state;
+       min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
+       max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
+       pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
+                       dev_name(dev), min_freq, max_freq);
+
+       return 0;
+
+err:
+       dev_pm_opp_of_remove_table(dev);
+       clk_disable_unprepare(bus->clk);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_bus_resume(struct device *dev)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       int ret;
+
+       ret = exynos_bus_enable_edev(bus);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable the devfreq-event devices\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int exynos_bus_suspend(struct device *dev)
+{
+       struct exynos_bus *bus = dev_get_drvdata(dev);
+       int ret;
+
+       ret = exynos_bus_disable_edev(bus);
+       if (ret < 0) {
+               dev_err(dev, "failed to disable the devfreq-event devices\n");
+               return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_bus_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(exynos_bus_suspend, exynos_bus_resume)
+};
+
+static const struct of_device_id exynos_bus_of_match[] = {
+       { .compatible = "samsung,exynos-bus", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, exynos_bus_of_match);
+
+static struct platform_driver exynos_bus_platdrv = {
+       .probe          = exynos_bus_probe,
+       .driver = {
+               .name   = "exynos-bus",
+               .pm     = &exynos_bus_pm,
+               .of_match_table = of_match_ptr(exynos_bus_of_match),
+       },
+};
+module_platform_driver(exynos_bus_platdrv);
+
+MODULE_DESCRIPTION("Generic Exynos Bus frequency driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
deleted file mode 100644 (file)
index 49bc917..0000000
+++ /dev/null
@@ -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
diff --git a/drivers/devfreq/exynos/exynos4_bus.c b/drivers/devfreq/exynos/exynos4_bus.c
deleted file mode 100644 (file)
index da95092..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-/* drivers/devfreq/exynos4210_memorybus.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *     MyungJoo Ham <myungjoo.ham@samsung.com>
- *
- * EXYNOS4 - Memory/Bus clock frequency scaling support in DEVFREQ framework
- *     This version supports EXYNOS4210 only. This changes bus frequencies
- *     and vddint voltages. Exynos4412/4212 should be able to be supported
- *     with minor modifications.
- *
- * 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/io.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/suspend.h>
-#include <linux/pm_opp.h>
-#include <linux/devfreq.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-
-#include <mach/map.h>
-
-#include "exynos_ppmu.h"
-#include "exynos4_bus.h"
-
-#define MAX_SAFEVOLT   1200000 /* 1.2V */
-
-enum exynos4_busf_type {
-       TYPE_BUSF_EXYNOS4210,
-       TYPE_BUSF_EXYNOS4x12,
-};
-
-/* Assume that the bus is saturated if the utilization is 40% */
-#define BUS_SATURATION_RATIO   40
-
-enum busclk_level_idx {
-       LV_0 = 0,
-       LV_1,
-       LV_2,
-       LV_3,
-       LV_4,
-       _LV_END
-};
-
-enum exynos_ppmu_idx {
-       PPMU_DMC0,
-       PPMU_DMC1,
-       PPMU_END,
-};
-
-#define EX4210_LV_MAX  LV_2
-#define EX4x12_LV_MAX  LV_4
-#define EX4210_LV_NUM  (LV_2 + 1)
-#define EX4x12_LV_NUM  (LV_4 + 1)
-
-/**
- * struct busfreq_opp_info - opp information for bus
- * @rate:      Frequency in hertz
- * @volt:      Voltage in microvolts corresponding to this OPP
- */
-struct busfreq_opp_info {
-       unsigned long rate;
-       unsigned long volt;
-};
-
-struct busfreq_data {
-       enum exynos4_busf_type type;
-       struct device *dev;
-       struct devfreq *devfreq;
-       bool disabled;
-       struct regulator *vdd_int;
-       struct regulator *vdd_mif; /* Exynos4412/4212 only */
-       struct busfreq_opp_info curr_oppinfo;
-       struct busfreq_ppmu_data ppmu_data;
-
-       struct notifier_block pm_notifier;
-       struct mutex lock;
-
-       /* Dividers calculated at boot/probe-time */
-       unsigned int dmc_divtable[_LV_END]; /* DMC0 */
-       unsigned int top_divtable[_LV_END];
-};
-
-/* 4210 controls clock of mif and voltage of int */
-static struct bus_opp_table exynos4210_busclk_table[] = {
-       {LV_0, 400000, 1150000},
-       {LV_1, 267000, 1050000},
-       {LV_2, 133000, 1025000},
-       {0, 0, 0},
-};
-
-/*
- * MIF is the main control knob clock for Exynos4x12 MIF/INT
- * clock and voltage of both mif/int are controlled.
- */
-static struct bus_opp_table exynos4x12_mifclk_table[] = {
-       {LV_0, 400000, 1100000},
-       {LV_1, 267000, 1000000},
-       {LV_2, 160000, 950000},
-       {LV_3, 133000, 950000},
-       {LV_4, 100000, 950000},
-       {0, 0, 0},
-};
-
-/*
- * INT is not the control knob of 4x12. LV_x is not meant to represent
- * the current performance. (MIF does)
- */
-static struct bus_opp_table exynos4x12_intclk_table[] = {
-       {LV_0, 200000, 1000000},
-       {LV_1, 160000, 950000},
-       {LV_2, 133000, 925000},
-       {LV_3, 100000, 900000},
-       {0, 0, 0},
-};
-
-/* TODO: asv volt definitions are "__initdata"? */
-/* Some chips have different operating voltages */
-static unsigned int exynos4210_asv_volt[][EX4210_LV_NUM] = {
-       {1150000, 1050000, 1050000},
-       {1125000, 1025000, 1025000},
-       {1100000, 1000000, 1000000},
-       {1075000, 975000, 975000},
-       {1050000, 950000, 950000},
-};
-
-static unsigned int exynos4x12_mif_step_50[][EX4x12_LV_NUM] = {
-       /* 400      267     160     133     100 */
-       {1050000, 950000, 900000, 900000, 900000}, /* ASV0 */
-       {1050000, 950000, 900000, 900000, 900000}, /* ASV1 */
-       {1050000, 950000, 900000, 900000, 900000}, /* ASV2 */
-       {1050000, 900000, 900000, 900000, 900000}, /* ASV3 */
-       {1050000, 900000, 900000, 900000, 850000}, /* ASV4 */
-       {1050000, 900000, 900000, 850000, 850000}, /* ASV5 */
-       {1050000, 900000, 850000, 850000, 850000}, /* ASV6 */
-       {1050000, 900000, 850000, 850000, 850000}, /* ASV7 */
-       {1050000, 900000, 850000, 850000, 850000}, /* ASV8 */
-};
-
-static unsigned int exynos4x12_int_volt[][EX4x12_LV_NUM] = {
-       /* 200    160      133     100 */
-       {1000000, 950000, 925000, 900000}, /* ASV0 */
-       {975000,  925000, 925000, 900000}, /* ASV1 */
-       {950000,  925000, 900000, 875000}, /* ASV2 */
-       {950000,  900000, 900000, 875000}, /* ASV3 */
-       {925000,  875000, 875000, 875000}, /* ASV4 */
-       {900000,  850000, 850000, 850000}, /* ASV5 */
-       {900000,  850000, 850000, 850000}, /* ASV6 */
-       {900000,  850000, 850000, 850000}, /* ASV7 */
-       {900000,  850000, 850000, 850000}, /* ASV8 */
-};
-
-/*** Clock Divider Data for Exynos4210 ***/
-static unsigned int exynos4210_clkdiv_dmc0[][8] = {
-       /*
-        * Clock divider value for following
-        * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
-        *              DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
-        */
-
-       /* DMC L0: 400MHz */
-       { 3, 1, 1, 1, 1, 1, 3, 1 },
-       /* DMC L1: 266.7MHz */
-       { 4, 1, 1, 2, 1, 1, 3, 1 },
-       /* DMC L2: 133MHz */
-       { 5, 1, 1, 5, 1, 1, 3, 1 },
-};
-static unsigned int exynos4210_clkdiv_top[][5] = {
-       /*
-        * Clock divider value for following
-        * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
-        */
-       /* ACLK200 L0: 200MHz */
-       { 3, 7, 4, 5, 1 },
-       /* ACLK200 L1: 160MHz */
-       { 4, 7, 5, 6, 1 },
-       /* ACLK200 L2: 133MHz */
-       { 5, 7, 7, 7, 1 },
-};
-static unsigned int exynos4210_clkdiv_lr_bus[][2] = {
-       /*
-        * Clock divider value for following
-        * { DIVGDL/R, DIVGPL/R }
-        */
-       /* ACLK_GDL/R L1: 200MHz */
-       { 3, 1 },
-       /* ACLK_GDL/R L2: 160MHz */
-       { 4, 1 },
-       /* ACLK_GDL/R L3: 133MHz */
-       { 5, 1 },
-};
-
-/*** Clock Divider Data for Exynos4212/4412 ***/
-static unsigned int exynos4x12_clkdiv_dmc0[][6] = {
-       /*
-        * Clock divider value for following
-        * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
-        *              DIVDMCP}
-        */
-
-       /* DMC L0: 400MHz */
-       {3, 1, 1, 1, 1, 1},
-       /* DMC L1: 266.7MHz */
-       {4, 1, 1, 2, 1, 1},
-       /* DMC L2: 160MHz */
-       {5, 1, 1, 4, 1, 1},
-       /* DMC L3: 133MHz */
-       {5, 1, 1, 5, 1, 1},
-       /* DMC L4: 100MHz */
-       {7, 1, 1, 7, 1, 1},
-};
-static unsigned int exynos4x12_clkdiv_dmc1[][6] = {
-       /*
-        * Clock divider value for following
-        * { G2DACP, DIVC2C, DIVC2C_ACLK }
-        */
-
-       /* DMC L0: 400MHz */
-       {3, 1, 1},
-       /* DMC L1: 266.7MHz */
-       {4, 2, 1},
-       /* DMC L2: 160MHz */
-       {5, 4, 1},
-       /* DMC L3: 133MHz */
-       {5, 5, 1},
-       /* DMC L4: 100MHz */
-       {7, 7, 1},
-};
-static unsigned int exynos4x12_clkdiv_top[][5] = {
-       /*
-        * Clock divider value for following
-        * { DIVACLK266_GPS, DIVACLK100, DIVACLK160,
-               DIVACLK133, DIVONENAND }
-        */
-
-       /* ACLK_GDL/R L0: 200MHz */
-       {2, 7, 4, 5, 1},
-       /* ACLK_GDL/R L1: 200MHz */
-       {2, 7, 4, 5, 1},
-       /* ACLK_GDL/R L2: 160MHz */
-       {4, 7, 5, 7, 1},
-       /* ACLK_GDL/R L3: 133MHz */
-       {4, 7, 5, 7, 1},
-       /* ACLK_GDL/R L4: 100MHz */
-       {7, 7, 7, 7, 1},
-};
-static unsigned int exynos4x12_clkdiv_lr_bus[][2] = {
-       /*
-        * Clock divider value for following
-        * { DIVGDL/R, DIVGPL/R }
-        */
-
-       /* ACLK_GDL/R L0: 200MHz */
-       {3, 1},
-       /* ACLK_GDL/R L1: 200MHz */
-       {3, 1},
-       /* ACLK_GDL/R L2: 160MHz */
-       {4, 1},
-       /* ACLK_GDL/R L3: 133MHz */
-       {5, 1},
-       /* ACLK_GDL/R L4: 100MHz */
-       {7, 1},
-};
-static unsigned int exynos4x12_clkdiv_sclkip[][3] = {
-       /*
-        * Clock divider value for following
-        * { DIVMFC, DIVJPEG, DIVFIMC0~3}
-        */
-
-       /* SCLK_MFC: 200MHz */
-       {3, 3, 4},
-       /* SCLK_MFC: 200MHz */
-       {3, 3, 4},
-       /* SCLK_MFC: 160MHz */
-       {4, 4, 5},
-       /* SCLK_MFC: 133MHz */
-       {5, 5, 5},
-       /* SCLK_MFC: 100MHz */
-       {7, 7, 7},
-};
-
-
-static int exynos4210_set_busclk(struct busfreq_data *data,
-                                struct busfreq_opp_info *oppi)
-{
-       unsigned int index;
-       unsigned int tmp;
-
-       for (index = LV_0; index < EX4210_LV_NUM; index++)
-               if (oppi->rate == exynos4210_busclk_table[index].clk)
-                       break;
-
-       if (index == EX4210_LV_NUM)
-               return -EINVAL;
-
-       /* Change Divider - DMC0 */
-       tmp = data->dmc_divtable[index];
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
-       } while (tmp & 0x11111111);
-
-       /* Change Divider - TOP */
-       tmp = data->top_divtable[index];
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
-       } while (tmp & 0x11111);
-
-       /* Change Divider - LEFTBUS */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
-
-       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
-               (exynos4210_clkdiv_lr_bus[index][1] <<
-                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
-       } while (tmp & 0x11);
-
-       /* Change Divider - RIGHTBUS */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
-
-       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
-                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
-               (exynos4210_clkdiv_lr_bus[index][1] <<
-                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
-       } while (tmp & 0x11);
-
-       return 0;
-}
-
-static int exynos4x12_set_busclk(struct busfreq_data *data,
-                                struct busfreq_opp_info *oppi)
-{
-       unsigned int index;
-       unsigned int tmp;
-
-       for (index = LV_0; index < EX4x12_LV_NUM; index++)
-               if (oppi->rate == exynos4x12_mifclk_table[index].clk)
-                       break;
-
-       if (index == EX4x12_LV_NUM)
-               return -EINVAL;
-
-       /* Change Divider - DMC0 */
-       tmp = data->dmc_divtable[index];
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
-       } while (tmp & 0x11111111);
-
-       /* Change Divider - DMC1 */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC1);
-
-       tmp &= ~(EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK |
-               EXYNOS4_CLKDIV_DMC1_C2C_MASK |
-               EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
-                               EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT) |
-               (exynos4x12_clkdiv_dmc1[index][1] <<
-                               EXYNOS4_CLKDIV_DMC1_C2C_SHIFT) |
-               (exynos4x12_clkdiv_dmc1[index][2] <<
-                               EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_DMC1);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC1);
-       } while (tmp & 0x111111);
-
-       /* Change Divider - TOP */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
-
-       tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK |
-               EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
-               EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
-               EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
-               EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_top[index][0] <<
-                               EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
-               (exynos4x12_clkdiv_top[index][1] <<
-                               EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
-               (exynos4x12_clkdiv_top[index][2] <<
-                               EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
-               (exynos4x12_clkdiv_top[index][3] <<
-                               EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
-               (exynos4x12_clkdiv_top[index][4] <<
-                               EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
-       } while (tmp & 0x11111);
-
-       /* Change Divider - LEFTBUS */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
-
-       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
-               (exynos4x12_clkdiv_lr_bus[index][1] <<
-                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
-       } while (tmp & 0x11);
-
-       /* Change Divider - RIGHTBUS */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
-
-       tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
-                               EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
-               (exynos4x12_clkdiv_lr_bus[index][1] <<
-                               EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
-       } while (tmp & 0x11);
-
-       /* Change Divider - MFC */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_MFC);
-
-       tmp &= ~(EXYNOS4_CLKDIV_MFC_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
-                               EXYNOS4_CLKDIV_MFC_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_MFC);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_MFC);
-       } while (tmp & 0x1);
-
-       /* Change Divider - JPEG */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_CAM1);
-
-       tmp &= ~(EXYNOS4_CLKDIV_CAM1_JPEG_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
-                               EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_CAM1);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
-       } while (tmp & 0x1);
-
-       /* Change Divider - FIMC0~3 */
-       tmp = __raw_readl(EXYNOS4_CLKDIV_CAM);
-
-       tmp &= ~(EXYNOS4_CLKDIV_CAM_FIMC0_MASK | EXYNOS4_CLKDIV_CAM_FIMC1_MASK |
-               EXYNOS4_CLKDIV_CAM_FIMC2_MASK | EXYNOS4_CLKDIV_CAM_FIMC3_MASK);
-
-       tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
-                               EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT) |
-               (exynos4x12_clkdiv_sclkip[index][2] <<
-                               EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT) |
-               (exynos4x12_clkdiv_sclkip[index][2] <<
-                               EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT) |
-               (exynos4x12_clkdiv_sclkip[index][2] <<
-                               EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT));
-
-       __raw_writel(tmp, EXYNOS4_CLKDIV_CAM);
-
-       do {
-               tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
-       } while (tmp & 0x1111);
-
-       return 0;
-}
-
-static int exynos4x12_get_intspec(unsigned long mifclk)
-{
-       int i = 0;
-
-       while (exynos4x12_intclk_table[i].clk) {
-               if (exynos4x12_intclk_table[i].clk <= mifclk)
-                       return i;
-               i++;
-       }
-
-       return -EINVAL;
-}
-
-static int exynos4_bus_setvolt(struct busfreq_data *data,
-                              struct busfreq_opp_info *oppi,
-                              struct busfreq_opp_info *oldoppi)
-{
-       int err = 0, tmp;
-       unsigned long volt = oppi->volt;
-
-       switch (data->type) {
-       case TYPE_BUSF_EXYNOS4210:
-               /* OPP represents DMC clock + INT voltage */
-               err = regulator_set_voltage(data->vdd_int, volt,
-                                           MAX_SAFEVOLT);
-               break;
-       case TYPE_BUSF_EXYNOS4x12:
-               /* OPP represents MIF clock + MIF voltage */
-               err = regulator_set_voltage(data->vdd_mif, volt,
-                                           MAX_SAFEVOLT);
-               if (err)
-                       break;
-
-               tmp = exynos4x12_get_intspec(oppi->rate);
-               if (tmp < 0) {
-                       err = tmp;
-                       regulator_set_voltage(data->vdd_mif,
-                                             oldoppi->volt,
-                                             MAX_SAFEVOLT);
-                       break;
-               }
-               err = regulator_set_voltage(data->vdd_int,
-                                           exynos4x12_intclk_table[tmp].volt,
-                                           MAX_SAFEVOLT);
-               /*  Try to recover */
-               if (err)
-                       regulator_set_voltage(data->vdd_mif,
-                                             oldoppi->volt,
-                                             MAX_SAFEVOLT);
-               break;
-       default:
-               err = -EINVAL;
-       }
-
-       return err;
-}
-
-static int exynos4_bus_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 *data = platform_get_drvdata(pdev);
-       struct dev_pm_opp *opp;
-       unsigned long freq;
-       unsigned long old_freq = data->curr_oppinfo.rate;
-       struct busfreq_opp_info new_oppinfo;
-
-       rcu_read_lock();
-       opp = devfreq_recommended_opp(dev, _freq, flags);
-       if (IS_ERR(opp)) {
-               rcu_read_unlock();
-               return PTR_ERR(opp);
-       }
-       new_oppinfo.rate = dev_pm_opp_get_freq(opp);
-       new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
-       freq = new_oppinfo.rate;
-
-       if (old_freq == freq)
-               return 0;
-
-       dev_dbg(dev, "targeting %lukHz %luuV\n", freq, new_oppinfo.volt);
-
-       mutex_lock(&data->lock);
-
-       if (data->disabled)
-               goto out;
-
-       if (old_freq < freq)
-               err = exynos4_bus_setvolt(data, &new_oppinfo,
-                                         &data->curr_oppinfo);
-       if (err)
-               goto out;
-
-       if (old_freq != freq) {
-               switch (data->type) {
-               case TYPE_BUSF_EXYNOS4210:
-                       err = exynos4210_set_busclk(data, &new_oppinfo);
-                       break;
-               case TYPE_BUSF_EXYNOS4x12:
-                       err = exynos4x12_set_busclk(data, &new_oppinfo);
-                       break;
-               default:
-                       err = -EINVAL;
-               }
-       }
-       if (err)
-               goto out;
-
-       if (old_freq > freq)
-               err = exynos4_bus_setvolt(data, &new_oppinfo,
-                                         &data->curr_oppinfo);
-       if (err)
-               goto out;
-
-       data->curr_oppinfo = new_oppinfo;
-out:
-       mutex_unlock(&data->lock);
-       return err;
-}
-
-static int exynos4_bus_get_dev_status(struct device *dev,
-                                     struct devfreq_dev_status *stat)
-{
-       struct busfreq_data *data = dev_get_drvdata(dev);
-       struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
-       int busier;
-
-       exynos_read_ppmu(ppmu_data);
-       busier = exynos_get_busier_ppmu(ppmu_data);
-       stat->current_frequency = data->curr_oppinfo.rate;
-
-       /* Number of cycles spent on memory access */
-       stat->busy_time = ppmu_data->ppmu[busier].count[PPMU_PMNCNT3];
-       stat->busy_time *= 100 / BUS_SATURATION_RATIO;
-       stat->total_time = ppmu_data->ppmu[busier].ccnt;
-
-       /* If the counters have overflown, retry */
-       if (ppmu_data->ppmu[busier].ccnt_overflow ||
-           ppmu_data->ppmu[busier].count_overflow[0])
-               return -EAGAIN;
-
-       return 0;
-}
-
-static struct devfreq_dev_profile exynos4_devfreq_profile = {
-       .initial_freq   = 400000,
-       .polling_ms     = 50,
-       .target         = exynos4_bus_target,
-       .get_dev_status = exynos4_bus_get_dev_status,
-};
-
-static int exynos4210_init_tables(struct busfreq_data *data)
-{
-       u32 tmp;
-       int mgrp;
-       int i, err = 0;
-
-       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
-       for (i = LV_0; i < EX4210_LV_NUM; i++) {
-               tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
-                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMC_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
-                       EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
-                       EXYNOS4_CLKDIV_DMC0_CORETI_MASK);
-
-               tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
-                                       EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][1] <<
-                                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][2] <<
-                                       EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][3] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][4] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][5] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][6] <<
-                                       EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
-                       (exynos4210_clkdiv_dmc0[i][7] <<
-                                       EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));
-
-               data->dmc_divtable[i] = tmp;
-       }
-
-       tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
-       for (i = LV_0; i <  EX4210_LV_NUM; i++) {
-               tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
-                       EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
-                       EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
-                       EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
-                       EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
-
-               tmp |= ((exynos4210_clkdiv_top[i][0] <<
-                                       EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
-                       (exynos4210_clkdiv_top[i][1] <<
-                                       EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
-                       (exynos4210_clkdiv_top[i][2] <<
-                                       EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
-                       (exynos4210_clkdiv_top[i][3] <<
-                                       EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
-                       (exynos4210_clkdiv_top[i][4] <<
-                                       EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
-
-               data->top_divtable[i] = tmp;
-       }
-
-       /*
-        * TODO: init tmp based on busfreq_data
-        * (device-tree or platform-data)
-        */
-       tmp = 0; /* Max voltages for the reliability of the unknown */
-
-       pr_debug("ASV Group of Exynos4 is %d\n", tmp);
-       /* Use merged grouping for voltage */
-       switch (tmp) {
-       case 0:
-               mgrp = 0;
-               break;
-       case 1:
-       case 2:
-               mgrp = 1;
-               break;
-       case 3:
-       case 4:
-               mgrp = 2;
-               break;
-       case 5:
-       case 6:
-               mgrp = 3;
-               break;
-       case 7:
-               mgrp = 4;
-               break;
-       default:
-               pr_warn("Unknown ASV Group. Use max voltage.\n");
-               mgrp = 0;
-       }
-
-       for (i = LV_0; i < EX4210_LV_NUM; i++)
-               exynos4210_busclk_table[i].volt = exynos4210_asv_volt[mgrp][i];
-
-       for (i = LV_0; i < EX4210_LV_NUM; i++) {
-               err = dev_pm_opp_add(data->dev, exynos4210_busclk_table[i].clk,
-                             exynos4210_busclk_table[i].volt);
-               if (err) {
-                       dev_err(data->dev, "Cannot add opp entries.\n");
-                       return err;
-               }
-       }
-
-
-       return 0;
-}
-
-static int exynos4x12_init_tables(struct busfreq_data *data)
-{
-       unsigned int i;
-       unsigned int tmp;
-       int ret;
-
-       /* Enable pause function for DREX2 DVFS */
-       tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
-       tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
-       __raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);
-
-       tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
-
-       for (i = 0; i <  EX4x12_LV_NUM; i++) {
-               tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
-                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMC_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
-                       EXYNOS4_CLKDIV_DMC0_DMCP_MASK);
-
-               tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
-                                       EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
-                       (exynos4x12_clkdiv_dmc0[i][1] <<
-                                       EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
-                       (exynos4x12_clkdiv_dmc0[i][2] <<
-                                       EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
-                       (exynos4x12_clkdiv_dmc0[i][3] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
-                       (exynos4x12_clkdiv_dmc0[i][4] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
-                       (exynos4x12_clkdiv_dmc0[i][5] <<
-                                       EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));
-
-               data->dmc_divtable[i] = tmp;
-       }
-
-       tmp = 0; /* Max voltages for the reliability of the unknown */
-
-       if (tmp > 8)
-               tmp = 0;
-       pr_debug("ASV Group of Exynos4x12 is %d\n", tmp);
-
-       for (i = 0; i < EX4x12_LV_NUM; i++) {
-               exynos4x12_mifclk_table[i].volt =
-                       exynos4x12_mif_step_50[tmp][i];
-               exynos4x12_intclk_table[i].volt =
-                       exynos4x12_int_volt[tmp][i];
-       }
-
-       for (i = 0; i < EX4x12_LV_NUM; i++) {
-               ret = dev_pm_opp_add(data->dev, exynos4x12_mifclk_table[i].clk,
-                             exynos4x12_mifclk_table[i].volt);
-               if (ret) {
-                       dev_err(data->dev, "Fail to add opp entries.\n");
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
-               unsigned long event, void *ptr)
-{
-       struct busfreq_data *data = container_of(this, struct busfreq_data,
-                                                pm_notifier);
-       struct dev_pm_opp *opp;
-       struct busfreq_opp_info new_oppinfo;
-       unsigned long maxfreq = ULONG_MAX;
-       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();
-                       dev_err(data->dev, "%s: unable to find a min freq\n",
-                               __func__);
-                       mutex_unlock(&data->lock);
-                       return PTR_ERR(opp);
-               }
-               new_oppinfo.rate = dev_pm_opp_get_freq(opp);
-               new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
-               rcu_read_unlock();
-
-               err = exynos4_bus_setvolt(data, &new_oppinfo,
-                                         &data->curr_oppinfo);
-               if (err)
-                       goto unlock;
-
-               switch (data->type) {
-               case TYPE_BUSF_EXYNOS4210:
-                       err = exynos4210_set_busclk(data, &new_oppinfo);
-                       break;
-               case TYPE_BUSF_EXYNOS4x12:
-                       err = exynos4x12_set_busclk(data, &new_oppinfo);
-                       break;
-               default:
-                       err = -EINVAL;
-               }
-               if (err)
-                       goto unlock;
-
-               data->curr_oppinfo = new_oppinfo;
-unlock:
-               mutex_unlock(&data->lock);
-               if (err)
-                       return err;
-               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 exynos4_busfreq_probe(struct platform_device *pdev)
-{
-       struct busfreq_data *data;
-       struct busfreq_ppmu_data *ppmu_data;
-       struct dev_pm_opp *opp;
-       struct device *dev = &pdev->dev;
-       int err = 0;
-
-       data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), 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;
-       }
-
-       data->type = pdev->id_entry->driver_data;
-       ppmu_data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0;
-       ppmu_data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1;
-       data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event;
-       data->dev = dev;
-       mutex_init(&data->lock);
-
-       switch (data->type) {
-       case TYPE_BUSF_EXYNOS4210:
-               err = exynos4210_init_tables(data);
-               break;
-       case TYPE_BUSF_EXYNOS4x12:
-               err = exynos4x12_init_tables(data);
-               break;
-       default:
-               dev_err(dev, "Cannot determine the device id %d\n", data->type);
-               err = -EINVAL;
-       }
-       if (err) {
-               dev_err(dev, "Cannot initialize busfreq table %d\n",
-                            data->type);
-               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);
-       }
-       if (data->type == TYPE_BUSF_EXYNOS4x12) {
-               data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
-               if (IS_ERR(data->vdd_mif)) {
-                       dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
-                       return PTR_ERR(data->vdd_mif);
-               }
-       }
-
-       rcu_read_lock();
-       opp = dev_pm_opp_find_freq_floor(dev,
-                                        &exynos4_devfreq_profile.initial_freq);
-       if (IS_ERR(opp)) {
-               rcu_read_unlock();
-               dev_err(dev, "Invalid initial frequency %lu kHz.\n",
-                       exynos4_devfreq_profile.initial_freq);
-               return PTR_ERR(opp);
-       }
-       data->curr_oppinfo.rate = dev_pm_opp_get_freq(opp);
-       data->curr_oppinfo.volt = dev_pm_opp_get_voltage(opp);
-       rcu_read_unlock();
-
-       platform_set_drvdata(pdev, data);
-
-       data->devfreq = devm_devfreq_add_device(dev, &exynos4_devfreq_profile,
-                                          "simple_ondemand", NULL);
-       if (IS_ERR(data->devfreq))
-               return PTR_ERR(data->devfreq);
-
-       /*
-        * Start PPMU (Performance Profiling Monitoring Unit) to check
-        * utilization of each IP in the Exynos4 SoC.
-        */
-       busfreq_mon_reset(ppmu_data);
-
-       /* Register opp_notifier for Exynos4 busfreq */
-       err = devm_devfreq_register_opp_notifier(dev, data->devfreq);
-       if (err < 0) {
-               dev_err(dev, "Failed to register opp notifier\n");
-               return err;
-       }
-
-       /* Register pm_notifier for Exynos4 busfreq */
-       err = register_pm_notifier(&data->pm_notifier);
-       if (err) {
-               dev_err(dev, "Failed to setup pm notifier\n");
-               return err;
-       }
-
-       return 0;
-}
-
-static int exynos4_busfreq_remove(struct platform_device *pdev)
-{
-       struct busfreq_data *data = platform_get_drvdata(pdev);
-
-       /* Unregister all of notifier chain */
-       unregister_pm_notifier(&data->pm_notifier);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos4_busfreq_resume(struct device *dev)
-{
-       struct busfreq_data *data = dev_get_drvdata(dev);
-       struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
-
-       busfreq_mon_reset(ppmu_data);
-       return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(exynos4_busfreq_pm_ops, NULL, exynos4_busfreq_resume);
-
-static const struct platform_device_id exynos4_busfreq_id[] = {
-       { "exynos4210-busfreq", TYPE_BUSF_EXYNOS4210 },
-       { "exynos4412-busfreq", TYPE_BUSF_EXYNOS4x12 },
-       { "exynos4212-busfreq", TYPE_BUSF_EXYNOS4x12 },
-       { },
-};
-
-static struct platform_driver exynos4_busfreq_driver = {
-       .probe  = exynos4_busfreq_probe,
-       .remove = exynos4_busfreq_remove,
-       .id_table = exynos4_busfreq_id,
-       .driver = {
-               .name   = "exynos4-busfreq",
-               .pm     = &exynos4_busfreq_pm_ops,
-       },
-};
-
-static int __init exynos4_busfreq_init(void)
-{
-       return platform_driver_register(&exynos4_busfreq_driver);
-}
-late_initcall(exynos4_busfreq_init);
-
-static void __exit exynos4_busfreq_exit(void)
-{
-       platform_driver_unregister(&exynos4_busfreq_driver);
-}
-module_exit(exynos4_busfreq_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("EXYNOS4 busfreq driver with devfreq framework");
-MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
diff --git a/drivers/devfreq/exynos/exynos4_bus.h b/drivers/devfreq/exynos/exynos4_bus.h
deleted file mode 100644 (file)
index 94c73c1..0000000
+++ /dev/null
@@ -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 */
diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
deleted file mode 100644 (file)
index 297ea30..0000000
+++ /dev/null
@@ -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");
diff --git a/drivers/devfreq/exynos/exynos_ppmu.c b/drivers/devfreq/exynos/exynos_ppmu.c
deleted file mode 100644 (file)
index 97b75e5..0000000
+++ /dev/null
@@ -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);
diff --git a/drivers/devfreq/exynos/exynos_ppmu.h b/drivers/devfreq/exynos/exynos_ppmu.h
deleted file mode 100644 (file)
index 71f17ba..0000000
+++ /dev/null
@@ -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 */
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
new file mode 100644 (file)
index 0000000..9ef46e2
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * linux/drivers/devfreq/governor_passive.c
+ *
+ * Copyright (C) 2016 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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/device.h>
+#include <linux/devfreq.h>
+#include "governor.h"
+
+static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
+                                       unsigned long *freq)
+{
+       struct devfreq_passive_data *p_data
+                       = (struct devfreq_passive_data *)devfreq->data;
+       struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
+       unsigned long child_freq = ULONG_MAX;
+       struct dev_pm_opp *opp;
+       int i, count, ret = 0;
+
+       /*
+        * If the devfreq device with passive governor has the specific method
+        * to determine the next frequency, should use the get_target_freq()
+        * of struct devfreq_passive_data.
+        */
+       if (p_data->get_target_freq) {
+               ret = p_data->get_target_freq(devfreq, freq);
+               goto out;
+       }
+
+       /*
+        * If the parent and passive devfreq device uses the OPP table,
+        * get the next frequency by using the OPP table.
+        */
+
+       /*
+        * - parent devfreq device uses the governors except for passive.
+        * - passive devfreq device uses the passive governor.
+        *
+        * Each devfreq has the OPP table. After deciding the new frequency
+        * from the governor of parent devfreq device, the passive governor
+        * need to get the index of new frequency on OPP table of parent
+        * device. And then the index is used for getting the suitable
+        * new frequency for passive devfreq device.
+        */
+       if (!devfreq->profile || !devfreq->profile->freq_table
+               || devfreq->profile->max_state <= 0)
+               return -EINVAL;
+
+       /*
+        * The passive governor have to get the correct frequency from OPP
+        * list of parent device. Because in this case, *freq is temporary
+        * value which is decided by ondemand governor.
+        */
+       rcu_read_lock();
+       opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
+       rcu_read_unlock();
+       if (IS_ERR(opp)) {
+               ret = PTR_ERR(opp);
+               goto out;
+       }
+
+       /*
+        * Get the OPP table's index of decided freqeuncy by governor
+        * of parent device.
+        */
+       for (i = 0; i < parent_devfreq->profile->max_state; i++)
+               if (parent_devfreq->profile->freq_table[i] == *freq)
+                       break;
+
+       if (i == parent_devfreq->profile->max_state) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* Get the suitable frequency by using index of parent device. */
+       if (i < devfreq->profile->max_state) {
+               child_freq = devfreq->profile->freq_table[i];
+       } else {
+               count = devfreq->profile->max_state;
+               child_freq = devfreq->profile->freq_table[count - 1];
+       }
+
+       /* Return the suitable frequency for passive device. */
+       *freq = child_freq;
+
+out:
+       return ret;
+}
+
+static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq)
+{
+       int ret;
+
+       if (!devfreq->governor)
+               return -EINVAL;
+
+       mutex_lock_nested(&devfreq->lock, SINGLE_DEPTH_NESTING);
+
+       ret = devfreq->governor->get_target_freq(devfreq, &freq);
+       if (ret < 0)
+               goto out;
+
+       ret = devfreq->profile->target(devfreq->dev.parent, &freq, 0);
+       if (ret < 0)
+               goto out;
+
+       devfreq->previous_freq = freq;
+
+out:
+       mutex_unlock(&devfreq->lock);
+
+       return 0;
+}
+
+static int devfreq_passive_notifier_call(struct notifier_block *nb,
+                               unsigned long event, void *ptr)
+{
+       struct devfreq_passive_data *data
+                       = container_of(nb, struct devfreq_passive_data, nb);
+       struct devfreq *devfreq = (struct devfreq *)data->this;
+       struct devfreq *parent = (struct devfreq *)data->parent;
+       struct devfreq_freqs *freqs = (struct devfreq_freqs *)ptr;
+       unsigned long freq = freqs->new;
+
+       switch (event) {
+       case DEVFREQ_PRECHANGE:
+               if (parent->previous_freq > freq)
+                       update_devfreq_passive(devfreq, freq);
+               break;
+       case DEVFREQ_POSTCHANGE:
+               if (parent->previous_freq < freq)
+                       update_devfreq_passive(devfreq, freq);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static int devfreq_passive_event_handler(struct devfreq *devfreq,
+                               unsigned int event, void *data)
+{
+       struct device *dev = devfreq->dev.parent;
+       struct devfreq_passive_data *p_data
+                       = (struct devfreq_passive_data *)devfreq->data;
+       struct devfreq *parent = (struct devfreq *)p_data->parent;
+       struct notifier_block *nb = &p_data->nb;
+       int ret = 0;
+
+       if (!parent)
+               return -EPROBE_DEFER;
+
+       switch (event) {
+       case DEVFREQ_GOV_START:
+               if (!p_data->this)
+                       p_data->this = devfreq;
+
+               nb->notifier_call = devfreq_passive_notifier_call;
+               ret = devm_devfreq_register_notifier(dev, parent, nb,
+                                       DEVFREQ_TRANSITION_NOTIFIER);
+               break;
+       case DEVFREQ_GOV_STOP:
+               devm_devfreq_unregister_notifier(dev, parent, nb,
+                                       DEVFREQ_TRANSITION_NOTIFIER);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static struct devfreq_governor devfreq_passive = {
+       .name = "passive",
+       .get_target_freq = devfreq_passive_get_target_freq,
+       .event_handler = devfreq_passive_event_handler,
+};
+
+static int __init devfreq_passive_init(void)
+{
+       return devfreq_add_governor(&devfreq_passive);
+}
+subsys_initcall(devfreq_passive_init);
+
+static void __exit devfreq_passive_exit(void)
+{
+       int ret;
+
+       ret = devfreq_remove_governor(&devfreq_passive);
+       if (ret)
+               pr_err("%s: failed remove governor %d\n", __func__, ret);
+}
+module_exit(devfreq_passive_exit);
+
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("DEVFREQ Passive governor");
+MODULE_LICENSE("GPL v2");
index 6fa02a2..2de4e2e 100644 (file)
 
 #define DEVFREQ_NAME_LEN 16
 
+/* DEVFREQ notifier interface */
+#define DEVFREQ_TRANSITION_NOTIFIER    (0)
+
+/* Transition notifiers of DEVFREQ_TRANSITION_NOTIFIER */
+#define        DEVFREQ_PRECHANGE               (0)
+#define DEVFREQ_POSTCHANGE             (1)
+
 struct devfreq;
 
 /**
@@ -143,6 +150,7 @@ struct devfreq_governor {
  * @trans_table:       Statistics of devfreq transitions
  * @time_in_state:     Statistics of devfreq states
  * @last_stat_updated: The last time stat updated
+ * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
  *
  * This structure stores the devfreq information for a give device.
  *
@@ -177,6 +185,13 @@ struct devfreq {
        unsigned int *trans_table;
        unsigned long *time_in_state;
        unsigned long last_stat_updated;
+
+       struct srcu_notifier_head transition_notifier_list;
+};
+
+struct devfreq_freqs {
+       unsigned long old;
+       unsigned long new;
 };
 
 #if defined(CONFIG_PM_DEVFREQ)
@@ -207,6 +222,22 @@ extern int devm_devfreq_register_opp_notifier(struct device *dev,
                                              struct devfreq *devfreq);
 extern void devm_devfreq_unregister_opp_notifier(struct device *dev,
                                                struct devfreq *devfreq);
+extern int devfreq_register_notifier(struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list);
+extern int devfreq_unregister_notifier(struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list);
+extern int devm_devfreq_register_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list);
+extern void devm_devfreq_unregister_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list);
+extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
+                                               int index);
 
 /**
  * devfreq_update_stats() - update the last_status pointer in struct devfreq
@@ -241,6 +272,39 @@ struct devfreq_simple_ondemand_data {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
+/**
+ * struct devfreq_passive_data - void *data fed to struct devfreq
+ *     and devfreq_add_device
+ * @parent:    the devfreq instance of parent device.
+ * @get_target_freq:   Optional callback, Returns desired operating frequency
+ *                     for the device using passive governor. That is called
+ *                     when passive governor should decide the next frequency
+ *                     by using the new frequency of parent devfreq device
+ *                     using governors except for passive governor.
+ *                     If the devfreq device has the specific method to decide
+ *                     the next frequency, should use this callback.
+ * @this:      the devfreq instance of own device.
+ * @nb:                the notifier block for DEVFREQ_TRANSITION_NOTIFIER list
+ *
+ * The devfreq_passive_data have to set the devfreq instance of parent
+ * device with governors except for the passive governor. But, don't need to
+ * initialize the 'this' and 'nb' field because the devfreq core will handle
+ * them.
+ */
+struct devfreq_passive_data {
+       /* Should set the devfreq instance of parent device */
+       struct devfreq *parent;
+
+       /* Optional callback to decide the next frequency of passvice device */
+       int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
+
+       /* For passive governor's internal use. Don't need to set them */
+       struct devfreq *this;
+       struct notifier_block nb;
+};
+#endif
+
 #else /* !CONFIG_PM_DEVFREQ */
 static inline struct devfreq *devfreq_add_device(struct device *dev,
                                          struct devfreq_dev_profile *profile,
@@ -307,6 +371,41 @@ static inline void devm_devfreq_unregister_opp_notifier(struct device *dev,
 {
 }
 
+static inline int devfreq_register_notifier(struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list)
+{
+       return 0;
+}
+
+static inline int devfreq_unregister_notifier(struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list)
+{
+       return 0;
+}
+
+static inline int devm_devfreq_register_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+       return 0;
+}
+
+static inline void devm_devfreq_unregister_notifier(struct device *dev,
+                               struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list)
+{
+}
+
+static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
+                                                       int index)
+{
+       return ERR_PTR(-ENODEV);
+}
+
 static inline int devfreq_update_stats(struct devfreq *df)
 {
        return -EINVAL;