qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

i.MX: Add i.MX6 CCM and ANALOG device.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Message-id: 9fa80b4d8c5d0f50c94e77d74f952a7a665e168f.1456868959.git.jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Jean-Christophe Dubois and committed by
Peter Maydell
a66d815c d552f675

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