Re: [PATCH v4 1/5] thermal: Add generic cpufreq cooling implementation

2012-06-25 Thread Rob Lee
Hey Amit,

I was just re-organizing the imx thermal driver that uses this cpu
cooling interface and noticed a couple of small issues here.   If
these suggestions are agreed upon and if it's too late for these
issues be changed with this patchset, I can submit them separately
unless you'd prefer to.

On Sat, May 12, 2012 at 4:40 AM, Amit Daniel Kachhap
amit.kach...@linaro.org wrote:
 This patch adds support for generic cpu thermal cooling low level
 implementations using frequency scaling up/down based on the registration
 parameters. Different cpu related cooling devices can be registered by the
 user and the binding of these cooling devices to the corresponding
 trip points can be easily done as the registration APIs return the
 cooling device pointer. The user of these APIs are responsible for
 passing clipping frequency . The drivers can also register to recieve
 notification about any cooling action called.

 Signed-off-by: Amit Daniel Kachhap amit.kach...@linaro.org
 ---
  Documentation/thermal/cpu-cooling-api.txt |   60 
  drivers/thermal/Kconfig                   |   11 +
  drivers/thermal/Makefile                  |    3 +-
  drivers/thermal/cpu_cooling.c             |  483 
 +
  include/linux/cpu_cooling.h               |   99 ++
  5 files changed, 655 insertions(+), 1 deletions(-)
  create mode 100644 Documentation/thermal/cpu-cooling-api.txt
  create mode 100644 drivers/thermal/cpu_cooling.c
  create mode 100644 include/linux/cpu_cooling.h

 diff --git a/Documentation/thermal/cpu-cooling-api.txt 
 b/Documentation/thermal/cpu-cooling-api.txt
 new file mode 100644
 index 000..557adb8
 --- /dev/null
 +++ b/Documentation/thermal/cpu-cooling-api.txt
 @@ -0,0 +1,60 @@
 +CPU cooling APIs How To
 +===
 +
 +Written by Amit Daniel Kachhap amit.kach...@linaro.org
 +
 +Updated: 12 May 2012
 +
 +Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
 +
 +0. Introduction
 +
 +The generic cpu cooling(freq clipping, cpuhotplug etc) provides
 +registration/unregistration APIs to the caller. The binding of the cooling
 +devices to the trip point is left for the user. The registration APIs returns
 +the cooling device pointer.
 +
 +1. cpu cooling APIs
 +
 +1.1 cpufreq registration/unregistration APIs
 +1.1.1 struct thermal_cooling_device *cpufreq_cooling_register(
 +       struct freq_clip_table *tab_ptr, unsigned int tab_size)
 +
 +    This interface function registers the cpufreq cooling device with the 
 name
 +    thermal-cpufreq-%x. This api can support multiple instances of cpufreq
 +    cooling devices.
 +
 +    tab_ptr: The table containing the maximum value of frequency to be 
 clipped
 +    for each cooling state.
 +       .freq_clip_max: Value of frequency to be clipped for each allowed
 +        cpus.
 +       .temp_level: Temperature level at which the frequency clamping will
 +       happen.
 +       .mask_val: cpumask of the allowed cpu's
 +    tab_size: the total number of cpufreq cooling states.
 +
 +1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 +
 +    This interface function unregisters the thermal-cpufreq-%x cooling 
 device.
 +
 +    cdev: Cooling device pointer which has to be unregistered.
 +
 +
 +1.2 CPU cooling action notifier register/unregister interface
 +1.2.1 int cputherm_register_notifier(struct notifier_block *nb,
 +       unsigned int list)
 +
 +    This interface registers a driver with cpu cooling layer. The driver will
 +    be notified when any cpu cooling action is called.
 +
 +    nb: notifier function to register
 +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
 +
 +1.2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
 +       unsigned int list)
 +
 +    This interface registers a driver with cpu cooling layer. The driver will
 +    be notified when any cpu cooling action is called.
 +
 +    nb: notifier function to register
 +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
 diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
 index 514a691..d9c529f 100644
 --- a/drivers/thermal/Kconfig
 +++ b/drivers/thermal/Kconfig
 @@ -19,6 +19,17 @@ config THERMAL_HWMON
        depends on HWMON=y || HWMON=THERMAL
        default y

 +config CPU_THERMAL

Perhaps the name CPU_COOLING or CPUFREQ_COOLING would more accurately
describe this functionality?  I like the latter since now this
mechanism only supports cooling by using cpufreq.

 +       bool generic cpu cooling support

If we use CPUFREQ_COOLING, then perhaps this could say:

bool cpu cooling through cpufreq frequency limiting

 +       depends on THERMAL  CPU_FREQ
 +       help
 +         This implements the generic cpu cooling mechanism through frequency
 +         reduction, cpu hotplug and any other ways of reducing temperature. 
 An
 +         ACPI version of this already 
 exists(drivers/acpi/processor_thermal.c).
 +         This will be useful for platforms using 

