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

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;
                     62: 
                     63:     QEMUBH *bh0;
                     64:     QEMUBH *bh1;
                     65:     ptimer_state *ptimer0;
                     66:     ptimer_state *ptimer1;
                     67: 
                     68:     uint32_t freq_hz;
                     69:     uint32_t capabilities;
                     70:     uint32_t systemid;
                     71:     uint32_t strappings;
                     72: 
                     73:     uint32_t regs[R_MAX];
                     74: 
                     75:     qemu_irq gpio_irq;
                     76:     qemu_irq timer0_irq;
                     77:     qemu_irq timer1_irq;
                     78: };
                     79: typedef struct MilkymistSysctlState MilkymistSysctlState;
                     80: 
                     81: static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
                     82: {
                     83:     trace_milkymist_sysctl_icap_write(value);
                     84:     switch (value & 0xffff) {
                     85:     case 0x000e:
                     86:         qemu_system_shutdown_request();
                     87:         break;
                     88:     }
                     89: }
                     90: 
                     91: static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
                     92: {
                     93:     MilkymistSysctlState *s = opaque;
                     94:     uint32_t r = 0;
                     95: 
                     96:     addr >>= 2;
                     97:     switch (addr) {
                     98:     case R_TIMER0_COUNTER:
                     99:         r = (uint32_t)ptimer_get_count(s->ptimer0);
                    100:         /* milkymist timer counts up */
                    101:         r = s->regs[R_TIMER0_COMPARE] - r;
                    102:         break;
                    103:     case R_TIMER1_COUNTER:
                    104:         r = (uint32_t)ptimer_get_count(s->ptimer1);
                    105:         /* milkymist timer counts up */
                    106:         r = s->regs[R_TIMER1_COMPARE] - r;
                    107:         break;
                    108:     case R_GPIO_IN:
                    109:     case R_GPIO_OUT:
                    110:     case R_GPIO_INTEN:
                    111:     case R_TIMER0_CONTROL:
                    112:     case R_TIMER0_COMPARE:
                    113:     case R_TIMER1_CONTROL:
                    114:     case R_TIMER1_COMPARE:
                    115:     case R_ICAP:
                    116:     case R_CAPABILITIES:
                    117:     case R_SYSTEM_ID:
                    118:         r = s->regs[addr];
                    119:         break;
                    120: 
                    121:     default:
                    122:         error_report("milkymist_sysctl: read access to unknown register 0x"
                    123:                 TARGET_FMT_plx, addr << 2);
                    124:         break;
                    125:     }
                    126: 
                    127:     trace_milkymist_sysctl_memory_read(addr << 2, r);
                    128: 
                    129:     return r;
                    130: }
                    131: 
                    132: static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
                    133: {
                    134:     MilkymistSysctlState *s = opaque;
                    135: 
                    136:     trace_milkymist_sysctl_memory_write(addr, value);
                    137: 
                    138:     addr >>= 2;
                    139:     switch (addr) {
                    140:     case R_GPIO_OUT:
                    141:     case R_GPIO_INTEN:
                    142:     case R_TIMER0_COUNTER:
                    143:     case R_TIMER1_COUNTER:
                    144:         s->regs[addr] = value;
                    145:         break;
                    146:     case R_TIMER0_COMPARE:
                    147:         ptimer_set_limit(s->ptimer0, value, 0);
                    148:         s->regs[addr] = value;
                    149:         break;
                    150:     case R_TIMER1_COMPARE:
                    151:         ptimer_set_limit(s->ptimer1, value, 0);
                    152:         s->regs[addr] = value;
                    153:         break;
                    154:     case R_TIMER0_CONTROL:
                    155:         s->regs[addr] = value;
                    156:         if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
                    157:             trace_milkymist_sysctl_start_timer0();
                    158:             ptimer_set_count(s->ptimer0,
                    159:                     s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
                    160:             ptimer_run(s->ptimer0, 0);
                    161:         } else {
                    162:             trace_milkymist_sysctl_stop_timer0();
                    163:             ptimer_stop(s->ptimer0);
                    164:         }
                    165:         break;
                    166:     case R_TIMER1_CONTROL:
                    167:         s->regs[addr] = value;
                    168:         if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
                    169:             trace_milkymist_sysctl_start_timer1();
                    170:             ptimer_set_count(s->ptimer1,
                    171:                     s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
                    172:             ptimer_run(s->ptimer1, 0);
                    173:         } else {
                    174:             trace_milkymist_sysctl_stop_timer1();
                    175:             ptimer_stop(s->ptimer1);
                    176:         }
                    177:         break;
                    178:     case R_ICAP:
                    179:         sysctl_icap_write(s, value);
                    180:         break;
                    181:     case R_SYSTEM_ID:
                    182:         qemu_system_reset_request();
                    183:         break;
                    184: 
                    185:     case R_GPIO_IN:
                    186:     case R_CAPABILITIES:
                    187:         error_report("milkymist_sysctl: write to read-only register 0x"
                    188:                 TARGET_FMT_plx, addr << 2);
                    189:         break;
                    190: 
                    191:     default:
                    192:         error_report("milkymist_sysctl: write access to unknown register 0x"
                    193:                 TARGET_FMT_plx, addr << 2);
                    194:         break;
                    195:     }
                    196: }
                    197: 
                    198: static CPUReadMemoryFunc * const sysctl_read_fn[] = {
                    199:     NULL,
                    200:     NULL,
                    201:     &sysctl_read,
                    202: };
                    203: 
                    204: static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
                    205:     NULL,
                    206:     NULL,
                    207:     &sysctl_write,
                    208: };
                    209: 
                    210: static void timer0_hit(void *opaque)
                    211: {
                    212:     MilkymistSysctlState *s = opaque;
                    213: 
                    214:     if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
                    215:         s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
                    216:         trace_milkymist_sysctl_stop_timer0();
                    217:         ptimer_stop(s->ptimer0);
                    218:     }
                    219: 
                    220:     trace_milkymist_sysctl_pulse_irq_timer0();
                    221:     qemu_irq_pulse(s->timer0_irq);
                    222: }
                    223: 
                    224: static void timer1_hit(void *opaque)
                    225: {
                    226:     MilkymistSysctlState *s = opaque;
                    227: 
                    228:     if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
                    229:         s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
                    230:         trace_milkymist_sysctl_stop_timer1();
                    231:         ptimer_stop(s->ptimer1);
                    232:     }
                    233: 
                    234:     trace_milkymist_sysctl_pulse_irq_timer1();
                    235:     qemu_irq_pulse(s->timer1_irq);
                    236: }
                    237: 
                    238: static void milkymist_sysctl_reset(DeviceState *d)
                    239: {
                    240:     MilkymistSysctlState *s =
                    241:             container_of(d, MilkymistSysctlState, busdev.qdev);
                    242:     int i;
                    243: 
                    244:     for (i = 0; i < R_MAX; i++) {
                    245:         s->regs[i] = 0;
                    246:     }
                    247: 
                    248:     ptimer_stop(s->ptimer0);
                    249:     ptimer_stop(s->ptimer1);
                    250: 
                    251:     /* defaults */
                    252:     s->regs[R_ICAP] = ICAP_READY;
                    253:     s->regs[R_SYSTEM_ID] = s->systemid;
                    254:     s->regs[R_CAPABILITIES] = s->capabilities;
                    255:     s->regs[R_GPIO_IN] = s->strappings;
                    256: }
                    257: 
                    258: static int milkymist_sysctl_init(SysBusDevice *dev)
                    259: {
                    260:     MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
                    261:     int sysctl_regs;
                    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: 
                    274:     sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
                    275:             DEVICE_NATIVE_ENDIAN);
                    276:     sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
                    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.