/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA"). * All rights reserved. * * This software is supplied "AS IS" without any warranties. * RDA assumes no responsibility or liability for the use of the software, * conveys no license or title under any patent, copyright, or mask work * right to the product. RDA reserves the right to make changes in the * software without notification. RDA also make no representation or * warranty that such application will be suitable for the specified use * without further testing or modification. */ #ifndef _OSI_CLOCK_H_ #define _OSI_CLOCK_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * \brief callback function for clk_sys change * * The callback is platform dependent. Typical usage is for hardware module, * whose clock is divided from clk_sys. So, when clk_sys is changed, it is * needed to update the divider from clk_sys. * * It is recommended to add callback only in hardware driver, and divider * change is needed. * * To ensure atomic, the callback will be called with interrupt disabled. * So, the callback should be as fast as possible, even trace inside * callback is discouraged. * * \param [in] sysClkFreq new clk_sys to be changed * \return hardware module working frequency */ typedef uint32_t (*osiSysClkChangeCallback_t)(uint32_t sysClkFreq); /** * \brief clk_sys change callback registry */ typedef struct { uint32_t tag; ///< name tag //! @cond Doxygen_Suppress uint32_t dummy0; uint32_t dummy1; uint32_t dummy2; //! @endcond } osiSysClkCallbackRegistry_t; /** * \brief clk_sys constraint registry */ typedef struct { uint32_t tag; ///< name tag //! @cond Doxygen_Suppress uint32_t dummy0; uint32_t dummy1; uint32_t dummy2; uint32_t dummy3; uint32_t dummy4; //! @endcond } osiClockConstrainRegistry_t; /** * \brief clock management module initialization */ void osiClockManInit(void); /** * \brief clock management start * * At initialization, clock management will just record clock constrains. Only * after this is called, clock management will start to change system clock * based on clock constrains. */ void osiClockManStart(void); /** * \brief register clk_sys change callback * * When \p cb is NULL, it is the same as \p osiUnregisterSysClkChangeCallback(r). * * \param [in] r callback registry, must be valid * \param [in] cb callback function */ void osiRegisterSysClkChangeCallback(osiSysClkCallbackRegistry_t *r, osiSysClkChangeCallback_t cb); /** * \brief unregister clk_sys change callback * * \param [in] r callback registry, must be valid */ void osiUnregisterSysClkChangeCallback(osiSysClkCallbackRegistry_t *r); /** * \brief initialize clock constrain * * \param [in] r clock constrain registry, must be valid * \param [in] tag tag name of the clock constrain */ void osiClockConstrainInit(osiClockConstrainRegistry_t *r, uint32_t tag); /** * \brief set hardware minimal clock constrain * * It is not needed to specify \p freq to be supported by hardware divider. * The **closest** supported hardware divider will be chosen. * * When \p freq is too high to be supported by hardware, the highest * supported frequency will be chosen. * * After this call, the actual clk_sys may be different with \p freq: * - When there are higher frequency requests, the actual clk_sys frequency * may be higher than \p freq. * - When the closest supported frequency is lower, the actual clk_sys * frequency may be lower than \p freq. * - When \p freq is too high, clk_sys will be set to be the highest * supported frequency. * * \param [in] r clock constrain registry, must be valid * \param [in] freq minimum clk_sys frequency */ void osiRequestSysClk(osiClockConstrainRegistry_t *r, uint32_t freq); /** * \brief set hardware maximum clock constrain * * This is for special purpose. In some cases, some hardware can only work * when sys_clk doesn't exceed a certain frequency. This can be called to * set the limit. * * This will have higher priority than \p osiRequestSysClk. For example, * module A call \p osiRequestSysClk to request minimal frequency 200MHz, * and module B call \p osiRequestMaxSysClk to limit the maximum frequency * 100MHz, sys_clk will be changed to 100MHz though it doesn't satisfy * the requirement of module A. * * \param [in] r clock constrain registry, must be valid * \param [in] freq maximum clk_sys frequency */ void osiRequestMaxSysClk(osiClockConstrainRegistry_t *r, uint32_t freq); /** * \brief set hardware minimal clock constrain, without specified frequency * * Besides it will prevent system sleep, it will prevent clk_sys related * power consumption optimization. * * \param [in] r clock constrain registry, must be valid */ void osiRequestSysClkActive(osiClockConstrainRegistry_t *r); /** * \brief set software minimal clock constrain * * It is similar to \p osiRequestSysClk. However, it won't prevent system * sleep or clk_sys related power consumption optimization. * * \param [in] r clock constrain registry, must be valid * \param [in] freq minimum clk_sys frequency */ void osiRequestPerfClk(osiClockConstrainRegistry_t *r, uint32_t freq); /** * \brief unset software or hardware minimal clock constrain * * \param [in] r clock constrain registry, must be valid */ void osiReleaseClk(osiClockConstrainRegistry_t *r); /** * \brief whether slow down sys clock is allowed * * \return * - true if allowed * - false if not allowed */ bool osiIsSlowSysClkAllowed(void); /** * \brief reapply clk_sys constrains * * It is possible that some constrains aren't satisfied immediately, * especially to decrease clk_sys. So, it may be needed to reapply * constrains. Usually, it is called in idle thread. * * It should be called by system only. */ void osiReapplySysClk(void); /** * \brief dump clock constrain information to memory * * It is for debug only. The data format of timer information dump is * not stable, and may change. When \p mem is NULL, it will return the * estimated dump size. * * \param mem memory for clock constrain information dump * \param size provided memory size * \return * - dump memory size * - -1 if memory size of not enough */ int osiClockConstrainDump(void *mem, unsigned size); #ifdef __cplusplus } #endif #endif