Alternative library and kernel for add-in development on fx-9860G and fx-CG50 under Linux.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
gint/src/cpg/cpg.c

163 lines
3.5 KiB

//---
// gint:clock:freq - Clock frequency management
//---
#include <gint/drivers.h>
#include <gint/clock.h>
#include <gint/hardware.h>
#include <gint/mpu/cpg.h>
//---
// 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
//---
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
#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;
gint[HWCPG] |= HWCPG_COMP;
}
#undef CPG
#endif /* FX9860G and platform-agnostic */
//---
// 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);
gint[HWCPG] |= HWCPG_COMP | HWCPG_EXT;
}
#undef CPG
//---
// Other driver stuff
//---
#ifdef GINT_BOOT_LOG
#include <gint/std/stdio.h>
static const char *cpg_status(void)
{
static char status[18];
sprintf(status, "I%03d B%03d P%03d 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)
{
gint[HWCPG] = HW_LOADED;
/* This avoids warnings about sh7705_probe() being undefined when
building for fxcg50 */
#if defined(FX9860G) || (!defined(FX9860G) && !defined(FXCG50))
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);