qemu

Форк
0
/
imx6_ccm.c 
770 строк · 22.1 Кб
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 "migration/vmstate.h"
16
#include "qemu/log.h"
17
#include "qemu/module.h"
18
#include "trace.h"
19

20
static const char *imx6_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
        snprintf(unknown, sizeof(unknown), "%u ?", reg);
89
        return unknown;
90
    }
91
}
92

93
static const char *imx6_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_MLB:
161
        return "PLL_MLB";
162
    case CCM_ANALOG_PLL_MLB_SET:
163
        return "PLL_MLB_SET";
164
    case CCM_ANALOG_PLL_MLB_CLR:
165
        return "PLL_MLB_CLR";
166
    case CCM_ANALOG_PLL_MLB_TOG:
167
        return "PLL_MLB_TOG";
168
    case CCM_ANALOG_PLL_ENET:
169
        return "PLL_ENET";
170
    case CCM_ANALOG_PLL_ENET_SET:
171
        return "PLL_ENET_SET";
172
    case CCM_ANALOG_PLL_ENET_CLR:
173
        return "PLL_ENET_CLR";
174
    case CCM_ANALOG_PLL_ENET_TOG:
175
        return "PLL_ENET_TOG";
176
    case CCM_ANALOG_PFD_480:
177
        return "PFD_480";
178
    case CCM_ANALOG_PFD_480_SET:
179
        return "PFD_480_SET";
180
    case CCM_ANALOG_PFD_480_CLR:
181
        return "PFD_480_CLR";
182
    case CCM_ANALOG_PFD_480_TOG:
183
        return "PFD_480_TOG";
184
    case CCM_ANALOG_PFD_528:
185
        return "PFD_528";
186
    case CCM_ANALOG_PFD_528_SET:
187
        return "PFD_528_SET";
188
    case CCM_ANALOG_PFD_528_CLR:
189
        return "PFD_528_CLR";
190
    case CCM_ANALOG_PFD_528_TOG:
191
        return "PFD_528_TOG";
192
    case CCM_ANALOG_MISC0:
193
        return "MISC0";
194
    case CCM_ANALOG_MISC0_SET:
195
        return "MISC0_SET";
196
    case CCM_ANALOG_MISC0_CLR:
197
        return "MISC0_CLR";
198
    case CCM_ANALOG_MISC0_TOG:
199
        return "MISC0_TOG";
200
    case CCM_ANALOG_MISC2:
201
        return "MISC2";
202
    case CCM_ANALOG_MISC2_SET:
203
        return "MISC2_SET";
204
    case CCM_ANALOG_MISC2_CLR:
205
        return "MISC2_CLR";
206
    case CCM_ANALOG_MISC2_TOG:
207
        return "MISC2_TOG";
208
    case PMU_REG_1P1:
209
        return "PMU_REG_1P1";
210
    case PMU_REG_3P0:
211
        return "PMU_REG_3P0";
212
    case PMU_REG_2P5:
213
        return "PMU_REG_2P5";
214
    case PMU_REG_CORE:
215
        return "PMU_REG_CORE";
216
    case PMU_MISC1:
217
        return "PMU_MISC1";
218
    case PMU_MISC1_SET:
219
        return "PMU_MISC1_SET";
220
    case PMU_MISC1_CLR:
221
        return "PMU_MISC1_CLR";
222
    case PMU_MISC1_TOG:
223
        return "PMU_MISC1_TOG";
224
    case USB_ANALOG_DIGPROG:
225
        return "USB_ANALOG_DIGPROG";
226
    default:
227
        snprintf(unknown, sizeof(unknown), "%u ?", reg);
228
        return unknown;
229
    }
230
}
231

232
#define CKIH_FREQ 24000000 /* 24MHz crystal input */
233

234
static const VMStateDescription vmstate_imx6_ccm = {
235
    .name = TYPE_IMX6_CCM,
236
    .version_id = 1,
237
    .minimum_version_id = 1,
238
    .fields = (const VMStateField[]) {
239
        VMSTATE_UINT32_ARRAY(ccm, IMX6CCMState, CCM_MAX),
240
        VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_MAX),
241
        VMSTATE_END_OF_LIST()
242
    },
243
};
244

