Annotation of qemu/hw/milkymist-sysctl.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  *  QEMU model of the Milkymist System Controller.
                      3:  *
                      4:  *  Copyright (c) 2010 Michael Walle <[email protected]>
                      5:  *
                      6:  * This library is free software; you can redistribute it and/or
                      7:  * modify it under the terms of the GNU Lesser General Public
                      8:  * License as published by the Free Software Foundation; either
                      9:  * version 2 of the License, or (at your option) any later version.
                     10:  *
                     11:  * This library 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 GNU
                     14:  * Lesser General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU Lesser General Public
                     17:  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
                     18:  *
                     19:  *
                     20:  * Specification available at:
                     21:  *   http://www.milkymist.org/socdoc/sysctl.pdf
                     22:  */
                     23: 
                     24: #include "hw.h"
                     25: #include "sysbus.h"
                     26: #include "sysemu.h"
                     27: #include "trace.h"
                     28: #include "qemu-timer.h"
                     29: #include "qemu-error.h"
                     30: 
                     31: enum {
                     32:     CTRL_ENABLE      = (1<<0),
                     33:     CTRL_AUTORESTART = (1<<1),
                     34: };
                     35: 
                     36: enum {
                     37:     ICAP_READY       = (1<<0),
                     38: };
                     39: 
                     40: enum {
                     41:     R_GPIO_IN = 0,
                     42:     R_GPIO_OUT,
                     43:     R_GPIO_INTEN,
                     44:     R_RESERVED0,
                     45:     R_TIMER0_CONTROL,
                     46:     R_TIMER0_COMPARE,
                     47:     R_TIMER0_COUNTER,
                     48:     R_RESERVED1,
                     49:     R_TIMER1_CONTROL,
                     50:     R_TIMER1_COMPARE,
                     51:     R_TIMER1_COUNTER,
                     52:     R_RESERVED2,
                     53:     R_RESERVED3,
                     54:     R_ICAP,
                     55:     R_CAPABILITIES,
                     56:     R_SYSTEM_ID,
                     57:     R_MAX
                     58: };
                     59: 
                     60: struct MilkymistSysctlState {
                     61:     SysBusDevice busdev;
1.1.1.2 ! root       62:     MemoryRegion regs_region;
1.1       root       63: 
                     64:     QEMUBH *bh0;
                     65:     QEMUBH *bh1;
                     66:     ptimer_state *ptimer0;
                     67:     ptimer_state *ptimer1;
                     68: 
                     69:     uint32_t freq_hz;
                     70:     uint32_t capabilities;
                     71:     uint32_t systemid;
                     72:     uint32_t strappings;
                     73: 
                     74:     uint32_t regs[R_MAX];
                     75: 
                     76:     qemu_irq gpio_irq;
                     77:     qemu_irq timer0_irq;
                     78:     qemu_irq timer1_irq;
                     79: };
                     80: typedef struct MilkymistSysctlState MilkymistSysctlState;
                     81: 
                     82: static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
                     83: {
                     84:     trace_milkymist_sysctl_icap_write(value);
                     85:     switch (value & 0xffff) {
                     86:     case 0x000e:
                     87:         qemu_system_shutdown_request();
                     88:         break;
                     89:     }
                     90: }
                     91: 
1.1.1.2 ! root       92: static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
        !            93:                             unsigned size)
1.1       root       94: {
                     95:     MilkymistSysctlState *s = opaque;
                     96:     uint32_t r = 0;
                     97: 
                     98:     addr >>= 2;
                     99:     switch (addr) {
                    100:     case R_TIMER0_COUNTER:
                    101:         r = (uint32_t)ptimer_get_count(s->ptimer0);
                    102:         /* milkymist timer counts up */
                    103:         r = s->regs[R_TIMER0_COMPARE] - r;
                    104:         break;
                    105:     case R_TIMER1_COUNTER:
                    106:         r = (uint32_t)ptimer_get_count(s->ptimer1);
                    107:         /* milkymist timer counts up */
                    108:         r = s->regs[R_TIMER1_COMPARE] - r;
                    109:         break;
                    110:     case R_GPIO_IN:
                    111:     case R_GPIO_OUT:
                    112:     case R_GPIO_INTEN:
                    113:     case R_TIMER0_CONTROL:
                    114:     case R_TIMER0_COMPARE:
                    115:     case R_TIMER1_CONTROL:
                    116:     case R_TIMER1_COMPARE:
                    117:     case R_ICAP:
                    118:     case R_CAPABILITIES:
                    119:     case R_SYSTEM_ID:
                    120:         r = s->regs[addr];
                    121:         break;
                    122: 
                    123:     default:
                    124:         error_report("milkymist_sysctl: read access to unknown register 0x"
                    125:                 TARGET_FMT_plx, addr << 2);
                    126:         break;
                    127:     }
                    128: 
                    129:     trace_milkymist_sysctl_memory_read(addr << 2, r);
                    130: 
                    131:     return r;
                    132: }
                    133: 
