qemu

Форк
0
/
pl011.c 
664 строки · 17.5 Кб
1
/*
2
 * Arm PrimeCell PL011 UART
3
 *
4
 * Copyright (c) 2006 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licensed under the GPL.
8
 */
9

10
/*
11
 * QEMU interface:
12
 *  + sysbus MMIO region 0: device registers
13
 *  + sysbus IRQ 0: UARTINTR (combined interrupt line)
14
 *  + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
15
 *  + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
16
 *  + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
17
 *  + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
18
 *  + sysbus IRQ 5: UARTEINTR (error interrupt line)
19
 */
20

21
#include "qemu/osdep.h"
22
#include "qapi/error.h"
23
#include "hw/char/pl011.h"
24
#include "hw/irq.h"
25
#include "hw/sysbus.h"
26
#include "hw/qdev-clock.h"
27
#include "hw/qdev-properties.h"
28
#include "hw/qdev-properties-system.h"
29
#include "migration/vmstate.h"
30
#include "chardev/char-fe.h"
31
#include "chardev/char-serial.h"
32
#include "qemu/log.h"
33
#include "qemu/module.h"
34
#include "trace.h"
35

36
DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
37
{
38
    DeviceState *dev;
39
    SysBusDevice *s;
40

41
    dev = qdev_new("pl011");
42
    s = SYS_BUS_DEVICE(dev);
43
    qdev_prop_set_chr(dev, "chardev", chr);
44
    sysbus_realize_and_unref(s, &error_fatal);
45
    sysbus_mmio_map(s, 0, addr);
46
    sysbus_connect_irq(s, 0, irq);
47

48
    return dev;
49
}
50

51
/* Flag Register, UARTFR */
52
#define PL011_FLAG_RI   0x100
53
#define PL011_FLAG_TXFE 0x80
54
#define PL011_FLAG_RXFF 0x40
55
#define PL011_FLAG_TXFF 0x20
56
#define PL011_FLAG_RXFE 0x10
57
#define PL011_FLAG_DCD  0x04
58
#define PL011_FLAG_DSR  0x02
59
#define PL011_FLAG_CTS  0x01
60

61
/* Data Register, UARTDR */
62
#define DR_BE   (1 << 10)
63

64
/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
65
#define INT_OE (1 << 10)
66
#define INT_BE (1 << 9)
67
#define INT_PE (1 << 8)
68
#define INT_FE (1 << 7)
69
#define INT_RT (1 << 6)
70
#define INT_TX (1 << 5)
71
#define INT_RX (1 << 4)
72
#define INT_DSR (1 << 3)
73
#define INT_DCD (1 << 2)
74
#define INT_CTS (1 << 1)
75
#define INT_RI (1 << 0)
76
#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
77
#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
78

79
/* Line Control Register, UARTLCR_H */
80
#define LCR_FEN     (1 << 4)
81
#define LCR_BRK     (1 << 0)
82

83
/* Control Register, UARTCR */
84
#define CR_OUT2     (1 << 13)
85
#define CR_OUT1     (1 << 12)
86
#define CR_RTS      (1 << 11)
87
#define CR_DTR      (1 << 10)
88
#define CR_LBE      (1 << 7)
89

90
/* Integer Baud Rate Divider, UARTIBRD */
91
#define IBRD_MASK 0x3f
92

93
/* Fractional Baud Rate Divider, UARTFBRD */
94
#define FBRD_MASK 0xffff
95

96
static const unsigned char pl011_id_arm[8] =
97
  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
98
static const unsigned char pl011_id_luminary[8] =
99
  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
100

101
static const char *pl011_regname(hwaddr offset)
102
{
103
    static const char *const rname[] = {
104
        [0] = "DR", [1] = "RSR", [6] = "FR", [8] = "ILPR", [9] = "IBRD",
105
        [10] = "FBRD", [11] = "LCRH", [12] = "CR", [13] = "IFLS", [14] = "IMSC",
106
        [15] = "RIS", [16] = "MIS", [17] = "ICR", [18] = "DMACR",
107
    };
108
    unsigned idx = offset >> 2;
109

110
    if (idx < ARRAY_SIZE(rname) && rname[idx]) {
111
        return rname[idx];
112
    }
113
    if (idx >= 0x3f8 && idx <= 0x400) {
114
        return "ID";
115
    }
116
    return "UNKN";
117
}
118

119
/* Which bits in the interrupt status matter for each outbound IRQ line ? */
120
static const uint32_t irqmask[] = {
121
    INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
122
    INT_RX,
123
    INT_TX,
124
    INT_RT,
125
    INT_MS,
126
    INT_E,
127
};
128

