* Re: [PATCH v4 1/4] powerpc/mm: refactor radix physical page mapping
From: Aneesh Kumar K.V @ 2017-01-04 5:04 UTC (permalink / raw)
To: Reza Arbab, Michael Ellerman, Benjamin Herrenschmidt,
Paul Mackerras
Cc: linuxppc-dev, Balbir Singh, Alistair Popple
In-Reply-To: <1483476218-17271-2-git-send-email-arbab@linux.vnet.ibm.com>
Reza Arbab <arbab@linux.vnet.ibm.com> writes:
> Move the page mapping code in radix_init_pgtable() into a separate
> function that will also be used for memory hotplug.
>
> The current goto loop progressively decreases its mapping size as it
> covers the tail of a range whose end is unaligned. Change this to a for
> loop which can do the same for both ends of the range.
>
We lost the below in the change.
pr_info("Mapping range 0x%lx - 0x%lx with 0x%lx\n",
(unsigned long)base, (unsigned long)end,
linear_page_size);
Is there a way to dump the range and the size with which we mapped that
range ?
> Signed-off-by: Reza Arbab <arbab@linux.vnet.ibm.com>
> ---
> arch/powerpc/mm/pgtable-radix.c | 69 ++++++++++++++++++-----------------------
> 1 file changed, 31 insertions(+), 38 deletions(-)
>
> diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
> index 623a0dc..5cee6d1 100644
> --- a/arch/powerpc/mm/pgtable-radix.c
> +++ b/arch/powerpc/mm/pgtable-radix.c
> @@ -107,54 +107,47 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,
> return 0;
> }
>
> +static int __meminit create_physical_mapping(unsigned long start,
> + unsigned long end)
> +{
> + unsigned long mapping_size;
> +
> + start = _ALIGN_UP(start, PAGE_SIZE);
> + for (; start < end; start += mapping_size) {
> + unsigned long gap = end - start;
> + int rc;
> +
> + if (IS_ALIGNED(start, PUD_SIZE) && gap >= PUD_SIZE &&
> + mmu_psize_defs[MMU_PAGE_1G].shift)
> + mapping_size = PUD_SIZE;
> + else if (IS_ALIGNED(start, PMD_SIZE) && gap >= PMD_SIZE &&
> + mmu_psize_defs[MMU_PAGE_2M].shift)
> + mapping_size = PMD_SIZE;
> + else
> + mapping_size = PAGE_SIZE;
> +
> + rc = radix__map_kernel_page((unsigned long)__va(start), start,
> + PAGE_KERNEL_X, mapping_size);
> + if (rc)
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> static void __init radix_init_pgtable(void)
> {
> - int loop_count;
> - u64 base, end, start_addr;
> unsigned long rts_field;
> struct memblock_region *reg;
> - unsigned long linear_page_size;
>
> /* We don't support slb for radix */
> mmu_slb_size = 0;
> /*
> * Create the linear mapping, using standard page size for now
> */
> - loop_count = 0;
> - for_each_memblock(memory, reg) {
> -
> - start_addr = reg->base;
> -
> -redo:
> - if (loop_count < 1 && mmu_psize_defs[MMU_PAGE_1G].shift)
> - linear_page_size = PUD_SIZE;
> - else if (loop_count < 2 && mmu_psize_defs[MMU_PAGE_2M].shift)
> - linear_page_size = PMD_SIZE;
> - else
> - linear_page_size = PAGE_SIZE;
> -
> - base = _ALIGN_UP(start_addr, linear_page_size);
> - end = _ALIGN_DOWN(reg->base + reg->size, linear_page_size);
> -
> - pr_info("Mapping range 0x%lx - 0x%lx with 0x%lx\n",
> - (unsigned long)base, (unsigned long)end,
> - linear_page_size);
> -
> - while (base < end) {
> - radix__map_kernel_page((unsigned long)__va(base),
> - base, PAGE_KERNEL_X,
> - linear_page_size);
> - base += linear_page_size;
> - }
> - /*
> - * map the rest using lower page size
> - */
> - if (end < reg->base + reg->size) {
> - start_addr = end;
> - loop_count++;
> - goto redo;
> - }
> - }
> + for_each_memblock(memory, reg)
> + WARN_ON(create_physical_mapping(reg->base,
> + reg->base + reg->size));
> /*
> * Allocate Partition table and process table for the
> * host.
> --
> 1.8.3.1
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v4 6/8] hw/timer: Add Epson RX8900 RTC support
From: Andrew Jeffery @ 2017-01-04 4:59 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: qemu-devel, Peter Maydell, Cédric Le Goater, Joel Stanley,
Alastair D'Silva, Chris Smart
In-Reply-To: <20161215054812.12602-7-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 43213 bytes --]
Hi Alastair,
I have some mostly minor comments below.
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> This patch adds support for the Epson RX8900 I2C RTC.
>
> The following chip features are implemented:
> - RTC (wallclock based, ptimer 10x oversampling to pick up
> wallclock transitions)
> - Time update interrupt (per second/minute, wallclock based)
> - Alarms (wallclock based)
> - Temperature (set via a property)
> - Countdown timer (emulated clock via ptimer)
> - FOUT via GPIO (emulated clock via ptimer)
>
> The following chip features are unimplemented:
> - Low voltage detection
> - i2c timeout
>
> The implementation exports the following named GPIOs:
> rx8900-interrupt-out
> rx8900-fout-enable
> rx8900-fout
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> > Signed-off-by: Chris Smart <chris@distroguy.com>
> ---
> default-configs/arm-softmmu.mak | 1 +
> hw/timer/Makefile.objs | 2 +
> hw/timer/rx8900.c | 912 ++++++++++++++++++++++++++++++++++++++++
> hw/timer/rx8900_regs.h | 141 +++++++
> hw/timer/trace-events | 31 ++
> 5 files changed, 1087 insertions(+)
> create mode 100644 hw/timer/rx8900.c
> create mode 100644 hw/timer/rx8900_regs.h
>
> 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..cb1a2c8
> --- /dev/null
> +++ b/hw/timer/rx8900.c
> @@ -0,0 +1,912 @@
> +/*
> + * Epson RX8900SA/CE Realtime Clock Module
> + *
> + * Copyright (c) 2016 IBM Corporation
> + * Authors:
> > + * Alastair D'Silva <alastair@d-silva.org>
> > + * Chris Smart <chris@distroguy.com>
> + *
> + * 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 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/log.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "trace.h"
> +
> +#define TYPE_RX8900 "rx8900"
> +#define RX8900(obj) OBJECT_CHECK(RX8900State, (obj), TYPE_RX8900)
> +
> +typedef struct RX8900State {
> + I2CSlave parent_obj;
> +
> + ptimer_state *sec_timer; /* triggered once per second */
> + ptimer_state *fout_timer;
> + ptimer_state *countdown_timer;
> + bool fout_state;
> + 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 nvram_offset; /* Wrapped to stay within RX8900_NVRAM_SIZE */
> + bool addr_byte;
> + uint8_t last_interrupt_seconds; /* The last time the second timer ticked */
> + /* the last minute the timer update interrupt was triggered (if enabled) */
> + uint8_t last_update_interrupt_minutes;
> + double supply_voltage;
> + qemu_irq interrupt_pin;
> + qemu_irq fout_pin;
> +} RX8900State;
> +
> +static const VMStateDescription vmstate_rx8900 = {
> + .name = "rx8900",
> + .version_id = 1,
> + .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_state, RX8900State),
> + VMSTATE_INT64(offset, RX8900State),
> + VMSTATE_UINT8(weekday, RX8900State),
> + VMSTATE_UINT8(wday_offset, RX8900State),
> + VMSTATE_UINT8_ARRAY(nvram, RX8900State, RX8900_NVRAM_SIZE),
> + VMSTATE_INT32(nvram_offset, RX8900State),
> + VMSTATE_BOOL(addr_byte, RX8900State),
> + VMSTATE_UINT8(last_interrupt_seconds, RX8900State),
> + VMSTATE_UINT8(last_update_interrupt_minutes, RX8900State),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void rx8900_reset(DeviceState *dev);
> +
> +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_rx8900_capture_current_time(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->nvram_offset = (s->nvram_offset + 1) & (RX8900_NVRAM_SIZE - 1);
> + trace_rx8900_regptr_update(s->nvram_offset);
> +
> + if (s->nvram_offset == START_ADDRESS) {
> + trace_rx8900_regptr_overflow();
> + capture_current_time(s);
> + }
> +}
> +
> +#define INVALID_WEEKDAY 0xff
> +
> +/**
> + * 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_rx8900_event_weekday(s->weekday, BIT(s->weekday),
> + s->wday_offset);
> +
> + s->weekday = INVALID_WEEKDAY;
> + }
> + 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->nvram_offset];
> + trace_rx8900_read_register(s->nvram_offset, res);
> + inc_regptr(s);
> + return res;
> +}
> +
> +/**
> + * Disable the countdown timer
> + * @param s the RTC to operate on
> + */
> +static void disable_countdown_timer(RX8900State *s)
> +{
> + trace_rx8900_disable_countdown_timer();
> + ptimer_stop(s->countdown_timer);
> +}
> +
> +/**
> + * Enable the countdown timer
> + * @param s the RTC to operate on
> + */
> +static void enable_countdown_timer(RX8900State *s)
> +{
> + trace_rx8900_enable_countdown_timer();
> + ptimer_run(s->countdown_timer, 0);
> +}
> +
> +/**
> + * 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_rx8900_countdown_tick(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_rx8900_countdown_elapsed();
> +
> + disable_countdown_timer(s);
> +
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_TF;
> +
> + if (s->nvram[CONTROL_REGISTER] & CTRL_MASK_TIE) {
> + trace_rx8900_fire_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_rx8900_disable_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_rx8900_enable_timer();
> + ptimer_run(s->sec_timer, 0);
> +}
> +
> +/**
> + * 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;
> + bool alarm_week_day_matches;
> +
> + qemu_get_timedate(&now, s->offset);
> +
> + if (now.tm_sec == s->last_interrupt_seconds) {
> + return;
> + }
> +
> + s->last_interrupt_seconds = now.tm_sec;
> +
> + trace_rx8900_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[EXTENSION_REGISTER] & EXT_MASK_WADA)) {
> + alarm_week_day_matches =
> + s->nvram[ALARM_WEEK_DAY] == to_bcd(now.tm_mday);
> + } else {
> + alarm_week_day_matches =
> + s->nvram[ALARM_WEEK_DAY] ==
> + 0x01 << ((now.tm_wday + s->wday_offset) % 7);
> + }
> +
> + if ((s->nvram[CONTROL_REGISTER] & CTRL_MASK_AIE) && now.tm_sec == 0 &&
> + s->nvram[ALARM_MINUTE] == to_bcd(now.tm_min) &&
> + s->nvram[ALARM_HOUR] == to_bcd(now.tm_hour) &&
> + alarm_week_day_matches) {
> + trace_rx8900_trigger_alarm();
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_AF;
> + fire_interrupt = true;
> + }
> +
> + if (fire_interrupt) {
> + trace_rx8900_fire_interrupt();
> + qemu_irq_pulse(s->interrupt_pin);
> + }
> +}
> +
> +
> +#define COUNTDOWN_TIMER_FREQ 4096
> +
> +/**
> + * 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) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Test bit is enabled but is forbidden by the manufacturer");
> + }
> +
> + if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> + (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> + /* FSELx has changed */
> +
> + switch (data & (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> + case EXT_MASK_FSEL0:
> + trace_rx8900_set_fout(1024);
> + ptimer_set_limit(s->fout_timer, 32, 1);
> + break;
> + case EXT_MASK_FSEL1:
> + trace_rx8900_set_fout(1);
> + ptimer_set_limit(s->fout_timer, 32768, 1);
> + break;
> + case 0:
> + case (EXT_MASK_FSEL0 | EXT_MASK_FSEL1):
> + trace_rx8900_set_fout(32768);
> + ptimer_set_limit(s->fout_timer, 1, 1);
> + break;
> + }
> + }
> +
> + if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> + (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> + /* TSELx has changed */
> + switch (data & (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> + case 0:
> + trace_rx8900_set_countdown_timer(64);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ / 64, 1);
> + break;
> + case EXT_MASK_TSEL0:
> + trace_rx8900_set_countdown_timer(1);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ, 1);
> + break;
> + case EXT_MASK_TSEL1:
> + trace_rx8900_set_countdown_timer_per_minute();
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ * 60, 1);
> + break;
> + case (EXT_MASK_TSEL0 | EXT_MASK_TSEL1):
> + trace_rx8900_set_countdown_timer(COUNTDOWN_TIMER_FREQ);
> + 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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Attempt to write to write protected bit %d in control register",
> + CTRL_REG_WP0);
> + }
> +
> + if (diffmask & CTRL_MASK_WP1) {
> + data &= ~CTRL_MASK_WP1;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Attempt to write to write protected bit %d in control register",
> + CTRL_REG_WP1);
> + }
> +
> + 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_rx8900_enable_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_rx8900_enable_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);
> + }
> +
> + 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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Only 0 can be written to unused bit %d in the flag register",
> + FLAG_REG_UNUSED_7);
> + }
> +}
> +
> +/**
> + * 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_rx8900_enable_fout();
> + ptimer_run(s->fout_timer, 0);
> + } else {
> + /* disable fout */
> + trace_rx8900_disable_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_rx8900_fout_toggle();
> + s->fout_state = !s->fout_state;
> +
> + if (s->fout_state) {
> + qemu_irq_raise(s->fout_pin);
> + } else {
> + qemu_irq_lower(s->fout_pin);
> + }
We could just use qemu_set_irq() here.
> +}
> +
> +/**
> + * Verify the current voltage and raise flags if it is low
> + * @param s the RTC to operate on
> + */
> +static void check_voltage(RX8900State *s)
> +{
> + if (!(s->nvram[BACKUP_FUNCTION] & BACKUP_MASK_VDETOFF)) {
> + if (s->supply_voltage < 2.0) {
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_VDET;
> + }
> +
> + if (s->supply_voltage < 1.6) {
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_VLF;
> + }
> + }
> +}
> +
> +/**
> + * 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_rx8900_i2c_data_receive(data);
> +
> + if (s->addr_byte) {
> + s->nvram_offset = data & (RX8900_NVRAM_SIZE - 1);
> + trace_rx8900_regptr_update(s->nvram_offset);
> + s->addr_byte = false;
> + return 0;
> + }
> +
> + trace_rx8900_set_register(s->nvram_offset, data);
> +
> + qemu_get_timedate(&now, s->offset);
> + switch (s->nvram_offset) {
> + case SECONDS:
> + case EXT_SECONDS:
> + now.tm_sec = from_bcd(data & 0x7f);
> + if (now.tm_sec > 59) { /* RX8900 does not support leap seconds */
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - second data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + s->offset = qemu_timedate_diff(&now);
> + break;
> +
> + case MINUTES:
> + case EXT_MINUTES:
> + now.tm_min = from_bcd(data & 0x7f);
> + if (now.tm_min > 59) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - minute data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + s->offset = qemu_timedate_diff(&now);
> + break;
> +
> + case HOURS:
> + case EXT_HOURS:
> + now.tm_hour = from_bcd(data & 0x3f);
> + if (now.tm_hour > 24) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - hour data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + 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
> + * with only 1 of bits 0-6 set. Otherwise behavior is undefined.
> + */
> + switch (data) {
> + case 0x01:
> + case 0x02:
> + case 0x04:
> + case 0x08:
> + case 0x10:
> + case 0x20:
> + case 0x40:
> + break;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - weekday data '%x' is out of range, "
> + "undefined behavior will result", data);
> + break;
> + }
I think it might be clearer to do:
if (data == 0x80 || ctpop8(data) != 1) {
qemu_log_mask(...);
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;
> +
> + check_voltage(s);
> + break;
> +
> + case CONTROL_REGISTER:
> + case EXT_CONTROL_REGISTER:
> + update_control_register(s, data);
> + break;
> +
> + default:
> + s->nvram[s->nvram_offset] = data;
> + }
> +
> + inc_regptr(s);
> + return 0;
> +}
> +
> +/**
> + * Get the device temperature in Celsius 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.0 - 187.1) / 3.218;
You have encode_temperature() below, should we not have
decode_temperature()?
> +
> + trace_rx8900_get_temperature(s->nvram[TEMPERATURE], value);
> +
> + visit_type_number(v, name, &value, errp);
> +}
> +
> +/**
> + * Encode a temperature in Celsius
> + * @param celsius the temperature
> + * @return the encoded temperature
> + */
> +static inline uint8_t encode_temperature(double celsius)
> +{
> + return (uint8_t) ((celsius * 3.218 + 187.19) / 2);
> +}
> +
> +/**
> + * Set the device temperature in Celsius 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 Celsius */
> + 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 %fC is out of range", temp);
> + return;
> + }
> +
> + s->nvram[TEMPERATURE] = encode_temperature(temp);
> +
> + trace_rx8900_set_temperature(s->nvram[TEMPERATURE], temp);
> +}
> +
> +/**
> + * Get the device supply voltage 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_voltage(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + RX8900State *s = RX8900(obj);
> +
> + visit_type_number(v, name, &s->supply_voltage, errp);
> +}
> +
> +/**
> + * Set the device supply voltage 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_voltage(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + RX8900State *s = RX8900(obj);
> + Error *local_err = NULL;
> + double temp;
Maybe voltage? It's ambiguous as to whether it's a copy/paste error
from 'temperature' or if you mean 'temporary'...
> + visit_type_number(v, name, &temp, &local_err);
> + if (local_err) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> + s->supply_voltage = temp;
... as this almost looks like a bug.
> + trace_rx8900_set_voltage(s->supply_voltage);
> +
> + check_voltage(s);
> +}
> +
> +
> +/**
> + * 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);
> +
> + object_property_add(obj, "voltage", "number",
> + rx8900_get_voltage,
> + rx8900_set_voltage, NULL, NULL, NULL);
> +}
> +
> +/**
> + * Reset the device
> + * @param dev the RX8900 device to reset
> + */
> +static void rx8900_reset(DeviceState *dev)
Is there a reason we can't define rx8900_reset() further up the file to
avoid forward-declaring it?
> +{
> + RX8900State *s = RX8900(dev);
> +
> + trace_rx8900_reset();
> +
> + /* The clock is running and synchronized with the host */
> + s->offset = 0;
> + s->weekday = 7; /* Set to an invalid value */
Can you explain why we do that rather than just stating that 7 is
invalid?
> +
> + s->nvram[EXTENSION_REGISTER] = EXT_MASK_TSEL1;
> + s->nvram[CONTROL_REGISTER] = CTRL_MASK_CSEL0;
> + s->nvram[FLAG_REGISTER] &= FLAG_MASK_VDET | FLAG_MASK_VLF;
> +
> + s->nvram_offset = 0;
> +
> + trace_rx8900_regptr_update(s->nvram_offset);
> +
> + s->addr_byte = false;
> +}
> +
> +/**
> + * Realize an RX8900 device instance
> + * Set up timers
> + * Configure GPIO lines
> + * @param dev the device instance to realize
> + * @param errp an error object to populate on error
> + */
> +static void rx8900_realize(DeviceState *dev, Error **errp)
> +{
> + RX8900State *s = RX8900(dev);
> + I2CSlave *i2c = I2C_SLAVE(dev);
> + QEMUBH *bh;
> + char name[64];
> +
> + s->fout_state = false;
> +
> + memset(s->nvram, 0, RX8900_NVRAM_SIZE);
> + /* Set the initial state to 25 degrees Celsius */
> + s->nvram[TEMPERATURE] = encode_temperature(25.0);
> +
> + /* Set up timers */
> + bh = qemu_bh_new(rx8900_timer_tick, s);
> + s->sec_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + /* we trigger the timer at 10Hz and check for rollover, as the qemu
> + * clock does not advance in realtime in the test environment,
> + * leading to unstable test results
> + */
It seems unfortunate that some of the code seems dedicated to working
around test suite issues (e.g. early return in some functions). Ah
well.
> + ptimer_set_freq(s->sec_timer, 10);
> + ptimer_set_limit(s->sec_timer, 1, 1);
> +
> + bh = qemu_bh_new(rx8900_fout_tick, s);
> + s->fout_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + /* frequency doubled to generate 50% duty cycle square wave */
> + ptimer_set_freq(s->fout_timer, 32768 * 2);
> + ptimer_set_limit(s->fout_timer, 1, 1);
> +
> + bh = qemu_bh_new(rx8900_countdown_tick, s);
> + s->countdown_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + ptimer_set_freq(s->countdown_timer, COUNTDOWN_TIMER_FREQ);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ, 1);
> +
> +
> + /* set up GPIO */
> + snprintf(name, sizeof(name), "rx8900-interrupt-out");
Why the snprintf()s?
> + qdev_init_gpio_out_named(&i2c->qdev, &s->interrupt_pin, name, 1);
> + trace_rx8900_pin_name("Interrupt", name);
> +
> + snprintf(name, sizeof(name), "rx8900-fout-enable");
> + qdev_init_gpio_in_named(&i2c->qdev, rx8900_fout_enable_handler, name, 1);
> + trace_rx8900_pin_name("Fout-enable", name);
> +
> + snprintf(name, sizeof(name), "rx8900-fout");
> + qdev_init_gpio_out_named(&i2c->qdev, &s->fout_pin, name, 1);
> + trace_rx8900_pin_name("Fout", name);
> +
> + /* Set up default voltage */
> + s->supply_voltage = 3.3f;
> + trace_rx8900_set_voltage(s->supply_voltage);
> +}
> +
> +/**
> + * Set up the device callbacks
> + * @param klass the device class
> + * @param data
> + */
> +static void rx8900_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +
> + k->event = rx8900_event;
> + k->recv = rx8900_recv;
> + k->send = rx8900_send;
> + dc->realize = rx8900_realize;
> + dc->reset = rx8900_reset;
> + dc->vmsd = &vmstate_rx8900;
> +}
> +
> +static const TypeInfo rx8900_info = {
> + .name = TYPE_RX8900,
> + .parent = TYPE_I2C_SLAVE,
> + .instance_size = sizeof(RX8900State),
> + .instance_init = rx8900_initfn,
> + .class_init = rx8900_class_init,
> +};
> +
> +/**
> + * Register the device with QEMU
> + */
> +static void rx8900_register_types(void)
> +{
> + type_register_static(&rx8900_info);
> +}
> +
> +type_init(rx8900_register_types)
> diff --git a/hw/timer/rx8900_regs.h b/hw/timer/rx8900_regs.h
> new file mode 100644
> index 0000000..0aaa9a3
> --- /dev/null
> +++ b/hw/timer/rx8900_regs.h
> @@ -0,0 +1,141 @@
> +/*
> + * 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
> + *
> + */
> +
> +#ifndef RX8900_REGS_H
> +#define RX8900_REGS_H
> +
> +#include "qemu/bitops.h"
> +
> +#define RX8900_NVRAM_SIZE 0x20
Do all the enums below need to be defined in the header or are they
only relevant to the implementation? If it's the latter, then they
should go in the .c file.
Also I would've reached for #define for all these values, not enums,
but that might be a personal thing.
> +
> +typedef enum RX8900Addresses {
> + START_ADDRESS = 0x00,
> + SECONDS = 0x00,
> + MINUTES = 0x01,
> + HOURS = 0x02,
> + WEEKDAY = 0x03, /* a walking bit with bit 0 set for Sunday, 1 for Monday...
> + 6 for Saturday, see the datasheet for details */
> + DAY = 0x04,
> + MONTH = 0x05,
> + YEAR = 0x06,
> + RAM = 0x07,
> + ALARM_MINUTE = 0x08,
> + ALARM_HOUR = 0x09,
> + ALARM_WEEK_DAY = 0x0A,
> + TIMER_COUNTER_0 = 0x0B,
> + TIMER_COUNTER_1 = 0x0C,
> + EXTENSION_REGISTER = 0x0D,
> + FLAG_REGISTER = 0X0E,
> + CONTROL_REGISTER = 0X0F,
> + EXT_SECONDS = 0x010, /* Alias of SECONDS */
> + EXT_MINUTES = 0x11, /* Alias of MINUTES */
> + EXT_HOURS = 0x12, /* Alias of HOURS */
> + EXT_WEEKDAY = 0x13, /* Alias of WEEKDAY */
> + EXT_DAY = 0x14, /* Alias of DAY */
> + EXT_MONTH = 0x15, /* Alias of MONTH */
> + EXT_YEAR = 0x16, /* Alias of YEAR */
> + TEMPERATURE = 0x17,
> + BACKUP_FUNCTION = 0x18,
> + NO_USE_1 = 0x19,
> + NO_USE_2 = 0x1A,
> + EXT_TIMER_COUNTER_0 = 0x1B, /* Alias of TIMER_COUNTER_0 */
> + EXT_TIMER_COUNTER_1 = 0x1C, /* Alias of TIMER_COUNTER_1 */
> + EXT_EXTENSION_REGISTER = 0x1D, /* Alias of EXTENSION_REGISTER */
> + EXT_FLAG_REGISTER = 0X1E, /* Alias of FLAG_REGISTER */
> + EXT_CONTROL_REGISTER = 0X1F /* Alias of CONTROL_REGISTER */
> +} RX8900Addresses;
> +
> +typedef enum ExtRegBits {
> + EXT_REG_TSEL0 = 0,
> + EXT_REG_TSEL1 = 1,
> + EXT_REG_FSEL0 = 2,
> + EXT_REG_FSEL1 = 3,
> + EXT_REG_TE = 4,
> + EXT_REG_USEL = 5,
> + EXT_REG_WADA = 6,
> + EXT_REG_TEST = 7
> +} ExtRegBits;
> +
> +typedef enum ExtRegMasks {
> + EXT_MASK_TSEL0 = BIT(0),
> + EXT_MASK_TSEL1 = BIT(1),
> + EXT_MASK_FSEL0 = BIT(2),
> + EXT_MASK_FSEL1 = BIT(3),
> + EXT_MASK_TE = BIT(4),
> + EXT_MASK_USEL = BIT(5),
> + EXT_MASK_WADA = BIT(6),
> + EXT_MASK_TEST = BIT(7)
> +} ExtRegMasks;
> +
> +typedef enum CtrlRegBits {
> + CTRL_REG_RESET = 0,
> + CTRL_REG_WP0 = 1,
> + CTRL_REG_WP1 = 2,
> + CTRL_REG_AIE = 3,
> + CTRL_REG_TIE = 4,
> + CTRL_REG_UIE = 5,
> + CTRL_REG_CSEL0 = 6,
> + CTRL_REG_CSEL1 = 7
> +} CtrlRegBits;
> +
> +typedef enum CtrlRegMask {
> + CTRL_MASK_RESET = BIT(0),
> + CTRL_MASK_WP0 = BIT(1),
> + CTRL_MASK_WP1 = BIT(2),
> + CTRL_MASK_AIE = BIT(3),
> + CTRL_MASK_TIE = BIT(4),
> + CTRL_MASK_UIE = BIT(5),
> + CTRL_MASK_CSEL0 = BIT(6),
> + CTRL_MASK_CSEL1 = BIT(7)
> +} CtrlRegMask;
> +
> +typedef enum FlagRegBits {
> + FLAG_REG_VDET = 0,
> + FLAG_REG_VLF = 1,
> + FLAG_REG_UNUSED_2 = 2,
> + FLAG_REG_AF = 3,
> + FLAG_REG_TF = 4,
> + FLAG_REG_UF = 5,
> + FLAG_REG_UNUSED_6 = 6,
> + FLAG_REG_UNUSED_7 = 7
> +} FlagRegBits;
> +
> +#define RX8900_INTERRUPT_SOURCES 6
> +typedef enum FlagRegMask {
> + FLAG_MASK_VDET = BIT(0),
> + FLAG_MASK_VLF = BIT(1),
> + FLAG_MASK_UNUSED_2 = BIT(2),
> + FLAG_MASK_AF = BIT(3),
> + FLAG_MASK_TF = BIT(4),
> + FLAG_MASK_UF = BIT(5),
> + FLAG_MASK_UNUSED_6 = BIT(6),
> + FLAG_MASK_UNUSED_7 = BIT(7)
> +} FlagRegMask;
> +
> +typedef enum BackupRegBits {
> + BACKUP_REG_BKSMP0 = 0,
> + BACKUP_REG_BKSMP1 = 1,
> + BACKUP_REG_SWOFF = 2,
> + BACKUP_REG_VDETOFF = 3
> +} BackupRegBits;
> +
> +typedef enum BackupRegMask {
> + BACKUP_MASK_BKSMP0 = BIT(0),
> + BACKUP_MASK_BKSMP1 = BIT(1),
> + BACKUP_MASK_SWOFF = BIT(2),
> + BACKUP_MASK_VDETOFF = BIT(3)
> +} BackupRegMask;
> +
> +#endif
> diff --git a/hw/timer/trace-events b/hw/timer/trace-events
> index 3495c41..8f4969b 100644
> --- a/hw/timer/trace-events
> +++ b/hw/timer/trace-events
> @@ -49,3 +49,34 @@ aspeed_timer_ctrl_pulse_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
> aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32
> aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32
> aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64
> +
> +# hw/timer/rx8900.c
> +rx8900_capture_current_time(int hour, int minute, int second, int weekday, int mday, int month, int year, int raw_hours, int raw_minutes, int raw_seconds, int raw_weekday, int raw_day, int raw_month, int raw_year) "Update current time to %02d:%02d:%02d %d %d/%d/%d (0x%02x%02x%02x%02x%02x%02x%02x)"
> +rx8900_regptr_update(uint32_t ptr) "Operating on register 0x%02x"
> +rx8900_regptr_overflow(void) "Register pointer has overflowed, wrapping to 0"
> +rx8900_event_weekday(int weekday, int weekmask, int weekday_offset) "Set weekday to %d (0x%02x), wday_offset=%d"
> +rx8900_read_register(int address, int val) "Read register 0x%x = 0x%x"
> +rx8900_set_fout(int hz) "Setting fout to %dHz"
> +rx8900_set_countdown_timer(int hz) "Setting countdown timer to %d Hz"
> +rx8900_set_countdown_timer_per_minute(void) "Setting countdown timer to per minute updates"
> +rx8900_enable_update_timer(void) ""
> +rx8900_enable_alarm(void) ""
> +rx8900_trigger_alarm(void) ""
> +rx8900_tick(void) ""
> +rx8900_fire_interrupt(void) ""
> +rx8900_disable_timer(void) ""
> +rx8900_enable_timer(void) ""
> +rx8900_disable_fout(void) ""
> +rx8900_enable_fout(void) ""
> +rx8900_fout_toggle(void) ""
> +rx8900_disable_countdown_timer(void) ""
> +rx8900_enable_countdown_timer(void) ""
> +rx8900_countdown_tick(int count) "Countdown tick, count=%d"
> +rx8900_countdown_elapsed(void) ""
> +rx8900_i2c_data_receive(uint8_t data) "Received I2C data 0x%02x"
> +rx8900_set_register(uint32_t addr, uint8_t data) "Set data 0x%02x=0x%02x"
> +rx8900_get_temperature(uint8_t raw, double val) "0x%x = %fC"
> +rx8900_set_temperature(uint8_t raw, double val) "0x%x = %fC"
> +rx8900_reset(void) ""
> +rx8900_pin_name(const char *type, const char *name) "'%s' pin is '%s'"
> +rx8900_set_voltage(double voltage) "Device voltage set to %f"
Is there a justification for all the empty traces?
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [Qemu-arm] [PATCH v4 6/8] hw/timer: Add Epson RX8900 RTC support
From: Andrew Jeffery @ 2017-01-04 4:59 UTC (permalink / raw)
To: Alastair D'Silva, qemu-arm
Cc: Peter Maydell, qemu-devel, Chris Smart, Joel Stanley,
Alastair D'Silva, Cédric Le Goater
In-Reply-To: <20161215054812.12602-7-alastair@au1.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 43213 bytes --]
Hi Alastair,
I have some mostly minor comments below.
On Thu, 2016-12-15 at 16:48 +1100, Alastair D'Silva wrote:
> > From: Alastair D'Silva <alastair@d-silva.org>
>
> This patch adds support for the Epson RX8900 I2C RTC.
>
> The following chip features are implemented:
> - RTC (wallclock based, ptimer 10x oversampling to pick up
> wallclock transitions)
> - Time update interrupt (per second/minute, wallclock based)
> - Alarms (wallclock based)
> - Temperature (set via a property)
> - Countdown timer (emulated clock via ptimer)
> - FOUT via GPIO (emulated clock via ptimer)
>
> The following chip features are unimplemented:
> - Low voltage detection
> - i2c timeout
>
> The implementation exports the following named GPIOs:
> rx8900-interrupt-out
> rx8900-fout-enable
> rx8900-fout
>
> > Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> > Signed-off-by: Chris Smart <chris@distroguy.com>
> ---
> default-configs/arm-softmmu.mak | 1 +
> hw/timer/Makefile.objs | 2 +
> hw/timer/rx8900.c | 912 ++++++++++++++++++++++++++++++++++++++++
> hw/timer/rx8900_regs.h | 141 +++++++
> hw/timer/trace-events | 31 ++
> 5 files changed, 1087 insertions(+)
> create mode 100644 hw/timer/rx8900.c
> create mode 100644 hw/timer/rx8900_regs.h
>
> 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..cb1a2c8
> --- /dev/null
> +++ b/hw/timer/rx8900.c
> @@ -0,0 +1,912 @@
> +/*
> + * Epson RX8900SA/CE Realtime Clock Module
> + *
> + * Copyright (c) 2016 IBM Corporation
> + * Authors:
> > + * Alastair D'Silva <alastair@d-silva.org>
> > + * Chris Smart <chris@distroguy.com>
> + *
> + * 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 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/log.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "trace.h"
> +
> +#define TYPE_RX8900 "rx8900"
> +#define RX8900(obj) OBJECT_CHECK(RX8900State, (obj), TYPE_RX8900)
> +
> +typedef struct RX8900State {
> + I2CSlave parent_obj;
> +
> + ptimer_state *sec_timer; /* triggered once per second */
> + ptimer_state *fout_timer;
> + ptimer_state *countdown_timer;
> + bool fout_state;
> + 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 nvram_offset; /* Wrapped to stay within RX8900_NVRAM_SIZE */
> + bool addr_byte;
> + uint8_t last_interrupt_seconds; /* The last time the second timer ticked */
> + /* the last minute the timer update interrupt was triggered (if enabled) */
> + uint8_t last_update_interrupt_minutes;
> + double supply_voltage;
> + qemu_irq interrupt_pin;
> + qemu_irq fout_pin;
> +} RX8900State;
> +
> +static const VMStateDescription vmstate_rx8900 = {
> + .name = "rx8900",
> + .version_id = 1,
> + .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_state, RX8900State),
> + VMSTATE_INT64(offset, RX8900State),
> + VMSTATE_UINT8(weekday, RX8900State),
> + VMSTATE_UINT8(wday_offset, RX8900State),
> + VMSTATE_UINT8_ARRAY(nvram, RX8900State, RX8900_NVRAM_SIZE),
> + VMSTATE_INT32(nvram_offset, RX8900State),
> + VMSTATE_BOOL(addr_byte, RX8900State),
> + VMSTATE_UINT8(last_interrupt_seconds, RX8900State),
> + VMSTATE_UINT8(last_update_interrupt_minutes, RX8900State),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void rx8900_reset(DeviceState *dev);
> +
> +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_rx8900_capture_current_time(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->nvram_offset = (s->nvram_offset + 1) & (RX8900_NVRAM_SIZE - 1);
> + trace_rx8900_regptr_update(s->nvram_offset);
> +
> + if (s->nvram_offset == START_ADDRESS) {
> + trace_rx8900_regptr_overflow();
> + capture_current_time(s);
> + }
> +}
> +
> +#define INVALID_WEEKDAY 0xff
> +
> +/**
> + * 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_rx8900_event_weekday(s->weekday, BIT(s->weekday),
> + s->wday_offset);
> +
> + s->weekday = INVALID_WEEKDAY;
> + }
> + 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->nvram_offset];
> + trace_rx8900_read_register(s->nvram_offset, res);
> + inc_regptr(s);
> + return res;
> +}
> +
> +/**
> + * Disable the countdown timer
> + * @param s the RTC to operate on
> + */
> +static void disable_countdown_timer(RX8900State *s)
> +{
> + trace_rx8900_disable_countdown_timer();
> + ptimer_stop(s->countdown_timer);
> +}
> +
> +/**
> + * Enable the countdown timer
> + * @param s the RTC to operate on
> + */
> +static void enable_countdown_timer(RX8900State *s)
> +{
> + trace_rx8900_enable_countdown_timer();
> + ptimer_run(s->countdown_timer, 0);
> +}
> +
> +/**
> + * 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_rx8900_countdown_tick(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_rx8900_countdown_elapsed();
> +
> + disable_countdown_timer(s);
> +
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_TF;
> +
> + if (s->nvram[CONTROL_REGISTER] & CTRL_MASK_TIE) {
> + trace_rx8900_fire_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_rx8900_disable_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_rx8900_enable_timer();
> + ptimer_run(s->sec_timer, 0);
> +}
> +
> +/**
> + * 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;
> + bool alarm_week_day_matches;
> +
> + qemu_get_timedate(&now, s->offset);
> +
> + if (now.tm_sec == s->last_interrupt_seconds) {
> + return;
> + }
> +
> + s->last_interrupt_seconds = now.tm_sec;
> +
> + trace_rx8900_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[EXTENSION_REGISTER] & EXT_MASK_WADA)) {
> + alarm_week_day_matches =
> + s->nvram[ALARM_WEEK_DAY] == to_bcd(now.tm_mday);
> + } else {
> + alarm_week_day_matches =
> + s->nvram[ALARM_WEEK_DAY] ==
> + 0x01 << ((now.tm_wday + s->wday_offset) % 7);
> + }
> +
> + if ((s->nvram[CONTROL_REGISTER] & CTRL_MASK_AIE) && now.tm_sec == 0 &&
> + s->nvram[ALARM_MINUTE] == to_bcd(now.tm_min) &&
> + s->nvram[ALARM_HOUR] == to_bcd(now.tm_hour) &&
> + alarm_week_day_matches) {
> + trace_rx8900_trigger_alarm();
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_AF;
> + fire_interrupt = true;
> + }
> +
> + if (fire_interrupt) {
> + trace_rx8900_fire_interrupt();
> + qemu_irq_pulse(s->interrupt_pin);
> + }
> +}
> +
> +
> +#define COUNTDOWN_TIMER_FREQ 4096
> +
> +/**
> + * 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) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Test bit is enabled but is forbidden by the manufacturer");
> + }
> +
> + if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> + (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> + /* FSELx has changed */
> +
> + switch (data & (EXT_MASK_FSEL0 | EXT_MASK_FSEL1)) {
> + case EXT_MASK_FSEL0:
> + trace_rx8900_set_fout(1024);
> + ptimer_set_limit(s->fout_timer, 32, 1);
> + break;
> + case EXT_MASK_FSEL1:
> + trace_rx8900_set_fout(1);
> + ptimer_set_limit(s->fout_timer, 32768, 1);
> + break;
> + case 0:
> + case (EXT_MASK_FSEL0 | EXT_MASK_FSEL1):
> + trace_rx8900_set_fout(32768);
> + ptimer_set_limit(s->fout_timer, 1, 1);
> + break;
> + }
> + }
> +
> + if ((data ^ s->nvram[EXTENSION_REGISTER]) &
> + (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> + /* TSELx has changed */
> + switch (data & (EXT_MASK_TSEL0 | EXT_MASK_TSEL1)) {
> + case 0:
> + trace_rx8900_set_countdown_timer(64);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ / 64, 1);
> + break;
> + case EXT_MASK_TSEL0:
> + trace_rx8900_set_countdown_timer(1);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ, 1);
> + break;
> + case EXT_MASK_TSEL1:
> + trace_rx8900_set_countdown_timer_per_minute();
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ * 60, 1);
> + break;
> + case (EXT_MASK_TSEL0 | EXT_MASK_TSEL1):
> + trace_rx8900_set_countdown_timer(COUNTDOWN_TIMER_FREQ);
> + 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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Attempt to write to write protected bit %d in control register",
> + CTRL_REG_WP0);
> + }
> +
> + if (diffmask & CTRL_MASK_WP1) {
> + data &= ~CTRL_MASK_WP1;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Attempt to write to write protected bit %d in control register",
> + CTRL_REG_WP1);
> + }
> +
> + 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_rx8900_enable_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_rx8900_enable_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);
> + }
> +
> + 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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "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;
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "Only 0 can be written to unused bit %d in the flag register",
> + FLAG_REG_UNUSED_7);
> + }
> +}
> +
> +/**
> + * 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_rx8900_enable_fout();
> + ptimer_run(s->fout_timer, 0);
> + } else {
> + /* disable fout */
> + trace_rx8900_disable_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_rx8900_fout_toggle();
> + s->fout_state = !s->fout_state;
> +
> + if (s->fout_state) {
> + qemu_irq_raise(s->fout_pin);
> + } else {
> + qemu_irq_lower(s->fout_pin);
> + }
We could just use qemu_set_irq() here.
> +}
> +
> +/**
> + * Verify the current voltage and raise flags if it is low
> + * @param s the RTC to operate on
> + */
> +static void check_voltage(RX8900State *s)
> +{
> + if (!(s->nvram[BACKUP_FUNCTION] & BACKUP_MASK_VDETOFF)) {
> + if (s->supply_voltage < 2.0) {
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_VDET;
> + }
> +
> + if (s->supply_voltage < 1.6) {
> + s->nvram[FLAG_REGISTER] |= FLAG_MASK_VLF;
> + }
> + }
> +}
> +
> +/**
> + * 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_rx8900_i2c_data_receive(data);
> +
> + if (s->addr_byte) {
> + s->nvram_offset = data & (RX8900_NVRAM_SIZE - 1);
> + trace_rx8900_regptr_update(s->nvram_offset);
> + s->addr_byte = false;
> + return 0;
> + }
> +
> + trace_rx8900_set_register(s->nvram_offset, data);
> +
> + qemu_get_timedate(&now, s->offset);
> + switch (s->nvram_offset) {
> + case SECONDS:
> + case EXT_SECONDS:
> + now.tm_sec = from_bcd(data & 0x7f);
> + if (now.tm_sec > 59) { /* RX8900 does not support leap seconds */
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - second data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + s->offset = qemu_timedate_diff(&now);
> + break;
> +
> + case MINUTES:
> + case EXT_MINUTES:
> + now.tm_min = from_bcd(data & 0x7f);
> + if (now.tm_min > 59) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - minute data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + s->offset = qemu_timedate_diff(&now);
> + break;
> +
> + case HOURS:
> + case EXT_HOURS:
> + now.tm_hour = from_bcd(data & 0x3f);
> + if (now.tm_hour > 24) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - hour data '%x' is out of range, "
> + "undefined behavior will result", data);
> + }
> + 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
> + * with only 1 of bits 0-6 set. Otherwise behavior is undefined.
> + */
> + switch (data) {
> + case 0x01:
> + case 0x02:
> + case 0x04:
> + case 0x08:
> + case 0x10:
> + case 0x20:
> + case 0x40:
> + break;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "RX8900 - weekday data '%x' is out of range, "
> + "undefined behavior will result", data);
> + break;
> + }
I think it might be clearer to do:
if (data == 0x80 || ctpop8(data) != 1) {
qemu_log_mask(...);
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;
> +
> + check_voltage(s);
> + break;
> +
> + case CONTROL_REGISTER:
> + case EXT_CONTROL_REGISTER:
> + update_control_register(s, data);
> + break;
> +
> + default:
> + s->nvram[s->nvram_offset] = data;
> + }
> +
> + inc_regptr(s);
> + return 0;
> +}
> +
> +/**
> + * Get the device temperature in Celsius 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.0 - 187.1) / 3.218;
You have encode_temperature() below, should we not have
decode_temperature()?
> +
> + trace_rx8900_get_temperature(s->nvram[TEMPERATURE], value);
> +
> + visit_type_number(v, name, &value, errp);
> +}
> +
> +/**
> + * Encode a temperature in Celsius
> + * @param celsius the temperature
> + * @return the encoded temperature
> + */
> +static inline uint8_t encode_temperature(double celsius)
> +{
> + return (uint8_t) ((celsius * 3.218 + 187.19) / 2);
> +}
> +
> +/**
> + * Set the device temperature in Celsius 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 Celsius */
> + 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 %fC is out of range", temp);
> + return;
> + }
> +
> + s->nvram[TEMPERATURE] = encode_temperature(temp);
> +
> + trace_rx8900_set_temperature(s->nvram[TEMPERATURE], temp);
> +}
> +
> +/**
> + * Get the device supply voltage 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_voltage(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + RX8900State *s = RX8900(obj);
> +
> + visit_type_number(v, name, &s->supply_voltage, errp);
> +}
> +
> +/**
> + * Set the device supply voltage 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_voltage(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + RX8900State *s = RX8900(obj);
> + Error *local_err = NULL;
> + double temp;
Maybe voltage? It's ambiguous as to whether it's a copy/paste error
from 'temperature' or if you mean 'temporary'...
> + visit_type_number(v, name, &temp, &local_err);
> + if (local_err) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> + s->supply_voltage = temp;
... as this almost looks like a bug.
> + trace_rx8900_set_voltage(s->supply_voltage);
> +
> + check_voltage(s);
> +}
> +
> +
> +/**
> + * 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);
> +
> + object_property_add(obj, "voltage", "number",
> + rx8900_get_voltage,
> + rx8900_set_voltage, NULL, NULL, NULL);
> +}
> +
> +/**
> + * Reset the device
> + * @param dev the RX8900 device to reset
> + */
> +static void rx8900_reset(DeviceState *dev)
Is there a reason we can't define rx8900_reset() further up the file to
avoid forward-declaring it?
> +{
> + RX8900State *s = RX8900(dev);
> +
> + trace_rx8900_reset();
> +
> + /* The clock is running and synchronized with the host */
> + s->offset = 0;
> + s->weekday = 7; /* Set to an invalid value */
Can you explain why we do that rather than just stating that 7 is
invalid?
> +
> + s->nvram[EXTENSION_REGISTER] = EXT_MASK_TSEL1;
> + s->nvram[CONTROL_REGISTER] = CTRL_MASK_CSEL0;
> + s->nvram[FLAG_REGISTER] &= FLAG_MASK_VDET | FLAG_MASK_VLF;
> +
> + s->nvram_offset = 0;
> +
> + trace_rx8900_regptr_update(s->nvram_offset);
> +
> + s->addr_byte = false;
> +}
> +
> +/**
> + * Realize an RX8900 device instance
> + * Set up timers
> + * Configure GPIO lines
> + * @param dev the device instance to realize
> + * @param errp an error object to populate on error
> + */
> +static void rx8900_realize(DeviceState *dev, Error **errp)
> +{
> + RX8900State *s = RX8900(dev);
> + I2CSlave *i2c = I2C_SLAVE(dev);
> + QEMUBH *bh;
> + char name[64];
> +
> + s->fout_state = false;
> +
> + memset(s->nvram, 0, RX8900_NVRAM_SIZE);
> + /* Set the initial state to 25 degrees Celsius */
> + s->nvram[TEMPERATURE] = encode_temperature(25.0);
> +
> + /* Set up timers */
> + bh = qemu_bh_new(rx8900_timer_tick, s);
> + s->sec_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + /* we trigger the timer at 10Hz and check for rollover, as the qemu
> + * clock does not advance in realtime in the test environment,
> + * leading to unstable test results
> + */
It seems unfortunate that some of the code seems dedicated to working
around test suite issues (e.g. early return in some functions). Ah
well.
> + ptimer_set_freq(s->sec_timer, 10);
> + ptimer_set_limit(s->sec_timer, 1, 1);
> +
> + bh = qemu_bh_new(rx8900_fout_tick, s);
> + s->fout_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + /* frequency doubled to generate 50% duty cycle square wave */
> + ptimer_set_freq(s->fout_timer, 32768 * 2);
> + ptimer_set_limit(s->fout_timer, 1, 1);
> +
> + bh = qemu_bh_new(rx8900_countdown_tick, s);
> + s->countdown_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
> + ptimer_set_freq(s->countdown_timer, COUNTDOWN_TIMER_FREQ);
> + ptimer_set_limit(s->countdown_timer, COUNTDOWN_TIMER_FREQ, 1);
> +
> +
> + /* set up GPIO */
> + snprintf(name, sizeof(name), "rx8900-interrupt-out");
Why the snprintf()s?
> + qdev_init_gpio_out_named(&i2c->qdev, &s->interrupt_pin, name, 1);
> + trace_rx8900_pin_name("Interrupt", name);
> +
> + snprintf(name, sizeof(name), "rx8900-fout-enable");
> + qdev_init_gpio_in_named(&i2c->qdev, rx8900_fout_enable_handler, name, 1);
> + trace_rx8900_pin_name("Fout-enable", name);
> +
> + snprintf(name, sizeof(name), "rx8900-fout");
> + qdev_init_gpio_out_named(&i2c->qdev, &s->fout_pin, name, 1);
> + trace_rx8900_pin_name("Fout", name);
> +
> + /* Set up default voltage */
> + s->supply_voltage = 3.3f;
> + trace_rx8900_set_voltage(s->supply_voltage);
> +}
> +
> +/**
> + * Set up the device callbacks
> + * @param klass the device class
> + * @param data
> + */
> +static void rx8900_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +
> + k->event = rx8900_event;
> + k->recv = rx8900_recv;
> + k->send = rx8900_send;
> + dc->realize = rx8900_realize;
> + dc->reset = rx8900_reset;
> + dc->vmsd = &vmstate_rx8900;
> +}
> +
> +static const TypeInfo rx8900_info = {
> + .name = TYPE_RX8900,
> + .parent = TYPE_I2C_SLAVE,
> + .instance_size = sizeof(RX8900State),
> + .instance_init = rx8900_initfn,
> + .class_init = rx8900_class_init,
> +};
> +
> +/**
> + * Register the device with QEMU
> + */
> +static void rx8900_register_types(void)
> +{
> + type_register_static(&rx8900_info);
> +}
> +
> +type_init(rx8900_register_types)
> diff --git a/hw/timer/rx8900_regs.h b/hw/timer/rx8900_regs.h
> new file mode 100644
> index 0000000..0aaa9a3
> --- /dev/null
> +++ b/hw/timer/rx8900_regs.h
> @@ -0,0 +1,141 @@
> +/*
> + * 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
> + *
> + */
> +
> +#ifndef RX8900_REGS_H
> +#define RX8900_REGS_H
> +
> +#include "qemu/bitops.h"
> +
> +#define RX8900_NVRAM_SIZE 0x20
Do all the enums below need to be defined in the header or are they
only relevant to the implementation? If it's the latter, then they
should go in the .c file.
Also I would've reached for #define for all these values, not enums,
but that might be a personal thing.
> +
> +typedef enum RX8900Addresses {
> + START_ADDRESS = 0x00,
> + SECONDS = 0x00,
> + MINUTES = 0x01,
> + HOURS = 0x02,
> + WEEKDAY = 0x03, /* a walking bit with bit 0 set for Sunday, 1 for Monday...
> + 6 for Saturday, see the datasheet for details */
> + DAY = 0x04,
> + MONTH = 0x05,
> + YEAR = 0x06,
> + RAM = 0x07,
> + ALARM_MINUTE = 0x08,
> + ALARM_HOUR = 0x09,
> + ALARM_WEEK_DAY = 0x0A,
> + TIMER_COUNTER_0 = 0x0B,
> + TIMER_COUNTER_1 = 0x0C,
> + EXTENSION_REGISTER = 0x0D,
> + FLAG_REGISTER = 0X0E,
> + CONTROL_REGISTER = 0X0F,
> + EXT_SECONDS = 0x010, /* Alias of SECONDS */
> + EXT_MINUTES = 0x11, /* Alias of MINUTES */
> + EXT_HOURS = 0x12, /* Alias of HOURS */
> + EXT_WEEKDAY = 0x13, /* Alias of WEEKDAY */
> + EXT_DAY = 0x14, /* Alias of DAY */
> + EXT_MONTH = 0x15, /* Alias of MONTH */
> + EXT_YEAR = 0x16, /* Alias of YEAR */
> + TEMPERATURE = 0x17,
> + BACKUP_FUNCTION = 0x18,
> + NO_USE_1 = 0x19,
> + NO_USE_2 = 0x1A,
> + EXT_TIMER_COUNTER_0 = 0x1B, /* Alias of TIMER_COUNTER_0 */
> + EXT_TIMER_COUNTER_1 = 0x1C, /* Alias of TIMER_COUNTER_1 */
> + EXT_EXTENSION_REGISTER = 0x1D, /* Alias of EXTENSION_REGISTER */
> + EXT_FLAG_REGISTER = 0X1E, /* Alias of FLAG_REGISTER */
> + EXT_CONTROL_REGISTER = 0X1F /* Alias of CONTROL_REGISTER */
> +} RX8900Addresses;
> +
> +typedef enum ExtRegBits {
> + EXT_REG_TSEL0 = 0,
> + EXT_REG_TSEL1 = 1,
> + EXT_REG_FSEL0 = 2,
> + EXT_REG_FSEL1 = 3,
> + EXT_REG_TE = 4,
> + EXT_REG_USEL = 5,
> + EXT_REG_WADA = 6,
> + EXT_REG_TEST = 7
> +} ExtRegBits;
> +
> +typedef enum ExtRegMasks {
> + EXT_MASK_TSEL0 = BIT(0),
> + EXT_MASK_TSEL1 = BIT(1),
> + EXT_MASK_FSEL0 = BIT(2),
> + EXT_MASK_FSEL1 = BIT(3),
> + EXT_MASK_TE = BIT(4),
> + EXT_MASK_USEL = BIT(5),
> + EXT_MASK_WADA = BIT(6),
> + EXT_MASK_TEST = BIT(7)
> +} ExtRegMasks;
> +
> +typedef enum CtrlRegBits {
> + CTRL_REG_RESET = 0,
> + CTRL_REG_WP0 = 1,
> + CTRL_REG_WP1 = 2,
> + CTRL_REG_AIE = 3,
> + CTRL_REG_TIE = 4,
> + CTRL_REG_UIE = 5,
> + CTRL_REG_CSEL0 = 6,
> + CTRL_REG_CSEL1 = 7
> +} CtrlRegBits;
> +
> +typedef enum CtrlRegMask {
> + CTRL_MASK_RESET = BIT(0),
> + CTRL_MASK_WP0 = BIT(1),
> + CTRL_MASK_WP1 = BIT(2),
> + CTRL_MASK_AIE = BIT(3),
> + CTRL_MASK_TIE = BIT(4),
> + CTRL_MASK_UIE = BIT(5),
> + CTRL_MASK_CSEL0 = BIT(6),
> + CTRL_MASK_CSEL1 = BIT(7)
> +} CtrlRegMask;
> +
> +typedef enum FlagRegBits {
> + FLAG_REG_VDET = 0,
> + FLAG_REG_VLF = 1,
> + FLAG_REG_UNUSED_2 = 2,
> + FLAG_REG_AF = 3,
> + FLAG_REG_TF = 4,
> + FLAG_REG_UF = 5,
> + FLAG_REG_UNUSED_6 = 6,
> + FLAG_REG_UNUSED_7 = 7
> +} FlagRegBits;
> +
> +#define RX8900_INTERRUPT_SOURCES 6
> +typedef enum FlagRegMask {
> + FLAG_MASK_VDET = BIT(0),
> + FLAG_MASK_VLF = BIT(1),
> + FLAG_MASK_UNUSED_2 = BIT(2),
> + FLAG_MASK_AF = BIT(3),
> + FLAG_MASK_TF = BIT(4),
> + FLAG_MASK_UF = BIT(5),
> + FLAG_MASK_UNUSED_6 = BIT(6),
> + FLAG_MASK_UNUSED_7 = BIT(7)
> +} FlagRegMask;
> +
> +typedef enum BackupRegBits {
> + BACKUP_REG_BKSMP0 = 0,
> + BACKUP_REG_BKSMP1 = 1,
> + BACKUP_REG_SWOFF = 2,
> + BACKUP_REG_VDETOFF = 3
> +} BackupRegBits;
> +
> +typedef enum BackupRegMask {
> + BACKUP_MASK_BKSMP0 = BIT(0),
> + BACKUP_MASK_BKSMP1 = BIT(1),
> + BACKUP_MASK_SWOFF = BIT(2),
> + BACKUP_MASK_VDETOFF = BIT(3)
> +} BackupRegMask;
> +
> +#endif
> diff --git a/hw/timer/trace-events b/hw/timer/trace-events
> index 3495c41..8f4969b 100644
> --- a/hw/timer/trace-events
> +++ b/hw/timer/trace-events
> @@ -49,3 +49,34 @@ aspeed_timer_ctrl_pulse_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
> aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32
> aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32
> aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64
> +
> +# hw/timer/rx8900.c
> +rx8900_capture_current_time(int hour, int minute, int second, int weekday, int mday, int month, int year, int raw_hours, int raw_minutes, int raw_seconds, int raw_weekday, int raw_day, int raw_month, int raw_year) "Update current time to %02d:%02d:%02d %d %d/%d/%d (0x%02x%02x%02x%02x%02x%02x%02x)"
> +rx8900_regptr_update(uint32_t ptr) "Operating on register 0x%02x"
> +rx8900_regptr_overflow(void) "Register pointer has overflowed, wrapping to 0"
> +rx8900_event_weekday(int weekday, int weekmask, int weekday_offset) "Set weekday to %d (0x%02x), wday_offset=%d"
> +rx8900_read_register(int address, int val) "Read register 0x%x = 0x%x"
> +rx8900_set_fout(int hz) "Setting fout to %dHz"
> +rx8900_set_countdown_timer(int hz) "Setting countdown timer to %d Hz"
> +rx8900_set_countdown_timer_per_minute(void) "Setting countdown timer to per minute updates"
> +rx8900_enable_update_timer(void) ""
> +rx8900_enable_alarm(void) ""
> +rx8900_trigger_alarm(void) ""
> +rx8900_tick(void) ""
> +rx8900_fire_interrupt(void) ""
> +rx8900_disable_timer(void) ""
> +rx8900_enable_timer(void) ""
> +rx8900_disable_fout(void) ""
> +rx8900_enable_fout(void) ""
> +rx8900_fout_toggle(void) ""
> +rx8900_disable_countdown_timer(void) ""
> +rx8900_enable_countdown_timer(void) ""
> +rx8900_countdown_tick(int count) "Countdown tick, count=%d"
> +rx8900_countdown_elapsed(void) ""
> +rx8900_i2c_data_receive(uint8_t data) "Received I2C data 0x%02x"
> +rx8900_set_register(uint32_t addr, uint8_t data) "Set data 0x%02x=0x%02x"
> +rx8900_get_temperature(uint8_t raw, double val) "0x%x = %fC"
> +rx8900_set_temperature(uint8_t raw, double val) "0x%x = %fC"
> +rx8900_reset(void) ""
> +rx8900_pin_name(const char *type, const char *name) "'%s' pin is '%s'"
> +rx8900_set_voltage(double voltage) "Device voltage set to %f"
Is there a justification for all the empty traces?
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH v4 3/3] ARM: dts: imx6: Support Savageboard quad
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer
Cc: Fabio Estevam, linux-arm-kernel, devicetree, linux-kernel,
Milo Kim
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
Use common board file and support SATA interface additionally.
Specify the dtb file for i.MX6 build.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6q-savageboard.dts | 55 +++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6q-savageboard.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index fb7f904a5235..2f21e59adc1e 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -403,6 +403,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-sabreauto.dtb \
imx6q-sabrelite.dtb \
imx6q-sabresd.dtb \
+ imx6q-savageboard.dtb \
imx6q-sbc6x.dtb \
imx6q-tbs2910.dtb \
imx6q-ts4900.dtb \
diff --git a/arch/arm/boot/dts/imx6q-savageboard.dts b/arch/arm/boot/dts/imx6q-savageboard.dts
new file mode 100644
index 000000000000..717ac62fc2cf
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-savageboard.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-savageboard.dtsi"
+
+/ {
+ model = "Poslab SavageBoard Quad";
+ compatible = "poslab,imx6q-savageboard", "fsl,imx6q";
+};
+
+&sata {
+ status = "okay";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 3/3] ARM: dts: imx6: Support Savageboard quad
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer
Cc: Fabio Estevam, devicetree, Milo Kim, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
Use common board file and support SATA interface additionally.
Specify the dtb file for i.MX6 build.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6q-savageboard.dts | 55 +++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6q-savageboard.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index fb7f904a5235..2f21e59adc1e 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -403,6 +403,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-sabreauto.dtb \
imx6q-sabrelite.dtb \
imx6q-sabresd.dtb \
+ imx6q-savageboard.dtb \
imx6q-sbc6x.dtb \
imx6q-tbs2910.dtb \
imx6q-ts4900.dtb \
diff --git a/arch/arm/boot/dts/imx6q-savageboard.dts b/arch/arm/boot/dts/imx6q-savageboard.dts
new file mode 100644
index 000000000000..717ac62fc2cf
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-savageboard.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-savageboard.dtsi"
+
+/ {
+ model = "Poslab SavageBoard Quad";
+ compatible = "poslab,imx6q-savageboard", "fsl,imx6q";
+};
+
+&sata {
+ status = "okay";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 3/3] ARM: dts: imx6: Support Savageboard quad
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
Use common board file and support SATA interface additionally.
Specify the dtb file for i.MX6 build.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6q-savageboard.dts | 55 +++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6q-savageboard.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index fb7f904a5235..2f21e59adc1e 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -403,6 +403,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-sabreauto.dtb \
imx6q-sabrelite.dtb \
imx6q-sabresd.dtb \
+ imx6q-savageboard.dtb \
imx6q-sbc6x.dtb \
imx6q-tbs2910.dtb \
imx6q-ts4900.dtb \
diff --git a/arch/arm/boot/dts/imx6q-savageboard.dts b/arch/arm/boot/dts/imx6q-savageboard.dts
new file mode 100644
index 000000000000..717ac62fc2cf
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-savageboard.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-savageboard.dtsi"
+
+/ {
+ model = "Poslab SavageBoard Quad";
+ compatible = "poslab,imx6q-savageboard", "fsl,imx6q";
+};
+
+&sata {
+ status = "okay";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 2/3] ARM: dts: imx6: Support Savageboard dual
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer
Cc: Fabio Estevam, devicetree, Milo Kim, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
Common savageboard DT file is used for board support.
Add the vendor name and specify the dtb file for i.MX6Q build.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6dl-savageboard.dts | 51 ++++++++++++++++++++++
3 files changed, 53 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6dl-savageboard.dts
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 16d3b5e7f5d1..88c33d827e51 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -227,6 +227,7 @@ pine64 Pine64
pixcir PIXCIR MICROELECTRONICS Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
+poslab Poslab Technology Co., Ltd.
powervr PowerVR (deprecated, use img)
pulsedlight PulsedLight, Inc
qca Qualcomm Atheros, Inc.
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index cccdbcb557b6..fb7f904a5235 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -357,6 +357,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-sabreauto.dtb \
imx6dl-sabrelite.dtb \
imx6dl-sabresd.dtb \
+ imx6dl-savageboard.dtb \
imx6dl-ts4900.dtb \
imx6dl-tx6dl-comtft.dtb \
imx6dl-tx6s-8034.dtb \
diff --git a/arch/arm/boot/dts/imx6dl-savageboard.dts b/arch/arm/boot/dts/imx6dl-savageboard.dts
new file mode 100644
index 000000000000..b95469c520a4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-savageboard.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-savageboard.dtsi"
+
+/ {
+ model = "Poslab SavageBoard Dual";
+ compatible = "poslab,imx6dl-savageboard", "fsl,imx6dl";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 2/3] ARM: dts: imx6: Support Savageboard dual
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
Common savageboard DT file is used for board support.
Add the vendor name and specify the dtb file for i.MX6Q build.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/imx6dl-savageboard.dts | 51 ++++++++++++++++++++++
3 files changed, 53 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6dl-savageboard.dts
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 16d3b5e7f5d1..88c33d827e51 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -227,6 +227,7 @@ pine64 Pine64
pixcir PIXCIR MICROELECTRONICS Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
+poslab Poslab Technology Co., Ltd.
powervr PowerVR (deprecated, use img)
pulsedlight PulsedLight, Inc
qca Qualcomm Atheros, Inc.
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index cccdbcb557b6..fb7f904a5235 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -357,6 +357,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-sabreauto.dtb \
imx6dl-sabrelite.dtb \
imx6dl-sabresd.dtb \
+ imx6dl-savageboard.dtb \
imx6dl-ts4900.dtb \
imx6dl-tx6dl-comtft.dtb \
imx6dl-tx6s-8034.dtb \
diff --git a/arch/arm/boot/dts/imx6dl-savageboard.dts b/arch/arm/boot/dts/imx6dl-savageboard.dts
new file mode 100644
index 000000000000..b95469c520a4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-savageboard.dts
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-savageboard.dtsi"
+
+/ {
+ model = "Poslab SavageBoard Dual";
+ compatible = "poslab,imx6dl-savageboard", "fsl,imx6dl";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 1/3] ARM: dts: imx6: Add Savageboard common file
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer
Cc: Fabio Estevam, devicetree, Milo Kim, linux-kernel,
linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
* Memory
memblock for DDR3 1GB
* Regulator
3.3V for panel and backlight.
* Display
Enable HDMI and LVDS panel. Savageboard supports AVIC TM097TDH02 panel
which is compatible with Hannstar HSD100PXN1, so reuse it.
* Clock
The commit d28be499c45e6 ("ARM: dts: imx6qdl-sabresd: Allow HDMI and
LVDS to work simultaneously") is applied to support LVDS and HDMI output
at the same time.
* Pinmux
Support eMMC, ethernet, gpio key for power button, I2C, PWM, SD card
and UART.
* Others
Enable ethernet, UART1 debug, USB host, USDHC3 for microSD card and
USDHC4 for built-in eMMC storage.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/imx6qdl-savageboard.dtsi | 255 +++++++++++++++++++++++++++++
1 file changed, 255 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6qdl-savageboard.dtsi
diff --git a/arch/arm/boot/dts/imx6qdl-savageboard.dtsi b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
new file mode 100644
index 000000000000..a616e3c400d3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory@10000000 {
+ device_type = "memory";
+ reg = <0x10000000 0x40000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ power {
+ gpios = <&gpio3 7 GPIO_ACTIVE_LOW>;
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ wakeup-source;
+ };
+ };
+
+ panel {
+ compatible = "avic,tm097tdh02", "hannstar,hsd100pxn1";
+ backlight = <&panel_bl>;
+ power-supply = <®_3p3v>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+
+ panel_bl: backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <4>;
+ power-supply = <®_3p3v>;
+ pwms = <&pwm1 0 10000>;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+};
+
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
+&fec {
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ reg = <0>;
+ status = "okay";
+
+ port@4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+/* SD card */
+&usdhc3 {
+ bus-width = <4>;
+ cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+ no-1-8-v;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sd>;
+ status = "okay";
+};
+
+/* eMMC */
+&usdhc4 {
+ bus-width = <8>;
+ keep-power-in-suspend;
+ no-1-8-v;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_emmc>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_emmc: emmcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
+ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
+ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
+ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
+ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
+ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
+ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
+ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
+ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
+ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ /* PHY reset */
+ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpio_keys: gpiokeysgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b0b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_sd: sdgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ /* CD pin */
+ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 1/3] ARM: dts: imx6: Add Savageboard common file
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170104045553.26576-1-woogyom.kim@gmail.com>
* Memory
memblock for DDR3 1GB
* Regulator
3.3V for panel and backlight.
* Display
Enable HDMI and LVDS panel. Savageboard supports AVIC TM097TDH02 panel
which is compatible with Hannstar HSD100PXN1, so reuse it.
* Clock
The commit d28be499c45e6 ("ARM: dts: imx6qdl-sabresd: Allow HDMI and
LVDS to work simultaneously") is applied to support LVDS and HDMI output
at the same time.
* Pinmux
Support eMMC, ethernet, gpio key for power button, I2C, PWM, SD card
and UART.
* Others
Enable ethernet, UART1 debug, USB host, USDHC3 for microSD card and
USDHC4 for built-in eMMC storage.
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
Signed-off-by: Milo Kim <woogyom.kim@gmail.com>
---
arch/arm/boot/dts/imx6qdl-savageboard.dtsi | 255 +++++++++++++++++++++++++++++
1 file changed, 255 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6qdl-savageboard.dtsi
diff --git a/arch/arm/boot/dts/imx6qdl-savageboard.dtsi b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
new file mode 100644
index 000000000000..a616e3c400d3
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-savageboard.dtsi
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2017 Milo Kim <woogyom.kim@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory at 10000000 {
+ device_type = "memory";
+ reg = <0x10000000 0x40000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ power {
+ gpios = <&gpio3 7 GPIO_ACTIVE_LOW>;
+ label = "Power Button";
+ linux,code = <KEY_POWER>;
+ wakeup-source;
+ };
+ };
+
+ panel {
+ compatible = "avic,tm097tdh02", "hannstar,hsd100pxn1";
+ backlight = <&panel_bl>;
+ power-supply = <®_3p3v>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+
+ panel_bl: backlight {
+ compatible = "pwm-backlight";
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <4>;
+ power-supply = <®_3p3v>;
+ pwms = <&pwm1 0 10000>;
+ };
+
+ reg_3p3v: regulator-3p3v {
+ compatible = "regulator-fixed";
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+};
+
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
+&fec {
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel at 0 {
+ reg = <0>;
+ status = "okay";
+
+ port at 4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+ };
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+/* SD card */
+&usdhc3 {
+ bus-width = <4>;
+ cd-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
+ no-1-8-v;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sd>;
+ status = "okay";
+};
+
+/* eMMC */
+&usdhc4 {
+ bus-width = <8>;
+ keep-power-in-suspend;
+ no-1-8-v;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_emmc>;
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_emmc: emmcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
+ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
+ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
+ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
+ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
+ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
+ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
+ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
+ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
+ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030
+ /* PHY reset */
+ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpio_keys: gpiokeysgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b0b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_sd: sdgrp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ /* CD pin */
+ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v4 0/3] ARM: dts: imx6: Support Poslab Savageboard dual & quad
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: Shawn Guo, Sascha Hauer
Cc: Fabio Estevam, devicetree, Milo Kim, linux-kernel,
linux-arm-kernel
Poslab Savageboard is the i.MX6 SoC base, but BSP code from the vendor is
not mainline u-boot and kernel. Personal reason of using this board is
testing etnaviv user-space driver, so I re-write device tree files based on
mainline kernel for the first step.
This patchset includes common DT file, dual and quad board files.
Supported components are
- Display: HDMI and LVDS panel
- eMMC and SD card
- Ethernet
- Pinmux configuration
- SATA: only for Savageboard quad
- UART1 for debug console
- USB host
Missing features are
- Audio (WM8903)
- USB OTG
- PMIC WM8326: default settings are used so no issue to bring-up the system
- MIPI DSI and CSI
Patches are tested on the Savageboard quad but the dual version should work
because the only difference between dual and quad is SATA support.
More information in http://www.savageboard.org
v4:
Fix the license text and add the vendor prefix.
Use generic node name for the backlight panel.
Sort alphabetically for the pinctrl nodes.
Remove unnecessary pinmux of HDMI CEC.
v3:
Specify the dtbs for i.MX6 build.
v2:
Fix DT node for regulator, phy-reset-gpios and iomuxc node.
Milo Kim (3):
ARM: dts: imx6: Add Savageboard common file
ARM: dts: imx6: Support Savageboard dual
ARM: dts: imx6: Support Savageboard quad
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6dl-savageboard.dts | 51 +++++
arch/arm/boot/dts/imx6q-savageboard.dts | 55 +++++
arch/arm/boot/dts/imx6qdl-savageboard.dtsi | 255 +++++++++++++++++++++
5 files changed, 364 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6dl-savageboard.dts
create mode 100644 arch/arm/boot/dts/imx6q-savageboard.dts
create mode 100644 arch/arm/boot/dts/imx6qdl-savageboard.dtsi
--
2.11.0
^ permalink raw reply
* [PATCH v4 0/3] ARM: dts: imx6: Support Poslab Savageboard dual & quad
From: Milo Kim @ 2017-01-04 4:55 UTC (permalink / raw)
To: linux-arm-kernel
Poslab Savageboard is the i.MX6 SoC base, but BSP code from the vendor is
not mainline u-boot and kernel. Personal reason of using this board is
testing etnaviv user-space driver, so I re-write device tree files based on
mainline kernel for the first step.
This patchset includes common DT file, dual and quad board files.
Supported components are
- Display: HDMI and LVDS panel
- eMMC and SD card
- Ethernet
- Pinmux configuration
- SATA: only for Savageboard quad
- UART1 for debug console
- USB host
Missing features are
- Audio (WM8903)
- USB OTG
- PMIC WM8326: default settings are used so no issue to bring-up the system
- MIPI DSI and CSI
Patches are tested on the Savageboard quad but the dual version should work
because the only difference between dual and quad is SATA support.
More information in http://www.savageboard.org
v4:
Fix the license text and add the vendor prefix.
Use generic node name for the backlight panel.
Sort alphabetically for the pinctrl nodes.
Remove unnecessary pinmux of HDMI CEC.
v3:
Specify the dtbs for i.MX6 build.
v2:
Fix DT node for regulator, phy-reset-gpios and iomuxc node.
Milo Kim (3):
ARM: dts: imx6: Add Savageboard common file
ARM: dts: imx6: Support Savageboard dual
ARM: dts: imx6: Support Savageboard quad
.../devicetree/bindings/vendor-prefixes.txt | 1 +
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6dl-savageboard.dts | 51 +++++
arch/arm/boot/dts/imx6q-savageboard.dts | 55 +++++
arch/arm/boot/dts/imx6qdl-savageboard.dtsi | 255 +++++++++++++++++++++
5 files changed, 364 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6dl-savageboard.dts
create mode 100644 arch/arm/boot/dts/imx6q-savageboard.dts
create mode 100644 arch/arm/boot/dts/imx6qdl-savageboard.dtsi
--
2.11.0
^ permalink raw reply
* [PATCH] fix value of label statement
From: Luc Van Oostenryck @ 2017-01-04 4:45 UTC (permalink / raw)
To: linux-sparse; +Cc: Luc Van Oostenryck
Normaly a label statement is not also an expression but it could be
in GCC's statement expression like : ({ ...; label: <expression>; })
Currently, during linearization sparse discards the return value
of the linearization of the label's sub-statement, thus also
discarding the value of such statement-expressions.
Trivialy fix this by not discarding the return value but returning
it instead, like other statements that also are an expression and
thus have a value.
Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
linearize.c | 3 +--
validation/label-expr.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
create mode 100644 validation/label-expr.c
This patch can also be found as 'sent/fix-label-statement-value' on
git://github.com/lucvoo/sparse.git
diff --git a/linearize.c b/linearize.c
index 725eafe7..8bd78777 100644
--- a/linearize.c
+++ b/linearize.c
@@ -2029,8 +2029,7 @@ pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt)
if (label->used) {
add_label(ep, label);
}
- linearize_statement(ep, stmt->label_statement);
- break;
+ return linearize_statement(ep, stmt->label_statement);
}
case STMT_GOTO: {
diff --git a/validation/label-expr.c b/validation/label-expr.c
new file mode 100644
index 00000000..e578ed00
--- /dev/null
+++ b/validation/label-expr.c
@@ -0,0 +1,17 @@
+int foo(void);
+int foo(void)
+{
+ int r;
+
+ r = ({ label: 1; });
+ return r;
+}
+
+/*
+ * check-name: label-expr
+ * check-command: test-linearize $file
+ * check-output-ignore
+ *
+ * check-output-excludes: ret\\.32\$
+ * check-output-contains: ret\\.32 *\\$1
+ */
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 0/4] Convert thermal subsystem to the IDA allocator
From: Zhang Rui @ 2017-01-04 4:49 UTC (permalink / raw)
To: Matthew Wilcox; +Cc: Matthew Wilcox, linux-pm
In-Reply-To: <1482342426-30520-1-git-send-email-mawilcox@linuxonhyperv.com>
Hi, Matthew,
On Wed, 2016-12-21 at 09:47 -0800, Matthew Wilcox wrote:
> From: Matthew Wilcox <mawilcox@microsoft.com>
>
> None of the ID allocations are in a hot path, so I think it's better
> to use the ida_simple_get/ida_simple_remove API instead of having
> individual mutexes.
>
I agree. Thanks for the patches.
Applied and queued for 4.11.
thanks,
rui
> I've only compile-tested these changes ... even that is quite tricky
> given
> the maze of Kconfig options which make it hard to select those
> drivers.
> I eventually gave up and played games with the header files to get
> the
> compiler to compile them cleanly.
>
> Matthew Wilcox (4):
> thermal core: convert ID allocation to IDA
> thermal: convert clock cooling to use an IDA
> thermal: convert cpu_cooling to use an IDA
> thermal: convert devfreq_cooling to use an IDA
>
> drivers/thermal/clock_cooling.c | 50 +++++---------------------
> drivers/thermal/cpu_cooling.c | 63 ++++++-----------------------
> ---
> drivers/thermal/devfreq_cooling.c | 53 +++++----------------------
> drivers/thermal/thermal_core.c | 75 ++++++++++++++---------------
> ----------
> include/linux/thermal.h | 4 +--
> 5 files changed, 56 insertions(+), 189 deletions(-)
>
^ permalink raw reply
* Re: [PATCH] thermal: add thermal_zone_remove_device_groups()
From: Zhang Rui @ 2017-01-04 4:45 UTC (permalink / raw)
To: Yasuaki Ishimatsu, linux-kernel, linux-pm; +Cc: edubezval
In-Reply-To: <1483504508.2320.41.camel@intel.com>
On Wed, 2017-01-04 at 12:35 +0800, Zhang Rui wrote:
> On Thu, 2016-12-15 at 16:47 -0500, Yasuaki Ishimatsu wrote:
> >
> > When offlining all cores on a CPU, the following system panic
> > occurs:
> >
> > BUG: unable to handle kernel NULL pointer dereference at (null)
> > IP: strlen+0x0/0x20
> > <snip>
> > Call Trace:
> > ? kernfs_name_hash+0x17/0x80
> > kernfs_find_ns+0x3f/0xd0
> > kernfs_remove_by_name_ns+0x36/0xa0
> > remove_files.isra.1+0x36/0x70
> > sysfs_remove_group+0x44/0x90
> > sysfs_remove_groups+0x2e/0x50
> > device_remove_attrs+0x5e/0x90
> > device_del+0x1ea/0x350
> > device_unregister+0x1a/0x60
> > thermal_zone_device_unregister+0x1f2/0x210
> > pkg_thermal_cpu_offline+0x14f/0x1a0 [x86_pkg_temp_thermal]
> > ? kzalloc.constprop.2+0x10/0x10 [x86_pkg_temp_thermal]
> > cpuhp_invoke_callback+0x8d/0x3f0
> > cpuhp_down_callbacks+0x42/0x80
> > cpuhp_thread_fun+0x8b/0xf0
> > smpboot_thread_fn+0x110/0x160
> > kthread+0x101/0x140
> > ? sort_range+0x30/0x30
> > ? kthread_park+0x90/0x90
> > ret_from_fork+0x25/0x30
> >
> > thermal_zone_create_device_group() sets attribute_groups in
> > thermal_zone_attribute_groups[] to tz->device.groups. But these
> > attributes_groups do not have name argument.
> >
> I'm a little confused here, in remove_files(),
> it is the (struct attribute *)->name which is passed into
> kernfs_remove_by_name, instead of attributes_groups->name.
>
> IMO, a NULL-name attribute group won't bring any problem.
>
hah, I see what the problem is here.
Just like the problem illustrated in this one
https://patchwork.kernel.org/patch/9492439/
The root cause is that, the trip point attributes are cleared and freed
BEFORE device_unregister(), this results in NULL trip point attributes
when removing the thermal zone device sysfs groups.
And I believe https://patchwork.kernel.org/patch/9492439/ should fix
the problem for you, right?
thanks,
rui> >
> > So when offlining all cores on CPU and executing
> > thermal_zone_device_unregister(), the panic occurs in strlen()
> > called from kernfs_name_hash() because name argument is NULL.
> >
> > The patch adds thermal_zone_remove_device_groups() to free
> > tz->device.groups and set NULL pointer.
> >
> > Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
> > CC: Zhang Rui <rui.zhang@intel.com>
> > CC: Eduardo Valentin <edubezval@gmail.com>
> > ---
> > drivers/thermal/thermal_core.c | 3 ++-
> > drivers/thermal/thermal_core.h | 1 +
> > drivers/thermal/thermal_sysfs.c | 6 ++++++
> > 3 files changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c
> > index 641faab..926e385 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -1251,6 +1251,7 @@ struct thermal_zone_device *
> >
> > unregister:
> > release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > + thermal_zone_remove_device_groups(tz);
> > device_unregister(&tz->device);
> > return ERR_PTR(result);
> > }
> > @@ -1315,8 +1316,8 @@ void thermal_zone_device_unregister(struct
> > thermal_zone_device *tz)
> > release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > idr_destroy(&tz->idr);
> > mutex_destroy(&tz->lock);
> > + thermal_zone_remove_device_groups(tz);
> > device_unregister(&tz->device);
> > - kfree(tz->device.groups);
> > }
> > EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
> >
> > diff --git a/drivers/thermal/thermal_core.h
> > b/drivers/thermal/thermal_core.h
> > index 2412b37..e3a60db 100644
> > --- a/drivers/thermal/thermal_core.h
> > +++ b/drivers/thermal/thermal_core.h
> > @@ -70,6 +70,7 @@ void thermal_zone_device_unbind_exception(struct
> > thermal_zone_device *,
> > int thermal_build_list_of_policies(char *buf);
> >
> > /* sysfs I/F */
> > +void thermal_zone_remove_device_groups(struct thermal_zone_device
> > *tz);
> > int thermal_zone_create_device_groups(struct thermal_zone_device
> > *,
> > int);
> > void thermal_cooling_device_setup_sysfs(struct
> > thermal_cooling_device *);
> > /* used only at binding time */
> > diff --git a/drivers/thermal/thermal_sysfs.c
> > b/drivers/thermal/thermal_sysfs.c
> > index a694de9..3dfd29b 100644
> > --- a/drivers/thermal/thermal_sysfs.c
> > +++ b/drivers/thermal/thermal_sysfs.c
> > @@ -605,6 +605,12 @@ static int create_trip_attrs(struct
> > thermal_zone_device *tz, int mask)
> > return 0;
> > }
> >
> > +void thermal_zone_remove_device_groups(struct thermal_zone_device
> > *tz)
> > +{
> > + kfree(tz->device.groups);
> > + tz->device.groups = NULL;
> > +}
> > +
> > int thermal_zone_create_device_groups(struct thermal_zone_device
> > *tz,
> > int mask)
> > {
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [U-Boot] am335x board i2c_probe fails from nand boot
From: Lokesh Vutla @ 2017-01-04 4:46 UTC (permalink / raw)
To: u-boot
In-Reply-To: <CADnUhn3RTk7FCk2YsRcJT5_7Krh1Qo3QBfSJ6CX28sKVNk6-1A@mail.gmail.com>
On Tuesday 03 January 2017 08:07 PM, matti kaasinen wrote:
> "The Expected Linux image was not found. Please check your NAND
> configuration" message is coming from:
> common/spl/spl_nand.c
> In practice this message seems coming from the fact that header of
> kernel image can't be identified from offset after executing:
> nand_spl_load_image(CONFIG_SYS_NAND_SPL_KERNEL_OFFS,,)
This is fine as SPL_OS_BOOT is enabled by default. We are successfully
going to u-boot prompt, so no issues.
> So, something gets broken in while executing nand_spl_load_image.
> Perhaps CONFIG_SYS_NAND_SPL_KERNEL_OFFS value.
>
> "Card did not respond to voltage select!" is coming from:
> drivers/mmc/mmc.c
Can you check if mmc mux is being done properly?
Thanks and regards,
Lokesh
>
> 2017-01-03 15:34 GMT+02:00 matti kaasinen <matti.kaasinen@gmail.com
> <mailto:matti.kaasinen@gmail.com>>:
>
>
> 2017-01-03 14:33 GMT+02:00 matti kaasinen <matti.kaasinen@gmail.com
> <mailto:matti.kaasinen@gmail.com>>:
>
> One reason why I2C configuration is wrong in nand mode could be
> the fact that I have CONFIG_TI_I2C_BOARD_DETECT variable is
> undefined (because I do not have that eeprom). But it looks that
> do_board_detect runs enable_i2c0_pin_mux() that I do not run
> separately. On the other hand, that does not explain why mmc
> boot works.
>
>
>
> Now I did this I2C0 configuration separately prior to running
> i2c_probe(). Nand boot went further now. However, main u-boot did
> not start properly. I got following messages
> Trying to boot from NAND
> The Expected Linux image was not found. Please check your NAND
> configuration.
> Trying to start u-boot now...
>
> ........ more messages ....
> Press SPACE to abort autoboot in 2 seconds
> Card did not respond to voltage select!
> Card did not respond to voltage select!
> Card did not respond to voltage select!
> Card did not respond to voltage select!
> Card did not respond to voltage select!
> data abort
> pc : [<8ff70f94>] lr : [<8ff701dd>]
> reloc pc : [<8081df94>] lr : [<8081d1dd>]
> sp : 8ef28678 ip : 8ff5891d fp : 00000003
> r10: 8ffb3af8 r9 : 8ef32ed8 r8 : 8ef41e40
> r7 : 8ff584bd r6 : 8ef39478 r5 : 8ef39500 r4 : 47810000
> r3 : 8ff70f85 r2 : 00000d8d r1 : 00000000 r0 : 8ef39500
> Flags: nZCv IRQs off FIQs on Mode SVC_32
> Resetting CPU ...
>
> resetting ...
>
> And game over....
> So, it's not quite sure that voltage adjustments went through even
> though I2C did not complain anymore.
> There could be something wrong with nand settings, too. I need to
> check where these complaints are coming.
>
> Thanks anyway for your comments,
> Matti
>
>
^ permalink raw reply
* Re: [PATCH 0/2] Begin auditing SECCOMP_RET_ERRNO return actions
From: Richard Guy Briggs @ 2017-01-04 4:43 UTC (permalink / raw)
To: Tyler Hicks
Cc: Kees Cook, Paul Moore, linux-audit, Will Drewry, LKML,
Andy Lutomirski
In-Reply-To: <3d1890e7-bef4-91e3-5d4c-cc5d4786d472@canonical.com>
On 2017-01-04 08:58, Tyler Hicks wrote:
> On 01/04/2017 04:44 AM, Kees Cook wrote:
> > On Tue, Jan 3, 2017 at 1:31 PM, Paul Moore <paul@paul-moore.com> wrote:
> >> On Tue, Jan 3, 2017 at 4:21 PM, Kees Cook <keescook@chromium.org> wrote:
> >>> On Tue, Jan 3, 2017 at 1:13 PM, Paul Moore <paul@paul-moore.com> wrote:
> >>>> On Tue, Jan 3, 2017 at 4:03 PM, Kees Cook <keescook@chromium.org> wrote:
> >>>>> On Tue, Jan 3, 2017 at 12:54 PM, Paul Moore <paul@paul-moore.com> wrote:
> >>>>>> On Tue, Jan 3, 2017 at 3:44 PM, Kees Cook <keescook@chromium.org> wrote:
> >>>>>>> I still wonder, though, isn't there a way to use auditctl to get all
> >>>>>>> the seccomp messages you need?
> >>>>>>
> >>>>>> Not all of the seccomp actions are currently logged, that's one of the
> >>>>>> problems (and the biggest at the moment).
> >>>>>
> >>>>> Well... sort of. It all gets passed around, but the logic isn't very
> >>>>> obvious (or at least I always have to go look it up).
> >>>>
> >>>> Last time I checked SECCOMP_RET_ALLOW wasn't logged (as well as at
> >>>> least one other action, but I can't remember which off the top of my
> >>>> head)?
> >>>
> >>> Sure, but if you're using audit, you don't need RET_ALLOW to be logged
> >>> because you'll get a full syscall log entry. Logging RET_ALLOW is
> >>> redundant and provides no new information, it seems to me.
> >>
> >> I only bring this up as it might be a way to help solve the
> >> SECCOMP_RET_AUDIT problem that Tyler mentioned.
> >
> > So, I guess I want to understand why something like this doesn't work,
> > with no changes at all to the kernel:
> >
> > Imaginary "seccomp-audit.c":
> >
> > ...
> > pid = fork();
> > if (pid) {
> > char cmd[80];
> >
> > sprintf(cmd, "auditctl -a always,exit -S all -F pid=%d", pid);
> > system(cmd);
> > release...
> > } else {
> > wait for release...
> > execv(argv[1], argv + 1);
> > }
> > ...
> >
> > This should dump all syscalls (both RET_ALLOW and RET_ERRNO), as well
> > as all seccomp actions of any kind. (Down side is the need for root to
> > launch auditctl...)
>
> Hey Kees - Thanks for the suggestion!
>
> Here are some of the reasons that it doesn't quite work:
>
> 1) We don't install/run auditd by default and would continue to prefer
> not to in some situations where resources are tight.
>
> 2) We block a relatively small number of syscalls as compared to what
> are allowed so auditing all syscalls is a really heavyweight solution.
> That could be fixed with a better -S argument, though.
>
> 3) We sometimes only block certain arguments for a given syscall and
> auditing all instances of the syscall could still be a heavyweight solution.
>
> 4) If the application spawns children processes, that rule doesn't audit
> their syscalls. That can be fixed with ppid=%d but then grandchildren
> pids are a problem.
This patch that wasn't accepted upstream might be useful:
https://www.redhat.com/archives/linux-audit/2015-August/msg00067.html
https://www.redhat.com/archives/linux-audit/2015-August/msg00068.html
> 5) Cleanup of the audit rule for an old pid, before the pid is reused,
> could be difficult.
>
> Tyler
>
> > Perhaps an improvement to this could be enabling audit when seccomp
> > syscall is seen? I can't tell if auditctl already has something to do
> > this ("start auditing this process and all children when syscall X is
> > performed").
> >
> > -Kees
- RGB
--
Richard Guy Briggs <rgb@redhat.com>
Kernel Security Engineering, Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635
^ permalink raw reply
* Re: [PATCH 0/2] Begin auditing SECCOMP_RET_ERRNO return actions
From: Richard Guy Briggs @ 2017-01-04 4:43 UTC (permalink / raw)
To: Tyler Hicks; +Cc: Will Drewry, LKML, Andy Lutomirski, linux-audit
In-Reply-To: <3d1890e7-bef4-91e3-5d4c-cc5d4786d472@canonical.com>
On 2017-01-04 08:58, Tyler Hicks wrote:
> On 01/04/2017 04:44 AM, Kees Cook wrote:
> > On Tue, Jan 3, 2017 at 1:31 PM, Paul Moore <paul@paul-moore.com> wrote:
> >> On Tue, Jan 3, 2017 at 4:21 PM, Kees Cook <keescook@chromium.org> wrote:
> >>> On Tue, Jan 3, 2017 at 1:13 PM, Paul Moore <paul@paul-moore.com> wrote:
> >>>> On Tue, Jan 3, 2017 at 4:03 PM, Kees Cook <keescook@chromium.org> wrote:
> >>>>> On Tue, Jan 3, 2017 at 12:54 PM, Paul Moore <paul@paul-moore.com> wrote:
> >>>>>> On Tue, Jan 3, 2017 at 3:44 PM, Kees Cook <keescook@chromium.org> wrote:
> >>>>>>> I still wonder, though, isn't there a way to use auditctl to get all
> >>>>>>> the seccomp messages you need?
> >>>>>>
> >>>>>> Not all of the seccomp actions are currently logged, that's one of the
> >>>>>> problems (and the biggest at the moment).
> >>>>>
> >>>>> Well... sort of. It all gets passed around, but the logic isn't very
> >>>>> obvious (or at least I always have to go look it up).
> >>>>
> >>>> Last time I checked SECCOMP_RET_ALLOW wasn't logged (as well as at
> >>>> least one other action, but I can't remember which off the top of my
> >>>> head)?
> >>>
> >>> Sure, but if you're using audit, you don't need RET_ALLOW to be logged
> >>> because you'll get a full syscall log entry. Logging RET_ALLOW is
> >>> redundant and provides no new information, it seems to me.
> >>
> >> I only bring this up as it might be a way to help solve the
> >> SECCOMP_RET_AUDIT problem that Tyler mentioned.
> >
> > So, I guess I want to understand why something like this doesn't work,
> > with no changes at all to the kernel:
> >
> > Imaginary "seccomp-audit.c":
> >
> > ...
> > pid = fork();
> > if (pid) {
> > char cmd[80];
> >
> > sprintf(cmd, "auditctl -a always,exit -S all -F pid=%d", pid);
> > system(cmd);
> > release...
> > } else {
> > wait for release...
> > execv(argv[1], argv + 1);
> > }
> > ...
> >
> > This should dump all syscalls (both RET_ALLOW and RET_ERRNO), as well
> > as all seccomp actions of any kind. (Down side is the need for root to
> > launch auditctl...)
>
> Hey Kees - Thanks for the suggestion!
>
> Here are some of the reasons that it doesn't quite work:
>
> 1) We don't install/run auditd by default and would continue to prefer
> not to in some situations where resources are tight.
>
> 2) We block a relatively small number of syscalls as compared to what
> are allowed so auditing all syscalls is a really heavyweight solution.
> That could be fixed with a better -S argument, though.
>
> 3) We sometimes only block certain arguments for a given syscall and
> auditing all instances of the syscall could still be a heavyweight solution.
>
> 4) If the application spawns children processes, that rule doesn't audit
> their syscalls. That can be fixed with ppid=%d but then grandchildren
> pids are a problem.
This patch that wasn't accepted upstream might be useful:
https://www.redhat.com/archives/linux-audit/2015-August/msg00067.html
https://www.redhat.com/archives/linux-audit/2015-August/msg00068.html
> 5) Cleanup of the audit rule for an old pid, before the pid is reused,
> could be difficult.
>
> Tyler
>
> > Perhaps an improvement to this could be enabling audit when seccomp
> > syscall is seen? I can't tell if auditctl already has something to do
> > this ("start auditing this process and all children when syscall X is
> > performed").
> >
> > -Kees
- RGB
--
Richard Guy Briggs <rgb@redhat.com>
Kernel Security Engineering, Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635
^ permalink raw reply
* Re: kvm: GPF in irq_bypass_unregister_consumer
From: Wanpeng Li @ 2017-01-04 4:36 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: Alex Williamson, Paolo Bonzini, KVM list, LKML, Steve Rutherford,
syzkaller
In-Reply-To: <CACT4Y+Yua2X_Qtqb8KKFvvGC9pLjtz7mesN=b2ThHuVzoB83PQ@mail.gmail.com>
2017-01-03 17:32 GMT+08:00 Dmitry Vyukov <dvyukov@google.com>:
> On Sat, Nov 12, 2016 at 2:21 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
>> Hello,
>>
>> The following programs triggers GPF in irq_bypass_unregister_consumer
>> if run in a parallel loop:
>> https://gist.githubusercontent.com/dvyukov/0d18d7b11659187ec3eab22285b4a67e/raw/c1c622ca26ebce0c7b77e3200970ca0f7792cb32/gistfile1.txt
>>
>> On commit 015ed9433be2b476ec7e2e6a9a411a56e3b5b035 (Nov 11).
>>
>> general protection fault: 0000 [#1] SMP KASAN
>> Dumping ftrace buffer:
>> (ftrace buffer empty)
>> Modules linked in:
>> CPU: 2 PID: 599 Comm: kworker/2:1 Not tainted 4.9.0-rc4+ #41
>> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
>> Workqueue: kvm-irqfd-cleanup irqfd_shutdown
>> task: ffff88006cb51700 task.stack: ffff88006cbd8000
>> RIP: 0010:[<ffffffff831d3957>] [< inline >] __list_del
>> include/linux/list.h:89
>> RIP: 0010:[<ffffffff831d3957>] [< inline >] list_del
>> include/linux/list.h:107
>> RIP: 0010:[<ffffffff831d3957>] [<ffffffff831d3957>]
>> irq_bypass_unregister_consumer+0x237/0x360 virt/lib/irqbypass.c:258
>> RSP: 0018:ffff88006cbdfb68 EFLAGS: 00010202
>> RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffff88006cb51f00
>> RDX: 0000000000000001 RSI: ffff88006cb51f50 RDI: 0000000000000008
>> RBP: ffff88006cbdfb90 R08: 0000000000000000 R09: 0000000000000000
>> R10: 0000000000000000 R11: 0000000000000000 R12: ffff88003caea638
>> R13: 0000000000000000 R14: ffffffff83ece9a0 R15: ffff88006bb0a530
>> FS: 0000000000000000(0000) GS:ffff88006e200000(0000) knlGS:0000000000000000
>> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>> CR2: 00000000006e0000 CR3: 0000000003a1d000 CR4: 00000000000026e0
>> Stack:
>> ffff88003caea4d0 ffff88003caea5f8 1ffff1000d97bf75 ffff88003caea5d0
>> dffffc0000000000 ffff88006cbdfc30 ffffffff8106d144 0000000000000000
>> 0000000041b58ab3 ffffffff837c38d1 ffffffff8106d030 0000000000000246
>> Call Trace:
>> [<ffffffff8106d144>] irqfd_shutdown+0x114/0x1a0
>> arch/x86/kvm/../../../virt/kvm/eventfd.c:145
>> [<ffffffff8129375c>] process_one_work+0x9fc/0x1900 kernel/workqueue.c:2096
>> [<ffffffff8129474f>] worker_thread+0xef/0x1480 kernel/workqueue.c:2230
>> [<ffffffff812a7a94>] kthread+0x244/0x2d0 kernel/kthread.c:209
>> [<ffffffff831ebf6a>] ret_from_fork+0x2a/0x40 arch/x86/entry/entry_64.S:433
>> Code: 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 b7 00 00 00 49 8d 7d 08
>> 48 b8 00 00 00 00 00 fc ff df 49 8b 5c 24 08 48 89 fa 48 c1 ea 03 <80>
>> 3c 02 00 0f 85 9d 00 00 00 48 89 da 48 b8 00 00 00 00 00 fc
>> RIP [< inline >] __list_del include/linux/list.h:89
>> RIP [< inline >] list_del include/linux/list.h:107
>> RIP [<ffffffff831d3957>] irq_bypass_unregister_consumer+0x237/0x360
>> virt/lib/irqbypass.c:258
>> RSP <ffff88006cbdfb68>
>> ---[ end trace 986ec3b53e4e0338 ]---
>> Kernel panic - not syncing: Fatal exception
>> Dumping ftrace buffer:
>> (ftrace buffer empty)
>> Kernel Offset: disabled
>> reboot: cpu_has_vmx: ecx=80a02021 1
>
>
> Still happens on c8b4ec8351d21da3299b045b37920e5cf5590793 (Jan 2).
>
> [ 480.585892] irq bypass consumer (token ffff88003e205700)
> registration fails: -16
> [ 480.686218] BUG: unable to handle kernel NULL pointer dereference
> at 0000000000000008
> [ 480.686868] IP: irq_bypass_unregister_consumer+0x8d/0xd0
> [ 480.686993] PGD 0
> [ 480.686993]
> [ 480.686993] Oops: 0002 [#1] SMP
> [ 480.686993] Modules linked in:
> [ 480.686993] CPU: 3 PID: 585 Comm: kworker/3:1 Not tainted 4.10.0-rc2+ #57
> [ 480.686993] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
> BIOS Bochs 01/01/2011
> [ 480.686993] Workqueue: kvm-irqfd-cleanup irqfd_shutdown
> [ 480.686993] task: ffff88007fa3a8c0 task.stack: ffffc90001524000
> [ 480.686993] RIP: 0010:irq_bypass_unregister_consumer+0x8d/0xd0
> [ 480.686993] RSP: 0018:ffffc90001527e20 EFLAGS: 00010246
> [ 480.686993] RAX: 0000000000000000 RBX: ffff88007dfa5170 RCX: 0000000000000004
> [ 480.686993] RDX: 0000000000000000 RSI: ffff88007dfa50e8 RDI: 0000000000000000
> [ 480.686993] RBP: ffffc90001527e28 R08: 0000000000000004 R09: ffff88007fd171c0
> [ 480.686993] R10: 0000006feb214fc0 R11: 0000000000000000 R12: ffff88007dfa5070
> [ 480.686993] R13: ffff88007fd1e300 R14: 00000000000000c0 R15: ffff88007dfa5150
> [ 480.686993] FS: 0000000000000000(0000) GS:ffff88007fd00000(0000)
> knlGS:0000000000000000
> [ 480.686993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 480.686993] CR2: 0000000000000008 CR3: 0000000001e0a000 CR4: 00000000000026e0
> [ 480.686993] Call Trace:
> [ 480.686993] irqfd_shutdown+0x52/0x70
> [ 480.686993] process_one_work+0x149/0x3f0
> [ 480.686993] worker_thread+0x126/0x4a0
> [ 480.686993] ? __schedule+0x21c/0x660
> [ 480.686993] kthread+0xfc/0x130
> [ 480.686993] ? rescuer_thread+0x320/0x320
> [ 480.686993] ? kthread_park+0x90/0x90
> [ 480.686993] ret_from_fork+0x25/0x30
> [ 480.686993] Code: 30 d7 f0 81 75 0e eb 1a 48 8b 3f 48 81 ff 30 d7
> f0 81 74 0e 48 39 57 10 75 ee 48 89 de e8 cc fb ff ff 48 8b 43 08 48
> 8b 13 31 ff <48> 89 42 08 48 89 10 48 b8 00 01 00 00 00 00 ad de 48 89
> 03 66
> [ 480.686993] RIP: irq_bypass_unregister_consumer+0x8d/0xd0 RSP:
> ffffc90001527e20
> [ 480.686993] CR2: 0000000000000008
> [ 480.686993] ---[ end trace e5a8ddcdf160fccb ]---
case 1:
r[2] = syscall(__NR_open, "/dev/kvm", 0x40042ul, 0, 0, 0, 0, 0, 0);
break;
case 2:
r[3] = execute_syscall(__NR_ioctl, r[2], 0xae01ul, 0x0ul, 0, 0, 0,
0, 0, 0);
break;
case 3:
r[4] = execute_syscall(__NR_ioctl, r[3], 0xae41ul, 0x3fful, 0, 0, 0,
0, 0, 0);
break;
case 4:
r[5] = execute_syscall(__NR_ioctl, r[4], 0xae9aul, 0, 0, 0, 0, 0, 0,
0);
break;
case 5:
r[6] = execute_syscall(__NR_eventfd2, 0x8ul, 0x801ul, 0, 0, 0, 0, 0,
0, 0);
What's the meaning of parameter "0x40042ul", “0xae01ul” etc here?
Regards,
Wanpeng Li
^ permalink raw reply
* Re: [PATCH] thermal: add thermal_zone_remove_device_groups()
From: Zhang Rui @ 2017-01-04 4:35 UTC (permalink / raw)
To: Yasuaki Ishimatsu, linux-kernel, linux-pm; +Cc: edubezval
In-Reply-To: <6c5a1a95-9b03-6f43-8de8-1ab4ac27cc78@gmail.com>
On Thu, 2016-12-15 at 16:47 -0500, Yasuaki Ishimatsu wrote:
> When offlining all cores on a CPU, the following system panic
> occurs:
>
> BUG: unable to handle kernel NULL pointer dereference at (null)
> IP: strlen+0x0/0x20
> <snip>
> Call Trace:
> ? kernfs_name_hash+0x17/0x80
> kernfs_find_ns+0x3f/0xd0
> kernfs_remove_by_name_ns+0x36/0xa0
> remove_files.isra.1+0x36/0x70
> sysfs_remove_group+0x44/0x90
> sysfs_remove_groups+0x2e/0x50
> device_remove_attrs+0x5e/0x90
> device_del+0x1ea/0x350
> device_unregister+0x1a/0x60
> thermal_zone_device_unregister+0x1f2/0x210
> pkg_thermal_cpu_offline+0x14f/0x1a0 [x86_pkg_temp_thermal]
> ? kzalloc.constprop.2+0x10/0x10 [x86_pkg_temp_thermal]
> cpuhp_invoke_callback+0x8d/0x3f0
> cpuhp_down_callbacks+0x42/0x80
> cpuhp_thread_fun+0x8b/0xf0
> smpboot_thread_fn+0x110/0x160
> kthread+0x101/0x140
> ? sort_range+0x30/0x30
> ? kthread_park+0x90/0x90
> ret_from_fork+0x25/0x30
>
> thermal_zone_create_device_group() sets attribute_groups in
> thermal_zone_attribute_groups[] to tz->device.groups. But these
> attributes_groups do not have name argument.
>
I'm a little confused here, in remove_files(),
it is the (struct attribute *)->name which is passed into
kernfs_remove_by_name, instead of attributes_groups->name.
IMO, a NULL-name attribute group won't bring any problem.
thanks,
rui
> So when offlining all cores on CPU and executing
> thermal_zone_device_unregister(), the panic occurs in strlen()
> called from kernfs_name_hash() because name argument is NULL.
>
> The patch adds thermal_zone_remove_device_groups() to free
> tz->device.groups and set NULL pointer.
>
> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
> CC: Zhang Rui <rui.zhang@intel.com>
> CC: Eduardo Valentin <edubezval@gmail.com>
> ---
> drivers/thermal/thermal_core.c | 3 ++-
> drivers/thermal/thermal_core.h | 1 +
> drivers/thermal/thermal_sysfs.c | 6 ++++++
> 3 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> index 641faab..926e385 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1251,6 +1251,7 @@ struct thermal_zone_device *
>
> unregister:
> release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> + thermal_zone_remove_device_groups(tz);
> device_unregister(&tz->device);
> return ERR_PTR(result);
> }
> @@ -1315,8 +1316,8 @@ void thermal_zone_device_unregister(struct
> thermal_zone_device *tz)
> release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> idr_destroy(&tz->idr);
> mutex_destroy(&tz->lock);
> + thermal_zone_remove_device_groups(tz);
> device_unregister(&tz->device);
> - kfree(tz->device.groups);
> }
> EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
>
> diff --git a/drivers/thermal/thermal_core.h
> b/drivers/thermal/thermal_core.h
> index 2412b37..e3a60db 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -70,6 +70,7 @@ void thermal_zone_device_unbind_exception(struct
> thermal_zone_device *,
> int thermal_build_list_of_policies(char *buf);
>
> /* sysfs I/F */
> +void thermal_zone_remove_device_groups(struct thermal_zone_device
> *tz);
> int thermal_zone_create_device_groups(struct thermal_zone_device *,
> int);
> void thermal_cooling_device_setup_sysfs(struct
> thermal_cooling_device *);
> /* used only at binding time */
> diff --git a/drivers/thermal/thermal_sysfs.c
> b/drivers/thermal/thermal_sysfs.c
> index a694de9..3dfd29b 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -605,6 +605,12 @@ static int create_trip_attrs(struct
> thermal_zone_device *tz, int mask)
> return 0;
> }
>
> +void thermal_zone_remove_device_groups(struct thermal_zone_device
> *tz)
> +{
> + kfree(tz->device.groups);
> + tz->device.groups = NULL;
> +}
> +
> int thermal_zone_create_device_groups(struct thermal_zone_device
> *tz,
> int mask)
> {
^ permalink raw reply
* [PATCH] Include sys/sysmacros.h
From: Anthony Ryan @ 2017-01-04 4:34 UTC (permalink / raw)
To: dm-devel
The major, minor & makedev macros are not supposed to be included
with sys/types.h but glibc has done this against POSIX standards.
Alternative libcs aren't able to be used because of this and glibc
has expressed interest in correcting this behaviour in a future
release.
---
kpartx/dasd.c | 1 +
kpartx/kpartx.c | 1 +
libmultipath/checkers/tur.c | 1 +
libmultipath/devmapper.c | 1 +
libmultipath/util.c | 1 +
5 files changed, 5 insertions(+)
diff --git a/kpartx/dasd.c b/kpartx/dasd.c
index 1206e45..f50c1bd 100644
--- a/kpartx/dasd.c
+++ b/kpartx/dasd.c
@@ -28,6 +28,7 @@
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <errno.h>
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index d31fea8..3452787 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -28,6 +28,7 @@
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include <ctype.h>
#include <libdevmapper.h>
diff --git a/libmultipath/checkers/tur.c b/libmultipath/checkers/tur.c
index 4d6c3c2..d9a9e67 100644
--- a/libmultipath/checkers/tur.c
+++ b/libmultipath/checkers/tur.c
@@ -11,6 +11,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <sys/sysmacros.h>
#include <errno.h>
#include <sys/time.h>
#include <pthread.h>
diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c
index 4f8ef13..9c0b240 100644
--- a/libmultipath/devmapper.c
+++ b/libmultipath/devmapper.c
@@ -12,6 +12,7 @@
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
+#include <sys/sysmacros.h>
#include "checkers.h"
#include "vector.h"
diff --git a/libmultipath/util.c b/libmultipath/util.c
index 03a5738..1841f35 100644
--- a/libmultipath/util.c
+++ b/libmultipath/util.c
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
--
2.11.0
^ permalink raw reply related
* [Qemu-devel] [PATCH] Crypto: fix leak in ivgen essiv init
From: Li Qiang @ 2017-01-04 4:31 UTC (permalink / raw)
To: berrange, qemu-devel; +Cc: liqiang6-s
From: Li Qiang <liqiang6-s@360.cn>
On error path, the 'salt' doesn't been freed thus leading
a memory leak. This patch avoid this.
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
---
crypto/ivgen-essiv.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/crypto/ivgen-essiv.c b/crypto/ivgen-essiv.c
index 634de63..cba20bd 100644
--- a/crypto/ivgen-essiv.c
+++ b/crypto/ivgen-essiv.c
@@ -48,6 +48,7 @@ static int qcrypto_ivgen_essiv_init(QCryptoIVGen *ivgen,
&salt, &nhash,
errp) < 0) {
g_free(essiv);
+ g_free(salt);
return -1;
}
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] dmaengine: ipu: Revert ipu_irq_handler changes.
From: Vinod Koul @ 2017-01-04 4:31 UTC (permalink / raw)
To: ivan.stoyanov; +Cc: arnd, dan.j.williams, dmaengine, linux-kernel
In-Reply-To: <1482496260-26409-1-git-send-email-ivan.stoyanov@amk-drives.bg>
On Fri, Dec 23, 2016 at 02:31:00PM +0200, ivan.stoyanov@amk-drives.bg wrote:
> From: Ivan Stoyanov <ivan.stoyanov@amk-drives.bg>
>
> In commit 3d8cc00073d6750ffe883685e49b2e4a0f596370 are consolidate functions ipu_irq_err and ipu_irq_fn considered for duplicated.
> Since this patch ipu driver does not work properly and cause kernel freeze during booting.
I dont think we can do the revert (kbot gave build errors), can you debug
further and find out why this causes regression?
>
> [ 1.018314] Remapped [mem 0x53fc00b4-0x53fc01bf] at f57c00b4
> [ 1.024010] dmaengine: private_candidate: dma0chan0 filter said false
> [ 1.030591] dmaengine: private_candidate: dma0chan1 filter said false
> [ 1.037044] dmaengine: private_candidate: dma0chan2 filter said false
> [ 1.043643] dmaengine: private_candidate: dma0chan3 filter said false
> [ 1.050096] dmaengine: private_candidate: dma0chan4 filter said false
> [ 1.056692] dmaengine: private_candidate: dma0chan5 filter said false
> [ 1.063146] dmaengine: private_candidate: dma0chan6 filter said false
> [ 1.069742] dmaengine: private_candidate: dma0chan7 filter said false
> [ 1.076233] dmaengine: private_candidate: dma0chan8 filter said false
> [ 1.082843] dmaengine: private_candidate: dma0chan9 filter said false
> [ 1.089296] dmaengine: private_candidate: dma0chan10 filter said false
> [ 1.095894] dmaengine: private_candidate: dma0chan11 filter said false
> [ 1.102491] dmaengine: private_candidate: dma0chan12 filter said false
> [ 1.109102] dmaengine: private_candidate: dma0chan13 filter said false
> [ 1.115718] IPU: mapped source 14 to IRQ 176
> [ 1.198869] ipu-core ipu-core: init channel = 14
> [ 1.203638] ipu-core ipu-core: IDMAC_CONF 0x70, IC_CONF 0x0, IDMAC_CHA_EN 0x0, IDMAC_CHA_PRI 0x4000, IDMAC_ CHA_BUSY 0x0
> [ 1.214447] ipu-core ipu-core: BUF0_RDY 0x4000, BUF1_RDY 0x0, CUR_BUF 0x0, DB_MODE 0x0, TASKS_STAT 0x2003
> [ 1.224442] dma dma0chan14: Found channel 0xe, irq 176
> [ 1.229690] dmaengine: __dma_request_channel: success (dma0chan14)
> [ 1.235966] return 1
> [ 1.238276] mx3_sdc_fb mx3_sdc_fb: mx3fb_check_var
> [ 1.243121] mx3_sdc_fb mx3_sdc_fb: mx3fb_check_var
> [ 1.247989] mx3_sdc_fb mx3_sdc_fb: sdc_set_brightness: value = 255
> [ 1.254238] mx3_sdc_fb mx3_sdc_fb: disabling irq 176
> [ 1.270275] mx3_sdc_fb mx3_sdc_fb: allocated fb @ p=0x97000000, v=0xd887d000, size=1536000.
> [ 1.294524] mx3_sdc_fb mx3_sdc_fb: pixclock = 33260000l Hz
> [ 1.300118] mx3_sdc_fb mx3_sdc_fb: panel size = 800 x 480
> [ 1.305528] hor_conf 3e80000, ver_conf 1f40001
> [ 1.310266] mx3_sdc_fb mx3_sdc_fb: InitPanel() - Pixel clock divider less than 4
> [ 1.317813] mx3_sdc_fb mx3_sdc_fb: pixel clk = 33260000, divider 4.0
> [ 1.324272] mx3_sdc_fb mx3_sdc_fb: DI_DISP_IF_CONF = 0x04000000
> [ 1.330209] mx3_sdc_fb mx3_sdc_fb: DI_DISP_SIG_POL = 0x06000000
> [ 1.336287] mx3_sdc_fb mx3_sdc_fb: DI_DISP3_TIME_CONF = 0x01C00040
> [ 1.348164] mx3_sdc_fb mx3_sdc_fb: mx3fbi d798d25c, txd = NULL
> [ 1.354123] ipu-core ipu-core: write param mem - addr = 0x000100E0, data = 0x00000000
> [ 1.362003] ipu-core ipu-core: write param mem - addr = 0x000100E1, data = 0x00004000
> [ 1.369987] ipu-core ipu-core: write param mem - addr = 0x000100E2, data = 0x00000000
> [ 1.377835] ipu-core ipu-core: write param mem - addr = 0x000100E3, data = 0xDF31F000
> [ 1.385821] ipu-core ipu-core: write param mem - addr = 0x000100E4, data = 0x00000001
> [ 1.393670] ipu-core ipu-core: write param mem - addr = 0x000100E8, data = 0x97000000
> [ 1.401655] ipu-core ipu-core: write param mem - addr = 0x000100E9, data = 0x00000000
> [ 1.409504] ipu-core ipu-core: write param mem - addr = 0x000100EA, data = 0x1E0831FA
> [ 1.417490] ipu-core ipu-core: write param mem - addr = 0x000100EB, data = 0x96416502
> [ 1.425338] ipu-core ipu-core: write param mem - addr = 0x000100EC, data = 0x00000000
> [ 1.433323] dma dma0chan14: Submitting sg d798d2d4
> [ 1.438224] dma dma0chan14: Updated sg d798d2d4 on channel 0xe buffer 0
> [ 1.444864] ipu-core ipu-core: IDMAC_CONF 0x70, IC_CONF 0x0, IDMAC_CHA_EN 0x0, IDMAC_CHA_PRI 0x4000, IDMAC_ CHA_BUSY 0x0
> [ 1.455798] ipu-core ipu-core: BUF0_RDY 0x4000, BUF1_RDY 0x0, CUR_BUF 0x0, DB_MODE 0x0, TASKS_STAT 0x3
> [ 1.465214] ipu-core ipu-core: IDMAC_CONF 0x70, IC_CONF 0x0, IDMAC_CHA_EN 0x4000, IDMAC_CHA_PRI 0x4000, IDM AC_CHA_BUSY 0x0
> [ 1.476365] ipu-core ipu-core: BUF0_RDY 0x4000, BUF1_RDY 0x0, CUR_BUF 0x0, DB_MODE 0x0, TASKS_STAT 0x3
> [ 1.485807] mx3_sdc_fb mx3_sdc_fb: 422: Submit d887b09c #2 [+]
> [ 1.510871] mx3_sdc_fb mx3_sdc_fb: sdc_set_brightness: value = 255
> [
>
> Signed-off-by: Ivan Stoyanov <ivan.stoyanov@amk-drives.bg>
> ---
> drivers/dma/ipu/ipu_irq.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
> 1 file changed, 42 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c
> index dd184b5..3f9477c 100644
> --- a/drivers/dma/ipu/ipu_irq.c
> +++ b/drivers/dma/ipu/ipu_irq.c
> @@ -265,8 +265,8 @@ int ipu_irq_unmap(unsigned int source)
> return ret;
> }
>
> -/* Chained IRQ handler for IPU function and error interrupt */
> -static void ipu_irq_handler(struct irq_desc *desc)
> +/* Chained IRQ handler for IPU error interrupt */
> +static void ipu_irq_err(struct irq_desc *desc)
> {
> struct ipu *ipu = irq_desc_get_handler_data(desc);
> u32 status;
> @@ -306,6 +306,44 @@ static void ipu_irq_handler(struct irq_desc *desc)
> }
> }
>
> +/* Chained IRQ handler for IPU function interrupt */
> +static void ipu_irq_fn(struct irq_desc *desc)
> +{
> + struct ipu *ipu = irq_desc_get_handler_data(desc);
> + u32 status;
> + int i, line;
> +
> + for (i = 0; i < IPU_IRQ_NR_FN_BANKS; i++) {
> + struct ipu_irq_bank *bank = irq_bank + i;
> +
> + raw_spin_lock(&bank_lock);
> + status = ipu_read_reg(ipu, bank->status);
> + /* Not clearing all interrupts, see above */
> + status &= ipu_read_reg(ipu, bank->control);
> + raw_spin_unlock(&bank_lock);
> + while ((line = ffs(status))) {
> + struct ipu_irq_map *map;
> + unsigned int irq;
> +
> + line--;
> + status &= ~(1UL << line);
> +
> + raw_spin_lock(&bank_lock);
> + map = src2map(32 * i + line);
> + if (map)
> + irq = map->irq;
> + raw_spin_unlock(&bank_lock);
> +
> + if (!map) {
> + pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
> + line, i);
> + continue;
> + }
> + generic_handle_irq(irq);
> + }
> + }
> +}
> +
> static struct irq_chip ipu_irq_chip = {
> .name = "ipu_irq",
> .irq_ack = ipu_irq_ack,
> @@ -343,9 +381,9 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
> irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
> }
>
> - irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_handler, ipu);
> + irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_fn, ipu);
>
> - irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_handler, ipu);
> + irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_err, ipu);
>
> ipu->irq_base = irq_base;
>
> --
> 2.7.4
>
--
~Vinod
^ permalink raw reply
* [Qemu-devel] [Bug 322602] Re: Snapshot usage makes qcow2 image unusable due to large tables
From: Launchpad Bug Tracker @ 2017-01-04 4:17 UTC (permalink / raw)
To: qemu-devel
In-Reply-To: <20090129032712.7039.50315.malonedeb@gandwana.canonical.com>
[Expired for QEMU because there has been no activity for 60 days.]
** Changed in: qemu
Status: Incomplete => Expired
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/322602
Title:
Snapshot usage makes qcow2 image unusable due to large tables
Status in QEMU:
Expired
Bug description:
To reproduce with 0.9.1 and svn:
- Create a 20G (or some size much greater than system RAM) qcow2 image
- Inside VM, install some OS, formatting whole drive
- Create snapshot with savevm
- Inside VM, reformat and reinstall OS
- Create snapshot with savevm
[...]
Eventually, qemu crashes, then neither qemu-img nor qemu can open the
image because memory is exhausted. The reason is that the whole
refcount_table is loaded into memory, and this refcount_table has now
become much bigger than the size of memory due to each snapshot taken
after significant changes to the disk image.
The refcount_table really needs to be loaded and used in fixed size
chunks to avoid this problem. It will only get worse as typical
storage set modifications during work sessions between snapshots
outpace the size of system RAM.
Alternatively, there needs to be a way to "rollback" a snapshot
without loading the whole disk image normally, so that a snapshot
which has made the image unusable in this way can be reversed.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/322602/+subscriptions
^ permalink raw reply
* [Qemu-devel] [Bug 441672] Re: Windos XP BSOD with HP Photosmart usb device attached
From: Launchpad Bug Tracker @ 2017-01-04 4:17 UTC (permalink / raw)
To: qemu-devel
In-Reply-To: <20091003195706.32421.28307.malonedeb@gangotri.canonical.com>
[Expired for QEMU because there has been no activity for 60 days.]
** Changed in: qemu
Status: Incomplete => Expired
--
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/441672
Title:
Windos XP BSOD with HP Photosmart usb device attached
Status in QEMU:
Expired
Bug description:
https://bugzilla.redhat.com/show_bug.cgi?id=524723 has all the details
of the problem.
I was just testing attaching a USB device to see if it really worked, and tried my HP Photosmart C5580 All-in-One
printer/scanner, and the Windows XP box then started getting bluescreens and crashing at random
(fairly short :-) intervals.
My latest attempt was on a fedora rawhide system with pretty up to date software
(qemu-kvm-0.11.0-2.fc12.x86_64), and the crashes still happen.
A reply to that bugzilla recommended adding this upstream bug, so here
it is.
To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/441672/+subscriptions
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
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.