rk29: limit aclk_cpu when use FB1 and HDMI
author黄涛 <huangtao@rock-chips.com>
Fri, 12 Aug 2011 12:16:29 +0000 (20:16 +0800)
committer黄涛 <huangtao@rock-chips.com>
Fri, 12 Aug 2011 12:16:29 +0000 (20:16 +0800)
arch/arm/mach-rk29/clock.c
arch/arm/mach-rk29/cpufreq.c
arch/arm/mach-rk29/include/mach/cpufreq.h
drivers/video/rk29_fb.c
drivers/video/rk29_fb.h

index 6f78ea504875a1881eecb29bc89f2bd3b58caf4a..f5fa5c8a09f3a9f5977b266a1787670c4edc8acc 100755 (executable)
@@ -452,7 +452,25 @@ static const struct arm_pll_set* arm_pll_clk_get_best_pll_set(unsigned long rate
 static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long flags;
-       const struct arm_pll_set *ps = arm_pll_clk_get_best_pll_set(rate);
+       const struct arm_pll_set *ps;
+       u32 clksel0_con;
+       bool aclk_limit = rate & 1;
+
+       rate &= ~1;
+       ps = arm_pll_clk_get_best_pll_set(rate);
+       clksel0_con = ps->clksel0_con;
+
+       if (aclk_limit) {
+               u32 aclk_div = clksel0_con & CORE_ACLK_MASK;
+               if (rate > 408 * MHZ && aclk_div < CORE_ACLK_41)
+                       aclk_div = CORE_ACLK_41;
+               clksel0_con = (clksel0_con & ~CORE_ACLK_MASK) | aclk_div;
+       }
+
+       if (ps->apll_con == cru_readl(CRU_APLL_CON)) {
+               cru_writel((cru_readl(CRU_CLKSEL0_CON) & ~(CORE_ACLK_MASK | ACLK_HCLK_MASK | ACLK_PCLK_MASK)) | clksel0_con, CRU_CLKSEL0_CON);
+               return 0;
+       }
 
        local_irq_save(flags);
        /* make aclk safe & reparent to general pll */
@@ -484,7 +502,7 @@ static int arm_pll_clk_set_rate(struct clk *clk, unsigned long rate)
 
        loops_per_jiffy = ps->lpj;
        /* reparent to arm pll & set aclk/hclk/pclk */
-       cru_writel((cru_readl(CRU_CLKSEL0_CON) & ~(CORE_PARENT_MASK | CORE_ACLK_MASK | ACLK_HCLK_MASK | ACLK_PCLK_MASK)) | CORE_PARENT_ARM_PLL | ps->clksel0_con, CRU_CLKSEL0_CON);
+       cru_writel((cru_readl(CRU_CLKSEL0_CON) & ~(CORE_PARENT_MASK | CORE_ACLK_MASK | ACLK_HCLK_MASK | ACLK_PCLK_MASK)) | CORE_PARENT_ARM_PLL | clksel0_con, CRU_CLKSEL0_CON);
        local_irq_restore(flags);
 
        return 0;
@@ -2677,7 +2695,7 @@ void __init rk29_clock_init2(enum periph_pll ppll_rate, enum codec_pll cpll_rate
        printk(KERN_INFO "Clocking rate (apll/dpll/cpll/gpll/core/aclk_cpu/hclk_cpu/pclk_cpu/aclk_periph/hclk_periph/pclk_periph): %ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld MHz",
               arm_pll_clk.rate / MHZ, ddr_pll_clk.rate / MHZ, codec_pll_clk.rate / MHZ, general_pll_clk.rate / MHZ, clk_core.rate / MHZ,
               aclk_cpu.rate / MHZ, hclk_cpu.rate / MHZ, pclk_cpu.rate / MHZ, aclk_periph.rate / MHZ, hclk_periph.rate / MHZ, pclk_periph.rate / MHZ);
-       printk(KERN_CONT " (20110729)\n");
+       printk(KERN_CONT " (20110812)\n");
 
        preset_lpj = loops_per_jiffy;
 }
index c6ca54753666857e782b53b908d0b79891d62112..8216d2c4cd9def78ed5574b6582bf0f43c051da0 100755 (executable)
 #include <linux/tick.h>
 #include <linux/workqueue.h>
 #include <mach/cpufreq.h>
+#include <../../../drivers/video/rk29_fb.h>
+
+#define MHZ    (1000*1000)
+#define KHZ    1000
 
 static int no_cpufreq_access;
 
@@ -45,15 +49,16 @@ static struct cpufreq_frequency_table default_freq_table[] = {
 };
 static struct cpufreq_frequency_table *freq_table = default_freq_table;
 static struct clk *arm_clk;
+static struct clk *ddr_clk;
 static DEFINE_MUTEX(mutex);
 
 #ifdef CONFIG_REGULATOR
 static struct regulator *vcore;
 static int vcore_uV;
-#define CONFIG_RK29_CPU_FREQ_LIMIT
+#define CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
 #endif
 
-#ifdef CONFIG_RK29_CPU_FREQ_LIMIT
+#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
 static struct workqueue_struct *wq;
 static void rk29_cpufreq_work_func(struct work_struct *work);
 static DECLARE_DELAYED_WORK(rk29_cpufreq_work, rk29_cpufreq_work_func);
@@ -70,19 +75,20 @@ static int limit_temp;
 module_param(limit_temp, int, 0444);
 
 #define LIMIT_AVG_VOLTAGE      1225000 /* vU */
-#else /* !CONFIG_RK29_CPU_FREQ_LIMIT */
+#else /* !CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP */
 #define LIMIT_AVG_VOLTAGE      1400000 /* vU */
-#endif /* CONFIG_RK29_CPU_FREQ_LIMIT */
+#endif /* CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP */
 
 enum {
        DEBUG_CHANGE    = 1U << 0,
-       DEBUG_LIMIT     = 1U << 1,
+       DEBUG_TEMP      = 1U << 1,
+       DEBUG_DISP      = 1U << 2,
 };
 static uint debug_mask = DEBUG_CHANGE;
 module_param(debug_mask, uint, 0644);
 #define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
 
-#define LIMIT_AVG_FREQ (816 * 1000) /* kHz */
+#define LIMIT_AVG_FREQ (816 * KHZ) /* kHz */
 static unsigned int limit_avg_freq = LIMIT_AVG_FREQ;
 static int rk29_cpufreq_set_limit_avg_freq(const char *val, struct kernel_param *kp)
 {
@@ -107,6 +113,16 @@ static int rk29_cpufreq_set_limit_avg_voltage(const char *val, struct kernel_par
 }
 module_param_call(limit_avg_voltage, rk29_cpufreq_set_limit_avg_voltage, param_get_uint, &limit_avg_voltage, 0644);
 
+static bool limit_fb1_is_on;
+static bool limit_hdmi_is_on;
+static bool aclk_limit(void) { return limit_hdmi_is_on && limit_fb1_is_on; }
+static int limit_index_816 = -1;
+static int limit_index_1008 = -1;
+module_param(limit_fb1_is_on, bool, 0644);
+module_param(limit_hdmi_is_on, bool, 0644);
+module_param(limit_index_816, int, 0444);
+module_param(limit_index_1008, int, 0444);
+
 static bool rk29_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy)
 {
        char c = 0;
@@ -115,23 +131,40 @@ static bool rk29_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy)
        return (c == 'o' || c == 'i' || c == 'c');
 }
 
