
* Update to QEMU v9.0.0 --------- Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Fabiano Rosas <farosas@suse.de> Signed-off-by: Peter Xu <peterx@redhat.com> Signed-off-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Zheyu Ma <zheyuma97@gmail.com> Signed-off-by: Ido Plat <ido.plat@ibm.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> Signed-off-by: Gregory Price <gregory.price@memverge.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Lorenz Brun <lorenz@brun.one> Signed-off-by: Yao Xingtao <yaoxt.fnst@fujitsu.com> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Signed-off-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Sven Schnelle <svens@stackframe.org> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Benjamin Gray <bgray@linux.ibm.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Joonas Kankaala <joonas.a.kankaala@gmail.com> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Glenn Miles <milesg@linux.ibm.com> Signed-off-by: Oleg Sviridov <oleg.sviridov@red-soft.ru> Signed-off-by: Artem Chernyshev <artem.chernyshev@red-soft.ru> Signed-off-by: Yajun Wu <yajunw@nvidia.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Pierre-Clément Tosi <ptosi@google.com> Signed-off-by: Lei Wang <lei4.wang@intel.com> Signed-off-by: Wei Wang <wei.w.wang@intel.com> Signed-off-by: Martin Hundebøll <martin@geanix.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Signed-off-by: Wafer <wafer@jaguarmicro.com> Signed-off-by: Yuxue Liu <yuxue.liu@jaguarmicro.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com> Signed-off-by: Zack Buhman <zack@buhman.org> Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Yuquan Wang wangyuquan1236@phytium.com.cn Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com> Signed-off-by: Cindy Lu <lulu@redhat.com> Co-authored-by: Peter Maydell <peter.maydell@linaro.org> Co-authored-by: Fabiano Rosas <farosas@suse.de> Co-authored-by: Peter Xu <peterx@redhat.com> Co-authored-by: Thomas Huth <thuth@redhat.com> Co-authored-by: Cédric Le Goater <clg@redhat.com> Co-authored-by: Zheyu Ma <zheyuma97@gmail.com> Co-authored-by: Ido Plat <ido.plat@ibm.com> Co-authored-by: Ilya Leoshkevich <iii@linux.ibm.com> Co-authored-by: Markus Armbruster <armbru@redhat.com> Co-authored-by: Marc-André Lureau <marcandre.lureau@redhat.com> Co-authored-by: Paolo Bonzini <pbonzini@redhat.com> Co-authored-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Co-authored-by: David Hildenbrand <david@redhat.com> Co-authored-by: Kevin Wolf <kwolf@redhat.com> Co-authored-by: Stefan Reiter <s.reiter@proxmox.com> Co-authored-by: Fiona Ebner <f.ebner@proxmox.com> Co-authored-by: Gregory Price <gregory.price@memverge.com> Co-authored-by: Lorenz Brun <lorenz@brun.one> Co-authored-by: Yao Xingtao <yaoxt.fnst@fujitsu.com> Co-authored-by: Philippe Mathieu-Daudé <philmd@linaro.org> Co-authored-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> Co-authored-by: BALATON Zoltan <balaton@eik.bme.hu> Co-authored-by: Igor Mammedov <imammedo@redhat.com> Co-authored-by: Akihiko Odaki <akihiko.odaki@daynix.com> Co-authored-by: Richard Henderson <richard.henderson@linaro.org> Co-authored-by: Sven Schnelle <svens@stackframe.org> Co-authored-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Co-authored-by: Helge Deller <deller@kernel.org> Co-authored-by: Harsh Prateek Bora <harshpb@linux.ibm.com> Co-authored-by: Benjamin Gray <bgray@linux.ibm.com> Co-authored-by: Nicholas Piggin <npiggin@gmail.com> Co-authored-by: Avihai Horon <avihaih@nvidia.com> Co-authored-by: Michael Tokarev <mjt@tls.msk.ru> Co-authored-by: Joonas Kankaala <joonas.a.kankaala@gmail.com> Co-authored-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Co-authored-by: Stefan Weil <sw@weilnetz.de> Co-authored-by: Dayu Liu <liu.dayu@zte.com.cn> Co-authored-by: Zhao Liu <zhao1.liu@intel.com> Co-authored-by: Glenn Miles <milesg@linux.vnet.ibm.com> Co-authored-by: Artem Chernyshev <artem.chernyshev@red-soft.ru> Co-authored-by: Yajun Wu <yajunw@nvidia.com> Co-authored-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Co-authored-by: Pierre-Clément Tosi <ptosi@google.com> Co-authored-by: Wei Wang <wei.w.wang@intel.com> Co-authored-by: Martin Hundebøll <martin@geanix.com> Co-authored-by: Michael S. Tsirkin <mst@redhat.com> Co-authored-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Co-authored-by: Wafer <wafer@jaguarmicro.com> Co-authored-by: lyx634449800 <yuxue.liu@jaguarmicro.com> Co-authored-by: Gerd Hoffmann <kraxel@redhat.com> Co-authored-by: Nguyen Dinh Phi <phind.uet@gmail.com> Co-authored-by: Zack Buhman <zack@buhman.org> Co-authored-by: Keith Packard <keithp@keithp.com> Co-authored-by: Yuquan Wang <wangyuquan1236@phytium.com.cn> Co-authored-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com> Co-authored-by: Cindy Lu <lulu@redhat.com>
492 lines
15 KiB
C
492 lines
15 KiB
C
/*
|
|
* QTest testcase for PowerNV 10 Host I2C Communications
|
|
*
|
|
* Copyright (c) 2023, IBM Corporation.
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
* later. See the COPYING file in the top-level directory.
|
|
*/
|
|
#include "qemu/osdep.h"
|
|
#include "libqtest.h"
|
|
#include "hw/gpio/pca9554_regs.h"
|
|
#include "hw/gpio/pca9552_regs.h"
|
|
#include "pnv-xscom.h"
|
|
|
|
#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
|
|
#define PPC_BIT32(bit) (0x80000000 >> (bit))
|
|
#define PPC_BIT8(bit) (0x80 >> (bit))
|
|
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
|
|
#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
|
|
PPC_BIT32(bs))
|
|
|
|
#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
|
|
#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
|
|
#define SETFIELD(m, v, val) \
|
|
(((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
|
|
|
|
#define PNV10_XSCOM_I2CM_BASE 0xa0000
|
|
#define PNV10_XSCOM_I2CM_SIZE 0x1000
|
|
|
|
#include "hw/i2c/pnv_i2c_regs.h"
|
|
|
|
typedef struct {
|
|
QTestState *qts;
|
|
const PnvChip *chip;
|
|
int engine;
|
|
} PnvI2cCtlr;
|
|
|
|
typedef struct {
|
|
PnvI2cCtlr *ctlr;
|
|
int port;
|
|
uint8_t addr;
|
|
} PnvI2cDev;
|
|
|
|
|
|
static uint64_t pnv_i2c_xscom_addr(PnvI2cCtlr *ctlr, uint32_t reg)
|
|
{
|
|
return pnv_xscom_addr(ctlr->chip, PNV10_XSCOM_I2CM_BASE +
|
|
(PNV10_XSCOM_I2CM_SIZE * ctlr->engine) + reg);
|
|
}
|
|
|
|
static uint64_t pnv_i2c_xscom_read(PnvI2cCtlr *ctlr, uint32_t reg)
|
|
{
|
|
return qtest_readq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg));
|
|
}
|
|
|
|
static void pnv_i2c_xscom_write(PnvI2cCtlr *ctlr, uint32_t reg, uint64_t val)
|
|
{
|
|
qtest_writeq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg), val);
|
|
}
|
|
|
|
/* Write len bytes from buf to i2c device with given addr and port */
|
|
static void pnv_i2c_send(PnvI2cDev *dev, const uint8_t *buf, uint16_t len)
|
|
{
|
|
int byte_num;
|
|
uint64_t reg64;
|
|
|
|
/* select requested port */
|
|
reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
|
|
reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
|
|
pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
|
|
|
|
/* check status for cmd complete and bus idle */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
|
|
I2C_STAT_CMD_COMP);
|
|
|
|
/* Send start, with stop, with address and len bytes of data */
|
|
reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR | I2C_CMD_WITH_STOP;
|
|
reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
|
|
reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
|
|
pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
|
|
|
|
/* check status for errors */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
|
|
|
|
/* write data bytes to fifo register */
|
|
for (byte_num = 0; byte_num < len; byte_num++) {
|
|
reg64 = SETFIELD(I2C_FIFO, 0ull, buf[byte_num]);
|
|
pnv_i2c_xscom_write(dev->ctlr, I2C_FIFO_REG, reg64);
|
|
}
|
|
|
|
/* check status for cmd complete and bus idle */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
|
|
I2C_STAT_CMD_COMP);
|
|
}
|
|
|
|
/* Recieve len bytes into buf from i2c device with given addr and port */
|
|
static void pnv_i2c_recv(PnvI2cDev *dev, uint8_t *buf, uint16_t len)
|
|
{
|
|
int byte_num;
|
|
uint64_t reg64;
|
|
|
|
/* select requested port */
|
|
reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be);
|
|
reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port);
|
|
pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64);
|
|
|
|
/* check status for cmd complete and bus idle */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
|
|
I2C_STAT_CMD_COMP);
|
|
|
|
/* Send start, with stop, with address and len bytes of data */
|
|
reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR |
|
|
I2C_CMD_WITH_STOP | I2C_CMD_READ_NOT_WRITE;
|
|
reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr);
|
|
reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len);
|
|
pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64);
|
|
|
|
/* check status for errors */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0);
|
|
|
|
/* Read data bytes from fifo register */
|
|
for (byte_num = 0; byte_num < len; byte_num++) {
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_FIFO_REG);
|
|
buf[byte_num] = GETFIELD(I2C_FIFO, reg64);
|
|
}
|
|
|
|
/* check status for cmd complete and bus idle */
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG);
|
|
g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
|
|
reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==,
|
|
I2C_STAT_CMD_COMP);
|
|
}
|
|
|
|
static void pnv_i2c_pca9554_default_cfg(PnvI2cDev *dev)
|
|
{
|
|
uint8_t buf[2];
|
|
|
|
/* input register bits are not inverted */
|
|
buf[0] = PCA9554_POLARITY;
|
|
buf[1] = 0;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
|
|
/* All pins are inputs */
|
|
buf[0] = PCA9554_CONFIG;
|
|
buf[1] = 0xff;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
|
|
/* Output value for when pins are outputs */
|
|
buf[0] = PCA9554_OUTPUT;
|
|
buf[1] = 0xff;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
}
|
|
|
|
static void pnv_i2c_pca9554_set_pin(PnvI2cDev *dev, int pin, bool high)
|
|
{
|
|
uint8_t send_buf[2];
|
|
uint8_t recv_buf[2];
|
|
uint8_t mask = 0x1 << pin;
|
|
uint8_t new_value = ((high) ? 1 : 0) << pin;
|
|
|
|
/* read current OUTPUT value */
|
|
send_buf[0] = PCA9554_OUTPUT;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
|
|
/* write new OUTPUT value */
|
|
send_buf[1] = (recv_buf[0] & ~mask) | new_value;
|
|
pnv_i2c_send(dev, send_buf, 2);
|
|
|
|
/* Update config bit for output */
|
|
send_buf[0] = PCA9554_CONFIG;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
send_buf[1] = recv_buf[0] & ~mask;
|
|
pnv_i2c_send(dev, send_buf, 2);
|
|
}
|
|
|
|
static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev)
|
|
{
|
|
uint8_t send_buf[1];
|
|
uint8_t recv_buf[1];
|
|
uint8_t inputs;
|
|
send_buf[0] = PCA9554_INPUT;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
inputs = recv_buf[0];
|
|
return inputs;
|
|
}
|
|
|
|
static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev)
|
|
{
|
|
uint8_t recv_buf[1];
|
|
uint8_t send_buf[2];
|
|
|
|
send_buf[0] = PCA9554_POLARITY;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
send_buf[1] = recv_buf[0] ^ 0xff;
|
|
pnv_i2c_send(dev, send_buf, 2);
|
|
}
|
|
|
|
static void pnv_i2c_pca9554_default_inputs(PnvI2cDev *dev)
|
|
{
|
|
uint8_t pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0xff);
|
|
}
|
|
|
|
/* Check that setting pin values and polarity changes inputs as expected */
|
|
static void pnv_i2c_pca554_set_pins(PnvI2cDev *dev)
|
|
{
|
|
uint8_t pin_values;
|
|
pnv_i2c_pca9554_set_pin(dev, 0, 0);
|
|
pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0xfe);
|
|
pnv_i2c_pca9554_flip_polarity(dev);
|
|
pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0x01);
|
|
pnv_i2c_pca9554_set_pin(dev, 2, 0);
|
|
pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0x05);
|
|
pnv_i2c_pca9554_flip_polarity(dev);
|
|
pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0xfa);
|
|
pnv_i2c_pca9554_default_cfg(dev);
|
|
pin_values = pnv_i2c_pca9554_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0xff);
|
|
}
|
|
|
|
static void pnv_i2c_pca9552_default_cfg(PnvI2cDev *dev)
|
|
{
|
|
uint8_t buf[2];
|
|
/* configure pwm/psc regs */
|
|
buf[0] = PCA9552_PSC0;
|
|
buf[1] = 0xff;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_PWM0;
|
|
buf[1] = 0x80;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_PSC1;
|
|
buf[1] = 0xff;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_PWM1;
|
|
buf[1] = 0x80;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
|
|
/* configure all pins as inputs */
|
|
buf[0] = PCA9552_LS0;
|
|
buf[1] = 0x55;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_LS1;
|
|
buf[1] = 0x55;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_LS2;
|
|
buf[1] = 0x55;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
buf[0] = PCA9552_LS3;
|
|
buf[1] = 0x55;
|
|
pnv_i2c_send(dev, buf, 2);
|
|
}
|
|
|
|
static void pnv_i2c_pca9552_set_pin(PnvI2cDev *dev, int pin, bool high)
|
|
{
|
|
uint8_t send_buf[2];
|
|
uint8_t recv_buf[2];
|
|
uint8_t reg = PCA9552_LS0 + (pin / 4);
|
|
uint8_t shift = (pin % 4) * 2;
|
|
uint8_t mask = ~(0x3 << shift);
|
|
uint8_t new_value = ((high) ? 1 : 0) << shift;
|
|
|
|
/* read current LSx value */
|
|
send_buf[0] = reg;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
|
|
/* write new value to LSx */
|
|
send_buf[1] = (recv_buf[0] & mask) | new_value;
|
|
pnv_i2c_send(dev, send_buf, 2);
|
|
}
|
|
|
|
static uint16_t pnv_i2c_pca9552_read_pins(PnvI2cDev *dev)
|
|
{
|
|
uint8_t send_buf[2];
|
|
uint8_t recv_buf[2];
|
|
uint16_t inputs;
|
|
send_buf[0] = PCA9552_INPUT0;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
inputs = recv_buf[0];
|
|
send_buf[0] = PCA9552_INPUT1;
|
|
pnv_i2c_send(dev, send_buf, 1);
|
|
pnv_i2c_recv(dev, recv_buf, 1);
|
|
inputs |= recv_buf[0] << 8;
|
|
return inputs;
|
|
}
|
|
|
|
static void pnv_i2c_pca9552_default_inputs(PnvI2cDev *dev)
|
|
{
|
|
uint16_t pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
g_assert_cmphex(pin_values, ==, 0xffff);
|
|
}
|
|
|
|
/*
|
|
* Set pins 0-4 one at a time and verify that pins 5-9 are
|
|
* set to the same value
|
|
*/
|
|
static void pnv_i2c_pca552_set_pins(PnvI2cDev *dev)
|
|
{
|
|
uint16_t pin_values;
|
|
|
|
/* set pin 0 low */
|
|
pnv_i2c_pca9552_set_pin(dev, 0, 0);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* pins 0 and 5 should be low */
|
|
g_assert_cmphex(pin_values, ==, 0xffde);
|
|
|
|
/* set pin 1 low */
|
|
pnv_i2c_pca9552_set_pin(dev, 1, 0);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* pins 0, 1, 5 and 6 should be low */
|
|
g_assert_cmphex(pin_values, ==, 0xff9c);
|
|
|
|
/* set pin 2 low */
|
|
pnv_i2c_pca9552_set_pin(dev, 2, 0);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* pins 0, 1, 2, 5, 6 and 7 should be low */
|
|
g_assert_cmphex(pin_values, ==, 0xff18);
|
|
|
|
/* set pin 3 low */
|
|
pnv_i2c_pca9552_set_pin(dev, 3, 0);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* pins 0, 1, 2, 3, 5, 6, 7 and 8 should be low */
|
|
g_assert_cmphex(pin_values, ==, 0xfe10);
|
|
|
|
/* set pin 4 low */
|
|
pnv_i2c_pca9552_set_pin(dev, 4, 0);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* pins 0, 1, 2, 3, 5, 6, 7, 8 and 9 should be low */
|
|
g_assert_cmphex(pin_values, ==, 0xfc00);
|
|
|
|
/* reset all pins to the high state */
|
|
pnv_i2c_pca9552_default_cfg(dev);
|
|
pin_values = pnv_i2c_pca9552_read_pins(dev);
|
|
|
|
/* verify all pins went back to the high state */
|
|
g_assert_cmphex(pin_values, ==, 0xffff);
|
|
}
|
|
|
|
static void reset_engine(PnvI2cCtlr *ctlr)
|
|
{
|
|
pnv_i2c_xscom_write(ctlr, I2C_RESET_I2C_REG, 0);
|
|
}
|
|
|
|
static void check_i2cm_por_regs(QTestState *qts, const PnvChip *chip)
|
|
{
|
|
int engine;
|
|
for (engine = 0; engine < chip->num_i2c; engine++) {
|
|
PnvI2cCtlr ctlr;
|
|
ctlr.qts = qts;
|
|
ctlr.chip = chip;
|
|
ctlr.engine = engine;
|
|
|
|
/* Check version in Extended Status Register */
|
|
uint64_t value = pnv_i2c_xscom_read(&ctlr, I2C_EXTD_STAT_REG);
|
|
g_assert_cmphex(value & I2C_EXTD_STAT_I2C_VERSION, ==, 0x1700000000);
|
|
|
|
/* Check for command complete and bus idle in Status Register */
|
|
value = pnv_i2c_xscom_read(&ctlr, I2C_STAT_REG);
|
|
g_assert_cmphex(value & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP),
|
|
==,
|
|
I2C_STAT_CMD_COMP);
|
|
}
|
|
}
|
|
|
|
static void reset_all(QTestState *qts, const PnvChip *chip)
|
|
{
|
|
int engine;
|
|
for (engine = 0; engine < chip->num_i2c; engine++) {
|
|
PnvI2cCtlr ctlr;
|
|
ctlr.qts = qts;
|
|
ctlr.chip = chip;
|
|
ctlr.engine = engine;
|
|
reset_engine(&ctlr);
|
|
pnv_i2c_xscom_write(&ctlr, I2C_MODE_REG, 0x02be040000000000);
|
|
}
|
|
}
|
|
|
|
static void test_host_i2c(const void *data)
|
|
{
|
|
const PnvChip *chip = data;
|
|
QTestState *qts;
|
|
const char *machine = "powernv8";
|
|
PnvI2cCtlr ctlr;
|
|
PnvI2cDev pca9552;
|
|
PnvI2cDev pca9554;
|
|
|
|
if (chip->chip_type == PNV_CHIP_POWER9) {
|
|
machine = "powernv9";
|
|
} else if (chip->chip_type == PNV_CHIP_POWER10) {
|
|
machine = "powernv10-rainier";
|
|
}
|
|
|
|
qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic "
|
|
"-nodefaults -serial mon:stdio -S "
|
|
"-d guest_errors",
|
|
machine, SMT, SMT);
|
|
|
|
/* Check the I2C master status registers after POR */
|
|
check_i2cm_por_regs(qts, chip);
|
|
|
|
/* Now do a forced "immediate" reset on all engines */
|
|
reset_all(qts, chip);
|
|
|
|
/* Check that the status values are still good */
|
|
check_i2cm_por_regs(qts, chip);
|
|
|
|
/* P9 doesn't have any i2c devices attached at this time */
|
|
if (chip->chip_type != PNV_CHIP_POWER10) {
|
|
qtest_quit(qts);
|
|
return;
|
|
}
|
|
|
|
/* Initialize for a P10 pca9552 hotplug device */
|
|
ctlr.qts = qts;
|
|
ctlr.chip = chip;
|
|
ctlr.engine = 2;
|
|
pca9552.ctlr = &ctlr;
|
|
pca9552.port = 1;
|
|
pca9552.addr = 0x63;
|
|
|
|
/* Set all pca9552 pins as inputs */
|
|
pnv_i2c_pca9552_default_cfg(&pca9552);
|
|
|
|
/* Check that all pins of the pca9552 are high */
|
|
pnv_i2c_pca9552_default_inputs(&pca9552);
|
|
|
|
/* perform individual pin tests */
|
|
pnv_i2c_pca552_set_pins(&pca9552);
|
|
|
|
/* Initialize for a P10 pca9554 CableCard Presence detection device */
|
|
pca9554.ctlr = &ctlr;
|
|
pca9554.port = 1;
|
|
pca9554.addr = 0x25;
|
|
|
|
/* Set all pca9554 pins as inputs */
|
|
pnv_i2c_pca9554_default_cfg(&pca9554);
|
|
|
|
/* Check that all pins of the pca9554 are high */
|
|
pnv_i2c_pca9554_default_inputs(&pca9554);
|
|
|
|
/* perform individual pin tests */
|
|
pnv_i2c_pca554_set_pins(&pca9554);
|
|
|
|
qtest_quit(qts);
|
|
}
|
|
|
|
static void add_test(const char *name, void (*test)(const void *data))
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) {
|
|
char *tname = g_strdup_printf("pnv-xscom/%s/%s", name,
|
|
pnv_chips[i].cpu_model);
|
|
qtest_add_data_func(tname, &pnv_chips[i], test);
|
|
g_free(tname);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
g_test_init(&argc, &argv, NULL);
|
|
|
|
add_test("host-i2c", test_host_i2c);
|
|
return g_test_run();
|
|
}
|