245
static uint64_t imx6_analog_get_pll2_clk(IMX6CCMState *dev)
246
{
247
    uint64_t freq = 24000000;
248

249
    if (EXTRACT(dev->analog[CCM_ANALOG_PLL_SYS], DIV_SELECT)) {
250
        freq *= 22;
251
    } else {
252
        freq *= 20;
253
    }
254

255
    trace_imx6_analog_get_pll2_clk(freq);
256

257
    return freq;
258
}
259

260
static uint64_t imx6_analog_get_pll2_pfd0_clk(IMX6CCMState *dev)
261
{
262
    uint64_t freq = 0;
263

264
    freq = imx6_analog_get_pll2_clk(dev) * 18
265
           / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD0_FRAC);
266

267
    trace_imx6_analog_get_pll2_pfd0_clk(freq);
268

269
    return freq;
270
}
271

272
static uint64_t imx6_analog_get_pll2_pfd2_clk(IMX6CCMState *dev)
273
{
274
    uint64_t freq = 0;
275

276
    freq = imx6_analog_get_pll2_clk(dev) * 18
277
           / EXTRACT(dev->analog[CCM_ANALOG_PFD_528], PFD2_FRAC);
278

279
    trace_imx6_analog_get_pll2_pfd2_clk(freq);
280

281
    return freq;
282
}
283

284
static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
285
{
286
    uint64_t freq = 0;
287

288
    switch (EXTRACT(dev->ccm[CCM_CBCMR], PRE_PERIPH_CLK_SEL)) {
289
    case 0:
290
        freq = imx6_analog_get_pll2_clk(dev);
291
        break;
292
    case 1:
293
        freq = imx6_analog_get_pll2_pfd2_clk(dev);
294
        break;
295
    case 2:
296
        freq = imx6_analog_get_pll2_pfd0_clk(dev);
297
        break;
298
    case 3:
299
        freq = imx6_analog_get_pll2_pfd2_clk(dev) / 2;
300
        break;
301
    default:
302
        /* We should never get there */
303
        g_assert_not_reached();
304
        break;
305
    }
306

307
    trace_imx6_analog_get_periph_clk(freq);
308

309
    return freq;
310
}
311

312
static uint64_t imx6_ccm_get_ahb_clk(IMX6CCMState *dev)
313
{
314
    uint64_t freq = 0;
315

316
    freq = imx6_analog_get_periph_clk(dev)
317
           / (1 + EXTRACT(dev->ccm[CCM_CBCDR], AHB_PODF));
318

319
    trace_imx6_ccm_get_ahb_clk(freq);
320

321
    return freq;
322
}
323

324
static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev)
325
{
326
    uint64_t freq = 0;
327

328
    freq = imx6_ccm_get_ahb_clk(dev)
329
           / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));
330

331
    trace_imx6_ccm_get_ipg_clk(freq);
332

333
    return freq;
334
}
335

336
static uint64_t imx6_ccm_get_per_clk(IMX6CCMState *dev)
337
{
338
    uint64_t freq = 0;
339

340
    freq = imx6_ccm_get_ipg_clk(dev)
341
           / (1 + EXTRACT(dev->ccm[CCM_CSCMR1], PERCLK_PODF));
342

343
    trace_imx6_ccm_get_per_clk(freq);
344

345
    return freq;
346
}
347

348
static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
349
{
350
    uint32_t freq = 0;
351
    IMX6CCMState *s = IMX6_CCM(dev);
352

353
    switch (clock) {
354
    case CLK_NONE:
355
        break;
356
    case CLK_IPG:
357
        freq = imx6_ccm_get_ipg_clk(s);
358
        break;
359
    case CLK_IPG_HIGH:
360
        freq = imx6_ccm_get_per_clk(s);
361
        break;
362
    case CLK_32k:
363
        freq = CKIL_FREQ;
364
        break;
365
    case CLK_HIGH:
366
        freq = 24000000;
367
        break;
368
    case CLK_HIGH_DIV:
369
        freq = 24000000 / 8;
370
        break;
371
    default:
372
        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
373
                      TYPE_IMX6_CCM, __func__, clock);
374
        break;
375
    }
376

377
    trace_imx6_ccm_get_clock_frequency(clock, freq);
