Annotation of qemu/hw/etraxfs_timer.c, revision 1.1.1.2

1.1       root        1: /*
1.1.1.2 ! root        2:  * QEMU ETRAX Timers
1.1       root        3:  *
                      4:  * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include <stdio.h>
                     25: #include <sys/time.h>
                     26: #include "hw.h"
1.1.1.2 ! root       27: #include "sysemu.h"
1.1       root       28: #include "qemu-timer.h"
1.1.1.2 ! root       29: #include "etraxfs.h"
1.1       root       30: 
1.1.1.2 ! root       31: #define D(x)
1.1       root       32: 
1.1.1.2 ! root       33: #define RW_TMR0_DIV   0x00
        !            34: #define R_TMR0_DATA   0x04
        !            35: #define RW_TMR0_CTRL  0x08
        !            36: #define RW_TMR1_DIV   0x10
        !            37: #define R_TMR1_DATA   0x14
        !            38: #define RW_TMR1_CTRL  0x18
        !            39: #define R_TIME        0x38
        !            40: #define RW_WD_CTRL    0x40
        !            41: #define R_WD_STAT     0x44
        !            42: #define RW_INTR_MASK  0x48
        !            43: #define RW_ACK_INTR   0x4c
        !            44: #define R_INTR        0x50
        !            45: #define R_MASKED_INTR 0x54
1.1       root       46: 
                     47: struct fs_timer_t {
                     48:        CPUState *env;
                     49:        qemu_irq *irq;
1.1.1.2 ! root       50:        qemu_irq *nmi;
1.1       root       51: 
1.1.1.2 ! root       52:        QEMUBH *bh_t0;
        !            53:        QEMUBH *bh_t1;
        !            54:        QEMUBH *bh_wd;
        !            55:        ptimer_state *ptimer_t0;
        !            56:        ptimer_state *ptimer_t1;
        !            57:        ptimer_state *ptimer_wd;
        !            58:        struct timeval last;
        !            59: 
        !            60:        int wd_hits;
        !            61: 
        !            62:        /* Control registers.  */
        !            63:        uint32_t rw_tmr0_div;
        !            64:        uint32_t r_tmr0_data;
        !            65:        uint32_t rw_tmr0_ctrl;
        !            66: 
        !            67:        uint32_t rw_tmr1_div;
        !            68:        uint32_t r_tmr1_data;
        !            69:        uint32_t rw_tmr1_ctrl;
        !            70: 
        !            71:        uint32_t rw_wd_ctrl;
        !            72: 
        !            73:        uint32_t rw_intr_mask;
        !            74:        uint32_t rw_ack_intr;
        !            75:        uint32_t r_intr;
        !            76:        uint32_t r_masked_intr;
        !            77: };
1.1       root       78: 
                     79: static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
                     80: {
1.1.1.2 ! root       81:        struct fs_timer_t *t = opaque;
1.1       root       82:        uint32_t r = 0;
                     83: 
                     84:        switch (addr) {
                     85:        case R_TMR0_DATA:
1.1.1.2 ! root       86:                r = ptimer_get_count(t->ptimer_t0);
1.1       root       87:                break;
                     88:        case R_TMR1_DATA:
1.1.1.2 ! root       89:                r = ptimer_get_count(t->ptimer_t1);
1.1       root       90:                break;
                     91:        case R_TIME:
1.1.1.2 ! root       92:                r = qemu_get_clock(vm_clock) / 10;
1.1       root       93:                break;
                     94:        case RW_INTR_MASK:
1.1.1.2 ! root       95:                r = t->rw_intr_mask;
1.1       root       96:                break;
                     97:        case R_MASKED_INTR:
1.1.1.2 ! root       98:                r = t->r_intr & t->rw_intr_mask;
1.1       root       99:                break;
                    100:        default:
1.1.1.2 ! root      101:                D(printf ("%s %x\n", __func__, addr));
1.1       root      102:                break;
                    103:        }
                    104:        return r;
                    105: }
                    106: 
1.1.1.2 ! root      107: #define TIMER_SLOWDOWN 1
        !           108: static void update_ctrl(struct fs_timer_t *t, int tnum)
