mbox series

[v3,0/3] Add and connect the ZynqMP RTC

Message ID cover.1516209965.git.alistair.francis@xilinx.com
Headers show
Series Add and connect the ZynqMP RTC | expand

Message

Alistair Francis Jan. 17, 2018, 5:27 p.m. UTC
V3:
 - Store an offset value
 - Use mktimegm()
 - Log unimplemented writes

V2:
 - Delete unused realise function
 - Add cover letter
 - Convert DB_PRINT() macro to trace

Alistair Francis (3):
  xlnx-zynqmp-rtc: Initial commit
  xlnx-zynqmp-rtc: Add basic time support
  xlnx-zynqmp: Connect the RTC device

 hw/arm/xlnx-zynqmp.c               |  14 ++
 hw/timer/Makefile.objs             |   1 +
 hw/timer/trace-events              |   3 +
 hw/timer/xlnx-zynqmp-rtc.c         | 282 +++++++++++++++++++++++++++++++++++++
 include/hw/arm/xlnx-zynqmp.h       |   2 +
 include/hw/timer/xlnx-zynqmp-rtc.h |  88 ++++++++++++
 6 files changed, 390 insertions(+)
 create mode 100644 hw/timer/xlnx-zynqmp-rtc.c
 create mode 100644 include/hw/timer/xlnx-zynqmp-rtc.h

--
2.14.1

This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Comments

Alistair Francis Jan. 17, 2018, 5:34 p.m. UTC | #1
On Wed, Jan 17, 2018 at 9:27 AM, Alistair Francis
<alistair.francis@xilinx.com> wrote:
> V3:
>  - Store an offset value
>  - Use mktimegm()
>  - Log unimplemented writes
>
> V2:
>  - Delete unused realise function
>  - Add cover letter
>  - Convert DB_PRINT() macro to trace
>
> Alistair Francis (3):
>   xlnx-zynqmp-rtc: Initial commit
>   xlnx-zynqmp-rtc: Add basic time support
>   xlnx-zynqmp: Connect the RTC device
>
>  hw/arm/xlnx-zynqmp.c               |  14 ++
>  hw/timer/Makefile.objs             |   1 +
>  hw/timer/trace-events              |   3 +
>  hw/timer/xlnx-zynqmp-rtc.c         | 282 +++++++++++++++++++++++++++++++++++++
>  include/hw/arm/xlnx-zynqmp.h       |   2 +
>  include/hw/timer/xlnx-zynqmp-rtc.h |  88 ++++++++++++
>  6 files changed, 390 insertions(+)
>  create mode 100644 hw/timer/xlnx-zynqmp-rtc.c
>  create mode 100644 include/hw/timer/xlnx-zynqmp-rtc.h
>
> --
> 2.14.1
>
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.

Sorry, I forgot this is still there. Still working with IT.