129
static void pl011_update(PL011State *s)
130
{
131
    uint32_t flags;
132
    int i;
133

134
    flags = s->int_level & s->int_enabled;
135
    trace_pl011_irq_state(flags != 0);
136
    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
137
        qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
138
    }
139
}
140

141
static bool pl011_is_fifo_enabled(PL011State *s)
142
{
143
    return (s->lcr & LCR_FEN) != 0;
144
}
145

146
static inline unsigned pl011_get_fifo_depth(PL011State *s)
147
{
148
    /* Note: FIFO depth is expected to be power-of-2 */
149
    return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
150
}
151

152
static inline void pl011_reset_fifo(PL011State *s)
153
{
154
    s->read_count = 0;
155
    s->read_pos = 0;
156

157
    /* Reset FIFO flags */
158
    s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
159
    s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
160
}
161

162
static uint64_t pl011_read(void *opaque, hwaddr offset,
163
                           unsigned size)
164
{
165
    PL011State *s = (PL011State *)opaque;
166
    uint32_t c;
167
    uint64_t r;
168

169
    switch (offset >> 2) {
170
    case 0: /* UARTDR */
171
        s->flags &= ~PL011_FLAG_RXFF;
172
        c = s->read_fifo[s->read_pos];
173
        if (s->read_count > 0) {
174
            s->read_count--;
175
            s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
176
        }
177
        if (s->read_count == 0) {
178
            s->flags |= PL011_FLAG_RXFE;
179
        }
180
        if (s->read_count == s->read_trigger - 1)
181
            s->int_level &= ~ INT_RX;
182
        trace_pl011_read_fifo(s->read_count);
183
        s->rsr = c >> 8;
184
        pl011_update(s);
185
        qemu_chr_fe_accept_input(&s->chr);
186
        r = c;
187
        break;
188
    case 1: /* UARTRSR */
189
        r = s->rsr;
190
        break;
191
    case 6: /* UARTFR */
192
        r = s->flags;
193
        break;
194
    case 8: /* UARTILPR */
195
        r = s->ilpr;
196
        break;
197
    case 9: /* UARTIBRD */
198
        r = s->ibrd;
199
        break;
200
    case 10: /* UARTFBRD */
201
        r = s->fbrd;
202
        break;
203
    case 11: /* UARTLCR_H */
204
        r = s->lcr;
205
        break;
206
    case 12: /* UARTCR */
207
        r = s->cr;
208
        break;
209
    case 13: /* UARTIFLS */
210
        r = s->ifl;
211
        break;
212
    case 14: /* UARTIMSC */
213
        r = s->int_enabled;
214
        break;
215
    case 15: /* UARTRIS */
216
        r = s->int_level;
217
        break;
218
    case 16: /* UARTMIS */
219
        r = s->int_level & s->int_enabled;
220
        break;
221
    case 18: /* UARTDMACR */
222
        r = s->dmacr;
223
        break;
224
    case 0x3f8 ... 0x400:
225
        r = s->id[(offset - 0xfe0) >> 2];
226
        break;
227
    default:
228
        qemu_log_mask(LOG_GUEST_ERROR,
229
                      "pl011_read: Bad offset 0x%x\n", (int)offset);
230
        r = 0;
231
        break;
232
    }
233

234
    trace_pl011_read(offset, r, pl011_regname(offset));
235
    return r;
236
}
237

238
static void pl011_set_read_trigger(PL011State *s)
239
{
240
#if 0
241
    /* The docs say the RX interrupt is triggered when the FIFO exceeds
242
       the threshold.  However linux only reads the FIFO in response to an
243
       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
244
       to make things work.  */
245
    if (s->lcr & LCR_FEN)
246
        s->read_trigger = (s->ifl >> 1) & 0x1c;
247
    else
248
#endif
249
        s->read_trigger = 1;
250
}
251

252
static unsigned int pl011_get_baudrate(const PL011State *s)
253
{
254
    uint64_t clk;
255

256
    if (s->ibrd == 0) {
257
        return 0;
258
    }
259

260
    clk = clock_get_hz(s->clk);
261
    return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
262
}
263

264
static void pl011_trace_baudrate_change(const PL011State *s)
265
{
266
    trace_pl011_baudrate_change(pl011_get_baudrate(s),
267
                                clock_get_hz(s->clk),
268
                                s->ibrd, s->fbrd);
269
}
270

271
static bool pl011_loopback_enabled(PL011State *s)
272
{
273
    return !!(s->cr & CR_LBE);
274
}
275

