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