+static void board_do_update_cpufreq_table(struct cpufreq_frequency_table *table)
+{
+       unsigned int i;
+
+       limit_avg_freq = 0;
+       limit_avg_index = -1;
+       limit_index_816 = -1;
+       limit_index_1008 = -1;
+
+       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               table[i].frequency = clk_round_rate(arm_clk, table[i].frequency * KHZ) / KHZ;
+               if (table[i].index <= limit_avg_voltage && limit_avg_freq < table[i].frequency) {
+                       limit_avg_freq = table[i].frequency;
+                       limit_avg_index = i;
+               }
+               if (table[i].frequency <= 816 * KHZ &&
+                   (limit_index_816 < 0 ||
+                   (limit_index_816 >= 0 && table[limit_index_816].frequency < table[i].frequency)))
+                       limit_index_816 = i;
+               if (table[i].frequency <= 1008 * KHZ &&
+                   (limit_index_1008 < 0 ||
+                   (limit_index_1008 >= 0 && table[limit_index_1008].frequency < table[i].frequency)))
+                       limit_index_1008 = i;
+       }
+
+       if (!limit_avg_freq)
+               limit_avg_freq = LIMIT_AVG_FREQ;
+}
+
 int board_update_cpufreq_table(struct cpufreq_frequency_table *table)
 {
        mutex_lock(&mutex);
        if (arm_clk) {
-               unsigned int i;
-
-               limit_avg_freq = 0;
-               limit_avg_index = -1;
-               for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
-                       table[i].frequency = clk_round_rate(arm_clk, table[i].frequency * 1000) / 1000;
-                       if (table[i].index <= limit_avg_voltage && limit_avg_freq < table[i].frequency) {
-                               limit_avg_freq = table[i].frequency;
-                               limit_avg_index = i;
-                       }
-               }
-               if (!limit_avg_freq)
-                       limit_avg_freq = LIMIT_AVG_FREQ;
+               board_do_update_cpufreq_table(table);
        }
        freq_table = table;
        mutex_unlock(&mutex);
