qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

nrf51_gpio.c (8546B)


      1 /*
      2  * nRF51 System-on-Chip general purpose input/output register definition
      3  *
      4  * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
      5  * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
      6  *
      7  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
      8  *
      9  * This code is licensed under the GPL version 2 or later.  See
     10  * the COPYING file in the top-level directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "qemu/log.h"
     15 #include "qemu/module.h"
     16 #include "hw/gpio/nrf51_gpio.h"
     17 #include "hw/irq.h"
     18 #include "migration/vmstate.h"
     19 #include "trace.h"
     20 
     21 /*
     22  * Check if the output driver is connected to the direction switch
     23  * given the current configuration and logic level.
     24  * It is not differentiated between standard and "high"(-power) drive modes.
     25  */
     26 static bool is_connected(uint32_t config, uint32_t level)
     27 {
     28     bool state;
     29     uint32_t drive_config = extract32(config, 8, 3);
     30 
     31     switch (drive_config) {
     32     case 0 ... 3:
     33         state = true;
     34         break;
     35     case 4 ... 5:
     36         state = level != 0;
     37         break;
     38     case 6 ... 7:
     39         state = level == 0;
     40         break;
     41     default:
     42         g_assert_not_reached();
     43         break;
     44     }
     45 
     46     return state;
     47 }
     48 
     49 static int pull_value(uint32_t config)
     50 {
     51     int pull = extract32(config, 2, 2);
     52     if (pull == NRF51_GPIO_PULLDOWN) {
     53         return 0;
     54     } else if (pull == NRF51_GPIO_PULLUP) {
     55         return 1;
     56     }
     57     return -1;
     58 }
     59 
     60 static void update_output_irq(NRF51GPIOState *s, size_t i,
     61                               bool connected, bool level)
     62 {
     63     int64_t irq_level = connected ? level : -1;
     64     bool old_connected = extract32(s->old_out_connected, i, 1);
     65     bool old_level = extract32(s->old_out, i, 1);
     66 
     67     if ((old_connected != connected) || (old_level != level)) {
     68         qemu_set_irq(s->output[i], irq_level);
     69         trace_nrf51_gpio_update_output_irq(i, irq_level);
     70     }
     71 
     72     s->old_out = deposit32(s->old_out, i, 1, level);
     73     s->old_out_connected = deposit32(s->old_out_connected, i, 1, connected);
     74 }
     75 
     76 static void update_state(NRF51GPIOState *s)
     77 {
     78     int pull;
     79     size_t i;
     80     bool connected_out, dir, connected_in, out, in, input;
     81 
     82     for (i = 0; i < NRF51_GPIO_PINS; i++) {
     83         pull = pull_value(s->cnf[i]);
     84         dir = extract32(s->cnf[i], 0, 1);
     85         connected_in = extract32(s->in_mask, i, 1);
     86         out = extract32(s->out, i, 1);
     87         in = extract32(s->in, i, 1);
     88         input = !extract32(s->cnf[i], 1, 1);
     89         connected_out = is_connected(s->cnf[i], out) && dir;
     90 
     91         if (!input) {
     92             if (pull >= 0) {
     93                 /* Input buffer disconnected from external drives */
     94                 s->in = deposit32(s->in, i, 1, pull);
     95             }
     96         } else {
     97             if (connected_out && connected_in && out != in) {
     98                 /* Pin both driven externally and internally */
     99                 qemu_log_mask(LOG_GUEST_ERROR,
    100                               "GPIO pin %zu short circuited\n", i);
    101             }
    102             if (!connected_in) {
    103                 /*
    104                  * Floating input: the output stimulates IN if connected,
    105                  * otherwise pull-up/pull-down resistors put a value on both
    106                  * IN and OUT.
    107                  */
    108                 if (pull >= 0 && !connected_out) {
    109                     connected_out = true;
    110                     out = pull;
    111                 }
    112                 if (connected_out) {
    113                     s->in = deposit32(s->in, i, 1, out);
    114                 }
    115             }
    116         }
    117         update_output_irq(s, i, connected_out, out);
    118     }
    119 }
    120 
    121 /*
    122  * Direction is exposed in both the DIR register and the DIR bit
    123  * of each PINs CNF configuration register. Reflect bits for pins in DIR
    124  * to individual pin configuration registers.
    125  */
    126 static void reflect_dir_bit_in_cnf(NRF51GPIOState *s)
    127 {
    128     size_t i;
    129 
    130     uint32_t value = s->dir;
    131 
    132     for (i = 0; i < NRF51_GPIO_PINS; i++) {
    133         s->cnf[i] = (s->cnf[i] & ~(1UL)) | ((value >> i) & 0x01);
    134     }
    135 }
    136 
    137 static uint64_t nrf51_gpio_read(void *opaque, hwaddr offset, unsigned int size)
    138 {
    139     NRF51GPIOState *s = NRF51_GPIO(opaque);
    140     uint64_t r = 0;
    141     size_t idx;
    142 
    143     switch (offset) {
    144     case NRF51_GPIO_REG_OUT ... NRF51_GPIO_REG_OUTCLR:
    145         r = s->out;
    146         break;
    147 
    148     case NRF51_GPIO_REG_IN:
    149         r = s->in;
    150         break;
    151 
    152     case NRF51_GPIO_REG_DIR ... NRF51_GPIO_REG_DIRCLR:
    153         r = s->dir;
    154         break;
    155 
    156     case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
    157         idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
    158         r = s->cnf[idx];
    159         break;
    160 
    161     default:
    162         qemu_log_mask(LOG_GUEST_ERROR,
    163                 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
    164                       __func__, offset);
    165     }
    166 
    167     trace_nrf51_gpio_read(offset, r);
    168 
    169     return r;
    170 }
    171 
    172 static void nrf51_gpio_write(void *opaque, hwaddr offset,
    173                        uint64_t value, unsigned int size)
    174 {
    175     NRF51GPIOState *s = NRF51_GPIO(opaque);
    176     size_t idx;
    177 
    178     trace_nrf51_gpio_write(offset, value);
    179 
    180     switch (offset) {
    181     case NRF51_GPIO_REG_OUT:
    182         s->out = value;
    183         break;
    184 
    185     case NRF51_GPIO_REG_OUTSET:
    186         s->out |= value;
    187         break;
    188 
    189     case NRF51_GPIO_REG_OUTCLR:
    190         s->out &= ~value;
    191         break;
    192 
    193     case NRF51_GPIO_REG_DIR:
    194         s->dir = value;
    195         reflect_dir_bit_in_cnf(s);
    196         break;
    197 
    198     case NRF51_GPIO_REG_DIRSET:
    199         s->dir |= value;
    200         reflect_dir_bit_in_cnf(s);
    201         break;
    202 
    203     case NRF51_GPIO_REG_DIRCLR:
    204         s->dir &= ~value;
    205         reflect_dir_bit_in_cnf(s);
    206         break;
    207 
    208     case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
    209         idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
    210         s->cnf[idx] = value;
    211         /*
    212          * direction is exposed in both the DIR register and the DIR bit
    213          * of each PINs CNF configuration register.
    214          */
    215         s->dir = (s->dir & ~(1UL << idx)) | ((value & 0x01) << idx);
    216         break;
    217 
    218     default:
    219         qemu_log_mask(LOG_GUEST_ERROR,
    220                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
    221                       __func__, offset);
    222     }
    223 
    224     update_state(s);
    225 }
    226 
    227 static const MemoryRegionOps gpio_ops = {
    228     .read =  nrf51_gpio_read,
    229     .write = nrf51_gpio_write,
    230     .endianness = DEVICE_LITTLE_ENDIAN,
    231     .impl.min_access_size = 4,
    232     .impl.max_access_size = 4,
    233 };
    234 
    235 static void nrf51_gpio_set(void *opaque, int line, int value)
    236 {
    237     NRF51GPIOState *s = NRF51_GPIO(opaque);
    238 
    239     trace_nrf51_gpio_set(line, value);
    240 
    241     assert(line >= 0 && line < NRF51_GPIO_PINS);
    242 
    243     s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
    244     if (value >= 0) {
    245         s->in = deposit32(s->in, line, 1, value != 0);
    246     }
    247 
    248     update_state(s);
    249 }
    250 
    251 static void nrf51_gpio_reset(DeviceState *dev)
    252 {
    253     NRF51GPIOState *s = NRF51_GPIO(dev);
    254     size_t i;
    255 
    256     s->out = 0;
    257     s->old_out = 0;
    258     s->old_out_connected = 0;
    259     s->in = 0;
    260     s->in_mask = 0;
    261     s->dir = 0;
    262 
    263     for (i = 0; i < NRF51_GPIO_PINS; i++) {
    264         s->cnf[i] = 0x00000002;
    265     }
    266 }
    267 
    268 static const VMStateDescription vmstate_nrf51_gpio = {
    269     .name = TYPE_NRF51_GPIO,
    270     .version_id = 1,
    271     .minimum_version_id = 1,
    272     .fields = (VMStateField[]) {
    273         VMSTATE_UINT32(out, NRF51GPIOState),
    274         VMSTATE_UINT32(in, NRF51GPIOState),
    275         VMSTATE_UINT32(in_mask, NRF51GPIOState),
    276         VMSTATE_UINT32(dir, NRF51GPIOState),
    277         VMSTATE_UINT32_ARRAY(cnf, NRF51GPIOState, NRF51_GPIO_PINS),
    278         VMSTATE_UINT32(old_out, NRF51GPIOState),
    279         VMSTATE_UINT32(old_out_connected, NRF51GPIOState),
    280         VMSTATE_END_OF_LIST()
    281     }
    282 };
    283 
    284 static void nrf51_gpio_init(Object *obj)
    285 {
    286     NRF51GPIOState *s = NRF51_GPIO(obj);
    287 
    288     memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
    289             TYPE_NRF51_GPIO, NRF51_GPIO_SIZE);
    290     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
    291 
    292     qdev_init_gpio_in(DEVICE(s), nrf51_gpio_set, NRF51_GPIO_PINS);
    293     qdev_init_gpio_out(DEVICE(s), s->output, NRF51_GPIO_PINS);
    294 }
    295 
    296 static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
    297 {
    298     DeviceClass *dc = DEVICE_CLASS(klass);
    299 
    300     dc->vmsd = &vmstate_nrf51_gpio;
    301     dc->reset = nrf51_gpio_reset;
    302     dc->desc = "nRF51 GPIO";
    303 }
    304 
    305 static const TypeInfo nrf51_gpio_info = {
    306     .name = TYPE_NRF51_GPIO,
    307     .parent = TYPE_SYS_BUS_DEVICE,
    308     .instance_size = sizeof(NRF51GPIOState),
    309     .instance_init = nrf51_gpio_init,
    310     .class_init = nrf51_gpio_class_init
    311 };
    312 
    313 static void nrf51_gpio_register_types(void)
    314 {
    315     type_register_static(&nrf51_gpio_info);
    316 }
    317 
    318 type_init(nrf51_gpio_register_types)