qemu

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

imx_gpio.c (9571B)


      1 /*
      2  * i.MX processors GPIO emulation.
      3  *
      4  * Copyright (C) 2015 Jean-Christophe Dubois <jcd@tribudubois.net>
      5  *
      6  * This program is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU General Public License as
      8  * published by the Free Software Foundation; either version 2 or
      9  * (at your option) version 3 of the License.
     10  *
     11  * This program is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  * GNU General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU General Public License along
     17  * with this program; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include "qemu/osdep.h"
     21 #include "hw/gpio/imx_gpio.h"
     22 #include "hw/irq.h"
     23 #include "hw/qdev-properties.h"
     24 #include "migration/vmstate.h"
     25 #include "qemu/log.h"
     26 #include "qemu/module.h"
     27 
     28 #ifndef DEBUG_IMX_GPIO
     29 #define DEBUG_IMX_GPIO 0
     30 #endif
     31 
     32 typedef enum IMXGPIOLevel {
     33     IMX_GPIO_LEVEL_LOW = 0,
     34     IMX_GPIO_LEVEL_HIGH = 1,
     35 } IMXGPIOLevel;
     36 
     37 #define DPRINTF(fmt, args...) \
     38     do { \
     39         if (DEBUG_IMX_GPIO) { \
     40             fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \
     41                                              __func__, ##args); \
     42         } \
     43     } while (0)
     44 
     45 static const char *imx_gpio_reg_name(uint32_t reg)
     46 {
     47     switch (reg) {
     48     case DR_ADDR:
     49         return "DR";
     50     case GDIR_ADDR:
     51         return "GDIR";
     52     case PSR_ADDR:
     53         return "PSR";
     54     case ICR1_ADDR:
     55         return "ICR1";
     56     case ICR2_ADDR:
     57         return "ICR2";
     58     case IMR_ADDR:
     59         return "IMR";
     60     case ISR_ADDR:
     61         return "ISR";
     62     case EDGE_SEL_ADDR:
     63         return "EDGE_SEL";
     64     default:
     65         return "[?]";
     66     }
     67 }
     68 
     69 static void imx_gpio_update_int(IMXGPIOState *s)
     70 {
     71     if (s->has_upper_pin_irq) {
     72         qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
     73         qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
     74     } else {
     75         qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
     76     }
     77 }
     78 
     79 static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
     80 {
     81     /* if this signal isn't configured as an input signal, nothing to do */
     82     if (!extract32(s->gdir, line, 1)) {
     83         return;
     84     }
     85 
     86     /* When set, EDGE_SEL overrides the ICR config */
     87     if (extract32(s->edge_sel, line, 1)) {
     88         /* we detect interrupt on rising and falling edge */
     89         if (extract32(s->psr, line, 1) != level) {
     90             /* level changed */
     91             s->isr = deposit32(s->isr, line, 1, 1);
     92         }
     93     } else if (extract64(s->icr, 2*line + 1, 1)) {
     94         /* interrupt is edge sensitive */
     95         if (extract32(s->psr, line, 1) != level) {
     96             /* level changed */
     97             if (extract64(s->icr, 2*line, 1) != level) {
     98                 s->isr = deposit32(s->isr, line, 1, 1);
     99             }
    100         }
    101     } else {
    102         /* interrupt is level sensitive */
    103         if (extract64(s->icr, 2*line, 1) == level) {
    104             s->isr = deposit32(s->isr, line, 1, 1);
    105         }
    106     }
    107 }
    108 
    109 static void imx_gpio_set(void *opaque, int line, int level)
    110 {
    111     IMXGPIOState *s = IMX_GPIO(opaque);
    112     IMXGPIOLevel imx_level = level ? IMX_GPIO_LEVEL_HIGH : IMX_GPIO_LEVEL_LOW;
    113 
    114     imx_gpio_set_int_line(s, line, imx_level);
    115 
    116     /* this is an input signal, so set PSR */
    117     s->psr = deposit32(s->psr, line, 1, imx_level);
    118 
    119     imx_gpio_update_int(s);
    120 }
    121 
    122 static void imx_gpio_set_all_int_lines(IMXGPIOState *s)
    123 {
    124     int i;
    125 
    126     for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
    127         IMXGPIOLevel imx_level = extract32(s->psr, i, 1);
    128         imx_gpio_set_int_line(s, i, imx_level);
    129     }
    130 
    131     imx_gpio_update_int(s);
    132 }
    133 
    134 static inline void imx_gpio_set_all_output_lines(IMXGPIOState *s)
    135 {
    136     int i;
    137 
    138     for (i = 0; i < IMX_GPIO_PIN_COUNT; i++) {
    139         /*
    140          * if the line is set as output, then forward the line
    141          * level to its user.
    142          */
    143         if (extract32(s->gdir, i, 1) && s->output[i]) {
    144             qemu_set_irq(s->output[i], extract32(s->dr, i, 1));
    145         }
    146     }
    147 }
    148 
    149 static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size)
    150 {
    151     IMXGPIOState *s = IMX_GPIO(opaque);
    152     uint32_t reg_value = 0;
    153 
    154     switch (offset) {
    155     case DR_ADDR:
    156         /*
    157          * depending on the "line" configuration, the bit values
    158          * are coming either from DR or PSR
    159          */
    160         reg_value = (s->dr & s->gdir) | (s->psr & ~s->gdir);
    161         break;
    162 
    163     case GDIR_ADDR:
    164         reg_value = s->gdir;
    165         break;
    166 
    167     case PSR_ADDR:
    168         reg_value = s->psr & ~s->gdir;
    169         break;
    170 
    171     case ICR1_ADDR:
    172         reg_value = extract64(s->icr, 0, 32);
    173         break;
    174 
    175     case ICR2_ADDR:
    176         reg_value = extract64(s->icr, 32, 32);
    177         break;
    178 
    179     case IMR_ADDR:
    180         reg_value = s->imr;
    181         break;
    182 
    183     case ISR_ADDR:
    184         reg_value = s->isr;
    185         break;
    186 
    187     case EDGE_SEL_ADDR:
    188         if (s->has_edge_sel) {
    189             reg_value = s->edge_sel;
    190         } else {
    191             qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
    192                           "present on this version of GPIO device\n",
    193                           TYPE_IMX_GPIO, __func__);
    194         }
    195         break;
    196 
    197     default:
    198         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    199                       HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
    200         break;
    201     }
    202 
    203     DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value);
    204 
    205     return reg_value;
    206 }
    207 
    208 static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value,
    209                            unsigned size)
    210 {
    211     IMXGPIOState *s = IMX_GPIO(opaque);
    212 
    213     DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset),
    214             (uint32_t)value);
    215 
    216     switch (offset) {
    217     case DR_ADDR:
    218         s->dr = value;
    219         imx_gpio_set_all_output_lines(s);
    220         break;
    221 
    222     case GDIR_ADDR:
    223         s->gdir = value;
    224         imx_gpio_set_all_output_lines(s);
    225         imx_gpio_set_all_int_lines(s);
    226         break;
    227 
    228     case ICR1_ADDR:
    229         s->icr = deposit64(s->icr, 0, 32, value);
    230         imx_gpio_set_all_int_lines(s);
    231         break;
    232 
    233     case ICR2_ADDR:
    234         s->icr = deposit64(s->icr, 32, 32, value);
    235         imx_gpio_set_all_int_lines(s);
    236         break;
    237 
    238     case IMR_ADDR:
    239         s->imr = value;
    240         imx_gpio_update_int(s);
    241         break;
    242 
    243     case ISR_ADDR:
    244         s->isr &= ~value;
    245         imx_gpio_set_all_int_lines(s);
    246         break;
    247 
    248     case EDGE_SEL_ADDR:
    249         if (s->has_edge_sel) {
    250             s->edge_sel = value;
    251             imx_gpio_set_all_int_lines(s);
    252         } else {
    253             qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not "
    254                           "present on this version of GPIO device\n",
    255                           TYPE_IMX_GPIO, __func__);
    256         }
    257         break;
    258 
    259     default:
    260         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    261                       HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset);
    262         break;
    263     }
    264 
    265     return;
    266 }
    267 
    268 static const MemoryRegionOps imx_gpio_ops = {
    269     .read = imx_gpio_read,
    270     .write = imx_gpio_write,
    271     .valid.min_access_size = 4,
    272     .valid.max_access_size = 4,
    273     .endianness = DEVICE_NATIVE_ENDIAN,
    274 };
    275 
    276 static const VMStateDescription vmstate_imx_gpio = {
    277     .name = TYPE_IMX_GPIO,
    278     .version_id = 1,
    279     .minimum_version_id = 1,
    280     .fields = (VMStateField[]) {
    281         VMSTATE_UINT32(dr, IMXGPIOState),
    282         VMSTATE_UINT32(gdir, IMXGPIOState),
    283         VMSTATE_UINT32(psr, IMXGPIOState),
    284         VMSTATE_UINT64(icr, IMXGPIOState),
    285         VMSTATE_UINT32(imr, IMXGPIOState),
    286         VMSTATE_UINT32(isr, IMXGPIOState),
    287         VMSTATE_BOOL(has_edge_sel, IMXGPIOState),
    288         VMSTATE_UINT32(edge_sel, IMXGPIOState),
    289         VMSTATE_END_OF_LIST()
    290     }
    291 };
    292 
    293 static Property imx_gpio_properties[] = {
    294     DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
    295     DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
    296                      false),
    297     DEFINE_PROP_END_OF_LIST(),
    298 };
    299 
    300 static void imx_gpio_reset(DeviceState *dev)
    301 {
    302     IMXGPIOState *s = IMX_GPIO(dev);
    303 
    304     s->dr       = 0;
    305     s->gdir     = 0;
    306     s->psr      = 0;
    307     s->icr      = 0;
    308     s->imr      = 0;
    309     s->isr      = 0;
    310     s->edge_sel = 0;
    311 
    312     imx_gpio_set_all_output_lines(s);
    313     imx_gpio_update_int(s);
    314 }
    315 
    316 static void imx_gpio_realize(DeviceState *dev, Error **errp)
    317 {
    318     IMXGPIOState *s = IMX_GPIO(dev);
    319 
    320     memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpio_ops, s,
    321                           TYPE_IMX_GPIO, IMX_GPIO_MEM_SIZE);
    322 
    323     qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
    324     qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
    325 
    326     sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
    327     sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
    328     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
    329 }
    330 
    331 static void imx_gpio_class_init(ObjectClass *klass, void *data)
    332 {
    333     DeviceClass *dc = DEVICE_CLASS(klass);
    334 
    335     dc->realize = imx_gpio_realize;
    336     dc->reset = imx_gpio_reset;
    337     device_class_set_props(dc, imx_gpio_properties);
    338     dc->vmsd = &vmstate_imx_gpio;
    339     dc->desc = "i.MX GPIO controller";
    340 }
    341 
    342 static const TypeInfo imx_gpio_info = {
    343     .name = TYPE_IMX_GPIO,
    344     .parent = TYPE_SYS_BUS_DEVICE,
    345     .instance_size = sizeof(IMXGPIOState),
    346     .class_init = imx_gpio_class_init,
    347 };
    348 
    349 static void imx_gpio_register_types(void)
    350 {
    351     type_register_static(&imx_gpio_info);
    352 }
    353 
    354 type_init(imx_gpio_register_types)