diff options
Diffstat (limited to 'hw/misc/imx_ccm.c')
-rw-r--r-- | hw/misc/imx_ccm.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c new file mode 100644 index 000000000..9403c5daa --- /dev/null +++ b/hw/misc/imx_ccm.c @@ -0,0 +1,86 @@ +/* + * IMX31 Clock Control Module + * + * Copyright (C) 2012 NICTA + * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * This is an abstract base class used to get a common interface to + * retrieve the CCM frequencies from the various i.MX SOC. + */ + +#include "qemu/osdep.h" +#include "hw/misc/imx_ccm.h" +#include "qemu/module.h" + +#ifndef DEBUG_IMX_CCM +#define DEBUG_IMX_CCM 0 +#endif + +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_CCM) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \ + __func__, ##args); \ + } \ + } while (0) + + +uint32_t imx_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) +{ + uint32_t freq = 0; + IMXCCMClass *klass = IMX_CCM_GET_CLASS(dev); + + if (klass->get_clock_frequency) { + freq = klass->get_clock_frequency(dev, clock); + } + + DPRINTF("(clock = %d) = %u\n", clock, freq); + + return freq; +} + +/* + * Calculate PLL output frequency + */ +uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq) +{ + int32_t freq; + int32_t mfn = MFN(pllreg); /* Numerator */ + uint32_t mfi = MFI(pllreg); /* Integer part */ + uint32_t mfd = 1 + MFD(pllreg); /* Denominator */ + uint32_t pd = 1 + PD(pllreg); /* Pre-divider */ + + if (mfi < 5) { + mfi = 5; + } + + /* mfn is 10-bit signed twos-complement */ + mfn <<= 32 - 10; + mfn >>= 32 - 10; + + freq = ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) / + (mfd * pd)) << 10; + + DPRINTF("(pllreg = 0x%08x, base_freq = %u) = %d\n", pllreg, base_freq, + freq); + + return freq; +} + +static const TypeInfo imx_ccm_info = { + .name = TYPE_IMX_CCM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IMXCCMState), + .class_size = sizeof(IMXCCMClass), + .abstract = true, +}; + +static void imx_ccm_register_types(void) +{ + type_register_static(&imx_ccm_info); +} + +type_init(imx_ccm_register_types) |