378

379
    return freq;
380
}
381

382
static void imx6_ccm_reset(DeviceState *dev)
383
{
384
    IMX6CCMState *s = IMX6_CCM(dev);
385

386
    trace_imx6_ccm_reset();
387

388
    s->ccm[CCM_CCR] = 0x040116FF;
389
    s->ccm[CCM_CCDR] = 0x00000000;
390
    s->ccm[CCM_CSR] = 0x00000010;
391
    s->ccm[CCM_CCSR] = 0x00000100;
392
    s->ccm[CCM_CACRR] = 0x00000000;
393
    s->ccm[CCM_CBCDR] = 0x00018D40;
394
    s->ccm[CCM_CBCMR] = 0x00022324;
395
    s->ccm[CCM_CSCMR1] = 0x00F00000;
396
    s->ccm[CCM_CSCMR2] = 0x02B92F06;
397
    s->ccm[CCM_CSCDR1] = 0x00490B00;
398
    s->ccm[CCM_CS1CDR] = 0x0EC102C1;
399
    s->ccm[CCM_CS2CDR] = 0x000736C1;
400
    s->ccm[CCM_CDCDR] = 0x33F71F92;
401
    s->ccm[CCM_CHSCCDR] = 0x0002A150;
402
    s->ccm[CCM_CSCDR2] = 0x0002A150;
403
    s->ccm[CCM_CSCDR3] = 0x00014841;
404
    s->ccm[CCM_CDHIPR] = 0x00000000;
405
    s->ccm[CCM_CTOR] = 0x00000000;
406
    s->ccm[CCM_CLPCR] = 0x00000079;
407
    s->ccm[CCM_CISR] = 0x00000000;
408
    s->ccm[CCM_CIMR] = 0xFFFFFFFF;
409
    s->ccm[CCM_CCOSR] = 0x000A0001;
410
    s->ccm[CCM_CGPR] = 0x0000FE62;
411
    s->ccm[CCM_CCGR0] = 0xFFFFFFFF;
412
    s->ccm[CCM_CCGR1] = 0xFFFFFFFF;
413
    s->ccm[CCM_CCGR2] = 0xFC3FFFFF;
414
    s->ccm[CCM_CCGR3] = 0xFFFFFFFF;
415
    s->ccm[CCM_CCGR4] = 0xFFFFFFFF;
416
    s->ccm[CCM_CCGR5] = 0xFFFFFFFF;
417
    s->ccm[CCM_CCGR6] = 0xFFFFFFFF;
418
    s->ccm[CCM_CMEOR] = 0xFFFFFFFF;
419

420
    s->analog[CCM_ANALOG_PLL_ARM] = 0x00013042;
421
    s->analog[CCM_ANALOG_PLL_USB1] = 0x00012000;
422
    s->analog[CCM_ANALOG_PLL_USB2] = 0x00012000;
423
    s->analog[CCM_ANALOG_PLL_SYS] = 0x00013001;
424
    s->analog[CCM_ANALOG_PLL_SYS_SS] = 0x00000000;
425
    s->analog[CCM_ANALOG_PLL_SYS_NUM] = 0x00000000;
426
    s->analog[CCM_ANALOG_PLL_SYS_DENOM] = 0x00000012;
427
    s->analog[CCM_ANALOG_PLL_AUDIO] = 0x00011006;
428
    s->analog[CCM_ANALOG_PLL_AUDIO_NUM] = 0x05F5E100;
429
    s->analog[CCM_ANALOG_PLL_AUDIO_DENOM] = 0x2964619C;
430
    s->analog[CCM_ANALOG_PLL_VIDEO] = 0x0001100C;
431
    s->analog[CCM_ANALOG_PLL_VIDEO_NUM] = 0x05F5E100;
432
    s->analog[CCM_ANALOG_PLL_VIDEO_DENOM] = 0x10A24447;
433
    s->analog[CCM_ANALOG_PLL_MLB] = 0x00010000;
434
    s->analog[CCM_ANALOG_PLL_ENET] = 0x00011001;
435
    s->analog[CCM_ANALOG_PFD_480] = 0x1311100C;
436
    s->analog[CCM_ANALOG_PFD_528] = 0x1018101B;
437

438
    s->analog[PMU_REG_1P1] = 0x00001073;
439
    s->analog[PMU_REG_3P0] = 0x00000F74;
440
    s->analog[PMU_REG_2P5] = 0x00005071;
441
    s->analog[PMU_REG_CORE] = 0x00402010;
442
    s->analog[PMU_MISC0] = 0x04000080;
443
    s->analog[PMU_MISC1] = 0x00000000;
444
    s->analog[PMU_MISC2] = 0x00272727;
445

446
    s->analog[USB_ANALOG_USB1_VBUS_DETECT] = 0x00000004;
447
    s->analog[USB_ANALOG_USB1_CHRG_DETECT] = 0x00000000;
448
    s->analog[USB_ANALOG_USB1_VBUS_DETECT_STAT] = 0x00000000;
449
    s->analog[USB_ANALOG_USB1_CHRG_DETECT_STAT] = 0x00000000;
450
    s->analog[USB_ANALOG_USB1_MISC] = 0x00000002;
451
    s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x00000004;
452
    s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
453
    s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
454
    s->analog[USB_ANALOG_DIGPROG] = 0x00630000;
455

456
    /* all PLLs need to be locked */
457
    s->analog[CCM_ANALOG_PLL_ARM]   |= CCM_ANALOG_PLL_LOCK;
458
    s->analog[CCM_ANALOG_PLL_USB1]  |= CCM_ANALOG_PLL_LOCK;
459
    s->analog[CCM_ANALOG_PLL_USB2]  |= CCM_ANALOG_PLL_LOCK;
460
    s->analog[CCM_ANALOG_PLL_SYS]   |= CCM_ANALOG_PLL_LOCK;
461
    s->analog[CCM_ANALOG_PLL_AUDIO] |= CCM_ANALOG_PLL_LOCK;
462
    s->analog[CCM_ANALOG_PLL_VIDEO] |= CCM_ANALOG_PLL_LOCK;
463
    s->analog[CCM_ANALOG_PLL_MLB]   |= CCM_ANALOG_PLL_LOCK;
464
    s->analog[CCM_ANALOG_PLL_ENET]  |= CCM_ANALOG_PLL_LOCK;
465
}
466

