1*7adca78eSYoshinori Sato /* 2*7adca78eSYoshinori Sato * Renesas 8bit timer 3*7adca78eSYoshinori Sato * 4*7adca78eSYoshinori Sato * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware 5*7adca78eSYoshinori Sato * (Rev.1.40 R01UH0033EJ0140) 6*7adca78eSYoshinori Sato * 7*7adca78eSYoshinori Sato * Copyright (c) 2019 Yoshinori Sato 8*7adca78eSYoshinori Sato * 9*7adca78eSYoshinori Sato * SPDX-License-Identifier: GPL-2.0-or-later 10*7adca78eSYoshinori Sato * 11*7adca78eSYoshinori Sato * This program is free software; you can redistribute it and/or modify it 12*7adca78eSYoshinori Sato * under the terms and conditions of the GNU General Public License, 13*7adca78eSYoshinori Sato * version 2 or later, as published by the Free Software Foundation. 14*7adca78eSYoshinori Sato * 15*7adca78eSYoshinori Sato * This program is distributed in the hope it will be useful, but WITHOUT 16*7adca78eSYoshinori Sato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17*7adca78eSYoshinori Sato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 18*7adca78eSYoshinori Sato * more details. 19*7adca78eSYoshinori Sato * 20*7adca78eSYoshinori Sato * You should have received a copy of the GNU General Public License along with 21*7adca78eSYoshinori Sato * this program. If not, see <http://www.gnu.org/licenses/>. 22*7adca78eSYoshinori Sato */ 23*7adca78eSYoshinori Sato 24*7adca78eSYoshinori Sato #include "qemu/osdep.h" 25*7adca78eSYoshinori Sato #include "qemu/log.h" 26*7adca78eSYoshinori Sato #include "hw/irq.h" 27*7adca78eSYoshinori Sato #include "hw/registerfields.h" 28*7adca78eSYoshinori Sato #include "hw/qdev-properties.h" 29*7adca78eSYoshinori Sato #include "hw/timer/renesas_tmr.h" 30*7adca78eSYoshinori Sato #include "migration/vmstate.h" 31*7adca78eSYoshinori Sato 32*7adca78eSYoshinori Sato REG8(TCR, 0) 33*7adca78eSYoshinori Sato FIELD(TCR, CCLR, 3, 2) 34*7adca78eSYoshinori Sato FIELD(TCR, OVIE, 5, 1) 35*7adca78eSYoshinori Sato FIELD(TCR, CMIEA, 6, 1) 36*7adca78eSYoshinori Sato FIELD(TCR, CMIEB, 7, 1) 37*7adca78eSYoshinori Sato REG8(TCSR, 2) 38*7adca78eSYoshinori Sato FIELD(TCSR, OSA, 0, 2) 39*7adca78eSYoshinori Sato FIELD(TCSR, OSB, 2, 2) 40*7adca78eSYoshinori Sato FIELD(TCSR, ADTE, 4, 2) 41*7adca78eSYoshinori Sato REG8(TCORA, 4) 42*7adca78eSYoshinori Sato REG8(TCORB, 6) 43*7adca78eSYoshinori Sato REG8(TCNT, 8) 44*7adca78eSYoshinori Sato REG8(TCCR, 10) 45*7adca78eSYoshinori Sato FIELD(TCCR, CKS, 0, 3) 46*7adca78eSYoshinori Sato FIELD(TCCR, CSS, 3, 2) 47*7adca78eSYoshinori Sato FIELD(TCCR, TMRIS, 7, 1) 48*7adca78eSYoshinori Sato 49*7adca78eSYoshinori Sato #define INTERNAL 0x01 50*7adca78eSYoshinori Sato #define CASCADING 0x03 51*7adca78eSYoshinori Sato #define CCLR_A 0x01 52*7adca78eSYoshinori Sato #define CCLR_B 0x02 53*7adca78eSYoshinori Sato 54*7adca78eSYoshinori Sato static const int clkdiv[] = {0, 1, 2, 8, 32, 64, 1024, 8192}; 55*7adca78eSYoshinori Sato 56*7adca78eSYoshinori Sato static uint8_t concat_reg(uint8_t *reg) 57*7adca78eSYoshinori Sato { 58*7adca78eSYoshinori Sato return (reg[0] << 8) | reg[1]; 59*7adca78eSYoshinori Sato } 60*7adca78eSYoshinori Sato 61*7adca78eSYoshinori Sato static void update_events(RTMRState *tmr, int ch) 62*7adca78eSYoshinori Sato { 63*7adca78eSYoshinori Sato uint16_t diff[TMR_NR_EVENTS], min; 64*7adca78eSYoshinori Sato int64_t next_time; 65*7adca78eSYoshinori Sato int i, event; 66*7adca78eSYoshinori Sato 67*7adca78eSYoshinori Sato if (tmr->tccr[ch] == 0) { 68*7adca78eSYoshinori Sato return ; 69*7adca78eSYoshinori Sato } 70*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tccr[ch], TCCR, CSS) == 0) { 71*7adca78eSYoshinori Sato /* external clock mode */ 72*7adca78eSYoshinori Sato /* event not happened */ 73*7adca78eSYoshinori Sato return ; 74*7adca78eSYoshinori Sato } 75*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) == CASCADING) { 76*7adca78eSYoshinori Sato /* cascading mode */ 77*7adca78eSYoshinori Sato if (ch == 1) { 78*7adca78eSYoshinori Sato tmr->next[ch] = none; 79*7adca78eSYoshinori Sato return ; 80*7adca78eSYoshinori Sato } 81*7adca78eSYoshinori Sato diff[cmia] = concat_reg(tmr->tcora) - concat_reg(tmr->tcnt); 82*7adca78eSYoshinori Sato diff[cmib] = concat_reg(tmr->tcorb) - concat_reg(tmr->tcnt); 83*7adca78eSYoshinori Sato diff[ovi] = 0x10000 - concat_reg(tmr->tcnt); 84*7adca78eSYoshinori Sato } else { 85*7adca78eSYoshinori Sato /* separate mode */ 86*7adca78eSYoshinori Sato diff[cmia] = tmr->tcora[ch] - tmr->tcnt[ch]; 87*7adca78eSYoshinori Sato diff[cmib] = tmr->tcorb[ch] - tmr->tcnt[ch]; 88*7adca78eSYoshinori Sato diff[ovi] = 0x100 - tmr->tcnt[ch]; 89*7adca78eSYoshinori Sato } 90*7adca78eSYoshinori Sato /* Search for the most recently occurring event. */ 91*7adca78eSYoshinori Sato for (event = 0, min = diff[0], i = 1; i < none; i++) { 92*7adca78eSYoshinori Sato if (min > diff[i]) { 93*7adca78eSYoshinori Sato event = i; 94*7adca78eSYoshinori Sato min = diff[i]; 95*7adca78eSYoshinori Sato } 96*7adca78eSYoshinori Sato } 97*7adca78eSYoshinori Sato tmr->next[ch] = event; 98*7adca78eSYoshinori Sato next_time = diff[event]; 99*7adca78eSYoshinori Sato next_time *= clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 100*7adca78eSYoshinori Sato next_time *= NANOSECONDS_PER_SECOND; 101*7adca78eSYoshinori Sato next_time /= tmr->input_freq; 102*7adca78eSYoshinori Sato next_time += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 103*7adca78eSYoshinori Sato timer_mod(&tmr->timer[ch], next_time); 104*7adca78eSYoshinori Sato } 105*7adca78eSYoshinori Sato 106*7adca78eSYoshinori Sato static int elapsed_time(RTMRState *tmr, int ch, int64_t delta) 107*7adca78eSYoshinori Sato { 108*7adca78eSYoshinori Sato int divrate = clkdiv[FIELD_EX8(tmr->tccr[ch], TCCR, CKS)]; 109*7adca78eSYoshinori Sato int et; 110*7adca78eSYoshinori Sato 111*7adca78eSYoshinori Sato tmr->div_round[ch] += delta; 112*7adca78eSYoshinori Sato if (divrate > 0) { 113*7adca78eSYoshinori Sato et = tmr->div_round[ch] / divrate; 114*7adca78eSYoshinori Sato tmr->div_round[ch] %= divrate; 115*7adca78eSYoshinori Sato } else { 116*7adca78eSYoshinori Sato /* disble clock. so no update */ 117*7adca78eSYoshinori Sato et = 0; 118*7adca78eSYoshinori Sato } 119*7adca78eSYoshinori Sato return et; 120*7adca78eSYoshinori Sato } 121*7adca78eSYoshinori Sato 122*7adca78eSYoshinori Sato static uint16_t read_tcnt(RTMRState *tmr, unsigned size, int ch) 123*7adca78eSYoshinori Sato { 124*7adca78eSYoshinori Sato int64_t delta, now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 125*7adca78eSYoshinori Sato int elapsed, ovf = 0; 126*7adca78eSYoshinori Sato uint16_t tcnt[2]; 127*7adca78eSYoshinori Sato uint32_t ret; 128*7adca78eSYoshinori Sato 129*7adca78eSYoshinori Sato delta = (now - tmr->tick) * NANOSECONDS_PER_SECOND / tmr->input_freq; 130*7adca78eSYoshinori Sato if (delta > 0) { 131*7adca78eSYoshinori Sato tmr->tick = now; 132*7adca78eSYoshinori Sato 133*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tccr[1], TCCR, CSS) == INTERNAL) { 134*7adca78eSYoshinori Sato /* timer1 count update */ 135*7adca78eSYoshinori Sato elapsed = elapsed_time(tmr, 1, delta); 136*7adca78eSYoshinori Sato if (elapsed >= 0x100) { 137*7adca78eSYoshinori Sato ovf = elapsed >> 8; 138*7adca78eSYoshinori Sato } 139*7adca78eSYoshinori Sato tcnt[1] = tmr->tcnt[1] + (elapsed & 0xff); 140*7adca78eSYoshinori Sato } 141*7adca78eSYoshinori Sato switch (FIELD_EX8(tmr->tccr[0], TCCR, CSS)) { 142*7adca78eSYoshinori Sato case INTERNAL: 143*7adca78eSYoshinori Sato elapsed = elapsed_time(tmr, 0, delta); 144*7adca78eSYoshinori Sato tcnt[0] = tmr->tcnt[0] + elapsed; 145*7adca78eSYoshinori Sato break; 146*7adca78eSYoshinori Sato case CASCADING: 147*7adca78eSYoshinori Sato if (ovf > 0) { 148*7adca78eSYoshinori Sato tcnt[0] = tmr->tcnt[0] + ovf; 149*7adca78eSYoshinori Sato } 150*7adca78eSYoshinori Sato break; 151*7adca78eSYoshinori Sato } 152*7adca78eSYoshinori Sato } else { 153*7adca78eSYoshinori Sato tcnt[0] = tmr->tcnt[0]; 154*7adca78eSYoshinori Sato tcnt[1] = tmr->tcnt[1]; 155*7adca78eSYoshinori Sato } 156*7adca78eSYoshinori Sato if (size == 1) { 157*7adca78eSYoshinori Sato return tcnt[ch]; 158*7adca78eSYoshinori Sato } else { 159*7adca78eSYoshinori Sato ret = 0; 160*7adca78eSYoshinori Sato ret = deposit32(ret, 0, 8, tcnt[1]); 161*7adca78eSYoshinori Sato ret = deposit32(ret, 8, 8, tcnt[0]); 162*7adca78eSYoshinori Sato return ret; 163*7adca78eSYoshinori Sato } 164*7adca78eSYoshinori Sato } 165*7adca78eSYoshinori Sato 166*7adca78eSYoshinori Sato static uint8_t read_tccr(uint8_t r) 167*7adca78eSYoshinori Sato { 168*7adca78eSYoshinori Sato uint8_t tccr = 0; 169*7adca78eSYoshinori Sato tccr = FIELD_DP8(tccr, TCCR, TMRIS, 170*7adca78eSYoshinori Sato FIELD_EX8(r, TCCR, TMRIS)); 171*7adca78eSYoshinori Sato tccr = FIELD_DP8(tccr, TCCR, CSS, 172*7adca78eSYoshinori Sato FIELD_EX8(r, TCCR, CSS)); 173*7adca78eSYoshinori Sato tccr = FIELD_DP8(tccr, TCCR, CKS, 174*7adca78eSYoshinori Sato FIELD_EX8(r, TCCR, CKS)); 175*7adca78eSYoshinori Sato return tccr; 176*7adca78eSYoshinori Sato } 177*7adca78eSYoshinori Sato 178*7adca78eSYoshinori Sato static uint64_t tmr_read(void *opaque, hwaddr addr, unsigned size) 179*7adca78eSYoshinori Sato { 180*7adca78eSYoshinori Sato RTMRState *tmr = opaque; 181*7adca78eSYoshinori Sato int ch = addr & 1; 182*7adca78eSYoshinori Sato uint64_t ret; 183*7adca78eSYoshinori Sato 184*7adca78eSYoshinori Sato if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 185*7adca78eSYoshinori Sato qemu_log_mask(LOG_GUEST_ERROR, "renesas_tmr: Invalid read size 0x%" 186*7adca78eSYoshinori Sato HWADDR_PRIX "\n", 187*7adca78eSYoshinori Sato addr); 188*7adca78eSYoshinori Sato return UINT64_MAX; 189*7adca78eSYoshinori Sato } 190*7adca78eSYoshinori Sato switch (addr & 0x0e) { 191*7adca78eSYoshinori Sato case A_TCR: 192*7adca78eSYoshinori Sato ret = 0; 193*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCR, CCLR, 194*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcr[ch], TCR, CCLR)); 195*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCR, OVIE, 196*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcr[ch], TCR, OVIE)); 197*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCR, CMIEA, 198*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)); 199*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCR, CMIEB, 200*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)); 201*7adca78eSYoshinori Sato return ret; 202*7adca78eSYoshinori Sato case A_TCSR: 203*7adca78eSYoshinori Sato ret = 0; 204*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCSR, OSA, 205*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcsr[ch], TCSR, OSA)); 206*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCSR, OSB, 207*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcsr[ch], TCSR, OSB)); 208*7adca78eSYoshinori Sato switch (ch) { 209*7adca78eSYoshinori Sato case 0: 210*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCSR, ADTE, 211*7adca78eSYoshinori Sato FIELD_EX8(tmr->tcsr[ch], TCSR, ADTE)); 212*7adca78eSYoshinori Sato break; 213*7adca78eSYoshinori Sato case 1: /* CH1 ADTE unimplement always 1 */ 214*7adca78eSYoshinori Sato ret = FIELD_DP8(ret, TCSR, ADTE, 1); 215*7adca78eSYoshinori Sato break; 216*7adca78eSYoshinori Sato } 217*7adca78eSYoshinori Sato return ret; 218*7adca78eSYoshinori Sato case A_TCORA: 219*7adca78eSYoshinori Sato if (size == 1) { 220*7adca78eSYoshinori Sato return tmr->tcora[ch]; 221*7adca78eSYoshinori Sato } else if (ch == 0) { 222*7adca78eSYoshinori Sato return concat_reg(tmr->tcora); 223*7adca78eSYoshinori Sato } 224*7adca78eSYoshinori Sato case A_TCORB: 225*7adca78eSYoshinori Sato if (size == 1) { 226*7adca78eSYoshinori Sato return tmr->tcorb[ch]; 227*7adca78eSYoshinori Sato } else { 228*7adca78eSYoshinori Sato return concat_reg(tmr->tcorb); 229*7adca78eSYoshinori Sato } 230*7adca78eSYoshinori Sato case A_TCNT: 231*7adca78eSYoshinori Sato return read_tcnt(tmr, size, ch); 232*7adca78eSYoshinori Sato case A_TCCR: 233*7adca78eSYoshinori Sato if (size == 1) { 234*7adca78eSYoshinori Sato return read_tccr(tmr->tccr[ch]); 235*7adca78eSYoshinori Sato } else { 236*7adca78eSYoshinori Sato return read_tccr(tmr->tccr[0]) << 8 | read_tccr(tmr->tccr[1]); 237*7adca78eSYoshinori Sato } 238*7adca78eSYoshinori Sato default: 239*7adca78eSYoshinori Sato qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 240*7adca78eSYoshinori Sato " not implemented\n", 241*7adca78eSYoshinori Sato addr); 242*7adca78eSYoshinori Sato break; 243*7adca78eSYoshinori Sato } 244*7adca78eSYoshinori Sato return UINT64_MAX; 245*7adca78eSYoshinori Sato } 246*7adca78eSYoshinori Sato 247*7adca78eSYoshinori Sato static void tmr_write_count(RTMRState *tmr, int ch, unsigned size, 248*7adca78eSYoshinori Sato uint8_t *reg, uint64_t val) 249*7adca78eSYoshinori Sato { 250*7adca78eSYoshinori Sato if (size == 1) { 251*7adca78eSYoshinori Sato reg[ch] = val; 252*7adca78eSYoshinori Sato update_events(tmr, ch); 253*7adca78eSYoshinori Sato } else { 254*7adca78eSYoshinori Sato reg[0] = extract32(val, 8, 8); 255*7adca78eSYoshinori Sato reg[1] = extract32(val, 0, 8); 256*7adca78eSYoshinori Sato update_events(tmr, 0); 257*7adca78eSYoshinori Sato update_events(tmr, 1); 258*7adca78eSYoshinori Sato } 259*7adca78eSYoshinori Sato } 260*7adca78eSYoshinori Sato 261*7adca78eSYoshinori Sato static void tmr_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 262*7adca78eSYoshinori Sato { 263*7adca78eSYoshinori Sato RTMRState *tmr = opaque; 264*7adca78eSYoshinori Sato int ch = addr & 1; 265*7adca78eSYoshinori Sato 266*7adca78eSYoshinori Sato if (size == 2 && (ch != 0 || addr == A_TCR || addr == A_TCSR)) { 267*7adca78eSYoshinori Sato qemu_log_mask(LOG_GUEST_ERROR, 268*7adca78eSYoshinori Sato "renesas_tmr: Invalid write size 0x%" HWADDR_PRIX "\n", 269*7adca78eSYoshinori Sato addr); 270*7adca78eSYoshinori Sato return; 271*7adca78eSYoshinori Sato } 272*7adca78eSYoshinori Sato switch (addr & 0x0e) { 273*7adca78eSYoshinori Sato case A_TCR: 274*7adca78eSYoshinori Sato tmr->tcr[ch] = val; 275*7adca78eSYoshinori Sato break; 276*7adca78eSYoshinori Sato case A_TCSR: 277*7adca78eSYoshinori Sato tmr->tcsr[ch] = val; 278*7adca78eSYoshinori Sato break; 279*7adca78eSYoshinori Sato case A_TCORA: 280*7adca78eSYoshinori Sato tmr_write_count(tmr, ch, size, tmr->tcora, val); 281*7adca78eSYoshinori Sato break; 282*7adca78eSYoshinori Sato case A_TCORB: 283*7adca78eSYoshinori Sato tmr_write_count(tmr, ch, size, tmr->tcorb, val); 284*7adca78eSYoshinori Sato break; 285*7adca78eSYoshinori Sato case A_TCNT: 286*7adca78eSYoshinori Sato tmr_write_count(tmr, ch, size, tmr->tcnt, val); 287*7adca78eSYoshinori Sato break; 288*7adca78eSYoshinori Sato case A_TCCR: 289*7adca78eSYoshinori Sato tmr_write_count(tmr, ch, size, tmr->tccr, val); 290*7adca78eSYoshinori Sato break; 291*7adca78eSYoshinori Sato default: 292*7adca78eSYoshinori Sato qemu_log_mask(LOG_UNIMP, "renesas_tmr: Register 0x%" HWADDR_PRIX 293*7adca78eSYoshinori Sato " not implemented\n", 294*7adca78eSYoshinori Sato addr); 295*7adca78eSYoshinori Sato break; 296*7adca78eSYoshinori Sato } 297*7adca78eSYoshinori Sato } 298*7adca78eSYoshinori Sato 299*7adca78eSYoshinori Sato static const MemoryRegionOps tmr_ops = { 300*7adca78eSYoshinori Sato .write = tmr_write, 301*7adca78eSYoshinori Sato .read = tmr_read, 302*7adca78eSYoshinori Sato .endianness = DEVICE_LITTLE_ENDIAN, 303*7adca78eSYoshinori Sato .impl = { 304*7adca78eSYoshinori Sato .min_access_size = 1, 305*7adca78eSYoshinori Sato .max_access_size = 2, 306*7adca78eSYoshinori Sato }, 307*7adca78eSYoshinori Sato .valid = { 308*7adca78eSYoshinori Sato .min_access_size = 1, 309*7adca78eSYoshinori Sato .max_access_size = 2, 310*7adca78eSYoshinori Sato }, 311*7adca78eSYoshinori Sato }; 312*7adca78eSYoshinori Sato 313*7adca78eSYoshinori Sato static void timer_events(RTMRState *tmr, int ch); 314*7adca78eSYoshinori Sato 315*7adca78eSYoshinori Sato static uint16_t issue_event(RTMRState *tmr, int ch, int sz, 316*7adca78eSYoshinori Sato uint16_t tcnt, uint16_t tcora, uint16_t tcorb) 317*7adca78eSYoshinori Sato { 318*7adca78eSYoshinori Sato uint16_t ret = tcnt; 319*7adca78eSYoshinori Sato 320*7adca78eSYoshinori Sato switch (tmr->next[ch]) { 321*7adca78eSYoshinori Sato case none: 322*7adca78eSYoshinori Sato break; 323*7adca78eSYoshinori Sato case cmia: 324*7adca78eSYoshinori Sato if (tcnt >= tcora) { 325*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_A) { 326*7adca78eSYoshinori Sato ret = tcnt - tcora; 327*7adca78eSYoshinori Sato } 328*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEA)) { 329*7adca78eSYoshinori Sato qemu_irq_pulse(tmr->cmia[ch]); 330*7adca78eSYoshinori Sato } 331*7adca78eSYoshinori Sato if (sz == 8 && ch == 0 && 332*7adca78eSYoshinori Sato FIELD_EX8(tmr->tccr[1], TCCR, CSS) == CASCADING) { 333*7adca78eSYoshinori Sato tmr->tcnt[1]++; 334*7adca78eSYoshinori Sato timer_events(tmr, 1); 335*7adca78eSYoshinori Sato } 336*7adca78eSYoshinori Sato } 337*7adca78eSYoshinori Sato break; 338*7adca78eSYoshinori Sato case cmib: 339*7adca78eSYoshinori Sato if (tcnt >= tcorb) { 340*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tcr[ch], TCR, CCLR) == CCLR_B) { 341*7adca78eSYoshinori Sato ret = tcnt - tcorb; 342*7adca78eSYoshinori Sato } 343*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tcr[ch], TCR, CMIEB)) { 344*7adca78eSYoshinori Sato qemu_irq_pulse(tmr->cmib[ch]); 345*7adca78eSYoshinori Sato } 346*7adca78eSYoshinori Sato } 347*7adca78eSYoshinori Sato break; 348*7adca78eSYoshinori Sato case ovi: 349*7adca78eSYoshinori Sato if ((tcnt >= (1 << sz)) && FIELD_EX8(tmr->tcr[ch], TCR, OVIE)) { 350*7adca78eSYoshinori Sato qemu_irq_pulse(tmr->ovi[ch]); 351*7adca78eSYoshinori Sato } 352*7adca78eSYoshinori Sato break; 353*7adca78eSYoshinori Sato default: 354*7adca78eSYoshinori Sato g_assert_not_reached(); 355*7adca78eSYoshinori Sato } 356*7adca78eSYoshinori Sato return ret; 357*7adca78eSYoshinori Sato } 358*7adca78eSYoshinori Sato 359*7adca78eSYoshinori Sato static void timer_events(RTMRState *tmr, int ch) 360*7adca78eSYoshinori Sato { 361*7adca78eSYoshinori Sato uint16_t tcnt; 362*7adca78eSYoshinori Sato 363*7adca78eSYoshinori Sato tmr->tcnt[ch] = read_tcnt(tmr, 1, ch); 364*7adca78eSYoshinori Sato if (FIELD_EX8(tmr->tccr[0], TCCR, CSS) != CASCADING) { 365*7adca78eSYoshinori Sato tmr->tcnt[ch] = issue_event(tmr, ch, 8, 366*7adca78eSYoshinori Sato tmr->tcnt[ch], 367*7adca78eSYoshinori Sato tmr->tcora[ch], 368*7adca78eSYoshinori Sato tmr->tcorb[ch]) & 0xff; 369*7adca78eSYoshinori Sato } else { 370*7adca78eSYoshinori Sato if (ch == 1) { 371*7adca78eSYoshinori Sato return ; 372*7adca78eSYoshinori Sato } 373*7adca78eSYoshinori Sato tcnt = issue_event(tmr, ch, 16, 374*7adca78eSYoshinori Sato concat_reg(tmr->tcnt), 375*7adca78eSYoshinori Sato concat_reg(tmr->tcora), 376*7adca78eSYoshinori Sato concat_reg(tmr->tcorb)); 377*7adca78eSYoshinori Sato tmr->tcnt[0] = (tcnt >> 8) & 0xff; 378*7adca78eSYoshinori Sato tmr->tcnt[1] = tcnt & 0xff; 379*7adca78eSYoshinori Sato } 380*7adca78eSYoshinori Sato update_events(tmr, ch); 381*7adca78eSYoshinori Sato } 382*7adca78eSYoshinori Sato 383*7adca78eSYoshinori Sato static void timer_event0(void *opaque) 384*7adca78eSYoshinori Sato { 385*7adca78eSYoshinori Sato RTMRState *tmr = opaque; 386*7adca78eSYoshinori Sato 387*7adca78eSYoshinori Sato timer_events(tmr, 0); 388*7adca78eSYoshinori Sato } 389*7adca78eSYoshinori Sato 390*7adca78eSYoshinori Sato static void timer_event1(void *opaque) 391*7adca78eSYoshinori Sato { 392*7adca78eSYoshinori Sato RTMRState *tmr = opaque; 393*7adca78eSYoshinori Sato 394*7adca78eSYoshinori Sato timer_events(tmr, 1); 395*7adca78eSYoshinori Sato } 396*7adca78eSYoshinori Sato 397*7adca78eSYoshinori Sato static void rtmr_reset(DeviceState *dev) 398*7adca78eSYoshinori Sato { 399*7adca78eSYoshinori Sato RTMRState *tmr = RTMR(dev); 400*7adca78eSYoshinori Sato tmr->tcr[0] = tmr->tcr[1] = 0x00; 401*7adca78eSYoshinori Sato tmr->tcsr[0] = 0x00; 402*7adca78eSYoshinori Sato tmr->tcsr[1] = 0x10; 403*7adca78eSYoshinori Sato tmr->tcnt[0] = tmr->tcnt[1] = 0x00; 404*7adca78eSYoshinori Sato tmr->tcora[0] = tmr->tcora[1] = 0xff; 405*7adca78eSYoshinori Sato tmr->tcorb[0] = tmr->tcorb[1] = 0xff; 406*7adca78eSYoshinori Sato tmr->tccr[0] = tmr->tccr[1] = 0x00; 407*7adca78eSYoshinori Sato tmr->next[0] = tmr->next[1] = none; 408*7adca78eSYoshinori Sato tmr->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 409*7adca78eSYoshinori Sato } 410*7adca78eSYoshinori Sato 411*7adca78eSYoshinori Sato static void rtmr_init(Object *obj) 412*7adca78eSYoshinori Sato { 413*7adca78eSYoshinori Sato SysBusDevice *d = SYS_BUS_DEVICE(obj); 414*7adca78eSYoshinori Sato RTMRState *tmr = RTMR(obj); 415*7adca78eSYoshinori Sato int i; 416*7adca78eSYoshinori Sato 417*7adca78eSYoshinori Sato memory_region_init_io(&tmr->memory, OBJECT(tmr), &tmr_ops, 418*7adca78eSYoshinori Sato tmr, "renesas-tmr", 0x10); 419*7adca78eSYoshinori Sato sysbus_init_mmio(d, &tmr->memory); 420*7adca78eSYoshinori Sato 421*7adca78eSYoshinori Sato for (i = 0; i < ARRAY_SIZE(tmr->ovi); i++) { 422*7adca78eSYoshinori Sato sysbus_init_irq(d, &tmr->cmia[i]); 423*7adca78eSYoshinori Sato sysbus_init_irq(d, &tmr->cmib[i]); 424*7adca78eSYoshinori Sato sysbus_init_irq(d, &tmr->ovi[i]); 425*7adca78eSYoshinori Sato } 426*7adca78eSYoshinori Sato timer_init_ns(&tmr->timer[0], QEMU_CLOCK_VIRTUAL, timer_event0, tmr); 427*7adca78eSYoshinori Sato timer_init_ns(&tmr->timer[1], QEMU_CLOCK_VIRTUAL, timer_event1, tmr); 428*7adca78eSYoshinori Sato } 429*7adca78eSYoshinori Sato 430*7adca78eSYoshinori Sato static const VMStateDescription vmstate_rtmr = { 431*7adca78eSYoshinori Sato .name = "rx-tmr", 432*7adca78eSYoshinori Sato .version_id = 1, 433*7adca78eSYoshinori Sato .minimum_version_id = 1, 434*7adca78eSYoshinori Sato .fields = (VMStateField[]) { 435*7adca78eSYoshinori Sato VMSTATE_INT64(tick, RTMRState), 436*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcnt, RTMRState, TMR_CH), 437*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcora, RTMRState, TMR_CH), 438*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcorb, RTMRState, TMR_CH), 439*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcr, RTMRState, TMR_CH), 440*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tccr, RTMRState, TMR_CH), 441*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcor, RTMRState, TMR_CH), 442*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(tcsr, RTMRState, TMR_CH), 443*7adca78eSYoshinori Sato VMSTATE_INT64_ARRAY(div_round, RTMRState, TMR_CH), 444*7adca78eSYoshinori Sato VMSTATE_UINT8_ARRAY(next, RTMRState, TMR_CH), 445*7adca78eSYoshinori Sato VMSTATE_TIMER_ARRAY(timer, RTMRState, TMR_CH), 446*7adca78eSYoshinori Sato VMSTATE_END_OF_LIST() 447*7adca78eSYoshinori Sato } 448*7adca78eSYoshinori Sato }; 449*7adca78eSYoshinori Sato 450*7adca78eSYoshinori Sato static Property rtmr_properties[] = { 451*7adca78eSYoshinori Sato DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), 452*7adca78eSYoshinori Sato DEFINE_PROP_END_OF_LIST(), 453*7adca78eSYoshinori Sato }; 454*7adca78eSYoshinori Sato 455*7adca78eSYoshinori Sato static void rtmr_class_init(ObjectClass *klass, void *data) 456*7adca78eSYoshinori Sato { 457*7adca78eSYoshinori Sato DeviceClass *dc = DEVICE_CLASS(klass); 458*7adca78eSYoshinori Sato 459*7adca78eSYoshinori Sato dc->vmsd = &vmstate_rtmr; 460*7adca78eSYoshinori Sato dc->reset = rtmr_reset; 461*7adca78eSYoshinori Sato device_class_set_props(dc, rtmr_properties); 462*7adca78eSYoshinori Sato } 463*7adca78eSYoshinori Sato 464*7adca78eSYoshinori Sato static const TypeInfo rtmr_info = { 465*7adca78eSYoshinori Sato .name = TYPE_RENESAS_TMR, 466*7adca78eSYoshinori Sato .parent = TYPE_SYS_BUS_DEVICE, 467*7adca78eSYoshinori Sato .instance_size = sizeof(RTMRState), 468*7adca78eSYoshinori Sato .instance_init = rtmr_init, 469*7adca78eSYoshinori Sato .class_init = rtmr_class_init, 470*7adca78eSYoshinori Sato }; 471*7adca78eSYoshinori Sato 472*7adca78eSYoshinori Sato static void rtmr_register_types(void) 473*7adca78eSYoshinori Sato { 474*7adca78eSYoshinori Sato type_register_static(&rtmr_info); 475*7adca78eSYoshinori Sato } 476*7adca78eSYoshinori Sato 477*7adca78eSYoshinori Sato type_init(rtmr_register_types) 478