1.1.1.2 ! root      134: static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
        !           135:                          unsigned size)
1.1       root      136: {
                    137:     MilkymistSysctlState *s = opaque;
                    138: 
                    139:     trace_milkymist_sysctl_memory_write(addr, value);
                    140: 
                    141:     addr >>= 2;
                    142:     switch (addr) {
                    143:     case R_GPIO_OUT:
                    144:     case R_GPIO_INTEN:
                    145:     case R_TIMER0_COUNTER:
                    146:     case R_TIMER1_COUNTER:
                    147:         s->regs[addr] = value;
                    148:         break;
                    149:     case R_TIMER0_COMPARE:
                    150:         ptimer_set_limit(s->ptimer0, value, 0);
                    151:         s->regs[addr] = value;
                    152:         break;
                    153:     case R_TIMER1_COMPARE:
                    154:         ptimer_set_limit(s->ptimer1, value, 0);
                    155:         s->regs[addr] = value;
                    156:         break;
                    157:     case R_TIMER0_CONTROL:
                    158:         s->regs[addr] = value;
                    159:         if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
                    160:             trace_milkymist_sysctl_start_timer0();
                    161:             ptimer_set_count(s->ptimer0,
                    162:                     s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
                    163:             ptimer_run(s->ptimer0, 0);
                    164:         } else {
                    165:             trace_milkymist_sysctl_stop_timer0();
                    166:             ptimer_stop(s->ptimer0);
                    167:         }
                    168:         break;
                    169:     case R_TIMER1_CONTROL:
                    170:         s->regs[addr] = value;
                    171:         if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
                    172:             trace_milkymist_sysctl_start_timer1();
                    173:             ptimer_set_count(s->ptimer1,
                    174:                     s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
                    175:             ptimer_run(s->ptimer1, 0);
                    176:         } else {
                    177:             trace_milkymist_sysctl_stop_timer1();
                    178:             ptimer_stop(s->ptimer1);
                    179:         }
                    180:         break;
                    181:     case R_ICAP:
                    182:         sysctl_icap_write(s, value);
                    183:         break;
                    184:     case R_SYSTEM_ID:
                    185:         qemu_system_reset_request();
                    186:         break;
                    187: 
                    188:     case R_GPIO_IN:
                    189:     case R_CAPABILITIES:
                    190:         error_report("milkymist_sysctl: write to read-only register 0x"
                    191:                 TARGET_FMT_plx, addr << 2);
                    192:         break;
                    193: 
                    194:     default:
                    195:         error_report("milkymist_sysctl: write access to unknown register 0x"
                    196:                 TARGET_FMT_plx, addr << 2);
                    197:         break;
                    198:     }
                    199: }
                    200: 