Alistair
Philippe Mathieu-Daudé Jan. 17, 2018, 8:48 p.m. UTC | #2
On 01/17/2018 02:27 PM, Alistair Francis wrote:
> Allow the guest to determine the time set from the QEMU command line.
> 
> This includes adding a trace event to debug the new time.
> 
> The migration logic was copied from the PL031 migration logic.
> 
> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
> ---
> V3:
>  - Store an offset value
>  - Use mktimegm()
>  - Log unimplemented writes
> V2:
>  - Convert DB_PRINT() macro to trace
> 
>  hw/timer/trace-events              |  3 ++
>  hw/timer/xlnx-zynqmp-rtc.c         | 64 ++++++++++++++++++++++++++++++++++++++
>  include/hw/timer/xlnx-zynqmp-rtc.h |  4 +++
>  3 files changed, 71 insertions(+)
> 
> diff --git a/hw/timer/trace-events b/hw/timer/trace-events
> index 640722b5d1..e6e042fddb 100644
> --- a/hw/timer/trace-events
> +++ b/hw/timer/trace-events
> @@ -60,3 +60,6 @@ systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr
>  cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
>  cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
>  cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
> +
> +# hw/timer/xlnx-zynqmp-rtc.c
> +xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
> diff --git a/hw/timer/xlnx-zynqmp-rtc.c b/hw/timer/xlnx-zynqmp-rtc.c
> index ead40fc42d..76c1af1afe 100644
> --- a/hw/timer/xlnx-zynqmp-rtc.c
> +++ b/hw/timer/xlnx-zynqmp-rtc.c
> @@ -29,6 +29,10 @@
>  #include "hw/register.h"
>  #include "qemu/bitops.h"
>  #include "qemu/log.h"
> +#include "hw/ptimer.h"
> +#include "qemu/cutils.h"
> +#include "sysemu/sysemu.h"
> +#include "trace.h"
>  #include "hw/timer/xlnx-zynqmp-rtc.h"
> 
>  #ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG
> @@ -47,6 +51,19 @@ static void addr_error_int_update_irq(XlnxZynqMPRTC *s)
>      qemu_set_irq(s->irq_addr_error_int, pending);
>  }
> 
> +static uint32_t rtc_get_count(XlnxZynqMPRTC *s)
> +{
> +    int64_t now = qemu_clock_get_ns(rtc_clock);
> +    return s->tick_offset + now / NANOSECONDS_PER_SECOND;
> +}
> +
> +static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64)
> +{
> +    XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
> +
> +    return rtc_get_count(s);
> +}
> +
>  static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64)
>  {
>      XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque);
> @@ -99,15 +116,25 @@ static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
>      return 0;
>  }
> 
> +static void unimp_postw(RegisterInfo *reg, uint64_t val64)
> +{
> +    qemu_log_mask(LOG_UNIMP, "The time setting functionality is not "
> +                  "implemented\n");
> +}
> +
>  static const RegisterAccessInfo rtc_regs_info[] = {
>      {   .name = "SET_TIME_WRITE",  .addr = A_SET_TIME_WRITE,
> +        .post_write = unimp_postw,

Why bother adding this function? Rather use ".unimp = ~0" which log
register name accessed.

>      },{ .name = "SET_TIME_READ",  .addr = A_SET_TIME_READ,
>          .ro = 0xffffffff,
> +        .post_read = current_time_postr,
>      },{ .name = "CALIB_WRITE",  .addr = A_CALIB_WRITE,
> +        .post_write = unimp_postw,

Ditto.

>      },{ .name = "CALIB_READ",  .addr = A_CALIB_READ,
>          .ro = 0x1fffff,
>      },{ .name = "CURRENT_TIME",  .addr = A_CURRENT_TIME,
>          .ro = 0xffffffff,
> +        .post_read = current_time_postr,
>      },{ .name = "CURRENT_TICK",  .addr = A_CURRENT_TICK,
>          .ro = 0xffff,
>      },{ .name = "ALARM",  .addr = A_ALARM,
> @@ -147,6 +174,10 @@ static void rtc_reset(DeviceState *dev)
>          register_reset(&s->regs_info[i]);
>      }
> 
> +    trace_xlnx_zynqmp_rtc_gettime(s->current_tm.tm_year, s->current_tm.tm_mon,
> +                                  s->current_tm.tm_mday, s->current_tm.tm_hour,
> +                                  s->current_tm.tm_min, s->current_tm.tm_sec);
> +
>      rtc_int_update_irq(s);
>      addr_error_int_update_irq(s);
>  }
> @@ -182,14 +213,47 @@ static void rtc_init(Object *obj)
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->irq_rtc_int);
>      sysbus_init_irq(sbd, &s->irq_addr_error_int);
> +
> +    qemu_get_timedate(&s->current_tm, 0);
> +    s->tick_offset = mktimegm(&s->current_tm) -
> +        qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND;
> +}
> +
> +static int rtc_pre_save(void *opaque)
> +{
> +    XlnxZynqMPRTC *s = opaque;
> +
> +    /* tick_offset is base_time - rtc_clock base time.  Instead, we want to
> +     * store the base time relative to the QEMU_CLOCK_VIRTUAL for
> +     * backwards-compatibility.
> +     */
> +    int64_t delta = qemu_clock_get_ns(rtc_clock) -
> +                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    s->tick_offset_vmstate = s->tick_offset + delta / NANOSECONDS_PER_SECOND;
> +
> +    return 0;
> +}
> +
> +static int rtc_post_load(void *opaque, int version_id)
> +{
> +    XlnxZynqMPRTC *s = opaque;
> +
> +    int64_t delta = qemu_clock_get_ns(rtc_clock) -
> +                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    s->tick_offset = s->tick_offset_vmstate - delta / NANOSECONDS_PER_SECOND;
> +
> +    return 0;
>  }
> 
>  static const VMStateDescription vmstate_rtc = {
>      .name = TYPE_XLNX_ZYNQMP_RTC,
>      .version_id = 1,
>      .minimum_version_id = 1,
> +    .pre_save = rtc_pre_save,
> +    .post_load = rtc_post_load,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX),
> +        VMSTATE_UINT32(tick_offset_vmstate, XlnxZynqMPRTC),
>          VMSTATE_END_OF_LIST(),
>      }
>  };
> diff --git a/include/hw/timer/xlnx-zynqmp-rtc.h b/include/hw/timer/xlnx-zynqmp-rtc.h
> index 87649836cc..b0f54e00c1 100644
> --- a/include/hw/timer/xlnx-zynqmp-rtc.h
> +++ b/include/hw/timer/xlnx-zynqmp-rtc.h
> @@ -79,6 +79,10 @@ typedef struct XlnxZynqMPRTC {
>      qemu_irq irq_rtc_int;
>      qemu_irq irq_addr_error_int;
> 
> +    struct tm current_tm;
> +    uint32_t tick_offset_vmstate;
> +    uint32_t tick_offset;
> +
>      uint32_t regs[XLNX_ZYNQMP_RTC_R_MAX];
>      RegisterInfo regs_info[XLNX_ZYNQMP_RTC_R_MAX];
>  } XlnxZynqMPRTC;
> --
> 2.14.1

