qemu

Форк
0
/
sifive_gpio.c 
397 строк · 9.8 Кб
1
/*
2
 * SiFive System-on-Chip general purpose input/output register definition
3
 *
4
 * Copyright 2019 AdaCore
5
 *
6
 * Base on nrf51_gpio.c:
7
 *
8
 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
9
 *
10
 * This code is licensed under the GPL version 2 or later.  See
11
 * the COPYING file in the top-level directory.
12
 */
13

14
#include "qemu/osdep.h"
15
#include "qemu/log.h"
16
#include "hw/irq.h"
17
#include "hw/qdev-properties.h"
18
#include "hw/gpio/sifive_gpio.h"
19
#include "migration/vmstate.h"
20
#include "trace.h"
21

22
static void update_output_irq(SIFIVEGPIOState *s)
23
{
24
    uint32_t pending;
25
    uint32_t pin;
26

27
    pending = s->high_ip & s->high_ie;
28
    pending |= s->low_ip & s->low_ie;
29
    pending |= s->rise_ip & s->rise_ie;
30
    pending |= s->fall_ip & s->fall_ie;
31

32
    for (int i = 0; i < s->ngpio; i++) {
33
        pin = 1 << i;
34
        qemu_set_irq(s->irq[i], (pending & pin) != 0);
35
        trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
36
    }
37
}
38

39
static void update_state(SIFIVEGPIOState *s)
40
{
41
    size_t i;
42
    bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
43
        rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
44

45
    for (i = 0; i < s->ngpio; i++) {
46

47
        prev_ival = extract32(s->value, i, 1);
48
        in        = extract32(s->in, i, 1);
49
        in_mask   = extract32(s->in_mask, i, 1);
50
        port      = extract32(s->port, i, 1);
51
        out_xor   = extract32(s->out_xor, i, 1);
52
        pull      = extract32(s->pue, i, 1);
53
        output_en = extract32(s->output_en, i, 1);
54
        input_en  = extract32(s->input_en, i, 1);
55
        rise_ip   = extract32(s->rise_ip, i, 1);
56
        fall_ip   = extract32(s->fall_ip, i, 1);
57
        low_ip    = extract32(s->low_ip, i, 1);
58
        high_ip   = extract32(s->high_ip, i, 1);
59

60
        /* Output value (IOF not supported) */
61
        oval = output_en && (port ^ out_xor);
62

63
        /* Pin both driven externally and internally */
64
        if (output_en && in_mask) {
65
            qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
66
        }
67

68
        if (in_mask) {
69
            /* The pin is driven by external device */
70
            actual_value = in;
71
        } else if (output_en) {
72
            /* The pin is driven by internal circuit */
73
            actual_value = oval;
74
        } else {
75
            /* Floating? Apply pull-up resistor */
76
            actual_value = pull;
77
        }
78

79
        if (output_en) {
80
            qemu_set_irq(s->output[i], actual_value);
81
        }
82

83
        /* Input value */
84
        ival = input_en && actual_value;
85

86
        /* Interrupts */
87
        high_ip = high_ip || ival;
88
        s->high_ip = deposit32(s->high_ip, i, 1, high_ip);
89

90
        low_ip = low_ip || !ival;
91
        s->low_ip = deposit32(s->low_ip,  i, 1, low_ip);
92

93
        rise_ip = rise_ip || (ival && !prev_ival);
94
        s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip);
95

96
        fall_ip = fall_ip || (!ival && prev_ival);
97
        s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip);
98

99
        /* Update value */
100
        s->value = deposit32(s->value, i, 1, ival);
101
    }
102
    update_output_irq(s);
103
}
104