276
static void pl011_loopback_mdmctrl(PL011State *s)
277
{
278
    uint32_t cr, fr, il;
279

280
    if (!pl011_loopback_enabled(s)) {
281
        return;
282
    }
283

284
    /*
285
     * Loopback software-driven modem control outputs to modem status inputs:
286
     *   FR.RI  <= CR.Out2
287
     *   FR.DCD <= CR.Out1
288
     *   FR.CTS <= CR.RTS
289
     *   FR.DSR <= CR.DTR
290
     *
291
     * The loopback happens immediately even if this call is triggered
292
     * by setting only CR.LBE.
293
     *
294
     * CTS/RTS updates due to enabled hardware flow controls are not
295
     * dealt with here.
296
     */
297
    cr = s->cr;
298
    fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
299
                      PL011_FLAG_DSR | PL011_FLAG_CTS);
300
    fr |= (cr & CR_OUT2) ? PL011_FLAG_RI  : 0;
301
    fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
302
    fr |= (cr & CR_RTS)  ? PL011_FLAG_CTS : 0;
303
    fr |= (cr & CR_DTR)  ? PL011_FLAG_DSR : 0;
304

305
    /* Change interrupts based on updated FR */
306
    il = s->int_level & ~(INT_DSR | INT_DCD | INT_CTS | INT_RI);
307
    il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
308
    il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
309
    il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
310
    il |= (fr & PL011_FLAG_RI)  ? INT_RI  : 0;
311

312
    s->flags = fr;
313
    s->int_level = il;
314
    pl011_update(s);
315
}
316

317
static void pl011_put_fifo(void *opaque, uint32_t value);
318

319
static void pl011_loopback_tx(PL011State *s, uint32_t value)
320
{
321
    if (!pl011_loopback_enabled(s)) {
322
        return;
323
    }
324

325
    /*
326
     * Caveat:
327
     *
328
     * In real hardware, TX loopback happens at the serial-bit level
329
     * and then reassembled by the RX logics back into bytes and placed
330
     * into the RX fifo. That is, loopback happens after TX fifo.
331
     *
332
     * Because the real hardware TX fifo is time-drained at the frame
333
     * rate governed by the configured serial format, some loopback
334
     * bytes in TX fifo may still be able to get into the RX fifo
335
     * that could be full at times while being drained at software
336
     * pace.
337
     *
338
     * In such scenario, the RX draining pace is the major factor
339
     * deciding which loopback bytes get into the RX fifo, unless
340
     * hardware flow-control is enabled.
341
     *
342
     * For simplicity, the above described is not emulated.
343
     */
344
    pl011_put_fifo(s, value);
345
}
346

347
static void pl011_loopback_break(PL011State *s, int brk_enable)
348
{
349
    if (brk_enable) {
350
        pl011_loopback_tx(s, DR_BE);
351
    }
352
}
353

354
static void pl011_write(void *opaque, hwaddr offset,
355
                        uint64_t value, unsigned size)
356
{
357
    PL011State *s = (PL011State *)opaque;
358
    unsigned char ch;
359

360
    trace_pl011_write(offset, value, pl011_regname(offset));
361

362
    switch (offset >> 2) {
363
    case 0: /* UARTDR */
364
        /* ??? Check if transmitter is enabled.  */
365
        ch = value;
366
        /* XXX this blocks entire thread. Rewrite to use
367
         * qemu_chr_fe_write and background I/O callbacks */
368
        qemu_chr_fe_write_all(&s->chr, &ch, 1);
369
        pl011_loopback_tx(s, ch);
370
        s->int_level |= INT_TX;
371
        pl011_update(s);
372
        break;
373
    case 1: /* UARTRSR/UARTECR */
374
        s->rsr = 0;
375
        break;
376
    case 6: /* UARTFR */
377
        /* Writes to Flag register are ignored.  */
378
        break;
379
    case 8: /* UARTILPR */
380
        s->ilpr = value;
381
        break;
382
    case 9: /* UARTIBRD */
383
        s->ibrd = value & IBRD_MASK;
384
        pl011_trace_baudrate_change(s);
385
        break;
386
    case 10: /* UARTFBRD */
387
        s->fbrd = value & FBRD_MASK;
388
        pl011_trace_baudrate_change(s);
389
        break;
390
    case 11: /* UARTLCR_H */
391
        /* Reset the FIFO state on FIFO enable or disable */
392
        if ((s->lcr ^ value) & LCR_FEN) {
393
            pl011_reset_fifo(s);
394
        }
395
        if ((s->lcr ^ value) & LCR_BRK) {
396
            int break_enable = value & LCR_BRK;
397
            qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
398
                              &break_enable);
399
            pl011_loopback_break(s, break_enable);
400
        }
401
        s->lcr = value;
402
        pl011_set_read_trigger(s);
403
        break;
404
    case 12: /* UARTCR */
405
        /* ??? Need to implement the enable bit.  */
406
        s->cr = value;
407
        pl011_loopback_mdmctrl(s);
408
        break;
409
    case 13: /* UARTIFS */
410
        s->ifl = value;
411
        pl011_set_read_trigger(s);
412
        break;
413
    case 14: /* UARTIMSC */
414
        s->int_enabled = value;
415
        pl011_update(s);
416
        break;
417
    case 17: /* UARTICR */
418
        s->int_level &= ~value;
419
        pl011_update(s);
420
        break;
421
    case 18: /* UARTDMACR */
422
        s->dmacr = value;
423
        if (value & 3) {
424
            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
425
        }
426
        break;
427
    default:
428
        qemu_log_mask(LOG_GUEST_ERROR,
429
                      "pl011_write: Bad offset 0x%x\n", (int)offset);
430
    }