Re: [PATCH] ARM: exynos: Adapt to cpuidle core time keeping and irq enable

2012-04-30 Thread Rob Lee
On Wed, Apr 25, 2012 at 9:44 AM, Daniel Lezcano
daniel.lezc...@linaro.org wrote:
 On 04/25/2012 02:11 PM, Amit Daniel Kachhap wrote:

 This patch enables core cpuidle timekeeping and irq enabling and
 remove those redundant parts from the exynos cpuidle drivers

 CC: Daniel Lezcanodaniel.lezc...@linaro.org
 CC: Robert Leerob@linaro.org
 Signed-off-by: Amit Danielamit.kach...@linaro.org
 ---
  arch/arm/mach-exynos/cpuidle.c |   53
 ---
  1 files changed, 6 insertions(+), 47 deletions(-)

 diff --git a/arch/arm/mach-exynos/cpuidle.c
 b/arch/arm/mach-exynos/cpuidle.c
 index 33ab4e7..26dac28 100644
 --- a/arch/arm/mach-exynos/cpuidle.c
 +++ b/arch/arm/mach-exynos/cpuidle.c
 @@ -20,6 +20,7 @@
  #includeasm/smp_scu.h
  #includeasm/suspend.h
  #includeasm/unified.h
 +#includeasm/cpuidle.h
  #includemach/regs-pmu.h
  #includemach/pmu.h

 @@ -34,22 +35,12 @@

  #define S5P_CHECK_AFTR                0xFCBA0D10

 -static int exynos4_enter_idle(struct cpuidle_device *dev,
 -                       struct cpuidle_driver *drv,
 -                             int index);
  static int exynos4_enter_lowpower(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
                                int index);

  static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
 -       [0] = {
 -               .enter                  = exynos4_enter_idle,
 -               .exit_latency           = 1,
 -               .target_residency       = 10,
 -               .flags                  = CPUIDLE_FLAG_TIME_VALID,
 -               .name                   = C0,
 -               .desc                   = ARM clock gating(WFI),
 -       },
 +       [0] = ARM_CPUIDLE_WFI_STATE,
        [1] = {
                .enter                  = exynos4_enter_lowpower,
                .exit_latency           = 300,
 @@ -63,8 +54,9 @@ static struct cpuidle_state exynos4_cpuidle_set[]
 __initdata = {
  static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);

  static struct cpuidle_driver exynos4_idle_driver = {
 -       .name           = exynos4_idle,
 -       .owner          = THIS_MODULE,
 +       .name                   = exynos4_idle,
 +       .owner                  = THIS_MODULE,
 +       .en_core_tk_irqen       = 1,
  };

  /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
 @@ -103,13 +95,8 @@ static int exynos4_enter_core0_aftr(struct
 cpuidle_device *dev,
                                struct cpuidle_driver *drv,
                                int index)
  {
 -       struct timeval before, after;
 -       int idle_time;
        unsigned long tmp;

 -       local_irq_disable();
 -       do_gettimeofday(before);
 -
        exynos4_set_wakeupmask();

        /* Set value of power down register for aftr mode */
 @@ -150,34 +137,6 @@ static int exynos4_enter_core0_aftr(struct
 cpuidle_device *dev,
        /* Clear wakeup state register */
        __raw_writel(0x0, S5P_WAKEUP_STAT);

 -       do_gettimeofday(after);
 -
 -       local_irq_enable();
 -       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 -                   (after.tv_usec - before.tv_usec);
 -
 -       dev-last_residency = idle_time;
 -       return index;
 -}
 -
 -static int exynos4_enter_idle(struct cpuidle_device *dev,
 -                               struct cpuidle_driver *drv,
 -                               int index)
 -{
 -       struct timeval before, after;
 -       int idle_time;
 -
 -       local_irq_disable();
 -       do_gettimeofday(before);
 -
 -       cpu_do_idle();
 -
 -       do_gettimeofday(after);
 -       local_irq_enable();
 -       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 -                   (after.tv_usec - before.tv_usec);
 -
 -       dev-last_residency = idle_time;
        return index;
  }

 @@ -192,7 +151,7 @@ static int exynos4_enter_lowpower(struct
 cpuidle_device *dev,
                new_index = drv-safe_state_index;

        if (new_index == 0)
 -               return exynos4_enter_idle(dev, drv, new_index);
 +               return arm_cpuidle_simple_enter(dev, drv, new_index);
        else
                return exynos4_enter_core0_aftr(dev, drv, new_index);
  }

Acked-by: Robert Lee rob@linaro.org



 Acked-by: Daniel Lezcano daniel.lezc...@linaro.org

 --
  http://www.linaro.org/ Linaro.org │ Open source software for ARM SoCs

 Follow Linaro:  http://www.facebook.com/pages/Linaro Facebook |
 http://twitter.com/#!/linaroorg Twitter |
 http://www.linaro.org/linaro-blog/ Blog

--
To unsubscribe from this list: send the line unsubscribe linux-samsung-soc in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH V6 1/5] ARM: exynos: Add support AFTR mode on EXYNOS4210

2012-02-22 Thread Rob Lee
  static struct cpuidle_state exynos4_cpuidle_set[] = {
        [0] = {
 @@ -27,9 +47,17 @@ static struct cpuidle_state exynos4_cpuidle_set[] = {
                .exit_latency           = 1,
                .target_residency       = 10,
                .flags                  = CPUIDLE_FLAG_TIME_VALID,
 -               .name                   = IDLE,
 +               .name                   = C0,
                .desc                   = ARM clock gating(WFI),
        },
 +       [1] = {
 +               .enter                  = exynos4_enter_lowpower,
 +               .exit_latency           = 300,
 +               .target_residency       = 10,
 +               .flags                  = CPUIDLE_FLAG_TIME_VALID,
 +               .name                   = C1,
 +               .desc                   = ARM power down,
 +       },
  };

It looks like you could make this __initdata because your are copying
this state data over to the cpuidle_driver object during
initialization.


  static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
 @@ -39,9 +67,100 @@ static struct cpuidle_driver exynos4_idle_driver = {
        .owner          = THIS_MODULE,
  };

 +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
 +static void exynos4_set_wakeupmask(void)
 +{
 +       __raw_writel(0xff3e, S5P_WAKEUP_MASK);
 +}
 +
 +static unsigned int g_pwr_ctrl, g_diag_reg;
 +
 +static void save_cpu_arch_register(void)
 +{
 +       /*read power control register*/
 +       asm(mrc p15, 0, %0, c15, c0, 0 : =r(g_pwr_ctrl) : : cc);
 +       /*read diagnostic register*/
 +       asm(mrc p15, 0, %0, c15, c0, 1 : =r(g_diag_reg) : : cc);
 +       return;
 +}
 +
 +static void restore_cpu_arch_register(void)
 +{
 +       /*write power control register*/
 +       asm(mcr p15, 0, %0, c15, c0, 0 : : r(g_pwr_ctrl) : cc);
 +       /*write diagnostic register*/
 +       asm(mcr p15, 0, %0, c15, c0, 1 : : r(g_diag_reg) : cc);
 +       return;
 +}
 +
 +static int idle_finisher(unsigned long flags)
 +{
 +       cpu_do_idle();
 +       return 1;
 +}
 +
 +static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
 +                               struct cpuidle_driver *drv,
 +                               int index)
 +{
 +       struct timeval before, after;
 +       int idle_time;
 +       unsigned long tmp;
 +
 +       local_irq_disable();
 +       do_gettimeofday(before);
 +
 +       exynos4_set_wakeupmask();
 +
 +       /* Set value of power down register for aftr mode */
 +       exynos4_sys_powerdown_conf(SYS_AFTR);
 +
 +       __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
 +       __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
 +
 +       save_cpu_arch_register();
 +
 +       /* Setting Central Sequence Register for power down mode */
 +       tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
 +       tmp = ~S5P_CENTRAL_LOWPWR_CFG;
 +       __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
 +
 +       cpu_pm_enter();
 +       cpu_suspend(0, idle_finisher);
 +
 +       scu_enable(S5P_VA_SCU);
 +       cpu_pm_exit();
 +
 +       restore_cpu_arch_register();
 +
 +       /*
 +        * If PMU failed while entering sleep mode, WFI will be
 +        * ignored by PMU and then exiting cpu_do_idle().
 +        * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
 +        * in this situation.
 +        */
 +       tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
 +       if (!(tmp  S5P_CENTRAL_LOWPWR_CFG)) {
 +               tmp |= S5P_CENTRAL_LOWPWR_CFG;
 +               __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
 +       }
 +
 +       /* Clear wakeup state register */
 +       __raw_writel(0x0, S5P_WAKEUP_STAT);
 +
 +       do_gettimeofday(after);
 +
 +       local_irq_enable();
 +       idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
 +                   (after.tv_usec - before.tv_usec);
 +
 +       dev-last_residency = idle_time;
 +       return index;
 +}
 +
  static int exynos4_enter_idle(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
 -                             int index)
 +                               int index)
  {
        struct timeval before, after;
        int idle_time;
 @@ -60,6 +179,22 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
        return index;
  }

 +static int exynos4_enter_lowpower(struct cpuidle_device *dev,
 +                               struct cpuidle_driver *drv,
 +                               int index)
 +{
 +       int new_index = index;
 +
 +       /* This mode only can be entered when other core's are offline */
 +       if (num_online_cpus()  1)
 +               new_index = drv-safe_state_index;
 +
 +       if (new_index == 0)
 +               return exynos4_enter_idle(dev, drv, new_index);
 +       else
 +               return exynos4_enter_core0_aftr(dev, drv, new_index);
 +}
 +
  static int __init exynos4_init_cpuidle(void)
  {
        int i, max_cpuidle_state, cpu_id;