removing unimp_postw():
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Philippe Mathieu-Daudé Jan. 17, 2018, 8:49 p.m. UTC | #3
On 01/17/2018 02:27 PM, Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
> 
>  hw/arm/xlnx-zynqmp.c         | 14 ++++++++++++++
>  include/hw/arm/xlnx-zynqmp.h |  2 ++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
> index 325642058b..deef583c2a 100644
> --- a/hw/arm/xlnx-zynqmp.c
> +++ b/hw/arm/xlnx-zynqmp.c
> @@ -50,6 +50,9 @@
>  #define DPDMA_ADDR          0xfd4c0000
>  #define DPDMA_IRQ           116
> 
> +#define RTC_ADDR            0xffa60000
> +#define RTC_IRQ             26
> +
>  static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
>      0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
>  };
> @@ -183,6 +186,9 @@ static void xlnx_zynqmp_init(Object *obj)
> 
>      object_initialize(&s->dpdma, sizeof(s->dpdma), TYPE_XLNX_DPDMA);
>      qdev_set_parent_bus(DEVICE(&s->dpdma), sysbus_get_default());
> +
> +    object_initialize(&s->rtc, sizeof(s->rtc), TYPE_XLNX_ZYNQMP_RTC);
> +    qdev_set_parent_bus(DEVICE(&s->rtc), sysbus_get_default());
>  }
> 
>  static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
> @@ -454,6 +460,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
>                               &error_abort);
>      sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR);
>      sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]);
> +
> +    object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, RTC_ADDR);
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, gic_spi[RTC_IRQ]);
>  }
> 
>  static Property xlnx_zynqmp_props[] = {
> diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
> index 3e6fb9b7bd..9e8c9e18dd 100644
> --- a/include/hw/arm/xlnx-zynqmp.h
> +++ b/include/hw/arm/xlnx-zynqmp.h
> @@ -28,6 +28,7 @@
>  #include "hw/ssi/xilinx_spips.h"
>  #include "hw/dma/xlnx_dpdma.h"
>  #include "hw/display/xlnx_dp.h"
> +#include "hw/timer/xlnx-zynqmp-rtc.h"
> 
>  #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
>  #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
> @@ -90,6 +91,7 @@ typedef struct XlnxZynqMPState {
>      XlnxZynqMPQSPIPS qspi;
>      XlnxDPState dp;
>      XlnxDPDMAState dpdma;
> +    XlnxZynqMPRTC rtc;
> 
>      char *boot_cpu;
>      ARMCPU *boot_cpu_ptr;
> --
> 2.14.1
>