* [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-15 7:28 ` Cédric Le Goater
2023-11-14 19:56 ` [PATCH v3 2/8] ppc/pnv: Wire up pca9552 GPIO pins " Glenn Miles
` (7 subsequent siblings)
8 siblings, 1 reply; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
The Power Hypervisor code expects to see a pca9552 device connected
to the 3rd PNV I2C engine on port 1 at I2C address 0x63 (or left-
justified address of 0xC6). This is used by hypervisor code to
control PCIe slot power during hotplug events.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
Based-on: <20231024181144.4045056-3-milesg@linux.vnet.ibm.com>
[PATCH v3 2/2] misc/pca9552: Let external devices set pca9552 inputs
No changes from v2
hw/ppc/Kconfig | 1 +
hw/ppc/pnv.c | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 56f0475a8e..f77ca773cf 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -32,6 +32,7 @@ config POWERNV
select XIVE
select FDT_PPC
select PCI_POWERNV
+ select PCA9552
config PPC405
bool
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 9c29727337..7afaf1008f 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1877,6 +1877,13 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&chip10->psi),
PSIHB9_IRQ_SBE_I2C));
}
+
+ /*
+ * Add a PCA9552 I2C device for PCIe hotplug control
+ * to engine 2, bus 1, address 0x63
+ */
+ i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9552", 0x63);
+
}
static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-14 19:56 ` [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control Glenn Miles
@ 2023-11-15 7:28 ` Cédric Le Goater
2023-11-15 16:37 ` Miles Glenn
0 siblings, 1 reply; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-15 7:28 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On 11/14/23 20:56, Glenn Miles wrote:
> The Power Hypervisor code expects to see a pca9552 device connected
> to the 3rd PNV I2C engine on port 1 at I2C address 0x63 (or left-
> justified address of 0xC6). This is used by hypervisor code to
> control PCIe slot power during hotplug events.
>
> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> ---
> Based-on: <20231024181144.4045056-3-milesg@linux.vnet.ibm.com>
> [PATCH v3 2/2] misc/pca9552: Let external devices set pca9552 inputs
>
> No changes from v2
>
> hw/ppc/Kconfig | 1 +
> hw/ppc/pnv.c | 7 +++++++
> 2 files changed, 8 insertions(+)
>
> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> index 56f0475a8e..f77ca773cf 100644
> --- a/hw/ppc/Kconfig
> +++ b/hw/ppc/Kconfig
> @@ -32,6 +32,7 @@ config POWERNV
> select XIVE
> select FDT_PPC
> select PCI_POWERNV
> + select PCA9552
>
> config PPC405
> bool
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 9c29727337..7afaf1008f 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -1877,6 +1877,13 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> qdev_get_gpio_in(DEVICE(&chip10->psi),
> PSIHB9_IRQ_SBE_I2C));
> }
> +
> + /*
> + * Add a PCA9552 I2C device for PCIe hotplug control
> + * to engine 2, bus 1, address 0x63
> + */
> + i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9552", 0x63);
You didn't answer my question in v2. Is this a P10 chip device or a
board/machine device ?
Thanks,
C.
> }
>
> static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-15 7:28 ` Cédric Le Goater
@ 2023-11-15 16:37 ` Miles Glenn
2023-11-15 22:34 ` Cédric Le Goater
0 siblings, 1 reply; 20+ messages in thread
From: Miles Glenn @ 2023-11-15 16:37 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On Wed, 2023-11-15 at 08:28 +0100, Cédric Le Goater wrote:
> On 11/14/23 20:56, Glenn Miles wrote:
> > The Power Hypervisor code expects to see a pca9552 device connected
> > to the 3rd PNV I2C engine on port 1 at I2C address 0x63 (or left-
> > justified address of 0xC6). This is used by hypervisor code to
> > control PCIe slot power during hotplug events.
> >
> > Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> > ---
> > Based-on: <20231024181144.4045056-3-milesg@linux.vnet.ibm.com>
> > [PATCH v3 2/2] misc/pca9552: Let external devices set pca9552
> > inputs
> >
> > No changes from v2
> >
> > hw/ppc/Kconfig | 1 +
> > hw/ppc/pnv.c | 7 +++++++
> > 2 files changed, 8 insertions(+)
> >
> > diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> > index 56f0475a8e..f77ca773cf 100644
> > --- a/hw/ppc/Kconfig
> > +++ b/hw/ppc/Kconfig
> > @@ -32,6 +32,7 @@ config POWERNV
> > select XIVE
> > select FDT_PPC
> > select PCI_POWERNV
> > + select PCA9552
> >
> > config PPC405
> > bool
> > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> > index 9c29727337..7afaf1008f 100644
> > --- a/hw/ppc/pnv.c
> > +++ b/hw/ppc/pnv.c
> > @@ -1877,6 +1877,13 @@ static void
> > pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> > qdev_get_gpio_in(DEVICE(&chip10-
> > >psi),
> > PSIHB9_IRQ_SBE_I2C
> > ));
> > }
> > +
> > + /*
> > + * Add a PCA9552 I2C device for PCIe hotplug control
> > + * to engine 2, bus 1, address 0x63
> > + */
> > + i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9552",
> > 0x63);
>
> You didn't answer my question in v2. Is this a P10 chip device or a
> board/machine device ?
>
> Thanks,
>
> C.
>
>
Sorry, you're right, I did miss that one, and after looking at the
Denali spec, I see that the topology is indeed different from Rainier
(which is what I have been modeling). For the Denali, the PCA9552
has a different I2C address (0x62 instead of 0x63) and the GPIO
connections are also different. Also, there is no PCA9554 chip because
it looks like they were able to cover all of the functionality with
just the GPIO's of the PCA9552. So, good catch!
I'll look at what they did on the Aspeed machines like you suggested.
Thanks,
Glenn
>
> > }
> >
> > static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip,
> > uint64_t addr)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-15 16:37 ` Miles Glenn
@ 2023-11-15 22:34 ` Cédric Le Goater
2023-11-16 22:43 ` Miles Glenn
0 siblings, 1 reply; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-15 22:34 UTC (permalink / raw)
To: Miles Glenn, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On 11/15/23 17:37, Miles Glenn wrote:
> On Wed, 2023-11-15 at 08:28 +0100, Cédric Le Goater wrote:
>> On 11/14/23 20:56, Glenn Miles wrote:
>>> The Power Hypervisor code expects to see a pca9552 device connected
>>> to the 3rd PNV I2C engine on port 1 at I2C address 0x63 (or left-
>>> justified address of 0xC6). This is used by hypervisor code to
>>> control PCIe slot power during hotplug events.
>>>
>>> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
>>> ---
>>> Based-on: <20231024181144.4045056-3-milesg@linux.vnet.ibm.com>
>>> [PATCH v3 2/2] misc/pca9552: Let external devices set pca9552
>>> inputs
>>>
>>> No changes from v2
>>>
>>> hw/ppc/Kconfig | 1 +
>>> hw/ppc/pnv.c | 7 +++++++
>>> 2 files changed, 8 insertions(+)
>>>
>>> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
>>> index 56f0475a8e..f77ca773cf 100644
>>> --- a/hw/ppc/Kconfig
>>> +++ b/hw/ppc/Kconfig
>>> @@ -32,6 +32,7 @@ config POWERNV
>>> select XIVE
>>> select FDT_PPC
>>> select PCI_POWERNV
>>> + select PCA9552
>>>
>>> config PPC405
>>> bool
>>> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
>>> index 9c29727337..7afaf1008f 100644
>>> --- a/hw/ppc/pnv.c
>>> +++ b/hw/ppc/pnv.c
>>> @@ -1877,6 +1877,13 @@ static void
>>> pnv_chip_power10_realize(DeviceState *dev, Error **errp)
>>> qdev_get_gpio_in(DEVICE(&chip10-
>>>> psi),
>>> PSIHB9_IRQ_SBE_I2C
>>> ));
>>> }
>>> +
>>> + /*
>>> + * Add a PCA9552 I2C device for PCIe hotplug control
>>> + * to engine 2, bus 1, address 0x63
>>> + */
>>> + i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9552",
>>> 0x63);
>>
>> You didn't answer my question in v2. Is this a P10 chip device or a
>> board/machine device ?
>>
>> Thanks,
>>
>> C.
>>
>>
>
> Sorry, you're right, I did miss that one, and after looking at the
> Denali spec, I see that the topology is indeed different from Rainier
> (which is what I have been modeling). For the Denali, the PCA9552
> has a different I2C address (0x62 instead of 0x63) and the GPIO
> connections are also different. Also, there is no PCA9554 chip because
> it looks like they were able to cover all of the functionality with
> just the GPIO's of the PCA9552. So, good catch!
>
> I'll look at what they did on the Aspeed machines like you suggested.
It should be a machine class extension with an i2c_setup handler and
a new "powernv10-rainier" machine modeling the board layout. The rest
looks good.
Please include the pca9552 series in the respin. The pca9554 model will
need a MAINTAINER (you?) I would be happy to let you take over pca9552
if you agree.
First, let's get patch 3 and 4 in QEMU 8.2.
Thanks,
C.
>
> Thanks,
>
> Glenn
>
>>
>>> }
>>>
>>> static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip,
>>> uint64_t addr)
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-15 22:34 ` Cédric Le Goater
@ 2023-11-16 22:43 ` Miles Glenn
2023-11-17 16:04 ` Cédric Le Goater
0 siblings, 1 reply; 20+ messages in thread
From: Miles Glenn @ 2023-11-16 22:43 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On Wed, 2023-11-15 at 23:34 +0100, Cédric Le Goater wrote:
> On 11/15/23 17:37, Miles Glenn wrote:
> > On Wed, 2023-11-15 at 08:28 +0100, Cédric Le Goater wrote:
> > > On 11/14/23 20:56, Glenn Miles wrote:
> > > > The Power Hypervisor code expects to see a pca9552 device
> > > > connected
> > > > to the 3rd PNV I2C engine on port 1 at I2C address 0x63 (or
> > > > left-
> > > > justified address of 0xC6). This is used by hypervisor code to
> > > > control PCIe slot power during hotplug events.
> > > >
> > > > Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> > > > ---
> > > > Based-on: <20231024181144.4045056-3-milesg@linux.vnet.ibm.com>
> > > > [PATCH v3 2/2] misc/pca9552: Let external devices set pca9552
> > > > inputs
> > > >
> > > > No changes from v2
> > > >
> > > > hw/ppc/Kconfig | 1 +
> > > > hw/ppc/pnv.c | 7 +++++++
> > > > 2 files changed, 8 insertions(+)
> > > >
> > > > diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
> > > > index 56f0475a8e..f77ca773cf 100644
> > > > --- a/hw/ppc/Kconfig
> > > > +++ b/hw/ppc/Kconfig
> > > > @@ -32,6 +32,7 @@ config POWERNV
> > > > select XIVE
> > > > select FDT_PPC
> > > > select PCI_POWERNV
> > > > + select PCA9552
> > > >
> > > > config PPC405
> > > > bool
> > > > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> > > > index 9c29727337..7afaf1008f 100644
> > > > --- a/hw/ppc/pnv.c
> > > > +++ b/hw/ppc/pnv.c
> > > > @@ -1877,6 +1877,13 @@ static void
> > > > pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> > > > qdev_get_gpio_in(DEVICE(&chip1
> > > > 0-
> > > > > psi),
> > > > PSIHB9_IRQ_SB
> > > > E_I2C
> > > > ));
> > > > }
> > > > +
> > > > + /*
> > > > + * Add a PCA9552 I2C device for PCIe hotplug control
> > > > + * to engine 2, bus 1, address 0x63
> > > > + */
> > > > + i2c_slave_create_simple(chip10->i2c[2].busses[1],
> > > > "pca9552",
> > > > 0x63);
> > >
> > > You didn't answer my question in v2. Is this a P10 chip device or
> > > a
> > > board/machine device ?
> > >
> > > Thanks,
> > >
> > > C.
> > >
> > >
> >
> > Sorry, you're right, I did miss that one, and after looking at the
> > Denali spec, I see that the topology is indeed different from
> > Rainier
> > (which is what I have been modeling). For the Denali, the PCA9552
> > has a different I2C address (0x62 instead of 0x63) and the GPIO
> > connections are also different. Also, there is no PCA9554 chip
> > because
> > it looks like they were able to cover all of the functionality with
> > just the GPIO's of the PCA9552. So, good catch!
> >
> > I'll look at what they did on the Aspeed machines like you
> > suggested.
>
> It should be a machine class extension with an i2c_setup handler and
> a new "powernv10-rainier" machine modeling the board layout. The rest
> looks good.
>
> Please include the pca9552 series in the respin. The pca9554 model
> will
> need a MAINTAINER (you?) I would be happy to let you take over
> pca9552
> if you agree.
>
> First, let's get patch 3 and 4 in QEMU 8.2.
>
> Thanks,
>
> C.
>
>
Well, I was hoping to sweep the pca9554 model under the PowerNV
maintainership (like pca9552 is under the BMC aspeed maintainership).
I did update the PowerNV list to include it, but perhaps that was
presumptuous of me. :-)
I would be ok with being added as a reviewer under the PowerNV list,
but I wonder if I shouldn't have more opensource experience before
becoming a maintainer? TBH, I have no idea what that would entail.
As for patches 3 and 4, it sounds like I should split those changes out
from the current patch series so that they can make it into QEMU 8.2.
Correct?
Thanks,
Glenn
>
>
> > Thanks,
> >
> > Glenn
> >
> > > > }
> > > >
> > > > static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip,
> > > > uint64_t addr)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-16 22:43 ` Miles Glenn
@ 2023-11-17 16:04 ` Cédric Le Goater
2023-11-17 19:08 ` Miles Glenn
0 siblings, 1 reply; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-17 16:04 UTC (permalink / raw)
To: Miles Glenn, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
> Well, I was hoping to sweep the pca9554 model under the PowerNV
> maintainership (like pca9552 is under the BMC aspeed maintainership).
> I did update the PowerNV list to include it, but perhaps that was
> presumptuous of me. :-)
Well, you are the person who has the most knowledge on both and
you have access to HW to check changes !
> I would be ok with being added as a reviewer under the PowerNV list,
> but I wonder if I shouldn't have more opensource experience before
> becoming a maintainer? TBH, I have no idea what that would entail.
For these devices, mostly acking the changes. I don't think anyone
will ask you to send PRs. This can be handled through some other
tree, PPC or Aspeed.
> As for patches 3 and 4, it sounds like I should split those changes out
> from the current patch series so that they can make it into QEMU 8.2.
> Correct?
I don't think this is needed. They can be picked in the series and
merged in the ppc tree independently.
Thanks,
C.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
2023-11-17 16:04 ` Cédric Le Goater
@ 2023-11-17 19:08 ` Miles Glenn
0 siblings, 0 replies; 20+ messages in thread
From: Miles Glenn @ 2023-11-17 19:08 UTC (permalink / raw)
To: Cédric Le Goater, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On Fri, 2023-11-17 at 17:04 +0100, Cédric Le Goater wrote:
> > Well, I was hoping to sweep the pca9554 model under the PowerNV
> > maintainership (like pca9552 is under the BMC aspeed
> > maintainership).
> > I did update the PowerNV list to include it, but perhaps that was
> > presumptuous of me. :-)
>
> Well, you are the person who has the most knowledge on both and
> you have access to HW to check changes !
>
> > I would be ok with being added as a reviewer under the PowerNV
> > list,
> > but I wonder if I shouldn't have more opensource experience before
> > becoming a maintainer? TBH, I have no idea what that would entail.
>
> For these devices, mostly acking the changes. I don't think anyone
> will ask you to send PRs. This can be handled through some other
> tree, PPC or Aspeed.
>
Ok, that doesn't sound too bad. Sign me up!
>
> > As for patches 3 and 4, it sounds like I should split those changes
> > out
> > from the current patch series so that they can make it into QEMU
> > 8.2.
> > Correct?
>
> I don't think this is needed. They can be picked in the series and
> merged in the ppc tree independently.
>
> Thanks,
>
> C.
>
Ok, sounds good.
Thanks,
Glenn
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 2/8] ppc/pnv: Wire up pca9552 GPIO pins for PCIe hotplug power control
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
2023-11-14 19:56 ` [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-14 19:56 ` [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses Glenn Miles
` (6 subsequent siblings)
8 siblings, 0 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
For power10, a pca9552 device is used for PCIe slot hotplug power
control by the Power Hypervisor code. The code expects that some
time after it enables power to a PCIe slot by asserting one of the
pca9552 GPIO pins 0-4, it should see a "power good" signal asserted
on one of pca9552 GPIO pins 5-9.
To simulate this behavior, we simply connect the GPIO outputs for
pins 0-4 to the GPIO inputs for pins 5-9.
Each PCIe slot is assigned 3 GPIO pins on the pca9552 device, for
control of up to 5 PCIe slots. The per-slot signal names are:
SLOTx_EN.......PHYP uses this as an output to enable
slot power. We connect this to the
SLOTx_PG pin to simulate a PGOOD signal.
SLOTx_PG.......PHYP uses this as in input to detect
PGOOD for the slot. For our purposes
we just connect this to the SLOTx_EN
output.
SLOTx_Control..PHYP uses this as an output to prevent
a race condition in the real hotplug
circuitry, but we can ignore this output
for simulation.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
Changes from previous version:
- Fixed formatting errors
hw/ppc/pnv.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 7afaf1008f..645379d5bf 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1882,7 +1882,24 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
* Add a PCA9552 I2C device for PCIe hotplug control
* to engine 2, bus 1, address 0x63
*/
- i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9552", 0x63);
+ I2CSlave *hotplug = i2c_slave_create_simple(chip10->i2c[2].busses[1],
+ "pca9552", 0x63);
+
+ /*
+ * Connect PCA9552 GPIO pins 0-4 (SLOTx_EN) outputs to GPIO pins 5-9
+ * (SLOTx_PG) inputs in order to fake the pgood state of PCIe slots after
+ * hypervisor code sets a SLOTx_EN pin high.
+ */
+ qdev_connect_gpio_out(DEVICE(hotplug), 0,
+ qdev_get_gpio_in(DEVICE(hotplug), 5));
+ qdev_connect_gpio_out(DEVICE(hotplug), 1,
+ qdev_get_gpio_in(DEVICE(hotplug), 6));
+ qdev_connect_gpio_out(DEVICE(hotplug), 2,
+ qdev_get_gpio_in(DEVICE(hotplug), 7));
+ qdev_connect_gpio_out(DEVICE(hotplug), 3,
+ qdev_get_gpio_in(DEVICE(hotplug), 8));
+ qdev_connect_gpio_out(DEVICE(hotplug), 4,
+ qdev_get_gpio_in(DEVICE(hotplug), 9));
}
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
2023-11-14 19:56 ` [PATCH v3 1/8] ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control Glenn Miles
2023-11-14 19:56 ` [PATCH v3 2/8] ppc/pnv: Wire up pca9552 GPIO pins " Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-15 22:19 ` Cédric Le Goater
2023-11-18 7:36 ` Cédric Le Goater
2023-11-14 19:56 ` [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset Glenn Miles
` (5 subsequent siblings)
8 siblings, 2 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
The PNV I2C engines for power9 and power10 were being assigned a base
XSCOM address that was off by one I2C engine's address range such
that engine 0 had engine 1's address and so on. The xscom address
assignment was being based on the device tree engine numbering, which
starts at 1. Rather than changing the device tree numbering to start
with 0, the addressing was changed to be based on the existing device
tree numbers minus one.
Fixes: 1ceda19c28a1 ("ppc/pnv: Connect PNV I2C controller to powernv10)
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
Changes from v2:
- Added Fixes: tag
hw/ppc/pnv.c | 6 ++++--
hw/ppc/pnv_i2c.c | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 645379d5bf..e82e9b30ec 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1623,7 +1623,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
return;
}
pnv_xscom_add_subregion(chip, PNV9_XSCOM_I2CM_BASE +
- chip9->i2c[i].engine * PNV9_XSCOM_I2CM_SIZE,
+ (chip9->i2c[i].engine - 1) *
+ PNV9_XSCOM_I2CM_SIZE,
&chip9->i2c[i].xscom_regs);
qdev_connect_gpio_out(DEVICE(&chip9->i2c[i]), 0,
qdev_get_gpio_in(DEVICE(&chip9->psi),
@@ -1871,7 +1872,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
return;
}
pnv_xscom_add_subregion(chip, PNV10_XSCOM_I2CM_BASE +
- chip10->i2c[i].engine * PNV10_XSCOM_I2CM_SIZE,
+ (chip10->i2c[i].engine - 1) *
+ PNV10_XSCOM_I2CM_SIZE,
&chip10->i2c[i].xscom_regs);
qdev_connect_gpio_out(DEVICE(&chip10->i2c[i]), 0,
qdev_get_gpio_in(DEVICE(&chip10->psi),
diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
index f75e59e709..b2c738da50 100644
--- a/hw/ppc/pnv_i2c.c
+++ b/hw/ppc/pnv_i2c.c
@@ -593,7 +593,7 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
int i2c_offset;
const char i2c_compat[] = "ibm,power8-i2cm\0ibm,power9-i2cm";
uint32_t i2c_pcba = PNV9_XSCOM_I2CM_BASE +
- i2c->engine * PNV9_XSCOM_I2CM_SIZE;
+ (i2c->engine - 1) * PNV9_XSCOM_I2CM_SIZE;
uint32_t reg[2] = {
cpu_to_be32(i2c_pcba),
cpu_to_be32(PNV9_XSCOM_I2CM_SIZE)
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses
2023-11-14 19:56 ` [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses Glenn Miles
@ 2023-11-15 22:19 ` Cédric Le Goater
2023-11-18 7:36 ` Cédric Le Goater
1 sibling, 0 replies; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-15 22:19 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On 11/14/23 20:56, Glenn Miles wrote:
> The PNV I2C engines for power9 and power10 were being assigned a base
> XSCOM address that was off by one I2C engine's address range such
> that engine 0 had engine 1's address and so on. The xscom address
> assignment was being based on the device tree engine numbering, which
> starts at 1. Rather than changing the device tree numbering to start
> with 0, the addressing was changed to be based on the existing device
> tree numbers minus one.
>
> Fixes: 1ceda19c28a1 ("ppc/pnv: Connect PNV I2C controller to powernv10)
> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> ---
This is 8.2 material.
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Thanks,
C.
>
> Changes from v2:
> - Added Fixes: tag
>
> hw/ppc/pnv.c | 6 ++++--
> hw/ppc/pnv_i2c.c | 2 +-
> 2 files changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 645379d5bf..e82e9b30ec 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -1623,7 +1623,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> return;
> }
> pnv_xscom_add_subregion(chip, PNV9_XSCOM_I2CM_BASE +
> - chip9->i2c[i].engine * PNV9_XSCOM_I2CM_SIZE,
> + (chip9->i2c[i].engine - 1) *
> + PNV9_XSCOM_I2CM_SIZE,
> &chip9->i2c[i].xscom_regs);
> qdev_connect_gpio_out(DEVICE(&chip9->i2c[i]), 0,
> qdev_get_gpio_in(DEVICE(&chip9->psi),
> @@ -1871,7 +1872,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> return;
> }
> pnv_xscom_add_subregion(chip, PNV10_XSCOM_I2CM_BASE +
> - chip10->i2c[i].engine * PNV10_XSCOM_I2CM_SIZE,
> + (chip10->i2c[i].engine - 1) *
> + PNV10_XSCOM_I2CM_SIZE,
> &chip10->i2c[i].xscom_regs);
> qdev_connect_gpio_out(DEVICE(&chip10->i2c[i]), 0,
> qdev_get_gpio_in(DEVICE(&chip10->psi),
> diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
> index f75e59e709..b2c738da50 100644
> --- a/hw/ppc/pnv_i2c.c
> +++ b/hw/ppc/pnv_i2c.c
> @@ -593,7 +593,7 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
> int i2c_offset;
> const char i2c_compat[] = "ibm,power8-i2cm\0ibm,power9-i2cm";
> uint32_t i2c_pcba = PNV9_XSCOM_I2CM_BASE +
> - i2c->engine * PNV9_XSCOM_I2CM_SIZE;
> + (i2c->engine - 1) * PNV9_XSCOM_I2CM_SIZE;
> uint32_t reg[2] = {
> cpu_to_be32(i2c_pcba),
> cpu_to_be32(PNV9_XSCOM_I2CM_SIZE)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses
2023-11-14 19:56 ` [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses Glenn Miles
2023-11-15 22:19 ` Cédric Le Goater
@ 2023-11-18 7:36 ` Cédric Le Goater
1 sibling, 0 replies; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-18 7:36 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
Nick,
Since I started collecting fixes for 8.2 while you were away, I will
finish this cycle with a last PR next week and let you take over 9.0.
On 11/14/23 20:56, Glenn Miles wrote:
> The PNV I2C engines for power9 and power10 were being assigned a base
> XSCOM address that was off by one I2C engine's address range such
> that engine 0 had engine 1's address and so on. The xscom address
> assignment was being based on the device tree engine numbering, which
> starts at 1. Rather than changing the device tree numbering to start
> with 0, the addressing was changed to be based on the existing device
> tree numbers minus one.
>
> Fixes: 1ceda19c28a1 ("ppc/pnv: Connect PNV I2C controller to powernv10)
> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> ---
>
> Changes from v2:
> - Added Fixes: tag
Applied to ppc-next.
Thanks,
C.
>
> hw/ppc/pnv.c | 6 ++++--
> hw/ppc/pnv_i2c.c | 2 +-
> 2 files changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 645379d5bf..e82e9b30ec 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -1623,7 +1623,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
> return;
> }
> pnv_xscom_add_subregion(chip, PNV9_XSCOM_I2CM_BASE +
> - chip9->i2c[i].engine * PNV9_XSCOM_I2CM_SIZE,
> + (chip9->i2c[i].engine - 1) *
> + PNV9_XSCOM_I2CM_SIZE,
> &chip9->i2c[i].xscom_regs);
> qdev_connect_gpio_out(DEVICE(&chip9->i2c[i]), 0,
> qdev_get_gpio_in(DEVICE(&chip9->psi),
> @@ -1871,7 +1872,8 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
> return;
> }
> pnv_xscom_add_subregion(chip, PNV10_XSCOM_I2CM_BASE +
> - chip10->i2c[i].engine * PNV10_XSCOM_I2CM_SIZE,
> + (chip10->i2c[i].engine - 1) *
> + PNV10_XSCOM_I2CM_SIZE,
> &chip10->i2c[i].xscom_regs);
> qdev_connect_gpio_out(DEVICE(&chip10->i2c[i]), 0,
> qdev_get_gpio_in(DEVICE(&chip10->psi),
> diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
> index f75e59e709..b2c738da50 100644
> --- a/hw/ppc/pnv_i2c.c
> +++ b/hw/ppc/pnv_i2c.c
> @@ -593,7 +593,7 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
> int i2c_offset;
> const char i2c_compat[] = "ibm,power8-i2cm\0ibm,power9-i2cm";
> uint32_t i2c_pcba = PNV9_XSCOM_I2CM_BASE +
> - i2c->engine * PNV9_XSCOM_I2CM_SIZE;
> + (i2c->engine - 1) * PNV9_XSCOM_I2CM_SIZE;
> uint32_t reg[2] = {
> cpu_to_be32(i2c_pcba),
> cpu_to_be32(PNV9_XSCOM_I2CM_SIZE)
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (2 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 3/8] ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-15 22:20 ` Cédric Le Goater
2023-11-18 7:36 ` Cédric Le Goater
2023-11-14 19:56 ` [PATCH v3 5/8] ppc/pnv: Use resettable interface to reset child I2C buses Glenn Miles
` (4 subsequent siblings)
8 siblings, 2 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
The PNV I2C Controller was clearing the status register
after a reset without repopulating the "upper threshold
for I2C ports", "Command Complete" and the SCL/SDA input
level fields.
Fixed this for resets caused by a system reset as well
as from writing to the "Immediate Reset" register.
Fixes: 263b81ee15af ("ppc/pnv: Add an I2C controller model")
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
Changes from v2:
-Added Fixes: tag
hw/ppc/pnv_i2c.c | 42 ++++++++++++++++++------------------------
1 file changed, 18 insertions(+), 24 deletions(-)
diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
index b2c738da50..f80589157b 100644
--- a/hw/ppc/pnv_i2c.c
+++ b/hw/ppc/pnv_i2c.c
@@ -462,6 +462,23 @@ static uint64_t pnv_i2c_xscom_read(void *opaque, hwaddr addr,
return val;
}
+static void pnv_i2c_reset(void *dev)
+{
+ PnvI2C *i2c = PNV_I2C(dev);
+
+ memset(i2c->regs, 0, sizeof(i2c->regs));
+
+ i2c->regs[I2C_STAT_REG] =
+ SETFIELD(I2C_STAT_UPPER_THRS, 0ull, i2c->num_busses - 1) |
+ I2C_STAT_CMD_COMP | I2C_STAT_SCL_INPUT_LEVEL |
+ I2C_STAT_SDA_INPUT_LEVEL;
+ i2c->regs[I2C_EXTD_STAT_REG] =
+ SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
+ SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
+
+ fifo8_reset(&i2c->fifo);
+}
+
static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -499,16 +516,7 @@ static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
break;
case I2C_RESET_I2C_REG:
- i2c->regs[I2C_MODE_REG] = 0;
- i2c->regs[I2C_CMD_REG] = 0;
- i2c->regs[I2C_WATERMARK_REG] = 0;
- i2c->regs[I2C_INTR_MASK_REG] = 0;
- i2c->regs[I2C_INTR_COND_REG] = 0;
- i2c->regs[I2C_INTR_RAW_COND_REG] = 0;
- i2c->regs[I2C_STAT_REG] = 0;
- i2c->regs[I2C_RESIDUAL_LEN_REG] = 0;
- i2c->regs[I2C_EXTD_STAT_REG] &=
- (I2C_EXTD_STAT_FIFO_SIZE | I2C_EXTD_STAT_I2C_VERSION);
+ pnv_i2c_reset(i2c);
break;
case I2C_RESET_ERRORS:
@@ -620,20 +628,6 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
-static void pnv_i2c_reset(void *dev)
-{
- PnvI2C *i2c = PNV_I2C(dev);
-
- memset(i2c->regs, 0, sizeof(i2c->regs));
-
- i2c->regs[I2C_STAT_REG] = I2C_STAT_CMD_COMP;
- i2c->regs[I2C_EXTD_STAT_REG] =
- SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
- SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
-
- fifo8_reset(&i2c->fifo);
-}
-
static void pnv_i2c_realize(DeviceState *dev, Error **errp)
{
PnvI2C *i2c = PNV_I2C(dev);
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset
2023-11-14 19:56 ` [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset Glenn Miles
@ 2023-11-15 22:20 ` Cédric Le Goater
2023-11-18 7:36 ` Cédric Le Goater
1 sibling, 0 replies; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-15 22:20 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On 11/14/23 20:56, Glenn Miles wrote:
> The PNV I2C Controller was clearing the status register
> after a reset without repopulating the "upper threshold
> for I2C ports", "Command Complete" and the SCL/SDA input
> level fields.
>
> Fixed this for resets caused by a system reset as well
> as from writing to the "Immediate Reset" register.
>
> Fixes: 263b81ee15af ("ppc/pnv: Add an I2C controller model")
> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> ---
>
This is 8.2 material.
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Thanks,
C.
> Changes from v2:
> -Added Fixes: tag
>
> hw/ppc/pnv_i2c.c | 42 ++++++++++++++++++------------------------
> 1 file changed, 18 insertions(+), 24 deletions(-)
>
> diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
> index b2c738da50..f80589157b 100644
> --- a/hw/ppc/pnv_i2c.c
> +++ b/hw/ppc/pnv_i2c.c
> @@ -462,6 +462,23 @@ static uint64_t pnv_i2c_xscom_read(void *opaque, hwaddr addr,
> return val;
> }
>
> +static void pnv_i2c_reset(void *dev)
> +{
> + PnvI2C *i2c = PNV_I2C(dev);
> +
> + memset(i2c->regs, 0, sizeof(i2c->regs));
> +
> + i2c->regs[I2C_STAT_REG] =
> + SETFIELD(I2C_STAT_UPPER_THRS, 0ull, i2c->num_busses - 1) |
> + I2C_STAT_CMD_COMP | I2C_STAT_SCL_INPUT_LEVEL |
> + I2C_STAT_SDA_INPUT_LEVEL;
> + i2c->regs[I2C_EXTD_STAT_REG] =
> + SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
> + SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
> +
> + fifo8_reset(&i2c->fifo);
> +}
> +
> static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
> uint64_t val, unsigned size)
> {
> @@ -499,16 +516,7 @@ static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
> break;
>
> case I2C_RESET_I2C_REG:
> - i2c->regs[I2C_MODE_REG] = 0;
> - i2c->regs[I2C_CMD_REG] = 0;
> - i2c->regs[I2C_WATERMARK_REG] = 0;
> - i2c->regs[I2C_INTR_MASK_REG] = 0;
> - i2c->regs[I2C_INTR_COND_REG] = 0;
> - i2c->regs[I2C_INTR_RAW_COND_REG] = 0;
> - i2c->regs[I2C_STAT_REG] = 0;
> - i2c->regs[I2C_RESIDUAL_LEN_REG] = 0;
> - i2c->regs[I2C_EXTD_STAT_REG] &=
> - (I2C_EXTD_STAT_FIFO_SIZE | I2C_EXTD_STAT_I2C_VERSION);
> + pnv_i2c_reset(i2c);
> break;
>
> case I2C_RESET_ERRORS:
> @@ -620,20 +628,6 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
> return 0;
> }
>
> -static void pnv_i2c_reset(void *dev)
> -{
> - PnvI2C *i2c = PNV_I2C(dev);
> -
> - memset(i2c->regs, 0, sizeof(i2c->regs));
> -
> - i2c->regs[I2C_STAT_REG] = I2C_STAT_CMD_COMP;
> - i2c->regs[I2C_EXTD_STAT_REG] =
> - SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
> - SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
> -
> - fifo8_reset(&i2c->fifo);
> -}
> -
> static void pnv_i2c_realize(DeviceState *dev, Error **errp)
> {
> PnvI2C *i2c = PNV_I2C(dev);
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset
2023-11-14 19:56 ` [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset Glenn Miles
2023-11-15 22:20 ` Cédric Le Goater
@ 2023-11-18 7:36 ` Cédric Le Goater
1 sibling, 0 replies; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-18 7:36 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
On 11/14/23 20:56, Glenn Miles wrote:
> The PNV I2C Controller was clearing the status register
> after a reset without repopulating the "upper threshold
> for I2C ports", "Command Complete" and the SCL/SDA input
> level fields.
>
> Fixed this for resets caused by a system reset as well
> as from writing to the "Immediate Reset" register.
>
> Fixes: 263b81ee15af ("ppc/pnv: Add an I2C controller model")
> Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
> ---
Applied to ppc-next.
Thanks,
C.
> Changes from v2:
> -Added Fixes: tag
>
> hw/ppc/pnv_i2c.c | 42 ++++++++++++++++++------------------------
> 1 file changed, 18 insertions(+), 24 deletions(-)
>
> diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
> index b2c738da50..f80589157b 100644
> --- a/hw/ppc/pnv_i2c.c
> +++ b/hw/ppc/pnv_i2c.c
> @@ -462,6 +462,23 @@ static uint64_t pnv_i2c_xscom_read(void *opaque, hwaddr addr,
> return val;
> }
>
> +static void pnv_i2c_reset(void *dev)
> +{
> + PnvI2C *i2c = PNV_I2C(dev);
> +
> + memset(i2c->regs, 0, sizeof(i2c->regs));
> +
> + i2c->regs[I2C_STAT_REG] =
> + SETFIELD(I2C_STAT_UPPER_THRS, 0ull, i2c->num_busses - 1) |
> + I2C_STAT_CMD_COMP | I2C_STAT_SCL_INPUT_LEVEL |
> + I2C_STAT_SDA_INPUT_LEVEL;
> + i2c->regs[I2C_EXTD_STAT_REG] =
> + SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
> + SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
> +
> + fifo8_reset(&i2c->fifo);
> +}
> +
> static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
> uint64_t val, unsigned size)
> {
> @@ -499,16 +516,7 @@ static void pnv_i2c_xscom_write(void *opaque, hwaddr addr,
> break;
>
> case I2C_RESET_I2C_REG:
> - i2c->regs[I2C_MODE_REG] = 0;
> - i2c->regs[I2C_CMD_REG] = 0;
> - i2c->regs[I2C_WATERMARK_REG] = 0;
> - i2c->regs[I2C_INTR_MASK_REG] = 0;
> - i2c->regs[I2C_INTR_COND_REG] = 0;
> - i2c->regs[I2C_INTR_RAW_COND_REG] = 0;
> - i2c->regs[I2C_STAT_REG] = 0;
> - i2c->regs[I2C_RESIDUAL_LEN_REG] = 0;
> - i2c->regs[I2C_EXTD_STAT_REG] &=
> - (I2C_EXTD_STAT_FIFO_SIZE | I2C_EXTD_STAT_I2C_VERSION);
> + pnv_i2c_reset(i2c);
> break;
>
> case I2C_RESET_ERRORS:
> @@ -620,20 +628,6 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
> return 0;
> }
>
> -static void pnv_i2c_reset(void *dev)
> -{
> - PnvI2C *i2c = PNV_I2C(dev);
> -
> - memset(i2c->regs, 0, sizeof(i2c->regs));
> -
> - i2c->regs[I2C_STAT_REG] = I2C_STAT_CMD_COMP;
> - i2c->regs[I2C_EXTD_STAT_REG] =
> - SETFIELD(I2C_EXTD_STAT_FIFO_SIZE, 0ull, PNV_I2C_FIFO_SIZE) |
> - SETFIELD(I2C_EXTD_STAT_I2C_VERSION, 0ull, 23); /* last version */
> -
> - fifo8_reset(&i2c->fifo);
> -}
> -
> static void pnv_i2c_realize(DeviceState *dev, Error **errp)
> {
> PnvI2C *i2c = PNV_I2C(dev);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 5/8] ppc/pnv: Use resettable interface to reset child I2C buses
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (3 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 4/8] ppc/pnv: Fix PNV I2C invalid status after reset Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-14 19:56 ` [PATCH v3 6/8] misc: Add a pca9554 GPIO device model Glenn Miles
` (3 subsequent siblings)
8 siblings, 0 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
The QEMU I2C buses and devices use the resettable
interface for resetting while the PNV I2C controller
and parent buses and devices have not yet transitioned
to this new interface and use the old reset strategy.
This was preventing the I2C buses and devices wired
to the PNV I2C controller from being reset.
The short term fix for this is to have the PNV I2C
Controller's reset function explicitly call the resettable
interface function, bus_cold_reset(), on all child
I2C buses.
The long term fix should be to transition all PNV parent
devices and buses to use the resettable interface so that
all child buses and devices are automatically reset.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
No changes from v2
hw/ppc/pnv_i2c.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c
index f80589157b..9ced596b98 100644
--- a/hw/ppc/pnv_i2c.c
+++ b/hw/ppc/pnv_i2c.c
@@ -628,6 +628,19 @@ static int pnv_i2c_dt_xscom(PnvXScomInterface *dev, void *fdt,
return 0;
}
+static void pnv_i2c_sys_reset(void *dev)
+{
+ int port;
+ PnvI2C *i2c = PNV_I2C(dev);
+
+ pnv_i2c_reset(dev);
+
+ /* reset all buses connected to this i2c controller */
+ for (port = 0; port < i2c->num_busses; port++) {
+ bus_cold_reset(BUS(i2c->busses[port]));
+ }
+}
+
static void pnv_i2c_realize(DeviceState *dev, Error **errp)
{
PnvI2C *i2c = PNV_I2C(dev);
@@ -648,7 +661,7 @@ static void pnv_i2c_realize(DeviceState *dev, Error **errp)
fifo8_create(&i2c->fifo, PNV_I2C_FIFO_SIZE);
- qemu_register_reset(pnv_i2c_reset, dev);
+ qemu_register_reset(pnv_i2c_sys_reset, dev);
qdev_init_gpio_out(DEVICE(dev), &i2c->psi_irq, 1);
}
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 6/8] misc: Add a pca9554 GPIO device model
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (4 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 5/8] ppc/pnv: Use resettable interface to reset child I2C buses Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-14 19:56 ` [PATCH v3 7/8] ppc/pnv: Add a pca9554 I2C device to powernv10 Glenn Miles
` (2 subsequent siblings)
8 siblings, 0 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
Specs are available here:
https://www.nxp.com/docs/en/data-sheet/PCA9554_9554A.pdf
This is a simple model supporting the basic registers for GPIO
mode. The device also supports an interrupt output line but the
model does not yet support this.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
No changes from v2
MAINTAINERS | 2 +
hw/misc/pca9554.c | 328 +++++++++++++++++++++++++++++++++
include/hw/misc/pca9554.h | 36 ++++
include/hw/misc/pca9554_regs.h | 19 ++
4 files changed, 385 insertions(+)
create mode 100644 hw/misc/pca9554.c
create mode 100644 include/hw/misc/pca9554.h
create mode 100644 include/hw/misc/pca9554_regs.h
diff --git a/MAINTAINERS b/MAINTAINERS
index e73a3ff544..209080e1a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1504,8 +1504,10 @@ F: hw/ppc/pnv*
F: hw/intc/pnv*
F: hw/intc/xics_pnv.c
F: hw/pci-host/pnv*
+F: hw/misc/pca9554.c
F: include/hw/ppc/pnv*
F: include/hw/pci-host/pnv*
+F: include/hw/misc/pca9554*.h
F: pc-bios/skiboot.lid
F: tests/qtest/pnv*
diff --git a/hw/misc/pca9554.c b/hw/misc/pca9554.c
new file mode 100644
index 0000000000..778b32e443
--- /dev/null
+++ b/hw/misc/pca9554.c
@@ -0,0 +1,328 @@
+/*
+ * PCA9554 I/O port
+ *
+ * Copyright (c) 2023, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/pca9554.h"
+#include "hw/misc/pca9554_regs.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "trace.h"
+#include "qom/object.h"
+
+struct PCA9554Class {
+ /*< private >*/
+ I2CSlaveClass parent_class;
+ /*< public >*/
+};
+typedef struct PCA9554Class PCA9554Class;
+
+DECLARE_CLASS_CHECKERS(PCA9554Class, PCA9554,
+ TYPE_PCA9554)
+
+#define PCA9554_PIN_LOW 0x0
+#define PCA9554_PIN_HIZ 0x1
+
+static const char *pin_state[] = {"low", "high"};
+
+static void pca9554_update_pin_input(PCA9554State *s)
+{
+ int i;
+ uint8_t config = s->regs[PCA9554_CONFIG];
+ uint8_t output = s->regs[PCA9554_OUTPUT];
+ uint8_t internal_state = config | output;
+
+ for (i = 0; i < PCA9554_PIN_COUNT; i++) {
+ uint8_t bit_mask = 1 << i;
+ uint8_t internal_pin_state = (internal_state >> i) & 0x1;
+ uint8_t old_value = s->regs[PCA9554_INPUT] & bit_mask;
+ uint8_t new_value;
+
+ switch (internal_pin_state) {
+ case PCA9554_PIN_LOW:
+ s->regs[PCA9554_INPUT] &= ~bit_mask;
+ break;
+ case PCA9554_PIN_HIZ:
+ /*
+ * pullup sets it to a logical 1 unless
+ * external device drives it low.
+ */
+ if (s->ext_state[i] == PCA9554_PIN_LOW) {
+ s->regs[PCA9554_INPUT] &= ~bit_mask;
+ } else {
+ s->regs[PCA9554_INPUT] |= bit_mask;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* update irq state only if pin state changed */
+ new_value = s->regs[PCA9554_INPUT] & bit_mask;
+ if (new_value != old_value) {
+ if (new_value) {
+ /* changed from 0 to 1 */
+ qemu_set_irq(s->gpio_out[i], 1);
+ } else {
+ /* changed from 1 to 0 */
+ qemu_set_irq(s->gpio_out[i], 0);
+ }
+ }
+ }
+}
+
+static uint8_t pca9554_read(PCA9554State *s, uint8_t reg)
+{
+ switch (reg) {
+ case PCA9554_INPUT:
+ return s->regs[PCA9554_INPUT] ^ s->regs[PCA9554_POLARITY];
+ case PCA9554_OUTPUT:
+ case PCA9554_POLARITY:
+ case PCA9554_CONFIG:
+ return s->regs[reg];
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected read to register %d\n",
+ __func__, reg);
+ return 0xFF;
+ }
+}
+
+static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data)
+{
+ switch (reg) {
+ case PCA9554_OUTPUT:
+ case PCA9554_CONFIG:
+ s->regs[reg] = data;
+ pca9554_update_pin_input(s);
+ break;
+ case PCA9554_POLARITY:
+ s->regs[reg] = data;
+ break;
+ case PCA9554_INPUT:
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: unexpected write to register %d\n",
+ __func__, reg);
+ }
+}
+
+static uint8_t pca9554_recv(I2CSlave *i2c)
+{
+ PCA9554State *s = PCA9554(i2c);
+ uint8_t ret;
+
+ ret = pca9554_read(s, s->pointer & 0x3);
+
+ return ret;
+}
+
+static int pca9554_send(I2CSlave *i2c, uint8_t data)
+{
+ PCA9554State *s = PCA9554(i2c);
+
+ /* First byte sent by is the register address */
+ if (s->len == 0) {
+ s->pointer = data;
+ s->len++;
+ } else {
+ pca9554_write(s, s->pointer & 0x3, data);
+ }
+
+ return 0;
+}
+
+static int pca9554_event(I2CSlave *i2c, enum i2c_event event)
+{
+ PCA9554State *s = PCA9554(i2c);
+
+ s->len = 0;
+ return 0;
+}
+
+static void pca9554_get_pin(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCA9554State *s = PCA9554(obj);
+ int pin, rc;
+ uint8_t state;
+
+ rc = sscanf(name, "pin%2d", &pin);
+ if (rc != 1) {
+ error_setg(errp, "%s: error reading %s", __func__, name);
+ return;
+ }
+ if (pin < 0 || pin > PCA9554_PIN_COUNT) {
+ error_setg(errp, "%s invalid pin %s", __func__, name);
+ return;
+ }
+
+ state = pca9554_read(s, PCA9554_CONFIG);
+ state |= pca9554_read(s, PCA9554_OUTPUT);
+ state = (state >> pin) & 0x1;
+ visit_type_str(v, name, (char **)&pin_state[state], errp);
+}
+
+static void pca9554_set_pin(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ PCA9554State *s = PCA9554(obj);
+ int pin, rc, val;
+ uint8_t state, mask;
+ char *state_str;
+
+ if (!visit_type_str(v, name, &state_str, errp)) {
+ return;
+ }
+ rc = sscanf(name, "pin%2d", &pin);
+ if (rc != 1) {
+ error_setg(errp, "%s: error reading %s", __func__, name);
+ return;
+ }
+ if (pin < 0 || pin > PCA9554_PIN_COUNT) {
+ error_setg(errp, "%s invalid pin %s", __func__, name);
+ return;
+ }
+
+ for (state = 0; state < ARRAY_SIZE(pin_state); state++) {
+ if (!strcmp(state_str, pin_state[state])) {
+ break;
+ }
+ }
+ if (state >= ARRAY_SIZE(pin_state)) {
+ error_setg(errp, "%s invalid pin state %s", __func__, state_str);
+ return;
+ }
+
+ /* First, modify the output register bit */
+ val = pca9554_read(s, PCA9554_OUTPUT);
+ mask = 0x1 << pin;
+ if (state == PCA9554_PIN_LOW) {
+ val &= ~(mask);
+ } else {
+ val |= mask;
+ }
+ pca9554_write(s, PCA9554_OUTPUT, val);
+
+ /* Then, clear the config register bit for output mode */
+ val = pca9554_read(s, PCA9554_CONFIG);
+ val &= ~mask;
+ pca9554_write(s, PCA9554_CONFIG, val);
+}
+
+static const VMStateDescription pca9554_vmstate = {
+ .name = "PCA9554",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(len, PCA9554State),
+ VMSTATE_UINT8(pointer, PCA9554State),
+ VMSTATE_UINT8_ARRAY(regs, PCA9554State, PCA9554_NR_REGS),
+ VMSTATE_UINT8_ARRAY(ext_state, PCA9554State, PCA9554_PIN_COUNT),
+ VMSTATE_I2C_SLAVE(i2c, PCA9554State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void pca9554_reset(DeviceState *dev)
+{
+ PCA9554State *s = PCA9554(dev);
+
+ s->regs[PCA9554_INPUT] = 0xFF;
+ s->regs[PCA9554_OUTPUT] = 0xFF;
+ s->regs[PCA9554_POLARITY] = 0x0; /* No pins are inverted */
+ s->regs[PCA9554_CONFIG] = 0xFF; /* All pins are inputs */
+
+ memset(s->ext_state, PCA9554_PIN_HIZ, PCA9554_PIN_COUNT);
+ pca9554_update_pin_input(s);
+
+ s->pointer = 0x0;
+ s->len = 0;
+}
+
+static void pca9554_initfn(Object *obj)
+{
+ int pin;
+
+ for (pin = 0; pin < PCA9554_PIN_COUNT; pin++) {
+ char *name;
+
+ name = g_strdup_printf("pin%d", pin);
+ object_property_add(obj, name, "bool", pca9554_get_pin, pca9554_set_pin,
+ NULL, NULL);
+ g_free(name);
+ }
+}
+
+static void pca9554_set_ext_state(PCA9554State *s, int pin, int level)
+{
+ if (s->ext_state[pin] != level) {
+ s->ext_state[pin] = level;
+ pca9554_update_pin_input(s);
+ }
+}
+
+static void pca9554_gpio_in_handler(void *opaque, int pin, int level)
+{
+
+ PCA9554State *s = PCA9554(opaque);
+
+ assert((pin >= 0) && (pin < PCA9554_PIN_COUNT));
+ pca9554_set_ext_state(s, pin, level);
+}
+
+static void pca9554_realize(DeviceState *dev, Error **errp)
+{
+ PCA9554State *s = PCA9554(dev);
+
+ if (!s->description) {
+ s->description = g_strdup("pca9554");
+ }
+
+ qdev_init_gpio_out(dev, s->gpio_out, PCA9554_PIN_COUNT);
+ qdev_init_gpio_in(dev, pca9554_gpio_in_handler, PCA9554_PIN_COUNT);
+}
+
+static Property pca9554_properties[] = {
+ DEFINE_PROP_STRING("description", PCA9554State, description),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pca9554_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->event = pca9554_event;
+ k->recv = pca9554_recv;
+ k->send = pca9554_send;
+ dc->realize = pca9554_realize;
+ dc->reset = pca9554_reset;
+ dc->vmsd = &pca9554_vmstate;
+ device_class_set_props(dc, pca9554_properties);
+}
+
+static const TypeInfo pca9554_info = {
+ .name = TYPE_PCA9554,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_init = pca9554_initfn,
+ .instance_size = sizeof(PCA9554State),
+ .class_init = pca9554_class_init,
+ .class_size = sizeof(PCA9554Class),
+ .abstract = false,
+};
+
+static void pca9554_register_types(void)
+{
+ type_register_static(&pca9554_info);
+}
+
+type_init(pca9554_register_types)
diff --git a/include/hw/misc/pca9554.h b/include/hw/misc/pca9554.h
new file mode 100644
index 0000000000..54bfc4c4c7
--- /dev/null
+++ b/include/hw/misc/pca9554.h
@@ -0,0 +1,36 @@
+/*
+ * PCA9554 I/O port
+ *
+ * Copyright (c) 2023, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef PCA9554_H
+#define PCA9554_H
+
+#include "hw/i2c/i2c.h"
+#include "qom/object.h"
+
+#define TYPE_PCA9554 "pca9554"
+typedef struct PCA9554State PCA9554State;
+DECLARE_INSTANCE_CHECKER(PCA9554State, PCA9554,
+ TYPE_PCA9554)
+
+#define PCA9554_NR_REGS 4
+#define PCA9554_PIN_COUNT 8
+
+struct PCA9554State {
+ /*< private >*/
+ I2CSlave i2c;
+ /*< public >*/
+
+ uint8_t len;
+ uint8_t pointer;
+
+ uint8_t regs[PCA9554_NR_REGS];
+ qemu_irq gpio_out[PCA9554_PIN_COUNT];
+ uint8_t ext_state[PCA9554_PIN_COUNT];
+ char *description; /* For debugging purpose only */
+};
+
+#endif
diff --git a/include/hw/misc/pca9554_regs.h b/include/hw/misc/pca9554_regs.h
new file mode 100644
index 0000000000..602c4a90e0
--- /dev/null
+++ b/include/hw/misc/pca9554_regs.h
@@ -0,0 +1,19 @@
+/*
+ * PCA9554 I/O port registers
+ *
+ * Copyright (c) 2023, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef PCA9554_REGS_H
+#define PCA9554_REGS_H
+
+/*
+ * Bits [0:1] are used to address a specific register.
+ */
+#define PCA9554_INPUT 0 /* read only input register */
+#define PCA9554_OUTPUT 1 /* read/write pin output state */
+#define PCA9554_POLARITY 2 /* Set polarity of input register */
+#define PCA9554_CONFIG 3 /* Set pins as inputs our ouputs */
+
+#endif
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 7/8] ppc/pnv: Add a pca9554 I2C device to powernv10
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (5 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 6/8] misc: Add a pca9554 GPIO device model Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-14 19:56 ` [PATCH v3 8/8] ppc/pnv: Test pnv i2c master and connected devices Glenn Miles
2023-11-15 10:03 ` [PATCH v3 0/8] Add powernv10 I2C devices and tests Cédric Le Goater
8 siblings, 0 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
The Power Hypervisor code expects to see a pca9554 device connected
to the 3rd PNV I2C engine on port 1 at I2C address 0x25 (or left-
justified address of 0x4A). This is used by the hypervisor code to
detect if a "Cable Card" is present.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
No changes from v2
hw/misc/Kconfig | 4 ++++
hw/misc/meson.build | 1 +
hw/ppc/Kconfig | 1 +
hw/ppc/pnv.c | 5 +++++
4 files changed, 11 insertions(+)
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index cc8a8c1418..c347a132c2 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -34,6 +34,10 @@ config PCA9552
bool
depends on I2C
+config PCA9554
+ bool
+ depends on I2C
+
config I2C_ECHO
bool
default y if TEST_DEVICES
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 36c20d5637..c39410e4a7 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -4,6 +4,7 @@ system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c'))
system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c'))
system_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c'))
system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c'))
+system_ss.add(when: 'CONFIG_PCA9554', if_true: files('pca9554.c'))
system_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c'))
system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index f77ca773cf..2302778265 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -33,6 +33,7 @@ config POWERNV
select FDT_PPC
select PCI_POWERNV
select PCA9552
+ select PCA9554
config PPC405
bool
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index e82e9b30ec..bbbc4ca868 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -1903,6 +1903,11 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_connect_gpio_out(DEVICE(hotplug), 4,
qdev_get_gpio_in(DEVICE(hotplug), 9));
+ /*
+ * Add a PCA9554 I2C device for cable card presence detection
+ * to engine 2, bus 1, address 0x25
+ */
+ i2c_slave_create_simple(chip10->i2c[2].busses[1], "pca9554", 0x25);
}
static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr)
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 8/8] ppc/pnv: Test pnv i2c master and connected devices
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (6 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 7/8] ppc/pnv: Add a pca9554 I2C device to powernv10 Glenn Miles
@ 2023-11-14 19:56 ` Glenn Miles
2023-11-15 10:03 ` [PATCH v3 0/8] Add powernv10 I2C devices and tests Cédric Le Goater
8 siblings, 0 replies; 20+ messages in thread
From: Glenn Miles @ 2023-11-14 19:56 UTC (permalink / raw)
To: qemu-devel, qemu-ppc
Cc: Glenn Miles, Cédric Le Goater, Nicholas Piggin,
Frédéric Barrat
Tests the following for both P9 and P10:
- I2C master POR status
- I2C master status after immediate reset
Tests the following for P10 only:
- Config pca9552 hotplug device pins as inputs then
Read the INPUT0/1 registers to verify all pins are high
- Connected GPIO pin tests of P10 PCA9552 device. Tests
output of pins 0-4 affect input of pins 5-9 respectively.
- PCA9554 GPIO pins test. Tests input and ouput functionality.
Signed-off-by: Glenn Miles <milesg@linux.vnet.ibm.com>
---
Changes from previous version:
- Fixed formatting errors
tests/qtest/meson.build | 1 +
tests/qtest/pnv-host-i2c-test.c | 650 ++++++++++++++++++++++++++++++++
2 files changed, 651 insertions(+)
create mode 100644 tests/qtest/pnv-host-i2c-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 47dabf91d0..fbb0bd204c 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -163,6 +163,7 @@ qtests_ppc64 = \
qtests_ppc + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c
new file mode 100644
index 0000000000..52639fc8f7
--- /dev/null
+++ b/tests/qtest/pnv-host-i2c-test.c
@@ -0,0 +1,650 @@
+/*
+ * 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/misc/pca9554_regs.h"
+#include "hw/misc/pca9552_regs.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 P10_XSCOM_BASE 0x000603fc00000000ull
+#define PNV10_CHIP_MAX_I2C 5
+#define PNV10_XSCOM_I2CM_BASE 0xa0000
+#define PNV10_XSCOM_I2CM_SIZE 0x1000
+
+/* I2C FIFO register */
+#define I2C_FIFO_REG 0x4
+#define I2C_FIFO PPC_BITMASK(0, 7)
+
+/* I2C command register */
+#define I2C_CMD_REG 0x5
+#define I2C_CMD_WITH_START PPC_BIT(0)
+#define I2C_CMD_WITH_ADDR PPC_BIT(1)
+#define I2C_CMD_READ_CONT PPC_BIT(2)
+#define I2C_CMD_WITH_STOP PPC_BIT(3)
+#define I2C_CMD_INTR_STEERING PPC_BITMASK(6, 7) /* P9 */
+#define I2C_CMD_INTR_STEER_HOST 1
+#define I2C_CMD_INTR_STEER_OCC 2
+#define I2C_CMD_DEV_ADDR PPC_BITMASK(8, 14)
+#define I2C_CMD_READ_NOT_WRITE PPC_BIT(15)
+#define I2C_CMD_LEN_BYTES PPC_BITMASK(16, 31)
+#define I2C_MAX_TFR_LEN 0xfff0ull
+
+/* I2C mode register */
+#define I2C_MODE_REG 0x6
+#define I2C_MODE_BIT_RATE_DIV PPC_BITMASK(0, 15)
+#define I2C_MODE_PORT_NUM PPC_BITMASK(16, 21)
+#define I2C_MODE_ENHANCED PPC_BIT(28)
+#define I2C_MODE_DIAGNOSTIC PPC_BIT(29)
+#define I2C_MODE_PACING_ALLOW PPC_BIT(30)
+#define I2C_MODE_WRAP PPC_BIT(31)
+
+/* I2C watermark register */
+#define I2C_WATERMARK_REG 0x7
+#define I2C_WATERMARK_HIGH PPC_BITMASK(16, 19)
+#define I2C_WATERMARK_LOW PPC_BITMASK(24, 27)
+
+/*
+ * I2C interrupt mask and condition registers
+ *
+ * NB: The function of 0x9 and 0xa changes depending on whether you're reading
+ * or writing to them. When read they return the interrupt condition bits
+ * and on writes they update the interrupt mask register.
+ *
+ * The bit definitions are the same for all the interrupt registers.
+ */
+#define I2C_INTR_MASK_REG 0x8
+
+#define I2C_INTR_RAW_COND_REG 0x9 /* read */
+#define I2C_INTR_MASK_OR_REG 0x9 /* write*/
+
+#define I2C_INTR_COND_REG 0xa /* read */
+#define I2C_INTR_MASK_AND_REG 0xa /* write */
+
+#define I2C_INTR_ALL PPC_BITMASK(16, 31)
+#define I2C_INTR_INVALID_CMD PPC_BIT(16)
+#define I2C_INTR_LBUS_PARITY_ERR PPC_BIT(17)
+#define I2C_INTR_BKEND_OVERRUN_ERR PPC_BIT(18)
+#define I2C_INTR_BKEND_ACCESS_ERR PPC_BIT(19)
+#define I2C_INTR_ARBT_LOST_ERR PPC_BIT(20)
+#define I2C_INTR_NACK_RCVD_ERR PPC_BIT(21)
+#define I2C_INTR_DATA_REQ PPC_BIT(22)
+#define I2C_INTR_CMD_COMP PPC_BIT(23)
+#define I2C_INTR_STOP_ERR PPC_BIT(24)
+#define I2C_INTR_I2C_BUSY PPC_BIT(25)
+#define I2C_INTR_NOT_I2C_BUSY PPC_BIT(26)
+#define I2C_INTR_SCL_EQ_1 PPC_BIT(28)
+#define I2C_INTR_SCL_EQ_0 PPC_BIT(29)
+#define I2C_INTR_SDA_EQ_1 PPC_BIT(30)
+#define I2C_INTR_SDA_EQ_0 PPC_BIT(31)
+
+/* I2C status register */
+#define I2C_RESET_I2C_REG 0xb /* write */
+#define I2C_RESET_ERRORS 0xc
+#define I2C_STAT_REG 0xb /* read */
+#define I2C_STAT_INVALID_CMD PPC_BIT(0)
+#define I2C_STAT_LBUS_PARITY_ERR PPC_BIT(1)
+#define I2C_STAT_BKEND_OVERRUN_ERR PPC_BIT(2)
+#define I2C_STAT_BKEND_ACCESS_ERR PPC_BIT(3)
+#define I2C_STAT_ARBT_LOST_ERR PPC_BIT(4)
+#define I2C_STAT_NACK_RCVD_ERR PPC_BIT(5)
+#define I2C_STAT_DATA_REQ PPC_BIT(6)
+#define I2C_STAT_CMD_COMP PPC_BIT(7)
+#define I2C_STAT_STOP_ERR PPC_BIT(8)
+#define I2C_STAT_UPPER_THRS PPC_BITMASK(9, 15)
+#define I2C_STAT_ANY_I2C_INTR PPC_BIT(16)
+#define I2C_STAT_PORT_HISTORY_BUSY PPC_BIT(19)
+#define I2C_STAT_SCL_INPUT_LEVEL PPC_BIT(20)
+#define I2C_STAT_SDA_INPUT_LEVEL PPC_BIT(21)
+#define I2C_STAT_PORT_BUSY PPC_BIT(22)
+#define I2C_STAT_INTERFACE_BUSY PPC_BIT(23)
+#define I2C_STAT_FIFO_ENTRY_COUNT PPC_BITMASK(24, 31)
+
+#define I2C_STAT_ANY_ERR (I2C_STAT_INVALID_CMD | I2C_STAT_LBUS_PARITY_ERR | \
+ I2C_STAT_BKEND_OVERRUN_ERR | \
+ I2C_STAT_BKEND_ACCESS_ERR | I2C_STAT_ARBT_LOST_ERR | \
+ I2C_STAT_NACK_RCVD_ERR | I2C_STAT_STOP_ERR)
+
+
+#define I2C_INTR_ACTIVE \
+ ((I2C_STAT_ANY_ERR >> 16) | I2C_INTR_CMD_COMP | I2C_INTR_DATA_REQ)
+
+/* Pseudo-status used for timeouts */
+#define I2C_STAT_PSEUDO_TIMEOUT PPC_BIT(63)
+
+/* I2C extended status register */
+#define I2C_EXTD_STAT_REG 0xc
+#define I2C_EXTD_STAT_FIFO_SIZE PPC_BITMASK(0, 7)
+#define I2C_EXTD_STAT_MSM_CURSTATE PPC_BITMASK(11, 15)
+#define I2C_EXTD_STAT_SCL_IN_SYNC PPC_BIT(16)
+#define I2C_EXTD_STAT_SDA_IN_SYNC PPC_BIT(17)
+#define I2C_EXTD_STAT_S_SCL PPC_BIT(18)
+#define I2C_EXTD_STAT_S_SDA PPC_BIT(19)
+#define I2C_EXTD_STAT_M_SCL PPC_BIT(20)
+#define I2C_EXTD_STAT_M_SDA PPC_BIT(21)
+#define I2C_EXTD_STAT_HIGH_WATER PPC_BIT(22)
+#define I2C_EXTD_STAT_LOW_WATER PPC_BIT(23)
+#define I2C_EXTD_STAT_I2C_BUSY PPC_BIT(24)
+#define I2C_EXTD_STAT_SELF_BUSY PPC_BIT(25)
+#define I2C_EXTD_STAT_I2C_VERSION PPC_BITMASK(27, 31)
+
+/* I2C residual front end/back end length */
+#define I2C_RESIDUAL_LEN_REG 0xd
+#define I2C_RESIDUAL_FRONT_END PPC_BITMASK(0, 15)
+#define I2C_RESIDUAL_BACK_END PPC_BITMASK(16, 31)
+
+/* Port busy register */
+#define I2C_PORT_BUSY_REG 0xe
+#define I2C_SET_S_SCL_REG 0xd
+#define I2C_RESET_S_SCL_REG 0xf
+#define I2C_SET_S_SDA_REG 0x10
+#define I2C_RESET_S_SDA_REG 0x11
+
+#define PNV_I2C_FIFO_SIZE 8
+
+#define SMT 4 /* some tests will break if less than 4 */
+
+typedef enum PnvChipType {
+ PNV_CHIP_POWER8E, /* AKA Murano (default) */
+ PNV_CHIP_POWER8, /* AKA Venice */
+ PNV_CHIP_POWER8NVL, /* AKA Naples */
+ PNV_CHIP_POWER9, /* AKA Nimbus */
+ PNV_CHIP_POWER10,
+} PnvChipType;
+
+typedef struct PnvChip {
+ PnvChipType chip_type;
+ const char *cpu_model;
+ uint64_t xscom_base;
+ uint64_t cfam_id;
+ uint32_t first_core;
+ uint32_t num_i2c;
+} PnvChip;
+
+static const PnvChip pnv_chips[] = {
+ {
+ .chip_type = PNV_CHIP_POWER9,
+ .cpu_model = "POWER9",
+ .xscom_base = 0x000603fc00000000ull,
+ .cfam_id = 0x220d104900008000ull,
+ .first_core = 0x0,
+ .num_i2c = 4,
+ },
+ {
+ .chip_type = PNV_CHIP_POWER10,
+ .cpu_model = "POWER10",
+ .xscom_base = 0x000603fc00000000ull,
+ .cfam_id = 0x120da04900008000ull,
+ .first_core = 0x0,
+ .num_i2c = 4,
+ },
+};
+
+
+typedef struct {
+ QTestState *qts;
+ int engine;
+ int port;
+ uint8_t addr;
+} pnv_i2c_dev_t;
+
+
+static uint64_t pnv_xscom_addr(uint32_t pcba)
+{
+ return P10_XSCOM_BASE | ((uint64_t) pcba << 3);
+}
+
+static uint64_t pnv_i2c_xscom_addr(int engine, uint32_t reg)
+{
+ return pnv_xscom_addr(PNV10_XSCOM_I2CM_BASE +
+ (PNV10_XSCOM_I2CM_SIZE * engine) + reg);
+}
+
+static uint64_t pnv_i2c_xscom_read(QTestState *qts, int engine, uint32_t reg)
+{
+ return qtest_readq(qts, pnv_i2c_xscom_addr(engine, reg));
+}
+
+static void pnv_i2c_xscom_write(QTestState *qts, int engine, uint32_t reg,
+ uint64_t val)
+{
+ qtest_writeq(qts, pnv_i2c_xscom_addr(engine, reg), val);
+}
+
+/* Write len bytes from buf to i2c device with given addr and port */
+static void pnv_i2c_send(pnv_i2c_dev_t *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->qts, dev->engine, I2C_MODE_REG, reg64);
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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->qts, dev->engine, I2C_CMD_REG, reg64);
+
+ /* check status for errors */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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->qts, dev->engine, I2C_FIFO_REG, reg64);
+ }
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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(pnv_i2c_dev_t *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->qts, dev->engine, I2C_MODE_REG, reg64);
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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->qts, dev->engine, I2C_CMD_REG, reg64);
+
+ /* check status for errors */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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->qts, dev->engine, I2C_FIFO_REG);
+ buf[byte_num] = GETFIELD(I2C_FIFO, reg64);
+ }
+
+ /* check status for cmd complete and bus idle */
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, I2C_EXTD_STAT_REG);
+ g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0);
+ reg64 = pnv_i2c_xscom_read(dev->qts, dev->engine, 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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(pnv_i2c_dev_t *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(QTestState *qts, int engine)
+{
+ pnv_i2c_xscom_write(qts, engine, 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++) {
+
+ /* Check version in Extended Status Register */
+ uint64_t value = pnv_i2c_xscom_read(qts, engine, 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(qts, engine, 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++) {
+ reset_engine(qts, engine);
+ pnv_i2c_xscom_write(qts, engine, I2C_MODE_REG, 0x02be040000000000);
+ }
+}
+
+static void test_host_i2c(const void *data)
+{
+ const PnvChip *chip = data;
+ QTestState *qts;
+ const char *machine = "powernv8";
+ pnv_i2c_dev_t pca9552;
+ pnv_i2c_dev_t pca9554;
+
+ if (chip->chip_type == PNV_CHIP_POWER9) {
+ machine = "powernv9";
+ } else if (chip->chip_type == PNV_CHIP_POWER10) {
+ machine = "powernv10";
+ }
+
+ 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 */
+ pca9552.qts = qts;
+ pca9552.engine = 2;
+ 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.qts = qts;
+ pca9554.engine = 2;
+ 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();
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v3 0/8] Add powernv10 I2C devices and tests
2023-11-14 19:56 [PATCH v3 0/8] Add powernv10 I2C devices and tests Glenn Miles
` (7 preceding siblings ...)
2023-11-14 19:56 ` [PATCH v3 8/8] ppc/pnv: Test pnv i2c master and connected devices Glenn Miles
@ 2023-11-15 10:03 ` Cédric Le Goater
8 siblings, 0 replies; 20+ messages in thread
From: Cédric Le Goater @ 2023-11-15 10:03 UTC (permalink / raw)
To: Glenn Miles, qemu-devel, qemu-ppc
Cc: Nicholas Piggin, Frédéric Barrat
Nick,
On 11/14/23 20:56, Glenn Miles wrote:
> This series of patches includes support, tests and fixes for
> adding PCA9552 and PCA9554 I2C devices to the powernv10 chip.
>
> The PCA9552 device is used for PCIe slot hotplug power control
> and monitoring, while the PCA9554 device is used for presence
> detection of IBM CableCard devices. Both devices are required
> by the Power Hypervisor Firmware on Power10 platforms.
>
> Changes from previous version:
> - Added Fixes: tag to commits 3 and 4
Are you preparing a QEMU 8.2 PR for fixes ?
Thanks,
C.
> - Fixed formatting errors in commits 2 and 8
>
> Glenn Miles (8):
> ppc/pnv: Add pca9552 to powernv10 for PCIe hotplug power control
> ppc/pnv: Wire up pca9552 GPIO pins for PCIe hotplug power control
> ppc/pnv: PNV I2C engines assigned incorrect XSCOM addresses
> ppc/pnv: Fix PNV I2C invalid status after reset
> ppc/pnv: Use resettable interface to reset child I2C buses
> misc: Add a pca9554 GPIO device model
> ppc/pnv: Add a pca9554 I2C device to powernv10
> ppc/pnv: Test pnv i2c master and connected devices
>
> MAINTAINERS | 2 +
> hw/misc/Kconfig | 4 +
> hw/misc/meson.build | 1 +
> hw/misc/pca9554.c | 328 ++++++++++++++++
> hw/ppc/Kconfig | 2 +
> hw/ppc/pnv.c | 35 +-
> hw/ppc/pnv_i2c.c | 47 ++-
> include/hw/misc/pca9554.h | 36 ++
> include/hw/misc/pca9554_regs.h | 19 +
> tests/qtest/meson.build | 1 +
> tests/qtest/pnv-host-i2c-test.c | 650 ++++++++++++++++++++++++++++++++
> 11 files changed, 1103 insertions(+), 22 deletions(-)
> create mode 100644 hw/misc/pca9554.c
> create mode 100644 include/hw/misc/pca9554.h
> create mode 100644 include/hw/misc/pca9554_regs.h
> create mode 100644 tests/qtest/pnv-host-i2c-test.c
>
^ permalink raw reply [flat|nested] 20+ messages in thread