/* * Setup the local clock events for a CPU. */ int __cpuinit local_timer_setup(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); struct kona_td kona_td; struct timer_ch_cfg config; /* allocate an AON timer channel as local tick timer */ kona_td = (struct kona_td)__get_cpu_var(percpu_kona_td); if (!kona_td.allocated) { kona_td.kona_timer = kona_timer_request(TICK_TIMER_NAME, TICK_TIMER_OFFSET + cpu); if (kona_td.kona_timer) { kona_td.allocated = true; } else { pr_err("%s: Failed to allocate %s channel %d as" "CPU %d local tick device\n", __func__, TICK_TIMER_NAME, TICK_TIMER_OFFSET + cpu, cpu); return -ENXIO; } } /* * In the future: The following codes should be one time configuration */ config.mode = MODE_ONESHOT; config.arg = evt; config.cb = kona_tick_interrupt_cb; kona_timer_config(kona_td.kona_timer, &config); irq_set_affinity(kona_td.kona_timer->irq, cpumask_of(cpu)); evt->name = "local_timer"; evt->cpumask = cpumask_of(cpu); evt->irq = kona_td.kona_timer->irq; evt->set_next_event = kona_tick_set_next_event; evt->set_mode = kona_tick_set_mode; evt->features = CLOCK_EVT_FEAT_ONESHOT; evt->rating = 250; evt->shift = 32; evt->mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, evt->shift); evt->max_delta_ns = clockevent_delta2ns(MAX_KONA_COUNT_CLOCK, evt); /* There is MIN_KONA_DELTA_CLOCK clock cycles delay in HUB Timer by * ASIC limitation. When min_delta_ns set N, real requested load value * in hrtimer becomes N - 1. So add 1 to be MIN_DELTA_CLOCK */ evt->min_delta_ns = clockevent_delta2ns(MIN_KONA_DELTA_CLOCK + 1, evt); per_cpu(percpu_kona_td, cpu) = kona_td; clockevents_register_device(evt); return 0; }
static void __init timers_init(struct gp_timer_setup *gpt_setup) { struct timer_ch_cfg evt_tm_cfg; if (kona_timer_modules_init() < 0) { pr_err ("timers_init: Unable to initialize kona timer modules \r\n"); return; } if (kona_timer_module_set_rate(gpt_setup->name, gpt_setup->rate) < 0) { pr_err("timers_init: Unable to set the clock rate to %d \r\n", gpt_setup->rate); return; } /* Initialize Event timer */ gpt_evt = kona_timer_request(gpt_setup->name, gpt_setup->ch_num); if (gpt_evt == NULL) { pr_err("timers_init: Unable to get GPT timer for event\r\n"); return; } pr_info("timers_init: === SYSTEM TIMER NAME: %s CHANNEL NUMBER %d \ RATE %d \r\n", gpt_setup->name, gpt_setup->ch_num, gpt_setup->rate); evt_tm_cfg.mode = MODE_ONESHOT; evt_tm_cfg.arg = &clockevent_gptimer; evt_tm_cfg.cb = gptimer_interrupt_cb; kona_timer_config(gpt_evt, &evt_tm_cfg); gptimer_set_next_event((CLOCK_TICK_RATE / HZ), NULL); /* * IMPORTANT * Note that we don't want to waste a channel for clock source. In Kona *timer module by default there is a counter that keeps counting *irrespective of the channels. So instead of implementing a periodic *timer using a channel (which in the HW is not peridoic) we can *simply read the counters of the timer that is used for event and *send it for source. The only catch is that this timer should not be *stopped by PM or any other sub-systems. */ gpt_src = gpt_evt; return; }
static ssize_t kona_timer_start_test(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { unsigned int ch_num, mode, count; char name[255]; if (sscanf(buf, "%s %d %d %d", name, &ch_num, &mode, &count) == 4) { pr_info("channel_num:%d mode(0-periodic 1-oneshot):%d " "count:%d\n", ch_num, mode, count); if (kt == NULL) kt = kona_timer_request(name, ch_num); if (kt == NULL) { pr_err("kona_timer_request returned error\n"); goto out; } cfg.mode = mode; cfg.arg = kt; cfg.cb = timer_callback; cfg.reload = count; if (kona_timer_config(kt, &cfg) < 0) { pr_err("kona_timer_config returned error\n"); goto out; } if (kona_timer_set_match_start(kt, count) < 0) { pr_err("kona_timer_set_match_start returned error\n"); goto out; } pr_info("Timer test started\n"); out: return n; } pr_info("\nusage: echo [name (aon-timer/slave-timer)] " "[channel num (0-3)] [mode(0-periodic" "1-oneshot)] [count value] > /sys/bcm/timer_start_test\n"); return -EINVAL; }
static int kona_timer_unit_test_program(struct kona_timer *lkt, enum timer_mode mode, unsigned long count) { struct timer_ch_cfg lcfg; lcfg.mode = mode; lcfg.arg = lkt; lcfg.cb = timer_callback; if (kona_timer_config(lkt, &lcfg) < 0) { pr_err("kona_timer_config returned error.\n"); goto error; } if (kona_timer_set_match_start(lkt, count) < 0) { pr_err("kona_timer_set_match_start returned error.\n"); goto error; } return 0; error: return -1; }