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