qemu

Форк
0
/
aspeed_peci.c 
152 строки · 4.2 Кб
1
/*
2
 * Aspeed PECI Controller
3
 *
4
 * Copyright (c) Meta Platforms, Inc. and affiliates. (http://www.meta.com)
5
 *
6
 * This code is licensed under the GPL version 2 or later. See the COPYING
7
 * file in the top-level directory.
8
 */
9

10
#include "qemu/osdep.h"
11
#include "qemu/log.h"
12
#include "hw/irq.h"
13
#include "hw/misc/aspeed_peci.h"
14
#include "hw/registerfields.h"
15
#include "trace.h"
16

17
#define ASPEED_PECI_CC_RSP_SUCCESS (0x40U)
18

19
/* Command Register */
20
REG32(PECI_CMD, 0x08)
21
    FIELD(PECI_CMD, FIRE, 0, 1)
22

23
/* Interrupt Control Register */
24
REG32(PECI_INT_CTRL, 0x18)
25

26
/* Interrupt Status Register */
27
REG32(PECI_INT_STS, 0x1C)
28
    FIELD(PECI_INT_STS, CMD_DONE, 0, 1)
29

30
/* Rx/Tx Data Buffer Registers */
31
REG32(PECI_WR_DATA0, 0x20)
32
REG32(PECI_RD_DATA0, 0x30)
33

34
static void aspeed_peci_raise_interrupt(AspeedPECIState *s, uint32_t status)
35
{
36
    trace_aspeed_peci_raise_interrupt(s->regs[R_PECI_INT_CTRL], status);
37

38
    s->regs[R_PECI_INT_STS] = s->regs[R_PECI_INT_CTRL] & status;
39
    if (!s->regs[R_PECI_INT_STS]) {
40
        return;
41
    }
42
    qemu_irq_raise(s->irq);
43
}
44

45
static uint64_t aspeed_peci_read(void *opaque, hwaddr offset, unsigned size)
46
{
47
    AspeedPECIState *s = ASPEED_PECI(opaque);
48
    uint64_t data;
49

50
    if (offset >= ASPEED_PECI_NR_REGS << 2) {
51
        qemu_log_mask(LOG_GUEST_ERROR,
52
                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
53
                      __func__, offset);
54
        return 0;
55
    }
56
    data = s->regs[offset >> 2];
57

58
    trace_aspeed_peci_read(offset, data);
59
    return data;
60
}
61

62
static void aspeed_peci_write(void *opaque, hwaddr offset, uint64_t data,
63
                              unsigned size)
64
{
65
    AspeedPECIState *s = ASPEED_PECI(opaque);
66

67
    trace_aspeed_peci_write(offset, data);
68

69
    if (offset >= ASPEED_PECI_NR_REGS << 2) {
70
        qemu_log_mask(LOG_GUEST_ERROR,
71
                      "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
72
                      __func__, offset);
73
        return;
74
    }
75

76
    switch (offset) {
77
    case A_PECI_INT_STS:
78
        s->regs[R_PECI_INT_STS] &= ~data;
79
        if (!s->regs[R_PECI_INT_STS]) {
80
            qemu_irq_lower(s->irq);
81
        }
82
        break;
83
    case A_PECI_CMD:
84
        /*
85
         * Only the FIRE bit is writable. Once the command is complete, it
86
         * should be cleared. Since we complete the command immediately, the
87
         * value is not stored in the register array.
88
         */
89
        if (!FIELD_EX32(data, PECI_CMD, FIRE)) {
90
            break;
91
        }
92
        if (s->regs[R_PECI_INT_STS]) {
93
            qemu_log_mask(LOG_GUEST_ERROR, "%s: Interrupt status must be "
94
                          "cleared before firing another command: 0x%08x\n",
95
                          __func__, s->regs[R_PECI_INT_STS]);
96
            break;
97
        }
98
        s->regs[R_PECI_RD_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
99
        s->regs[R_PECI_WR_DATA0] = ASPEED_PECI_CC_RSP_SUCCESS;
100
        aspeed_peci_raise_interrupt(s,
101
                                    FIELD_DP32(0, PECI_INT_STS, CMD_DONE, 1));
102
        break;
103
    default:
104
        s->regs[offset / sizeof(s->regs[0])] = data;
105
        break;
106
    }
107
}
108

109
static const MemoryRegionOps aspeed_peci_ops = {
110
    .read = aspeed_peci_read,
111
    .write = aspeed_peci_write,
112
    .endianness = DEVICE_LITTLE_ENDIAN,
113
};
114

115
static void aspeed_peci_realize(DeviceState *dev, Error **errp)
116
{
117
    AspeedPECIState *s = ASPEED_PECI(dev);
118
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
119

120
    memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_peci_ops, s,
121
                          TYPE_ASPEED_PECI, 0x1000);
122
    sysbus_init_mmio(sbd, &s->mmio);
123
    sysbus_init_irq(sbd, &s->irq);
124
}
125

126
static void aspeed_peci_reset(DeviceState *dev)
127
{
128
    AspeedPECIState *s = ASPEED_PECI(dev);
129

130
    memset(s->regs, 0, sizeof(s->regs));
131
}
132

133
static void aspeed_peci_class_init(ObjectClass *klass, void *data)
134
{
135
    DeviceClass *dc = DEVICE_CLASS(klass);
136

137
    dc->realize = aspeed_peci_realize;
138
    dc->reset = aspeed_peci_reset;
139
    dc->desc = "Aspeed PECI Controller";
140
}
141

142
static const TypeInfo aspeed_peci_types[] = {
143
    {
144
        .name = TYPE_ASPEED_PECI,
145
        .parent = TYPE_SYS_BUS_DEVICE,
146
        .instance_size = sizeof(AspeedPECIState),
147
        .class_init = aspeed_peci_class_init,
148
        .abstract = false,
149
    },
150
};
151

152
DEFINE_TYPES(aspeed_peci_types);
153

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

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

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

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