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