All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alastair D'Silva" <alastair@au1.ibm.com>
To: "Cédric Le Goater" <clg@kaod.org>, qemu-arm@nongnu.org
Cc: Andrew Jeffery <andrew@aj.id.au>,
	Peter Maydell <peter.maydell@linaro.org>,
	qemu-devel@nongnu.org, Joel Stanley <joel@jms.id.au>
Subject: Re: [Qemu-arm] [PATCH 3/4] hw/timer: Add Epson RX8900 RTC support
Date: Fri, 18 Nov 2016 11:19:18 +1100	[thread overview]
Message-ID: <1479428358.11116.46.camel@au1.ibm.com> (raw)
In-Reply-To: <b4c2feb1-7c5a-01de-b8c8-893d2c7785f6@kaod.org>

On Thu, 2016-11-17 at 09:29 +0100, Cédric Le Goater wrote:
On 11/17/2016 05:36 AM, Alastair D'Silva wrote:
> > 
> > From: Alastair D'Silva <alastair@d-silva.org>
> > 
> > This patch adds support for the Epson RX8900 RTC chip.
> 
> It would be nice to have a short list of the features this 
> chip has and also the main point of the design. I see you 
> are using a BH.
> 

Ok

> 
> > 
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> > ---
> >  default-configs/arm-softmmu.mak |   1 +
> >  hw/timer/Makefile.objs          |   2 +
> >  hw/timer/rx8900.c               | 891
> > ++++++++++++++++++++++++++++++++++++++++
> >  hw/timer/rx8900_regs.h          | 125 ++++++
> >  tests/Makefile.include          |   2 +
> >  tests/rx8900-test.c             | 800
> > ++++++++++++++++++++++++++++++++++++
> 
> Nice test ! But Why aren't you using the aspeed machine in 
> qtest ? 
> 
> The reason I am asking is because the I2C controller model 
> is a little too simplistic in the way it handles the irq 
> status and we would need a test for it.
> 

The aspeed machine is missing a bunch of I2C infrastructure
(imx_i2c_create & friends) required to access it from the test harness,
and I don't have the knowledge required to implement it. I am working
on the premise that the RX8900 is an independent device, and so can be
tested independently of the aspeed model.

> 
> Also I would put the test case in another patch, after the 
> model and after patch 2 also which introduces named 
> interrupts for qtest.
> 

Ok

