1 /* 2 * Renesas SCP/MCP Software 3 * Copyright (c) 2020-2022, Renesas Electronics Corporation. All rights 4 * reserved. 5 * 6 * SPDX-License-Identifier: BSD-3-Clause 7 */ 8 9 /* The use of "subordinate" may not be in sync with platform documentation */ 10 11 #ifndef MOD_RCAR_CLOCK_H 12 #define MOD_RCAR_CLOCK_H 13 14 #include <rcar_mmap.h> 15 #include <utils_def.h> 16 17 #include <mod_clock.h> 18 19 #include <fwk_element.h> 20 21 #include <stdint.h> 22 23 /*! 24 * \addtogroup GroupRCARModule RCAR Product Modules 25 * @{ 26 */ 27 28 /*! 29 * \defgroup GroupRCARClock Clock 30 * @{ 31 */ 32 33 /*! 34 * \brief Clock driver interface. 35 */ 36 struct mod_rcar_clock_drv_api { 37 /*! Name of the driver */ 38 const char *name; 39 40 /*! 41 * \brief Set a new clock rate by providing a frequency in Hertz (Hz). 42 * 43 * \param clock_id Clock device identifier. 44 * 45 * \param rate The desired frequency in Hertz. 46 * 47 * \param round_mode The type of rounding to perform, if required, to 48 * achieve the given rate. 49 * 50 * \retval FWK_SUCCESS The operation succeeded. 51 * \return One of the standard framework error codes. 52 */ 53 int (*set_rate)( 54 fwk_id_t clock_id, 55 uint64_t rate, 56 enum mod_clock_round_mode round_mode); 57 58 /*! 59 * \brief Get the current rate of a clock in Hertz (Hz). 60 * 61 * \param clock_id Clock device identifier. 62 * 63 * \param [out] rate The current clock rate in Hertz. 64 * 65 * \retval FWK_SUCCESS The operation succeeded. 66 * \return One of the standard framework error codes. 67 */ 68 int (*get_rate)(fwk_id_t clock_id, uint64_t *rate); 69 70 /*! 71 * \brief Get a clock rate in Hertz from an index into the clock's range. 72 * 73 * \param clock_id Clock device identifier. 74 * 75 * \param rate_index The index into the clock's range to get the rate of. 76 * 77 * \param[out] rate The rate, in Hertz, corresponding to the index. 78 * 79 * \retval FWK_SUCCESS The operation succeeded. 80 * \return One of the standard framework error codes. 81 */ 82 int (*get_rate_from_index)( 83 fwk_id_t clock_id, 84 unsigned int rate_index, 85 uint64_t *rate); 86 87 /*! 88 * \brief Set the running state of a clock. 89 * 90 * \param clock_id Clock device identifier. 91 * 92 * \param state One of the valid clock states. 93 * 94 * \retval FWK_SUCCESS The operation succeeded. 95 * \return One of the standard framework error codes. 96 */ 97 int (*set_state)(fwk_id_t clock_id, enum mod_clock_state state); 98 99 /*! 100 * \brief Get the running state of a clock. 101 * 102 * \param clock_id Clock device identifier. 103 * 104 * \param[out] state The current clock state. 105 * 106 * \retval FWK_SUCCESS The operation succeeded. 107 * \return One of the standard framework error codes. 108 */ 109 int (*get_state)(fwk_id_t clock_id, enum mod_clock_state *state); 110 111 /*! 112 * \brief Get the range of rates that the clock supports. 113 * 114 * \param clock_id Clock device identifier. 115 * 116 * \param[out] range The clock range structure. 117 * 118 * \retval FWK_SUCCESS The operation succeeded. 119 * \return One of the standard framework error codes. 120 */ 121 int (*get_range)(fwk_id_t clock_id, struct mod_clock_range *range); 122 123 /*! 124 * \brief Handle the condition where the state of a clock's power domain is 125 * about to change. 126 * 127 * \details This function will be called prior to the change in power 128 * state occurring so that the clock driver implementing this API is 129 * able to perform any required preparatory work beforehand. 130 * 131 * \note This function is optional. If the driver does not control any 132 * clocks that require power state awareness then the pointer may be set 133 * to NULL. 134 * 135 * \param clock_id Clock device identifier. 136 * 137 * \param current_state The current power state that the clock's power 138 * domain will transition away from. 139 * 140 * \param new_state The power state that the clock's power domain will 141 * transition to. 142 * 143 * \retval FWK_SUCCESS The operation succeeded. 144 * \return One of the standard framework error codes. 145 */ 146 int (*process_pending_power_transition)( 147 fwk_id_t clock_id, 148 unsigned int current_state, 149 unsigned int new_state); 150 151 /*! 152 * \brief Handle the condition where the state of a clock's power domain 153 * has changed. 154 * 155 * \details This function will be called after the change in power state 156 * has occurred. The driver can take any appropriate actions that are 157 * required to accommodate the new state. The transition can be to a 158 * deeper power state (e.g. ON->OFF) or to a shallower power state 159 * (e.g. OFF->ON). 160 * 161 * \note This function is optional. If the driver does not control any 162 * clocks that require power state awareness then the pointer may be set 163 * to NULL. 164 * 165 * \param clock_id Clock device identifier. 166 * 167 * \param state The power state that the clock's power domain transitioned 168 * to. 169 * 170 * \retval FWK_SUCCESS The operation succeeded. 171 * \return One of the standard framework error codes. 172 */ 173 int (*process_power_transition)(fwk_id_t clock_id, unsigned int state); 174 }; 175 176 /*! 177 * \brief APIs provided by the driver. 178 */ 179 enum mod_rcar_clock_api_type { 180 /*! An implementation of the Clock HAL module's clock driver API */ 181 MOD_RCAR_CLOCK_API_TYPE_CLOCK, 182 /*! A low-level API for direct control of CSS clocks */ 183 MOD_RCAR_CLOCK_API_TYPE_CSS, 184 MOD_RCAR_CLOCK_API_TYPE_SYSTEM, 185 MOD_RCAR_CLOCK_API_COUNT, 186 }; 187 188 /*! 189 * \brief Sub-types of rcar clock. 190 */ 191 enum mod_rcar_clock_type { 192 /*! A clock with a fixed source. Only its divider can be changed. */ 193 MOD_RCAR_CLOCK_TYPE_SINGLE_SOURCE, 194 /*! A clock with multiple, selectable sources and at least one divider. */ 195 MOD_RCAR_CLOCK_TYPE_MULTI_SOURCE, 196 /*! 197 * A clock with multiple, selectable sources, at least one divider, and 198 * support for modulation. 199 */ 200 MOD_RCAR_CLOCK_TYPE_CLUSTER, 201 }; 202 203 /*! 204 * \brief Divider register types. 205 */ 206 enum mod_rcar_clock_msclock_divider { 207 /*! Divider affecting the A57 PLL clock source. */ 208 MOD_RCAR_CLOCK_A57_DIVIDER_DIV_EXT = 1, 209 /*! Divider affecting the A53 PLL clock source. */ 210 MOD_RCAR_CLOCK_A53_DIVIDER_DIV_EXT = 2, 211 }; 212 213 /*! 214 * \brief Selectable clock sources for V8.2 cluster clocks. 215 */ 216 enum mod_clusclock_source { 217 /*! The clock source is set to a private cluster PLL */ 218 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL0 = 0, 219 /*! The clock source is set to a private cluster PLL */ 220 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL1 = 1, 221 /*! The clock source is set to a private cluster PLL */ 222 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL2 = 2, 223 /*! The clock source is set to a private cluster PLL */ 224 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL3 = 3, 225 /*! The clock source is set to a private cluster PLL */ 226 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL4 = 4, 227 /*! The clock source is set to a private cluster PLL */ 228 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL5 = 5, 229 /*! The clock source is set to a private cluster PLL */ 230 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL6 = 6, 231 /*! The clock source is set to a private cluster PLL */ 232 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_PLL7 = 7, 233 /*! Number of valid clock sources */ 234 MOD_RCAR_CLOCK_CLUSCLK_SOURCE_MAX 235 }; 236 237 /*! 238 * \brief Rate lookup entry. 239 */ 240 struct mod_rcar_clock_rate { 241 /*! Rate in Hertz. */ 242 uint64_t rate; 243 /*! Clock source used to obtain the rate (multi-source clocks only). */ 244 uint8_t source; 245 /*! The divider register to use (multi-source clocks only). */ 246 enum mod_rcar_clock_msclock_divider divider_reg; 247 /*! Divider used to obtain the rate. */ 248 uint8_t divider; 249 }; 250 251 /*! 252 * \brief Ext clock rate lookup entry. 253 */ 254 struct mod_ext_clock_rate { 255 /*! Rate in Hertz. */ 256 uint32_t ext_clk_rate; 257 }; 258 259 /*! 260 * \brief Subsystem clock device configuration. 261 */ 262 struct mod_rcar_clock_dev_config { 263 /*! The type of the clock device. */ 264 enum mod_rcar_clock_type type; 265 266 /*! 267 * \brief Indicates whether the clock is part of a CSS clock group (\c true) 268 * or operating as an independent clock (\c false). 269 */ 270 bool is_group_member; 271 272 /*! Pointer to the clock's control register. */ 273 volatile uint32_t *const control_reg; 274 275 /*! Pointer to the clock's modulator register, if any. */ 276 volatile uint32_t *const modulator_reg; 277 278 /*! Pointer to the clock's DIV_SYS divider register, if any. */ 279 volatile uint32_t *const divsys_reg; 280 281 /*! Pointer to the clock's DIV_EXT divider register, if any. */ 282 volatile uint32_t *const divext_reg; 283 284 /*! Pointer to the clock's rate lookup table. */ 285 const struct mod_rcar_clock_rate *rate_table; 286 287 /*! The number of rates in the rate lookup table. */ 288 uint32_t rate_count; 289 290 /*! The rate, in Hz, to set during module initialization. */ 291 uint64_t initial_rate; 292 293 /*! 294 * If \c true, the driver will not attempt to set a default frequency, or to 295 * otherwise configure the PLL during the pre-runtime phase. The PLL is 296 * expected to be initialized later in response to a notification or other 297 * event. 298 */ 299 const bool defer_initialization; 300 }; 301 302 /*! 303 * @cond 304 */ 305 306 /* Device context */ 307 struct rcar_clock_dev_ctx { 308 bool initialized; 309 uint64_t current_rate; 310 enum mod_clock_state current_state; 311 const struct mod_rcar_clock_dev_config *config; 312 }; 313 314 /* Module context */ 315 struct rcar_clock_ctx { 316 struct rcar_clock_dev_ctx *dev_ctx_table; 317 unsigned int dev_count; 318 uint32_t extal_clk; 319 }; 320 321 struct op_points { 322 unsigned long freq; /* Hz */ 323 unsigned long volt; /* uV */ 324 }; 325 326 #define PLL_BASE_CLOCK (16640000UL) 327 #define CPG_FRQCRB (CPG_BASE + 0x0004) 328 #define CPG_FRQCRB_KICK 0x80000000 329 #define CPG_FRQCRC (CPG_BASE + 0x00e0) 330 #define CPG_FRQCRC_ZFC_A57_MASK 0x00001F00 331 #define CPG_FRQCRC_ZFC_A57_SHIFT 8 332 #define CPG_FRQCRC_ZFC_A53_MASK 0x0000001F 333 #define CPG_FRQCRC_ZFC_A53_SHIFT 0 334 #ifndef CPG_PLL0CR 335 # define CPG_PLL0CR (CPG_BASE + 0x00d8) 336 #endif 337 #define CPG_PLL0CR_ZFC_MASK 0x7F000000 338 #define CPG_PLL0CR_ZFC_SHIFT 24 339 #ifndef CPG_PLL2CR 340 # define CPG_PLL2CR (CPG_BASE + 0x002c) 341 #endif 342 #define CPG_PLL2CR_ZFC_MASK 0x7F000000 343 #define CPG_PLL2CR_ZFC_SHIFT 24 344 345 #define min(x, y) \ 346 ({ \ 347 __typeof__(x) _x = (x); \ 348 __typeof__(y) _y = (y); \ 349 _x < _y ? _x : _y; \ 350 }) 351 352 #define max(x, y) \ 353 ({ \ 354 __typeof__(x) _x = (x); \ 355 __typeof__(y) _y = (y); \ 356 _x > _y ? _x : _y; \ 357 }) 358 359 #define clamp(val, lo, hi) min((__typeof__(val))max(val, lo), hi) 360 361 #define A57_DOMAIN 0 362 #define A53_DOMAIN 1 363 #define NR_H3_A57_OPP 5 364 #define NR_M3_A57_OPP 6 365 #define NR_H3_A53_OPP 3 366 #define NR_M3_A53_OPP 4 367 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 368 #define DIV_ROUND(n, d) (((n) + (d) / 2) / (d)) 369 370 /* CPG base address */ 371 #define CPG_PLLECR 0x00D0 372 373 /* Implementation for customized clocks (Z-clk, Z2-clk, PLL0-clk) for CPUFreq */ 374 #define CPG_PLLECR_PLL0ST BIT(8) 375 #define CPG_PLLECR_PLL2ST BIT(10) 376 377 /* Define for PLL0 clk driver */ 378 #define CPG_PLLCR_STC_MASK 0x7f000000 379 #define CPG_PLLCR_STC_SHIFT 24 380 381 /* Modify for Z-clock and Z2-clock 382 * 383 * Traits of this clock: 384 * prepare - clk_prepare only ensures that parents are prepared 385 * enable - clk_enable only ensures that parents are enabled 386 * rate - rate is adjustable. clk->rate = parent->rate * mult / 32 387 * parent - fixed parent. No clk_set_parent support 388 */ 389 #define CPG_FRQCRC_ZFC_MASK (0x1f << 8) 390 #define CPG_FRQCRC_ZFC_SHIFT 8 391 #define CPG_FRQCRC_Z2FC_MASK 0x1f 392 #define Z_CLK_MAX_THRESHOLD 1500000000U 393 #define Z2_CLK_MAX_THRESHOLD 1200000000U 394 395 extern int32_t rcar_iic_dvfs_receive( 396 uint8_t subordinate, 397 uint8_t reg, 398 uint8_t *data); 399 extern int32_t rcar_iic_dvfs_send( 400 uint8_t subordinate, 401 uint8_t regr, 402 uint8_t data); 403 404 /*! 405 * @endcond 406 */ 407 408 /*! 409 * @} 410 */ 411 412 /*! 413 * @} 414 */ 415 416 #endif /* MOD_RCAR_CLOCK_H */ 417