--- /dev/null
+#define pr_fmt(fmt) "ddrfreq: " fmt
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/sched/rt.h>
+#include <linux/of.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <linux/vmalloc.h>
+#include <dt-bindings/clock/ddr.h>
+
+#include "dvfs.h"
+#include "common.h"
+
+enum {
+ DEBUG_DDR = 1U << 0,
+ DEBUG_VIDEO_STATE = 1U << 1,
+ DEBUG_SUSPEND = 1U << 2,
+ DEBUG_VERBOSE = 1U << 3,
+};
+static int debug_mask = DEBUG_DDR;
+module_param(debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) pr_info(fmt, ##__VA_ARGS__); } while (0)
+
+#define MHZ (1000*1000)
+#define KHZ 1000
+
+struct ddr {
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ struct dvfs_node *clk_dvfs_node;
+ unsigned long normal_rate;
+ unsigned long video_rate;
+ unsigned long dualview_rate;
+ unsigned long idle_rate;
+ unsigned long suspend_rate;
+ unsigned long reboot_rate;
+ bool auto_self_refresh;
+ char *mode;
+ unsigned long sys_status;
+ struct task_struct *task;
+ wait_queue_head_t wait;
+};
+static struct ddr ddr;
+
+module_param_named(sys_status, ddr.sys_status, ulong, S_IRUGO);
+module_param_named(auto_self_refresh, ddr.auto_self_refresh, bool, S_IRUGO);
+module_param_named(mode, ddr.mode, charp, S_IRUGO);
+
+static noinline void ddrfreq_set_sys_status(int status)
+{
+ ddr.sys_status |= status;
+ wake_up(&ddr.wait);
+}
+
+static noinline void ddrfreq_clear_sys_status(int status)
+{
+ ddr.sys_status &= ~status;
+ wake_up(&ddr.wait);
+}
+int ddr_set_rate(uint32_t nMHz);
+
+static void ddrfreq_mode(bool auto_self_refresh, unsigned long *target_rate, char *name)
+{
+ ddr.mode = name;
+ if (auto_self_refresh != ddr.auto_self_refresh) {
+ ddr_set_auto_self_refresh(auto_self_refresh);
+ ddr.auto_self_refresh = auto_self_refresh;
+ dprintk(DEBUG_DDR, "change auto self refresh to %d when %s\n", auto_self_refresh, name);
+ }
+ if (*target_rate != dvfs_clk_get_rate(ddr.clk_dvfs_node)) {
+ if (dvfs_clk_set_rate(ddr.clk_dvfs_node, *target_rate) == 0) {
+ *target_rate = dvfs_clk_get_rate(ddr.clk_dvfs_node);
+ dprintk(DEBUG_DDR, "change freq to %lu MHz when %s\n", *target_rate / MHZ, name);
+ }
+ }
+}
+
+static noinline void ddrfreq_work(unsigned long sys_status)
+{
+ static struct clk *cpu = NULL;
+ static struct clk *gpu = NULL;
+ unsigned long s = sys_status;
+
+ if (!cpu)
+ cpu = clk_get(NULL, "cpu");
+ if (!gpu)
+ gpu = clk_get(NULL, "gpu");
+
+ dprintk(DEBUG_VERBOSE, "sys_status %02lx\n", sys_status);
+
+ if (ddr.reboot_rate && (s & SYS_STATUS_REBOOT)) {
+ ddrfreq_mode(false, &ddr.reboot_rate, "shutdown/reboot");
+ } else if (ddr.suspend_rate && (s & SYS_STATUS_SUSPEND)) {
+ ddrfreq_mode(true, &ddr.suspend_rate, "suspend");
+ } else if (ddr.dualview_rate &&
+ (s & SYS_STATUS_LCDC0) && (s & SYS_STATUS_LCDC1)) {
+ ddrfreq_mode(false, &ddr.dualview_rate, "dual-view");
+ } else if (ddr.video_rate &&
+ ((s & SYS_STATUS_VIDEO_720P)||(s & SYS_STATUS_VIDEO_1080P))) {
+ ddrfreq_mode(false, &ddr.video_rate, "video");
+ } else if (ddr.idle_rate
+ && !(s & SYS_STATUS_GPU)
+ && !(s & SYS_STATUS_RGA)
+ && !(s & SYS_STATUS_CIF0)
+ && !(s & SYS_STATUS_CIF1)
+ && (clk_get_rate(cpu) < 816 * MHZ)
+ && (clk_get_rate(gpu) <= 200 * MHZ)
+ ) {
+ ddrfreq_mode(false, &ddr.idle_rate, "idle");
+ } else {
+ ddrfreq_mode(false, &ddr.normal_rate, "normal");
+ }
+}
+
+static int ddrfreq_task(void *data)
+{
+ set_freezable();
+
+ do {
+ unsigned long status = ddr.sys_status;
+ ddrfreq_work(status);
+ wait_event_freezable(ddr.wait, (status != ddr.sys_status) || kthread_should_stop());
+ } while (!kthread_should_stop());
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void ddrfreq_early_suspend(struct early_suspend *h)
+{
+ dprintk(DEBUG_SUSPEND, "early suspend\n");
+ ddrfreq_set_sys_status(SYS_STATUS_SUSPEND);
+}
+
+static void ddrfreq_late_resume(struct early_suspend *h)
+{
+ dprintk(DEBUG_SUSPEND, "late resume\n");
+ ddrfreq_clear_sys_status(SYS_STATUS_SUSPEND);
+}
+#endif
+
+static int video_state_release(struct inode *inode, struct file *file)
+{
+ dprintk(DEBUG_VIDEO_STATE, "video_state release\n");
+ ddrfreq_clear_sys_status(SYS_STATUS_VIDEO);
+ return 0;
+}
+
+#define VIDEO_LOW_RESOLUTION (1080*720)
+static ssize_t video_state_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char state;
+ char *cookie_pot;
+ char *p;
+ char *buf = vzalloc(count);
+ uint32_t v_width=0,v_height=0,v_sync=0;
+ cookie_pot = buf;
+
+ if(!buf)
+ return -ENOMEM;
+
+ if (count < 1){
+ vfree(buf);
+ return -EPERM;
+ }
+
+ if (copy_from_user(cookie_pot, buffer, count)) {
+ vfree(buf);
+ return -EFAULT;
+ }
+
+ dprintk(DEBUG_VIDEO_STATE, "video_state write %s,len %d\n", cookie_pot,count);
+
+ state=cookie_pot[0];
+ if( (count>=3) && (cookie_pot[2]=='w') )
+ {
+ strsep(&cookie_pot,",");
+ strsep(&cookie_pot,"=");
+ p=strsep(&cookie_pot,",");
+ v_width = simple_strtol(p,NULL,10);
+ strsep(&cookie_pot,"=");
+ p=strsep(&cookie_pot,",");
+ v_height= simple_strtol(p,NULL,10);
+ strsep(&cookie_pot,"=");
+ p=strsep(&cookie_pot,",");
+ v_sync= simple_strtol(p,NULL,10);
+ dprintk(DEBUG_VIDEO_STATE, "video_state %c,width=%d,height=%d,sync=%d\n", state,v_width,v_height,v_sync);
+ }
+
+ switch (state) {
+ case '0':
+ ddrfreq_clear_sys_status(SYS_STATUS_VIDEO);
+ break;
+ case '1':
+ if( (v_width == 0) && (v_height == 0)){
+ ddrfreq_set_sys_status(SYS_STATUS_VIDEO_1080P);
+ }
+ /*else if(v_sync==1){
+ if(ddr.video_low_rate && ((v_width*v_height) <= VIDEO_LOW_RESOLUTION) )
+ ddrfreq_set_sys_status(SYS_STATUS_VIDEO_720P);
+ else
+ ddrfreq_set_sys_status(SYS_STATUS_VIDEO_1080P);
+ }*/
+ else{
+ ddrfreq_clear_sys_status(SYS_STATUS_VIDEO);
+ }
+ break;
+ default:
+ vfree(buf);
+ return -EINVAL;
+
+ }
+ vfree(buf);
+ return count;
+}
+
+static const struct file_operations video_state_fops = {
+ .owner = THIS_MODULE,
+ .release= video_state_release,
+ .write = video_state_write,
+};
+
+static struct miscdevice video_state_dev = {
+ .fops = &video_state_fops,
+ .name = "video_state",
+ .minor = MISC_DYNAMIC_MINOR,
+};
+/*
+static int ddrfreq_clk_event(int status, unsigned long event)
+{
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ ddrfreq_set_sys_status(status);
+ break;
+ case POST_RATE_CHANGE:
+ case ABORT_RATE_CHANGE:
+ ddrfreq_clear_sys_status(status);
+ break;
+ }
+ return NOTIFY_OK;
+}
+*/
+#define CLK_NOTIFIER(name, status) \
+static int ddrfreq_clk_##name##_event(struct notifier_block *this, unsigned long event, void *ptr) \
+{ \
+ return ddrfreq_clk_event(SYS_STATUS_##status, event); \
+} \
+static struct notifier_block ddrfreq_clk_##name##_notifier = { .notifier_call = ddrfreq_clk_##name##_event };
+
+#define REGISTER_CLK_NOTIFIER(name) \
+do { \
+ struct clk *clk = clk_get(NULL, #name); \
+ clk_notifier_register(clk, &ddrfreq_clk_##name##_notifier); \
+ clk_put(clk); \
+} while (0)
+
+#define UNREGISTER_CLK_NOTIFIER(name) \
+do { \
+ struct clk *clk = clk_get(NULL, #name); \
+ clk_notifier_unregister(clk, &ddrfreq_clk_##name##_notifier); \
+ clk_put(clk); \
+} while (0)
+/*
+CLK_NOTIFIER(pd_gpu, GPU);
+CLK_NOTIFIER(pd_rga, RGA);
+CLK_NOTIFIER(pd_cif0, CIF0);
+CLK_NOTIFIER(pd_cif1, CIF1);
+CLK_NOTIFIER(pd_lcdc0, LCDC0);
+CLK_NOTIFIER(pd_lcdc1, LCDC1);
+*/
+static int ddrfreq_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ u32 timeout = 1000; // 10s
+ ddrfreq_set_sys_status(SYS_STATUS_REBOOT);
+ while (dvfs_clk_get_rate(ddr.clk_dvfs_node) != ddr.reboot_rate && --timeout) {
+ msleep(10);
+ }
+ if (!timeout) {
+ pr_err("failed to set ddr clk from %luMHz to %luMHz when shutdown/reboot\n", dvfs_clk_get_rate(ddr.clk_dvfs_node) / MHZ, ddr.reboot_rate / MHZ);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ddrfreq_reboot_notifier = {
+ .notifier_call = ddrfreq_reboot_notifier_event,
+};
+
+int of_init_ddr_freq_table(void)
+{
+ struct device_node *clk_ddr_dev_node;
+ const struct property *prop;
+ const __be32 *val;
+ int nr;
+
+ clk_ddr_dev_node = of_find_node_by_name(NULL, "clk_ddr");
+ if (IS_ERR_OR_NULL(clk_ddr_dev_node)) {
+ pr_err("%s: get clk ddr dev node err\n", __func__);
+ return PTR_ERR(clk_ddr_dev_node);
+ }
+
+ prop = of_find_property(clk_ddr_dev_node, "freq_table", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (!prop->value)
+ return -ENODATA;
+
+ nr = prop->length / sizeof(u32);
+ if (nr % 2) {
+ pr_err("%s: Invalid freq list\n", __func__);
+ return -EINVAL;
+ }
+
+ val = prop->value;
+ while (nr) {
+ unsigned long status = be32_to_cpup(val++);
+ unsigned long rate = be32_to_cpup(val++) * 1000;
+
+ if (status & SYS_STATUS_NORMAL)
+ ddr.normal_rate = rate;
+ if (status & SYS_STATUS_SUSPEND)
+ ddr.suspend_rate = rate;
+ if ((status & SYS_STATUS_VIDEO_720P)||(status & SYS_STATUS_VIDEO_720P))
+ ddr.video_rate = rate;
+ if ((status & SYS_STATUS_LCDC0)&&(status & SYS_STATUS_LCDC1))
+ ddr.dualview_rate = rate;
+ if (status & SYS_STATUS_IDLE)
+ ddr.idle_rate= rate;
+ if (status & SYS_STATUS_REBOOT)
+ ddr.reboot_rate= rate;
+
+ nr -= 2;
+ }
+
+ return 0;
+}
+
+static int ddrfreq_init(void)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ int ret;
+
+ ddr.clk_dvfs_node = clk_get_dvfs_node("clk_ddr");
+ if (!ddr.clk_dvfs_node){
+ return -EINVAL;
+ }
+
+ init_waitqueue_head(&ddr.wait);
+ ddr.mode = "normal";
+
+ ddr.normal_rate = dvfs_clk_get_rate(ddr.clk_dvfs_node);
+ ddr.video_rate = ddr.normal_rate;
+ ddr.dualview_rate = 0;
+ ddr.idle_rate = 0;
+ ddr.suspend_rate = ddr.normal_rate;
+ ddr.reboot_rate = ddr.normal_rate;
+
+ of_init_ddr_freq_table();
+
+ if (ddr.idle_rate) {
+ //REGISTER_CLK_NOTIFIER(pd_gpu);
+ //REGISTER_CLK_NOTIFIER(pd_rga);
+ //REGISTER_CLK_NOTIFIER(pd_cif0);
+ //REGISTER_CLK_NOTIFIER(pd_cif1);
+ }
+
+ if (ddr.dualview_rate) {
+ //REGISTER_CLK_NOTIFIER(pd_lcdc0);
+ //REGISTER_CLK_NOTIFIER(pd_lcdc1);
+ }
+
+ ret = misc_register(&video_state_dev);
+ if (unlikely(ret)) {
+ pr_err("failed to register video_state misc device! error %d\n", ret);
+ goto err;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ddr.early_suspend.suspend = ddrfreq_early_suspend;
+ ddr.early_suspend.resume = ddrfreq_late_resume;
+ ddr.early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50;
+ register_early_suspend(&ddr.early_suspend);
+#endif
+
+ ddr.task = kthread_create(ddrfreq_task, NULL, "ddrfreqd");
+ if (IS_ERR(ddr.task)) {
+ ret = PTR_ERR(ddr.task);
+ pr_err("failed to create kthread! error %d\n", ret);
+ goto err1;
+ }
+
+ sched_setscheduler_nocheck(ddr.task, SCHED_FIFO, ¶m);
+ get_task_struct(ddr.task);
+ kthread_bind(ddr.task, 0);
+ wake_up_process(ddr.task);
+
+ register_reboot_notifier(&ddrfreq_reboot_notifier);
+
+ pr_info("verion 1.0 20140228\n");
+ dprintk(DEBUG_DDR, "normal %luMHz video %luMHz dualview %luMHz idle %luMHz suspend %luMHz reboot %luMHz\n",
+ ddr.normal_rate / MHZ, ddr.video_rate / MHZ, ddr.dualview_rate / MHZ, ddr.idle_rate / MHZ, ddr.suspend_rate / MHZ, ddr.reboot_rate / MHZ);
+
+ return 0;
+
+err1:
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&ddr.early_suspend);
+#endif
+ misc_deregister(&video_state_dev);
+err:
+ if (ddr.idle_rate) {
+ //UNREGISTER_CLK_NOTIFIER(pd_gpu);
+ //UNREGISTER_CLK_NOTIFIER(pd_rga);
+ //UNREGISTER_CLK_NOTIFIER(pd_cif0);
+ //UNREGISTER_CLK_NOTIFIER(pd_cif1);
+ }
+ if (ddr.dualview_rate) {
+ //UNREGISTER_CLK_NOTIFIER(pd_lcdc0);
+ //UNREGISTER_CLK_NOTIFIER(pd_lcdc1);
+ }
+
+ return ret;
+}
+late_initcall(ddrfreq_init);
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
+#include <linux/cpu.h>
+#include <dt-bindings/clock/ddr.h>
#include "cru.h"
-#include "ddr.h"
typedef uint32_t uint32;
#define pd_video_pwr_st (1<<8)
#define pd_gpu_pwr_st (1<<9)
+struct ddr_freq_t {
+ unsigned long screen_ft_us;
+ unsigned long long t0;
+ unsigned long long t1;
+ unsigned long t2;
+};
+
//PMU registers
typedef volatile struct tagPMU_FILE
{
param.dqstr_value = dqstr_value;
call_with_stack(fn_to_pie(rockchip_pie_chunk, &FUNC(ddr_change_freq_sram)),
¶m,
- rockchip_sram_stack);
+ rockchip_sram_stack-(NR_CPUS-1)*PAUSE_CPU_STACK_SZIE);
#if defined (DDR_CHANGE_FREQ_IN_LCDC_VSYNC)
end:
500MHz-800MHz 2:250MHz-400MHz
200MHz-500MHz 1:200MHz-500MHz
******************************************/
+#if 0
static noinline uint32_t ddr_change_freq(uint32_t nMHz)
{
struct ddr_freq_t ddr_freq_t;
ddr_freq_t.screen_ft_us = 0;
-
+
#if defined(ENABLE_DDR_CLCOK_GPLL_PATH) && (defined(CONFIG_ARCH_RK3188) || defined(CONFIG_ARCH_RK319X))
return ddr_change_freq_gpll_dpll(nMHz);
#else
return ddr_change_freq_sram(nMHz,ddr_freq_t);
#endif
}
+#endif
+
+bool DEFINE_PIE_DATA(cpu_pause[NR_CPUS]);
+volatile bool *p_cpu_pause;
+static inline bool is_cpu0_paused(unsigned int cpu) { smp_rmb(); return DATA(cpu_pause)[0]; }
+static inline void set_cpuX_paused(unsigned int cpu, bool pause) { DATA(cpu_pause)[cpu] = pause; smp_wmb(); }
+static inline bool is_cpuX_paused(unsigned int cpu) { smp_rmb(); return p_cpu_pause[cpu]; }
+static inline void set_cpu0_paused(bool pause) { p_cpu_pause[0] = pause; smp_wmb();}
+
+#define MAX_TIMEOUT (16000000UL << 6) //>0.64s
+
+/* Do not use stack, safe on SMP */
+void PIE_FUNC(_pause_cpu)(void *arg)
+{
+ unsigned int cpu = (unsigned int)arg;
+
+ set_cpuX_paused(cpu, true);
+ while (is_cpu0_paused(cpu));
+ set_cpuX_paused(cpu, false);
+}
+
+static void pause_cpu(void *info)
+{
+ unsigned int cpu = raw_smp_processor_id();
+
+ call_with_stack(fn_to_pie(rockchip_pie_chunk, &FUNC(_pause_cpu)),
+ (void *)cpu,
+ rockchip_sram_stack-(cpu-1)*PAUSE_CPU_STACK_SZIE);
+}
+
+static void wait_cpu(void *info)
+{
+}
+
+static int __ddr_change_freq(uint32_t nMHz, struct ddr_freq_t ddr_freq_t)
+{
+ u32 timeout = MAX_TIMEOUT;
+ unsigned int cpu;
+ unsigned int this_cpu = smp_processor_id();
+ int ret = 0;
+
+ cpu_maps_update_begin();
+ local_bh_disable();
+ set_cpu0_paused(true);
+ smp_call_function((smp_call_func_t)pause_cpu, NULL, 0);
+
+ for_each_online_cpu(cpu) {
+ if (cpu == this_cpu)
+ continue;
+ while (!is_cpuX_paused(cpu) && --timeout);
+ if (timeout == 0) {
+ pr_err("pause cpu %d timeout\n", cpu);
+ goto out;
+ }
+ }
+
+ ret = ddr_change_freq_sram(nMHz, ddr_freq_t);
+
+out:
+ set_cpu0_paused(false);
+ local_bh_enable();
+ smp_call_function(wait_cpu, NULL, true);
+ cpu_maps_update_done();
+
+ return ret;
+}
+
+static int _ddr_change_freq(uint32_t nMHz)
+{
+ struct ddr_freq_t ddr_freq_t;
+ //int test_count=0;
+
+ ddr_freq_t.screen_ft_us = 0;
+ ddr_freq_t.t0 = 0;
+ ddr_freq_t.t1 = 0;
+#if defined (DDR_CHANGE_FREQ_IN_LCDC_VSYNC)
+ do
+ {
+ if(rk_fb_poll_wait_frame_complete() == true)
+ {
+ ddr_freq_t.t0 = cpu_clock(0);
+ ddr_freq_t.screen_ft_us = rk_fb_get_prmry_screen_ft();
+
+ test_count++;
+ if(test_count > 10) //test 10 times
+ {
+ ddr_freq_t.screen_ft_us = 0xfefefefe;
+ dprintk(DEBUG_DDR,"%s:test_count exceed maximum!\n",__func__);
+ }
+ dprintk(DEBUG_VERBOSE,"%s:test_count=%d\n",__func__,test_count);
+ usleep_range(ddr_freq_t.screen_ft_us-test_count*1000,ddr_freq_t.screen_ft_us-test_count*1000);
+
+ flush_cache_all();
+ outer_flush_all();
+ flush_tlb_all();
+ }
+ }while(__ddr_change_freq(nMHz, ddr_freq_t)==0);
+#else
+ return __ddr_change_freq(nMHz, ddr_freq_t);
+#endif
+}
+
+static long _ddr_round_rate(uint32_t nMHz)
+{
+ return p_ddr_set_pll(nMHz, 0);
+}
-static void ddr_set_auto_self_refresh(bool en)
+static void _ddr_set_auto_self_refresh(bool en)
{
//set auto self-refresh idle
*kern_to_pie(rockchip_pie_chunk, &DATA(ddr_sr_idle)) = en ? SR_IDLE : 0;
uint32_t gsr,dqstr;
struct clk *clk;
- ddr_print("version 1.00 20131223 \n");
+ ddr_print("version 1.00 20140228 \n");
p_ddr_reg = kern_to_pie(rockchip_pie_chunk, &DATA(ddr_reg));
p_ddr_select_gpll_div = kern_to_pie(rockchip_pie_chunk, &DATA(ddr_select_gpll_div));
p_mem_type = kern_to_pie(rockchip_pie_chunk, &DATA(mem_type));
p_ddr_set_pll = fn_to_pie(rockchip_pie_chunk, &FUNC(ddr_set_pll));
+ p_cpu_pause = kern_to_pie(rockchip_pie_chunk, &DATA(cpu_pause[0]));
*p_mem_type = pPHY_Reg->DCR.b.DDRMD;
ddr_speed_bin = dram_speed_bin;
(ddr_get_cap()>>20));
ddr_adjust_config(*p_mem_type);
- clk = clk_get(NULL, "ddr");
+ clk = clk_get(NULL, "clk_ddr");
if (IS_ERR(clk)) {
ddr_print("failed to get ddr clk\n");
clk = NULL;
if(ddr_rk3188_dpll_is_good == true)
{
if(freq != 0)
- value=ddr_change_freq(freq);
+ value = clk_set_rate(clk, 1000*1000*freq);
else
- value=ddr_change_freq(clk_get_rate(clk)/1000000);
+ value = clk_set_rate(clk, clk_get_rate(clk));
}
- clk_set_rate(clk, 0);
ddr_print("init success!!! freq=%luMHz\n", clk ? clk_get_rate(clk)/1000000 : freq);
for(value=0;value<4;value++)