diff options
4 files changed, 290 insertions, 2 deletions
diff --git a/drivers/staging/thermal_framework/governor/Makefile b/drivers/staging/thermal_framework/governor/Makefile index 0b5eff7..8ba37ee 100644 --- a/drivers/staging/thermal_framework/governor/Makefile +++ b/drivers/staging/thermal_framework/governor/Makefile @@ -2,3 +2,4 @@ # Makefile for Thermal governor drivers. # obj-$(CONFIG_OMAP_DIE_GOVERNOR) += omap_die_governor.o +obj-$(CONFIG_OMAP4_DUTY_CYCLE) += omap4_duty_cycle_governor.o diff --git a/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c b/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c new file mode 100644 index 0000000..c1d4edb --- /dev/null +++ b/drivers/staging/thermal_framework/governor/omap4_duty_cycle_governor.c @@ -0,0 +1,199 @@ +/* + * Duty cycle governor + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Eugene Mandrenko <Ievgen.mandrenko@ti.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/omap4_duty_cycle_governor.h> +#include <plat/omap_device.h> + +#define NORMAL_TEMP_MONITORING_RATE 1000 +#define NORMAL_MONITORING_RATE 10000 +#define DEFAULT_TEMPERATURE 65000 +#define TEMP_THRESHOLD 1 +#define INIT_SECTION -1 + +struct duty_governor { + struct pcb_sens *tpcb; + struct duty_cycle *tduty; + struct pcb_section *tpcb_sections; + int period; + int previous_temp; + int curr_pcb_temp; + int previous_pcb_temp; + int working_section; + int npcb_sections; + struct delayed_work duty_cycle_governor_work; +}; + +static struct duty_governor *t_governor; +static struct pcb_section *pcb_sections; +static int pcb_sections_size; + +void omap4_duty_pcb_section_reg(struct pcb_section *pcb_sect, int sect_size) +{ + pcb_sections = pcb_sect; + pcb_sections_size = sect_size; +} + +static void omap4_duty_schedule(struct duty_governor *t_gov) +{ + if (!IS_ERR_OR_NULL(t_gov) && + !IS_ERR_OR_NULL(t_gov->tpcb) && + !IS_ERR_OR_NULL(t_gov->tduty)) + schedule_delayed_work(&t_governor->duty_cycle_governor_work, + msecs_to_jiffies(0)); +} + +int omap4_duty_pcb_register(struct pcb_sens *tpcb) +{ + if (!IS_ERR_OR_NULL(t_governor)) { + if (t_governor->tpcb == NULL) { + t_governor->tpcb = tpcb; + t_governor->period = NORMAL_TEMP_MONITORING_RATE; + } else { + pr_err("%s:dublicate of pcb registration\n", __func__); + + return -EBUSY; + } + } + omap4_duty_schedule(t_governor); + + return 0; +} +static bool is_treshold(struct duty_governor *tgov) +{ + int delta; + + delta = abs(tgov->previous_pcb_temp - tgov->curr_pcb_temp); + + if (delta > TEMP_THRESHOLD) + return true; + + return false; +} + +static int omap4_duty_apply_constraint(struct duty_governor *tgov, + int sect_num) +{ + struct pcb_section *t_pcb_sections = &tgov->tpcb_sections[sect_num]; + struct duty_cycle_params *tduty_params = &t_pcb_sections->tduty_params; + int dc_enabled = t_pcb_sections->duty_cycle_enabled; + struct duty_cycle *t_duty = tgov->tduty; + int ret = true; + + if (tgov->working_section != sect_num) { + ret = tgov->tduty->enable(false, false); + + if (ret) + return ret; + + if (dc_enabled) { + if (t_duty->update_params(tduty_params)) + return ret; + + tgov->tduty->enable(dc_enabled, true); + } + tgov->working_section = sect_num; + } + + return ret; +} + +static void omap4_duty_update(struct duty_governor *tgov) +{ + int sect_num; + + for (sect_num = 0; sect_num < tgov->npcb_sections; sect_num++) + if (tgov->tpcb_sections[sect_num].pcb_temp_level > + tgov->curr_pcb_temp) + break; + if (sect_num >= tgov->npcb_sections) + sect_num = tgov->npcb_sections - 1; + + if (omap4_duty_apply_constraint(tgov, sect_num)) + tgov->previous_pcb_temp = tgov->curr_pcb_temp; +} + +static void omap4_duty_governor_delayed_work_fn(struct work_struct *work) +{ + if (!IS_ERR_OR_NULL(t_governor->tpcb)) { + if (!IS_ERR_OR_NULL(t_governor->tpcb->update_temp)) { + t_governor->curr_pcb_temp = + t_governor->tpcb->update_temp(); + if (is_treshold(t_governor)) + omap4_duty_update(t_governor); + } else { + pr_err("%s:update_temp() isn't defined\n", __func__); + } + } + schedule_delayed_work(&t_governor->duty_cycle_governor_work, + msecs_to_jiffies(t_governor->period)); +} + +int omap4_duty_cycle_register(struct duty_cycle *tduty) +{ + if (!IS_ERR_OR_NULL(t_governor)) { + if (t_governor->tduty == NULL) { + t_governor->tduty = tduty; + } else { + pr_err("%s:dublicate of duty cycle registration\n", + __func__); + + return -EBUSY; + } + } + omap4_duty_schedule(t_governor); + + return 0; +} + +static int __init omap4_duty_governor_init(void) +{ + if (!cpu_is_omap443x()) + return 0; + + t_governor = kzalloc(sizeof(struct duty_governor), GFP_KERNEL); + if (IS_ERR_OR_NULL(t_governor)) { + pr_err("%s:Cannot allocate memory\n", __func__); + + return -ENOMEM; + } + t_governor->period = NORMAL_MONITORING_RATE; + t_governor->previous_temp = DEFAULT_TEMPERATURE; + t_governor->tpcb_sections = pcb_sections; + t_governor->npcb_sections = pcb_sections_size; + t_governor->working_section = INIT_SECTION; + INIT_DELAYED_WORK(&t_governor->duty_cycle_governor_work, + omap4_duty_governor_delayed_work_fn); + + return 0; +} + +static void __exit omap4_duty_governor_exit(void) +{ + cancel_delayed_work_sync(&t_governor->duty_cycle_governor_work); + kfree(t_governor); +} + +early_initcall(omap4_duty_governor_init); +module_exit(omap4_duty_governor_exit); + +MODULE_AUTHOR("Euvgen Mandrenko <ievgen.mandrenko@ti.com>"); +MODULE_DESCRIPTION("OMAP on-die thermal governor"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/thermal_framework/omap4_duty_cycle.c b/drivers/staging/thermal_framework/omap4_duty_cycle.c index cf81548..896ec5c 100644 --- a/drivers/staging/thermal_framework/omap4_duty_cycle.c +++ b/drivers/staging/thermal_framework/omap4_duty_cycle.c @@ -30,6 +30,7 @@ #include <linux/workqueue.h> #include <linux/mutex.h> #include <linux/platform_device.h> +#include <linux/omap4_duty_cycle_governor.h> #include <plat/omap_device.h> @@ -62,6 +63,7 @@ static bool enabled; static bool saved_hotplug_enabled; static int heating_budget; static unsigned long t_heating_start; +static struct duty_cycle *t_duty; static struct workqueue_struct *duty_wq; static struct delayed_work work_exit_cool; @@ -556,6 +558,39 @@ static struct platform_driver omap4_duty_driver = { .remove = __exit_p(omap4_duty_remove), }; +static int update_params(struct duty_cycle_params *dc_params) +{ + int ret; + + ret = mutex_lock_interruptible(&mutex_duty); + if (ret) + return ret; + + cooling_rate = dc_params->cooling_rate; + nitro_rate = dc_params->nitro_rate; + nitro_percentage = dc_params->nitro_percentage; + nitro_interval = dc_params->nitro_interval; + + mutex_unlock(&mutex_duty); + + return 0; +} + +static int __init omap4_duty_register(void) +{ + t_duty = kzalloc(sizeof(struct duty_cycle), GFP_KERNEL); + if (IS_ERR_OR_NULL(t_duty)) { + pr_err("%s:Cannot allocate memory\n", __func__); + + return -ENOMEM; + } + t_duty->enable = omap4_duty_cycle_set_enabled; + t_duty->update_params = update_params; + omap4_duty_cycle_register(t_duty); + + return 0; +} + /* Module Interface */ static int __init omap4_duty_module_init(void) { @@ -604,12 +639,18 @@ static int __init omap4_duty_module_init(void) goto unregister_hotplug; } - err = platform_driver_probe(&omap4_duty_driver, omap4_duty_probe); + err = omap4_duty_register(); if (err) goto exit_pdevice; + err = platform_driver_probe(&omap4_duty_driver, omap4_duty_probe); + if (err) + goto unregister_duty; + return 0; +unregister_duty: + kfree(t_duty); exit_pdevice: platform_device_unregister(omap4_duty_device); unregister_hotplug: @@ -637,7 +678,7 @@ static void __exit omap4_duty_module_exit(void) cancel_work_sync(&work_enter_cool1); cancel_work_sync(&work_cpu1_plugin); cancel_work_sync(&work_cpu1_plugout); - + kfree(t_duty); destroy_workqueue(duty_wq); pr_debug("%s Done\n", __func__); diff --git a/include/linux/omap4_duty_cycle_governor.h b/include/linux/omap4_duty_cycle_governor.h new file mode 100644 index 0000000..4e2baa9 --- /dev/null +++ b/include/linux/omap4_duty_cycle_governor.h @@ -0,0 +1,47 @@ +/* + * Duty sycle governor + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Eugene Mandrenko <ievgen.mandrenko@ti.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * +*/ + +#ifndef __OMAP4_DUTY_CYCLE_GOVERNOR_H__ +#define __OMAP4_DUTY_CYCLE_GOVERNOR_H__ + +struct pcb_sens { + int (*update_temp) (void); +}; + +struct duty_cycle_params { + u32 nitro_rate; /* the maximum OPP frequency */ + u32 cooling_rate; /* the OPP used to cool off */ + u32 nitro_interval; /* time interval to control the duty cycle */ + u32 nitro_percentage; /* % out of nitro_interval to use max OPP */ +}; + +struct pcb_section { + u32 pcb_temp_level; + u32 max_opp; + struct duty_cycle_params tduty_params; + bool duty_cycle_enabled; +}; + +struct duty_cycle { + int (*update_params)(struct duty_cycle_params *); + int (*enable)(bool val, bool update); +}; + +void omap4_duty_pcb_section_reg(struct pcb_section *pcb_sect, int sect_size); +int omap4_duty_pcb_register(struct pcb_sens *tpcb); +int omap4_duty_cycle_register(struct duty_cycle *tduty); +#endif /*__OMAP4_DUTY_CYCLE_GOVERNOR_H__*/ |