105
static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
106
{
107
    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
108
    uint64_t r = 0;
109

110
    switch (offset) {
111
    case SIFIVE_GPIO_REG_VALUE:
112
        r = s->value;
113
        break;
114

115
    case SIFIVE_GPIO_REG_INPUT_EN:
116
        r = s->input_en;
117
        break;
118

119
    case SIFIVE_GPIO_REG_OUTPUT_EN:
120
        r = s->output_en;
121
        break;
122

123
    case SIFIVE_GPIO_REG_PORT:
124
        r = s->port;
125
        break;
126

127
    case SIFIVE_GPIO_REG_PUE:
128
        r = s->pue;
129
        break;
130

131
    case SIFIVE_GPIO_REG_DS:
132
        r = s->ds;
133
        break;
134

135
    case SIFIVE_GPIO_REG_RISE_IE:
136
        r = s->rise_ie;
137
        break;
138

139
    case SIFIVE_GPIO_REG_RISE_IP:
140
        r = s->rise_ip;
141
        break;
142

143
    case SIFIVE_GPIO_REG_FALL_IE:
144
        r = s->fall_ie;
145
        break;
146

147
    case SIFIVE_GPIO_REG_FALL_IP:
148
        r = s->fall_ip;
149
        break;
150

151
    case SIFIVE_GPIO_REG_HIGH_IE:
152
        r = s->high_ie;
153
        break;
154

155
    case SIFIVE_GPIO_REG_HIGH_IP:
156
        r = s->high_ip;
157
        break;
158

159
    case SIFIVE_GPIO_REG_LOW_IE:
160
        r = s->low_ie;
161
        break;
162

163
    case SIFIVE_GPIO_REG_LOW_IP:
164
        r = s->low_ip;
165
        break;
166

167
    case SIFIVE_GPIO_REG_IOF_EN:
168
        r = s->iof_en;
169
        break;
170

171
    case SIFIVE_GPIO_REG_IOF_SEL:
172
        r = s->iof_sel;
173
        break;
174

175
    case SIFIVE_GPIO_REG_OUT_XOR:
176
        r = s->out_xor;
177
        break;
178

179
    default:
180
        qemu_log_mask(LOG_GUEST_ERROR,
181
                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
182
                      __func__, offset);
183
    }
184

185
    trace_sifive_gpio_read(offset, r);
186

187
    return r;
188
}
189

190
static void sifive_gpio_write(void *opaque, hwaddr offset,
191
                              uint64_t value, unsigned int size)
192
{
193
    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
194

195
    trace_sifive_gpio_write(offset, value);
196

197
    switch (offset) {
198

199
    case SIFIVE_GPIO_REG_INPUT_EN:
200
        s->input_en = value;
201
        break;
202

203
    case SIFIVE_GPIO_REG_OUTPUT_EN:
204
        s->output_en = value;
205
        break;
206

207
    case SIFIVE_GPIO_REG_PORT:
208
        s->port = value;
209
        break;
210

211
    case SIFIVE_GPIO_REG_PUE:
212
        s->pue = value;
213
        break;
214

215
    case SIFIVE_GPIO_REG_DS:
216
        s->ds = value;
217
        break;
218

219
    case SIFIVE_GPIO_REG_RISE_IE:
220
        s->rise_ie = value;
221
        break;
222

223
    case SIFIVE_GPIO_REG_RISE_IP:
224
         /* Write 1 to clear */
225
        s->rise_ip &= ~value;
226
        break;
227

228
    case SIFIVE_GPIO_REG_FALL_IE:
229
        s->fall_ie = value;
230
        break;
231

232
    case SIFIVE_GPIO_REG_FALL_IP:
233
         /* Write 1 to clear */
234
        s->fall_ip &= ~value;
235
        break;
236

237
    case SIFIVE_GPIO_REG_HIGH_IE:
238
        s->high_ie = value;
239
        break;
240

241
    case SIFIVE_GPIO_REG_HIGH_IP:
242
         /* Write 1 to clear */
243
        s->high_ip &= ~value;
244
        break;
245

246
    case SIFIVE_GPIO_REG_LOW_IE:
247
        s->low_ie = value;
248
        break;
249

250
    case SIFIVE_GPIO_REG_LOW_IP:
251
         /* Write 1 to clear */
252
        s->low_ip &= ~value;
253
        break;
254

255
    case SIFIVE_GPIO_REG_IOF_EN:
256
        s->iof_en = value;
257
        break;
258

259
    case SIFIVE_GPIO_REG_IOF_SEL:
260
        s->iof_sel = value;
261
        break;
262

263
    case SIFIVE_GPIO_REG_OUT_XOR:
264
        s->out_xor = value;
265
        break;
266

267
    default:
268
        qemu_log_mask(LOG_GUEST_ERROR,
269
                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
270
                      __func__, offset);
271
    }
272

273
    update_state(s);
274
}
275

276
static const MemoryRegionOps gpio_ops = {
277
    .read =  sifive_gpio_read,
278
    .write = sifive_gpio_write,
279
    .endianness = DEVICE_LITTLE_ENDIAN,
280
    .impl.min_access_size = 4,
281
    .impl.max_access_size = 4,
282
};
283

