qemu/hw/misc/imx6_ccm.c
<<
>>
Prefs
   1/*
   2 * IMX6 Clock Control Module
   3 *
   4 * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 *
   9 * To get the timer frequencies right, we need to emulate at least part of
  10 * the CCM.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "hw/misc/imx6_ccm.h"
  15#include "qemu/log.h"
  16
  17#ifndef DEBUG_IMX6_CCM
  18#define DEBUG_IMX6_CCM 0
  19#endif
  20
  21#define DPRINTF(fmt, args...) \
  22    do { \
  23        if (DEBUG_IMX6_CCM) { \
  24            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_CCM, \
  25                                             __func__, ##args); \
  26        } \
  27    } while (0)
  28
  29static const char *imx6_ccm_reg_name(uint32_t reg)
  30{
  31    static char unknown[20];
  32
  33    switch (reg) {
  34    case CCM_CCR:
  35        return "CCR";
  36    case CCM_CCDR:
  37        return "CCDR";
  38    case CCM_CSR:
  39        return "CSR";
  40    case CCM_CCSR:
  41        return "CCSR";
  42    case CCM_CACRR:
  43        return "CACRR";
  44    case CCM_CBCDR:
  45        return "CBCDR";
  46    case CCM_CBCMR:
  47        return "CBCMR";
  48    case CCM_CSCMR1:
  49        return "CSCMR1";
  50    case CCM_CSCMR2:
  51        return "CSCMR2";
  52    case CCM_CSCDR1:
  53        return "CSCDR1";
  54    case CCM_CS1CDR:
  55        return "CS1CDR";
  56    case CCM_CS2CDR:
  57        return "CS2CDR";
  58    case CCM_CDCDR:
  59        return "CDCDR";
  60    case CCM_CHSCCDR:
  61        return "CHSCCDR";
  62    case CCM_CSCDR2:
  63        return "CSCDR2";
  64    case CCM_CSCDR3:
  65        return "CSCDR3";
  66    case CCM_CDHIPR:
  67        return "CDHIPR";
  68    case CCM_CTOR:
  69        return "CTOR";
  70    case CCM_CLPCR:
  71        return "CLPCR";
  72    case CCM_CISR:
  73        return "CISR";
  74    case CCM_CIMR:
  75        return "CIMR";
  76    case CCM_CCOSR:
  77        return "CCOSR";
  78    case CCM_CGPR:
  79        return "CGPR";
  80    case CCM_CCGR0:
  81        return "CCGR0";
  82    case CCM_CCGR1:
  83        return "CCGR1";
  84    case CCM_CCGR2:
  85        return "CCGR2";
  86    case CCM_CCGR3:
  87        return "CCGR3";
  88    case CCM_CCGR4:
  89        return "CCGR4";
  90    case CCM_CCGR5:
  91        return "CCGR5";
  92    case CCM_CCGR6:
  93        return "CCGR6";
  94    case CCM_CMEOR:
  95        return "CMEOR";
  96    default:
  97        sprintf(unknown, "%d ?", reg);
  98        return unknown;
  99    }
 100}
 101
 102static const char *imx6_analog_reg_name(uint32_t reg)
 103{
 104    static char unknown[20];
 105
 106    switch (reg) {
 107    case CCM_ANALOG_PLL_ARM:
 108        return "PLL_ARM";
 109    case CCM_ANALOG_PLL_ARM_SET:
 110        return "PLL_ARM_SET";
 111    case CCM_ANALOG_PLL_ARM_CLR:
 112        return "PLL_ARM_CLR";
 113    case CCM_ANALOG_PLL_ARM_TOG:
 114        return "PLL_ARM_TOG";
 115    case CCM_ANALOG_PLL_USB1:
 116        return "PLL_USB1";
 117    case CCM_ANALOG_PLL_USB1_SET:
 118        return "PLL_USB1_SET";
 119    case CCM_ANALOG_PLL_USB1_CLR:
 120        return "PLL_USB1_CLR";
 121    case CCM_ANALOG_PLL_USB1_TOG:
 122        return "PLL_USB1_TOG";
 123    case CCM_ANALOG_PLL_USB2:
 124        return "PLL_USB2";
 125    case CCM_ANALOG_PLL_USB2_SET:
 126        return "PLL_USB2_SET";
 127    case CCM_ANALOG_PLL_USB2_CLR:
 128        return "PLL_USB2_CLR";
 129    case CCM_ANALOG_PLL_USB2_TOG:
 130        return "PLL_USB2_TOG";
 131    case CCM_ANALOG_PLL_SYS:
 132        return "PLL_SYS";
 133    case CCM_ANALOG_PLL_SYS_SET:
 134        return "PLL_SYS_SET";
 135    case CCM_ANALOG_PLL_SYS_CLR:
 136        return "PLL_SYS_CLR";
 137    case CCM_ANALOG_PLL_SYS_TOG:
 138        return "PLL_SYS_TOG";
 139    case CCM_ANALOG_PLL_SYS_SS:
 140        return "PLL_SYS_SS";
 141    case CCM_ANALOG_PLL_SYS_NUM:
 142        return "PLL_SYS_NUM";
 143    case CCM_ANALOG_PLL_SYS_DENOM:
 144        return "PLL_SYS_DENOM";
 145    case CCM_ANALOG_PLL_AUDIO:
 146        return "PLL_AUDIO";
 147    case CCM_ANALOG_PLL_AUDIO_SET:
 148        return "PLL_AUDIO_SET";
 149    case CCM_ANALOG_PLL_AUDIO_CLR:
 150        return "PLL_AUDIO_CLR";
 151    case CCM_ANALOG_PLL_AUDIO_TOG:
 152        return "PLL_AUDIO_TOG";
 153    case CCM_ANALOG_PLL_AUDIO_NUM:
 154        return "PLL_AUDIO_NUM";
 155    case CCM_ANALOG_PLL_AUDIO_DENOM:
 156        return "PLL_AUDIO_DENOM";
 157    case CCM_ANALOG_PLL_VIDEO:
 158        return "PLL_VIDEO";
 159    case CCM_ANALOG_PLL_VIDEO_SET:
 160        return "PLL_VIDEO_SET";
 161    case CCM_ANALOG_PLL_VIDEO_CLR:
 162        return "PLL_VIDEO_CLR";
 163    case CCM_ANALOG_PLL_VIDEO_TOG:
 164        return "PLL_VIDEO_TOG";
 165    case CCM_ANALOG_PLL_VIDEO_NUM:
 166        return "PLL_VIDEO_NUM";
 167    case CCM_ANALOG_PLL_VIDEO_DENOM:
 168        return "PLL_VIDEO_DENOM";
 169    case CCM_ANALOG_PLL_MLB:
 170        return "PLL_MLB";
 171    case CCM_ANALOG_PLL_MLB_SET:
 172        return "PLL_MLB_SET";
 173    case CCM_ANALOG_PLL_MLB_CLR:
 174        return "PLL_MLB_CLR";
 175    case CCM_ANALOG_PLL_MLB_TOG:
 176        return "PLL_MLB_TOG";
 177    case CCM_ANALOG_PLL_ENET:
 178        return "PLL_ENET";
 179    case CCM_ANALOG_PLL_ENET_SET:
 180        return "PLL_ENET_SET";
 181    case CCM_ANALOG_PLL_ENET_CLR:
 182        return "PLL_ENET_CLR";
 183    case CCM_ANALOG_PLL_ENET_TOG:
 184        return "PLL_ENET_TOG";
 185    case CCM_ANALOG_PFD_480:
 186        return "PFD_480";
 187    case CCM_ANALOG_PFD_480_SET:
 188        return "PFD_480_SET";
 189    case CCM_ANALOG_PFD_480_CLR:
 190        return "PFD_480_CLR";
 191    case CCM_ANALOG_PFD_480_TOG:
 192        return "PFD_480_TOG";
 193    case CCM_ANALOG_PFD_528:
 194        return "PFD_528";
 195    case CCM_ANALOG_PFD_528_SET:
 196        return "PFD_528_SET";
 197    case CCM_ANALOG_PFD_528_CLR:
 198        return "PFD_528_CLR";
 199    case CCM_ANALOG_PFD_528_TOG:
 200        return "PFD_528_TOG";
 201    case CCM_ANALOG_MISC0:
 202        return "MISC0";
 203    case CCM_ANALOG_MISC0_SET:
 204        return "MISC0_SET";
 205    case CCM_ANALOG_MISC0_CLR:
 206        return "MISC0_CLR";
 207    case CCM_ANALOG_MISC0_TOG:
 208        return "MISC0_TOG";
 209    case CCM_ANALOG_MISC2:
 210        return "MISC2";
 211    case CCM_ANALOG_MISC2_SET:
 212        return "MISC2_SET";
 213    case CCM_ANALOG_MISC2_CLR:
 214        return "MISC2_CLR";
 215    case CCM_ANALOG_MISC2_TOG:
 216        return "MISC2_TOG";
 217    case PMU_REG_1P1:
 218        return "PMU_REG_1P1";
 219    case PMU_REG_3P0:
 220        return "PMU_REG_3P0";
 221    case PMU_REG_2P5:
 222        return "PMU_REG_2P5";
 223    case PMU_REG_CORE:
 224        return "PMU_REG_CORE";
 225    case PMU_MISC1:
 226        return "PMU_MISC1";
 227    case PMU_MISC1_SET:
 228        return "PMU_MISC1_SET";
 229    case PMU_MISC1_CLR:
 230        return "PMU_MISC1_CLR";
 231    case PMU_MISC1_TOG:
 232        return "PMU_MISC1_TOG";
 233    case USB_ANALOG_DIGPROG:
 234        return "USB_ANALOG_DIGPROG";
 235    default:
 236        sprintf(unknown, "%d ?", reg);
 237        return unknown;
 238    }
 239}
 240
 241#define CKIH_FREQ 24000000 /* 24MHz crystal input */
 242
 243static const VMStateDescription vmstate_imx6_ccm = {
 244    .name = TYPE_IMX6_CCM,
 245    .version_id = 1,
 246    .minimum_version_id = 1,
 247    .fields = (VMStateField[]) {
 248        VMSTATE_UINT32_ARRAY(ccm, IMX6CCMState, CCM_MAX),
 249        VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_MAX),
 250        VMSTATE_END_OF_LIST()
 251    },
 252};
 253
 254static uint64_t imx6_analog_get_pll2_clk(IMX6CCMState *dev)
 255{
 256    uint64_t freq = 24000000;
 257
 258    if (EXTRACT(dev->analog[CCM_ANALOG_PLL_SYS], DIV_SELECT)) {
 259        freq *= 22;
 260    } else {
 261        freq *= 20;
 262    }
 263
 264    DPRINTF("freq = %d\n", (uint32_t)freq);
 265
 266    return freq;
 267}
 268
 269static uint64_t imx6_analog_get_pll2_pfd0_clk(IMX6CCMState *dev)
 270{
 271    uint64_t freq = 0;
 272
 273    freq = imx6_analog_get_pll2_clk(dev) * 18
 274           / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD0_FRAC);
 275
 276    DPRINTF("freq = %d\n", (uint32_t)freq);
 277
 278    return freq;
 279}
 280
 281static uint64_t imx6_analog_get_pll2_pfd2_clk(IMX6CCMState *dev)
 282{
 283    uint64_t freq = 0;
 284
 285    freq = imx6_analog_get_pll2_clk(dev) * 18
 286           / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD2_FRAC);
 287
 288    DPRINTF("freq = %d\n", (uint32_t)freq);
 289
 290    return freq;
 291}
 292
 293static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
 294{
 295    uint64_t freq = 0;
 296
 297    switch (EXTRACT(dev->ccm[CCM_CBCMR], PRE_PERIPH_CLK_SEL)) {
 298    case 0:
 299        freq = imx6_analog_get_pll2_clk(dev);
 300        break;
 301    case 1:
 302        freq = imx6_analog_get_pll2_pfd2_clk(dev);
 303        break;
 304    case 2:
 305        freq = imx6_analog_get_pll2_pfd0_clk(dev);
 306        break;
 307    case 3:
 308        freq = imx6_analog_get_pll2_pfd2_clk(dev) / 2;
 309        break;
 310    default:
 311        /* We should never get there */
 312        g_assert_not_reached();
 313        break;
 314    }
 315
 316    DPRINTF("freq = %d\n", (uint32_t)freq);
 317
 318    return freq;
 319}
 320
 321static uint64_t imx6_ccm_get_ahb_clk(IMX6CCMState *dev)
 322{
 323    uint64_t freq = 0;
 324
 325    freq = imx6_analog_get_periph_clk(dev)
 326           / (1 + EXTRACT(dev->ccm[CCM_CBCDR], AHB_PODF));
 327
 328    DPRINTF("freq = %d\n", (uint32_t)freq);
 329
 330    return freq;
 331}
 332
 333static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev)
 334{
 335    uint64_t freq = 0;
 336
 337    freq = imx6_ccm_get_ahb_clk(dev)
 338           / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));
 339
 340    DPRINTF("freq = %d\n", (uint32_t)freq);
 341
 342    return freq;
 343}
 344
 345static uint64_t imx6_ccm_get_per_clk(IMX6CCMState *dev)
 346{
 347    uint64_t freq = 0;
 348
 349    freq = imx6_ccm_get_ipg_clk(dev)
 350           / (1 + EXTRACT(dev->ccm[CCM_CSCMR1], PERCLK_PODF));
 351
 352    DPRINTF("freq = %d\n", (uint32_t)freq);
 353
 354    return freq;
 355}
 356
 357static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
 358{
 359    uint32_t freq = 0;
 360    IMX6CCMState *s = IMX6_CCM(dev);
 361
 362    switch (clock) {
 363    case CLK_NONE:
 364        break;
 365    case CLK_IPG:
 366        freq = imx6_ccm_get_ipg_clk(s);
 367        break;
 368    case CLK_IPG_HIGH:
 369        freq = imx6_ccm_get_per_clk(s);
 370        break;
 371    case CLK_32k:
 372        freq = CKIL_FREQ;
 373        break;
 374    case CLK_HIGH:
 375        freq = 24000000;
 376        break;
 377    case CLK_HIGH_DIV:
 378        freq = 24000000 / 8;
 379        break;
 380    default:
 381        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
 382                      TYPE_IMX6_CCM, __func__, clock);
 383        break;
 384    }
 385
 386    DPRINTF("Clock = %d) = %d\n", clock, freq);
 387
 388    return freq;
 389}
 390
 391static void imx6_ccm_reset(DeviceState *dev)
 392{
 393    IMX6CCMState *s = IMX6_CCM(dev);
 394
 395    DPRINTF("\n");
 396
 397    s->ccm[CCM_CCR] = 0x040116FF;
 398    s->ccm[CCM_CCDR] = 0x00000000;
 399    s->ccm[CCM_CSR] = 0x00000010;
 400    s->ccm[CCM_CCSR] = 0x00000100;
 401    s->ccm[CCM_CACRR] = 0x00000000;
 402    s->ccm[CCM_CBCDR] = 0x00018D40;
 403    s->ccm[CCM_CBCMR] = 0x00022324;
 404    s->ccm[CCM_CSCMR1] = 0x00F00000;
 405    s->ccm[CCM_CSCMR2] = 0x02B92F06;
 406    s->ccm[CCM_CSCDR1] = 0x00490B00;
 407    s->ccm[CCM_CS1CDR] = 0x0EC102C1;
 408    s->ccm[CCM_CS2CDR] = 0x000736C1;
 409    s->ccm[CCM_CDCDR] = 0x33F71F92;
 410    s->ccm[CCM_CHSCCDR] = 0x0002A150;
 411    s->ccm[CCM_CSCDR2] = 0x0002A150;
 412    s->ccm[CCM_CSCDR3] = 0x00014841;
 413    s->ccm[CCM_CDHIPR] = 0x00000000;
 414    s->ccm[CCM_CTOR] = 0x00000000;
 415    s->ccm[CCM_CLPCR] = 0x00000079;
 416    s->ccm[CCM_CISR] = 0x00000000;
 417    s->ccm[CCM_CIMR] = 0xFFFFFFFF;
 418    s->ccm[CCM_CCOSR] = 0x000A0001;
 419    s->ccm[CCM_CGPR] = 0x0000FE62;
 420    s->ccm[CCM_CCGR0] = 0xFFFFFFFF;
 421    s->ccm[CCM_CCGR1] = 0xFFFFFFFF;
 422    s->ccm[CCM_CCGR2] = 0xFC3FFFFF;
 423    s->ccm[CCM_CCGR3] = 0xFFFFFFFF;
 424    s->ccm[CCM_CCGR4] = 0xFFFFFFFF;
 425    s->ccm[CCM_CCGR5] = 0xFFFFFFFF;
 426    s->ccm[CCM_CCGR6] = 0xFFFFFFFF;
 427    s->ccm[CCM_CMEOR] = 0xFFFFFFFF;
 428
 429    s->analog[CCM_ANALOG_PLL_ARM] = 0x00013042;
 430    s->analog[CCM_ANALOG_PLL_USB1] = 0x00012000;
 431    s->analog[CCM_ANALOG_PLL_USB2] = 0x00012000;
 432    s->analog[CCM_ANALOG_PLL_SYS] = 0x00013001;
 433    s->analog[CCM_ANALOG_PLL_SYS_SS] = 0x00000000;
 434    s->analog[CCM_ANALOG_PLL_SYS_NUM] = 0x00000000;
 435    s->analog[CCM_ANALOG_PLL_SYS_DENOM] = 0x00000012;
 436    s->analog[CCM_ANALOG_PLL_AUDIO] = 0x00011006;
 437    s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05F5E100;
 438    s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619C;
 439    s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0001100C;
 440    s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0x05F5E100;
 441    s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x10A24447;
 442    s->analog[CCM_ANALOG_PLL_MLB] = 0x00010000;
 443    s->analog[CCM_ANALOG_PLL_ENET] = 0x00011001;
 444    s->analog[CCM_ANALOG_PFD_480] = 0x1311100C;
 445    s->analog[CCM_ANALOG_PFD_528] = 0x1018101B;
 446
 447    s->analog[PMU_REG_1P1] = 0x00001073;
 448    s->analog[PMU_REG_3P0] = 0x00000F74;
 449    s->analog[PMU_REG_2P5] = 0x00005071;
 450    s->analog[PMU_REG_CORE] = 0x00402010;
 451    s->analog[PMU_MISC0] = 0x04000000;
 452    s->analog[PMU_MISC1] = 0x00000000;
 453    s->analog[PMU_MISC2] = 0x00272727;
 454
 455    s->analog[USB_ANALOG_USB1_VBUS_DETECT] = 0x00000004;
 456    s->analog[USB_ANALOG_USB1_CHRG_DETECT] = 0x00000000;
 457    s->analog[USB_ANALOG_USB1_VBUS_DETECT_STAT] = 0x00000000;
 458    s->analog[USB_ANALOG_USB1_CHRG_DETECT_STAT] = 0x00000000;
 459    s->analog[USB_ANALOG_USB1_MISC] = 0x00000002;
 460    s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x00000004;
 461    s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
 462    s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
 463    s->analog[USB_ANALOG_DIGPROG] = 0x00000000;
 464
 465    /* all PLLs need to be locked */
 466    s->analog[CCM_ANALOG_PLL_ARM]   |= CCM_ANALOG_PLL_LOCK;
 467    s->analog[CCM_ANALOG_PLL_USB1]  |= CCM_ANALOG_PLL_LOCK;
 468    s->analog[CCM_ANALOG_PLL_USB2]  |= CCM_ANALOG_PLL_LOCK;
 469    s->analog[CCM_ANALOG_PLL_SYS]   |= CCM_ANALOG_PLL_LOCK;
 470    s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK;
 471    s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK;
 472    s->analog[CCM_ANALOG_PLL_MLB]   |= CCM_ANALOG_PLL_LOCK;
 473    s->analog[CCM_ANALOG_PLL_ENET]  |= CCM_ANALOG_PLL_LOCK;
 474}
 475
 476static uint64_t imx6_ccm_read(void *opaque, hwaddr offset, unsigned size)
 477{
 478    uint32_t value = 0;
 479    uint32_t index = offset >> 2;
 480    IMX6CCMState *s = (IMX6CCMState *)opaque;
 481
 482    value = s->ccm[index];
 483
 484    DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_ccm_reg_name(index), value);
 485
 486    return (uint64_t)value;
 487}
 488
 489static void imx6_ccm_write(void *opaque, hwaddr offset, uint64_t value,
 490                           unsigned size)
 491{
 492    uint32_t index = offset >> 2;
 493    IMX6CCMState *s = (IMX6CCMState *)opaque;
 494
 495    DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_ccm_reg_name(index),
 496            (uint32_t)value);
 497
 498    /*
 499     * We will do a better implementation later. In particular some bits
 500     * cannot be written to.
 501     */
 502    s->ccm[index] = (uint32_t)value;
 503}
 504
 505static uint64_t imx6_analog_read(void *opaque, hwaddr offset, unsigned size)
 506{
 507    uint32_t value;
 508    uint32_t index = offset >> 2;
 509    IMX6CCMState *s = (IMX6CCMState *)opaque;
 510
 511    switch (index) {
 512    case CCM_ANALOG_PLL_ARM_SET:
 513    case CCM_ANALOG_PLL_USB1_SET:
 514    case CCM_ANALOG_PLL_USB2_SET:
 515    case CCM_ANALOG_PLL_SYS_SET:
 516    case CCM_ANALOG_PLL_AUDIO_SET:
 517    case CCM_ANALOG_PLL_VIDEO_SET:
 518    case CCM_ANALOG_PLL_MLB_SET:
 519    case CCM_ANALOG_PLL_ENET_SET:
 520    case CCM_ANALOG_PFD_480_SET:
 521    case CCM_ANALOG_PFD_528_SET:
 522    case CCM_ANALOG_MISC0_SET:
 523    case PMU_MISC1_SET:
 524    case CCM_ANALOG_MISC2_SET:
 525    case USB_ANALOG_USB1_VBUS_DETECT_SET:
 526    case USB_ANALOG_USB1_CHRG_DETECT_SET:
 527    case USB_ANALOG_USB1_MISC_SET:
 528    case USB_ANALOG_USB2_VBUS_DETECT_SET:
 529    case USB_ANALOG_USB2_CHRG_DETECT_SET:
 530    case USB_ANALOG_USB2_MISC_SET:
 531        /*
 532         * All REG_NAME_SET register access are in fact targeting the
 533         * the REG_NAME register.
 534         */
 535        value = s->analog[index - 1];
 536        break;
 537    case CCM_ANALOG_PLL_ARM_CLR:
 538    case CCM_ANALOG_PLL_USB1_CLR:
 539    case CCM_ANALOG_PLL_USB2_CLR:
 540    case CCM_ANALOG_PLL_SYS_CLR:
 541    case CCM_ANALOG_PLL_AUDIO_CLR:
 542    case CCM_ANALOG_PLL_VIDEO_CLR:
 543    case CCM_ANALOG_PLL_MLB_CLR:
 544    case CCM_ANALOG_PLL_ENET_CLR:
 545    case CCM_ANALOG_PFD_480_CLR:
 546    case CCM_ANALOG_PFD_528_CLR:
 547    case CCM_ANALOG_MISC0_CLR:
 548    case PMU_MISC1_CLR:
 549    case CCM_ANALOG_MISC2_CLR:
 550    case USB_ANALOG_USB1_VBUS_DETECT_CLR:
 551    case USB_ANALOG_USB1_CHRG_DETECT_CLR:
 552    case USB_ANALOG_USB1_MISC_CLR:
 553    case USB_ANALOG_USB2_VBUS_DETECT_CLR:
 554    case USB_ANALOG_USB2_CHRG_DETECT_CLR:
 555    case USB_ANALOG_USB2_MISC_CLR:
 556        /*
 557         * All REG_NAME_CLR register access are in fact targeting the
 558         * the REG_NAME register.
 559         */
 560        value = s->analog[index - 2];
 561        break;
 562    case CCM_ANALOG_PLL_ARM_TOG:
 563    case CCM_ANALOG_PLL_USB1_TOG:
 564    case CCM_ANALOG_PLL_USB2_TOG:
 565    case CCM_ANALOG_PLL_SYS_TOG:
 566    case CCM_ANALOG_PLL_AUDIO_TOG:
 567    case CCM_ANALOG_PLL_VIDEO_TOG:
 568    case CCM_ANALOG_PLL_MLB_TOG:
 569    case CCM_ANALOG_PLL_ENET_TOG:
 570    case CCM_ANALOG_PFD_480_TOG:
 571    case CCM_ANALOG_PFD_528_TOG:
 572    case CCM_ANALOG_MISC0_TOG:
 573    case PMU_MISC1_TOG:
 574    case CCM_ANALOG_MISC2_TOG:
 575    case USB_ANALOG_USB1_VBUS_DETECT_TOG:
 576    case USB_ANALOG_USB1_CHRG_DETECT_TOG:
 577    case USB_ANALOG_USB1_MISC_TOG:
 578    case USB_ANALOG_USB2_VBUS_DETECT_TOG:
 579    case USB_ANALOG_USB2_CHRG_DETECT_TOG:
 580    case USB_ANALOG_USB2_MISC_TOG:
 581        /*
 582         * All REG_NAME_TOG register access are in fact targeting the
 583         * the REG_NAME register.
 584         */
 585        value = s->analog[index - 3];
 586        break;
 587    default:
 588        value = s->analog[index];
 589        break;
 590    }
 591
 592    DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_analog_reg_name(index), value);
 593
 594    return (uint64_t)value;
 595}
 596
 597static void imx6_analog_write(void *opaque, hwaddr offset, uint64_t value,
 598                              unsigned size)
 599{
 600    uint32_t index = offset >> 2;
 601    IMX6CCMState *s = (IMX6CCMState *)opaque;
 602
 603    DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_analog_reg_name(index),
 604            (uint32_t)value);
 605
 606    switch (index) {
 607    case CCM_ANALOG_PLL_ARM_SET:
 608    case CCM_ANALOG_PLL_USB1_SET:
 609    case CCM_ANALOG_PLL_USB2_SET:
 610    case CCM_ANALOG_PLL_SYS_SET:
 611    case CCM_ANALOG_PLL_AUDIO_SET:
 612    case CCM_ANALOG_PLL_VIDEO_SET:
 613    case CCM_ANALOG_PLL_MLB_SET:
 614    case CCM_ANALOG_PLL_ENET_SET:
 615    case CCM_ANALOG_PFD_480_SET:
 616    case CCM_ANALOG_PFD_528_SET:
 617    case CCM_ANALOG_MISC0_SET:
 618    case PMU_MISC1_SET:
 619    case CCM_ANALOG_MISC2_SET:
 620    case USB_ANALOG_USB1_VBUS_DETECT_SET:
 621    case USB_ANALOG_USB1_CHRG_DETECT_SET:
 622    case USB_ANALOG_USB1_MISC_SET:
 623    case USB_ANALOG_USB2_VBUS_DETECT_SET:
 624    case USB_ANALOG_USB2_CHRG_DETECT_SET:
 625    case USB_ANALOG_USB2_MISC_SET:
 626        /*
 627         * All REG_NAME_SET register access are in fact targeting the
 628         * the REG_NAME register. So we change the value of the
 629         * REG_NAME register, setting bits passed in the value.
 630         */
 631        s->analog[index - 1] |= value;
 632        break;
 633    case CCM_ANALOG_PLL_ARM_CLR:
 634    case CCM_ANALOG_PLL_USB1_CLR:
 635    case CCM_ANALOG_PLL_USB2_CLR:
 636    case CCM_ANALOG_PLL_SYS_CLR:
 637    case CCM_ANALOG_PLL_AUDIO_CLR:
 638    case CCM_ANALOG_PLL_VIDEO_CLR:
 639    case CCM_ANALOG_PLL_MLB_CLR:
 640    case CCM_ANALOG_PLL_ENET_CLR:
 641    case CCM_ANALOG_PFD_480_CLR:
 642    case CCM_ANALOG_PFD_528_CLR:
 643    case CCM_ANALOG_MISC0_CLR:
 644    case PMU_MISC1_CLR:
 645    case CCM_ANALOG_MISC2_CLR:
 646    case USB_ANALOG_USB1_VBUS_DETECT_CLR:
 647    case USB_ANALOG_USB1_CHRG_DETECT_CLR:
 648    case USB_ANALOG_USB1_MISC_CLR:
 649    case USB_ANALOG_USB2_VBUS_DETECT_CLR:
 650    case USB_ANALOG_USB2_CHRG_DETECT_CLR:
 651    case USB_ANALOG_USB2_MISC_CLR:
 652        /*
 653         * All REG_NAME_CLR register access are in fact targeting the
 654         * the REG_NAME register. So we change the value of the
 655         * REG_NAME register, unsetting bits passed in the value.
 656         */
 657        s->analog[index - 2] &= ~value;
 658        break;
 659    case CCM_ANALOG_PLL_ARM_TOG:
 660    case CCM_ANALOG_PLL_USB1_TOG:
 661    case CCM_ANALOG_PLL_USB2_TOG:
 662    case CCM_ANALOG_PLL_SYS_TOG:
 663    case CCM_ANALOG_PLL_AUDIO_TOG:
 664    case CCM_ANALOG_PLL_VIDEO_TOG:
 665    case CCM_ANALOG_PLL_MLB_TOG:
 666    case CCM_ANALOG_PLL_ENET_TOG:
 667    case CCM_ANALOG_PFD_480_TOG:
 668    case CCM_ANALOG_PFD_528_TOG:
 669    case CCM_ANALOG_MISC0_TOG:
 670    case PMU_MISC1_TOG:
 671    case CCM_ANALOG_MISC2_TOG:
 672    case USB_ANALOG_USB1_VBUS_DETECT_TOG:
 673    case USB_ANALOG_USB1_CHRG_DETECT_TOG:
 674    case USB_ANALOG_USB1_MISC_TOG:
 675    case USB_ANALOG_USB2_VBUS_DETECT_TOG:
 676    case USB_ANALOG_USB2_CHRG_DETECT_TOG:
 677    case USB_ANALOG_USB2_MISC_TOG:
 678        /*
 679         * All REG_NAME_TOG register access are in fact targeting the
 680         * the REG_NAME register. So we change the value of the
 681         * REG_NAME register, toggling bits passed in the value.
 682         */
 683        s->analog[index - 3] ^= value;
 684        break;
 685    default:
 686        /*
 687         * We will do a better implementation later. In particular some bits
 688         * cannot be written to.
 689         */
 690        s->analog[index] = value;
 691        break;
 692    }
 693}
 694
 695static const struct MemoryRegionOps imx6_ccm_ops = {
 696    .read = imx6_ccm_read,
 697    .write = imx6_ccm_write,
 698    .endianness = DEVICE_NATIVE_ENDIAN,
 699    .valid = {
 700        /*
 701         * Our device would not work correctly if the guest was doing
 702         * unaligned access. This might not be a limitation on the real
 703         * device but in practice there is no reason for a guest to access
 704         * this device unaligned.
 705         */
 706        .min_access_size = 4,
 707        .max_access_size = 4,
 708        .unaligned = false,
 709    },
 710};
 711
 712static const struct MemoryRegionOps imx6_analog_ops = {
 713    .read = imx6_analog_read,
 714    .write = imx6_analog_write,
 715    .endianness = DEVICE_NATIVE_ENDIAN,
 716    .valid = {
 717        /*
 718         * Our device would not work correctly if the guest was doing
 719         * unaligned access. This might not be a limitation on the real
 720         * device but in practice there is no reason for a guest to access
 721         * this device unaligned.
 722         */
 723        .min_access_size = 4,
 724        .max_access_size = 4,
 725        .unaligned = false,
 726    },
 727};
 728
 729static void imx6_ccm_init(Object *obj)
 730{
 731    DeviceState *dev = DEVICE(obj);
 732    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
 733    IMX6CCMState *s = IMX6_CCM(obj);
 734
 735    /* initialize a container for the all memory range */
 736    memory_region_init(&s->container, OBJECT(dev), TYPE_IMX6_CCM, 0x5000);
 737
 738    /* We initialize an IO memory region for the CCM part */
 739    memory_region_init_io(&s->ioccm, OBJECT(dev), &imx6_ccm_ops, s,
 740                          TYPE_IMX6_CCM ".ccm", CCM_MAX * sizeof(uint32_t));
 741
 742    /* Add the CCM as a subregion at offset 0 */
 743    memory_region_add_subregion(&s->container, 0, &s->ioccm);
 744
 745    /* We initialize an IO memory region for the ANALOG part */
 746    memory_region_init_io(&s->ioanalog, OBJECT(dev), &imx6_analog_ops, s,
 747                          TYPE_IMX6_CCM ".analog",
 748                          CCM_ANALOG_MAX * sizeof(uint32_t));
 749
 750    /* Add the ANALOG as a subregion at offset 0x4000 */
 751    memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
 752
 753    sysbus_init_mmio(sd, &s->container);
 754}
 755
 756static void imx6_ccm_class_init(ObjectClass *klass, void *data)
 757{
 758    DeviceClass *dc = DEVICE_CLASS(klass);
 759    IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
 760
 761    dc->reset = imx6_ccm_reset;
 762    dc->vmsd = &vmstate_imx6_ccm;
 763    dc->desc = "i.MX6 Clock Control Module";
 764
 765    ccm->get_clock_frequency = imx6_ccm_get_clock_frequency;
 766}
 767
 768static const TypeInfo imx6_ccm_info = {
 769    .name          = TYPE_IMX6_CCM,
 770    .parent        = TYPE_IMX_CCM,
 771    .instance_size = sizeof(IMX6CCMState),
 772    .instance_init = imx6_ccm_init,
 773    .class_init    = imx6_ccm_class_init,
 774};
 775
 776static void imx6_ccm_register_types(void)
 777{
 778    type_register_static(&imx6_ccm_info);
 779}
 780
 781type_init(imx6_ccm_register_types)
 782