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