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