1/*
2 * Copyright 2017, 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 <stdint.h>
16#include <assert.h>
17#include <utils/util.h>
18
19struct clock;
20struct clock_sys;
21
22typedef struct clock clk_t;
23typedef struct clock_sys clock_sys_t;
24
25#include <platsupport/plat/clock.h>
26
27typedef enum clk_id clk_id_t;
28typedef enum clock_gate clock_gate_t;
29
30typedef enum clock_gate_mode {
31    CLKGATE_ON,
32    CLKGATE_IDLE,
33    CLKGATE_SLEEP,
34    CLKGATE_OFF
35} clock_gate_mode_t;
36
37struct clock_sys {
38    clk_t *(*get_clock)(clock_sys_t *clock_sys, enum clk_id id);
39    int (*gate_enable)(clock_sys_t *clock_sys, enum clock_gate gate, enum clock_gate_mode mode);
40    void *priv;
41};
42
43#include <platsupport/io.h>
44
45struct clock {
46    enum clk_id id;
47    /// Name of the clock
48    const char *name;
49    /// Clock specific private data
50    void *priv;
51    /// The requested frequency (not the actual frequency)
52    freq_t req_freq;
53    /* For requesting a freq change up the tree. This should
54     * be NULL until clk_register_child has been called */
55    clk_t *parent;
56    /// Provide linked list for this clock's parent.
57    clk_t *sibling;
58    /// For signalling a freq change down the tree
59    clk_t *child;
60    /* Changing parents and initialisation requires access to the clock
61     * subsystem. A reference is stored here for convenience */
62    clock_sys_t *clk_sys;
63    /// Clock specific functions
64    clk_t *(*init)(clk_t *clk);
65    freq_t (*get_freq)(clk_t *);
66    freq_t (*set_freq)(clk_t *, freq_t hz);
67    void (*recal)(clk_t *);
68};
69
70/**
71 * Determine if a clock subsystem structure is valid
72 * @param[in] clock_sys  A handle to the clock subsystem
73 * @return               1 if the structure is valid;
74 */
75static inline int clock_sys_valid(const clock_sys_t *clock_sys)
76{
77    return clock_sys && clock_sys->priv;
78}
79
80/**
81 * Initialise the clock subsystem
82 * @parm[in] io_ops      A handle to io operations that may be used for
83 *                       initialisation. If NULL is passed, the clock system
84 * @param[out] clock_sys On success, clk_sys will contain a handle
85 *                       to the clocking subsystem
86 * @return               0 on success
87 */
88int clock_sys_init(ps_io_ops_t *io_ops, clock_sys_t *clock_sys);
89
90/**
91 * Initialise a clock subsystem that does not support clock configuration
92 * and reports a static set of default clock frequencies.
93 * The use of this initialisation method is not advised as the accuracy
94 * of default clock frequencies are heavily tied to what the bootloader
95 * may (or may not) have configured.
96 * @param[out] clock_sys On success, clk_sys will contain a handle
97 *                       to the clocking subsystem
98 * @return               0 on success
99 */
100int clock_sys_init_default(clock_sys_t *clock_sys);
101
102/**
103 * Override the default frequency for a clock.
104 * This function may be used in conjunction with clock_sys_init_default.
105 * Again, the use of these methods are not advised.
106 * @param[in] id         The ID of the clock to configure
107 * @param[in] hz         The frequency of the clock
108 * @return               0 on success
109 */
110int clock_sys_set_default_freq(enum clk_id id, freq_t hz);
111
112/**
113 * Initialise and acquire a system clock
114 * @param[in] clock_sys  A handle to the clock subsystem
115 * @param[in] id         The ID of the clock to acquire
116 * @return               On success, a handle to the acquired clock.
117 *                       Otherwise, NULL.
118 */
119static inline clk_t *clk_get_clock(clock_sys_t *clock_sys, enum clk_id id)
120{
121    clk_t *clk;
122    assert(clock_sys);
123    assert(clock_sys->get_clock);
124    clk = clock_sys->get_clock(clock_sys, id);
125    return clk;
126};
127
128/**
129 * prints a list of initialised clocks
130 * @param[in] clock_sys  A handle to the clock subsystem
131 */
132void clk_print_clock_tree(clock_sys_t *clock_sys);
133
134/**
135 * Configure the gating mode of a clock
136 * @param[in] clock_sys  A handle to the clock subsystem
137 * @param[in] gate       The ID of the gate to control
138 * @param[in] mode       The mode at which the clock should be gated
139 * @return               0 on success;
140
141 */
142static inline int clk_gate_enable(clock_sys_t *clock_sys, enum clock_gate gate,
143                                  enum clock_gate_mode mode)
144{
145    assert(clock_sys);
146    assert(clock_sys->gate_enable);
147    return clock_sys->gate_enable(clock_sys, gate, mode);
148}
149
150/**
151 * Set the clock frequency.
152 * @param[in] clk    The clock to set the frequency of.
153 * @param[in] hz     Hz to set the clk to
154 * @return           The hz the clock was set to
155 *                   (may not exactly match input param)
156 */
157static inline freq_t clk_set_freq(clk_t *clk, freq_t hz)
158{
159    assert(clk);
160    assert(clk->set_freq);
161    return clk->set_freq(clk, hz);
162}
163
164/**
165 * Set the clock frequency.
166 * @param[in] clk    The clock to set the frequency of.
167 * @param[in] hz     Hz to set the clk to
168 * @return           The hz the clock was set to
169 *                   (may not exactly match input param)
170 */
171static inline freq_t clk_get_freq(clk_t *clk)
172{
173    assert(clk);
174    assert(clk->get_freq);
175    return clk->get_freq(clk);
176}
177
178/**
179 * Register a clock as a child of another
180 * If the parent clock frequency ever changes, the recal function for the
181 * child clock will be called.
182 * @param[in] parent  The parent of this clock relationship
183 * @param[in] child   The child of this clock relationship
184 */
185void clk_register_child(clk_t *parent, clk_t *child);
186
187/**
188 * Initialise a clock structure which reports a fixed frequency
189 * @param[in] id    The ID for the clock
190 * @param[in] freq  The frequency of the fixed clock
191 * @return          A populated clk_t structure ready for use
192 */
193clk_t clk_generate_fixed_clk(enum clk_id id, freq_t frequency);
194
195