Annotation of qemu/hw/milkymist-sysctl.c, revision 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.