1e28bee8eSPaolo Bonzini /* 2e28bee8eSPaolo Bonzini * IMX31 Clock Control Module 3e28bee8eSPaolo Bonzini * 4e28bee8eSPaolo Bonzini * Copyright (C) 2012 NICTA 5*282e74c8SJean-Christophe Dubois * Updated by Jean-Christophe Dubois <jcd@tribudubois.net> 6e28bee8eSPaolo Bonzini * 7e28bee8eSPaolo Bonzini * This work is licensed under the terms of the GNU GPL, version 2 or later. 8e28bee8eSPaolo Bonzini * See the COPYING file in the top-level directory. 9e28bee8eSPaolo Bonzini * 10e28bee8eSPaolo Bonzini * To get the timer frequencies right, we need to emulate at least part of 11e28bee8eSPaolo Bonzini * the CCM. 12e28bee8eSPaolo Bonzini */ 13e28bee8eSPaolo Bonzini 14*282e74c8SJean-Christophe Dubois #include "hw/misc/imx_ccm.h" 15e28bee8eSPaolo Bonzini 16e28bee8eSPaolo Bonzini #define CKIH_FREQ 26000000 /* 26MHz crystal input */ 17e28bee8eSPaolo Bonzini #define CKIL_FREQ 32768 /* nominal 32khz clock */ 18e28bee8eSPaolo Bonzini 19e28bee8eSPaolo Bonzini 20e28bee8eSPaolo Bonzini //#define DEBUG_CCM 1 21e28bee8eSPaolo Bonzini #ifdef DEBUG_CCM 22e28bee8eSPaolo Bonzini #define DPRINTF(fmt, args...) \ 23e28bee8eSPaolo Bonzini do { printf("imx_ccm: " fmt , ##args); } while (0) 24e28bee8eSPaolo Bonzini #else 25e28bee8eSPaolo Bonzini #define DPRINTF(fmt, args...) do {} while (0) 26e28bee8eSPaolo Bonzini #endif 27e28bee8eSPaolo Bonzini 28e28bee8eSPaolo Bonzini static int imx_ccm_post_load(void *opaque, int version_id); 29e28bee8eSPaolo Bonzini 30e28bee8eSPaolo Bonzini static const VMStateDescription vmstate_imx_ccm = { 31e28bee8eSPaolo Bonzini .name = "imx-ccm", 32e28bee8eSPaolo Bonzini .version_id = 1, 33e28bee8eSPaolo Bonzini .minimum_version_id = 1, 34e28bee8eSPaolo Bonzini .fields = (VMStateField[]) { 35e28bee8eSPaolo Bonzini VMSTATE_UINT32(ccmr, IMXCCMState), 36e28bee8eSPaolo Bonzini VMSTATE_UINT32(pdr0, IMXCCMState), 37e28bee8eSPaolo Bonzini VMSTATE_UINT32(pdr1, IMXCCMState), 38e28bee8eSPaolo Bonzini VMSTATE_UINT32(mpctl, IMXCCMState), 39e28bee8eSPaolo Bonzini VMSTATE_UINT32(spctl, IMXCCMState), 40e28bee8eSPaolo Bonzini VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3), 41e28bee8eSPaolo Bonzini VMSTATE_UINT32(pmcr0, IMXCCMState), 42e28bee8eSPaolo Bonzini VMSTATE_UINT32(pmcr1, IMXCCMState), 43e28bee8eSPaolo Bonzini VMSTATE_UINT32(pll_refclk_freq, IMXCCMState), 44ef493d5cSPeter Maydell VMSTATE_END_OF_LIST() 45e28bee8eSPaolo Bonzini }, 46e28bee8eSPaolo Bonzini .post_load = imx_ccm_post_load, 47e28bee8eSPaolo Bonzini }; 48e28bee8eSPaolo Bonzini 49e28bee8eSPaolo Bonzini uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock) 50e28bee8eSPaolo Bonzini { 51bcb34c7aSAndreas Färber IMXCCMState *s = IMX_CCM(dev); 52e28bee8eSPaolo Bonzini 53e28bee8eSPaolo Bonzini switch (clock) { 54e28bee8eSPaolo Bonzini case NOCLK: 55e28bee8eSPaolo Bonzini return 0; 56e28bee8eSPaolo Bonzini case MCU: 57e28bee8eSPaolo Bonzini return s->mcu_clk_freq; 58e28bee8eSPaolo Bonzini case HSP: 59e28bee8eSPaolo Bonzini return s->hsp_clk_freq; 60e28bee8eSPaolo Bonzini case IPG: 61e28bee8eSPaolo Bonzini return s->ipg_clk_freq; 62e28bee8eSPaolo Bonzini case CLK_32k: 63e28bee8eSPaolo Bonzini return CKIL_FREQ; 64e28bee8eSPaolo Bonzini } 65e28bee8eSPaolo Bonzini return 0; 66e28bee8eSPaolo Bonzini } 67e28bee8eSPaolo Bonzini 68e28bee8eSPaolo Bonzini /* 69e28bee8eSPaolo Bonzini * Calculate PLL output frequency 70e28bee8eSPaolo Bonzini */ 71e28bee8eSPaolo Bonzini static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq) 72e28bee8eSPaolo Bonzini { 73e28bee8eSPaolo Bonzini int32_t mfn = MFN(pllreg); /* Numerator */ 74e28bee8eSPaolo Bonzini uint32_t mfi = MFI(pllreg); /* Integer part */ 75e28bee8eSPaolo Bonzini uint32_t mfd = 1 + MFD(pllreg); /* Denominator */ 76e28bee8eSPaolo Bonzini uint32_t pd = 1 + PD(pllreg); /* Pre-divider */ 77e28bee8eSPaolo Bonzini 78e28bee8eSPaolo Bonzini if (mfi < 5) { 79e28bee8eSPaolo Bonzini mfi = 5; 80e28bee8eSPaolo Bonzini } 81e28bee8eSPaolo Bonzini /* mfn is 10-bit signed twos-complement */ 82e28bee8eSPaolo Bonzini mfn <<= 32 - 10; 83e28bee8eSPaolo Bonzini mfn >>= 32 - 10; 84e28bee8eSPaolo Bonzini 85e28bee8eSPaolo Bonzini return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) / 86e28bee8eSPaolo Bonzini (mfd * pd)) << 10; 87e28bee8eSPaolo Bonzini } 88e28bee8eSPaolo Bonzini 89e28bee8eSPaolo Bonzini static void update_clocks(IMXCCMState *s) 90e28bee8eSPaolo Bonzini { 91e28bee8eSPaolo Bonzini /* 92e28bee8eSPaolo Bonzini * If we ever emulate more clocks, this should switch to a data-driven 93e28bee8eSPaolo Bonzini * approach 94e28bee8eSPaolo Bonzini */ 95e28bee8eSPaolo Bonzini 96f3c8fac2SStefan Weil if ((s->ccmr & CCMR_PRCS) == 2) { 97e28bee8eSPaolo Bonzini s->pll_refclk_freq = CKIL_FREQ * 1024; 98e28bee8eSPaolo Bonzini } else { 99e28bee8eSPaolo Bonzini s->pll_refclk_freq = CKIH_FREQ; 100e28bee8eSPaolo Bonzini } 101e28bee8eSPaolo Bonzini 102e28bee8eSPaolo Bonzini /* ipg_clk_arm aka MCU clock */ 103e28bee8eSPaolo Bonzini if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) { 104e28bee8eSPaolo Bonzini s->mcu_clk_freq = s->pll_refclk_freq; 105e28bee8eSPaolo Bonzini } else { 106e28bee8eSPaolo Bonzini s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq); 107e28bee8eSPaolo Bonzini } 108e28bee8eSPaolo Bonzini 109e28bee8eSPaolo Bonzini /* High-speed clock */ 110e28bee8eSPaolo Bonzini s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP)); 111e28bee8eSPaolo Bonzini s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG)); 112e28bee8eSPaolo Bonzini 113e28bee8eSPaolo Bonzini DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n", 114e28bee8eSPaolo Bonzini s->mcu_clk_freq / 1000000, 115e28bee8eSPaolo Bonzini s->hsp_clk_freq / 1000000, 116e28bee8eSPaolo Bonzini s->ipg_clk_freq); 117e28bee8eSPaolo Bonzini } 118e28bee8eSPaolo Bonzini 119e28bee8eSPaolo Bonzini static void imx_ccm_reset(DeviceState *dev) 120e28bee8eSPaolo Bonzini { 121bcb34c7aSAndreas Färber IMXCCMState *s = IMX_CCM(dev); 122e28bee8eSPaolo Bonzini 123e28bee8eSPaolo Bonzini s->ccmr = 0x074b0b7b; 124e28bee8eSPaolo Bonzini s->pdr0 = 0xff870b48; 125e28bee8eSPaolo Bonzini s->pdr1 = 0x49fcfe7f; 126e28bee8eSPaolo Bonzini s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0); 127e28bee8eSPaolo Bonzini s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff; 128e28bee8eSPaolo Bonzini s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1); 129e28bee8eSPaolo Bonzini s->pmcr0 = 0x80209828; 130e28bee8eSPaolo Bonzini 131e28bee8eSPaolo Bonzini update_clocks(s); 132e28bee8eSPaolo Bonzini } 133e28bee8eSPaolo Bonzini 134e28bee8eSPaolo Bonzini static uint64_t imx_ccm_read(void *opaque, hwaddr offset, 135e28bee8eSPaolo Bonzini unsigned size) 136e28bee8eSPaolo Bonzini { 137e28bee8eSPaolo Bonzini IMXCCMState *s = (IMXCCMState *)opaque; 138e28bee8eSPaolo Bonzini 139e28bee8eSPaolo Bonzini DPRINTF("read(offset=%x)", offset >> 2); 140e28bee8eSPaolo Bonzini switch (offset >> 2) { 141e28bee8eSPaolo Bonzini case 0: /* CCMR */ 142e28bee8eSPaolo Bonzini DPRINTF(" ccmr = 0x%x\n", s->ccmr); 143e28bee8eSPaolo Bonzini return s->ccmr; 144e28bee8eSPaolo Bonzini case 1: 145e28bee8eSPaolo Bonzini DPRINTF(" pdr0 = 0x%x\n", s->pdr0); 146e28bee8eSPaolo Bonzini return s->pdr0; 147e28bee8eSPaolo Bonzini case 2: 148e28bee8eSPaolo Bonzini DPRINTF(" pdr1 = 0x%x\n", s->pdr1); 149e28bee8eSPaolo Bonzini return s->pdr1; 150e28bee8eSPaolo Bonzini case 4: 151e28bee8eSPaolo Bonzini DPRINTF(" mpctl = 0x%x\n", s->mpctl); 152e28bee8eSPaolo Bonzini return s->mpctl; 153e28bee8eSPaolo Bonzini case 6: 154e28bee8eSPaolo Bonzini DPRINTF(" spctl = 0x%x\n", s->spctl); 155e28bee8eSPaolo Bonzini return s->spctl; 156e28bee8eSPaolo Bonzini case 8: 157e28bee8eSPaolo Bonzini DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]); 158e28bee8eSPaolo Bonzini return s->cgr[0]; 159e28bee8eSPaolo Bonzini case 9: 160e28bee8eSPaolo Bonzini DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]); 161e28bee8eSPaolo Bonzini return s->cgr[1]; 162e28bee8eSPaolo Bonzini case 10: 163e28bee8eSPaolo Bonzini DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]); 164e28bee8eSPaolo Bonzini return s->cgr[2]; 165e28bee8eSPaolo Bonzini case 18: /* LTR1 */ 166e28bee8eSPaolo Bonzini return 0x00004040; 167e28bee8eSPaolo Bonzini case 23: 168e28bee8eSPaolo Bonzini DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0); 169e28bee8eSPaolo Bonzini return s->pmcr0; 170e28bee8eSPaolo Bonzini } 171e28bee8eSPaolo Bonzini DPRINTF(" return 0\n"); 172e28bee8eSPaolo Bonzini return 0; 173e28bee8eSPaolo Bonzini } 174e28bee8eSPaolo Bonzini 175e28bee8eSPaolo Bonzini static void imx_ccm_write(void *opaque, hwaddr offset, 176e28bee8eSPaolo Bonzini uint64_t value, unsigned size) 177e28bee8eSPaolo Bonzini { 178e28bee8eSPaolo Bonzini IMXCCMState *s = (IMXCCMState *)opaque; 179e28bee8eSPaolo Bonzini 180e28bee8eSPaolo Bonzini DPRINTF("write(offset=%x, value = %x)\n", 181e28bee8eSPaolo Bonzini offset >> 2, (unsigned int)value); 182e28bee8eSPaolo Bonzini switch (offset >> 2) { 183e28bee8eSPaolo Bonzini case 0: 184e28bee8eSPaolo Bonzini s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff); 185e28bee8eSPaolo Bonzini break; 186e28bee8eSPaolo Bonzini case 1: 187e28bee8eSPaolo Bonzini s->pdr0 = value & 0xff9f3fff; 188e28bee8eSPaolo Bonzini break; 189e28bee8eSPaolo Bonzini case 2: 190e28bee8eSPaolo Bonzini s->pdr1 = value; 191e28bee8eSPaolo Bonzini break; 192e28bee8eSPaolo Bonzini case 4: 193e28bee8eSPaolo Bonzini s->mpctl = value & 0xbfff3fff; 194e28bee8eSPaolo Bonzini break; 195e28bee8eSPaolo Bonzini case 6: 196e28bee8eSPaolo Bonzini s->spctl = value & 0xbfff3fff; 197e28bee8eSPaolo Bonzini break; 198e28bee8eSPaolo Bonzini case 8: 199e28bee8eSPaolo Bonzini s->cgr[0] = value; 200e28bee8eSPaolo Bonzini return; 201e28bee8eSPaolo Bonzini case 9: 202e28bee8eSPaolo Bonzini s->cgr[1] = value; 203e28bee8eSPaolo Bonzini return; 204e28bee8eSPaolo Bonzini case 10: 205e28bee8eSPaolo Bonzini s->cgr[2] = value; 206e28bee8eSPaolo Bonzini return; 207e28bee8eSPaolo Bonzini 208e28bee8eSPaolo Bonzini default: 209e28bee8eSPaolo Bonzini return; 210e28bee8eSPaolo Bonzini } 211e28bee8eSPaolo Bonzini update_clocks(s); 212e28bee8eSPaolo Bonzini } 213e28bee8eSPaolo Bonzini 214e28bee8eSPaolo Bonzini static const struct MemoryRegionOps imx_ccm_ops = { 215e28bee8eSPaolo Bonzini .read = imx_ccm_read, 216e28bee8eSPaolo Bonzini .write = imx_ccm_write, 217e28bee8eSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN, 218e28bee8eSPaolo Bonzini }; 219e28bee8eSPaolo Bonzini 220e28bee8eSPaolo Bonzini static int imx_ccm_init(SysBusDevice *dev) 221e28bee8eSPaolo Bonzini { 222bcb34c7aSAndreas Färber IMXCCMState *s = IMX_CCM(dev); 223e28bee8eSPaolo Bonzini 2243c161542SPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s, 225*282e74c8SJean-Christophe Dubois TYPE_IMX_CCM, 0x1000); 226e28bee8eSPaolo Bonzini sysbus_init_mmio(dev, &s->iomem); 227e28bee8eSPaolo Bonzini 228e28bee8eSPaolo Bonzini return 0; 229e28bee8eSPaolo Bonzini } 230e28bee8eSPaolo Bonzini 231e28bee8eSPaolo Bonzini static int imx_ccm_post_load(void *opaque, int version_id) 232e28bee8eSPaolo Bonzini { 233e28bee8eSPaolo Bonzini IMXCCMState *s = (IMXCCMState *)opaque; 234e28bee8eSPaolo Bonzini 235e28bee8eSPaolo Bonzini update_clocks(s); 236e28bee8eSPaolo Bonzini return 0; 237e28bee8eSPaolo Bonzini } 238e28bee8eSPaolo Bonzini 239e28bee8eSPaolo Bonzini static void imx_ccm_class_init(ObjectClass *klass, void *data) 240e28bee8eSPaolo Bonzini { 241e28bee8eSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 242e28bee8eSPaolo Bonzini SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 243e28bee8eSPaolo Bonzini 244e28bee8eSPaolo Bonzini sbc->init = imx_ccm_init; 245e28bee8eSPaolo Bonzini dc->reset = imx_ccm_reset; 246e28bee8eSPaolo Bonzini dc->vmsd = &vmstate_imx_ccm; 247e28bee8eSPaolo Bonzini dc->desc = "i.MX Clock Control Module"; 248e28bee8eSPaolo Bonzini } 249e28bee8eSPaolo Bonzini 250e28bee8eSPaolo Bonzini static const TypeInfo imx_ccm_info = { 251bcb34c7aSAndreas Färber .name = TYPE_IMX_CCM, 252e28bee8eSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 253e28bee8eSPaolo Bonzini .instance_size = sizeof(IMXCCMState), 254e28bee8eSPaolo Bonzini .class_init = imx_ccm_class_init, 255e28bee8eSPaolo Bonzini }; 256e28bee8eSPaolo Bonzini 257e28bee8eSPaolo Bonzini static void imx_ccm_register_types(void) 258e28bee8eSPaolo Bonzini { 259e28bee8eSPaolo Bonzini type_register_static(&imx_ccm_info); 260e28bee8eSPaolo Bonzini } 261e28bee8eSPaolo Bonzini 262e28bee8eSPaolo Bonzini type_init(imx_ccm_register_types) 263