431
}
432

433
static int pl011_can_receive(void *opaque)
434
{
435
    PL011State *s = (PL011State *)opaque;
436
    int r;
437

438
    r = s->read_count < pl011_get_fifo_depth(s);
439
    trace_pl011_can_receive(s->lcr, s->read_count, r);
440
    return r;
441
}
442

443
static void pl011_put_fifo(void *opaque, uint32_t value)
444
{
445
    PL011State *s = (PL011State *)opaque;
446
    int slot;
447
    unsigned pipe_depth;
448

449
    pipe_depth = pl011_get_fifo_depth(s);
450
    slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
451
    s->read_fifo[slot] = value;
452
    s->read_count++;
453
    s->flags &= ~PL011_FLAG_RXFE;
454
    trace_pl011_put_fifo(value, s->read_count);
455
    if (s->read_count == pipe_depth) {
456
        trace_pl011_put_fifo_full();
457
        s->flags |= PL011_FLAG_RXFF;
458
    }
459
    if (s->read_count == s->read_trigger) {
460
        s->int_level |= INT_RX;
461
        pl011_update(s);
462
    }
463
}
464

465
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
466
{
467
    /*
468
     * In loopback mode, the RX input signal is internally disconnected
469
     * from the entire receiving logics; thus, all inputs are ignored,
470
     * and BREAK detection on RX input signal is also not performed.
471
     */
472
    if (pl011_loopback_enabled(opaque)) {
473
        return;
474
    }
475

476
    pl011_put_fifo(opaque, *buf);
477
}
478

479
static void pl011_event(void *opaque, QEMUChrEvent event)
480
{
481
    if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) {
482
        pl011_put_fifo(opaque, DR_BE);
483
    }
484
}
485

486
static void pl011_clock_update(void *opaque, ClockEvent event)
487
{
488
    PL011State *s = PL011(opaque);
489

490
    pl011_trace_baudrate_change(s);
491
}
492

493
static const MemoryRegionOps pl011_ops = {
494
    .read = pl011_read,
495
    .write = pl011_write,
496
    .endianness = DEVICE_NATIVE_ENDIAN,
497
    .impl.min_access_size = 4,
498
    .impl.max_access_size = 4,
499
};
500

501
static bool pl011_clock_needed(void *opaque)
502
{
503
    PL011State *s = PL011(opaque);
504

505
    return s->migrate_clk;
506
}
507

508
static const VMStateDescription vmstate_pl011_clock = {
509
    .name = "pl011/clock",
510
    .version_id = 1,
511
    .minimum_version_id = 1,
512
    .needed = pl011_clock_needed,
513
    .fields = (const VMStateField[]) {
514
        VMSTATE_CLOCK(clk, PL011State),
515
        VMSTATE_END_OF_LIST()
516
    }
517
};
518

519
static int pl011_post_load(void *opaque, int version_id)
520
{
521
    PL011State* s = opaque;
522

523
    /* Sanity-check input state */
524
    if (s->read_pos >= ARRAY_SIZE(s->read_fifo) ||
525
        s->read_count > ARRAY_SIZE(s->read_fifo)) {
526
        return -1;
527
    }
528

529
    if (!pl011_is_fifo_enabled(s) && s->read_count > 0 && s->read_pos > 0) {
530
        /*
531
         * Older versions of PL011 didn't ensure that the single
532
         * character in the FIFO in FIFO-disabled mode is in
533
         * element 0 of the array; convert to follow the current
534
         * code's assumptions.
535
         */
536
        s->read_fifo[0] = s->read_fifo[s->read_pos];
537
        s->read_pos = 0;
538
    }
539

540
    s->ibrd &= IBRD_MASK;
541
    s->fbrd &= FBRD_MASK;
542

543
    return 0;
544
}
545

