| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /* Copyright 2018 Canaan Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <syslog.h>
- #include "io.h"
- #include "plic.h"
- #include "stddef.h"
- #include "sysctl.h"
- #include "timer.h"
- #include "utils.h"
- /**
- * @brief Private definitions for the timer instance
- */
- typedef struct timer_instance
- {
- timer_device_number_t device;
- timer_channel_number_t channel;
- timer_callback_t callback;
- void *ctx;
- bool single_shot;
- } timer_instance_t;
- volatile timer_instance_t timer_instance[TIMER_DEVICE_MAX][TIMER_CHANNEL_MAX];
- volatile kendryte_timer_t *const timer[3] =
- {
- (volatile kendryte_timer_t *)TIMER0_BASE_ADDR,
- (volatile kendryte_timer_t *)TIMER1_BASE_ADDR,
- (volatile kendryte_timer_t *)TIMER2_BASE_ADDR};
- void timer_init(timer_device_number_t timer_number)
- {
- for(size_t i = 0; i < TIMER_CHANNEL_MAX; i++)
- timer_instance[timer_number][i] = (const timer_instance_t){
- .device = 0,
- .channel = 0,
- .callback = NULL,
- .ctx = NULL,
- .single_shot = 0,
- };
- sysctl_clock_enable(SYSCTL_CLOCK_TIMER0 + timer_number);
- }
- void timer_set_clock_div(timer_device_number_t timer_number, uint32_t div)
- {
- sysctl_clock_set_threshold(timer_number == 0 ? SYSCTL_THRESHOLD_TIMER0 : timer_number == 1 ? SYSCTL_THRESHOLD_TIMER1 : SYSCTL_THRESHOLD_TIMER2, div);
- }
- void timer_enable(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control |= TIMER_CR_ENABLE;
- }
- void timer_disable(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control &= (~TIMER_CR_ENABLE);
- }
- void timer_enable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control |= TIMER_CR_PWM_ENABLE;
- }
- void timer_disable_pwm(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control &= (~TIMER_CR_PWM_ENABLE);
- }
- void timer_enable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control &= (~TIMER_CR_INTERRUPT_MASK);
- }
- void timer_disable_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].control |= TIMER_CR_INTERRUPT_MASK;
- }
- void timer_set_mode(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t mode)
- {
- timer[timer_number]->channel[channel].control &= (~TIMER_CR_MODE_MASK);
- timer[timer_number]->channel[channel].control |= mode;
- }
- void timer_set_reload(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
- {
- timer[timer_number]->channel[channel].load_count = count;
- }
- void timer_set_reload2(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t count)
- {
- timer[timer_number]->load_count2[channel] = count;
- }
- uint32_t timer_get_count(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- return timer[timer_number]->channel[channel].current_value;
- }
- uint32_t timer_get_reload(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- return timer[timer_number]->channel[channel].load_count;
- }
- uint32_t timer_get_reload2(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- return timer[timer_number]->load_count2[channel];
- }
- uint32_t timer_get_interrupt_status(timer_device_number_t timer_number)
- {
- return timer[timer_number]->intr_stat;
- }
- uint32_t timer_get_raw_interrupt_status(timer_device_number_t timer_number)
- {
- return timer[timer_number]->raw_intr_stat;
- }
- uint32_t timer_channel_get_interrupt_status(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- return timer[timer_number]->channel[channel].intr_stat;
- }
- void timer_clear_interrupt(timer_device_number_t timer_number)
- {
- timer[timer_number]->eoi = timer[timer_number]->eoi;
- }
- void timer_channel_clear_interrupt(timer_device_number_t timer_number, timer_channel_number_t channel)
- {
- timer[timer_number]->channel[channel].eoi = timer[timer_number]->channel[channel].eoi;
- }
- void timer_set_enable(timer_device_number_t timer_number, timer_channel_number_t channel, uint32_t enable)
- {
- if(enable)
- timer[timer_number]->channel[channel].control = TIMER_CR_USER_MODE | TIMER_CR_ENABLE;
- else
- timer[timer_number]->channel[channel].control = TIMER_CR_INTERRUPT_MASK;
- }
- size_t timer_set_interval(timer_device_number_t timer_number, timer_channel_number_t channel, size_t nanoseconds)
- {
- uint32_t clk_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_TIMER0 + timer_number);
- double min_step = 1e9 / clk_freq;
- size_t value = (size_t)(nanoseconds / min_step);
- configASSERT(value > 0 && value < UINT32_MAX);
- timer[timer_number]->channel[channel].load_count = (uint32_t)value;
- return (size_t)(min_step * value);
- }
- typedef void (*timer_ontick)();
- timer_ontick time_irq[3][4] = {NULL};
- static int timer_isr(void *parm)
- {
- uint32_t timer_number;
- for(timer_number = 0; timer_number < 3; timer_number++)
- {
- if(parm == timer[timer_number])
- break;
- }
- uint32_t channel = timer[timer_number]->intr_stat;
- size_t i = 0;
- for(i = 0; i < 4; i++)
- {
- if(channel & 1)
- {
- if(time_irq[timer_number][i])
- (time_irq[timer_number][i])();
- break;
- }
- channel >>= 1;
- }
- readl(&timer[timer_number]->eoi);
- return 0;
- }
- void timer_set_irq(timer_device_number_t timer_number, timer_channel_number_t channel, void (*func)(), uint32_t priority)
- {
- time_irq[timer_number][channel] = func;
- if(channel < 2)
- {
- plic_set_priority(IRQN_TIMER0A_INTERRUPT + timer_number * 2, priority);
- plic_irq_register(IRQN_TIMER0A_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
- plic_irq_enable(IRQN_TIMER0A_INTERRUPT + timer_number * 2);
- } else
- {
- plic_set_priority(IRQN_TIMER0B_INTERRUPT + timer_number * 2, priority);
- plic_irq_register(IRQN_TIMER0B_INTERRUPT + timer_number * 2, timer_isr, (void *)timer[timer_number]);
- plic_irq_enable(IRQN_TIMER0B_INTERRUPT + timer_number * 2);
- }
- }
- /**
- * @brief Get the timer irqn by device and channel object
- *
- * @note Internal function, not public
- * @param device The device
- * @param channel The channel
- * @return plic_irq_t IRQ number
- */
- static plic_irq_t get_timer_irqn_by_device_and_channel(timer_device_number_t device, timer_channel_number_t channel)
- {
- if(device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX)
- {
- /*
- * Select timer interrupt part
- * Hierarchy of Timer interrupt to PLIC
- * +---------+ +-----------+
- * | 0+----+ | |
- * | | +--+0A |
- * | 1+----+ | |
- * | TIMER0 | | |
- * | 2+----+ | |
- * | | +--+0B |
- * | 3+----+ | |
- * +---------+ | |
- * | |
- * +---------+ | |
- * | 0+----+ | |
- * | | +--+1A |
- * | 1+----+ | |
- * | TIMER1 | | PLIC |
- * | 2+----+ | |
- * | | +--+1B |
- * | 3+----+ | |
- * +---------+ | |
- * | |
- * +---------+ | |
- * | 0+----+ | |
- * | | +--+2A |
- * | 1+----+ | |
- * | TIMER2 | | |
- * | 2+----+ | |
- * | | +--+2B |
- * | 3+----+ | |
- * +---------+ +-----------+
- *
- */
- if(channel < 2)
- {
- /* It is part A interrupt, offset + 0 */
- return IRQN_TIMER0A_INTERRUPT + device * 2;
- } else
- {
- /* It is part B interrupt, offset + 1 */
- return IRQN_TIMER0B_INTERRUPT + device * 2;
- }
- }
- return IRQN_NO_INTERRUPT;
- }
- /**
- * @brief Process user callback function
- *
- * @note Internal function, not public
- * @param ctx The context
- * @return int The callback result
- */
- static int timer_interrupt_handler(void *ctx)
- {
- timer_instance_t *instance = (timer_instance_t *)ctx;
- timer_device_number_t device = instance->device;
- timer_channel_number_t channel = instance->channel;
- uint32_t channel_int_stat = timer[device]->intr_stat;
- uint32_t irq_channel = (channel >> 1) << 1;
- channel_int_stat >>= irq_channel;
- for(size_t i = irq_channel; i < irq_channel + 2; i++)
- {
- /* Check every bit for interrupt status */
- if(channel_int_stat & 1)
- {
- if(timer_instance[device][i].callback)
- {
- /* Process user callback function */
- timer_instance[device][i].callback(timer_instance[device][i].ctx);
- /* Check if this timer is a single shot timer */
- if(timer_instance[device][i].single_shot)
- {
- /* Single shot timer, disable it */
- timer_set_enable(device, i, 0);
- }
- }
- /* Clear timer interrupt flag for specific channel */
- readl(&timer[device]->channel[i].eoi);
- }
- channel_int_stat >>= 1;
- }
- /*
- * NOTE:
- * Don't read timer[device]->eoi here, or you will lost some interrupt
- * readl(&timer[device]->eoi);
- */
- return 0;
- }
- int timer_irq_register(timer_device_number_t device, timer_channel_number_t channel, int is_single_shot, uint32_t priority, timer_callback_t callback, void *ctx)
- {
- if(device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX)
- {
- plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
- timer_instance[device][channel] = (const timer_instance_t){
- .device = device,
- .channel = channel,
- .callback = callback,
- .ctx = ctx,
- .single_shot = is_single_shot,
- };
- plic_set_priority(irq_number, priority);
- plic_irq_register(irq_number, timer_interrupt_handler, (void *)&timer_instance[device][channel]);
- plic_irq_enable(irq_number);
- return 0;
- }
- return -1;
- }
- int timer_irq_unregister(timer_device_number_t device, timer_channel_number_t channel)
- {
- if(device < TIMER_DEVICE_MAX && channel < TIMER_CHANNEL_MAX)
- {
- timer_instance[device][channel] = (const timer_instance_t){
- .device = 0,
- .channel = 0,
- .callback = NULL,
- .ctx = NULL,
- .single_shot = 0,
- };
- /* Combine 0 and 1 to A interrupt, 2 and 3 to B interrupt */
- if((!(timer_instance[device][TIMER_CHANNEL_0].callback ||
- timer_instance[device][TIMER_CHANNEL_1].callback)) ||
- (!(timer_instance[device][TIMER_CHANNEL_2].callback ||
- timer_instance[device][TIMER_CHANNEL_3].callback)))
- {
- plic_irq_t irq_number = get_timer_irqn_by_device_and_channel(device, channel);
- plic_irq_unregister(irq_number);
- }
- return 0;
- }
- return -1;
- }
|