/* **************************************************************************** PROJECT : clock device driver FILE : $Id: r_dev_clk.c 15427 2017-12-15 07:52:33Z shinya.tomari $ ============================================================================ DESCRIPTION clock driver system functions for D1Mx (D1M1(H) .. D1M2(H)) ============================================================================ C O P Y R I G H T ============================================================================ Copyright (c) 2016 by Renesas Electronics (Europe) GmbH. Arcadiastrasse 10 D-40472 Duesseldorf Germany All rights reserved. ============================================================================ Purpose: only for testing, not for mass production DISCLAIMER LICENSEE has read, understood and accepted the terms and conditions defined in the license agreement, especially the usage rights. In any case, it is LICENSEE's responsibility to make sure that any user of the software complies with the terms and conditions of the signed license agreement. SAMPLE CODE is not part of the licensed software, as such it must not be used in mass-production applications. It can only be used for evaluation and demonstration purposes at customer's premises listed in the signed license agreement. **************************************************************************** */ /******************************************************************************* Title: D1Mx clock driver */ /******************************************************************************* Section: Local Constants */ /******************************************************************************* Section: Includes */ #include "r_typedefs.h" #include "r_dev_api.h" #if defined (R_DBG_PRINT_DEV_REGS) || defined (R_DBG_PRINT_MSG) #include <stdio.h> #include "r_dbg_api.h" #endif /******************************************************************************* Section: Local Types */ /******************************************************************************* Type: loc_PllCfgReg_t Contents of the PLL clock control/configuration register Members: NI - Integer part of Divider Nr P - Pr M - Mr SSMode - Spread Spectrum Mode NF - real part of Nr SSPerc - Spread Spectrum Percentage SSFreq - Spread Spectrum middle frequency FVV - VCO output frequency range */ typedef struct { uint32_t NI : 7; uint32_t P : 3; uint32_t M : 2; uint32_t SSMode : 2; uint32_t NF : 4; uint32_t SSPerc : 3; uint32_t SMFreq : 5; uint32_t FVV : 3; } loc_PllCfgReg_t; /******************************************************************************* Type: loc_CksBase_t Cks Base address type If there is no selection, because only one source clock is there, the ID of the clock is put instead the selector address If there is no divider register, the address is 0 Members: Sel - Address of clock source selection register Div - Address of divider DivIdx - index of the corresponding entry in the divider table DivMsk - Mask - valid divider bits */ typedef struct { uint32_t Sel; uint32_t Div; uint16_t DivIdx; uint16_t DivMsk; } loc_CksBase_t; /******************************************************************************* Section: Local Constants */ /******************************************************************************* Constant: LOC_HIGHS_FRQ_HZ The frequency of the internal High speed oscillator */ #define LOC_HIGHS_FRQ_HZ (8000000uL) /******************************************************************************* Constant: LOC_LOWS_FRQ_HZ The frequency of the internal High speed oscillator */ #define LOC_LOWS_FRQ_HZ (240000uL) /******************************************************************************* Constants: Register Offsets for clockgenerator registers LOC_GEN_E - Enable register LOC_GEN_S - Status register LOC_GEN_C - Control register LOC_GEN_STABI - Stabilisation time LOC_GEN_STPMSK - Stop mask */ #define LOC_GEN_E 0x00u #define LOC_GEN_S 0x04u #define LOC_GEN_C 0x08u #define LOC_GEN_STABI 0x0Cu #define LOC_GEN_STPMSK 0x18u /******************************************************************************* Constants: Register Offsets for clock selector registers LOC_CKS_S - Status LOC_CKS_A - Active selection LOC_CKS_STPMSK - Stop mask */ #define LOC_CKS_S 0x04u #define LOC_CKS_A 0x08u #define LOC_CKS_STPMSK 0x18u /******************************************************************************* Constant: LOC_GEN_ACTIVE_MASK */ #define LOC_GEN_ACTIVE_MASK (0x04u) /******************************************************************************* Constant: LOC_STOP_MASKED_SET */ #define LOC_STOP_MASKED_SET (0x01u) /******************************************************************************* Constant: LOC_AWO_CKS_BASE_ADDR Register base adress for AWO clock selectors */ #define LOC_AWO_CKS_BASE_ADDR 0xfff82000u /******************************************************************************* Constant: LOC_CPUSS_CKS_BASE_ADDR Register base adress for ISO clock selectors */ #define LOC_CPUSS_CKS_BASE_ADDR 0xfff8A000u /******************************************************************************* Constant: LOC_ISO_BASEADDRESS Register base adress for ISO clock selectors */ #define LOC_ISO_CKS_BASE_ADDR 0xfff85000u /******************************************************************************* Constant: loc_Base Register base adress for clock generators */ static const uint32_t loc_Base[R_DEV_CLK_GEN_NUM] = { /*R_DEV_PLL0 */ 0xFFF89000u, /*R_DEV_PLL1 */ 0xFFF89100u, /*R_DEV_PLL2 */ 0xFFF850C0u, /*R_DEV_HS_RING */ 0xFFF81000u, /*R_DEV_MOSC */ 0xFFF81100u, /*R_DEV_SUB_OSC */ 0xFFF81200u }; /******************************************************************************* Constant: LOC_PROTCMD0 Address of the AWO protection register */ #define LOC_PROTCMD0 (0xfff80000u) /******************************************************************************* Constant: LOC_PROTCMD1 Address of the ISO protection register */ #define LOC_PROTCMD1 (0xfff88000u) /******************************************************************************* Constant: LOC_PROTCMDD1 Address of the another ISO protection cluster */ #define LOC_PROTCMDD1 (0xfff87000u) /******************************************************************************* Constant: LOC_PBUS_RATIO Address of the PBUS CLOCK ratio setting register Old header: 0xfff8f504 UM: 0xfff8f510u */ #define LOC_PBUS_RATIO (0xfff8f510u) /******************************************************************************* Constant: LOC_PROTCMDPWRGD Address of the PBUS CLOCK ratio protection register */ #define LOC_PROTCMDPWRGD (0xfff8f580u) /******************************************************************************* Constant: LOC_F Placeholder, marker If the divider slot 0 has this value in the allowed settings table, the divider value is not taken from any slot but literaly from the given register */ #define LOC_F 0xFEFEu /******************************************************************************* Constant: LOC_D Placeholder, marker If the divider slot has this value, the setting is not available */ #define LOC_N 0xFFFFu static const uint32_t locBusRegAddr[R_DEV_CLK_BUS_LAST] = { /* R_DEV_CLK_PLL0 */ 0xFFF89200u, /* R_DEV_CLK_PLL1 */ 0xFFF89300u, /* R_DEV_CLK_PLL2 */ 0xFFF85100u, /* R_DEV_CLK_PLL0PIX */ 0xFFF85640u, /* R_DEV_CLK_SDRB */ 0xFFF85140u, /* R_DEV_CLK_ETNBP */ 0xFFF85280u, /* R_DEV_CLK_MLBP */ 0xFFF852C0u, /* R_DEV_CLK_RSCANP */ 0xFFF85240u, /* R_DEV_CLK_XCC */ 0xFFF85180u, /* R_DEV_CLK_ETNBXCC */ 0xFFF851C0u, /* R_DEV_CLK_MLBXCC */ 0xFFF85200u, }; /******************************************************************************* Constant: loc_ClkSelOffset Register base adress for clock selectors The clock selection for RLIN and RLIN30 uses the same register But the RLIN30 has an additional divider regiaster */ static const loc_CksBase_t loc_CkcsBaseAddr[R_DEV_CKS_LAST] = { /* Clock selector sourceID or selector addr , divider addr or 0 DivIdx DivMsk*/ /* R_DEV_CKS_WDT0 */ {R_DEV_CKS_SRC_LRNG, LOC_AWO_CKS_BASE_ADDR , 0 , 0x7Eu}, /* R_DEV_CKS_AWOT */ {LOC_AWO_CKS_BASE_ADDR + 0x100u, LOC_AWO_CKS_BASE_ADDR + 0x200u, 1 , 0x3Eu}, /* R_DEV_CKS_RTCA */ {LOC_AWO_CKS_BASE_ADDR + 0x300u, LOC_AWO_CKS_BASE_ADDR + 0x400u, 2 , 0x3Fu}, /* R_DEV_CKS_FOUT */ {LOC_AWO_CKS_BASE_ADDR + 0x700u, LOC_AWO_CKS_BASE_ADDR + 0x800u, 3 , 0xFFu}, /* R_DEV_CKS_CPU */ {LOC_CPUSS_CKS_BASE_ADDR , LOC_CPUSS_CKS_BASE_ADDR + 0x100u, 4 , 0x3Eu}, /* R_DEV_CKS_MLB */ {LOC_ISO_CKS_BASE_ADDR + 0x300u, 0, 0xFFu, 0x0} , /* R_DEV_CKS_SFMA */ {LOC_ISO_CKS_BASE_ADDR + 0x340u, LOC_ISO_CKS_BASE_ADDR + 0x380u, 5 , 0x1Fu}, /* R_DEV_CKS_RSCAN */ {R_DEV_CKS_SRC_PLLFIX , LOC_ISO_CKS_BASE_ADDR + 0x780u, 6 , 0x0Fu}, /* R_DEV_CKS_RSCANXIN*/ {LOC_ISO_CKS_BASE_ADDR + 0x800u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_SSIF */ {R_DEV_CKS_SRC_PLLFIX , LOC_ISO_CKS_BASE_ADDR + 0x7C0u, 7 , 0x01u}, /* R_DEV_CKS_TAUB0 */ {LOC_ISO_CKS_BASE_ADDR + 0x540u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_TAUB2 */ {LOC_ISO_CKS_BASE_ADDR + 0x580u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_TAUJ */ {LOC_ISO_CKS_BASE_ADDR + 0x5C0u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_OSTM */ {LOC_ISO_CKS_BASE_ADDR + 0x600u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_LCBI */ {LOC_ISO_CKS_BASE_ADDR + 0x4C0u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_ADCE */ {R_DEV_CKS_SRC_CLKJIT , LOC_ISO_CKS_BASE_ADDR + 0x480u, 8 , 0x06u}, /* R_DEV_CKS_ISM */ {LOC_ISO_CKS_BASE_ADDR + 0x440u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_RLIN */ {LOC_ISO_CKS_BASE_ADDR + 0x500u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_CLKJIT */ {LOC_ISO_CKS_BASE_ADDR + 0x400u, LOC_ISO_CKS_BASE_ADDR + 0x3C0u, 9 , 0x02u}, /* R_DEV_CKS_CLKFIX */ {LOC_ISO_CKS_BASE_ADDR + 0x740u, LOC_ISO_CKS_BASE_ADDR + 0x700u, 10 , 0x02u}, /* R_DEV_CKS_PLLFIX */ {LOC_ISO_CKS_BASE_ADDR , 0, 0xFFu, 0x0}, /* R_DEV_CKS_PLL2IN */ {LOC_ISO_CKS_BASE_ADDR + 0x080u, LOC_ISO_CKS_BASE_ADDR + 0x040u, 11 , 0x02u}, /* R_DEV_CKS_DOTCK0 */ {LOC_ISO_CKS_BASE_ADDR + 0x940u, LOC_ISO_CKS_BASE_ADDR + 0x9C0u, 12 , 0x02u}, /* R_DEV_CKS_DOTCK1 */ {LOC_ISO_CKS_BASE_ADDR + 0x980u, LOC_ISO_CKS_BASE_ADDR + 0xA00u, 13 , 0x02u}, /* R_DEV_CKS_VDCE0CK */ {LOC_ISO_CKS_BASE_ADDR + 0x880u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_VDCE1CK */ {LOC_ISO_CKS_BASE_ADDR + 0x8C0u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_RSDSCK */ {LOC_ISO_CKS_BASE_ADDR + 0xA40u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_VI0CLK */ {LOC_ISO_CKS_BASE_ADDR + 0x840u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_MIPIPLL */ {LOC_ISO_CKS_BASE_ADDR + 0x680u, 0, 0xFFu, 0x0}, /* R_DEV_CKS_MIPIPXL */ {R_DEV_CKS_SRC_MIPIPLL , LOC_ISO_CKS_BASE_ADDR + 0x6C0u, 14 , 0x0Fu} }; #define LOC_DIS (R_DEV_CKS_SRC_DISABLED) #define LOC_LRNG (R_DEV_CKS_SRC_LRNG) #define LOC_HRING (R_DEV_CKS_SRC_HRING) #define LOC_EM (R_DEV_CKS_SRC_ERING) #define LOC_MOSC (R_DEV_CKS_SRC_MOSC) #define LOC_SOSC (R_DEV_CKS_SRC_SOSC) #define LOC_PLL0 (R_DEV_CKS_SRC_PLL0) #define LOC_PLL0_2 (R_DEV_CKS_SRC_PLL0_2) #define LOC_PLL0_4 (R_DEV_CKS_SRC_PLL0_4) #define LOC_PLL1 (R_DEV_CKS_SRC_PLL1) #define LOC_PLL1_4 (R_DEV_CKS_SRC_PLL1_4) #define LOC_PLL2 (R_DEV_CKS_SRC_PLL2) #define LOC_PLL2_4 (R_DEV_CKS_SRC_PLL2_4) #define LOC_ISOCPU_4 (R_DEV_CKS_SRC_ISOCPU_4) #define LOC_CLKFIX (R_DEV_CKS_SRC_CLKFIX) #define LOC_CLKFIX_8 (R_DEV_CKS_SRC_CLKFIX_8) #define LOC_CLKJIT (R_DEV_CKS_SRC_CLKJIT) #define LOC_CLKJIT_2 (R_DEV_CKS_SRC_CLKJIT_2) #define LOC_CLKJIT_4 (R_DEV_CKS_SRC_CLKJIT_4) #define LOC_CLKJIT_8 (R_DEV_CKS_SRC_CLKJIT_8) #define LOC_PLLFIX_10 (R_DEV_CKS_SRC_PLLFIX_10) #define LOC_PLLFIX_20 (R_DEV_CKS_SRC_PLLFIX_20) #define LOC_PLL0PIX (R_DEV_CKS_SRC_PLL0PIX) #define LOC_PLLFIX (R_DEV_CKS_SRC_PLLFIX) #define LOC_PLL0PIX_3 (R_DEV_CKS_SRC_PLL0PIX_3) #define LOC_PLLFIX_3 (R_DEV_CKS_SRC_PLLFIX_3) #define LOC_DOTC0 (R_DEV_CKS_SRC_DOTCK0) #define LOC_DOTC0_4 (R_DEV_CKS_SRC_DOTCK0_4) #define LOC_DOTC0_7 (R_DEV_CKS_SRC_DOTCK0_7) #define LOC_DOTC1 (R_DEV_CKS_SRC_DOTCK1) #define LOC_DOTC1_4 (R_DEV_CKS_SRC_DOTCK1_4) #define LOC_DOTC1_7 (R_DEV_CKS_SRC_DOTCK1_7) #define LOC_V1PIX (R_DEV_CKS_SRC_VI1PIX) #define LOC_V0PIX (R_DEV_CKS_SRC_VI0PIX) #define LOC_VI0CLK (R_DEV_CKS_SRC_VI0CLK) #define LOC_MIPIPIX (R_DEV_CKS_SRC_MIPIPXL) #define LOC_MIPIPLL (R_DEV_CKS_SRC_MIPIPLL) #define LOC_XX (R_DEV_CKS_SRC_LAST) #define LOC_DIV (R_DEV_CKS_SRC_DIV) static const r_dev_CksSrc_t loc_ClockTree[R_DEV_CKS_LAST][8] = { /* there are max 8 slots, LOC_XX means forbidden value/selection */ /* Clock selector domain cks source slot 0 1 2 3 4 5 6 7 */ /* R_DEV_CKS_WDT0 */{LOC_XX, LOC_LRNG, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_AWOT */{LOC_DIS, LOC_HRING, LOC_MOSC, LOC_LRNG, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_RTCA */{LOC_DIS, LOC_SOSC, LOC_MOSC, LOC_LRNG, LOC_HRING, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_FOUT */{LOC_DIS, LOC_MOSC, LOC_HRING, LOC_LRNG, LOC_SOSC, LOC_PLL0_4, LOC_PLL1_4, LOC_PLL2_4}, /* R_DEV_CKS_CPU */{LOC_XX, LOC_EM, LOC_XX, LOC_PLL0, LOC_PLL1, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_MLB */{LOC_DIS, LOC_PLL0_2, LOC_PLL0_4, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_SFMA */{LOC_XX, LOC_PLL0, LOC_PLL1, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_RSCAN */{LOC_PLLFIX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_RSCANXIN*/{LOC_DIS, LOC_MOSC, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_SSIF */{LOC_PLLFIX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_TAUB0 */{LOC_DIS, LOC_CLKFIX, LOC_CLKFIX_8, LOC_CLKJIT, LOC_CLKJIT_8, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_TAUB2 */{LOC_DIS, LOC_CLKFIX, LOC_CLKFIX_8, LOC_CLKJIT, LOC_CLKJIT_8, LOC_MOSC, LOC_XX, LOC_XX }, /* R_DEV_CKS_TAUJ */{LOC_DIS, LOC_CLKFIX, LOC_CLKFIX_8, LOC_CLKJIT, LOC_CLKJIT_8, LOC_MOSC, LOC_ISOCPU_4, LOC_XX }, /* R_DEV_CKS_OSTM */{LOC_DIS, LOC_CLKJIT, LOC_ISOCPU_4, LOC_MOSC, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_LCBI */{LOC_DIS, LOC_CLKJIT, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_ADCE */{LOC_XX, LOC_CLKJIT_2, LOC_CLKJIT_4, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_ISM */{LOC_DIS, LOC_CLKJIT, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_RLIN */{LOC_XX, LOC_PLLFIX_10, LOC_CLKJIT, LOC_PLLFIX_20, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_CLKJIT */{LOC_XX, LOC_DIV, LOC_HRING, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_CLKFIX */{LOC_XX, LOC_DIV, LOC_HRING, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_PLLFIX */{LOC_XX, LOC_PLL1, LOC_PLL2, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_PLL2IN */{LOC_XX, LOC_DIV, LOC_MOSC, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_DOTCK0 */{LOC_DIS, LOC_PLL0PIX, LOC_PLL1, LOC_PLL2, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_DOTCK1 */{LOC_DIS, LOC_PLL0PIX, LOC_PLLFIX, LOC_PLL2, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_VDCE0CK */{LOC_DIS, LOC_DOTC0, LOC_DOTC0_4, LOC_V0PIX, LOC_V1PIX, LOC_DOTC0_7, LOC_XX, LOC_XX }, /* R_DEV_CKS_VDCE1CK */{LOC_DIS, LOC_DOTC1, LOC_DOTC1_4, LOC_V1PIX, LOC_V0PIX, LOC_DOTC1_7, LOC_XX, LOC_XX }, /* R_DEV_CKS_RSDSCK */{LOC_XX, LOC_DOTC0, LOC_DOTC1, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_VI0CLK */{LOC_XX, LOC_VI0CLK, LOC_MIPIPIX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_MIPIPLL */{LOC_XX, LOC_PLL0PIX_3, LOC_PLLFIX_3, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX }, /* R_DEV_CKS_MIPIPXL */{LOC_XX, LOC_MIPIPLL, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX, LOC_XX } }; /******************************************************************************* Constant: loc_ClkDivSel For each divider, the register value has different meaning. Sometimes it is a divider selection, sometimes it is the divider value itself Explanation of settings: LOC_N : Setting not valid (the corresponding value is not allowed for the given register) LOC_F : Full register is used (no translation of values) as divider for the selected source The source selection is determined by the value stored in loc_ClockTree That means if for the sourceID the div value in the corresponding slot is LOC_F, the register value of the divider register is used as divider for the corresponding clock source any number: Divider for the selected source clock Following selectors have dividers: R_DEV_CKS_WDT0 7E R_DEV_CKS_AWOT 3E R_DEV_CKS_RTC 3F R_DEV_CKS_FOUT FF R_DEV_CKS_CPU 3E R_DEV_CKS_SFMA 1F R_DEV_CKS_RSCAN 0F R_DEV_CKS_SSIF 01 R_DEV_CKS_ADCE 06 R_DEV_CKS_CLKJIT 02 R_DEV_CKS_CLKFIX 02 R_DEV_CKS_PLL2IN 02 R_DEV_CKS_DOTCK0 02 R_DEV_CKS_DOTCK1 02 R_DEV_CKS_MIPIPXL 0F */ static const uint16_t loc_ClkSelDiv[15][8] = { /* (0xFF - setting prohibited) */ /* div slot 0, 1, 2, 3, 4, 5, 6 , 7*/ /* R_DEV_CKS_WDT0 */ {LOC_N, 128u, 1u, 256u, 512u, 1024u, 2048u, LOC_N}, /* R_DEV_CKS_AWOT */ {LOC_N, 1u, 2u, 4u, 8u, 16u, LOC_N, LOC_N}, /* R_DEV_CKS_RTC */ { 0, 1u, 2u, 4u, 8u, 16u, LOC_N, LOC_N}, /* R_DEV_CKS_FOUT */ {LOC_F, LOC_F, LOC_F, LOC_F, LOC_F, LOC_F, LOC_F, LOC_F}, /* R_DEV_CKS_CPU */ {LOC_N, 1u, 2u, 4u, 8u, 3u, LOC_N, LOC_N}, /* R_DEV_CKS_SFMA */ { 0, 2u, 3u, 4u, 6u, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_RSCAN */ { 0, 30u, 40u, 60u, 12u, 24u, LOC_N, LOC_N}, /* R_DEV_CKS_SSIF */ {LOC_F, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_ADCE */ {LOC_N, 2u, 4u, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_CLKJIT */ {LOC_N, LOC_F, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_CLKFIX */ {LOC_N, LOC_F, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_PLL2IN */ {LOC_N, LOC_F, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_DOTCK0 */ {LOC_N, LOC_F, LOC_F, LOC_F, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_DOTCK1 */ {LOC_N, LOC_F, LOC_F, LOC_F, LOC_N, LOC_N, LOC_N, LOC_N}, /* R_DEV_CKS_MIPIPXL */ { 0, 3u, 6u, 12u, LOC_N, LOC_N, LOC_N, LOC_N}, }; static const uint16_t loc_SscgDiv[32] = { 10 , 12 , 18 , 20 , 22 , 26 , 28 , 30 , 34 , 38 , 40 , 44 , 50 , 56 , 58 , 60 , 62 , 66 , 72 , 76 , 80 , 84 , 86 , 100 , 120 , 126 , 134 , 150 , 166 , 200 , 250 , 300 }; static const uint8_t loc_SscgPercent[8] = { 1 , 2 , 3 , 4 , 5 , 6 , 8 , 10 , }; /******************************************************************************* Section: Local Variables */ /******************************************************************************* Variable: LocPbusRatio Store the PBUS clock ration (it's configurable for D1M1 only) */ volatile static uint32_t LocPbusRatio = 2; /* loc_ClkGenCfg - local Clock generator configuration */ static r_dev_ClkGenConfig_t loc_ClkGenCfg; /******************************************************************************* Variable: loc_Vdce0ViFreq Store the frequency (in Hz) of the external input VDCE0_VI_CLK */ static uint32_t loc_Vdce0ViFreq = 0; /******************************************************************************* Variable: loc_Vdce1ViFreq Store the frequency (in Hz) of the external input VDCE1_VI_CLK */ static uint32_t loc_Vdce1ViFreq = 0; /******************************************************************************* Section: Local functions */ static void loc_WritePllCfg (r_dev_ClkGen_t Pll, loc_PllCfgReg_t * PllCfgReg); static r_Error_t loc_CalcFreqPll0(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut); static r_Error_t loc_CalcFreqPll1(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut); static r_Error_t loc_CalcFreqPll2(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut); static uint32_t loc_SrcFrequencyHz(r_dev_CksSrc_t ClkSrc); static r_Error_t loc_CalcSscgPll0(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, const r_dev_PllCfg_t * PllCfg); static void loc_PllCfgStore(uint32_t FrqIn, r_dev_ClkGen_t Pll, const r_dev_PllCfg_t *PllCfg); /******************************************************************************* Function: loc_PllCfgStore this is a copy of the PllConfig function, used to store the settings after low init whre all the structures were deleted */ static void loc_PllCfgStore(uint32_t FrqIn, r_dev_ClkGen_t Pll, const r_dev_PllCfg_t *PllCfg) { uint32_t freq_out = PllCfg->FrequencyHz/1000000u; r_Error_t ret_val = R_NG; uint32_t regval = 0; loc_PllCfgReg_t pllcfg_reg; /* This one is not needed here */ Pll = Pll; /* Clear Config */ pllcfg_reg.NI = 0; pllcfg_reg.P = 0; pllcfg_reg.M = 0; pllcfg_reg.NF = 0; pllcfg_reg.SSMode = 0; pllcfg_reg.SSPerc = 0; pllcfg_reg.SMFreq = 0; /* VC = freq = fin * Nr/Pr */ /* Set/Check the frequency */ switch (Pll) { case R_DEV_PLL0: ret_val = loc_CalcFreqPll0(FrqIn/1000000, &pllcfg_reg, &freq_out); if ((R_ERR_OK == ret_val) && (R_DEV_PLL_SSCG == PllCfg->Mode)) { /*The input frequency is provided in KHz here */ ret_val = loc_CalcSscgPll0(FrqIn/1000, &pllcfg_reg, PllCfg); } break; case R_DEV_PLL1: ret_val = loc_CalcFreqPll1(FrqIn/1000000, &pllcfg_reg, &freq_out); break; case R_DEV_PLL2 : /* First, get the input frquency */ regval = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLL2IN); ret_val = loc_CalcFreqPll2(regval/1000000, &pllcfg_reg, &freq_out); pllcfg_reg.FVV = 0; /* Init value */ pllcfg_reg.NF = 1; break; default: ret_val = R_PARAMETER_RANGE; break; } /* If everything went smooth, store the values */ if (R_ERR_OK == ret_val) { /* Store the config */ loc_ClkGenCfg.Pll[Pll].Mode = PllCfg->Mode ; loc_ClkGenCfg.Pll[Pll].DithMode = PllCfg->DithMode ; loc_ClkGenCfg.Pll[Pll].DithRange = PllCfg->DithRange ; loc_ClkGenCfg.Pll[Pll].ModFreq = PllCfg->ModFreq ; loc_ClkGenCfg.Pll[Pll].FrequencyHz = freq_out * 1000000u ; loc_ClkGenCfg.Pll[Pll].StabiTimeNs = PllCfg->StabiTimeNs ; loc_ClkGenCfg.Pll[Pll].StpReqMsk = PllCfg->StpReqMsk ; } } /******************************************************************************* Function: loc_WritePLLCfg Write the PLL configuration to the PLL config register Parameters: Returns: void r_dev_PllMode_t Mode r_dev_PllDithMode_t DithMode uint8_t DithRange uint32_t ModFreq uint32_t FrequencyHz uint32_t StabiTimeNs uint8_t StpReqMsk */ static void loc_WritePllCfg (r_dev_ClkGen_t Pll, loc_PllCfgReg_t * PllCfgReg) { uint32_t addr = 0; uint32_t reg_val = 0; /* Allign the inforemation */ reg_val |= ((uint32_t) PllCfgReg->NI << 0u); reg_val |= ((uint32_t) PllCfgReg->P << 8u); reg_val |= ((uint32_t) PllCfgReg->M << 11u); reg_val |= ((uint32_t) PllCfgReg->SSMode << 13u); reg_val |= ((uint32_t) PllCfgReg->NF << 16u); reg_val |= ((uint32_t) PllCfgReg->SSPerc << 20u); reg_val |= ((uint32_t) PllCfgReg->SMFreq << 24u); reg_val |= ((uint32_t) PllCfgReg->FVV << 29u); /* Write the value */ addr = loc_Base[Pll] + LOC_GEN_C; R_DEV_WRITE_REG(32, addr, reg_val); } /******************************************************************************* Function: loc_CalcSscgPll0 Calculate the right paramaters to set the SSCG function for PLL0 Parameters: FrqIn - input frequency in KHz PllCfgReg - pointer to PLLC register structure, see <loc_PllCfgReg_t> PllCfg - pointer to PLLC config structure, see <r_dev_PllCfg_t> Returns: == R_ERR_OK - found apropriate settings != R_ERR_OK - no matching parameters found */ static r_Error_t loc_CalcSscgPll0(uint32_t FrqIn, loc_PllCfgReg_t *PllCfgReg, const r_dev_PllCfg_t *PllCfg) { uint32_t vc_in = 0; uint16_t d_r = 0; uint32_t i = 0; uint16_t perc = 0; r_Error_t retval = R_ERR_OK; if (R_DEV_PLL_DITH_CENTER == PllCfg->DithMode) { PllCfgReg->SSMode = 3u; if ((0 < PllCfg->DithRange) && (PllCfg->DithRange < 6)) { perc = PllCfg->DithRange * 2u; } else { return R_PARAMETER_INCORRECT; } } else { PllCfgReg->SSMode = 2u; if ((0 < PllCfg->DithRange) && (PllCfg->DithRange < 11)) { perc = PllCfg->DithRange; } else { return R_PARAMETER_INCORRECT; } } d_r = 0; if(PllCfgReg->M != 0) { vc_in = FrqIn / PllCfgReg->M; } else { vc_in = FrqIn; } /* F_mod = vc_in / (4* Dr) Dr = vc_in / (4 * f_mod) */ if ((PllCfg->ModFreq > 19u) && (PllCfg->ModFreq < 101u)) { d_r = vc_in / (4u * PllCfg->ModFreq); } else { return R_PARAMETER_INCORRECT; } for (i = 0; i < 32; i ++) { if (loc_SscgDiv[i] >= d_r) { break; } } /* check if the search was successfull */ if (i < 32) { /* Yes, we found some */ PllCfgReg->SMFreq = i; } else { return R_PARAMETER_INCORRECT; } for (i = 0; i < 8; i ++) { if (loc_SscgPercent[i] >= perc) { break; } } if (i < 8) { /* Yes, we found some */ PllCfgReg->SSPerc = i; } else { return R_PARAMETER_INCORRECT; } return retval; } /******************************************************************************* Function: loc_CalcFreqPlln Calculate the right paramaters to set the desired PLL Frequency Parameters: FrqIn - input frequency in MHz PllCfgReg - pointer to PLLC register structure, see <loc_PllCfgReg_t> *FreqOut - desired output frequency in Mhz Returns: == R_ERR_OK - found apropriate settings != R_ERR_OK - no matching parameters found */ static r_Error_t loc_CalcFreqPll0(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut) { /* Caculate the right values */ /*F = (Fx * Nr) / (Mr * Pr) : Mr = PLLkC.M[1:0] + 1 Pr = 1, 2, 3, 4, 8 16 P[2:0] = log_2(Pr); 2^(P[]) = Pr Nr = PLLkC.NI + 1 + PLLkC.NF. We set PLLkC.NF to 0 Nr = PLLkC.NI + 1 PLL0: NI[6:0] = Nr - 1 PLL1: NI[6:0] = Nr/2 - 1 */ uint32_t p_r = 0; uint32_t m_r = 0; uint32_t n_r = 0; uint32_t freq = 0; uint32_t vc_out = 0; uint32_t i = 1; r_Error_t retval = R_NG; PllCfgReg->NI = 0; PllCfgReg->P = 0; PllCfgReg->M = 0; freq = *FrqOut; if (freq > 480u) { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } else if (freq > 320u) { p_r = 1u; PllCfgReg->P = 0; } else if (freq > 160u) { p_r = 2; PllCfgReg->P = 1u; } else if (freq > 80u) { p_r = 4u; PllCfgReg->P = 2u; } else if (freq > 40u) { p_r = 8; PllCfgReg->P = 3u; } else if (freq > 20u) { p_r = 16u; PllCfgReg->P = 4u; } else { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } if (24u == FrqIn) { m_r = 3u; } else if (16u <= FrqIn) { m_r = 2u; } else if (8u <= FrqIn) { m_r = 1u; } else { /* the input frequency is not valid */ return R_PARAMETER_INCORRECT; } n_r = (freq * m_r * p_r)/FrqIn; /* we omit the check of Nr is even */ /* as all parameters are even and we expect the frequency input to be even too */ /* nr will be also even */ /* do we have a valid parameter */ if ((n_r > 11) && (n_r < 81) ) { PllCfgReg->NI = (uint8_t) n_r - 1u ; PllCfgReg->M = (uint8_t) m_r - 1u ; *FrqOut = (FrqIn * n_r)/(m_r * p_r); /* Calculate FVV setting */ vc_out = *FrqOut * p_r; while ((320u + (i * 40u)) < vc_out) { i++; } if (i < 9) { PllCfgReg->FVV = i - 1u; } else { PllCfgReg->FVV = 3; /* init value */ } retval = R_ERR_OK; } else { *FrqOut = 0; PllCfgReg->NI = 0; PllCfgReg->M = 0; PllCfgReg->P = 0; PllCfgReg->FVV = 3; /* Init value */ retval = R_PARAMETER_INCORRECT; } return retval; } static r_Error_t loc_CalcFreqPll1(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut) { /* Caculate the right values */ /*F = (Fx * Nr) / (Mr * Pr) : Mr = PLLkC.M[1:0] + 1 Pr = 1, 2, 3, 4, 8 16 P[2:0] = log_2(Pr); 2^(P[]) = Pr Nr = PLLkC.NI + 1 + PLLkC.NF. We set PLLkC.NF to 0 Nr = PLLkC.NI + 1 PLL0: NI[6:0] = Nr - 1 PLL1: NI[6:0] = Nr/2 - 1 */ uint32_t p_r = 0; uint32_t m_r = 0; uint32_t n_r = 0; uint32_t freq = 0; uint32_t vc_out = 0; uint32_t i = 1; r_Error_t retval = R_NG; r_dev_Device_t device; PllCfgReg->NI = 0; PllCfgReg->P = 0; PllCfgReg->M = 0; freq = *FrqOut; /* These functions can cover all devices of the d1l/d1m family including the D1M2(H). */ /* The D1M2(H) has a different HW-configuration for PLL1 which is reflected by the values shown here. */ /* For this function to work with all lower devices, their FrqOut has to be multiplied by 2 */ device = R_DEV_GetDev(); if (((device >= R_DEV_R7F701400) && (device <= R_DEV_R7F701407)) || (device == R_DEV_R7F701442) || (device == R_DEV_R7F701418) || (device == R_DEV_R7F701441)) { freq = freq * 2; } if (freq > 960u) { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } else if (freq > 533u) { p_r = 1u; PllCfgReg->P = 0; } else if (freq > 266u) { p_r = 2; PllCfgReg->P = 1u; } else if (freq > 160u) { p_r = 4u; PllCfgReg->P = 2u; } else if (freq > 67u) { p_r = 8; PllCfgReg->P = 3u; } else if (freq > 40u) { p_r = 16u; PllCfgReg->P = 4u; } else { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } if (24u == FrqIn) { m_r = 3u; } else if (16u <= FrqIn) { m_r = 2u; } else if (8u <= FrqIn) { m_r = 1u; } else { /* the input frequency is not valid */ return R_PARAMETER_INCORRECT; } n_r = (freq * m_r * p_r)/FrqIn; /* do we have a valid parameter */ if ((n_r > 23) && (n_r < 161) ) { *FrqOut = (FrqIn * n_r)/(m_r * p_r); PllCfgReg->NI = (uint8_t) (n_r/2) - 1u ; PllCfgReg->M = (uint8_t) m_r - 1u ; /* Calculate FVV setting */ vc_out = *FrqOut * p_r; i = 1; while ((640u + (i * 80u)) < vc_out) { i++; } if (i < 8) { PllCfgReg->FVV = i -1u; } else { PllCfgReg->FVV = 3; /* init value */ } /* D1Lx and D1M1(H): See comment at begin of function. */ /* => Divide back the factor of 2 added at the begin of this function. */ /* D1M2(H): The PLL1 is followed by a DIVIDE 2, so in the end, */ /* we ALWAYS divide by two. */ *FrqOut /= 2; retval = R_ERR_OK; } else { *FrqOut = 0; PllCfgReg->NI = 0; PllCfgReg->M = 0; PllCfgReg->P = 0; retval = R_PARAMETER_INCORRECT; } return retval; } static r_Error_t loc_CalcFreqPll2(uint32_t FrqIn, loc_PllCfgReg_t * PllCfgReg, uint32_t *FrqOut) { /* Caculate the right values */ /*F = (Fx * Nr) / (Mr * Pr) : Mr = PLLkC.M[1:0] + 1 Pr = 1, 2, 3, 4, 8 16 P[2:0] = log_2(Pr); 2^(P[]) = Pr Nr = PLLkC.NI + 1 + PLLkC.NF. We set PLLkC.NF to 0 Nr = PLLkC.NI + 1 PLL0: NI[6:0] = Nr - 1 PLL1: NI[6:0] = Nr/2 - 1 */ uint32_t p_r = 0; uint32_t m_r = 0; uint32_t n_r = 0; uint32_t freq = 0; r_Error_t retval = R_NG; PllCfgReg->NI = 0; PllCfgReg->P = 0; PllCfgReg->M = 0; freq = *FrqOut; if (freq > 480u) { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } else if (freq > 240u) { p_r = 1u; PllCfgReg->P = 0; } else if (freq > 120u) { p_r = 2; PllCfgReg->P = 1u; } else if (freq > 60u) { p_r = 4u; PllCfgReg->P = 2u; } else if (freq > 40u) { p_r = 6; PllCfgReg->P = 3u; } else if (freq > 30u) { p_r = 8u; PllCfgReg->P = 4u; } else if (freq > 20u) { p_r = 16u; PllCfgReg->P = 4u; } else { /* the desired frequency is not valid */ return R_PARAMETER_INCORRECT; } if (24u == FrqIn) { m_r = 3u; } else if (16u <= FrqIn) { m_r = 2u; } else if (8u <= FrqIn) { m_r = 1u; } else { /* the input frequency is not valid */ return R_PARAMETER_INCORRECT; } n_r = (freq * m_r * p_r)/FrqIn; /* do we have a valid parameter */ if ((n_r > 19) && (n_r < 61) ) { *FrqOut = (FrqIn * n_r)/(m_r * p_r); PllCfgReg->NI = (uint8_t) n_r - 1u; PllCfgReg->M = (uint8_t) m_r - 1u; retval = R_ERR_OK; } else { *FrqOut = 0; PllCfgReg->NI = 0; PllCfgReg->M = 0; PllCfgReg->P = 0; retval = R_PARAMETER_INCORRECT; } return retval; } /******************************************************************************* Function: loc_SrcFrequencyHz Get the frequency setting for the given source */ static uint32_t loc_SrcFrequencyHz(r_dev_CksSrc_t ClkSrc) { uint32_t freq = 0; switch (ClkSrc) { case R_DEV_CKS_SRC_DISABLED : freq = 0; break; case R_DEV_CKS_SRC_LRNG : freq = LOC_LOWS_FRQ_HZ; break; case R_DEV_CKS_SRC_HRING : freq = LOC_HIGHS_FRQ_HZ; break; case R_DEV_CKS_SRC_ERING : /* select the right OSC */ if (0 != R_DEV_ClkGenActive(R_DEV_HS_RING)) { freq = LOC_HIGHS_FRQ_HZ; } else { freq = LOC_LOWS_FRQ_HZ; } break; case R_DEV_CKS_SRC_MOSC : if (0 != R_DEV_ClkGenActive(R_DEV_MOSC)) { freq = R_DEV_MOSC_FRQ_HZ; } else { freq = 0; } break; case R_DEV_CKS_SRC_SOSC : if (0 != R_DEV_ClkGenActive(R_DEV_SOSC)) { freq = loc_ClkGenCfg.SubOsc.FrequencyHz; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL0 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL0)) { freq = loc_ClkGenCfg.Pll[0].FrequencyHz; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL0_2 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL0)) { freq = loc_ClkGenCfg.Pll[0].FrequencyHz / 2; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL0_4 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL0)) { freq = loc_ClkGenCfg.Pll[0].FrequencyHz / 4; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL1 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL1)) { freq = loc_ClkGenCfg.Pll[1].FrequencyHz / 1; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL1_4 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL1)) { freq = loc_ClkGenCfg.Pll[1].FrequencyHz / 4; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL2 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL2)) { freq = loc_ClkGenCfg.Pll[2].FrequencyHz; } else { freq = 0; } break; case R_DEV_CKS_SRC_PLL2_4 : if (0 != R_DEV_ClkGenActive(R_DEV_PLL2)) { freq = loc_ClkGenCfg.Pll[2].FrequencyHz / 4; } else { freq = 0; } break; case R_DEV_CKS_SRC_ISOCPU_4 : freq = R_DEV_BusFrequencyHz(R_DEV_CLK_CPU) / 4; break; case R_DEV_CKS_SRC_CLKFIX : freq = R_DEV_BusFrequencyHz(R_DEV_CLK_FIX); break; case R_DEV_CKS_SRC_CLKFIX_8 : freq = R_DEV_BusFrequencyHz(R_DEV_CLK_FIX) / 8; break; case R_DEV_CKS_SRC_CLKJIT : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKJIT); break; case R_DEV_CKS_SRC_CLKJIT_2 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKJIT) / 2; break; case R_DEV_CKS_SRC_CLKJIT_4 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKJIT) / 4; break; case R_DEV_CKS_SRC_CLKJIT_8 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKJIT) / 8; break; case R_DEV_CKS_SRC_PLLFIX : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLLFIX); break; case R_DEV_CKS_SRC_PLLFIX_3 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLLFIX) / 3; break; case R_DEV_CKS_SRC_PLLFIX_10: freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLLFIX) / 10; break; case R_DEV_CKS_SRC_PLLFIX_20: freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLLFIX) / 20; break; case R_DEV_CKS_SRC_PLL0PIX: freq = R_DEV_BusFrequencyHz(R_DEV_CLK_PLL0PIX); break; case R_DEV_CKS_SRC_PLL0PIX_3: freq = R_DEV_BusFrequencyHz(R_DEV_CLK_PLL0PIX) / 3; break; case R_DEV_CKS_SRC_DOTCK0 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK0); break; case R_DEV_CKS_SRC_DOTCK0_4 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK0) / 4; break; case R_DEV_CKS_SRC_DOTCK0_7 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK0) / 7; break; case R_DEV_CKS_SRC_DOTCK1 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK1); break; case R_DEV_CKS_SRC_DOTCK1_4 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK1) / 4; break; case R_DEV_CKS_SRC_DOTCK1_7 : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_DOTCK1) / 7; break; case R_DEV_CKS_SRC_VI0CLK : freq = loc_Vdce0ViFreq; break; case R_DEV_CKS_SRC_VI0PIX : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_VI0CLK); break; case R_DEV_CKS_SRC_VI1PIX : freq = loc_Vdce1ViFreq; break; case R_DEV_CKS_SRC_MIPIPXL : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_MIPIPXL); break; case R_DEV_CKS_SRC_MIPIPLL : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_MIPIPLL); break; default: R_DEV_ERROR((uint32_t)ClkSrc, R_DEV_ERR_IDX, "Wrong ClockID!"); break; } return freq; } /******************************************************************************* Section: Global API Functions */ /******************************************************************************* Function: R_DEV_ClkGenActive see: <r_dev_api.h> for details */ uint8_t R_DEV_ClkGenActive(r_dev_ClkGen_t ClkGen) { uint32_t addr = 0; uint8_t ret_val = 0; if (ClkGen < R_DEV_CLK_GEN_NUM) { addr = loc_Base[ClkGen] + LOC_GEN_S; if (LOC_GEN_ACTIVE_MASK == (R_DEV_READ_REG(32, addr) & LOC_GEN_ACTIVE_MASK)) { ret_val = 1; } } else { R_DEV_ERROR((uint32_t)ClkGen, R_DEV_ERR_IDX, "Wrong clock generator selected!"); } return ret_val; } /******************************************************************************* Function: R_DEV_ClkIdSet see: <r_dev_api.h> for details */ r_Error_t R_DEV_ClkIdSet(const r_dev_ClkSelConfig_t * ClkSelCfg) { uint32_t sel_addr = 0; uint32_t div_addr = 0; uint16_t div_idx = 0; uint32_t reg_val = 0; r_Error_t ret_val = R_NG; uint8_t i = 0; uint16_t cks_sel = 0; uint16_t div_sel = 0; r_dev_Device_t device; r_dev_CksSrc_t pll_sub; r_dev_CksSrc_t clk_src; /* D1M1 translation */ /* Double substitution: 1. replace source selection Pll2 -> Pll1 2. replace allowed setting Pll2 -> Pll1 */ device = R_DEV_GetDev(); clk_src = ClkSelCfg->SrcId; /* 1. PLL2 -> Pll1 */ if (((device >= R_DEV_R7F701401) && (device <= R_DEV_R7F701407)) || (device == R_DEV_R7F701442) || (device == R_DEV_R7F701418)) { if (LOC_PLL2 == clk_src) { clk_src = LOC_PLL1; } } /* Check range */ if (ClkSelCfg->Cks < R_DEV_CKS_LAST) { sel_addr = loc_CkcsBaseAddr[ClkSelCfg->Cks].Sel; div_addr = loc_CkcsBaseAddr[ClkSelCfg->Cks].Div; div_idx = loc_CkcsBaseAddr[ClkSelCfg->Cks].DivIdx; } else { R_DEV_ERROR((uint32_t)ClkSelCfg->Cks, R_DEV_ERR_IDX, "Wrong clock domain selected!"); } /* Find the right ID setting */ for (i = 0; i < 8; i++) /* Search for the ID*/ { pll_sub = loc_ClockTree[ClkSelCfg->Cks][i]; if ( ( (device >= R_DEV_R7F701401) && (device <= R_DEV_R7F701407) ) || ( (device == R_DEV_R7F701442) || (device == R_DEV_R7F701418) ) ) { /* 2. replace allowed setting Pll2 -> Pll1 */ if (LOC_PLL2 == pll_sub) { pll_sub = LOC_PLL1; } } if (pll_sub == clk_src) { break; } } if (i < 8) /* we found a match */ { cks_sel = i; } else { R_DEV_ERROR((uint32_t)clk_src, R_DEV_ERR_IDX, "Bad clock config!"); } if (0 != div_addr) /* we do have a divider register */ { /* Find out what kind of divider we have */ /* Find the right Div setting */ /* Using cks_sel to access the loc_ClkSelDiv table is safe as long as we do not have more valid clock ids then divider ids */ if (LOC_F == loc_ClkSelDiv[div_idx][cks_sel]) { /* For the selected source the divider value is written directly to the register */ if (ClkSelCfg->Cks < R_DEV_CKS_AWO_LAST) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD0, div_addr, (uint32_t)ClkSelCfg->Div); } else if(div_addr >= LOC_CPUSS_CKS_BASE_ADDR) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD1, div_addr, (uint32_t)ClkSelCfg->Div); } else { R_DEV_WRITE_PROT_REG(LOC_PROTCMDD1, div_addr, (uint32_t)ClkSelCfg->Div); } div_sel = ClkSelCfg->Div; /* check setting */ if (0 == div_sel) /* Clock set to disabled */ { while (((R_DEV_READ_REG(32, div_addr + LOC_CKS_S) & 0x2ul) == 0x20ul)) { } } else /* clock src might be not set up yet, do not wait here for status active, will be checked later */ { } } else if (LOC_N == loc_ClkSelDiv[div_idx][cks_sel]) { /* For the selected clock source, there is no divider setting at all */ div_sel = LOC_N; } else /* all others dividers settings */ { for (i = 0; i < 8; i++) { if (loc_ClkSelDiv[div_idx][i] == (uint16_t) ClkSelCfg->Div) { break; } } if (i < 8) /* we found a match */ { /* Write ID */ if (ClkSelCfg->Cks < R_DEV_CKS_AWO_LAST) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD0, div_addr, (uint32_t)i); } else if(div_addr >= LOC_CPUSS_CKS_BASE_ADDR) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD1, div_addr, (uint32_t)i); } else { R_DEV_WRITE_PROT_REG(LOC_PROTCMDD1, div_addr, (uint32_t)i); } div_sel = i; } else { R_DEV_ERROR((uint32_t)ClkSelCfg->Div, R_DEV_ERR_RANGE, "Bad divider config!"); } /* in case of CPU, make sure to wait for the divider first */ if (R_DEV_CKS_CPU == ClkSelCfg->Cks) { while (R_DEV_READ_REG(32, div_addr + LOC_CKS_A) != (uint32_t)div_sel) { /* Wait for setting to become effective */ } } } } else /* if (0 != loc_CkcsBaseAddr[ClkSelCfg->Cks].Div) -> we do NOT have a divider */ { } /* check if we have an address or a direct source clock setting */ if (sel_addr > (uint32_t) R_DEV_CKS_SRC_LAST) { /* The address is valid */ /* Write ID */ if (ClkSelCfg->Cks < R_DEV_CKS_AWO_LAST) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD0, sel_addr, (uint32_t)cks_sel); } else if(sel_addr >= LOC_CPUSS_CKS_BASE_ADDR) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD1, sel_addr, (uint32_t)cks_sel); } else { R_DEV_WRITE_PROT_REG(LOC_PROTCMDD1, sel_addr, (uint32_t)cks_sel); } } /* Write stop request mask */ /* It is mandatory to set bit 1 in any case */ if (0 != ClkSelCfg->StpReqMsk) { reg_val = 0x3u; } else { reg_val = 0x2u; } /* Stop mask for AWO only */ if (ClkSelCfg->Cks < R_DEV_CKS_FOUT) { R_DEV_WRITE_REG(32, div_addr + LOC_CKS_STPMSK, reg_val); } else if (ClkSelCfg->Cks == R_DEV_CKS_FOUT) { R_DEV_WRITE_REG(32, sel_addr + LOC_CKS_STPMSK, reg_val); } else { /* nothing to do here */ } /* Now check the selector settings */ /* check if we have an address or a direct source clock setting If we have an address, there also exist a status register */ if (sel_addr > (uint32_t) R_DEV_CKS_SRC_LAST) { while (R_DEV_READ_REG(32, sel_addr + LOC_CKS_A) != cks_sel) {} } /* Now, check the divider */ if ((LOC_N != div_sel) && (0xFFu != div_idx) && (0 != div_sel)) { if (LOC_F != loc_ClkSelDiv[div_idx][cks_sel]) { while (R_DEV_READ_REG(32, div_addr + LOC_CKS_A) != (uint32_t)div_sel) { /* Wait for setting to become effective */ } } else { while (R_DEV_READ_REG(32, div_addr + LOC_CKS_S) != 0x3u) { } } } ret_val = R_ERR_OK; return ret_val; } /******************************************************************************* Function: R_DEV_FoutDivSet se: <r_dev_api.h> for details */ r_Error_t R_DEV_FoutDivSet(uint16_t Div) { r_Error_t ret_val = R_PARAMETER_RANGE; uint32_t addr; if (Div < 512) { addr = loc_CkcsBaseAddr[R_DEV_CKS_FOUT].Div; R_DEV_WRITE_REG(32, addr, Div); /* Wait for activation */ while (0 != R_DEV_READ_REG(32, addr + LOC_CKS_S)) {} ret_val = R_ERR_OK; } return ret_val; } /******************************************************************************* Function: R_DEV_ClkFrequencyHz see: <r_dev_api.h> for details */ uint32_t R_DEV_ClkFrequencyHz(r_dev_ClkSel_t ClkSel) { uint32_t sel_addr = 0; uint32_t div_addr = 0; uint8_t div_idx = 0; uint32_t reg_val = 0; uint8_t i = 0; r_dev_CksSrc_t cks_src = R_DEV_CKS_SRC_DISABLED; uint16_t cks_div = 0; uint32_t cks_act = 0; /* Some translation to get frequency for macros that do not allow configuration */ if (R_DEV_CKS_FIX_LOW == ClkSel) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_LRNG); return reg_val; } if (R_DEV_CKS_VI0PIX == ClkSel) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_VI0PIX); return reg_val; } if (R_DEV_CKS_VI1PIX == ClkSel) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_VI1PIX); return reg_val; } if (R_DEV_CKS_FIX_JIT == ClkSel) { ClkSel = R_DEV_CKS_CLKJIT; } /* now we can continue */ if (ClkSel < R_DEV_CKS_LAST) { sel_addr = loc_CkcsBaseAddr[ClkSel].Sel; div_addr = loc_CkcsBaseAddr[ClkSel].Div; div_idx = loc_CkcsBaseAddr[ClkSel].DivIdx; } else { R_DEV_ERROR((uint32_t)ClkSel, R_DEV_ERR_IDX, "Wrong clock domain selected!"); } if (sel_addr < (uint32_t) R_DEV_CKS_SRC_LAST) { /* There is no selector, the source clock is fixed */ /* But there is a divider for sure, and sel_addr is the R_DEV_CKS_SRC in this case */ cks_src = (r_dev_CksSrc_t)sel_addr; /* Get Frequency here, if result is 0, the Clock is inactive */ cks_act = loc_SrcFrequencyHz(cks_src); } else { reg_val = R_DEV_READ_REG(32, sel_addr); cks_src = loc_ClockTree[ClkSel][reg_val]; cks_act = R_DEV_READ_REG(32, sel_addr + LOC_CKS_A); } if (LOC_DIV == cks_src) { /* The source clock is not stored in the clock tree if the selection is like: use divider output or an internal OSC, here we have three "special" casess */ switch (ClkSel) { case R_DEV_CKS_CLKJIT: cks_src = R_DEV_CKS_SRC_PLL0; break; case R_DEV_CKS_CLKFIX: cks_src = R_DEV_CKS_SRC_PLLFIX; break; case R_DEV_CKS_PLL2IN: cks_src = R_DEV_CKS_SRC_PLL0; break; default: break; } cks_act = loc_SrcFrequencyHz(cks_src); } else { /* now the other way round, we need to check if the divider output is selected or a fixed clock (see PLL2In fro example - per selection we have divider output, or MOSC w/o divider */ switch (ClkSel) { case R_DEV_CKS_CLKJIT: case R_DEV_CKS_CLKFIX: case R_DEV_CKS_PLL2IN: /* The source clock was stored in the selector, and in this case the divider does not count */ div_addr = 0; break; default: break; } cks_act = loc_SrcFrequencyHz(cks_src); } /* Selected disabled clock or clock source inactive, we're done here */ if ((LOC_DIS == cks_src) || (0 == cks_act)) { /* Clock disabled */ return 0; } /* Get divider */ if (0 != div_addr) { for (i = 0; i < 8; i++ ) { if (LOC_F == loc_ClkSelDiv[div_idx][i]) { break; } } reg_val = R_DEV_READ_REG(32, div_addr); if (i < 8 ) { cks_div = reg_val; } else { cks_div = loc_ClkSelDiv[div_idx][reg_val]; } } else { cks_div = 1; } /* Divider disabled */ if (0 == cks_div) { /* Clock disabled */ reg_val = 0; } else { reg_val = loc_SrcFrequencyHz(cks_src) / cks_div; } return reg_val; } /******************************************************************************* Function: R_DEV_GetClkConfig see: <r_dev_api.h> for details */ uint32_t R_DEV_GetClkConfig(r_dev_ClkSelConfig_t *ClkData) { uint32_t sel_addr = 0; uint32_t div_addr = 0; uint8_t div_idx = 0; uint32_t reg_val = 0; uint8_t i = 0; r_dev_CksSrc_t cks_src = R_DEV_CKS_SRC_DISABLED; uint16_t cks_div = 0; uint32_t cks_act = 0; /* Just dummy */ ClkData->StpReqMsk = 0; /* Some translation to get frequency for macros that do not allow configuration */ if (R_DEV_CKS_FIX_LOW == ClkData->Cks) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_LRNG); ClkData->SrcId = R_DEV_CKS_SRC_LRNG; ClkData->Div = 1; return reg_val; } if (R_DEV_CKS_VI0PIX == ClkData->Cks) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_VI0PIX); ClkData->SrcId = R_DEV_CKS_SRC_VI0PIX; ClkData->Div = 1; return reg_val; } if (R_DEV_CKS_VI1PIX == ClkData->Cks) { reg_val = loc_SrcFrequencyHz(R_DEV_CKS_SRC_VI1PIX); ClkData->SrcId = R_DEV_CKS_SRC_VI1PIX; ClkData->Div = 1; return reg_val; } if (R_DEV_CKS_FIX_JIT == ClkData->Cks) { ClkData->Cks = R_DEV_CKS_CLKJIT; } /* now we can continue */ if (ClkData->Cks < R_DEV_CKS_LAST) { sel_addr = loc_CkcsBaseAddr[ClkData->Cks].Sel; div_addr = loc_CkcsBaseAddr[ClkData->Cks].Div; div_idx = loc_CkcsBaseAddr[ClkData->Cks].DivIdx; } else { R_DEV_ERROR((uint32_t)(ClkData->Cks), R_DEV_ERR_IDX, "Wrong clock domain selected!"); } if (sel_addr < (uint32_t) R_DEV_CKS_SRC_LAST) { /* There is no selector, the source clock is fixed */ /* But there is a divider for sure, and sel_addr is the R_DEV_CKS_SRC in this case */ cks_src = (r_dev_CksSrc_t)sel_addr; /* Get Frequency here, if result is 0, the Clock is inactive */ cks_act = loc_SrcFrequencyHz(cks_src); } else { reg_val = R_DEV_READ_REG(32, sel_addr); cks_src = loc_ClockTree[ClkData->Cks][reg_val]; cks_act = R_DEV_READ_REG(32, sel_addr + LOC_CKS_A); } if (LOC_DIV == cks_src) { /* The source clock is not stored in the clock tree if the selection is like: use divider output or an internal OSC, here we have three "special" casess */ switch (ClkData->Cks) { case R_DEV_CKS_CLKJIT: cks_src = R_DEV_CKS_SRC_PLL0; break; case R_DEV_CKS_CLKFIX: cks_src = R_DEV_CKS_SRC_PLLFIX; break; case R_DEV_CKS_PLL2IN: cks_src = R_DEV_CKS_SRC_PLL0; break; default: break; } cks_act = loc_SrcFrequencyHz(cks_src); } else { /* now the other way round, we need to check if the divider output is selected or a fixed clock (see PLL2In fro example - per selection we have divider output, or MOSC w/o divider */ switch (ClkData->Cks) { case R_DEV_CKS_CLKJIT: case R_DEV_CKS_CLKFIX: case R_DEV_CKS_PLL2IN: /* The source clock was stored in the selector, and in this case the divider does not count */ div_addr = 0; break; default: break; } cks_act = loc_SrcFrequencyHz(cks_src); } /* Selected disabled clock or clock source inactive, we're done here */ if ((LOC_DIS == cks_src) || (0 == cks_act)) { /* Clock disabled */ ClkData->SrcId = R_DEV_CKS_SRC_DISABLED; ClkData->Div = 0; /* Stop mask for AWO only */ if (ClkData->Cks < R_DEV_CKS_FOUT) { ClkData->StpReqMsk = R_DEV_READ_REG(32, div_addr + LOC_CKS_STPMSK); /* We just want the stop mask here */ ClkData->StpReqMsk &= 0x1u; } else if (ClkData->Cks == R_DEV_CKS_FOUT) { ClkData->StpReqMsk = R_DEV_READ_REG(32, sel_addr + LOC_CKS_STPMSK); /* We just want the stop mask here */ ClkData->StpReqMsk &= 0x1u; } else { /* nothing to do here */ ClkData->StpReqMsk = 0; } return 0; } /* Get divider */ if (0 != div_addr) { for (i = 0; i < 8; i++ ) { if (LOC_F == loc_ClkSelDiv[div_idx][i]) { break; } } reg_val = R_DEV_READ_REG(32, div_addr); if (i < 8 ) { cks_div = reg_val; } else { cks_div = loc_ClkSelDiv[div_idx][reg_val]; } } else { cks_div = 1; } /* Divider disabled */ if (0 == cks_div) { /* Clock disabled */ reg_val = 0; } else { reg_val = loc_SrcFrequencyHz(cks_src) / cks_div; } ClkData->SrcId = cks_src; ClkData->Div = cks_div; /* Stop mask for AWO only */ if (ClkData->Cks < R_DEV_CKS_FOUT) { ClkData->StpReqMsk = R_DEV_READ_REG(32, div_addr + LOC_CKS_STPMSK); /* We just want the stop mask here */ ClkData->StpReqMsk &= 0x1u; } else if (ClkData->Cks == R_DEV_CKS_FOUT) { ClkData->StpReqMsk = R_DEV_READ_REG(32, sel_addr + LOC_CKS_STPMSK); /* We just want the stop mask here */ ClkData->StpReqMsk &= 0x1u; } else { /* nothing to do here */ ClkData->StpReqMsk = 0; } return reg_val; } /******************************************************************************* Function: R_DEV_SetViClk0 se: <r_dev_clk_types.h> for details */ void R_DEV_SetViClk0(uint32_t Freq) { loc_Vdce0ViFreq = Freq; } /******************************************************************************* Function: R_DEV_SetViClk1 se: <r_dev_clk_types.h> for details */ void R_DEV_SetViClk1(uint32_t Freq) { loc_Vdce1ViFreq = Freq; } /******************************************************************************* Function: R_DEV_BusFrequencyHz se: <r_dev_api.h> for details */ uint32_t R_DEV_BusFrequencyHz(r_dev_Bus_t Bus) { uint32_t freq = 0; uint32_t ratio = 1; uint32_t check1, check2; r_dev_Device_t device; device = R_DEV_GetDev(); if (Bus < R_DEV_CLK_BUS_LAST) /* there is an enable setting */ { if (0 == R_DEV_READ_REG(32, locBusRegAddr[Bus]+ LOC_CKS_A)) { return 0; } } ratio = LocPbusRatio; switch (Bus) { case R_DEV_CLK_XCC : /* check if the XCC itself is "on"*/ if (0 != R_DEV_READ_REG(32, locBusRegAddr[R_DEV_CLK_XCC]+ LOC_CKS_A)) { freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / 2; } else { freq = 0; } break; case R_DEV_CLK_PLL0 : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL0); break; case R_DEV_CLK_PLL1 : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL1); break; case R_DEV_CLK_PLL2 : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL2); break; case R_DEV_CLK_PLL0PIX : freq = loc_ClkGenCfg.Pll[0].FrequencyHz; break; case R_DEV_CLK_SDRB : if (((device >= R_DEV_R7F701406) && (device <= R_DEV_R7F701407)) || (device == R_DEV_R7F701418) || (device == R_DEV_R7F701441)) { freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL0) / 2u; } else if ((device >= R_DEV_R7F701408) && (device <= R_DEV_R7F701412)) { freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL1); } else { freq = 0u; } break; case R_DEV_CLK_ETNBP : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / (2 * ratio) ; break; case R_DEV_CLK_ETNBXCC : /** hail to the MISRA god */ check1 = R_DEV_READ_REG(32, locBusRegAddr[R_DEV_CLK_ETNBXCC] + LOC_CKS_A); check2 = R_DEV_READ_REG(32, locBusRegAddr[R_DEV_CLK_XCC]+ LOC_CKS_A); /* check if the XCC itself is "on"*/ if ((0 != check1) || (0 != check2)) { freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / 2; } else { freq = 0; } break; case R_DEV_CLK_MLBP : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / (2 * ratio) ; break; case R_DEV_CLK_MLBXCC : /** hail to the MISRA god */ check1 = R_DEV_READ_REG(32, locBusRegAddr[R_DEV_CLK_MLBXCC] + LOC_CKS_A); check2 = R_DEV_READ_REG(32, locBusRegAddr[R_DEV_CLK_XCC]+ LOC_CKS_A); /* check if the XCC itself is "on"*/ if ((0 != check1) || (0 != check2)) /* check if the XCC itself is "on"*/ { freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / 2; } else { freq = 0; } break; case R_DEV_CLK_RSCANP : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / (2 * ratio) ; break; case R_DEV_CLK_CPU : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU); break; case R_DEV_CLK_GPU2D : if ((device >= R_DEV_R7F701408) && (device <= R_DEV_R7F701412)) { /* D1M2(H) run GPU2D clk same as CPU clk */ freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU); } else { /* D1M1(H) and D1M1A run GPU2D clk at half of CPU clk */ freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / 2; } break; case R_DEV_CLK_PLL1_INTERNAL: if (((device >= R_DEV_R7F701400) && (device <= R_DEV_R7F701407)) || (device == R_DEV_R7F701442) || (device == R_DEV_R7F701418) || (device == R_DEV_R7F701441)) { freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL1) * 1; } else { /* For D1M2(H), the PLL1 is always divided by 2, so this value is returned by */ /* loc_SrcFrequencyHz, as that function gives the frequency input into other macros. */ /* If we request the internal working frequency of PLL1, we have to double it up. */ freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_PLL1) * 2; } break; case R_DEV_CLK_ISOPCLK : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CPU) / (2 * ratio) ; break; case R_DEV_CLK_FIX : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKFIX); break; case R_DEV_CLK_JIT : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_CLKJIT); break; case R_DEV_CLK_PLLFIX : freq = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLLFIX); break; case R_DEV_CLK_LRNG : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_LRNG); break; case R_DEV_CLK_HRING : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_HRING); break; case R_DEV_CLK_ERING : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_ERING); break; case R_DEV_CLK_MOSC : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_MOSC); break; case R_DEV_CLK_SOSC : freq = loc_SrcFrequencyHz(R_DEV_CKS_SRC_SOSC); break; default : R_DEV_ERROR((uint32_t)Bus, R_DEV_ERR_UNIT, "Wher's the Bus!"); break; } return (freq); } /******************************************************************************* Function: R_DEV_BusEnable see: <r_dev_clk_types.h> for details */ r_Error_t R_DEV_BusEnable(r_dev_Bus_t BusClk, uint8_t EnDis) { uint32_t regval = 0; r_Error_t retval = R_ERR_OK; regval = (0 != EnDis)? 1:0; if (BusClk < R_DEV_CLK_BUS_LAST) { if (BusClk < R_DEV_CLK_PLL2) { R_DEV_WRITE_PROT_REG(LOC_PROTCMD1, locBusRegAddr[BusClk],regval); } else { R_DEV_WRITE_PROT_REG(LOC_PROTCMDD1, locBusRegAddr[BusClk],regval); } while (R_DEV_READ_REG(32, locBusRegAddr[BusClk]+ LOC_CKS_A) != regval) { /* Just wait until setting becomes active */ } } else { retval = R_PARAMETER_RANGE; } return retval; } /******************************************************************************* Function: R_DEV_ClkGenStop se: <r_dev_api.h> for details */ r_Error_t R_DEV_ClkGenStop(r_dev_ClkGen_t ClkGen) { uint32_t addr = loc_Base[ClkGen] + LOC_GEN_E; uint32_t reg_val = 0; uint32_t prot_addr = 0; r_Error_t ret_val = R_NG; switch (ClkGen) { case R_DEV_HS_RING: case R_DEV_MOSC: case R_DEV_SOSC: prot_addr = LOC_PROTCMD0; break; case R_DEV_PLL0: case R_DEV_PLL1: prot_addr = LOC_PROTCMD1; break; case R_DEV_PLL2: prot_addr = LOC_PROTCMDD1; break; default: ret_val = R_PARAMETER_RANGE; break; } if (R_PARAMETER_RANGE != ret_val) { /* now set stop trigger */ reg_val |= 0x2u; R_DEV_WRITE_PROT_REG(prot_addr, addr, reg_val); /* wait for status */ while (0 != R_DEV_ClkGenActive(ClkGen)) { } ret_val = R_ERR_OK; } return ret_val; } /******************************************************************************* Function: R_DEV_ClkGenStart se: <r_dev_api.h> for details */ r_Error_t R_DEV_ClkGenStart(r_dev_ClkGen_t ClkGen) { uint32_t addr = loc_Base[ClkGen] + LOC_GEN_E; uint32_t reg_val = 0; uint32_t prot_addr = 0; r_Error_t ret_val = R_NG; switch (ClkGen) { case R_DEV_HS_RING: case R_DEV_MOSC: case R_DEV_SOSC: prot_addr = LOC_PROTCMD0; break; case R_DEV_PLL0: case R_DEV_PLL1: prot_addr = LOC_PROTCMD1; break; case R_DEV_PLL2: prot_addr = LOC_PROTCMDD1; break; default: ret_val = R_PARAMETER_RANGE; break; } if (R_PARAMETER_RANGE != ret_val) { /* now set start trigger */ reg_val |= 0x1u; R_DEV_WRITE_PROT_REG(prot_addr, addr, reg_val); /* wait for status */ while (0 == R_DEV_ClkGenActive(ClkGen)) { } ret_val = R_ERR_OK; } return ret_val; } /******************************************************************************* Function: R_DEV_MoscCfg see: <r_dev_clk_types.h> for details */ r_Error_t R_DEV_MoscCfg(const r_dev_MoscCfg_t * ClkCfg) { uint32_t addr = 0 ; uint32_t reg_val = 0 ; r_Error_t ret_val = R_NG; /* We have to stop before the settings can be written */ if (0 != R_DEV_ClkGenActive(R_DEV_MOSC)) { R_DEV_ClkGenStop(R_DEV_MOSC); while (0 != R_DEV_ClkGenActive(R_DEV_MOSC)) { } } /* Stabi time: for X1X it's reg_val = (ClkCfg->StabiTimeNs * 8) / 1000 HS ring active: or = (ClkCfg->StabiTimeNs *24) / 100000 HS ring stopped : */ if (0 != R_DEV_ClkGenActive(R_DEV_HS_RING)) { reg_val = (ClkCfg->StabiTimeNs * 8u) / 1000u; } else { reg_val = (ClkCfg->StabiTimeNs * 24u) / 100000u; } addr = loc_Base[R_DEV_MOSC] + LOC_GEN_STABI; R_DEV_WRITE_REG(32, addr, reg_val); /* Gain: */ reg_val = ClkCfg->Gain; /* required setting according to UM */ reg_val |= 0x4u; addr = loc_Base[R_DEV_MOSC] + LOC_GEN_C; R_DEV_WRITE_REG(32, addr, reg_val); /* Check if register values fit */ if (R_DEV_READ_REG(32, addr) == reg_val) { /* Continue configuraton */ if (0 != ClkCfg->Running) { addr = loc_Base[R_DEV_MOSC] + LOC_GEN_E; R_DEV_WRITE_PROT_REG(LOC_PROTCMD0, addr, (uint32_t)1u); } /* It is mandatory to set bit 1 in any case */ if (0 != ClkCfg->StpReqMsk) { reg_val = 0x03u; } else { reg_val = 0x02u; } addr = loc_Base[R_DEV_MOSC] + LOC_GEN_STPMSK; R_DEV_WRITE_REG(32, addr, reg_val); /* Do not store the settings - this has to be done separately */ /* Proceed - wait for the setting to take effect */ R_DBG_PRINT(R_DBG_MSG_INFO, "Wait for setting to take effect"); while (R_DEV_ClkGenActive(R_DEV_MOSC) != ClkCfg->Running) { } ret_val = R_ERR_OK; } return ret_val; } /******************************************************************************* Function: R_DEV_SubOscCfg see: <r_dev_clk_types.h> for details */ r_Error_t R_DEV_SubOscCfg(const r_dev_SubOscCfg_t * ClkCfg) { uint32_t addr = 0 ; uint32_t reg_val = 0 ; r_Error_t ret_val = R_NG; addr = loc_Base[R_DEV_SOSC] + LOC_GEN_E; /* Do we have a status change? */ if (0u != ClkCfg->Running) { reg_val |= 0x01u; } else { reg_val |= 0x02u; } R_DEV_WRITE_PROT_REG(LOC_PROTCMD0, addr, reg_val); /* Do not store the settings - this has to be done separately */ /* Proceed - wait for the setting to take effect */ while (R_DEV_ClkGenActive(R_DEV_SOSC) != ClkCfg->Running) { } ret_val = R_ERR_OK; return ret_val; } /******************************************************************************* Function: R_DEV_SetGenStopMask se: <r_dev_api.h> for details */ r_Error_t R_DEV_SetGenStopMask(r_dev_ClkGen_t ClkGen, uint8_t Val) { uint32_t addr = 0 ; uint32_t reg_val = 0 ; r_Error_t ret_val = R_NG; addr = loc_Base[ClkGen] + LOC_GEN_STPMSK; switch (ClkGen) { case R_DEV_HS_RING: loc_ClkGenCfg.RoscStpReqMsk = Val; break; case R_DEV_MOSC: loc_ClkGenCfg.MainOsc.StpReqMsk = Val; break; default: ret_val = R_PARAMETER_RANGE; break; } if (R_PARAMETER_RANGE != ret_val) { if (0u != Val) { reg_val = LOC_STOP_MASKED_SET; } /* It is mandatory to set bit 1 in any case */ reg_val |= 0x2u; /* Write the value */ R_DEV_WRITE_REG(32, addr, reg_val); /* Check the value */ if ((R_DEV_READ_REG(32, addr) & (LOC_STOP_MASKED_SET | 0x2u)) == reg_val) { ret_val = R_ERR_OK; } } return ret_val; } /******************************************************************************* Function: R_DEV_ClkPllCfg se: <r_dev_clk_types.h> for details */ r_Error_t R_DEV_PllCfg(uint32_t FrqIn, r_dev_ClkGen_t Pll, const r_dev_PllCfg_t *PllCfg) { uint32_t freq_out = PllCfg->FrequencyHz/1000000u; r_Error_t ret_val = R_NG; uint32_t regval = 0; loc_PllCfgReg_t pllcfg_reg; /* This one is not needed here */ Pll = Pll; /* Clear Config */ pllcfg_reg.NI = 0; pllcfg_reg.P = 0; pllcfg_reg.M = 0; pllcfg_reg.NF = 0; pllcfg_reg.SSMode = 0; pllcfg_reg.SSPerc = 0; pllcfg_reg.SMFreq = 0; /* VC= freq = fin * Nr/Pr */ /* Set/Check the frequency */ switch (Pll) { case R_DEV_PLL0: ret_val = loc_CalcFreqPll0(FrqIn/1000000, &pllcfg_reg, &freq_out); if ((R_ERR_OK == ret_val) && (R_DEV_PLL_SSCG == PllCfg->Mode)) { /*The input frequency is provided in KHz here */ ret_val = loc_CalcSscgPll0(FrqIn/1000, &pllcfg_reg, PllCfg); } break; case R_DEV_PLL1: ret_val = loc_CalcFreqPll1(FrqIn/1000000, &pllcfg_reg, &freq_out); break; case R_DEV_PLL2 : /* First, get the input frquency */ regval = R_DEV_ClkFrequencyHz(R_DEV_CKS_PLL2IN); ret_val = loc_CalcFreqPll2(regval/1000000, &pllcfg_reg, &freq_out); pllcfg_reg.FVV = 0; /* Init value */ pllcfg_reg.NF = 1; break; default: ret_val = R_PARAMETER_RANGE; break; } /* If everything went smooth, store the values */ if (R_ERR_OK == ret_val) { /* Do NOT Store the config here, use the store function instead */ /* .bss area is not working */ /* Make sure that PLL is stopped */ if (0 != R_DEV_ClkGenActive(Pll)) { R_DEV_ClkGenStop(Pll); } loc_WritePllCfg(Pll, &pllcfg_reg); } return ret_val; } /******************************************************************************* Function: R_DEV_ClkPrepare se: <r_dev_api.h> for details */ void R_DEV_ClkPrepare(void) { /* Init Device Clocks */ loc_ClkGenCfg.MainOsc.FrequencyHz = 8000000; loc_ClkGenCfg.MainOsc.StabiTimeNs = 4000000; loc_ClkGenCfg.MainOsc.Gain = 3; loc_ClkGenCfg.MainOsc.Running = 0; loc_ClkGenCfg.MainOsc.StpReqMsk = 1; ; loc_ClkGenCfg.SubOsc.FrequencyHz = 32768; loc_ClkGenCfg.SubOsc.Running = 0; loc_ClkGenCfg.RoscStpReqMsk = 1; loc_ClkGenCfg.Pll[0].Mode = R_DEV_PLL_OFF; loc_ClkGenCfg.Pll[0].DithMode = R_DEV_PLL_DITH_CENTER; loc_ClkGenCfg.Pll[0].DithRange = 3; loc_ClkGenCfg.Pll[0].ModFreq = 50; loc_ClkGenCfg.Pll[0].FrequencyHz = 120000000; loc_ClkGenCfg.Pll[0].StabiTimeNs = 4000000; loc_ClkGenCfg.Pll[0].StpReqMsk =0; loc_ClkGenCfg.Pll[1].Mode = R_DEV_PLL_OFF; loc_ClkGenCfg.Pll[1].DithMode = R_DEV_PLL_DITH_FIXED; loc_ClkGenCfg.Pll[1].DithRange = 0; loc_ClkGenCfg.Pll[1].ModFreq = 0; loc_ClkGenCfg.Pll[1].FrequencyHz = 120000000; loc_ClkGenCfg.Pll[1].StabiTimeNs = 1000000; loc_ClkGenCfg.Pll[1].StpReqMsk = 0; loc_ClkGenCfg.Pll[2].Mode = R_DEV_PLL_OFF; loc_ClkGenCfg.Pll[2].DithMode = R_DEV_PLL_DITH_FIXED; loc_ClkGenCfg.Pll[2].DithRange = 0; loc_ClkGenCfg.Pll[2].ModFreq = 00; loc_ClkGenCfg.Pll[2].FrequencyHz = 120000000; loc_ClkGenCfg.Pll[2].StabiTimeNs = 1000000; loc_ClkGenCfg.Pll[2].StpReqMsk = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_XCC] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL0] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL1] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL2] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL0PIX] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_SDRB] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_ETNBP] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_ETNBXCC] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_MLBP] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_MLBXCC] = 0; loc_ClkGenCfg.BusEnable[R_DEV_CLK_RSCANP] = 0; } /******************************************************************************* Function: R_DEV_ClkGenInit se: <r_dev_api.h> for details */ void R_DEV_ClkGenInit(r_dev_ClkGenConfig_t * ClkGenCfg, const r_dev_ClkSelConfig_t * ClkSelCfg) { r_dev_ClkGen_t i; r_dev_Bus_t bus; uint32_t j = 0; r_dev_Device_t device; /* D1M1, D1M1-V2 PBUS divider */ device = R_DEV_GetDev(); if (((device >= R_DEV_R7F701404) && (device <= R_DEV_R7F701405)) || (device >= R_DEV_R7F701442)) { /* change PBUS divider (4-> 2) */ R_DEV_WRITE_PROT_REG(LOC_PROTCMDPWRGD, LOC_PBUS_RATIO, 0u); LocPbusRatio = 1; } if (0 == R_DEV_ClkGenActive(R_DEV_MOSC)) { R_DEV_MoscCfg(&(ClkGenCfg->MainOsc)); } R_DEV_SubOscCfg(&(ClkGenCfg->SubOsc)); /* Config and start PLL (but not yet PLL2) */ for (i = R_DEV_PLL0; i < R_DEV_PLL2; i++) { R_DEV_PllCfg(ClkGenCfg->MainOsc.FrequencyHz, i, &(ClkGenCfg->Pll[i])); if (R_DEV_PLL_OFF != ClkGenCfg->Pll[i].Mode) { R_DEV_ClkGenStart(i); } } /* Switch PLL buses (but not yet PLL2) */ for (bus = R_DEV_CLK_PLL0; bus < R_DEV_CLK_PLL2; bus++) { R_DEV_BusEnable(bus, ClkGenCfg->BusEnable[bus]); } /* First we need to configure the input selector for PLL2 */ j = 0; while (R_DEV_CKS_LAST != ClkSelCfg[j].Cks) { if (R_DEV_CKS_PLL2IN == ClkSelCfg[j].Cks) { R_DEV_ClkIdSet(&(ClkSelCfg[j])); break; } j++; } /* Now the PLL2 */ R_DEV_PllCfg(ClkGenCfg->MainOsc.FrequencyHz, R_DEV_PLL2, &(ClkGenCfg->Pll[R_DEV_PLL2])); if (R_DEV_PLL_OFF != ClkGenCfg->Pll[R_DEV_PLL2].Mode) { R_DEV_ClkGenStart(R_DEV_PLL2); } /* And finally its bus */ R_DEV_BusEnable(R_DEV_CLK_PLL2, ClkGenCfg->BusEnable[R_DEV_CLK_PLL2]); /* Last but not least, config all clock domians */ R_DEV_ClkSelection(ClkSelCfg); /* ... and switch remaining buses */ for (bus = R_DEV_CLK_PLL0PIX; bus < R_DEV_CLK_BUS_LAST; bus++) { R_DEV_BusEnable(bus, ClkGenCfg->BusEnable[bus]); } } /******************************************************************************* Function: R_DEV_ClkGenInitStore se: <r_dev_api.h> for details */ void R_DEV_ClkGenInitStore(r_dev_ClkGenConfig_t * ClkGenCfg) { r_dev_ClkGen_t i; r_dev_Device_t device; /* Just to be clean */ R_DEV_ClkPrepare(); loc_ClkGenCfg.MainOsc.FrequencyHz = ClkGenCfg->MainOsc.FrequencyHz ; loc_ClkGenCfg.MainOsc.StabiTimeNs = ClkGenCfg->MainOsc.StabiTimeNs ; loc_ClkGenCfg.MainOsc.Gain = ClkGenCfg->MainOsc.Gain ; loc_ClkGenCfg.MainOsc.Running = ClkGenCfg->MainOsc.Running ; loc_ClkGenCfg.MainOsc.StpReqMsk = ClkGenCfg->MainOsc.StpReqMsk ; loc_ClkGenCfg.SubOsc.FrequencyHz = ClkGenCfg->SubOsc.FrequencyHz ; loc_ClkGenCfg.SubOsc.Running = ClkGenCfg->SubOsc.Running ; loc_ClkGenCfg.RoscStpReqMsk = ClkGenCfg->RoscStpReqMsk; loc_ClkGenCfg.BusEnable[R_DEV_CLK_XCC] = ClkGenCfg->BusEnable[R_DEV_CLK_XCC] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL0] = ClkGenCfg->BusEnable[R_DEV_CLK_PLL0] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL1] = ClkGenCfg->BusEnable[R_DEV_CLK_PLL1] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL2] = ClkGenCfg->BusEnable[R_DEV_CLK_PLL2] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_PLL0PIX] = ClkGenCfg->BusEnable[R_DEV_CLK_PLL0PIX] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_SDRB] = ClkGenCfg->BusEnable[R_DEV_CLK_SDRB] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_ETNBP] = ClkGenCfg->BusEnable[R_DEV_CLK_ETNBP] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_ETNBXCC] = ClkGenCfg->BusEnable[R_DEV_CLK_ETNBXCC] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_MLBP] = ClkGenCfg->BusEnable[R_DEV_CLK_MLBP] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_MLBXCC] = ClkGenCfg->BusEnable[R_DEV_CLK_MLBXCC] ; loc_ClkGenCfg.BusEnable[R_DEV_CLK_RSCANP] = ClkGenCfg->BusEnable[R_DEV_CLK_RSCANP] ; R_DEV_SetGenStopMask(R_DEV_HS_RING, ClkGenCfg->RoscStpReqMsk); for (i = R_DEV_PLL0; i <= R_DEV_PLL2; i++) { loc_PllCfgStore(ClkGenCfg->MainOsc.FrequencyHz, i, &(ClkGenCfg->Pll[i])); } /*D1M1, D1M1-V2 PBUS divider */ device = R_DEV_GetDev(); if (((device >= R_DEV_R7F701404) && (device <= R_DEV_R7F701405)) || (device >= R_DEV_R7F701442)) { LocPbusRatio = 1; } else { LocPbusRatio = 2; } } /******************************************************************************* Function: R_DEV_ClkSelection se: <r_dev_api.h> for details */ void R_DEV_ClkSelection(const r_dev_ClkSelConfig_t * ClkSelCfg) { uint16_t i = 0; /* assuming we got a config table, we go through it until we see the delimiter */ while (R_DEV_CKS_LAST != ClkSelCfg[i].Cks) { R_DEV_ClkIdSet(&(ClkSelCfg[i])); i++; } }