aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahid Akhtar <sakhtar@ti.com>2010-12-10 02:37:31 -0500
committerPaolo Pisati <paolo.pisati@canonical.com>2012-08-17 04:19:11 -0400
commitd15bd422aea2047e026563c4a684b16b657a3467 (patch)
treee151af01d24c19c1ace66f9a5e15632851327817
parente12e9df954d8f26d66f7cf3809393d0b83265e50 (diff)
syslink:ipu_pm: Modifications for timer setup for WDT
Modified to configure timer 3 that is used to trigger hibernation and it is also used as watch dog timer. Since both ducati cores can go to retention together and if one core is not responding both need to be reset, we only use 1 timer [Hari K] The free irq while freeing checks the dev_id as the token with the dev_id that it was registered earlier. To avoid the race condition as when the remote proc frees the dmtimer handle save the handle in ipu_pm to use it as a token when passing to free_irq A cleaner solution should be investigated for watchdog timer Change-Id: I15d3c0182d84861819cc36abf1f78cbc1674375f Signed-off-by: Shahid Akhtar <sakhtar@ti.com>
-rw-r--r--drivers/dsp/syslink/Kconfig33
-rw-r--r--drivers/dsp/syslink/ipu_pm/ipu_pm.c198
-rw-r--r--drivers/dsp/syslink/ipu_pm/ipu_pm.h24
3 files changed, 250 insertions, 5 deletions
diff --git a/drivers/dsp/syslink/Kconfig b/drivers/dsp/syslink/Kconfig
index 0ac3187d475..08eeb5c8715 100644
--- a/drivers/dsp/syslink/Kconfig
+++ b/drivers/dsp/syslink/Kconfig
@@ -29,11 +29,36 @@ config DUCATI_BASEIMAGE_PHYS_ADDR
29 loaded. 29 loaded.
30 30
31config SYSLINK_DUCATI_PM 31config SYSLINK_DUCATI_PM
32 tristate "DUCATI POWER MANAGEMENT" 32 bool "IPU Power Management"
33 depends on SYSLINK_PROC && SYSLINK_PROC4430 33 depends on SYSLINK_PROC
34 default n 34 default y
35 help 35 help
36 Ducati Power Management Implementation 36 Enables the options available for ipu_pm implementation
37
38config SYSLINK_IPU_SELF_HIBERNATION
39 bool "Enable IPU Self hibernation"
40 depends on SYSLINK_DUCATI_PM
41 default y
42 help
43 IPU will hibernate by it self after a configurable time, this
44 controls the self hibernation, IPU will hibernate when a system
45 suspend is executed and wake up when system resumes.
46
47config DUCATI_WATCH_DOG
48 bool "Enable Ducati watch dog timer"
49 depends on SYSLINK_IPU_SELF_HIBERNATION
50 default n
51 help
52 Ducati cores will trigger reset if any of the two M3 cores stop
53 responding after 7 seconds. Requires Hibernation enabled. If
54 hibernation is enabled, M3 cores go to hibernation after 5
55 seconds. Ducati cannot go to hibernation if fault occurs on one
56 of the M3 cores
57
58config SYSLINK_IPU_PM_TRACES
59 bool "IPU PM Debug Traces"
60 depends on SYSLINK_DUCATI_PM
61 default n
37 62
38config OMAP_DEVICE_HANDLER 63config OMAP_DEVICE_HANDLER
39 tristate "Device Handler" 64 tristate "Device Handler"
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.c b/drivers/dsp/syslink/ipu_pm/ipu_pm.c
index f3ca91a569c..0af1b592ff6 100644
--- a/drivers/dsp/syslink/ipu_pm/ipu_pm.c
+++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.c
@@ -27,7 +27,12 @@
27#include <linux/io.h> 27#include <linux/io.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/vmalloc.h> 29#include <linux/vmalloc.h>
30#include <linux/interrupt.h>
31#include <linux/notifier.h>
32#include <linux/clk.h>
30#include <linux/uaccess.h> 33#include <linux/uaccess.h>
34#include <linux/irq.h>
35
31#include <linux/platform_device.h> 36#include <linux/platform_device.h>
32#include <syslink/notify.h> 37#include <syslink/notify.h>
33#include <syslink/notify_driver.h> 38#include <syslink/notify_driver.h>
@@ -261,6 +266,18 @@ static inline int ipu_pm_rel_cstr(struct ipu_pm_object *handle,
261 struct rcb_block *rcb_p, 266 struct rcb_block *rcb_p,
262 struct ipu_pm_params *params); 267 struct ipu_pm_params *params);
263 268
269/* Hibernate and watch dog timer interrupt */
270static irqreturn_t ipu_pm_timer_interrupt(int irq,
271 void *dev_id);
272
273/* Hibernate and watch dog timer function */
274static int ipu_pm_timer_state(int event);
275
276#ifdef CONFIG_DUCATI_WATCH_DOG
277/* Functions for reporing watch dog reset */
278static int ipu_pm_notify_event(int event, void *data);
279#endif
280
264/** ============================================================================ 281/** ============================================================================
265 * Globals 282 * Globals
266 * ============================================================================ 283 * ============================================================================
@@ -371,7 +388,9 @@ static struct ipu_pm_params pm_params = {
371 .pm_notification_event = PM_NOTIFICATION, 388 .pm_notification_event = PM_NOTIFICATION,
372 .proc_id = A9, 389 .proc_id = A9,
373 .remote_proc_id = -1, 390 .remote_proc_id = -1,
374 .line_id = 0 391 .line_id = 0,
392 .hib_timer_state = PM_HIB_TIMER_RESET,
393 .wdt_time = 0
375} ; 394} ;
376 395
377/* Functions to request resources */ 396/* Functions to request resources */
@@ -423,6 +442,8 @@ static int (*release_fxn[PM_NUM_RES]) (struct ipu_pm_object *handle,
423 442
424}; 443};
425 444
445static struct blocking_notifier_head ipu_pm_notifier;
446
426/* 447/*
427 Function to schedule the recover process 448 Function to schedule the recover process
428 * 449 *
@@ -2392,6 +2413,11 @@ int ipu_pm_save_ctx(int proc_id)
2392 2413
2393 num_loaded_cores = app_loaded + sys_loaded; 2414 num_loaded_cores = app_loaded + sys_loaded;
2394 2415
2416#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
2417 /* Turn off timer before hibernation */
2418 ipu_pm_timer_state(PM_HIB_TIMER_OFF);
2419#endif
2420
2395 flag = 1; 2421 flag = 1;
2396 timeout = jiffies + msecs_to_jiffies(WAIT_FOR_IDLE_TIMEOUT); 2422 timeout = jiffies + msecs_to_jiffies(WAIT_FOR_IDLE_TIMEOUT);
2397 /* Wait fot Ducati to hibernate */ 2423 /* Wait fot Ducati to hibernate */
@@ -2434,10 +2460,15 @@ int ipu_pm_save_ctx(int proc_id)
2434 pr_err("Not able to save iommu"); 2460 pr_err("Not able to save iommu");
2435 } else 2461 } else
2436 goto error; 2462 goto error;
2463
2464
2437exit: 2465exit:
2438 mutex_unlock(ipu_pm_state.gate_handle); 2466 mutex_unlock(ipu_pm_state.gate_handle);
2439 return 0; 2467 return 0;
2440error: 2468error:
2469#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
2470 ipu_pm_timer_state(PM_HIB_TIMER_ON);
2471#endif
2441 mutex_unlock(ipu_pm_state.gate_handle); 2472 mutex_unlock(ipu_pm_state.gate_handle);
2442 pr_debug("Aborting hibernation process\n"); 2473 pr_debug("Aborting hibernation process\n");
2443 return -EINVAL; 2474 return -EINVAL;
@@ -2473,6 +2504,8 @@ int ipu_pm_restore_ctx(int proc_id)
2473 /* Enable/disable ipu hibernation*/ 2504 /* Enable/disable ipu hibernation*/
2474#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION 2505#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
2475 handle->rcb_table->pm_flags.hibernateAllowed = 1; 2506 handle->rcb_table->pm_flags.hibernateAllowed = 1;
2507 /* turn on ducati hibernation timer */
2508 ipu_pm_timer_state(PM_HIB_TIMER_ON);
2476#else 2509#else
2477 handle->rcb_table->pm_flags.hibernateAllowed = 0; 2510 handle->rcb_table->pm_flags.hibernateAllowed = 0;
2478#endif 2511#endif
@@ -2533,6 +2566,10 @@ int ipu_pm_restore_ctx(int proc_id)
2533 goto error; 2566 goto error;
2534 handle->rcb_table->state_flag &= ~APP_PROC_DOWN; 2567 handle->rcb_table->state_flag &= ~APP_PROC_DOWN;
2535 } 2568 }
2569#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
2570 /* turn on ducati hibernation timer */
2571 ipu_pm_timer_state(PM_HIB_TIMER_ON);
2572#endif
2536#ifdef CONFIG_OMAP_PM 2573#ifdef CONFIG_OMAP_PM
2537 retval = omap_pm_set_max_sdma_lat(&pm_qos_handle_2, 2574 retval = omap_pm_set_max_sdma_lat(&pm_qos_handle_2,
2538 IPU_PM_MM_MPU_LAT_CONSTRAINT); 2575 IPU_PM_MM_MPU_LAT_CONSTRAINT);
@@ -2649,6 +2686,8 @@ int ipu_pm_setup(struct ipu_pm_config *cfg)
2649 goto exit; 2686 goto exit;
2650 } 2687 }
2651 2688
2689 BLOCKING_INIT_NOTIFIER_HEAD(&ipu_pm_notifier);
2690
2652 return retval; 2691 return retval;
2653exit: 2692exit:
2654 pr_err("ipu_pm_setup failed! retval = 0x%x", retval); 2693 pr_err("ipu_pm_setup failed! retval = 0x%x", retval);
@@ -2705,6 +2744,7 @@ int ipu_pm_attach(u16 remote_proc_id, void *shared_addr)
2705 __func__, __LINE__); 2744 __func__, __LINE__);
2706 goto exit; 2745 goto exit;
2707 } 2746 }
2747 handle->dmtimer = NULL;
2708 } else if (remote_proc_id == APP_M3 && IS_ERR_OR_NULL(app_rproc)) { 2748 } else if (remote_proc_id == APP_M3 && IS_ERR_OR_NULL(app_rproc)) {
2709 pr_debug("requesting app_rproc\n"); 2749 pr_debug("requesting app_rproc\n");
2710 app_rproc = omap_rproc_get("ducati-proc1"); 2750 app_rproc = omap_rproc_get("ducati-proc1");
@@ -2715,6 +2755,7 @@ int ipu_pm_attach(u16 remote_proc_id, void *shared_addr)
2715 __func__, __LINE__); 2755 __func__, __LINE__);
2716 goto exit; 2756 goto exit;
2717 } 2757 }
2758 handle->dmtimer = NULL;
2718 } 2759 }
2719 2760
2720 if (IS_ERR_OR_NULL(ducati_iommu)) { 2761 if (IS_ERR_OR_NULL(ducati_iommu)) {
@@ -2775,6 +2816,12 @@ int ipu_pm_detach(u16 remote_proc_id)
2775 goto exit; 2816 goto exit;
2776 } 2817 }
2777 2818
2819#ifdef CONFIG_SYSLINK_IPU_SELF_HIBERNATION
2820 /* reset the ducati hibernation timer */
2821 if (remote_proc_id == SYS_M3)
2822 ipu_pm_timer_state(PM_HIB_TIMER_RESET);
2823#endif
2824
2778 /* When recovering clean_up was called, so wait for completion. 2825 /* When recovering clean_up was called, so wait for completion.
2779 * If not make sure there is no resource pending. 2826 * If not make sure there is no resource pending.
2780 */ 2827 */
@@ -2847,6 +2894,7 @@ int ipu_pm_detach(u16 remote_proc_id)
2847 if (recover) 2894 if (recover)
2848 recover = false; 2895 recover = false;
2849 global_rcb = NULL; 2896 global_rcb = NULL;
2897 first_time = 1;
2850 } 2898 }
2851 2899
2852 /* Deleting the handle based on remote_proc_id */ 2900 /* Deleting the handle based on remote_proc_id */
@@ -2912,3 +2960,151 @@ exit:
2912 return retval; 2960 return retval;
2913} 2961}
2914EXPORT_SYMBOL(ipu_pm_destroy); 2962EXPORT_SYMBOL(ipu_pm_destroy);
2963
2964static irqreturn_t ipu_pm_timer_interrupt(int irq, void *dev_id)
2965{
2966 struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
2967
2968 ipu_pm_timer_state(PM_HIB_TIMER_EXPIRE);
2969 omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
2970 return IRQ_HANDLED;
2971}
2972
2973/* Function implements hibernation and watch dog timer
2974 * The functionality is based on following states
2975 * RESET: Timer is disabed
2976 * OFF: Timer is OFF
2977 * ON: Timer running
2978 * HIBERNATE: Waking up for ducati cores to hibernate
2979 * WD_RESET: Waiting for Ducati cores to complete hibernation
2980 */
2981static int ipu_pm_timer_state(int event)
2982{
2983 int retval = 0;
2984 int tick_rate;
2985 struct ipu_pm_object *handle;
2986 struct ipu_pm_params *params;
2987
2988 handle = ipu_pm_get_handle(SYS_M3);
2989 if (handle == NULL) {
2990 pr_err("ipu_pm_timer_state handle ptr NULL\n");
2991 retval = PTR_ERR(handle);
2992 goto exit;
2993 }
2994 params = handle->params;
2995 if (params == NULL) {
2996 pr_err("ipu_pm_timer_state params ptr NULL\n");
2997 retval = PTR_ERR(params);
2998 goto exit;
2999 }
3000 if (sys_rproc == NULL)
3001 goto exit;
3002
3003 switch (event) {
3004 case PM_HIB_TIMER_EXPIRE:
3005 if (params->hib_timer_state == PM_HIB_TIMER_ON) {
3006 /* If any resource in use, no hibernation */
3007 if (handle->rcb_table->state_flag & HIB_REF_MASK)
3008 goto exit;
3009
3010 pr_debug("Starting hibernation, waking up M3 cores");
3011 handle->rcb_table->state_flag |= (SYS_PROC_HIB |
3012 APP_PROC_HIB | ENABLE_IPU_HIB);
3013#ifdef CONFIG_DUCATI_WATCH_DOG
3014 if (sys_rproc->dmtimer != NULL)
3015 omap_dm_timer_set_load(sys_rproc->dmtimer, 1,
3016 params->wdt_time);
3017 params->hib_timer_state = PM_HIB_TIMER_WDRESET;
3018 } else if (params->hib_timer_state ==
3019 PM_HIB_TIMER_WDRESET) {
3020 /* notify devh to begin error recovery here */
3021 pr_debug("Timer ISR: Trigger WD reset + recovery\n");
3022 ipu_pm_notify_event(0, NULL);
3023 if (sys_rproc->dmtimer != NULL)
3024 omap_dm_timer_stop(sys_rproc->dmtimer);
3025 params->hib_timer_state = PM_HIB_TIMER_OFF;
3026#endif
3027 }
3028 break;
3029 case PM_HIB_TIMER_RESET:
3030 /* disable timer and remove irq handler */
3031 if (handle->dmtimer) {
3032 free_irq(OMAP44XX_IRQ_GPT3, (void *)handle->dmtimer);
3033 handle->dmtimer = NULL;
3034 params->hib_timer_state = PM_HIB_TIMER_RESET;
3035 }
3036 break;
3037 case PM_HIB_TIMER_OFF: /* disable timer */
3038 /* no need to disable timer since it
3039 * is done in rproc context */
3040 params->hib_timer_state = PM_HIB_TIMER_OFF;
3041 break;
3042 case PM_HIB_TIMER_ON: /* enable timer */
3043 if (params->hib_timer_state == PM_HIB_TIMER_RESET) {
3044 tick_rate = clk_get_rate(omap_dm_timer_get_fclk(
3045 sys_rproc->dmtimer));
3046 handle->rcb_table->hib_time = 0xFFFFFFFF - (
3047 (tick_rate/1000) * PM_HIB_DEFAULT_TIME);
3048 params->wdt_time = 0xFFFFFFFF - (
3049 (tick_rate/1000) * PM_HIB_WDT_TIME);
3050 retval = request_irq(OMAP44XX_IRQ_GPT3,
3051 ipu_pm_timer_interrupt,
3052 IRQF_DISABLED,
3053 "HIB_TIMER",
3054 (void *)sys_rproc->dmtimer);
3055 if (retval < 0)
3056 pr_warn("request_irq status: %x\n", retval);
3057 /*
3058 * store the dmtimer handle locally to use during
3059 * free_irq as dev_id token in cases where the remote
3060 * proc frees the dmtimer handle first
3061 */
3062 handle->dmtimer = sys_rproc->dmtimer;
3063 }
3064 if (sys_rproc->dmtimer != NULL)
3065 omap_dm_timer_set_load_start(sys_rproc->dmtimer, 1,
3066 handle->rcb_table->hib_time);
3067 params->hib_timer_state = PM_HIB_TIMER_ON;
3068 break;
3069 }
3070 return retval;
3071exit:
3072 if (retval < 0)
3073 pr_err("ipu_pm_timer_state failed, retval: %x\n", retval);
3074 return retval;
3075}
3076
3077/*
3078 * ======== ipu_pm_notify_event ========
3079 * IPU event notifications.
3080 */
3081#ifdef CONFIG_DUCATI_WATCH_DOG
3082static int ipu_pm_notify_event(int event, void *data)
3083{
3084 return blocking_notifier_call_chain(&ipu_pm_notifier, event, data);
3085}
3086#endif
3087
3088/*
3089 * ======== ipu_pm_register_notifier ========
3090 * Register for IPC events.
3091 */
3092int ipu_pm_register_notifier(struct notifier_block *nb)
3093{
3094 if (!nb)
3095 return -EINVAL;
3096 return blocking_notifier_chain_register(&ipu_pm_notifier, nb);
3097}
3098EXPORT_SYMBOL_GPL(ipu_pm_register_notifier);
3099
3100/*
3101 * ======== ipu_pm_unregister_notifier ========
3102 * Un-register for events.
3103 */
3104int ipu_pm_unregister_notifier(struct notifier_block *nb)
3105{
3106 if (!nb)
3107 return -EINVAL;
3108 return blocking_notifier_chain_unregister(&ipu_pm_notifier, nb);
3109}
3110EXPORT_SYMBOL_GPL(ipu_pm_unregister_notifier);
diff --git a/drivers/dsp/syslink/ipu_pm/ipu_pm.h b/drivers/dsp/syslink/ipu_pm/ipu_pm.h
index 42021d5e7f1..9b11cc54533 100644
--- a/drivers/dsp/syslink/ipu_pm/ipu_pm.h
+++ b/drivers/dsp/syslink/ipu_pm/ipu_pm.h
@@ -225,6 +225,9 @@
225#define SYS_PROC_DOWN 0x00010000 225#define SYS_PROC_DOWN 0x00010000
226#define APP_PROC_DOWN 0x00020000 226#define APP_PROC_DOWN 0x00020000
227#define ENABLE_IPU_HIB 0x00000040 227#define ENABLE_IPU_HIB 0x00000040
228#define SYS_PROC_HIB 0x00000001
229#define APP_PROC_HIB 0x00000002
230#define HIB_REF_MASK 0x00000F80
228 231
229#define SYS_PROC_IDLING 0x00000001 232#define SYS_PROC_IDLING 0x00000001
230#define APP_PROC_IDLING 0x00000002 233#define APP_PROC_IDLING 0x00000002
@@ -337,6 +340,18 @@ enum pm_event_type{
337 PM_LAST_EVENT 340 PM_LAST_EVENT
338}; 341};
339 342
343
344enum pm_hib_timer_event{
345 PM_HIB_TIMER_RESET,
346 PM_HIB_TIMER_OFF,
347 PM_HIB_TIMER_ON,
348 PM_HIB_TIMER_WDRESET,
349 PM_HIB_TIMER_EXPIRE
350};
351
352#define PM_HIB_DEFAULT_TIME 5000 /* 5 SEC */
353#define PM_HIB_WDT_TIME 3000 /* 3 SEC */
354
340struct rcb_message { 355struct rcb_message {
341 unsigned rcb_flag:1; 356 unsigned rcb_flag:1;
342 unsigned rcb_num:6; 357 unsigned rcb_num:6;
@@ -429,6 +444,8 @@ struct ipu_pm_params {
429 int remote_proc_id; 444 int remote_proc_id;
430 int line_id; 445 int line_id;
431 void *gate_mp; 446 void *gate_mp;
447 int hib_timer_state;
448 int wdt_time;
432}; 449};
433 450
434/* This structure defines attributes for initialization of the ipu_pm module. */ 451/* This structure defines attributes for initialization of the ipu_pm module. */
@@ -465,6 +482,7 @@ struct ipu_pm_object {
465 struct work_struct work; 482 struct work_struct work;
466 struct kfifo fifo; 483 struct kfifo fifo;
467 spinlock_t lock; 484 spinlock_t lock;
485 struct omap_dm_timer *dmtimer;
468}; 486};
469 487
470/* Function for PM resources Callback */ 488/* Function for PM resources Callback */
@@ -537,4 +555,10 @@ int ipu_pm_module_set_bandwidth(unsigned rsrc,
537/* Function to get ducati state flag from share memory */ 555/* Function to get ducati state flag from share memory */
538u32 ipu_pm_get_state(int proc_id); 556u32 ipu_pm_get_state(int proc_id);
539 557
558/* Function to register notifier from devh module */
559int ipu_pm_register_notifier(struct notifier_block *nb);
560
561/* Function to unregister notifier from devh module */
562int ipu_pm_unregister_notifier(struct notifier_block *nb);
563
540#endif 564#endif