1.1       root      109: {
1.1.1.2 ! root      110:        unsigned int op;
        !           111:        unsigned int freq;
        !           112:        unsigned int freq_hz;
        !           113:        unsigned int div;
        !           114:        uint32_t ctrl;
        !           115: 
        !           116:        ptimer_state *timer;
        !           117: 
        !           118:        if (tnum == 0) {
        !           119:                ctrl = t->rw_tmr0_ctrl;
        !           120:                div = t->rw_tmr0_div;
        !           121:                timer = t->ptimer_t0;
        !           122:        } else {
        !           123:                ctrl = t->rw_tmr1_ctrl;
        !           124:                div = t->rw_tmr1_div;
        !           125:                timer = t->ptimer_t1;
        !           126:        }
1.1       root      127: 
                    128: 
1.1.1.2 ! root      129:        op = ctrl & 3;
        !           130:        freq = ctrl >> 2;
1.1       root      131:        freq_hz = 32000000;
                    132: 
                    133:        switch (freq)
                    134:        {
                    135:        case 0:
                    136:        case 1:
1.1.1.2 ! root      137:                D(printf ("extern or disabled timer clock?\n"));
1.1       root      138:                break;
                    139:        case 4: freq_hz =  29493000; break;
                    140:        case 5: freq_hz =  32000000; break;
                    141:        case 6: freq_hz =  32768000; break;
                    142:        case 7: freq_hz = 100000000; break;
                    143:        default:
                    144:                abort();
                    145:                break;
                    146:        }
                    147: 
1.1.1.2 ! root      148:        D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
        !           149:        div = div * TIMER_SLOWDOWN;
        !           150:        div /= 1000;
        !           151:        freq_hz /= 1000;
        !           152:        ptimer_set_freq(timer, freq_hz);
        !           153:        ptimer_set_limit(timer, div, 0);
1.1       root      154: 
                    155:        switch (op)
                    156:        {
                    157:                case 0:
1.1.1.2 ! root      158:                        /* Load.  */
        !           159:                        ptimer_set_limit(timer, div, 1);
1.1       root      160:                        break;
                    161:                case 1:
1.1.1.2 ! root      162:                        /* Hold.  */
        !           163:                        ptimer_stop(timer);
1.1       root      164:                        break;
                    165:                case 2:
1.1.1.2 ! root      166:                        /* Run.  */
        !           167:                        ptimer_run(timer, 0);
1.1       root      168:                        break;
                    169:                default:
                    170:                        abort();
                    171:                        break;
                    172:        }
                    173: }
                    174: 
1.1.1.2 ! root      175: static void timer_update_irq(struct fs_timer_t *t)
        !           176: {
        !           177:        t->r_intr &= ~(t->rw_ack_intr);
        !           178:        t->r_masked_intr = t->r_intr & t->rw_intr_mask;
        !           179: 
        !           180:        D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
        !           181:        if (t->r_masked_intr)
        !           182:                qemu_irq_raise(t->irq[0]);
        !           183:        else
        !           184:                qemu_irq_lower(t->irq[0]);
        !           185: }
        !           186: 
        !           187: static void timer0_hit(void *opaque)
        !           188: {
        !           189:        struct fs_timer_t *t = opaque;
        !           190:        t->r_intr |= 1;
        !           191:        timer_update_irq(t);
        !           192: }
        !           193: 
        !           194: static void timer1_hit(void *opaque)
1.1       root      195: {
1.1.1.2 ! root      196:        struct fs_timer_t *t = opaque;
        !           197:        t->r_intr |= 2;
        !           198:        timer_update_irq(t);
        !           199: }
        !           200: 
        !           201: static void watchdog_hit(void *opaque)
        !           202: {
        !           203:        struct fs_timer_t *t = opaque;
        !           204:        if (t->wd_hits == 0) {
        !           205:                /* real hw gives a single tick before reseting but we are
        !           206:                   a bit friendlier to compensate for our slower execution.  */
        !           207:                ptimer_set_count(t->ptimer_wd, 10);
        !           208:                ptimer_run(t->ptimer_wd, 1);
        !           209:                qemu_irq_raise(t->nmi[0]);
1.1       root      210:        }
1.1.1.2 ! root      211:        else
        !           212:                qemu_system_reset_request();
        !           213: 
        !           214:        t->wd_hits++;
        !           215: }
        !           216: 
        !           217: static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value)
        !           218: {
        !           219:        unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
        !           220:        unsigned int wd_key = t->rw_wd_ctrl >> 9;
        !           221:        unsigned int wd_cnt = t->rw_wd_ctrl & 511;
        !           222:        unsigned int new_key = value >> 9 & ((1 << 7) - 1);
        !           223:        unsigned int new_cmd = (value >> 8) & 1;
        !           224: 
        !           225:        /* If the watchdog is enabled, they written key must match the
        !           226:           complement of the previous.  */
        !           227:        wd_key = ~wd_key & ((1 << 7) - 1);
        !           228: 
        !           229:        if (wd_en && wd_key != new_key)
        !           230:                return;
        !           231: 
        !           232:        D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
        !           233:                 wd_en, new_key, wd_key, new_cmd, wd_cnt));
        !           234: 
        !           235:        if (t->wd_hits)
        !           236:                qemu_irq_lower(t->nmi[0]);
        !           237: 
        !           238:        t->wd_hits = 0;
        !           239: 
        !           240:        ptimer_set_freq(t->ptimer_wd, 760);
        !           241:        if (wd_cnt == 0)
        !           242:                wd_cnt = 256;
        !           243:        ptimer_set_count(t->ptimer_wd, wd_cnt);
        !           244:        if (new_cmd)
        !           245:                ptimer_run(t->ptimer_wd, 1);
        !           246:        else
        !           247:                ptimer_stop(t->ptimer_wd);
        !           248: 
        !           249:        t->rw_wd_ctrl = value;
