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