> 
> > 
> >  6 files changed, 1821 insertions(+)
> >  create mode 100644 hw/timer/rx8900.c
> >  create mode 100644 hw/timer/rx8900_regs.h
> >  create mode 100644 tests/rx8900-test.c
> > 
> > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-
> > softmmu.mak
> > index 6de3e16..adb600e 100644
> > --- a/default-configs/arm-softmmu.mak
> > +++ b/default-configs/arm-softmmu.mak
> > @@ -29,6 +29,7 @@ CONFIG_SMC91C111=y
> >  CONFIG_ALLWINNER_EMAC=y
> >  CONFIG_IMX_FEC=y
> >  CONFIG_DS1338=y
> > +CONFIG_RX8900=y
> >  CONFIG_PFLASH_CFI01=y
> >  CONFIG_PFLASH_CFI02=y
> >  CONFIG_MICRODRIVE=y
> > diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> > index 7ba8c23..fa028ac 100644
> > --- a/hw/timer/Makefile.objs
> > +++ b/hw/timer/Makefile.objs
> > @@ -3,6 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
> >  common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
> >  common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
> >  common-obj-$(CONFIG_DS1338) += ds1338.o
> > +common-obj-$(CONFIG_RX8900) += rx8900.o
> >  common-obj-$(CONFIG_HPET) += hpet.o
> >  common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
> >  common-obj-$(CONFIG_M48T59) += m48t59.o
> > @@ -17,6 +18,7 @@ common-obj-$(CONFIG_IMX) += imx_epit.o
> >  common-obj-$(CONFIG_IMX) += imx_gpt.o
> >  common-obj-$(CONFIG_LM32) += lm32_timer.o
> >  common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
> > +common-obj-$(CONFIG_RX8900) += rx8900.o
> >  
> >  obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
> >  obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
> > diff --git a/hw/timer/rx8900.c b/hw/timer/rx8900.c
> > new file mode 100644
> > index 0000000..208a31b
> > --- /dev/null
> > +++ b/hw/timer/rx8900.c
> > @@ -0,0 +1,891 @@
> > +/*
> > + * Epson RX8900SA/CE Realtime Clock Module
> > + *
> > + * Copyright (c) 2016 IBM Corporation
> > + * Authors:
> > + *  Alastair D'Silva <alastair@d-silva.org>
> > + *
> > + * This code is licensed under the GPL version 2 or later.  See
> > + * the COPYING file in the top-level directory.
> > + *
> > + * Datasheet available at:
> > + *  https://support.epson.biz/td/api/doc_check.php?dl=app_RX8900CE
> > &lang=en
> > + *
> > + * Not implemented:
> > + *  Implement Timer Counters
> > + *  Implement i2c timeout
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "hw/i2c/i2c.h"
> > +#include "hw/timer/rx8900_regs.h"
> > +#include "hw/ptimer.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/bcd.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/log.h"
> > +#include "qapi/error.h"
> > +#include "qapi/visitor.h"
> > +
> > + #include <sys/time.h>
> > +
> > + #include <execinfo.h>
> > +
> > +#define TYPE_RX8900 "rx8900"
> > +#define RX8900(obj) OBJECT_CHECK(RX8900State, (obj), TYPE_RX8900)
> > +
> > +static bool log;
> > +
> > +typedef struct RX8900State {
> > +    I2CSlave parent_obj;
> > +
> > +    ptimer_state *sec_timer; /* triggered once per second */
> > +    ptimer_state *fout_timer;
> > +    ptimer_state *countdown_timer;
> > +    bool fout;
> > +    int64_t offset;
> > +    uint8_t weekday; /* Saved for deferred offset calculation, 0-6 
> > */
> > +    uint8_t wday_offset;
> > +    uint8_t nvram[RX8900_NVRAM_SIZE];
> > +    int32_t ptr; /* Wrapped to stay within RX8900_NVRAM_SIZE */
> > +    bool addr_byte;
> > +    uint8_t last_interrupt_seconds;
> > +    uint8_t last_update_interrupt_minutes;
> > +    qemu_irq interrupt_pin;
> > +    qemu_irq fout_pin;
> > +} RX8900State;
> > +
> > +static const VMStateDescription vmstate_rx8900 = {
> > +    .name = "rx8900",
> > +    .version_id = 2,
> > +    .minimum_version_id = 1,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_I2C_SLAVE(parent_obj, RX8900State),
> > +        VMSTATE_PTIMER(sec_timer, RX8900State),
> > +        VMSTATE_PTIMER(fout_timer, RX8900State),
> > +        VMSTATE_PTIMER(countdown_timer, RX8900State),
> > +        VMSTATE_BOOL(fout, RX8900State),
> > +        VMSTATE_INT64(offset, RX8900State),
> > +        VMSTATE_UINT8_V(weekday, RX8900State, 2),
> > +        VMSTATE_UINT8_V(wday_offset, RX8900State, 2),
> > +        VMSTATE_UINT8_ARRAY(nvram, RX8900State,
> > RX8900_NVRAM_SIZE),
> > +        VMSTATE_INT32(ptr, RX8900State),
> > +        VMSTATE_BOOL(addr_byte, RX8900State),
> > +        VMSTATE_UINT8_V(last_interrupt_seconds, RX8900State, 2),
> > +        VMSTATE_UINT8_V(last_update_interrupt_minutes,
> > RX8900State, 2),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void rx8900_reset(DeviceState *dev);
> > +static void disable_countdown_timer(RX8900State *s);
> > +static void enable_countdown_timer(RX8900State *s);
> > +static void disable_timer(RX8900State *s);
> > +static void enable_timer(RX8900State *s);
> > +
> > +#ifdef RX8900_TRACE
> > +#define RX8900_TRACE_BUF_SIZE 256
> > +/**
> > + * Emit a trace message
> > + * @param file the source filename
> > + * @param line the line number the message was emitted from
> > + * @param dev the RX8900 device
> > + * @param fmt a printf style format
> > + */
> > +static void trace(const char *file, int line, const char *func,
> > +        I2CSlave *dev, const char *fmt, ...)
> > +{
> > +    va_list ap;
> > +    char buf[RX8900_TRACE_BUF_SIZE];
> > +    char timestamp[32];
> > +    int len;
> > +    struct timeval now;
> > +    struct tm *now2;
> > +
> > +    gettimeofday(&now, NULL);
> > +    now2 = localtime(&now.tv_sec);
> > +
> > +    strftime(timestamp, sizeof(timestamp), "%F %T", now2);
> > +
> > +    len = snprintf(buf, sizeof(buf), "\n\t%s.%03ld %s:%s:%d:
> > RX8900 %s %s@0x%x: %s",
> > +            timestamp, now.tv_usec / 1000,
> > +            file, func, line, dev->qdev.id, dev->qdev.parent_bus-
> > >name,
> > +            dev->address, fmt);
> > +    if (len >= RX8900_TRACE_BUF_SIZE) {
> > +        error_report("%s:%d: Trace buffer overflow", file, line);
> > +    }
> > +
> > +    va_start(ap, fmt);
> > +    error_vreport(buf, ap);
> > +    va_end(ap);
> > +}
> > +
> > +/**
> > + * Emit a trace message
> > + * @param dev the RX8900 device
> > + * @param fmt a printf format
> > + */
> > +#define TRACE(dev, fmt, ...) \
> > +    do { \
> > +        if (log) { \
> > +            trace(__FILE__, __LINE__, __func__, &dev, fmt, ##
> > __VA_ARGS__); \
> > +        } \
> > +    } while (0)
> > +#else
> > +#define TRACE(dev, fmt, ...)
> > +#endif
> 
> 
> Although this is very pratical and nicely written, I don't 
> think you can keep these TRACE calls in the code. You should 
> use the qemu trace subsystem for it.
> 

Ok. Would it be worth expanding this to include the file & line, or do
you expect resistance?

> 
> > 
> > +static void capture_current_time(RX8900State *s)
> > +{
> > +    /* Capture the current time into the secondary registers
> > +     * which will be actually read by the data transfer operation.
> > +     */
> > +    struct tm now;
> > +    qemu_get_timedate(&now, s->offset);
> > +    s->nvram[SECONDS] = to_bcd(now.tm_sec);
> > +    s->nvram[MINUTES] = to_bcd(now.tm_min);
> > +    s->nvram[HOURS] = to_bcd(now.tm_hour);
> > +
> > +    s->nvram[WEEKDAY] = 0x01 << ((now.tm_wday + s->wday_offset) %
> > 7);
> > +    s->nvram[DAY] = to_bcd(now.tm_mday);
> > +    s->nvram[MONTH] = to_bcd(now.tm_mon + 1);
> > +    s->nvram[YEAR] = to_bcd(now.tm_year % 100);
> > +
> > +    s->nvram[EXT_SECONDS] = s->nvram[SECONDS];
> > +    s->nvram[EXT_MINUTES] = s->nvram[MINUTES];
> > +    s->nvram[EXT_HOURS] = s->nvram[HOURS];
> > +    s->nvram[EXT_WEEKDAY] = s->nvram[WEEKDAY];
> > +    s->nvram[EXT_DAY] = s->nvram[DAY];
> > +    s->nvram[EXT_MONTH] = s->nvram[MONTH];
> > +    s->nvram[EXT_YEAR] = s->nvram[YEAR];
> > +
> > +    TRACE(s->parent_obj, "Update current time to %02d:%02d:%02d %d
> > %d/%d/%d "
> > +            "(0x%02x%02x%02x%02x%02x%02x%02x)",
> > +            now.tm_hour, now.tm_min, now.tm_sec,
> > +            (now.tm_wday + s->wday_offset) % 7,
> > +            now.tm_mday, now.tm_mon, now.tm_year + 1900,
> > +            s->nvram[HOURS], s->nvram[MINUTES], s->nvram[SECONDS],
> > +            s->nvram[WEEKDAY],
> > +            s->nvram[DAY], s->nvram[MONTH], s->nvram[YEAR]);
> > +}
> > +
> > +/**
> > + * Increment the internal register pointer, dealing with wrapping
> > + * @param s the RTC to operate on
> > + */
> > +static void inc_regptr(RX8900State *s)
> > +{
> > +    /* The register pointer wraps around after 0x1F
> > +     */
> > +    s->ptr = (s->ptr + 1) & (RX8900_NVRAM_SIZE - 1);
> > +    TRACE(s->parent_obj, "Operating on register 0x%02x", s->ptr);
> > +
> > +    if (s->ptr == 0x00) {
> > +        TRACE(s->parent_obj, "Register pointer has overflowed,
> > wrapping to 0");
> > +        capture_current_time(s);
> > +    }
> > +}
> > +
> > +/**
> > + * Receive an I2C Event
> > + * @param i2c the i2c device instance
> > + * @param event the event to handle
> > + */
> > +static void rx8900_event(I2CSlave *i2c, enum i2c_event event)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +
> > +    switch (event) {
> > +    case I2C_START_RECV:
> > +        /* In h/w, time capture happens on any START condition,
> > not just a
> > +         * START_RECV. For the emulation, it doesn't actually
> > matter,
> > +         * since a START_RECV has to occur before the data can be
> > read.
> > +         */
> > +        capture_current_time(s);
> > +        break;
> > +    case I2C_START_SEND:
> > +        s->addr_byte = true;
> > +        break;
> > +    case I2C_FINISH:
> > +        if (s->weekday < 7) {
> > +            /* We defer the weekday calculation as it is handed to
> > us before
> > +             * the date has been updated. If we calculate the
> > weekday offset
> > +             * when it is passed to us, we will incorrectly
> > determine it
> > +             * based on the current emulated date, rather than the
> > date that
> > +             * has been written.
> > +             */
> > +            struct tm now;
> > +            qemu_get_timedate(&now, s->offset);
> > +
> > +            s->wday_offset = (s->weekday - now.tm_wday + 7) % 7;
> > +
> > +            TRACE(s->parent_obj, "Set weekday to %d (0x%02x),
> > wday_offset=%d",
> > +                    s->weekday, BIT(s->weekday), s->wday_offset);
> > +
> > +            s->weekday = 7;
> > +        }
> > +        break;
> > +
> > +    default:
> > +        break;
> > +    }
> > +}
> > +
> > +/**
> > + * Perform an i2c receive action
> > + * @param i2c the i2c device instance
> > + * @return the value of the current register
> > + * @post the internal register pointer is incremented
> > + */
> > +static int rx8900_recv(I2CSlave *i2c)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +    uint8_t res = s->nvram[s->ptr];
> > +    TRACE(s->parent_obj, "Read register 0x%x = 0x%x", s->ptr,
> > res);
> > +    inc_regptr(s);
> > +    return res;
> > +}
> > +
> > +/**
> > + * Validate the extension register and perform actions based on
> > the bits
> > + * @param s the RTC to operate on
> > + * @param data the new data for the extension register
> > + */
> > +static void update_extension_register(RX8900State *s, uint8_t
> > data)
> > +{
> > +    if (data & EXT_MASK_TEST) {
> > +        error_report("WARNING: RX8900 - "
> > +            "Test bit is enabled but is forbidden by the
> > manufacturer");
> 
> may be use instead :
> 
>        qemu_log_mask(LOG_GUEST_ERROR,
> 

OK

> > 
> > +    }
> > +
> > +    if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> > +            (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> > +        uint8_t fsel = (data & (EXT_MASK_FSEL0 | EXT_MASK_FSEL1))
> > +                >> EXT_REG_FSEL0;
> > +        /* FSELx has changed */
> > +        switch (fsel) {
> > +        case 0x01:
> > +            TRACE(s->parent_obj, "Setting fout to 1024Hz");
> > +            ptimer_set_limit(s->fout_timer, 32, 1);
> > +            break;
> > +        case 0x02:
> > +            TRACE(s->parent_obj, "Setting fout to 1Hz");
> > +            ptimer_set_limit(s->fout_timer, 32768, 1);
> > +            break;
> > +        default:
> > +            TRACE(s->parent_obj, "Setting fout to 32768Hz");
> > +            ptimer_set_limit(s->fout_timer, 1, 1);
> > +            break;
> > +        }
> > +    }
> > +
> > +    if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> > +            (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> > +        uint8_t tsel = (data & (EXT_MASK_TSEL0 | EXT_MASK_TSEL1))
> > +                >> EXT_REG_TSEL0;
> > +        /* TSELx has changed */
> > +        switch (tsel) {
> > +        case 0x00:
> > +            TRACE(s->parent_obj, "Setting countdown timer to 64
> > Hz");
> > +            ptimer_set_limit(s->countdown_timer, 4096 / 64, 1);
> > +            break;
> > +        case 0x01:
> > +            TRACE(s->parent_obj, "Setting countdown timer to 1
> > Hz");
> > +            ptimer_set_limit(s->countdown_timer, 4096, 1);
> > +            break;
> > +        case 0x02:
> > +            TRACE(s->parent_obj,
> > +                    "Setting countdown timer to per minute
> > updates");
> > +            ptimer_set_limit(s->countdown_timer, 4069 * 60, 1);
> > +            break;
> > +        case 0x03:
> > +            TRACE(s->parent_obj, "Setting countdown timer to
> > 4096Hz");
> > +            ptimer_set_limit(s->countdown_timer, 1, 1);
> > +            break;
> > +        }
> > +    }
> > +
> > +    if (data & EXT_MASK_TE) {
> > +        enable_countdown_timer(s);
> > +    }
> > +
> > +    s->nvram[EXTENSION_REGISTER] = data;
> > +    s->nvram[EXT_EXTENSION_REGISTER] = data;
> > +
> > +}
> > +/**
> > + * Validate the control register and perform actions based on the
> > bits
> > + * @param s the RTC to operate on
> > + * @param data the new value for the control register
> > + */
> > +
> > +static void update_control_register(RX8900State *s, uint8_t data)
> > +{
> > +    uint8_t diffmask = ~s->nvram[CONTROL_REGISTER] & data;
> > +
> > +    if (diffmask & CTRL_MASK_WP0) {
> > +        data &= ~CTRL_MASK_WP0;
> > +        error_report("WARNING: RX8900 - "
> > +            "Attempt to write to write protected bit %d in control
> > register",
> > +            CTRL_REG_WP0);
> 
> 
> may be use instead :
> 
>        qemu_log_mask(LOG_GUEST_ERROR,
> 
> > 
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_WP1) {
> > +        data &= ~CTRL_MASK_WP1;
> > +        error_report("WARNING: RX8900 - "
> > +            "Attempt to write to write protected bit %d in control
> > register",
> > +            CTRL_REG_WP1);
> 
> ditto for all in fact.
> 
> > 
> > +    }
> > +
> > +    if (data & CTRL_MASK_RESET) {
> > +        data &= ~CTRL_MASK_RESET;
> > +        rx8900_reset(DEVICE(s));
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_UIE) {
> > +        /* Update interrupts were off and are now on */
> > +        struct tm now;
> > +
> > +        TRACE(s->parent_obj, "Enabling update timer");
> > +
> > +        qemu_get_timedate(&now, s->offset);
> > +
> > +        s->last_update_interrupt_minutes = now.tm_min;
> > +        s->last_interrupt_seconds = now.tm_sec;
> > +        enable_timer(s);
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_AIE) {
> > +        /* Alarm interrupts were off and are now on */
> > +        struct tm now;
> > +
> > +        TRACE(s->parent_obj, "Enabling alarm");
> > +
> > +        qemu_get_timedate(&now, s->offset);
> > +
> > +        s->last_interrupt_seconds = now.tm_sec;
> > +        enable_timer(s);
> > +    }
> > +
> > +    if (!(data & (CTRL_MASK_UIE | CTRL_MASK_AIE))) {
> > +        disable_timer(s);
> > +    }
> > +
> > +    if (data & CTRL_MASK_TIE) {
> > +        enable_countdown_timer(s);
> > +    }
> > +
> > +    s->nvram[CONTROL_REGISTER] = data;
> > +    s->nvram[EXT_CONTROL_REGISTER] = data;
> > +}
> > +
> > +/**
> > + * Validate the flag register
> > + * @param s the RTC to operate on
> > + * @param data the new value for the flag register
> > + */
> > +static void validate_flag_register(RX8900State *s, uint8_t *data)
> > +{
> > +    uint8_t diffmask = ~s->nvram[FLAG_REGISTER] & *data;
> > +
> > +    if (diffmask & FLAG_MASK_VDET) {
> > +        *data &= ~FLAG_MASK_VDET;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to VDET bit %d in the flag
> > register",
> > +            FLAG_REG_VDET);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_VLF) {
> > +        *data &= ~FLAG_MASK_VLF;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to VLF bit %d in the flag
> > register",
> > +            FLAG_REG_VLF);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_2) {
> > +        *data &= ~FLAG_MASK_UNUSED_2;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_2);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_6) {
> > +        *data &= ~FLAG_MASK_UNUSED_6;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_6);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_7) {
> > +        *data &= ~FLAG_MASK_UNUSED_7;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_7);
> > +    }
> > +}
> > +
> > +/**
> > + * Tick the per second timer (can be called more frequently as it
> > early exits
> > + * if the wall clock has not progressed)
> > + * @param opaque the RTC to tick
> > + */
> > +static void rx8900_timer_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +    struct tm now;
> > +    bool fire_interrupt = false;
> > +
> > +    qemu_get_timedate(&now, s->offset);
> > +
> > +    if (now.tm_sec == s->last_interrupt_seconds) {
> > +        return;
> > +    }
> > +
> > +    s->last_interrupt_seconds = now.tm_sec;
> > +
> > +    TRACE(s->parent_obj, "Tick");
> > +
> > +    /* Update timer interrupt */
> > +    if (s->nvram[CONTROL_REGISTER] & CTRL_MASK_UIE) {
> > +        if ((s->nvram[EXTENSION_REGISTER] & EXT_MASK_USEL) &&
> > +                now.tm_min != s->last_update_interrupt_minutes) {
> > +            s->last_update_interrupt_minutes = now.tm_min;
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_UF;
> > +            fire_interrupt = true;
> > +        } else if (!(s->nvram[EXTENSION_REGISTER] &
> > EXT_MASK_USEL)) {
> > +            /* per second update interrupt */
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_UF;
> > +            fire_interrupt = true;
> > +        }
> > +    }
> > +
> > +    /* Alarm interrupt */
> > +    if ((s->nvram[CONTROL_REGISTER] & CTRL_MASK_AIE) && now.tm_sec
> > == 0) {
> > +        if (s->nvram[ALARM_MINUTE] == to_bcd(now.tm_min) &&
> > +                s->nvram[ALARM_HOUR] == to_bcd(now.tm_hour) &&
> > +                s->nvram[ALARM_WEEK_DAY] ==
> > +                        ((s->nvram[EXTENSION_REGISTER] &
> > EXT_MASK_WADA) ?
> > +                                to_bcd(now.tm_mday) :
> > +                                0x01 << ((now.tm_wday + s-
> > >wday_offset) % 7))) {
> 
> 
> that's a nice if condition :) May be we could use a temp variable for
> the last one.

Ok, it was more readable with longer lines :)

> 
> > 
> > +            TRACE(s->parent_obj, "Triggering alarm");
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_AF;
> > +            fire_interrupt = true;
> > +        }
> > +    }
> > +
> > +    if (fire_interrupt) {
> > +        TRACE(s->parent_obj, "Pulsing interrupt");
> > +        qemu_irq_pulse(s->interrupt_pin);
> > +    }
> > +}
> > +
> > +/**
> > + * Disable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void disable_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Disabling timer");
> > +    ptimer_stop(s->sec_timer);
> > +}
> > +
> > +/**
> > + * Enable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void enable_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Enabling timer");
> > +    ptimer_run(s->sec_timer, 0);
> > +}
> > +
> > +/**
> > + * Handle FOUT_ENABLE (FOE) line
> > + * Enables/disables the FOUT line
> > + * @param opaque the device instance
> > + * @param n the IRQ number
> > + * @param level true if the line has been raised
> > + */
> > +static void rx8900_fout_enable_handler(void *opaque, int n, int
> > level)
> > +{
> > +    RX8900State *s = RX8900(opaque);
> > +
> > +    if (level) {
> > +        TRACE(s->parent_obj, "Enabling fout");
> > +        ptimer_run(s->fout_timer, 0);
> > +    } else {
> > +        /* disable fout */
> > +        TRACE(s->parent_obj, "Disabling fout");
> > +        ptimer_stop(s->fout_timer);
> > +    }
> > +}
> > +
> > +/**
> > + * Tick the FOUT timer
> > + * @param opaque the device instance
> > + */
> > +static void rx8900_fout_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +
> > +    TRACE(s->parent_obj, "fout toggle");
> > +    s->fout = !s->fout;
> > +
> > +    if (s->fout) {
> > +        qemu_irq_raise(s->fout_pin);
> > +    } else {
> > +        qemu_irq_lower(s->fout_pin);
> > +    }
> > +}
> > +
> > +
> > +/**
> > + * Disable the countdown timer
> > + * @param s the RTC to operate on
> > + */
> > +static void disable_countdown_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Disabling countdown timer");
> > +    ptimer_stop(s->countdown_timer);
> > +}
> > +
> > +/**
> > + * Enable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void enable_countdown_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Enabling countdown timer");
> > +    ptimer_run(s->countdown_timer, 0);
> > +}
> 
> These helpers don't add much I think.

They are called in multiple places and add tracing.

> > 
> > +/**
> > + * Tick the countdown timer
> > + * @param opaque the device instance
> > + */
> > +static void rx8900_countdown_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +
> > +    uint16_t count = s->nvram[TIMER_COUNTER_0] +
> > +            ((s->nvram[TIMER_COUNTER_1] & 0x0F) << 8);
> > +    TRACE(s->parent_obj, "countdown tick, count=%d", count);
> > +    count--;
> > +
> > +    s->nvram[TIMER_COUNTER_0] = (uint8_t)(count & 0x00ff);
> > +    s->nvram[TIMER_COUNTER_1] = (uint8_t)((count & 0x0f00) >> 8);
> > +
> > +    if (count == 0) {
> > +        TRACE(s->parent_obj, "Countdown has elapsed, pulsing
> > interrupt");
> > +
> > +        disable_countdown_timer(s);
> > +
> > +        s->nvram[FLAG_REGISTER] |= FLAG_MASK_TF;
> > +        qemu_irq_pulse(s->interrupt_pin);
> > +    }
> > +}
> > +
> > +
> > +/**
> > + * Receive a byte of data from i2c
> > + * @param i2c the i2c device that is receiving data
> > + * @param data the data that was received
> > + */
> > +static int rx8900_send(I2CSlave *i2c, uint8_t data)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +    struct tm now;
> > +
> > +    TRACE(s->parent_obj, "Received I2C data 0x%02x", data);
> > +
> > +    if (s->addr_byte) {
> > +        s->ptr = data & (RX8900_NVRAM_SIZE - 1);
> > +        TRACE(s->parent_obj, "Operating on register 0x%02x", s-
> > >ptr);
> > +        s->addr_byte = false;
> > +        return 0;
> > +    }
> > +
> > +    TRACE(s->parent_obj, "Set data 0x%02x=0x%02x", s->ptr, data);
> > +
> > +    qemu_get_timedate(&now, s->offset);
> > +    switch (s->ptr) {
> > +    case SECONDS:
> > +    case EXT_SECONDS:
> > +        now.tm_sec = from_bcd(data & 0x7f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case MINUTES:
> > +    case EXT_MINUTES:
> > +        now.tm_min = from_bcd(data & 0x7f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case HOURS:
> > +    case EXT_HOURS:
> > +        now.tm_hour = from_bcd(data & 0x3f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case WEEKDAY:
> > +    case EXT_WEEKDAY: {
> > +        int user_wday = ctz32(data);
> > +        /* The day field is supposed to contain a value in
> > +         * the range 0-6. Otherwise behavior is undefined.
> > +         */
> > +        switch (data) {
> > +        case 0x01:
> > +        case 0x02:
> > +        case 0x04:
> > +        case 0x08:
> > +        case 0x10:
> > +        case 0x20:
> > +        case 0x40:
> > +            break;
> > +        default:
> > +            error_report("WARNING: RX8900 - weekday data '%x' is
> > out of range,"
> > +                    " undefined behavior will result", data);
> > +            break;
> > +        }
> > +        s->weekday = user_wday;
> > +        break;
> > +    }
> > +
> > +    case DAY:
> > +    case EXT_DAY:
> > +        now.tm_mday = from_bcd(data & 0x3f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case MONTH:
> > +    case EXT_MONTH:
> > +        now.tm_mon = from_bcd(data & 0x1f) - 1;
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case YEAR:
> > +    case EXT_YEAR:
> > +        now.tm_year = from_bcd(data) + 100;
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case EXTENSION_REGISTER:
> > +    case EXT_EXTENSION_REGISTER:
> > +        update_extension_register(s, data);
> > +        break;
> > +
> > +    case FLAG_REGISTER:
> > +    case EXT_FLAG_REGISTER:
> > +        validate_flag_register(s, &data);
> > +
> > +        s->nvram[FLAG_REGISTER] = data;
> > +        s->nvram[EXT_FLAG_REGISTER] = data;
> > +        break;
> > +
> > +    case CONTROL_REGISTER:
> > +    case EXT_CONTROL_REGISTER:
> > +        update_control_register(s, data);
> > +        break;
> > +
> > +    default:
> > +        s->nvram[s->ptr] = data;
> > +    }
> > +
> > +    inc_regptr(s);
> > +    return 0;
> > +}
> > +
> > +/**
> > + * Get the device temperature in Celcius as a property
> > + * @param obj the device
> > + * @param v
> > + * @param name the property name
> > + * @param opaque
> > + * @param errp an error object to populate on failure
> > + */
> > +static void rx8900_get_temperature(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    RX8900State *s = RX8900(obj);
> > +    double value = (s->nvram[TEMPERATURE] * 2.0f - 187.1f) /
> > 3.218f;
> > +
> > +    TRACE(s->parent_obj, "Read temperature property, 0x%x = %f°C",
> > +            s->nvram[TEMPERATURE], value);
> > +
> > +    visit_type_number(v, name, &value, errp);
> > +}
> > +
> > +/**
> > + * Set the device temperature in Celcius as a property
> > + * @param obj the device
> > + * @param v
> > + * @param name the property name
> > + * @param opaque
> > + * @param errp an error object to populate on failure
> > + */
> > +static void rx8900_set_temperature(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    RX8900State *s = RX8900(obj);
> > +    Error *local_err = NULL;
> > +    double temp; /* degrees Celcius */
> > +    visit_type_number(v, name, &temp, &local_err);
> > +    if (local_err) {
> > +        error_propagate(errp, local_err);
> > +        return;
> > +    }
> > +    if (temp >= 100 || temp < -58) {
> > +        error_setg(errp, "value %f°C is out of range", temp);
> > +        return;
> > +    }
> > +
> > +    s->nvram[TEMPERATURE] = (uint8_t) ((temp * 3.218f + 187.19f) /
> > 2);
> > +
> > +    TRACE(s->parent_obj, "Set temperature property, 0x%x = %f°C",
> > +            s->nvram[TEMPERATURE], temp);
> > +}
> > +
> > +
> > +/**
> > + * Initialize the device
> > + * @param i2c the i2c device instance
> > + */
> > +static int rx8900_init(I2CSlave *i2c)
> > +{
> > +    TRACE(*i2c, "Initialized");
> > +
> > +    return 0;
> > +}
> 
> you can remove this routine.
> 

I don't think I can, core.c:i2c_slave_qdev_init() calls it without a
guard.

> > 
> > +/**
> > + * Configure device properties
> > + * @param obj the device
> > + */
> > +static void rx8900_initfn(Object *obj)
> > +{
> > +    object_property_add(obj, "temperature", "number",
> > +                        rx8900_get_temperature,
> > +                        rx8900_set_temperature, NULL, NULL, NULL);
> > +}
> > +
> > +/**
> > + * Reset the device
> > + * @param dev the RX8900 device to reset
> > + */
> > +static void rx8900_reset(DeviceState *dev)
> > +{
> > +    RX8900State *s = RX8900(dev);
> > +
> > +    TRACE(s->parent_obj, "Reset");
> > +
> > +    /* The clock is running and synchronized with the host */
> > +    s->offset = 0;
> > +    s->weekday = 7; /* Set to an invalid value */
> > +
> > +    /* Temperature formulation from the datasheet
> > +     * ( TEMP[ 7:0 ] * 2 - 187.19) / 3.218
> > +     *
> > +     * Set the initial state to 25 degrees Celcius
> > +     */
> > +    s->nvram[TEMPERATURE] = 135; /* (25 * 3.218 + 187.19) / 2 */
> > +
> > +    s->nvram[EXTENSION_REGISTER] = EXT_MASK_TSEL1;
> > +    s->nvram[CONTROL_REGISTER] = CTRL_MASK_CSEL0;
> > +    s->nvram[FLAG_REGISTER] = FLAG_MASK_VLF | FLAG_MASK_VDET;
> 
> Just asking : why not fully memset(0) the nvram  and then set 
> the values ?

I also use this function for a soft-reset, which does not clear the
nvram.

Actually, I should move the temperature out of there...


Cheers,

-- 
Alastair D'Silva
Open Source Developer
Linux Technology Centre, IBM Australia
mob: 0423 762 819


WARNING: multiple messages have this Message-ID (diff)
From: "Alastair D'Silva" <alastair@au1.ibm.com>
To: "Cédric Le Goater" <clg@kaod.org>, qemu-arm@nongnu.org
Cc: qemu-devel@nongnu.org, Peter Maydell <peter.maydell@linaro.org>,
	Andrew Jeffery <andrew@aj.id.au>, Joel Stanley <joel@jms.id.au>
Subject: Re: [Qemu-devel] [PATCH 3/4] hw/timer: Add Epson RX8900 RTC support
Date: Fri, 18 Nov 2016 11:19:18 +1100	[thread overview]
Message-ID: <1479428358.11116.46.camel@au1.ibm.com> (raw)
In-Reply-To: <b4c2feb1-7c5a-01de-b8c8-893d2c7785f6@kaod.org>

On Thu, 2016-11-17 at 09:29 +0100, Cédric Le Goater wrote:
On 11/17/2016 05:36 AM, Alastair D'Silva wrote:
> > 
> > From: Alastair D'Silva <alastair@d-silva.org>
> > 
> > This patch adds support for the Epson RX8900 RTC chip.
> 
> It would be nice to have a short list of the features this 
> chip has and also the main point of the design. I see you 
> are using a BH.
> 

Ok

> 
> > 
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> > ---
> >  default-configs/arm-softmmu.mak |   1 +
> >  hw/timer/Makefile.objs          |   2 +
> >  hw/timer/rx8900.c               | 891
> > ++++++++++++++++++++++++++++++++++++++++
> >  hw/timer/rx8900_regs.h          | 125 ++++++
> >  tests/Makefile.include          |   2 +
> >  tests/rx8900-test.c             | 800
> > ++++++++++++++++++++++++++++++++++++
> 
> Nice test ! But Why aren't you using the aspeed machine in 
> qtest ? 
> 
> The reason I am asking is because the I2C controller model 
> is a little too simplistic in the way it handles the irq 
> status and we would need a test for it.
> 

The aspeed machine is missing a bunch of I2C infrastructure
(imx_i2c_create & friends) required to access it from the test harness,
and I don't have the knowledge required to implement it. I am working
on the premise that the RX8900 is an independent device, and so can be
tested independently of the aspeed model.

> 
> Also I would put the test case in another patch, after the 
> model and after patch 2 also which introduces named 
> interrupts for qtest.
> 

Ok

> 
> > 
> >  6 files changed, 1821 insertions(+)
> >  create mode 100644 hw/timer/rx8900.c
> >  create mode 100644 hw/timer/rx8900_regs.h
> >  create mode 100644 tests/rx8900-test.c
> > 
> > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-
> > softmmu.mak
> > index 6de3e16..adb600e 100644
> > --- a/default-configs/arm-softmmu.mak
> > +++ b/default-configs/arm-softmmu.mak
> > @@ -29,6 +29,7 @@ CONFIG_SMC91C111=y
> >  CONFIG_ALLWINNER_EMAC=y
> >  CONFIG_IMX_FEC=y
> >  CONFIG_DS1338=y
> > +CONFIG_RX8900=y
> >  CONFIG_PFLASH_CFI01=y
> >  CONFIG_PFLASH_CFI02=y
> >  CONFIG_MICRODRIVE=y
> > diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
> > index 7ba8c23..fa028ac 100644
> > --- a/hw/timer/Makefile.objs
> > +++ b/hw/timer/Makefile.objs
> > @@ -3,6 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
> >  common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o
> >  common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
> >  common-obj-$(CONFIG_DS1338) += ds1338.o
> > +common-obj-$(CONFIG_RX8900) += rx8900.o
> >  common-obj-$(CONFIG_HPET) += hpet.o
> >  common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
> >  common-obj-$(CONFIG_M48T59) += m48t59.o
> > @@ -17,6 +18,7 @@ common-obj-$(CONFIG_IMX) += imx_epit.o
> >  common-obj-$(CONFIG_IMX) += imx_gpt.o
> >  common-obj-$(CONFIG_LM32) += lm32_timer.o
> >  common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
> > +common-obj-$(CONFIG_RX8900) += rx8900.o
> >  
> >  obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
> >  obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
> > diff --git a/hw/timer/rx8900.c b/hw/timer/rx8900.c
> > new file mode 100644
> > index 0000000..208a31b
> > --- /dev/null
> > +++ b/hw/timer/rx8900.c
> > @@ -0,0 +1,891 @@
> > +/*
> > + * Epson RX8900SA/CE Realtime Clock Module
> > + *
> > + * Copyright (c) 2016 IBM Corporation
> > + * Authors:
> > + *  Alastair D'Silva <alastair@d-silva.org>
> > + *
> > + * This code is licensed under the GPL version 2 or later.  See
> > + * the COPYING file in the top-level directory.
> > + *
> > + * Datasheet available at:
> > + *  https://support.epson.biz/td/api/doc_check.php?dl=app_RX8900CE
> > &lang=en
> > + *
> > + * Not implemented:
> > + *  Implement Timer Counters
> > + *  Implement i2c timeout
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "hw/i2c/i2c.h"
> > +#include "hw/timer/rx8900_regs.h"
> > +#include "hw/ptimer.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/bcd.h"
> > +#include "qemu/error-report.h"
> > +#include "qemu/log.h"
> > +#include "qapi/error.h"
> > +#include "qapi/visitor.h"
> > +
> > + #include <sys/time.h>
> > +
> > + #include <execinfo.h>
> > +
> > +#define TYPE_RX8900 "rx8900"
> > +#define RX8900(obj) OBJECT_CHECK(RX8900State, (obj), TYPE_RX8900)
> > +
> > +static bool log;
> > +
> > +typedef struct RX8900State {
> > +    I2CSlave parent_obj;
> > +
> > +    ptimer_state *sec_timer; /* triggered once per second */
> > +    ptimer_state *fout_timer;
> > +    ptimer_state *countdown_timer;
> > +    bool fout;
> > +    int64_t offset;
> > +    uint8_t weekday; /* Saved for deferred offset calculation, 0-6 
> > */
> > +    uint8_t wday_offset;
> > +    uint8_t nvram[RX8900_NVRAM_SIZE];
> > +    int32_t ptr; /* Wrapped to stay within RX8900_NVRAM_SIZE */
> > +    bool addr_byte;
> > +    uint8_t last_interrupt_seconds;
> > +    uint8_t last_update_interrupt_minutes;
> > +    qemu_irq interrupt_pin;
> > +    qemu_irq fout_pin;
> > +} RX8900State;
> > +
> > +static const VMStateDescription vmstate_rx8900 = {
> > +    .name = "rx8900",
> > +    .version_id = 2,
> > +    .minimum_version_id = 1,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_I2C_SLAVE(parent_obj, RX8900State),
> > +        VMSTATE_PTIMER(sec_timer, RX8900State),
> > +        VMSTATE_PTIMER(fout_timer, RX8900State),
> > +        VMSTATE_PTIMER(countdown_timer, RX8900State),
> > +        VMSTATE_BOOL(fout, RX8900State),
> > +        VMSTATE_INT64(offset, RX8900State),
> > +        VMSTATE_UINT8_V(weekday, RX8900State, 2),
> > +        VMSTATE_UINT8_V(wday_offset, RX8900State, 2),
> > +        VMSTATE_UINT8_ARRAY(nvram, RX8900State,
> > RX8900_NVRAM_SIZE),
> > +        VMSTATE_INT32(ptr, RX8900State),
> > +        VMSTATE_BOOL(addr_byte, RX8900State),
> > +        VMSTATE_UINT8_V(last_interrupt_seconds, RX8900State, 2),
> > +        VMSTATE_UINT8_V(last_update_interrupt_minutes,
> > RX8900State, 2),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void rx8900_reset(DeviceState *dev);
> > +static void disable_countdown_timer(RX8900State *s);
> > +static void enable_countdown_timer(RX8900State *s);
> > +static void disable_timer(RX8900State *s);
> > +static void enable_timer(RX8900State *s);
> > +
> > +#ifdef RX8900_TRACE
> > +#define RX8900_TRACE_BUF_SIZE 256
> > +/**
> > + * Emit a trace message
> > + * @param file the source filename
> > + * @param line the line number the message was emitted from
> > + * @param dev the RX8900 device
> > + * @param fmt a printf style format
> > + */
> > +static void trace(const char *file, int line, const char *func,
> > +        I2CSlave *dev, const char *fmt, ...)
> > +{
> > +    va_list ap;
> > +    char buf[RX8900_TRACE_BUF_SIZE];
> > +    char timestamp[32];
> > +    int len;
> > +    struct timeval now;
> > +    struct tm *now2;
> > +
> > +    gettimeofday(&now, NULL);
> > +    now2 = localtime(&now.tv_sec);
> > +
> > +    strftime(timestamp, sizeof(timestamp), "%F %T", now2);
> > +
> > +    len = snprintf(buf, sizeof(buf), "\n\t%s.%03ld %s:%s:%d:
> > RX8900 %s %s@0x%x: %s",
> > +            timestamp, now.tv_usec / 1000,
> > +            file, func, line, dev->qdev.id, dev->qdev.parent_bus-
> > >name,
> > +            dev->address, fmt);
> > +    if (len >= RX8900_TRACE_BUF_SIZE) {
> > +        error_report("%s:%d: Trace buffer overflow", file, line);
> > +    }
> > +
> > +    va_start(ap, fmt);
> > +    error_vreport(buf, ap);
> > +    va_end(ap);
> > +}
> > +
> > +/**
> > + * Emit a trace message
> > + * @param dev the RX8900 device
> > + * @param fmt a printf format
> > + */
> > +#define TRACE(dev, fmt, ...) \
> > +    do { \
> > +        if (log) { \
> > +            trace(__FILE__, __LINE__, __func__, &dev, fmt, ##
> > __VA_ARGS__); \
> > +        } \
> > +    } while (0)
> > +#else
> > +#define TRACE(dev, fmt, ...)
> > +#endif
> 
> 
> Although this is very pratical and nicely written, I don't 
> think you can keep these TRACE calls in the code. You should 
> use the qemu trace subsystem for it.
> 

Ok. Would it be worth expanding this to include the file & line, or do
you expect resistance?

> 
> > 
> > +static void capture_current_time(RX8900State *s)
> > +{
> > +    /* Capture the current time into the secondary registers
> > +     * which will be actually read by the data transfer operation.
> > +     */
> > +    struct tm now;
> > +    qemu_get_timedate(&now, s->offset);
> > +    s->nvram[SECONDS] = to_bcd(now.tm_sec);
> > +    s->nvram[MINUTES] = to_bcd(now.tm_min);
> > +    s->nvram[HOURS] = to_bcd(now.tm_hour);
> > +
> > +    s->nvram[WEEKDAY] = 0x01 << ((now.tm_wday + s->wday_offset) %
> > 7);
> > +    s->nvram[DAY] = to_bcd(now.tm_mday);
> > +    s->nvram[MONTH] = to_bcd(now.tm_mon + 1);
> > +    s->nvram[YEAR] = to_bcd(now.tm_year % 100);
> > +
> > +    s->nvram[EXT_SECONDS] = s->nvram[SECONDS];
> > +    s->nvram[EXT_MINUTES] = s->nvram[MINUTES];
> > +    s->nvram[EXT_HOURS] = s->nvram[HOURS];
> > +    s->nvram[EXT_WEEKDAY] = s->nvram[WEEKDAY];
> > +    s->nvram[EXT_DAY] = s->nvram[DAY];
> > +    s->nvram[EXT_MONTH] = s->nvram[MONTH];
> > +    s->nvram[EXT_YEAR] = s->nvram[YEAR];
> > +
> > +    TRACE(s->parent_obj, "Update current time to %02d:%02d:%02d %d
> > %d/%d/%d "
> > +            "(0x%02x%02x%02x%02x%02x%02x%02x)",
> > +            now.tm_hour, now.tm_min, now.tm_sec,
> > +            (now.tm_wday + s->wday_offset) % 7,
> > +            now.tm_mday, now.tm_mon, now.tm_year + 1900,
> > +            s->nvram[HOURS], s->nvram[MINUTES], s->nvram[SECONDS],
> > +            s->nvram[WEEKDAY],
> > +            s->nvram[DAY], s->nvram[MONTH], s->nvram[YEAR]);
> > +}
> > +
> > +/**
> > + * Increment the internal register pointer, dealing with wrapping
> > + * @param s the RTC to operate on
> > + */
> > +static void inc_regptr(RX8900State *s)
> > +{
> > +    /* The register pointer wraps around after 0x1F
> > +     */
> > +    s->ptr = (s->ptr + 1) & (RX8900_NVRAM_SIZE - 1);
> > +    TRACE(s->parent_obj, "Operating on register 0x%02x", s->ptr);
> > +
> > +    if (s->ptr == 0x00) {
> > +        TRACE(s->parent_obj, "Register pointer has overflowed,
> > wrapping to 0");
> > +        capture_current_time(s);
> > +    }
> > +}
> > +
> > +/**
> > + * Receive an I2C Event
> > + * @param i2c the i2c device instance
> > + * @param event the event to handle
> > + */
> > +static void rx8900_event(I2CSlave *i2c, enum i2c_event event)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +
> > +    switch (event) {
> > +    case I2C_START_RECV:
> > +        /* In h/w, time capture happens on any START condition,
> > not just a
> > +         * START_RECV. For the emulation, it doesn't actually
> > matter,
> > +         * since a START_RECV has to occur before the data can be
> > read.
> > +         */
> > +        capture_current_time(s);
> > +        break;
> > +    case I2C_START_SEND:
> > +        s->addr_byte = true;
> > +        break;
> > +    case I2C_FINISH:
> > +        if (s->weekday < 7) {
> > +            /* We defer the weekday calculation as it is handed to
> > us before
> > +             * the date has been updated. If we calculate the
> > weekday offset
> > +             * when it is passed to us, we will incorrectly
> > determine it
> > +             * based on the current emulated date, rather than the
> > date that
> > +             * has been written.
> > +             */
> > +            struct tm now;
> > +            qemu_get_timedate(&now, s->offset);
> > +
> > +            s->wday_offset = (s->weekday - now.tm_wday + 7) % 7;
> > +
> > +            TRACE(s->parent_obj, "Set weekday to %d (0x%02x),
> > wday_offset=%d",
> > +                    s->weekday, BIT(s->weekday), s->wday_offset);
> > +
> > +            s->weekday = 7;
> > +        }
> > +        break;
> > +
> > +    default:
> > +        break;
> > +    }
> > +}
> > +
> > +/**
> > + * Perform an i2c receive action
> > + * @param i2c the i2c device instance
> > + * @return the value of the current register
> > + * @post the internal register pointer is incremented
> > + */
> > +static int rx8900_recv(I2CSlave *i2c)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +    uint8_t res = s->nvram[s->ptr];
> > +    TRACE(s->parent_obj, "Read register 0x%x = 0x%x", s->ptr,
> > res);
> > +    inc_regptr(s);
> > +    return res;
> > +}
> > +
> > +/**
> > + * Validate the extension register and perform actions based on
> > the bits
> > + * @param s the RTC to operate on
> > + * @param data the new data for the extension register
> > + */
> > +static void update_extension_register(RX8900State *s, uint8_t
> > data)
> > +{
> > +    if (data & EXT_MASK_TEST) {
> > +        error_report("WARNING: RX8900 - "
> > +            "Test bit is enabled but is forbidden by the
> > manufacturer");
> 
> may be use instead :
> 
>        qemu_log_mask(LOG_GUEST_ERROR,
> 

OK

> > 
> > +    }
> > +
> > +    if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> > +            (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> > +        uint8_t fsel = (data & (EXT_MASK_FSEL0 | EXT_MASK_FSEL1))
> > +                >> EXT_REG_FSEL0;
> > +        /* FSELx has changed */
> > +        switch (fsel) {
> > +        case 0x01:
> > +            TRACE(s->parent_obj, "Setting fout to 1024Hz");
> > +            ptimer_set_limit(s->fout_timer, 32, 1);
> > +            break;
> > +        case 0x02:
> > +            TRACE(s->parent_obj, "Setting fout to 1Hz");
> > +            ptimer_set_limit(s->fout_timer, 32768, 1);
> > +            break;
> > +        default:
> > +            TRACE(s->parent_obj, "Setting fout to 32768Hz");
> > +            ptimer_set_limit(s->fout_timer, 1, 1);
> > +            break;
> > +        }
> > +    }
> > +
> > +    if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> > +            (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> > +        uint8_t tsel = (data & (EXT_MASK_TSEL0 | EXT_MASK_TSEL1))
> > +                >> EXT_REG_TSEL0;
> > +        /* TSELx has changed */
> > +        switch (tsel) {
> > +        case 0x00:
> > +            TRACE(s->parent_obj, "Setting countdown timer to 64
> > Hz");
> > +            ptimer_set_limit(s->countdown_timer, 4096 / 64, 1);
> > +            break;
> > +        case 0x01:
> > +            TRACE(s->parent_obj, "Setting countdown timer to 1
> > Hz");
> > +            ptimer_set_limit(s->countdown_timer, 4096, 1);
> > +            break;
> > +        case 0x02:
> > +            TRACE(s->parent_obj,
> > +                    "Setting countdown timer to per minute
> > updates");
> > +            ptimer_set_limit(s->countdown_timer, 4069 * 60, 1);
> > +            break;
> > +        case 0x03:
> > +            TRACE(s->parent_obj, "Setting countdown timer to
> > 4096Hz");
> > +            ptimer_set_limit(s->countdown_timer, 1, 1);
> > +            break;
> > +        }
> > +    }
> > +
> > +    if (data & EXT_MASK_TE) {
> > +        enable_countdown_timer(s);
> > +    }
> > +
> > +    s->nvram[EXTENSION_REGISTER] = data;
> > +    s->nvram[EXT_EXTENSION_REGISTER] = data;
> > +
> > +}
> > +/**
> > + * Validate the control register and perform actions based on the
> > bits
> > + * @param s the RTC to operate on
> > + * @param data the new value for the control register
> > + */
> > +
> > +static void update_control_register(RX8900State *s, uint8_t data)
> > +{
> > +    uint8_t diffmask = ~s->nvram[CONTROL_REGISTER] & data;
> > +
> > +    if (diffmask & CTRL_MASK_WP0) {
> > +        data &= ~CTRL_MASK_WP0;
> > +        error_report("WARNING: RX8900 - "
> > +            "Attempt to write to write protected bit %d in control
> > register",
> > +            CTRL_REG_WP0);
> 
> 
> may be use instead :
> 
>        qemu_log_mask(LOG_GUEST_ERROR,
> 
> > 
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_WP1) {
> > +        data &= ~CTRL_MASK_WP1;
> > +        error_report("WARNING: RX8900 - "
> > +            "Attempt to write to write protected bit %d in control
> > register",
> > +            CTRL_REG_WP1);
> 
> ditto for all in fact.
> 
> > 
> > +    }
> > +
> > +    if (data & CTRL_MASK_RESET) {
> > +        data &= ~CTRL_MASK_RESET;
> > +        rx8900_reset(DEVICE(s));
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_UIE) {
> > +        /* Update interrupts were off and are now on */
> > +        struct tm now;
> > +
> > +        TRACE(s->parent_obj, "Enabling update timer");
> > +
> > +        qemu_get_timedate(&now, s->offset);
> > +
> > +        s->last_update_interrupt_minutes = now.tm_min;
> > +        s->last_interrupt_seconds = now.tm_sec;
> > +        enable_timer(s);
> > +    }
> > +
> > +    if (diffmask & CTRL_MASK_AIE) {
> > +        /* Alarm interrupts were off and are now on */
> > +        struct tm now;
> > +
> > +        TRACE(s->parent_obj, "Enabling alarm");
> > +
> > +        qemu_get_timedate(&now, s->offset);
> > +
> > +        s->last_interrupt_seconds = now.tm_sec;
> > +        enable_timer(s);
> > +    }
> > +
> > +    if (!(data & (CTRL_MASK_UIE | CTRL_MASK_AIE))) {
> > +        disable_timer(s);
> > +    }
> > +
> > +    if (data & CTRL_MASK_TIE) {
> > +        enable_countdown_timer(s);
> > +    }
> > +
> > +    s->nvram[CONTROL_REGISTER] = data;
> > +    s->nvram[EXT_CONTROL_REGISTER] = data;
> > +}
> > +
> > +/**
> > + * Validate the flag register
> > + * @param s the RTC to operate on
> > + * @param data the new value for the flag register
> > + */
> > +static void validate_flag_register(RX8900State *s, uint8_t *data)
> > +{
> > +    uint8_t diffmask = ~s->nvram[FLAG_REGISTER] & *data;
> > +
> > +    if (diffmask & FLAG_MASK_VDET) {
> > +        *data &= ~FLAG_MASK_VDET;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to VDET bit %d in the flag
> > register",
> > +            FLAG_REG_VDET);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_VLF) {
> > +        *data &= ~FLAG_MASK_VLF;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to VLF bit %d in the flag
> > register",
> > +            FLAG_REG_VLF);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_2) {
> > +        *data &= ~FLAG_MASK_UNUSED_2;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_2);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_6) {
> > +        *data &= ~FLAG_MASK_UNUSED_6;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_6);
> > +    }
> > +
> > +    if (diffmask & FLAG_MASK_UNUSED_7) {
> > +        *data &= ~FLAG_MASK_UNUSED_7;
> > +        error_report("WARNING: RX8900 - "
> > +            "Only 0 can be written to unused bit %d in the flag
> > register",
> > +            FLAG_REG_UNUSED_7);
> > +    }
> > +}
> > +
> > +/**
> > + * Tick the per second timer (can be called more frequently as it
> > early exits
> > + * if the wall clock has not progressed)
> > + * @param opaque the RTC to tick
> > + */
> > +static void rx8900_timer_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +    struct tm now;
> > +    bool fire_interrupt = false;
> > +
> > +    qemu_get_timedate(&now, s->offset);
> > +
> > +    if (now.tm_sec == s->last_interrupt_seconds) {
> > +        return;
> > +    }
> > +
> > +    s->last_interrupt_seconds = now.tm_sec;
> > +
> > +    TRACE(s->parent_obj, "Tick");
> > +
> > +    /* Update timer interrupt */
> > +    if (s->nvram[CONTROL_REGISTER] & CTRL_MASK_UIE) {
> > +        if ((s->nvram[EXTENSION_REGISTER] & EXT_MASK_USEL) &&
> > +                now.tm_min != s->last_update_interrupt_minutes) {
> > +            s->last_update_interrupt_minutes = now.tm_min;
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_UF;
> > +            fire_interrupt = true;
> > +        } else if (!(s->nvram[EXTENSION_REGISTER] &
> > EXT_MASK_USEL)) {
> > +            /* per second update interrupt */
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_UF;
> > +            fire_interrupt = true;
> > +        }
> > +    }
> > +
> > +    /* Alarm interrupt */
> > +    if ((s->nvram[CONTROL_REGISTER] & CTRL_MASK_AIE) && now.tm_sec
> > == 0) {
> > +        if (s->nvram[ALARM_MINUTE] == to_bcd(now.tm_min) &&
> > +                s->nvram[ALARM_HOUR] == to_bcd(now.tm_hour) &&
> > +                s->nvram[ALARM_WEEK_DAY] ==
> > +                        ((s->nvram[EXTENSION_REGISTER] &
> > EXT_MASK_WADA) ?
> > +                                to_bcd(now.tm_mday) :
> > +                                0x01 << ((now.tm_wday + s-
> > >wday_offset) % 7))) {
> 
> 
> that's a nice if condition :) May be we could use a temp variable for
> the last one.

Ok, it was more readable with longer lines :)

> 
> > 
> > +            TRACE(s->parent_obj, "Triggering alarm");
> > +            s->nvram[FLAG_REGISTER] |= FLAG_MASK_AF;
> > +            fire_interrupt = true;
> > +        }
> > +    }
> > +
> > +    if (fire_interrupt) {
> > +        TRACE(s->parent_obj, "Pulsing interrupt");
> > +        qemu_irq_pulse(s->interrupt_pin);
> > +    }
> > +}
> > +
> > +/**
> > + * Disable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void disable_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Disabling timer");
> > +    ptimer_stop(s->sec_timer);
> > +}
> > +
> > +/**
> > + * Enable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void enable_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Enabling timer");
> > +    ptimer_run(s->sec_timer, 0);
> > +}
> > +
> > +/**
> > + * Handle FOUT_ENABLE (FOE) line
> > + * Enables/disables the FOUT line
> > + * @param opaque the device instance
> > + * @param n the IRQ number
> > + * @param level true if the line has been raised
> > + */
> > +static void rx8900_fout_enable_handler(void *opaque, int n, int
> > level)
> > +{
> > +    RX8900State *s = RX8900(opaque);
> > +
> > +    if (level) {
> > +        TRACE(s->parent_obj, "Enabling fout");
> > +        ptimer_run(s->fout_timer, 0);
> > +    } else {
> > +        /* disable fout */
> > +        TRACE(s->parent_obj, "Disabling fout");
> > +        ptimer_stop(s->fout_timer);
> > +    }
> > +}
> > +
> > +/**
> > + * Tick the FOUT timer
> > + * @param opaque the device instance
> > + */
> > +static void rx8900_fout_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +
> > +    TRACE(s->parent_obj, "fout toggle");
> > +    s->fout = !s->fout;
> > +
> > +    if (s->fout) {
> > +        qemu_irq_raise(s->fout_pin);
> > +    } else {
> > +        qemu_irq_lower(s->fout_pin);
> > +    }
> > +}
> > +
> > +
> > +/**
> > + * Disable the countdown timer
> > + * @param s the RTC to operate on
> > + */
> > +static void disable_countdown_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Disabling countdown timer");
> > +    ptimer_stop(s->countdown_timer);
> > +}
> > +
> > +/**
> > + * Enable the per second timer
> > + * @param s the RTC to operate on
> > + */
> > +static void enable_countdown_timer(RX8900State *s)
> > +{
> > +    TRACE(s->parent_obj, "Enabling countdown timer");
> > +    ptimer_run(s->countdown_timer, 0);
> > +}
> 
> These helpers don't add much I think.

They are called in multiple places and add tracing.

> > 
> > +/**
> > + * Tick the countdown timer
> > + * @param opaque the device instance
> > + */
> > +static void rx8900_countdown_tick(void *opaque)
> > +{
> > +    RX8900State *s = (RX8900State *)opaque;
> > +
> > +    uint16_t count = s->nvram[TIMER_COUNTER_0] +
> > +            ((s->nvram[TIMER_COUNTER_1] & 0x0F) << 8);
> > +    TRACE(s->parent_obj, "countdown tick, count=%d", count);
> > +    count--;
> > +
> > +    s->nvram[TIMER_COUNTER_0] = (uint8_t)(count & 0x00ff);
> > +    s->nvram[TIMER_COUNTER_1] = (uint8_t)((count & 0x0f00) >> 8);
> > +
> > +    if (count == 0) {
> > +        TRACE(s->parent_obj, "Countdown has elapsed, pulsing
> > interrupt");
> > +
> > +        disable_countdown_timer(s);
> > +
> > +        s->nvram[FLAG_REGISTER] |= FLAG_MASK_TF;
> > +        qemu_irq_pulse(s->interrupt_pin);
> > +    }
> > +}
> > +
> > +
> > +/**
> > + * Receive a byte of data from i2c
> > + * @param i2c the i2c device that is receiving data
> > + * @param data the data that was received
> > + */
> > +static int rx8900_send(I2CSlave *i2c, uint8_t data)
> > +{
> > +    RX8900State *s = RX8900(i2c);
> > +    struct tm now;
> > +
> > +    TRACE(s->parent_obj, "Received I2C data 0x%02x", data);
> > +
> > +    if (s->addr_byte) {
> > +        s->ptr = data & (RX8900_NVRAM_SIZE - 1);
> > +        TRACE(s->parent_obj, "Operating on register 0x%02x", s-
> > >ptr);
> > +        s->addr_byte = false;
> > +        return 0;
> > +    }
> > +
> > +    TRACE(s->parent_obj, "Set data 0x%02x=0x%02x", s->ptr, data);
> > +
> > +    qemu_get_timedate(&now, s->offset);
> > +    switch (s->ptr) {
> > +    case SECONDS:
> > +    case EXT_SECONDS:
> > +        now.tm_sec = from_bcd(data & 0x7f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case MINUTES:
> > +    case EXT_MINUTES:
> > +        now.tm_min = from_bcd(data & 0x7f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case HOURS:
> > +    case EXT_HOURS:
> > +        now.tm_hour = from_bcd(data & 0x3f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case WEEKDAY:
> > +    case EXT_WEEKDAY: {
> > +        int user_wday = ctz32(data);
> > +        /* The day field is supposed to contain a value in
> > +         * the range 0-6. Otherwise behavior is undefined.
> > +         */
> > +        switch (data) {
> > +        case 0x01:
> > +        case 0x02:
> > +        case 0x04:
> > +        case 0x08:
> > +        case 0x10:
> > +        case 0x20:
> > +        case 0x40:
> > +            break;
> > +        default:
> > +            error_report("WARNING: RX8900 - weekday data '%x' is
> > out of range,"
> > +                    " undefined behavior will result", data);
> > +            break;
> > +        }
> > +        s->weekday = user_wday;
> > +        break;
> > +    }
> > +
> > +    case DAY:
> > +    case EXT_DAY:
> > +        now.tm_mday = from_bcd(data & 0x3f);
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case MONTH:
> > +    case EXT_MONTH:
> > +        now.tm_mon = from_bcd(data & 0x1f) - 1;
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case YEAR:
> > +    case EXT_YEAR:
> > +        now.tm_year = from_bcd(data) + 100;
> > +        s->offset = qemu_timedate_diff(&now);
> > +        break;
> > +
> > +    case EXTENSION_REGISTER:
> > +    case EXT_EXTENSION_REGISTER:
> > +        update_extension_register(s, data);
> > +        break;
> > +
> > +    case FLAG_REGISTER:
> > +    case EXT_FLAG_REGISTER:
> > +        validate_flag_register(s, &data);
> > +
> > +        s->nvram[FLAG_REGISTER] = data;
> > +        s->nvram[EXT_FLAG_REGISTER] = data;
> > +        break;
> > +
> > +    case CONTROL_REGISTER:
> > +    case EXT_CONTROL_REGISTER:
> > +        update_control_register(s, data);
> > +        break;
> > +
> > +    default:
> > +        s->nvram[s->ptr] = data;
> > +    }
> > +
> > +    inc_regptr(s);
> > +    return 0;
> > +}
> > +
> > +/**
> > + * Get the device temperature in Celcius as a property
> > + * @param obj the device
> > + * @param v
> > + * @param name the property name
> > + * @param opaque
> > + * @param errp an error object to populate on failure
> > + */
> > +static void rx8900_get_temperature(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    RX8900State *s = RX8900(obj);
> > +    double value = (s->nvram[TEMPERATURE] * 2.0f - 187.1f) /
> > 3.218f;
> > +
> > +    TRACE(s->parent_obj, "Read temperature property, 0x%x = %f°C",
> > +            s->nvram[TEMPERATURE], value);
> > +
> > +    visit_type_number(v, name, &value, errp);
> > +}
> > +
> > +/**
> > + * Set the device temperature in Celcius as a property
> > + * @param obj the device
> > + * @param v
> > + * @param name the property name
> > + * @param opaque
> > + * @param errp an error object to populate on failure
> > + */
> > +static void rx8900_set_temperature(Object *obj, Visitor *v, const
> > char *name,
> > +                                   void *opaque, Error **errp)
> > +{
> > +    RX8900State *s = RX8900(obj);
> > +    Error *local_err = NULL;
> > +    double temp; /* degrees Celcius */
> > +    visit_type_number(v, name, &temp, &local_err);
> > +    if (local_err) {
> > +        error_propagate(errp, local_err);
> > +        return;
> > +    }
> > +    if (temp >= 100 || temp < -58) {
> > +        error_setg(errp, "value %f°C is out of range", temp);
> > +        return;
> > +    }
> > +
> > +    s->nvram[TEMPERATURE] = (uint8_t) ((temp * 3.218f + 187.19f) /
> > 2);
> > +
> > +    TRACE(s->parent_obj, "Set temperature property, 0x%x = %f°C",
> > +            s->nvram[TEMPERATURE], temp);
> > +}
> > +
> > +
> > +/**
> > + * Initialize the device
> > + * @param i2c the i2c device instance
> > + */
> > +static int rx8900_init(I2CSlave *i2c)
> > +{
> > +    TRACE(*i2c, "Initialized");
> > +
> > +    return 0;
> > +}
> 
> you can remove this routine.
> 

I don't think I can, core.c:i2c_slave_qdev_init() calls it without a
guard.

> > 
> > +/**
> > + * Configure device properties
> > + * @param obj the device
> > + */
> > +static void rx8900_initfn(Object *obj)
> > +{
> > +    object_property_add(obj, "temperature", "number",
> > +                        rx8900_get_temperature,
> > +                        rx8900_set_temperature, NULL, NULL, NULL);
> > +}
> > +
> > +/**
> > + * Reset the device
> > + * @param dev the RX8900 device to reset
> > + */
> > +static void rx8900_reset(DeviceState *dev)
> > +{
> > +    RX8900State *s = RX8900(dev);
> > +
> > +    TRACE(s->parent_obj, "Reset");
> > +
> > +    /* The clock is running and synchronized with the host */
> > +    s->offset = 0;
> > +    s->weekday = 7; /* Set to an invalid value */
> > +
> > +    /* Temperature formulation from the datasheet
> > +     * ( TEMP[ 7:0 ] * 2 - 187.19) / 3.218
> > +     *
> > +     * Set the initial state to 25 degrees Celcius
> > +     */
> > +    s->nvram[TEMPERATURE] = 135; /* (25 * 3.218 + 187.19) / 2 */
> > +
> > +    s->nvram[EXTENSION_REGISTER] = EXT_MASK_TSEL1;
> > +    s->nvram[CONTROL_REGISTER] = CTRL_MASK_CSEL0;
> > +    s->nvram[FLAG_REGISTER] = FLAG_MASK_VLF | FLAG_MASK_VDET;
> 
> Just asking : why not fully memset(0) the nvram  and then set 
> the values ?

I also use this function for a soft-reset, which does not clear the
nvram.

Actually, I should move the temperature out of there...


Cheers,

-- 
Alastair D'Silva
Open Source Developer
Linux Technology Centre, IBM Australia
mob: 0423 762 819


  reply	other threads:[~2016-11-18  0:19 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-17  4:36 [Qemu-devel] [PATCH 0/4] Add support for the Epson RX8900 RTC to the aspeed board Alastair D'Silva
2016-11-17  4:36 ` Alastair D'Silva
2016-11-17  4:36 ` [Qemu-devel] [PATCH 1/4] arm: Uniquely name imx25 I2C buses Alastair D'Silva
2016-11-17  4:36   ` Alastair D'Silva
2016-11-17  7:50   ` [Qemu-arm] " Cédric Le Goater
2016-11-17  7:50     ` [Qemu-devel] " Cédric Le Goater
2016-11-17  4:36 ` [Qemu-arm] [PATCH 2/4] qtest: Support named interrupts Alastair D'Silva
2016-11-17  4:36   ` [Qemu-devel] " Alastair D'Silva
2016-11-22 17:22   ` Cédric Le Goater
2016-11-22 17:22     ` Cédric Le Goater
2016-11-22 17:24     ` [Qemu-arm] " Paolo Bonzini
2016-11-22 17:24       ` [Qemu-devel] " Paolo Bonzini
2016-11-22 22:31       ` Alastair D'Silva
2016-11-22 22:31         ` Alastair D'Silva
2016-11-22 22:39         ` [Qemu-arm] " Paolo Bonzini
2016-11-22 22:39           ` [Qemu-devel] " Paolo Bonzini
2016-11-22 23:19           ` [Qemu-arm] " Alastair D'Silva
2016-11-22 23:19             ` [Qemu-devel] " Alastair D'Silva
2016-11-23  9:43             ` [Qemu-arm] " Paolo Bonzini
2016-11-23  9:43               ` [Qemu-devel] " Paolo Bonzini
2016-11-23 10:05               ` [Qemu-arm] " Edgar E. Iglesias
2016-11-23 10:05                 ` [Qemu-devel] " Edgar E. Iglesias
2016-11-23 10:34                 ` Paolo Bonzini
2016-11-23 10:34                   ` [Qemu-devel] " Paolo Bonzini
2016-11-17  4:36 ` [Qemu-arm] [PATCH 3/4] hw/timer: Add Epson RX8900 RTC support Alastair D'Silva
2016-11-17  4:36   ` [Qemu-devel] " Alastair D'Silva
2016-11-17  8:29   ` [Qemu-arm] " Cédric Le Goater
2016-11-17  8:29     ` [Qemu-devel] " Cédric Le Goater
2016-11-18  0:19     ` Alastair D'Silva [this message]
2016-11-18  0:19       ` Alastair D'Silva
2016-11-18  8:52       ` [Qemu-arm] " Cédric Le Goater
2016-11-18  8:52         ` [Qemu-devel] " Cédric Le Goater
2016-11-17  4:36 ` [Qemu-arm] [PATCH 4/4] arm: Add an RX8900 RTC to the ASpeed board Alastair D'Silva
2016-11-17  4:36   ` [Qemu-devel] " Alastair D'Silva
2016-11-22 16:56   ` [Qemu-arm] " Cédric Le Goater
2016-11-22 16:56     ` [Qemu-devel] " Cédric Le Goater
2016-11-23  0:46     ` [Qemu-arm] " Alastair D'Silva
2016-11-23  0:46       ` [Qemu-devel] " Alastair D'Silva
2016-11-23  8:48       ` [Qemu-arm] " Cédric Le Goater
2016-11-23  8:48         ` [Qemu-devel] " Cédric Le Goater
2016-11-24  0:15         ` [Qemu-arm] " Andrew Jeffery
2016-11-24  0:15           ` [Qemu-devel] " Andrew Jeffery
2016-11-17 15:33 ` [Qemu-arm] [Qemu-devel] [PATCH 0/4] Add support for the Epson RX8900 RTC to the aspeed board no-reply
2016-11-17 15:33   ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1479428358.11116.46.camel@au1.ibm.com \
    --to=alastair@au1.ibm.com \
    --cc=andrew@aj.id.au \
    --cc=clg@kaod.org \
    --cc=joel@jms.id.au \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.