@@ -143,8 +176,8 @@ static int rk29_cpufreq_verify(struct cpufreq_policy *policy)
        return cpufreq_frequency_table_verify(policy, freq_table);
 }
 
-#ifdef CONFIG_RK29_CPU_FREQ_LIMIT
-static void rk29_cpufreq_limit(struct cpufreq_policy *policy, unsigned int relation, int *index)
+#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
+static void rk29_cpufreq_limit_by_temp(struct cpufreq_policy *policy, unsigned int relation, int *index)
 {
        int c, ms;
        ktime_t now;
@@ -170,11 +203,11 @@ static void rk29_cpufreq_limit(struct cpufreq_policy *policy, unsigned int relat
        }
 
        limit_temp -= idle_time_us - last_idle_time_us; // -1000
-       dprintk(DEBUG_LIMIT, "idle %lld us (%lld - %lld)\n", idle_time_us - last_idle_time_us, idle_time_us, last_idle_time_us);
+       dprintk(DEBUG_TEMP, "idle %lld us (%lld - %lld)\n", idle_time_us - last_idle_time_us, idle_time_us, last_idle_time_us);
        last_idle_time_us = idle_time_us;
 
        ms = div_u64(ktime_us_delta(now, last), 1000);
-       dprintk(DEBUG_LIMIT, "%d kHz (%d uV) elapsed %d ms (%lld - %lld)\n", cur, vcore_uV, ms, now.tv64, last.tv64);
+       dprintk(DEBUG_TEMP, "%d kHz (%d uV) elapsed %d ms (%lld - %lld)\n", cur, vcore_uV, ms, now.tv64, last.tv64);
        last = now;
 
        if (cur <= 408 * 1000)
@@ -189,14 +222,39 @@ static void rk29_cpufreq_limit(struct cpufreq_policy *policy, unsigned int relat
 
        if (limit_temp < 0)
                limit_temp = 0;
-       if (limit_temp > 325 * limit_secs * 1000)
+       if (limit_temp > 325 * limit_secs * 1000 && freq_table[*index].frequency > limit_avg_freq)
                *index = limit_avg_index;
-       dprintk(DEBUG_LIMIT, "c %d temp %d (%s) index %d", c, limit_temp, limit_temp > 325 * limit_secs * 1000 ? "overheat" : "normal", *index);
+       dprintk(DEBUG_TEMP, "c %d temp %d (%s) index %d", c, limit_temp, limit_temp > 325 * limit_secs * 1000 ? "overheat" : "normal", *index);
 }
 #else
-#define rk29_cpufreq_limit(...) do {} while (0)
+#define rk29_cpufreq_limit_by_temp(...) do {} while (0)
 #endif
 
+static void rk29_cpufreq_limit_by_disp(int *index)
+{
+       unsigned long ddr_rate;
+       unsigned int frequency = freq_table[*index].frequency;
+       int new_index = -1;
+
+       if (!ddr_clk || !aclk_limit())
+               return;
+
+       ddr_rate = clk_get_rate(ddr_clk);
+
+       if (ddr_rate < 492 * MHZ) {
+               if (limit_index_816 >= 0 && frequency > 816 * KHZ)
+                       new_index = limit_index_816;
+       } else {
+               if (limit_index_1008 >= 0 && frequency > 1008 * KHZ)
+                       new_index = limit_index_1008;
+       }
+
+       if (new_index != -1) {
+               dprintk(DEBUG_DISP, "old %d new %d\n", freq_table[*index].frequency, freq_table[new_index].frequency);
+               *index = new_index;
+       }
+}
+
 static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
 {
        int index;
@@ -204,6 +262,9 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta
        struct cpufreq_freqs freqs;
        const struct cpufreq_frequency_table *freq;
        int err = 0;
+       bool force = relation & CPUFREQ_FORCE_CHANGE;
+
+       relation &= ~CPUFREQ_FORCE_CHANGE;
 
        if ((relation & ENABLE_FURTHER_CPUFREQ) &&
            (relation & DISABLE_FURTHER_CPUFREQ)) {
@@ -227,10 +288,11 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta
                pr_err("invalid target_freq: %d\n", target_freq);
                return -EINVAL;
        }
-       rk29_cpufreq_limit(policy, relation, &index);
+       rk29_cpufreq_limit_by_disp(&index);
+       rk29_cpufreq_limit_by_temp(policy, relation, &index);
        freq = &freq_table[index];
 
-       if (policy->cur == freq->frequency)
+       if (policy->cur == freq->frequency && !force)
                return 0;
 
        freqs.old = policy->cur;
@@ -256,9 +318,9 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta
 
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        dprintk(DEBUG_CHANGE, "pre change\n");
-       clk_set_rate(arm_clk, freqs.new * 1000);
+       clk_set_rate(arm_clk, freqs.new * KHZ + aclk_limit());
        dprintk(DEBUG_CHANGE, "post change\n");
-       freqs.new = clk_get_rate(arm_clk) / 1000;
+       freqs.new = clk_get_rate(arm_clk) / KHZ;
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
 #ifdef CONFIG_REGULATOR
@@ -291,7 +353,7 @@ static int rk29_cpufreq_target(struct cpufreq_policy *policy, unsigned int targe
        return err;
 }
 
-#ifdef CONFIG_RK29_CPU_FREQ_LIMIT
+#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
 static int rk29_cpufreq_notifier_policy(struct notifier_block *nb,
                unsigned long val, void *data)
 {
@@ -303,12 +365,12 @@ static int rk29_cpufreq_notifier_policy(struct notifier_block *nb,
 
        is_ondemand = rk29_cpufreq_is_ondemand_policy(policy);
        if (!wq && is_ondemand) {
-               dprintk(DEBUG_LIMIT, "start wq\n");
+               dprintk(DEBUG_TEMP, "start wq\n");
                wq = create_singlethread_workqueue("rk29_cpufreqd");
                if (wq)
                        queue_delayed_work(wq, &rk29_cpufreq_work, WORK_DELAY);
        } else if (wq && !is_ondemand) {
-               dprintk(DEBUG_LIMIT, "stop wq\n");
+               dprintk(DEBUG_TEMP, "stop wq\n");
                cancel_delayed_work(&rk29_cpufreq_work);
                destroy_workqueue(wq);
                wq = NULL;
@@ -335,13 +397,22 @@ static void rk29_cpufreq_work_func(struct work_struct *work)
 
 static int rk29_cpufreq_init(struct cpufreq_policy *policy)
 {
-       arm_clk = clk_get(NULL, "arm_pll");
-       if (IS_ERR(arm_clk))
-               return PTR_ERR(arm_clk);
-
        if (policy->cpu != 0)
                return -EINVAL;
 
+       arm_clk = clk_get(NULL, "arm_pll");
+       if (IS_ERR(arm_clk)) {
+               int err = PTR_ERR(arm_clk);
+               arm_clk = NULL;
+               return err;
+       }
+
+       ddr_clk = clk_get(NULL, "ddr");
+       if (IS_ERR(ddr_clk)) {
+               pr_err("fail to get ddr clk: %ld\n", PTR_ERR(ddr_clk));
+               ddr_clk = NULL;
+       }
+
 #ifdef CONFIG_REGULATOR
        vcore = regulator_get(NULL, "vcore");
        if (IS_ERR(vcore)) {
@@ -353,13 +424,13 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
        board_update_cpufreq_table(freq_table); /* force update frequency */
        BUG_ON(cpufreq_frequency_table_cpuinfo(policy, freq_table));
        cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
-       policy->cur = clk_get_rate(arm_clk) / 1000;
+       policy->cur = clk_get_rate(arm_clk) / KHZ;
 
        policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC; // make default sampling_rate to 40000
 
-#ifdef CONFIG_RK29_CPU_FREQ_LIMIT
+#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
        if (rk29_cpufreq_is_ondemand_policy(policy)) {
-               dprintk(DEBUG_LIMIT, "start wq\n");
+               dprintk(DEBUG_TEMP, "start wq\n");
                wq = create_singlethread_workqueue("rk29_cpufreqd");
                if (wq)
                        queue_delayed_work(wq, &rk29_cpufreq_work, WORK_DELAY);
@@ -371,10 +442,10 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
 
 static int rk29_cpufreq_exit(struct cpufreq_policy *policy)
 {
-#ifdef CONFIG_RK29_CPU_FREQ_LIMIT
+#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_TEMP
        cpufreq_unregister_notifier(&notifier_policy_block, CPUFREQ_POLICY_NOTIFIER);
        if (wq) {
-               dprintk(DEBUG_LIMIT, "stop wq\n");
+               dprintk(DEBUG_TEMP, "stop wq\n");
                cancel_delayed_work(&rk29_cpufreq_work);
                destroy_workqueue(wq);
                wq = NULL;
@@ -439,9 +510,44 @@ static struct notifier_block rk29_cpufreq_pm_notifier = {
        .notifier_call = rk29_cpufreq_pm_notifier_event,
 };
 
+static int rk29_cpufreq_fb_notifier_event(struct notifier_block *this,
+               unsigned long event, void *ptr)
+{
+       struct cpufreq_policy *policy;
+
+       switch (event) {
+       case RK29FB_EVENT_HDMI_ON:
+               limit_hdmi_is_on = true;
+               break;
+       case RK29FB_EVENT_HDMI_OFF:
+               limit_hdmi_is_on = false;
+               break;
+       case RK29FB_EVENT_FB1_ON:
+               limit_fb1_is_on = true;
+               break;
+       case RK29FB_EVENT_FB1_OFF:
+               limit_fb1_is_on = false;
+               break;
+       }
+
+       dprintk(DEBUG_DISP, "event: %lu aclk_limit: %d\n", event, aclk_limit());
+       policy = cpufreq_cpu_get(0);
+       if (policy) {
+               cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L | CPUFREQ_FORCE_CHANGE);
+               cpufreq_cpu_put(policy);
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rk29_cpufreq_fb_notifier = {
+       .notifier_call = rk29_cpufreq_fb_notifier_event,
+};
+
 static int __init rk29_cpufreq_register(void)
 {
        register_pm_notifier(&rk29_cpufreq_pm_notifier);
+       rk29fb_register_notifier(&rk29_cpufreq_fb_notifier);
 
        return cpufreq_register_driver(&rk29_cpufreq_driver);
 }
index 805df6b092605ab6cd379e092018b4c84705d545..28737d3ede5b8f6e68208ff4188a30e094fd6dbe 100644 (file)
@@ -23,6 +23,7 @@
 #define ENABLE_FURTHER_CPUFREQ          0x20
 #define MASK_FURTHER_CPUFREQ            0x30
 /* With 0x00(NOCHANGE), it depends on the previous "further" status */
+#define CPUFREQ_FORCE_CHANGE            0x40
 
 #ifdef CONFIG_CPU_FREQ
 int board_update_cpufreq_table(struct cpufreq_frequency_table *table);
index 6ab22268fd260fd6c5a45304cd348d313529044b..7fcfbd4a9cb8cb231a7e788f98bf5eb594ce41b8 100755 (executable)
@@ -271,6 +271,37 @@ static bool has_set_rotate;
 static u32 last_yuv_phy[2] = {0,0};
 #endif
 
+static BLOCKING_NOTIFIER_HEAD(rk29fb_notifier_list);
+int rk29fb_register_notifier(struct notifier_block *nb)
+{
+       int ret = 0;
+       if (g_pdev) {
+               struct rk29fb_inf *inf = platform_get_drvdata(g_pdev);
+               if (inf) {
+                       if (inf->cur_screen && inf->cur_screen->type == SCREEN_HDMI)
+                               nb->notifier_call(nb, RK29FB_EVENT_HDMI_ON, inf->cur_screen);
+                       if (inf->fb1 && inf->fb1->par) {
+                               struct win0_par *par = inf->fb1->par;
+                               if (par->refcount)
+                                       nb->notifier_call(nb, RK29FB_EVENT_FB1_ON, inf->cur_screen);
+                       }
+               }
+       }
+       ret = blocking_notifier_chain_register(&rk29fb_notifier_list, nb);
+
+       return ret;
+}
+
+int rk29fb_unregister_notifier(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&rk29fb_notifier_list, nb);
+}
+
+static int rk29fb_notify(struct rk29fb_inf *inf, unsigned long event)
+{
+       return blocking_notifier_call_chain(&rk29fb_notifier_list, event, inf->cur_screen);
+}
+
 int mcu_do_refresh(struct rk29fb_inf *inf)
 {
     if(inf->mcu_stopflush)  return 0;
@@ -2040,6 +2071,7 @@ int fb1_open(struct fb_info *info, int user)
         fb0_set_par(inf->fb0);
         fb0_pan_display(&inf->fb0->var, inf->fb0);
         win0_blank(FB_BLANK_POWERDOWN, info);
+       rk29fb_notify(inf, RK29FB_EVENT_FB1_ON);
         return 0;
     }
 }
@@ -2073,6 +2105,7 @@ int fb1_release(struct fb_info *info, int user)
         info->fix.smem_len = 0;
                // clean the var param
                memset(var0, 0, sizeof(struct fb_var_screeninfo));
+       rk29fb_notify(inf, RK29FB_EVENT_FB1_OFF);
     }
 
     return 0;
@@ -2299,6 +2332,7 @@ int FB_Switch_Screen( struct rk29fb_screen *screen, u32 enable )
     fb0_set_par(inf->fb0);
     LcdMskReg(inf, DSP_CTRL1, m_BLACK_MODE,  v_BLACK_MODE(0));
     LcdWrReg(inf, REG_CFG_DONE, 0x01);
+    rk29fb_notify(inf, enable ? RK29FB_EVENT_HDMI_ON : RK29FB_EVENT_HDMI_OFF);
     return 0;
 }
 
index 7bdea368997607fc3deec557f9f08d2908b2c417..f843ea0c6d74be2297f81e6799ded450900fb424 100644 (file)
@@ -439,4 +439,12 @@ typedef volatile struct tagLCDC_REG
 extern void __init rk29_add_device_lcdc(void);
 extern int mcu_ioctl(unsigned int cmd, unsigned long arg);
 
+#define RK29FB_EVENT_HDMI_ON   1
+#define RK29FB_EVENT_HDMI_OFF  2
+#define RK29FB_EVENT_FB1_ON    3
+#define RK29FB_EVENT_FB1_OFF   4
+#include <linux/notifier.h>
+int rk29fb_register_notifier(struct notifier_block *nb);
+int rk29fb_unregister_notifier(struct notifier_block *nb);
+
 #endif