aboutsummaryrefslogtreecommitdiff
#ifndef ARMCLOCK_H
#define ARMCLOCK_H

#include <stdint.h>

#include "global.h"
#include "interrupts.h"
#define ARMCLK_LOAD                 (ARM_BASE + 0x400)
#define ARMCLK_VALUE                (ARM_BASE + 0x404)
#define ARMCLK_CONTROL              (ARM_BASE + 0x408)
#define ARMCLK_IRQ_CLR_ACK          (ARM_BASE + 0x40C)
#define ARMCLK_RAW_IRQ              (ARM_BASE + 0x410)
#define ARMCLK_MASKED_IRQ           (ARM_BASE + 0x414)
#define ARMCLK_RELOAD               (ARM_BASE + 0x418)
#define ARMCLK_PRE_DRIVER           (ARM_BASE + 0x41C)
#define ARMCLK_FREE_RUNNING_COUNTER (ARM_BASE + 0x420)

typedef union armclk_control
{
  uint32_t raw;
  struct
  {
    uint32_t one_shot_mode           : 1; // bit  0; unused in RPi
    uint32_t counter_23bit           : 1; // bit  1
    uint32_t pre_scale               : 2; // bits 3:2
    uint32_t bit_4                   : 1; // bit  4
    uint32_t interrupt_enable        : 1; // bit  5
    uint32_t periodic_mode           : 1; // bit  6; unused in RPi
    uint32_t timer_enable            : 1; // bit  7
    uint32_t halt_in_debug           : 1; // bit  8
    uint32_t free_running_enable     : 1; // bit  9
    uint32_t bits_15_10              : 6; // bits 15:10
    uint32_t free_running_pre_scaler : 8; // bits 23:16
    uint32_t bits_31_24              : 8; // bits 31:24
  } fields;
} armclk_control_t;

static inline void armclk_init(void)
{
  armclk_control_t ctrl = (armclk_control_t) (uint32_t) 0;
  ctrl.fields.timer_enable = 1;
  ctrl.fields.interrupt_enable = 1;
  ctrl.fields.counter_23bit = 1;
  wr32(ARMCLK_CONTROL, ctrl.raw);
}

static inline void armclk_enable_timer_irq(void)
{
  armclk_control_t ctrl = (armclk_control_t) rd32(ARMCLK_CONTROL);
  ctrl.fields.interrupt_enable = 1;
  wr32(ARMCLK_CONTROL, ctrl.raw);
  
  wr32(ARM_ENABLE_BASIC_IRQS, 1);
}

static inline void armclk_disable_timer_irq(void)
{
  armclk_control_t ctrl = (armclk_control_t) rd32(ARMCLK_CONTROL);
  ctrl.fields.interrupt_enable = 0;
  wr32(ARMCLK_CONTROL, ctrl.raw);
  
  wr32(ARM_DISABLE_BASIC_IRQS, 1);
}

static inline void armclk_irq_settimeout(uint32_t timeout)
{
  wr32(ARMCLK_IRQ_CLR_ACK, 0);
  wr32(ARMCLK_LOAD, timeout);
}

static inline _Bool armclk_irq_pending(void)
{
  return rd32(ARM_IRQ_BASIC_PENDING) & 1;
}

#endif // ARMCLOCK_H