467
static uint64_t imx6_ccm_read(void *opaque, hwaddr offset, unsigned size)
468
{
469
    uint32_t value = 0;
470
    uint32_t index = offset >> 2;
471
    IMX6CCMState *s = (IMX6CCMState *)opaque;
472

473
    value = s->ccm[index];
474

475
    trace_imx6_ccm_read(imx6_ccm_reg_name(index), value);
476

477
    return (uint64_t)value;
478
}
479

480
static void imx6_ccm_write(void *opaque, hwaddr offset, uint64_t value,
481
                           unsigned size)
482
{
483
    uint32_t index = offset >> 2;
484
    IMX6CCMState *s = (IMX6CCMState *)opaque;
485

486
    trace_imx6_ccm_write(imx6_ccm_reg_name(index), (uint32_t)value);
487

488
    /*
489
     * We will do a better implementation later. In particular some bits
490
     * cannot be written to.
491
     */
492
    s->ccm[index] = (uint32_t)value;
493
}
494

495
static uint64_t imx6_analog_read(void *opaque, hwaddr offset, unsigned size)
496
{
497
    uint32_t value;
498
    uint32_t index = offset >> 2;
499
    IMX6CCMState *s = (IMX6CCMState *)opaque;
500

501
    switch (index) {
502
    case CCM_ANALOG_PLL_ARM_SET:
503
    case CCM_ANALOG_PLL_USB1_SET:
504
    case CCM_ANALOG_PLL_USB2_SET:
505
    case CCM_ANALOG_PLL_SYS_SET:
506
    case CCM_ANALOG_PLL_AUDIO_SET:
507
    case CCM_ANALOG_PLL_VIDEO_SET:
508
    case CCM_ANALOG_PLL_MLB_SET:
509
    case CCM_ANALOG_PLL_ENET_SET:
510
    case CCM_ANALOG_PFD_480_SET:
511
    case CCM_ANALOG_PFD_528_SET:
512
    case CCM_ANALOG_MISC0_SET:
513
    case PMU_MISC1_SET:
514
    case CCM_ANALOG_MISC2_SET:
515
    case USB_ANALOG_USB1_VBUS_DETECT_SET:
516
    case USB_ANALOG_USB1_CHRG_DETECT_SET:
517
    case USB_ANALOG_USB1_MISC_SET:
518
    case USB_ANALOG_USB2_VBUS_DETECT_SET:
519
    case USB_ANALOG_USB2_CHRG_DETECT_SET:
520
    case USB_ANALOG_USB2_MISC_SET:
521
        /*
522
         * All REG_NAME_SET register access are in fact targeting the
523
         * the REG_NAME register.
524
         */
525
        value = s->analog[index - 1];
526
        break;
527
    case CCM_ANALOG_PLL_ARM_CLR:
528
    case CCM_ANALOG_PLL_USB1_CLR:
529
    case CCM_ANALOG_PLL_USB2_CLR:
530
    case CCM_ANALOG_PLL_SYS_CLR:
531
    case CCM_ANALOG_PLL_AUDIO_CLR:
532
    case CCM_ANALOG_PLL_VIDEO_CLR:
533
    case CCM_ANALOG_PLL_MLB_CLR:
534
    case CCM_ANALOG_PLL_ENET_CLR:
535
    case CCM_ANALOG_PFD_480_CLR:
536
    case CCM_ANALOG_PFD_528_CLR:
537
    case CCM_ANALOG_MISC0_CLR:
538
    case PMU_MISC1_CLR:
539
    case CCM_ANALOG_MISC2_CLR:
540
    case USB_ANALOG_USB1_VBUS_DETECT_CLR:
541
    case USB_ANALOG_USB1_CHRG_DETECT_CLR:
542
    case USB_ANALOG_USB1_MISC_CLR:
543
    case USB_ANALOG_USB2_VBUS_DETECT_CLR:
544
    case USB_ANALOG_USB2_CHRG_DETECT_CLR:
545
    case USB_ANALOG_USB2_MISC_CLR:
546
        /*
547
         * All REG_NAME_CLR register access are in fact targeting the
548
         * the REG_NAME register.
549
         */
550
        value = s->analog[index - 2];
551
        break;
552
    case CCM_ANALOG_PLL_ARM_TOG:
553
    case CCM_ANALOG_PLL_USB1_TOG:
554
    case CCM_ANALOG_PLL_USB2_TOG:
555
    case CCM_ANALOG_PLL_SYS_TOG:
556
    case CCM_ANALOG_PLL_AUDIO_TOG:
557
    case CCM_ANALOG_PLL_VIDEO_TOG:
558
    case CCM_ANALOG_PLL_MLB_TOG:
559
    case CCM_ANALOG_PLL_ENET_TOG:
560
    case CCM_ANALOG_PFD_480_TOG:
561
    case CCM_ANALOG_PFD_528_TOG:
562
    case CCM_ANALOG_MISC0_TOG:
563
    case PMU_MISC1_TOG:
564
    case CCM_ANALOG_MISC2_TOG:
565
    case USB_ANALOG_USB1_VBUS_DETECT_TOG:
566
    case USB_ANALOG_USB1_CHRG_DETECT_TOG:
567
    case USB_ANALOG_USB1_MISC_TOG:
568
    case USB_ANALOG_USB2_VBUS_DETECT_TOG:
569
    case USB_ANALOG_USB2_CHRG_DETECT_TOG:
570
    case USB_ANALOG_USB2_MISC_TOG:
571
        /*
572
         * All REG_NAME_TOG register access are in fact targeting the
573
         * the REG_NAME register.
574
         */
575
        value = s->analog[index - 3];
576
        break;
577
    default:
578
        value = s->analog[index];
579
        break;
580
    }
581

582
    trace_imx6_analog_read(imx6_analog_reg_name(index), value);
583

584
    return (uint64_t)value;
585
}
586

