qemu/hw/misc/imx31_ccm.c
<<
>>
Prefs
   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 i.MX31 CCM.
  12 */
  13
  14#include "qemu/osdep.h"
  15#include "hw/misc/imx31_ccm.h"
  16#include "qemu/log.h"
  17
  18#define CKIH_FREQ 26000000 /* 26MHz crystal input */
  19
  20#ifndef DEBUG_IMX31_CCM
  21#define DEBUG_IMX31_CCM 0
  22#endif
  23
  24#define DPRINTF(fmt, args...) \
  25    do { \
  26        if (DEBUG_IMX31_CCM) { \
  27            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \
  28                                             __func__, ##args); \
  29        } \
  30    } while (0)
  31
  32static const char *imx31_ccm_reg_name(uint32_t reg)
  33{
  34    static char unknown[20];
  35
  36    switch (reg) {
  37    case IMX31_CCM_CCMR_REG:
  38        return "CCMR";
  39    case IMX31_CCM_PDR0_REG:
  40        return "PDR0";
  41    case IMX31_CCM_PDR1_REG:
  42        return "PDR1";
  43    case IMX31_CCM_RCSR_REG:
  44        return "RCSR";
  45    case IMX31_CCM_MPCTL_REG:
  46        return "MPCTL";
  47    case IMX31_CCM_UPCTL_REG:
  48        return "UPCTL";
  49    case IMX31_CCM_SPCTL_REG:
  50        return "SPCTL";
  51    case IMX31_CCM_COSR_REG:
  52        return "COSR";
  53    case IMX31_CCM_CGR0_REG:
  54        return "CGR0";
  55    case IMX31_CCM_CGR1_REG:
  56        return "CGR1";
  57    case IMX31_CCM_CGR2_REG:
  58        return "CGR2";
  59    case IMX31_CCM_WIMR_REG:
  60        return "WIMR";
  61    case IMX31_CCM_LDC_REG:
  62        return "LDC";
  63    case IMX31_CCM_DCVR0_REG:
  64        return "DCVR0";
  65    case IMX31_CCM_DCVR1_REG:
  66        return "DCVR1";
  67    case IMX31_CCM_DCVR2_REG:
  68        return "DCVR2";
  69    case IMX31_CCM_DCVR3_REG:
  70        return "DCVR3";
  71    case IMX31_CCM_LTR0_REG:
  72        return "LTR0";
  73    case IMX31_CCM_LTR1_REG:
  74        return "LTR1";
  75    case IMX31_CCM_LTR2_REG:
  76        return "LTR2";
  77    case IMX31_CCM_LTR3_REG:
  78        return "LTR3";
  79    case IMX31_CCM_LTBR0_REG:
  80        return "LTBR0";
  81    case IMX31_CCM_LTBR1_REG:
  82        return "LTBR1";
  83    case IMX31_CCM_PMCR0_REG:
  84        return "PMCR0";
  85    case IMX31_CCM_PMCR1_REG:
  86        return "PMCR1";
  87    case IMX31_CCM_PDR2_REG:
  88        return "PDR2";
  89    default:
  90        sprintf(unknown, "[%d ?]", reg);
  91        return unknown;
  92    }
  93}
  94
  95static const VMStateDescription vmstate_imx31_ccm = {
  96    .name = TYPE_IMX31_CCM,
  97    .version_id = 2,
  98    .minimum_version_id = 2,
  99    .fields = (VMStateField[]) {
 100        VMSTATE_UINT32_ARRAY(reg, IMX31CCMState, IMX31_CCM_MAX_REG),
 101        VMSTATE_END_OF_LIST()
 102    },
 103};
 104
 105static uint32_t imx31_ccm_get_pll_ref_clk(IMXCCMState *dev)
 106{
 107    uint32_t freq = 0;
 108    IMX31CCMState *s = IMX31_CCM(dev);
 109
 110    if ((s->reg[IMX31_CCM_CCMR_REG] & CCMR_PRCS) == 2) {
 111        if (s->reg[IMX31_CCM_CCMR_REG] & CCMR_FPME) {
 112            freq = CKIL_FREQ;
 113            if (s->reg[IMX31_CCM_CCMR_REG] & CCMR_FPMF) {
 114                freq *= 1024;
 115            }
 116        } 
 117    } else {
 118        freq = CKIH_FREQ;
 119    }
 120
 121    DPRINTF("freq = %d\n", freq);
 122
 123    return freq;
 124}
 125
 126static uint32_t imx31_ccm_get_mpll_clk(IMXCCMState *dev)
 127{
 128    uint32_t freq;
 129    IMX31CCMState *s = IMX31_CCM(dev);
 130
 131    freq = imx_ccm_calc_pll(s->reg[IMX31_CCM_MPCTL_REG],
 132                            imx31_ccm_get_pll_ref_clk(dev));
 133
 134    DPRINTF("freq = %d\n", freq);
 135
 136    return freq;
 137}
 138
 139static uint32_t imx31_ccm_get_mcu_main_clk(IMXCCMState *dev)
 140{
 141    uint32_t freq;
 142    IMX31CCMState *s = IMX31_CCM(dev);
 143
 144    if ((s->reg[IMX31_CCM_CCMR_REG] & CCMR_MDS) ||
 145        !(s->reg[IMX31_CCM_CCMR_REG] & CCMR_MPE)) {
 146        freq = imx31_ccm_get_pll_ref_clk(dev);
 147    } else {
 148        freq = imx31_ccm_get_mpll_clk(dev);
 149    }
 150
 151    DPRINTF("freq = %d\n", freq);
 152
 153    return freq;
 154}
 155
 156static uint32_t imx31_ccm_get_hclk_clk(IMXCCMState *dev)
 157{
 158    uint32_t freq;
 159    IMX31CCMState *s = IMX31_CCM(dev);
 160
 161    freq = imx31_ccm_get_mcu_main_clk(dev)
 162           / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], MAX));
 163
 164    DPRINTF("freq = %d\n", freq);
 165
 166    return freq;
 167}
 168
 169static uint32_t imx31_ccm_get_ipg_clk(IMXCCMState *dev)
 170{
 171    uint32_t freq;
 172    IMX31CCMState *s = IMX31_CCM(dev);
 173
 174    freq = imx31_ccm_get_hclk_clk(dev)
 175           / (1 + EXTRACT(s->reg[IMX31_CCM_PDR0_REG], IPG));
 176
 177    DPRINTF("freq = %d\n", freq);
 178
 179    return freq;
 180}
 181
 182static uint32_t imx31_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
 183{
 184    uint32_t freq = 0;
 185
 186    switch (clock) {
 187    case CLK_NONE:
 188        break;
 189    case CLK_IPG:
 190    case CLK_IPG_HIGH:
 191        freq = imx31_ccm_get_ipg_clk(dev);
 192        break;
 193    case CLK_32k:
 194        freq = CKIL_FREQ;
 195        break;
 196    default:
 197        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
 198                      TYPE_IMX31_CCM, __func__, clock);
 199        break;
 200    }
 201
 202    DPRINTF("Clock = %d) = %d\n", clock, freq);
 203
 204    return freq;
 205}
 206
 207static void imx31_ccm_reset(DeviceState *dev)
 208{
 209    IMX31CCMState *s = IMX31_CCM(dev);
 210
 211    DPRINTF("()\n");
 212
 213    memset(s->reg, 0, sizeof(uint32_t) * IMX31_CCM_MAX_REG);
 214
 215    s->reg[IMX31_CCM_CCMR_REG]   = 0x074b0b7d;
 216    s->reg[IMX31_CCM_PDR0_REG]   = 0xff870b48;
 217    s->reg[IMX31_CCM_PDR1_REG]   = 0x49fcfe7f;
 218    s->reg[IMX31_CCM_RCSR_REG]   = 0x007f0000;
 219    s->reg[IMX31_CCM_MPCTL_REG]  = 0x04001800;
 220    s->reg[IMX31_CCM_UPCTL_REG]  = 0x04051c03;
 221    s->reg[IMX31_CCM_SPCTL_REG]  = 0x04043001;
 222    s->reg[IMX31_CCM_COSR_REG]   = 0x00000280;
 223    s->reg[IMX31_CCM_CGR0_REG]   = 0xffffffff;
 224    s->reg[IMX31_CCM_CGR1_REG]   = 0xffffffff;
 225    s->reg[IMX31_CCM_CGR2_REG]   = 0xffffffff;
 226    s->reg[IMX31_CCM_WIMR_REG]   = 0xffffffff;
 227    s->reg[IMX31_CCM_LTR1_REG]   = 0x00004040;
 228    s->reg[IMX31_CCM_PMCR0_REG]  = 0x80209828;
 229    s->reg[IMX31_CCM_PMCR1_REG]  = 0x00aa0000;
 230    s->reg[IMX31_CCM_PDR2_REG]   = 0x00000285;
 231}
 232
 233static uint64_t imx31_ccm_read(void *opaque, hwaddr offset, unsigned size)
 234{
 235    uint32_t value = 0;
 236    IMX31CCMState *s = (IMX31CCMState *)opaque;
 237
 238    if ((offset >> 2) < IMX31_CCM_MAX_REG) {
 239        value = s->reg[offset >> 2];
 240    } else {
 241        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 242                      HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
 243    }
 244
 245    DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
 246            value);
 247
 248    return (uint64_t)value;
 249}
 250
 251static void imx31_ccm_write(void *opaque, hwaddr offset, uint64_t value,
 252                            unsigned size)
 253{
 254    IMX31CCMState *s = (IMX31CCMState *)opaque;
 255
 256    DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
 257            (uint32_t)value);
 258
 259    switch (offset >> 2) {
 260    case IMX31_CCM_CCMR_REG:
 261        s->reg[IMX31_CCM_CCMR_REG] = CCMR_FPMF | (value & 0x3b6fdfff);
 262        break;
 263    case IMX31_CCM_PDR0_REG:
 264        s->reg[IMX31_CCM_PDR0_REG] = value & 0xff9f3fff;
 265        break;
 266    case IMX31_CCM_PDR1_REG:
 267        s->reg[IMX31_CCM_PDR1_REG] = value;
 268        break;
 269    case IMX31_CCM_MPCTL_REG:
 270        s->reg[IMX31_CCM_MPCTL_REG] = value & 0xbfff3fff;
 271        break;
 272    case IMX31_CCM_SPCTL_REG:
 273        s->reg[IMX31_CCM_SPCTL_REG] = value & 0xbfff3fff;
 274        break;
 275    case IMX31_CCM_CGR0_REG:
 276        s->reg[IMX31_CCM_CGR0_REG] = value;
 277        break;
 278    case IMX31_CCM_CGR1_REG:
 279        s->reg[IMX31_CCM_CGR1_REG] = value;
 280        break;
 281    case IMX31_CCM_CGR2_REG:
 282        s->reg[IMX31_CCM_CGR2_REG] = value;
 283        break;
 284    default:
 285        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 286                      HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
 287        break;
 288    }
 289}
 290
 291static const struct MemoryRegionOps imx31_ccm_ops = {
 292    .read = imx31_ccm_read,
 293    .write = imx31_ccm_write,
 294    .endianness = DEVICE_NATIVE_ENDIAN,
 295    .valid = {
 296        /*
 297         * Our device would not work correctly if the guest was doing
 298         * unaligned access. This might not be a limitation on the real
 299         * device but in practice there is no reason for a guest to access
 300         * this device unaligned.
 301         */
 302        .min_access_size = 4,
 303        .max_access_size = 4,
 304        .unaligned = false,
 305    },
 306
 307};
 308
 309static void imx31_ccm_init(Object *obj)
 310{
 311    DeviceState *dev = DEVICE(obj);
 312    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
 313    IMX31CCMState *s = IMX31_CCM(obj);
 314
 315    memory_region_init_io(&s->iomem, OBJECT(dev), &imx31_ccm_ops, s,
 316                          TYPE_IMX31_CCM, 0x1000);
 317    sysbus_init_mmio(sd, &s->iomem);
 318}
 319
 320static void imx31_ccm_class_init(ObjectClass *klass, void *data)
 321{
 322    DeviceClass *dc  = DEVICE_CLASS(klass);
 323    IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
 324
 325    dc->reset = imx31_ccm_reset;
 326    dc->vmsd  = &vmstate_imx31_ccm;
 327    dc->desc  = "i.MX31 Clock Control Module";
 328
 329    ccm->get_clock_frequency = imx31_ccm_get_clock_frequency;
 330}
 331
 332static const TypeInfo imx31_ccm_info = {
 333    .name          = TYPE_IMX31_CCM,
 334    .parent        = TYPE_IMX_CCM,
 335    .instance_size = sizeof(IMX31CCMState),
 336    .instance_init = imx31_ccm_init,
 337    .class_init    = imx31_ccm_class_init,
 338};
 339
 340static void imx31_ccm_register_types(void)
 341{
 342    type_register_static(&imx31_ccm_info);
 343}
 344
 345type_init(imx31_ccm_register_types)
 346