1/*
2 * Copyright 2019, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <platsupport/timer.h>
16
17#include <utils/util.h>
18#include <stdint.h>
19#include <stdbool.h>
20
21/* The input frequence is 0.5 of the CPU frequency which is 1GHz by default */
22#define PWM_INPUT_FREQ (500*1000*1000)
23#define PWM0_PADDR   0x10020000
24#define PWM1_PADDR   0x10021000
25
26#define PWM0_INTERRUPT0 42
27#define PWM0_INTERRUPT1 43
28#define PWM0_INTERRUPT2 44
29#define PWM0_INTERRUPT3 45
30
31#define PWM1_INTERRUPT0 46
32#define PWM1_INTERRUPT1 47
33#define PWM1_INTERRUPT2 48
34#define PWM1_INTERRUPT3 49
35
36/**
37 * When used in UPCOUNTER, pwm_handle_irq needs to be called on each interrupt
38 * to handle the overflow. This device doesn't seem to have a way to tell that
39 * an overflow happened other than by the delivery of an IRQ. This means that
40 * if pwm_get_time is called before pwm_handle_irq the time could be incorrect.
41 */
42typedef enum PWM_MODE {
43	TIMEOUT,
44	UPCOUNTER,
45} pwm_mode_t;
46
47typedef struct {
48    /* vaddr pwm is mapped to */
49    void *vaddr;
50    pwm_mode_t mode;
51} pwm_config_t;
52
53/* Memory map for pwm */
54struct pwm_map {
55    uint32_t pwmcfg;
56    uint32_t res0;
57    uint32_t pwmcount;
58    uint32_t res1;
59    uint32_t pwms;
60    uint32_t res2;
61    uint32_t res3;
62    uint32_t res4;
63    uint32_t pwmcmp0;
64    uint32_t pwmcmp1;
65    uint32_t pwmcmp2;
66    uint32_t pwmcmp3;
67};
68
69typedef struct pwm {
70    volatile struct pwm_map *pwm_map;
71    uint64_t time_h;
72    pwm_mode_t mode;
73} pwm_t;
74
75static UNUSED timer_properties_t pwm_properties = {
76    .upcounter = true,
77    .bit_width = 31,
78    .irqs = 4,
79    .periodic_timeouts = true,
80    .relative_timeouts = true,
81    .absolute_timeouts = false,
82    .timeouts = true,
83};
84
85int pwm_start(pwm_t *pwm);
86int pwm_stop(pwm_t *pwm);
87void pwm_handle_irq(pwm_t *pwm, uint32_t irq);
88uint64_t pwm_get_time(pwm_t *pwm);
89int pwm_set_timeout(pwm_t *pwm, uint64_t ns, bool periodic);
90int pwm_init(pwm_t *pwm, pwm_config_t config);
91