587
static void imx6_analog_write(void *opaque, hwaddr offset, uint64_t value,
588
                              unsigned size)
589
{
590
    uint32_t index = offset >> 2;
591
    IMX6CCMState *s = (IMX6CCMState *)opaque;
592

593
    trace_imx6_analog_write(imx6_analog_reg_name(index), (uint32_t)value);
594

595
    switch (index) {
596
    case CCM_ANALOG_PLL_ARM_SET:
597
    case CCM_ANALOG_PLL_USB1_SET:
598
    case CCM_ANALOG_PLL_USB2_SET:
599
    case CCM_ANALOG_PLL_SYS_SET:
600
    case CCM_ANALOG_PLL_AUDIO_SET:
601
    case CCM_ANALOG_PLL_VIDEO_SET:
602
    case CCM_ANALOG_PLL_MLB_SET:
603
    case CCM_ANALOG_PLL_ENET_SET:
604
    case CCM_ANALOG_PFD_480_SET:
605
    case CCM_ANALOG_PFD_528_SET:
606
    case CCM_ANALOG_MISC0_SET:
607
    case PMU_MISC1_SET:
608
    case CCM_ANALOG_MISC2_SET:
609
    case USB_ANALOG_USB1_VBUS_DETECT_SET:
610
    case USB_ANALOG_USB1_CHRG_DETECT_SET:
611
    case USB_ANALOG_USB1_MISC_SET:
612
    case USB_ANALOG_USB2_VBUS_DETECT_SET:
613
    case USB_ANALOG_USB2_CHRG_DETECT_SET:
614
    case USB_ANALOG_USB2_MISC_SET:
615
        /*
616
         * All REG_NAME_SET register access are in fact targeting the
617
         * the REG_NAME register. So we change the value of the
618
         * REG_NAME register, setting bits passed in the value.
619
         */
620
        s->analog[index - 1] |= value;
621
        break;
622
    case CCM_ANALOG_PLL_ARM_CLR:
623
    case CCM_ANALOG_PLL_USB1_CLR:
624
    case CCM_ANALOG_PLL_USB2_CLR:
625
    case CCM_ANALOG_PLL_SYS_CLR:
626
    case CCM_ANALOG_PLL_AUDIO_CLR:
627
    case CCM_ANALOG_PLL_VIDEO_CLR:
628
    case CCM_ANALOG_PLL_MLB_CLR:
629
    case CCM_ANALOG_PLL_ENET_CLR:
630
    case CCM_ANALOG_PFD_480_CLR:
631
    case CCM_ANALOG_PFD_528_CLR:
632
    case CCM_ANALOG_MISC0_CLR:
633
    case PMU_MISC1_CLR:
634
    case CCM_ANALOG_MISC2_CLR:
635
    case USB_ANALOG_USB1_VBUS_DETECT_CLR:
636
    case USB_ANALOG_USB1_CHRG_DETECT_CLR:
637
    case USB_ANALOG_USB1_MISC_CLR:
638
    case USB_ANALOG_USB2_VBUS_DETECT_CLR:
639
    case USB_ANALOG_USB2_CHRG_DETECT_CLR:
640
    case USB_ANALOG_USB2_MISC_CLR:
641
        /*
642
         * All REG_NAME_CLR register access are in fact targeting the
643
         * the REG_NAME register. So we change the value of the
644
         * REG_NAME register, unsetting bits passed in the value.
645
         */
646
        s->analog[index - 2] &= ~value;
647
        break;
648
    case CCM_ANALOG_PLL_ARM_TOG:
649
    case CCM_ANALOG_PLL_USB1_TOG:
650
    case CCM_ANALOG_PLL_USB2_TOG:
651
    case CCM_ANALOG_PLL_SYS_TOG:
652
    case CCM_ANALOG_PLL_AUDIO_TOG:
653
    case CCM_ANALOG_PLL_VIDEO_TOG:
654
    case CCM_ANALOG_PLL_MLB_TOG:
655
    case CCM_ANALOG_PLL_ENET_TOG:
656
    case CCM_ANALOG_PFD_480_TOG:
657
    case CCM_ANALOG_PFD_528_TOG:
658
    case CCM_ANALOG_MISC0_TOG:
659
    case PMU_MISC1_TOG:
660
    case CCM_ANALOG_MISC2_TOG:
661
    case USB_ANALOG_USB1_VBUS_DETECT_TOG:
662
    case USB_ANALOG_USB1_CHRG_DETECT_TOG:
663
    case USB_ANALOG_USB1_MISC_TOG:
664
    case USB_ANALOG_USB2_VBUS_DETECT_TOG:
665
    case USB_ANALOG_USB2_CHRG_DETECT_TOG:
666
    case USB_ANALOG_USB2_MISC_TOG:
667
        /*
668
         * All REG_NAME_TOG register access are in fact targeting the
669
         * the REG_NAME register. So we change the value of the
670
         * REG_NAME register, toggling bits passed in the value.
671
         */
672
        s->analog[index - 3] ^= value;
673
        break;
674
    default:
675
        /*
676
         * We will do a better implementation later. In particular some bits
677
         * cannot be written to.
678
         */
679
        s->analog[index] = value;
680
        break;
681
    }
682
}
683

