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

1.1       root        1: /*
                      2:  *  QEMU model of the Milkymist System Controller.
                      3:  *
1.1.1.3 ! root        4:  *  Copyright (c) 2010-2012 Michael Walle <[email protected]>
1.1       root        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"
1.1.1.3 ! root       29: #include "ptimer.h"
1.1       root       30: #include "qemu-error.h"
                     31: 
                     32: enum {
                     33:     CTRL_ENABLE      = (1<<0),
                     34:     CTRL_AUTORESTART = (1<<1),
                     35: };
                     36: 
                     37: enum {
                     38:     ICAP_READY       = (1<<0),
                     39: };
                     40: 
                     41: enum {
1.1.1.3 ! root       42:     R_GPIO_IN         = 0,
1.1       root       43:     R_GPIO_OUT,
                     44:     R_GPIO_INTEN,
1.1.1.3 ! root       45:     R_TIMER0_CONTROL  = 4,
1.1       root       46:     R_TIMER0_COMPARE,
                     47:     R_TIMER0_COUNTER,
1.1.1.3 ! root       48:     R_TIMER1_CONTROL  = 8,
1.1       root       49:     R_TIMER1_COMPARE,
                     50:     R_TIMER1_COUNTER,
1.1.1.3 ! root       51:     R_ICAP = 16,
        !            52:     R_DBG_SCRATCHPAD  = 20,
        !            53:     R_DBG_WRITE_LOCK,
        !            54:     R_CLK_FREQUENCY   = 29,
1.1       root       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:
1.1.1.3 ! root      118:     case R_DBG_SCRATCHPAD:
        !           119:     case R_DBG_WRITE_LOCK:
        !           120:     case R_CLK_FREQUENCY:
1.1       root      121:     case R_CAPABILITIES:
                    122:     case R_SYSTEM_ID:
                    123:         r = s->regs[addr];
                    124:         break;
                    125: 
                    126:     default:
                    127:         error_report("milkymist_sysctl: read access to unknown register 0x"
                    128:                 TARGET_FMT_plx, addr << 2);
                    129:         break;
                    130:     }
                    131: 
                    132:     trace_milkymist_sysctl_memory_read(addr << 2, r);
                    133: 
                    134:     return r;
                    135: }
                    136: 
1.1.1.2   root      137: static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
                    138:                          unsigned size)
1.1       root      139: {
                    140:     MilkymistSysctlState *s = opaque;
                    141: 
                    142:     trace_milkymist_sysctl_memory_write(addr, value);
                    143: 
                    144:     addr >>= 2;
                    145:     switch (addr) {
                    146:     case R_GPIO_OUT:
                    147:     case R_GPIO_INTEN:
                    148:     case R_TIMER0_COUNTER:
                    149:     case R_TIMER1_COUNTER:
1.1.1.3 ! root      150:     case R_DBG_SCRATCHPAD:
1.1       root      151:         s->regs[addr] = value;
                    152:         break;
                    153:     case R_TIMER0_COMPARE:
                    154:         ptimer_set_limit(s->ptimer0, value, 0);
                    155:         s->regs[addr] = value;
                    156:         break;
                    157:     case R_TIMER1_COMPARE:
                    158:         ptimer_set_limit(s->ptimer1, value, 0);
                    159:         s->regs[addr] = value;
                    160:         break;
                    161:     case R_TIMER0_CONTROL:
                    162:         s->regs[addr] = value;
                    163:         if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
                    164:             trace_milkymist_sysctl_start_timer0();
                    165:             ptimer_set_count(s->ptimer0,
                    166:                     s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
                    167:             ptimer_run(s->ptimer0, 0);
                    168:         } else {
                    169:             trace_milkymist_sysctl_stop_timer0();
                    170:             ptimer_stop(s->ptimer0);
                    171:         }
                    172:         break;
                    173:     case R_TIMER1_CONTROL:
                    174:         s->regs[addr] = value;
                    175:         if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
                    176:             trace_milkymist_sysctl_start_timer1();
                    177:             ptimer_set_count(s->ptimer1,
                    178:                     s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
                    179:             ptimer_run(s->ptimer1, 0);
                    180:         } else {
                    181:             trace_milkymist_sysctl_stop_timer1();
                    182:             ptimer_stop(s->ptimer1);
                    183:         }
                    184:         break;
                    185:     case R_ICAP:
                    186:         sysctl_icap_write(s, value);
                    187:         break;
1.1.1.3 ! root      188:     case R_DBG_WRITE_LOCK:
        !           189:         s->regs[addr] = 1;
        !           190:         break;
1.1       root      191:     case R_SYSTEM_ID:
                    192:         qemu_system_reset_request();
                    193:         break;
                    194: 
                    195:     case R_GPIO_IN:
1.1.1.3 ! root      196:     case R_CLK_FREQUENCY:
1.1       root      197:     case R_CAPABILITIES:
                    198:         error_report("milkymist_sysctl: write to read-only register 0x"
                    199:                 TARGET_FMT_plx, addr << 2);
                    200:         break;
                    201: 
                    202:     default:
                    203:         error_report("milkymist_sysctl: write access to unknown register 0x"
                    204:                 TARGET_FMT_plx, addr << 2);
                    205:         break;
                    206:     }
                    207: }
                    208: 
1.1.1.2   root      209: static const MemoryRegionOps sysctl_mmio_ops = {
                    210:     .read = sysctl_read,
                    211:     .write = sysctl_write,
                    212:     .valid = {
                    213:         .min_access_size = 4,
                    214:         .max_access_size = 4,
                    215:     },
                    216:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      217: };
                    218: 
                    219: static void timer0_hit(void *opaque)
                    220: {
                    221:     MilkymistSysctlState *s = opaque;
                    222: 
                    223:     if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
                    224:         s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
                    225:         trace_milkymist_sysctl_stop_timer0();
                    226:         ptimer_stop(s->ptimer0);
                    227:     }
                    228: 
                    229:     trace_milkymist_sysctl_pulse_irq_timer0();
                    230:     qemu_irq_pulse(s->timer0_irq);
                    231: }
                    232: 
                    233: static void timer1_hit(void *opaque)
                    234: {
                    235:     MilkymistSysctlState *s = opaque;
                    236: 
                    237:     if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
                    238:         s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
                    239:         trace_milkymist_sysctl_stop_timer1();
                    240:         ptimer_stop(s->ptimer1);
                    241:     }
                    242: 
                    243:     trace_milkymist_sysctl_pulse_irq_timer1();
                    244:     qemu_irq_pulse(s->timer1_irq);
                    245: }
                    246: 
                    247: static void milkymist_sysctl_reset(DeviceState *d)
                    248: {
                    249:     MilkymistSysctlState *s =
                    250:             container_of(d, MilkymistSysctlState, busdev.qdev);
                    251:     int i;
                    252: 
                    253:     for (i = 0; i < R_MAX; i++) {
                    254:         s->regs[i] = 0;
                    255:     }
                    256: 
                    257:     ptimer_stop(s->ptimer0);
                    258:     ptimer_stop(s->ptimer1);
                    259: 
                    260:     /* defaults */
                    261:     s->regs[R_ICAP] = ICAP_READY;
                    262:     s->regs[R_SYSTEM_ID] = s->systemid;
