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