1.1.1.2 ! root      201: static const MemoryRegionOps sysctl_mmio_ops = {
        !           202:     .read = sysctl_read,
        !           203:     .write = sysctl_write,
        !           204:     .valid = {
        !           205:         .min_access_size = 4,
        !           206:         .max_access_size = 4,
        !           207:     },
        !           208:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      209: };
                    210: 
                    211: static void timer0_hit(void *opaque)
                    212: {
                    213:     MilkymistSysctlState *s = opaque;
                    214: 
                    215:     if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
                    216:         s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
                    217:         trace_milkymist_sysctl_stop_timer0();
                    218:         ptimer_stop(s->ptimer0);
                    219:     }
                    220: 
                    221:     trace_milkymist_sysctl_pulse_irq_timer0();
                    222:     qemu_irq_pulse(s->timer0_irq);
                    223: }
                    224: 
                    225: static void timer1_hit(void *opaque)
                    226: {
                    227:     MilkymistSysctlState *s = opaque;
                    228: 
                    229:     if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
                    230:         s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
                    231:         trace_milkymist_sysctl_stop_timer1();
                    232:         ptimer_stop(s->ptimer1);
                    233:     }
                    234: 
                    235:     trace_milkymist_sysctl_pulse_irq_timer1();
                    236:     qemu_irq_pulse(s->timer1_irq);
                    237: }
                    238: 
                    239: static void milkymist_sysctl_reset(DeviceState *d)
                    240: {
                    241:     MilkymistSysctlState *s =
                    242:             container_of(d, MilkymistSysctlState, busdev.qdev);
                    243:     int i;
                    244: 
                    245:     for (i = 0; i < R_MAX; i++) {
                    246:         s->regs[i] = 0;
                    247:     }
                    248: 
                    249:     ptimer_stop(s->ptimer0);
                    250:     ptimer_stop(s->ptimer1);
                    251: 
                    252:     /* defaults */
                    253:     s->regs[R_ICAP] = ICAP_READY;
                    254:     s->regs[R_SYSTEM_ID] = s->systemid;
                    255:     s->regs[R_CAPABILITIES] = s->capabilities;
                    256:     s->regs[R_GPIO_IN] = s->strappings;
                    257: }
                    258: 
                    259: static int milkymist_sysctl_init(SysBusDevice *dev)
                    260: {
                    261:     MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
                    262: 
                    263:     sysbus_init_irq(dev, &s->gpio_irq);
                    264:     sysbus_init_irq(dev, &s->timer0_irq);
                    265:     sysbus_init_irq(dev, &s->timer1_irq);
                    266: 
                    267:     s->bh0 = qemu_bh_new(timer0_hit, s);
                    268:     s->bh1 = qemu_bh_new(timer1_hit, s);
                    269:     s->ptimer0 = ptimer_init(s->bh0);
                    270:     s->ptimer1 = ptimer_init(s->bh1);
                    271:     ptimer_set_freq(s->ptimer0, s->freq_hz);
                    272:     ptimer_set_freq(s->ptimer1, s->freq_hz);
                    273: 
1.1.1.2 ! root      274:     memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
        !           275:             "milkymist-sysctl", R_MAX * 4);
        !           276:     sysbus_init_mmio_region(dev, &s->regs_region);
1.1       root      277: 
                    278:     return 0;
                    279: }
                    280: 
                    281: static const VMStateDescription vmstate_milkymist_sysctl = {
                    282:     .name = "milkymist-sysctl",
                    283:     .version_id = 1,
                    284:     .minimum_version_id = 1,
                    285:     .minimum_version_id_old = 1,
                    286:     .fields      = (VMStateField[]) {
                    287:         VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
                    288:         VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
                    289:         VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
                    290:         VMSTATE_END_OF_LIST()
                    291:     }
                    292: };
                    293: 
                    294: static SysBusDeviceInfo milkymist_sysctl_info = {
                    295:     .init = milkymist_sysctl_init,
                    296:     .qdev.name  = "milkymist-sysctl",
                    297:     .qdev.size  = sizeof(MilkymistSysctlState),
                    298:     .qdev.vmsd  = &vmstate_milkymist_sysctl,
                    299:     .qdev.reset = milkymist_sysctl_reset,
                    300:     .qdev.props = (Property[]) {
                    301:         DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
                    302:                 freq_hz, 80000000),
                    303:         DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
                    304:                 capabilities, 0x00000000),
                    305:         DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
                    306:                 systemid, 0x10014d31),
                    307:         DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
                    308:                 strappings, 0x00000001),
                    309:         DEFINE_PROP_END_OF_LIST(),
                    310:     }
                    311: };
                    312: 
                    313: static void milkymist_sysctl_register(void)
                    314: {
                    315:     sysbus_register_withprop(&milkymist_sysctl_info);
                    316: }
                    317: 
                    318: device_init(milkymist_sysctl_register)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.