546
static const VMStateDescription vmstate_pl011 = {
547
    .name = "pl011",
548
    .version_id = 2,
549
    .minimum_version_id = 2,
550
    .post_load = pl011_post_load,
551
    .fields = (const VMStateField[]) {
552
        VMSTATE_UINT32(readbuff, PL011State),
553
        VMSTATE_UINT32(flags, PL011State),
554
        VMSTATE_UINT32(lcr, PL011State),
555
        VMSTATE_UINT32(rsr, PL011State),
556
        VMSTATE_UINT32(cr, PL011State),
557
        VMSTATE_UINT32(dmacr, PL011State),
558
        VMSTATE_UINT32(int_enabled, PL011State),
559
        VMSTATE_UINT32(int_level, PL011State),
560
        VMSTATE_UINT32_ARRAY(read_fifo, PL011State, PL011_FIFO_DEPTH),
561
        VMSTATE_UINT32(ilpr, PL011State),
562
        VMSTATE_UINT32(ibrd, PL011State),
563
        VMSTATE_UINT32(fbrd, PL011State),
564
        VMSTATE_UINT32(ifl, PL011State),
565
        VMSTATE_INT32(read_pos, PL011State),
566
        VMSTATE_INT32(read_count, PL011State),
567
        VMSTATE_INT32(read_trigger, PL011State),
568
        VMSTATE_END_OF_LIST()
569
    },
570
    .subsections = (const VMStateDescription * const []) {
571
        &vmstate_pl011_clock,
572
        NULL
573
    }
574
};
575

576
static Property pl011_properties[] = {
577
    DEFINE_PROP_CHR("chardev", PL011State, chr),
578
    DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
579
    DEFINE_PROP_END_OF_LIST(),
580
};
581

582
static void pl011_init(Object *obj)
583
{
584
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
585
    PL011State *s = PL011(obj);
586
    int i;
587

588
    memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
589
    sysbus_init_mmio(sbd, &s->iomem);
590
    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
591
        sysbus_init_irq(sbd, &s->irq[i]);
592
    }
593

594
    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
595
                                ClockUpdate);
596

597
    s->id = pl011_id_arm;
598
}
599

600
static void pl011_realize(DeviceState *dev, Error **errp)
601
{
602
    PL011State *s = PL011(dev);
603

604
    qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
605
                             pl011_event, NULL, s, NULL, true);
606
}
607

608
static void pl011_reset(DeviceState *dev)
609
{
610
    PL011State *s = PL011(dev);
611

612
    s->lcr = 0;
613
    s->rsr = 0;
614
    s->dmacr = 0;
615
    s->int_enabled = 0;
616
    s->int_level = 0;
617
    s->ilpr = 0;
618
    s->ibrd = 0;
619
    s->fbrd = 0;
620
    s->read_trigger = 1;
621
    s->ifl = 0x12;
622
    s->cr = 0x300;
623
    s->flags = 0;
624
    pl011_reset_fifo(s);
625
}
626

627
static void pl011_class_init(ObjectClass *oc, void *data)
628
{
629
    DeviceClass *dc = DEVICE_CLASS(oc);
630

631
    dc->realize = pl011_realize;
632
    dc->reset = pl011_reset;
633
    dc->vmsd = &vmstate_pl011;
634
    device_class_set_props(dc, pl011_properties);
635
}
636

637
static const TypeInfo pl011_arm_info = {
638
    .name          = TYPE_PL011,
639
    .parent        = TYPE_SYS_BUS_DEVICE,
640
    .instance_size = sizeof(PL011State),
641
    .instance_init = pl011_init,
642
    .class_init    = pl011_class_init,
643
};
644

645
static void pl011_luminary_init(Object *obj)
646
{
647
    PL011State *s = PL011(obj);
648

649
    s->id = pl011_id_luminary;
650
}
651

652
static const TypeInfo pl011_luminary_info = {
653
    .name          = TYPE_PL011_LUMINARY,
654
    .parent        = TYPE_PL011,
655
    .instance_init = pl011_luminary_init,
656
};
657

658
static void pl011_register_types(void)
659
{
660
    type_register_static(&pl011_arm_info);
661
    type_register_static(&pl011_luminary_info);
662
}
663

664
type_init(pl011_register_types)
665

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

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

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

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