1.1       root      250: }
                    251: 
                    252: static void
                    253: timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
                    254: {
1.1.1.2 ! root      255:        struct fs_timer_t *t = opaque;
        !           256: 
1.1       root      257:        switch (addr)
                    258:        {
                    259:                case RW_TMR0_DIV:
1.1.1.2 ! root      260:                        t->rw_tmr0_div = value;
1.1       root      261:                        break;
                    262:                case RW_TMR0_CTRL:
1.1.1.2 ! root      263:                        D(printf ("RW_TMR0_CTRL=%x\n", value));
        !           264:                        t->rw_tmr0_ctrl = value;
        !           265:                        update_ctrl(t, 0);
1.1       root      266:                        break;
                    267:                case RW_TMR1_DIV:
1.1.1.2 ! root      268:                        t->rw_tmr1_div = value;
1.1       root      269:                        break;
                    270:                case RW_TMR1_CTRL:
1.1.1.2 ! root      271:                        D(printf ("RW_TMR1_CTRL=%x\n", value));
        !           272:                        t->rw_tmr1_ctrl = value;
        !           273:                        update_ctrl(t, 1);
1.1       root      274:                        break;
                    275:                case RW_INTR_MASK:
1.1.1.2 ! root      276:                        D(printf ("RW_INTR_MASK=%x\n", value));
        !           277:                        t->rw_intr_mask = value;
        !           278:                        timer_update_irq(t);
        !           279:                        break;
        !           280:                case RW_WD_CTRL:
        !           281:                        timer_watchdog_update(t, value);
1.1       root      282:                        break;
                    283:                case RW_ACK_INTR:
1.1.1.2 ! root      284:                        t->rw_ack_intr = value;
        !           285:                        timer_update_irq(t);
        !           286:                        t->rw_ack_intr = 0;
1.1       root      287:                        break;
                    288:                default:
1.1.1.2 ! root      289:                        printf ("%s " TARGET_FMT_plx " %x\n",
        !           290:                                __func__, addr, value);
1.1       root      291:                        break;
                    292:        }
                    293: }
                    294: 
                    295: static CPUReadMemoryFunc *timer_read[] = {
1.1.1.2 ! root      296:        NULL, NULL,
        !           297:        &timer_readl,
1.1       root      298: };
                    299: 
                    300: static CPUWriteMemoryFunc *timer_write[] = {
1.1.1.2 ! root      301:        NULL, NULL,
        !           302:        &timer_writel,
1.1       root      303: };
                    304: 
1.1.1.2 ! root      305: static void etraxfs_timer_reset(void *opaque)
1.1       root      306: {
                    307:        struct fs_timer_t *t = opaque;
                    308: 
1.1.1.2 ! root      309:        ptimer_stop(t->ptimer_t0);
        !           310:        ptimer_stop(t->ptimer_t1);
        !           311:        ptimer_stop(t->ptimer_wd);
        !           312:        t->rw_wd_ctrl = 0;
        !           313:        t->r_intr = 0;
        !           314:        t->rw_intr_mask = 0;
        !           315:        qemu_irq_lower(t->irq[0]);
1.1       root      316: }
                    317: 
1.1.1.2 ! root      318: void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, qemu_irq *nmi,
        !           319:                        target_phys_addr_t base)
1.1       root      320: {
1.1.1.2 ! root      321:        static struct fs_timer_t *t;
1.1       root      322:        int timer_regs;
                    323: 
1.1.1.2 ! root      324:        t = qemu_mallocz(sizeof *t);
        !           325: 
        !           326:        t->bh_t0 = qemu_bh_new(timer0_hit, t);
        !           327:        t->bh_t1 = qemu_bh_new(timer1_hit, t);
        !           328:        t->bh_wd = qemu_bh_new(watchdog_hit, t);
        !           329:        t->ptimer_t0 = ptimer_init(t->bh_t0);
        !           330:        t->ptimer_t1 = ptimer_init(t->bh_t1);
        !           331:        t->ptimer_wd = ptimer_init(t->bh_wd);
        !           332:        t->irq = irqs;
        !           333:        t->nmi = nmi;
        !           334:        t->env = env;
        !           335: 
        !           336:        timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t);
        !           337:        cpu_register_physical_memory (base, 0x5c, timer_regs);
1.1       root      338: 
1.1.1.2 ! root      339:        qemu_register_reset(etraxfs_timer_reset, t);
1.1       root      340: }

unix.superglobalmegacorp.com

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