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