//--- // gint:clock:freq - Clock frequency management //--- #include #include #include #include #include //--- // Driver storage //--- /* Local copy of the CPG settings */ GBSS static clock_frequency_t freq; /* clock_freq() - get the frequency of the main clocks */ const clock_frequency_t *clock_freq(void) { return &freq; } //--- // SH7705 Clock signals //--- #ifdef FX9860G #define CPG SH7705_CPG static void sh7705_probe(void) { /* According to Sentaro21 in the sources of Ftune 1.0.1, the clock mode is thought to be 5, which means that: - CPG input is XTAL (14.745'600 MHz) - PLL2 is active and *2 (29.491'200 MHz) - CKIO is output from PLL2 (29.491'200 MHz) */ int xtal = 14745600; int pll2 = 2; int ckio = xtal * pll2; /* This signal is multiplied by the PLL1 circuit */ int pll1 = CPG.FRQCR.STC + 1; /* Iphi and Pphi have dividers (Bphi is always equal to CKIO) */ int idiv = CPG.FRQCR.IFC; int pdiv = CPG.FRQCR.PFC; /* Fill in the setting structure */ freq.PLL1 = pll1; freq.PLL2 = pll2; freq.Bphi_div = 1; freq.Iphi_div = idiv + 1; freq.Pphi_div = pdiv + 1; /* Deduce the frequency of the main clocks. This value is ckio/3 */ int ckio_3 = 9830400; /* Exchange the setting values 2 and 3 */ idiv = idiv ^ (idiv >> 1); pdiv = pdiv ^ (pdiv >> 1); freq.CKIO_f = ckio; freq.Bphi_f = ckio; freq.Iphi_f = (idiv == 3) ? ckio_3 : ckio >> idiv; freq.Pphi_f = (pdiv == 3) ? ckio_3 : ckio >> pdiv; } #undef CPG #endif /* FX9860G */ //--- // SH7305 clock signals //--- #define CPG SH7305_CPG static void sh7305_probe(void) { /* The meaning of the PLL setting on SH7305 differs from the documentation of SH7224; the value must not be doubled. */ int pll = CPG.FRQCRA.STC + 1; freq.PLL = pll; /* The FLL ratio is the value of the setting, halved if SELXM=1 */ int fll = CPG.FLLFRQ.FLF; if(CPG.FLLFRQ.SELXM == 1) fll >>= 1; freq.FLL = fll; /* On SH7724, the divider ratio is given by 1 / (setting + 1), but SH7305 behaves as 1 / (2^setting + 1). */ int divb = CPG.FRQCRA.BFC; int divi = CPG.FRQCRA.IFC; int divp = CPG.FRQCRA.P1FC; freq.Bphi_div = 1 << (divb + 1); freq.Iphi_div = 1 << (divi + 1); freq.Pphi_div = 1 << (divp + 1); /* Deduce the input frequency of divider 1 */ int base = 32768; if(CPG.PLLCR.FLLE) base *= fll; if(CPG.PLLCR.PLLE) base *= pll; /* And the frequency of all other input clocks */ freq.RTCCLK_f = 32768; freq.Bphi_f = base >> (divb + 1); freq.Iphi_f = base >> (divi + 1); freq.Pphi_f = base >> (divp + 1); } #undef CPG //--- // Other driver stuff //--- #ifdef GINT_BOOT_LOG static const char *cpg_status(void) { static char status[18]; sprintf(status, "I%3d B%3d P%3d C%c", freq.Iphi_f / 1000000, freq.Bphi_f / 1000000, freq.Pphi_f / 1000000, isSH3() ? 'e' : 'E' ); return status; } #endif /* GINT_BOOT_LOG */ static void init(void) { /* This avoids warnings about sh7705() not being defined on fxcg50 */ #ifdef FX9860G isSH3() ? sh7705_probe() : #endif sh7305_probe(); } gint_driver_t drv_cpg = { .name = "CPG", .init = init, .status = GINT_DRIVER_STATUS(cpg_status), .ctx_size = 0, .sys_ctx = NULL, .ctx_save = NULL, .ctx_restore = NULL, }; GINT_DECLARE_DRIVER(1, drv_cpg);