284
static void sifive_gpio_set(void *opaque, int line, int value)
285
{
286
    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
287

288
    trace_sifive_gpio_set(line, value);
289

290
    assert(line >= 0 && line < SIFIVE_GPIO_PINS);
291

292
    s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
293
    if (value >= 0) {
294
        s->in = deposit32(s->in, line, 1, value != 0);
295
    }
296

297
    update_state(s);
298
}
299

300
static void sifive_gpio_reset(DeviceState *dev)
301
{
302
    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
303

304
    s->value = 0;
305
    s->input_en = 0;
306
    s->output_en = 0;
307
    s->port = 0;
308
    s->pue = 0;
309
    s->ds = 0;
310
    s->rise_ie = 0;
311
    s->rise_ip = 0;
312
    s->fall_ie = 0;
313
    s->fall_ip = 0;
314
    s->high_ie = 0;
315
    s->high_ip = 0;
316
    s->low_ie = 0;
317
    s->low_ip = 0;
318
    s->iof_en = 0;
319
    s->iof_sel = 0;
320
    s->out_xor = 0;
321
    s->in = 0;
322
    s->in_mask = 0;
323
}
324

325
static const VMStateDescription vmstate_sifive_gpio = {
326
    .name = TYPE_SIFIVE_GPIO,
327
    .version_id = 1,
328
    .minimum_version_id = 1,
329
    .fields = (const VMStateField[]) {
330
        VMSTATE_UINT32(value,     SIFIVEGPIOState),
331
        VMSTATE_UINT32(input_en,  SIFIVEGPIOState),
332
        VMSTATE_UINT32(output_en, SIFIVEGPIOState),
333
        VMSTATE_UINT32(port,      SIFIVEGPIOState),
334
        VMSTATE_UINT32(pue,       SIFIVEGPIOState),
335
        VMSTATE_UINT32(rise_ie,   SIFIVEGPIOState),
336
        VMSTATE_UINT32(rise_ip,   SIFIVEGPIOState),
337
        VMSTATE_UINT32(fall_ie,   SIFIVEGPIOState),
338
        VMSTATE_UINT32(fall_ip,   SIFIVEGPIOState),
339
        VMSTATE_UINT32(high_ie,   SIFIVEGPIOState),
340
        VMSTATE_UINT32(high_ip,   SIFIVEGPIOState),
341
        VMSTATE_UINT32(low_ie,    SIFIVEGPIOState),
342
        VMSTATE_UINT32(low_ip,    SIFIVEGPIOState),
343
        VMSTATE_UINT32(iof_en,    SIFIVEGPIOState),
344
        VMSTATE_UINT32(iof_sel,   SIFIVEGPIOState),
345
        VMSTATE_UINT32(out_xor,   SIFIVEGPIOState),
346
        VMSTATE_UINT32(in,        SIFIVEGPIOState),
347
        VMSTATE_UINT32(in_mask,   SIFIVEGPIOState),
348
        VMSTATE_END_OF_LIST()
349
    }
350
};
351

352
static Property sifive_gpio_properties[] = {
353
    DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
354
    DEFINE_PROP_END_OF_LIST(),
355
};
356

357
static void sifive_gpio_realize(DeviceState *dev, Error **errp)
358
{
359
    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
360

361
    memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
362
            TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
363

364
    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
365

366
    for (int i = 0; i < s->ngpio; i++) {
367
        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
368
    }
369

370
    qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
371
    qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
372
}
373

374
static void sifive_gpio_class_init(ObjectClass *klass, void *data)
375
{
376
    DeviceClass *dc = DEVICE_CLASS(klass);
377

378
    device_class_set_props(dc, sifive_gpio_properties);
379
    dc->vmsd = &vmstate_sifive_gpio;
380
    dc->realize = sifive_gpio_realize;
381
    dc->reset = sifive_gpio_reset;
382
    dc->desc = "SiFive GPIO";
383
}
384

385
static const TypeInfo sifive_gpio_info = {
386
    .name = TYPE_SIFIVE_GPIO,
387
    .parent = TYPE_SYS_BUS_DEVICE,
388
    .instance_size = sizeof(SIFIVEGPIOState),
389
    .class_init = sifive_gpio_class_init
390
};
391

392
static void sifive_gpio_register_types(void)
393
{
394
    type_register_static(&sifive_gpio_info);
395
}
396

397
type_init(sifive_gpio_register_types)
398

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

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

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

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