1.1.1.3 ! root      263:     s->regs[R_CLK_FREQUENCY] = s->freq_hz;
1.1       root      264:     s->regs[R_CAPABILITIES] = s->capabilities;
                    265:     s->regs[R_GPIO_IN] = s->strappings;
                    266: }
                    267: 
                    268: static int milkymist_sysctl_init(SysBusDevice *dev)
                    269: {
                    270:     MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
                    271: 
                    272:     sysbus_init_irq(dev, &s->gpio_irq);
                    273:     sysbus_init_irq(dev, &s->timer0_irq);
                    274:     sysbus_init_irq(dev, &s->timer1_irq);
                    275: 
                    276:     s->bh0 = qemu_bh_new(timer0_hit, s);
                    277:     s->bh1 = qemu_bh_new(timer1_hit, s);
                    278:     s->ptimer0 = ptimer_init(s->bh0);
                    279:     s->ptimer1 = ptimer_init(s->bh1);
                    280:     ptimer_set_freq(s->ptimer0, s->freq_hz);
                    281:     ptimer_set_freq(s->ptimer1, s->freq_hz);
                    282: 
1.1.1.2   root      283:     memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
                    284:             "milkymist-sysctl", R_MAX * 4);
1.1.1.3 ! root      285:     sysbus_init_mmio(dev, &s->regs_region);
1.1       root      286: 
                    287:     return 0;
                    288: }
                    289: 
                    290: static const VMStateDescription vmstate_milkymist_sysctl = {
                    291:     .name = "milkymist-sysctl",
                    292:     .version_id = 1,
                    293:     .minimum_version_id = 1,
                    294:     .minimum_version_id_old = 1,
                    295:     .fields      = (VMStateField[]) {
                    296:         VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
                    297:         VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
                    298:         VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
                    299:         VMSTATE_END_OF_LIST()
                    300:     }
                    301: };
                    302: 
1.1.1.3 ! root      303: static Property milkymist_sysctl_properties[] = {
        !           304:     DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
        !           305:     freq_hz, 80000000),
        !           306:     DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
        !           307:     capabilities, 0x00000000),
        !           308:     DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
        !           309:     systemid, 0x10014d31),
        !           310:     DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
        !           311:     strappings, 0x00000001),
        !           312:     DEFINE_PROP_END_OF_LIST(),
        !           313: };
        !           314: 
        !           315: static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
        !           316: {
        !           317:     DeviceClass *dc = DEVICE_CLASS(klass);
        !           318:     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
        !           319: 
        !           320:     k->init = milkymist_sysctl_init;
        !           321:     dc->reset = milkymist_sysctl_reset;
        !           322:     dc->vmsd = &vmstate_milkymist_sysctl;
        !           323:     dc->props = milkymist_sysctl_properties;
        !           324: }
        !           325: 
        !           326: static TypeInfo milkymist_sysctl_info = {
        !           327:     .name          = "milkymist-sysctl",
        !           328:     .parent        = TYPE_SYS_BUS_DEVICE,
        !           329:     .instance_size = sizeof(MilkymistSysctlState),
        !           330:     .class_init    = milkymist_sysctl_class_init,
1.1       root      331: };
                    332: 
1.1.1.3 ! root      333: static void milkymist_sysctl_register_types(void)
1.1       root      334: {
1.1.1.3 ! root      335:     type_register_static(&milkymist_sysctl_info);
1.1       root      336: }
                    337: 
1.1.1.3 ! root      338: type_init(milkymist_sysctl_register_types)

unix.superglobalmegacorp.com

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