On Mon, Aug 10, 2015 at 3:03 PM, Jean-Christophe Dubois <j...@tribudubois.net> wrote: > This is using a ds1338 RTC chip on the I2C bus. This RTC chip is > not present on the real 3DS PDK board. > > Signed-off-by: Jean-Christophe Dubois <j...@tribudubois.net>
Not an expert, but looks ok. Acked-by: Peter Crosthwaite <crosthwaite.pe...@gmail.com> > --- > > Changes since v1: > * not present on v1 > > Changes since v2: > * use a common header file for I2C regs definition > > Changes since v3: > * rework GPL headers. > > Changes since v4: > * none > > Changes since v5: > * none > > Changes since v6: > * none > > Changes since v7: > * adapt to new i.MX I2C header file. > > Changes since v8: > * no change > > Changes since v9: > * no change > > Changes since v10: > * no change > > Changes since v11: > * no change > > Changes since v12: > * no change > > Changes since v13: > * Fix imx25_3ds to imx25_pdk for "make check" target > * move bcd2bin() as inline function > * Spelling fix. > > tests/Makefile | 3 + > tests/ds1338-test.c | 78 ++++++++++++++++++ > tests/libqos/i2c-imx.c | 209 > +++++++++++++++++++++++++++++++++++++++++++++++++ > tests/libqos/i2c.h | 3 + > 4 files changed, 293 insertions(+) > create mode 100644 tests/ds1338-test.c > create mode 100644 tests/libqos/i2c-imx.c > > diff --git a/tests/Makefile b/tests/Makefile > index 7494582..7be50fc 100644 > --- a/tests/Makefile > +++ b/tests/Makefile > @@ -201,6 +201,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF) > gcov-files-sparc-y += hw/timer/m48t59.c > gcov-files-sparc64-y += hw/timer/m48t59.c > check-qtest-arm-y = tests/tmp105-test$(EXESUF) > +check-qtest-arm-y = tests/ds1338-test$(EXESUF) > gcov-files-arm-y += hw/misc/tmp105.c > check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) > gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c > @@ -354,6 +355,7 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o > libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o > libqos-pc-obj-y += tests/libqos/ahci.o > libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o > +libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o > libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o > libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o > tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o > tests/libqos/malloc-generic.o > > @@ -368,6 +370,7 @@ tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o > tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) > tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) > tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) > +tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) > tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) > tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y) > tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) > diff --git a/tests/ds1338-test.c b/tests/ds1338-test.c > new file mode 100644 > index 0000000..a7fb415 > --- /dev/null > +++ b/tests/ds1338-test.c > @@ -0,0 +1,78 @@ > +/* > + * QTest testcase for the DS1338 RTC > + * > + * Copyright (c) 2013 Jean-Christophe Dubois > + * > + * This program 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 program 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. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "libqtest.h" > +#include "libqos/i2c.h" > + > +#include <glib.h> > + > +#define IMX25_I2C_0_BASE 0x43F80000 > + > +#define DS1338_ADDR 0x68 > + > +static I2CAdapter *i2c; > +static uint8_t addr; > + > +static inline uint8_t bcd2bin(uint8_t x) > +{ > + return ((x) & 0x0f) + ((x) >> 4) * 10; > +} > + > +static void send_and_receive(void) > +{ > + uint8_t cmd[1]; > + uint8_t resp[7]; > + time_t now = time(NULL); > + struct tm *tm_ptr = gmtime(&now); > + > + /* reset the index in the RTC memory */ > + cmd[0] = 0; > + i2c_send(i2c, addr, cmd, 1); > + > + /* retrieve the date */ > + i2c_recv(i2c, addr, resp, 7); > + > + /* check retrieved time againt local time */ > + g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday); > + g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon); > + g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year); > +} > + > +int main(int argc, char **argv) > +{ > + QTestState *s = NULL; > + int ret; > + > + g_test_init(&argc, &argv, NULL); > + > + s = qtest_start("-display none -machine imx25_pdk"); > + i2c = imx_i2c_create(IMX25_I2C_0_BASE); > + addr = DS1338_ADDR; > + > + qtest_add_func("/ds1338/tx-rx", send_and_receive); > + > + ret = g_test_run(); > + > + if (s) { > + qtest_quit(s); > + } > + g_free(i2c); > + > + return ret; > +} > diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c > new file mode 100644 > index 0000000..b5cef66 > --- /dev/null > +++ b/tests/libqos/i2c-imx.c > @@ -0,0 +1,209 @@ > +/* > + * QTest i.MX I2C driver > + * > + * Copyright (c) 2013 Jean-Christophe Dubois > + * > + * This program 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 program 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. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "libqos/i2c.h" > + > +#include <glib.h> > +#include <string.h> > + > +#include "qemu/osdep.h" > +#include "libqtest.h" > + > +#include "hw/i2c/imx_i2c.h" > + > +enum IMXI2CDirection { > + IMX_I2C_READ, > + IMX_I2C_WRITE, > +}; > + > +typedef struct IMXI2C { > + I2CAdapter parent; > + > + uint64_t addr; > +} IMXI2C; > + > + > +static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, > + enum IMXI2CDirection direction) > +{ > + writeb(s->addr + I2DR_ADDR, (addr << 1) | > + (direction == IMX_I2C_READ ? 1 : 0)); > +} > + > +static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr, > + const uint8_t *buf, uint16_t len) > +{ > + IMXI2C *s = (IMXI2C *)i2c; > + uint8_t data; > + uint8_t status; > + uint16_t size = 0; > + > + if (!len) { > + return; > + } > + > + /* set the bus for write */ > + data = I2CR_IEN | > + I2CR_IIEN | > + I2CR_MSTA | > + I2CR_MTX | > + I2CR_TXAK; > + > + writeb(s->addr + I2CR_ADDR, data); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) != 0); > + > + /* set the slave address */ > + imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) != 0); > + g_assert((status & I2SR_RXAK) == 0); > + > + /* ack the interrupt */ > + writeb(s->addr + I2SR_ADDR, 0); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) == 0); > + > + while (size < len) { > + /* check we are still busy */ > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) != 0); > + > + /* write the data */ > + writeb(s->addr + I2DR_ADDR, buf[size]); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) != 0); > + g_assert((status & I2SR_RXAK) == 0); > + > + /* ack the interrupt */ > + writeb(s->addr + I2SR_ADDR, 0); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) == 0); > + > + size++; > + } > + > + /* release the bus */ > + data &= ~(I2CR_MSTA | I2CR_MTX); > + writeb(s->addr + I2CR_ADDR, data); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) == 0); > +} > + > +static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr, > + uint8_t *buf, uint16_t len) > +{ > + IMXI2C *s = (IMXI2C *)i2c; > + uint8_t data; > + uint8_t status; > + uint16_t size = 0; > + > + if (!len) { > + return; > + } > + > + /* set the bus for write */ > + data = I2CR_IEN | > + I2CR_IIEN | > + I2CR_MSTA | > + I2CR_MTX | > + I2CR_TXAK; > + > + writeb(s->addr + I2CR_ADDR, data); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) != 0); > + > + /* set the slave address */ > + imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) != 0); > + g_assert((status & I2SR_RXAK) == 0); > + > + /* ack the interrupt */ > + writeb(s->addr + I2SR_ADDR, 0); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) == 0); > + > + /* set the bus for read */ > + data &= ~I2CR_MTX; > + /* if only one byte don't ack */ > + if (len != 1) { > + data &= ~I2CR_TXAK; > + } > + writeb(s->addr + I2CR_ADDR, data); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) != 0); > + > + /* dummy read */ > + readb(s->addr + I2DR_ADDR); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) != 0); > + > + /* ack the interrupt */ > + writeb(s->addr + I2SR_ADDR, 0); > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) == 0); > + > + while (size < len) { > + /* check we are still busy */ > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) != 0); > + > + if (size == (len - 1)) { > + /* stop the read transaction */ > + data &= ~(I2CR_MSTA | I2CR_MTX); > + } else { > + /* ack the data read */ > + data |= I2CR_TXAK; > + } > + writeb(s->addr + I2CR_ADDR, data); > + > + /* read the data */ > + buf[size] = readb(s->addr + I2DR_ADDR); > + > + if (size != (len - 1)) { > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) != 0); > + > + /* ack the interrupt */ > + writeb(s->addr + I2SR_ADDR, 0); > + } > + > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IIF) == 0); > + > + size++; > + } > + > + status = readb(s->addr + I2SR_ADDR); > + g_assert((status & I2SR_IBB) == 0); > +} > + > +I2CAdapter *imx_i2c_create(uint64_t addr) > +{ > + IMXI2C *s = g_malloc0(sizeof(*s)); > + I2CAdapter *i2c = (I2CAdapter *)s; > + > + s->addr = addr; > + > + i2c->send = imx_i2c_send; > + i2c->recv = imx_i2c_recv; > + > + return i2c; > +} > diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h > index 1ce9af4..c21f1dc 100644 > --- a/tests/libqos/i2c.h > +++ b/tests/libqos/i2c.h > @@ -27,4 +27,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr, > /* libi2c-omap.c */ > I2CAdapter *omap_i2c_create(uint64_t addr); > > +/* libi2c-imx.c */ > +I2CAdapter *imx_i2c_create(uint64_t addr); > + > #endif > -- > 2.1.4 > >