684
static const struct MemoryRegionOps imx6_ccm_ops = {
685
    .read = imx6_ccm_read,
686
    .write = imx6_ccm_write,
687
    .endianness = DEVICE_NATIVE_ENDIAN,
688
    .valid = {
689
        /*
690
         * Our device would not work correctly if the guest was doing
691
         * unaligned access. This might not be a limitation on the real
692
         * device but in practice there is no reason for a guest to access
693
         * this device unaligned.
694
         */
695
        .min_access_size = 4,
696
        .max_access_size = 4,
697
        .unaligned = false,
698
    },
699
};
700

701
static const struct MemoryRegionOps imx6_analog_ops = {
702
    .read = imx6_analog_read,
703
    .write = imx6_analog_write,
704
    .endianness = DEVICE_NATIVE_ENDIAN,
705
    .valid = {
706
        /*
707
         * Our device would not work correctly if the guest was doing
708
         * unaligned access. This might not be a limitation on the real
709
         * device but in practice there is no reason for a guest to access
710
         * this device unaligned.
711
         */
712
        .min_access_size = 4,
713
        .max_access_size = 4,
714
        .unaligned = false,
715
    },
716
};
717

718
static void imx6_ccm_init(Object *obj)
719
{
720
    DeviceState *dev = DEVICE(obj);
721
    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
722
    IMX6CCMState *s = IMX6_CCM(obj);
723

724
    /* initialize a container for the all memory range */
725
    memory_region_init(&s->container, OBJECT(dev), TYPE_IMX6_CCM, 0x5000);
726

727
    /* We initialize an IO memory region for the CCM part */
728
    memory_region_init_io(&s->ioccm, OBJECT(dev), &imx6_ccm_ops, s,
729
                          TYPE_IMX6_CCM ".ccm", CCM_MAX * sizeof(uint32_t));
730

731
    /* Add the CCM as a subregion at offset 0 */
732
    memory_region_add_subregion(&s->container, 0, &s->ioccm);
733

734
    /* We initialize an IO memory region for the ANALOG part */
735
    memory_region_init_io(&s->ioanalog, OBJECT(dev), &imx6_analog_ops, s,
736
                          TYPE_IMX6_CCM ".analog",
737
                          CCM_ANALOG_MAX * sizeof(uint32_t));
738

739
    /* Add the ANALOG as a subregion at offset 0x4000 */
740
    memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
741

742
    sysbus_init_mmio(sd, &s->container);
743
}
744

745
static void imx6_ccm_class_init(ObjectClass *klass, void *data)
746
{
747
    DeviceClass *dc = DEVICE_CLASS(klass);
748
    IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
749

750
    dc->reset = imx6_ccm_reset;
751
    dc->vmsd = &vmstate_imx6_ccm;
752
    dc->desc = "i.MX6 Clock Control Module";
753

754
    ccm->get_clock_frequency = imx6_ccm_get_clock_frequency;
755
}
756

757
static const TypeInfo imx6_ccm_info = {
758
    .name          = TYPE_IMX6_CCM,
759
    .parent        = TYPE_IMX_CCM,
760
    .instance_size = sizeof(IMX6CCMState),
761
    .instance_init = imx6_ccm_init,
762
    .class_init    = imx6_ccm_class_init,
763
};
764

765
static void imx6_ccm_register_types(void)
766
{
767
    type_register_static(&imx6_ccm_info);
768
}
769

770
type_init(imx6_ccm_register_types)
771

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.