qemu/hw/misc/imx25_ccm.c
<<
>>
Prefs
   1/*
   2 * IMX25 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 "qemu/osdep.h"
  15#include "hw/misc/imx25_ccm.h"
  16
  17#ifndef DEBUG_IMX25_CCM
  18#define DEBUG_IMX25_CCM 0
  19#endif
  20
  21#define DPRINTF(fmt, args...) \
  22    do { \
  23        if (DEBUG_IMX25_CCM) { \
  24            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
  25                                             __func__, ##args); \
  26        } \
  27    } while (0)
  28
  29static char const *imx25_ccm_reg_name(uint32_t reg)
  30{
  31    static char unknown[20];
  32
  33    switch (reg) {
  34    case IMX25_CCM_MPCTL_REG:
  35        return "mpctl";
  36    case IMX25_CCM_UPCTL_REG:
  37        return "upctl";
  38    case IMX25_CCM_CCTL_REG:
  39        return "cctl";
  40    case IMX25_CCM_CGCR0_REG:
  41        return "cgcr0";
  42    case IMX25_CCM_CGCR1_REG:
  43        return "cgcr1";
  44    case IMX25_CCM_CGCR2_REG:
  45        return "cgcr2";
  46    case IMX25_CCM_PCDR0_REG:
  47        return "pcdr0";
  48    case IMX25_CCM_PCDR1_REG:
  49        return "pcdr1";
  50    case IMX25_CCM_PCDR2_REG:
  51        return "pcdr2";
  52    case IMX25_CCM_PCDR3_REG:
  53        return "pcdr3";
  54    case IMX25_CCM_RCSR_REG:
  55        return "rcsr";
  56    case IMX25_CCM_CRDR_REG:
  57        return "crdr";
  58    case IMX25_CCM_DCVR0_REG:
  59        return "dcvr0";
  60    case IMX25_CCM_DCVR1_REG:
  61        return "dcvr1";
  62    case IMX25_CCM_DCVR2_REG:
  63        return "dcvr2";
  64    case IMX25_CCM_DCVR3_REG:
  65        return "dcvr3";
  66    case IMX25_CCM_LTR0_REG:
  67        return "ltr0";
  68    case IMX25_CCM_LTR1_REG:
  69        return "ltr1";
  70    case IMX25_CCM_LTR2_REG:
  71        return "ltr2";
  72    case IMX25_CCM_LTR3_REG:
  73        return "ltr3";
  74    case IMX25_CCM_LTBR0_REG:
  75        return "ltbr0";
  76    case IMX25_CCM_LTBR1_REG:
  77        return "ltbr1";
  78    case IMX25_CCM_PMCR0_REG:
  79        return "pmcr0";
  80    case IMX25_CCM_PMCR1_REG:
  81        return "pmcr1";
  82    case IMX25_CCM_PMCR2_REG:
  83        return "pmcr2";
  84    case IMX25_CCM_MCR_REG:
  85        return "mcr";
  86    case IMX25_CCM_LPIMR0_REG:
  87        return "lpimr0";
  88    case IMX25_CCM_LPIMR1_REG:
  89        return "lpimr1";
  90    default:
  91        sprintf(unknown, "[%d ?]", reg);
  92        return unknown;
  93    }
  94}
  95#define CKIH_FREQ 24000000 /* 24MHz crystal input */
  96
  97static const VMStateDescription vmstate_imx25_ccm = {
  98    .name = TYPE_IMX25_CCM,
  99    .version_id = 1,
 100    .minimum_version_id = 1,
 101    .fields = (VMStateField[]) {
 102        VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
 103        VMSTATE_END_OF_LIST()
 104    },
 105};
 106
 107static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
 108{
 109    uint32_t freq;
 110    IMX25CCMState *s = IMX25_CCM(dev);
 111
 112    if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
 113        freq = CKIH_FREQ;
 114    } else {
 115        freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
 116    }
 117
 118    DPRINTF("freq = %d\n", freq);
 119
 120    return freq;
 121}
 122
 123static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
 124{
 125    uint32_t freq;
 126    IMX25CCMState *s = IMX25_CCM(dev);
 127
 128    freq = imx25_ccm_get_mpll_clk(dev);
 129
 130    if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
 131        freq = (freq * 3 / 4);
 132    }
 133
 134    freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
 135
 136    DPRINTF("freq = %d\n", freq);
 137
 138    return freq;
 139}
 140
 141static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
 142{
 143    uint32_t freq;
 144    IMX25CCMState *s = IMX25_CCM(dev);
 145
 146    freq = imx25_ccm_get_mcu_clk(dev)
 147           / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
 148
 149    DPRINTF("freq = %d\n", freq);
 150
 151    return freq;
 152}
 153
 154static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
 155{
 156    uint32_t freq;
 157
 158    freq = imx25_ccm_get_ahb_clk(dev) / 2;
 159
 160    DPRINTF("freq = %d\n", freq);
 161
 162    return freq;
 163}
 164
 165static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
 166{
 167    uint32_t freq = 0;
 168    DPRINTF("Clock = %d)\n", clock);
 169
 170    switch (clock) {
 171    case CLK_NONE:
 172        break;
 173    case CLK_IPG:
 174    case CLK_IPG_HIGH:
 175        freq = imx25_ccm_get_ipg_clk(dev);
 176        break;
 177    case CLK_32k:
 178        freq = CKIL_FREQ;
 179        break;
 180    default:
 181        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
 182                      TYPE_IMX25_CCM, __func__, clock);
 183        break;
 184    }
 185
 186    DPRINTF("Clock = %d) = %d\n", clock, freq);
 187
 188    return freq;
 189}
 190
 191static void imx25_ccm_reset(DeviceState *dev)
 192{
 193    IMX25CCMState *s = IMX25_CCM(dev);
 194
 195    DPRINTF("\n");
 196
 197    memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
 198    s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
 199    s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
 200    /* 
 201     * The value below gives:
 202     * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz. 
 203     */
 204    s->reg[IMX25_CCM_CCTL_REG]  = 0xd0030000;
 205    s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
 206    s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
 207    s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
 208    s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
 209    s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
 210    s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
 211    s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
 212    s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
 213    s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
 214    s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
 215    s->reg[IMX25_CCM_MCR_REG]   = 0x43000000;
 216
 217    /*
 218     * default boot will change the reset values to allow:
 219     * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz. 
 220     * For some reason, this doesn't work. With the value below, linux
 221     * detects a 88 MHz IPG CLK instead of 66,5 MHz.
 222    s->reg[IMX25_CCM_CCTL_REG]  = 0x20032000;
 223     */
 224}
 225
 226static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
 227{
 228    uint32_t value = 0;
 229    IMX25CCMState *s = (IMX25CCMState *)opaque;
 230
 231    if (offset < 0x70) {
 232        value = s->reg[offset >> 2];
 233    } else {
 234        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 235                      HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
 236    }
 237
 238    DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
 239            value);
 240
 241    return value;
 242}
 243
 244static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
 245                            unsigned size)
 246{
 247    IMX25CCMState *s = (IMX25CCMState *)opaque;
 248
 249    DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
 250            (uint32_t)value);
 251
 252    if (offset < 0x70) {
 253        /*
 254         * We will do a better implementation later. In particular some bits
 255         * cannot be written to.
 256         */
 257        s->reg[offset >> 2] = value;
 258    } else {
 259        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
 260                      HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
 261    }
 262}
 263
 264static const struct MemoryRegionOps imx25_ccm_ops = {
 265    .read = imx25_ccm_read,
 266    .write = imx25_ccm_write,
 267    .endianness = DEVICE_NATIVE_ENDIAN,
 268    .valid = {
 269        /*
 270         * Our device would not work correctly if the guest was doing
 271         * unaligned access. This might not be a limitation on the real
 272         * device but in practice there is no reason for a guest to access
 273         * this device unaligned.
 274         */
 275        .min_access_size = 4,
 276        .max_access_size = 4,
 277        .unaligned = false,
 278    },
 279};
 280
 281static void imx25_ccm_init(Object *obj)
 282{
 283    DeviceState *dev = DEVICE(obj);
 284    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
 285    IMX25CCMState *s = IMX25_CCM(obj);
 286
 287    memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
 288                          TYPE_IMX25_CCM, 0x1000);
 289    sysbus_init_mmio(sd, &s->iomem);
 290}
 291
 292static void imx25_ccm_class_init(ObjectClass *klass, void *data)
 293{
 294    DeviceClass *dc = DEVICE_CLASS(klass);
 295    IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
 296
 297    dc->reset = imx25_ccm_reset;
 298    dc->vmsd = &vmstate_imx25_ccm;
 299    dc->desc = "i.MX25 Clock Control Module";
 300
 301    ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
 302}
 303
 304static const TypeInfo imx25_ccm_info = {
 305    .name          = TYPE_IMX25_CCM,
 306    .parent        = TYPE_IMX_CCM,
 307    .instance_size = sizeof(IMX25CCMState),
 308    .instance_init = imx25_ccm_init,
 309    .class_init    = imx25_ccm_class_init,
 310};
 311
 312static void imx25_ccm_register_types(void)
 313{
 314    type_register_static(&imx25_ccm_info);
 315}
 316
 317type_init(imx25_ccm_register_types)
 318