* [PATCH net-next v2 0/3] ptp: ocp: support the WiWi production Time Card
@ 2026-11-12 16:33 Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Ahmad Byagowi @ 2026-11-12 16:33 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Randy Dunlap, Michal Simek, Richard Cochran,
Andrew Lunn, linux-doc, linux-kernel, linux-arm-kernel
The WiWi Time Card (2163:1008, subsystem 10ee:0007) uses a
Celestica-compatible register map behind LitePCIe. Its bridge does not
support the subword MMIO used by the XIIC driver. Add an opt-in word
access mode, exercise both modes with KUnit, and enable ptp_ocp on the
revision 02 interface. Other cards retain their existing access modes.
The series does not enable WiWi flash updates or change LED policy.
Patch 3 uses the platform-data field from patch 1. Could the I2C
maintainers review patches 1 and 2 for an Ack to take the series
through net-next?
Changes since v1:
- 1/3: Drop five explicit inline annotations in the C file and
shorten the platform-data comment. No access semantics change.
- 2/3: Wrap the offsets and expectations flagged by checkpatch.
The four test modes, register offsets and expected values are unchanged.
- 3/3: Follow NetTimeLogic's PCI revision convention. Replace the exact
image ID and per-core version checks with a revision 02 gate. Reject
unknown revisions before FPGA MMIO and retain the BAR/MSI-X checks.
Report the full build ID in devlink; select capabilities by interface
revision. Update the documentation and wrap overlength lines.
The revision 02 driver was tested on a physical card running build
0x0000800f under Secure Boot. It bound with 64 MSI-X vectors; the PHC
advanced 3.000441080 s over three one-second sleeps. SPI NOR and both
EEPROM clients bound. The PHC was UNSYNCED at probe; this test does not
establish PPS lock or valid UTC. Only that firmware build was tested on
hardware. Subsequent edits to the tested drivers remove inline hints or
change formatting and comments.
On the rebased v2, the XIIC and ptp_ocp objects built on x86-64 with
W=1 under allmodconfig and allyesconfig. Four XIIC KUnit cases passed
in an isolated x86-64 QEMU boot. Fixtures exercised all 256 PCI
revisions, bad PCI layouts and multiple image IDs. These are not
additional hardware tests. No full allmodconfig or allyesconfig build
is claimed for v2.
Codex assisted with the changes, tests and changelogs using the board
layout, machine-check evidence, vendor revision rule and v1 CI reports.
v1: https://lore.kernel.org/netdev/20261111041904.48916-1-ahmadexp@gmail.com/
Ahmad Byagowi (3):
i2c: xiic: allow platforms to require 32-bit register accesses
i2c: xiic: add KUnit coverage for register access modes
ptp: ocp: support the WiWi revision 02 Time Card
Documentation/networking/devlink/ptp_ocp.rst | 36 +++-
MAINTAINERS | 1 +
drivers/i2c/busses/Kconfig | 14 ++
drivers/i2c/busses/i2c-xiic.c | 60 +++++--
drivers/i2c/busses/tests/i2c_xiic_kunit.c | 91 +++++++++++
drivers/ptp/ptp_ocp.c | 163 ++++++++++++++++++-
include/linux/platform_data/i2c-xiic.h | 3 +
7 files changed, 341 insertions(+), 27 deletions(-)
create mode 100644 drivers/i2c/busses/tests/i2c_xiic_kunit.c
base-commit: 368fbf5d82da9ebce309449c74fc0b128f7d0219
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net-next v2 1/3] i2c: xiic: allow platforms to require 32-bit register accesses
2026-11-12 16:33 [PATCH net-next v2 0/3] ptp: ocp: support the WiWi production Time Card Ahmad Byagowi
@ 2026-11-12 16:33 ` Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 3/3] ptp: ocp: support the WiWi revision 02 Time Card Ahmad Byagowi
2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Byagowi @ 2026-11-12 16:33 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Michal Simek, linux-arm-kernel, linux-kernel
The LitePCIe bridge in the WiWi Time Card production image cannot safely
service subword MMIO accesses. Bringing up its AXI IIC controller with the
existing byte accessors caused a fatal machine check. Two crash dumps
placed the faulting access in ioread8(), called by xiic_clear_rx_fifo()
during xiic_reinit(). The affected register was the IIC status register.
Add a platform-data flag to use aligned 32-bit accesses for registers
carrying byte or halfword values. Keep the detected register endianness
and use a single transaction, not read-modify-write, for FIFO accesses.
Platforms that do not request this mode retain their existing accessors.
With these accessors on a WiWi card, the controller probed and at24
registered the board and MAC EEPROMs. Repeated EEPROM reads and I2C
interrupt delivery were tested separately on an earlier Ubuntu port.
Tool-origin disclosure, as required by generated-content.rst: Codex was
used to analyze the supplied crash evidence, implement the accessors,
prepare tests and draft this changelog. The request was to support the
WiWi card while retaining the existing behavior on other platforms.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
drivers/i2c/busses/i2c-xiic.c | 56 +++++++++++++++++---------
include/linux/platform_data/i2c-xiic.h | 3 ++
2 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index ba560462d..8425a540f 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -66,6 +66,7 @@ enum i2c_scl_freq {
* @rx_msg: Current RX message
* @rx_pos: Position within current RX message
* @endianness: big/little-endian byte order
+ * @force_32bit_access: Bridge requires aligned 32-bit register accesses
* @clk: Pointer to AXI4-lite input clock
* @irq: Interrupt number
* @state: See STATE_
@@ -95,6 +96,7 @@ struct xiic_i2c {
struct i2c_msg *rx_msg;
int rx_pos;
enum xiic_endian endianness;
+ bool force_32bit_access;
struct clk *clk;
int irq;
enum xilinx_i2c_state state;
@@ -282,52 +284,68 @@ static int xiic_i2c_runtime_resume(struct device *dev)
* Only the least significant byte [doublet] of the register are ever
* accessed. This requires an offset of 3 [2] from the base address for
* big-endian systems.
+ * Some bridges only support aligned 32-bit accesses. For these, access the
+ * entire register in its detected byte order, without a read-modify-write:
+ * reading or writing a FIFO register must perform exactly one transaction.
*/
-static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+static void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
{
if (i2c->endianness == LITTLE)
- iowrite8(value, i2c->base + reg);
+ iowrite32(value, i2c->base + reg);
else
- iowrite8(value, i2c->base + reg + 3);
+ iowrite32be(value, i2c->base + reg);
}
-static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+static int xiic_getreg32(struct xiic_i2c *i2c, int reg)
{
- u8 ret;
+ u32 ret;
if (i2c->endianness == LITTLE)
- ret = ioread8(i2c->base + reg);
+ ret = ioread32(i2c->base + reg);
else
- ret = ioread8(i2c->base + reg + 3);
+ ret = ioread32be(i2c->base + reg);
return ret;
}
-static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+static void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
{
+ if (i2c->force_32bit_access) {
+ xiic_setreg32(i2c, reg, value);
+ return;
+ }
+
if (i2c->endianness == LITTLE)
- iowrite16(value, i2c->base + reg);
+ iowrite8(value, i2c->base + reg);
else
- iowrite16be(value, i2c->base + reg + 2);
+ iowrite8(value, i2c->base + reg + 3);
}
-static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+static u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
{
+ u8 ret;
+
+ if (i2c->force_32bit_access)
+ return xiic_getreg32(i2c, reg);
+
if (i2c->endianness == LITTLE)
- iowrite32(value, i2c->base + reg);
+ ret = ioread8(i2c->base + reg);
else
- iowrite32be(value, i2c->base + reg);
+ ret = ioread8(i2c->base + reg + 3);
+ return ret;
}
-static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+static void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
{
- u32 ret;
+ if (i2c->force_32bit_access) {
+ xiic_setreg32(i2c, reg, value);
+ return;
+ }
if (i2c->endianness == LITTLE)
- ret = ioread32(i2c->base + reg);
+ iowrite16(value, i2c->base + reg);
else
- ret = ioread32be(i2c->base + reg);
- return ret;
+ iowrite16be(value, i2c->base + reg + 2);
}
static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
@@ -1480,6 +1498,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
return irq;
pdata = dev_get_platdata(dev);
+ if (pdata)
+ i2c->force_32bit_access = pdata->force_32bit_access;
/* hook up driver to tree */
platform_set_drvdata(pdev, i2c);
diff --git a/include/linux/platform_data/i2c-xiic.h b/include/linux/platform_data/i2c-xiic.h
index 2e3683c23..afad9a49c 100644
--- a/include/linux/platform_data/i2c-xiic.h
+++ b/include/linux/platform_data/i2c-xiic.h
@@ -16,6 +16,8 @@
* @num_devices: Number of devices that shall be added when the driver
* is probed.
* @devices: The actuall devices to add.
+ * @force_32bit_access: Use aligned 32-bit accesses even for byte and
+ * halfword payloads on bridges without subword I/O.
*
* This purpose of this platform data struct is to be able to provide a number
* of devices that should be added to the I2C bus. The reason is that sometimes
@@ -26,6 +28,7 @@
struct xiic_i2c_platform_data {
u8 num_devices;
struct i2c_board_info const *devices;
+ bool force_32bit_access;
};
#endif /* _LINUX_I2C_XIIC_H */
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net-next v2 2/3] i2c: xiic: add KUnit coverage for register access modes
2026-11-12 16:33 [PATCH net-next v2 0/3] ptp: ocp: support the WiWi production Time Card Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
@ 2026-11-12 16:33 ` Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 3/3] ptp: ocp: support the WiWi revision 02 Time Card Ahmad Byagowi
2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Byagowi @ 2026-11-12 16:33 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Michal Simek, linux-kernel, linux-arm-kernel
Exercise the driver's private register accessors with memory-backed
registers instead of physical hardware. Cover native byte/halfword and
forced 32-bit accesses in both register byte orders, across 22 register
offsets. Check payload truncation, high-bit values and neighboring
sentinels. These tests do not validate physical bus transaction widths
or hardware interrupt behavior.
Include the tests in the driver translation unit so no accessors need
to become exported interfaces. Require built-in KUnit to avoid a
built-in driver depending on a modular test framework. The tests follow
the driver into either its built-in image or module.
The four parameterized cases passed in an isolated x86-64 QEMU boot
with networking disabled and no physical-device passthrough.
Tool-origin disclosure, as required by generated-content.rst: Codex was
used to implement this test suite, run the KUnit build/boot and draft
this changelog, in response to a request for upstream-quality testing.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
MAINTAINERS | 1 +
drivers/i2c/busses/Kconfig | 14 ++++
drivers/i2c/busses/i2c-xiic.c | 4 +
drivers/i2c/busses/tests/i2c_xiic_kunit.c | 91 +++++++++++++++++++++++
4 files changed, 110 insertions(+)
create mode 100644 drivers/i2c/busses/tests/i2c_xiic_kunit.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 893b0670a..64fa74c40 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4018,6 +4018,7 @@ F: drivers/cpuidle/cpuidle-zynq.c
F: drivers/edac/synopsys_edac.c
F: drivers/i2c/busses/i2c-cadence.c
F: drivers/i2c/busses/i2c-xiic.c
+F: drivers/i2c/busses/tests/i2c_xiic_kunit.c
F: drivers/mmc/host/sdhci-of-arasan.c
N: zynq
N: xilinx
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 275aaa7f3..014281fa2 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1322,6 +1322,20 @@ config I2C_XILINX
This driver can also be built as a module. If so, the module
will be called xilinx_i2c.
+config I2C_XILINX_KUNIT_TEST
+ bool "KUnit tests for Xilinx I2C register accesses" if !KUNIT_ALL_TESTS
+ depends on I2C_XILINX && KUNIT=y
+ default KUNIT_ALL_TESTS
+ help
+ Test the Xilinx I2C driver's register accessors with both byte orders
+ and with native-width or forced 32-bit accesses. KUnit is a kernel
+ unit testing framework. These tests use memory-backed registers and
+ do not require an I2C controller.
+
+ The tests are compiled into the driver to exercise its private
+ accessors, and follow the driver's built-in or module configuration.
+ If unsure, say N.
+
config I2C_XLP9XX
tristate "Cavium ThunderX2 I2C support"
depends on ARCH_THUNDER2 || COMPILE_TEST
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index 8425a540f..6c0f04aaa 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -1650,3 +1650,7 @@ MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_AUTHOR("info@mocean-labs.com");
MODULE_DESCRIPTION("Xilinx I2C bus driver");
MODULE_LICENSE("GPL v2");
+
+#if IS_ENABLED(CONFIG_I2C_XILINX_KUNIT_TEST)
+#include "tests/i2c_xiic_kunit.c"
+#endif
diff --git a/drivers/i2c/busses/tests/i2c_xiic_kunit.c b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
new file mode 100644
index 000000000..b4c818d8b
--- /dev/null
+++ b/drivers/i2c/busses/tests/i2c_xiic_kunit.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Included by i2c-xiic.c to exercise the driver's private accessors. */
+#include <kunit/test.h>
+
+struct xiic_access_param {
+ const char *name;
+ enum xiic_endian endianness;
+ bool force_32bit_access;
+};
+
+static const struct xiic_access_param xiic_access_params[] = {
+ { "native_little_endian", LITTLE, false },
+ { "native_big_endian", BIG, false },
+ { "word_little_endian", LITTLE, true },
+ { "word_big_endian", BIG, true },
+};
+
+KUNIT_ARRAY_PARAM_DESC(xiic_access, xiic_access_params, name);
+
+static void xiic_register_access(struct kunit *test)
+{
+ static const int offsets[] = {
+ XIIC_DGIER_OFFSET, XIIC_IISR_OFFSET, XIIC_IIER_OFFSET,
+ XIIC_RESETR_OFFSET, XIIC_CR_REG_OFFSET, XIIC_SR_REG_OFFSET,
+ XIIC_DTR_REG_OFFSET, XIIC_DRR_REG_OFFSET, XIIC_ADR_REG_OFFSET,
+ XIIC_TFO_REG_OFFSET, XIIC_RFO_REG_OFFSET, XIIC_TBA_REG_OFFSET,
+ XIIC_RFD_REG_OFFSET, XIIC_GPO_REG_OFFSET,
+ XIIC_TSUSTA_REG_OFFSET, XIIC_TSUSTO_REG_OFFSET,
+ XIIC_THDSTA_REG_OFFSET,
+ XIIC_TSUDAT_REG_OFFSET, XIIC_TBUF_REG_OFFSET,
+ XIIC_THIGH_REG_OFFSET, XIIC_TLOW_REG_OFFSET,
+ XIIC_THDDAT_REG_OFFSET,
+ };
+ const struct xiic_access_param *param = test->param_value;
+ struct xiic_i2c *i2c;
+ u32 expected;
+ u8 *mem;
+ size_t i;
+ int reg;
+
+ i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, i2c);
+ mem = kunit_kmalloc(test, 0x200, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, mem);
+ /* Aligned RAM stands in for MMIO. No hardware is accessed. */
+ i2c->base = (void __force __iomem *)(mem + sizeof(u32));
+ i2c->endianness = param->endianness;
+ i2c->force_32bit_access = param->force_32bit_access;
+
+ for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+ reg = offsets[i];
+ memset(mem, 0xa5, 0x200);
+
+ xiic_setreg8(i2c, reg, 0xc0);
+ expected = param->force_32bit_access ? 0xc0 : 0xa5a5a5c0;
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), expected);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xc0);
+
+ xiic_setreg16(i2c, reg, 0x03ff);
+ expected = param->force_32bit_access ? 0x03ff : 0xa5a503ff;
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg), expected);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xff);
+
+ xiic_setreg32(i2c, reg, 0x12345678);
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg),
+ 0x12345678U);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0x78);
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32)],
+ (u8)(param->endianness == BIG ? 0x12 : 0x78));
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32) + 3],
+ (u8)(param->endianness == BIG ? 0x78 : 0x12));
+ xiic_setreg32(i2c, reg, 0x89abcdefU);
+ KUNIT_EXPECT_EQ(test, (u32)xiic_getreg32(i2c, reg),
+ 0x89abcdefU);
+ KUNIT_EXPECT_EQ(test, xiic_getreg8(i2c, reg), (u8)0xef);
+ KUNIT_EXPECT_EQ(test, mem[reg + sizeof(u32) - 1], (u8)0xa5);
+ KUNIT_EXPECT_EQ(test, mem[reg + 2 * sizeof(u32)], (u8)0xa5);
+ }
+}
+
+static struct kunit_case xiic_access_test_cases[] = {
+ KUNIT_CASE_PARAM(xiic_register_access, xiic_access_gen_params),
+ {}
+};
+
+static struct kunit_suite xiic_access_test_suite = {
+ .name = "i2c_xiic",
+ .test_cases = xiic_access_test_cases,
+};
+
+kunit_test_suite(xiic_access_test_suite);
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net-next v2 3/3] ptp: ocp: support the WiWi revision 02 Time Card
2026-11-12 16:33 [PATCH net-next v2 0/3] ptp: ocp: support the WiWi production Time Card Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
@ 2026-11-12 16:33 ` Ahmad Byagowi
2 siblings, 0 replies; 4+ messages in thread
From: Ahmad Byagowi @ 2026-11-12 16:33 UTC (permalink / raw)
To: netdev, vadim.fedorenko, andi.shyti
Cc: linux-i2c, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Randy Dunlap, Richard Cochran, Andrew Lunn, linux-doc,
linux-kernel
Match WiWi 2163:1008, subsystem 10ee:0007. NetTimeLogic uses the PCI
Revision ID for incompatible interface changes. Revision 02 identifies
the LitePCIe/MSI-X interface; the Xilinx subsystem ID and FPGA build
number do not identify the register interface. Reject unknown revisions
and check BAR0 and the MSI-X layout before accessing FPGA registers.
Do not probe a CoreList or require exact versions of individual cores.
Report the full 32-bit image ID as the running firmware build. Derive
signal and frequency capabilities from the supported revision, not the
legacy FB build-number thresholds. Retain legacy version behavior on
other cards.
Translate a copy of each peripheral resource by 0x02000000 and its
interrupt input by 32. Use aligned 32-bit UART and XIIC register I/O.
Leave GNSS2 unregistered: it is not wired on the tested production
image. Do not change other cards' resource tables or access modes.
Open the UART, I2C and SPI inputs before probing children: SPI NOR
identification can wait for an interrupt. Enable timing inputs after
registering the PHC and its consumers. Keep unused inputs masked and
leave child interrupts available through removal.
Reject WiWi devlink flash updates before looking up or modifying MTD.
The flash header differs from Celestica and the vendor update path
requires a modified spi-xilinx. Device recognition is not validation
of an update path.
Thomas Schaub of NetTimeLogic described the production register layout
and interrupt gate on 10 November 2026 and the PCI revision convention
on 11 November.
On a revision 02 production card, devlink reported build 0x0000800f.
The driver allocated 64 MSI-X vectors, registered the PHC, PPS and
three UARTs, and exposed four generator and four frequency-counter
groups. SPI NOR and both at24 devices bound. The PHC advanced
3.000441080 s over three one-second sleeps, with each delta inside
the host monotonic bounds. PCIe AER counters did not change. The clock
reported UNSYNCED at probe; the test did not establish PPS lock or UTC.
Tool-origin disclosure: Codex assisted with the driver changes, tests
and changelog using the supplied hardware evidence and revision rule.
Signed-off-by: Ahmad Byagowi <ahmadexp@gmail.com>
---
Documentation/networking/devlink/ptp_ocp.rst | 36 +++-
drivers/ptp/ptp_ocp.c | 163 ++++++++++++++++++-
2 files changed, 190 insertions(+), 9 deletions(-)
diff --git a/Documentation/networking/devlink/ptp_ocp.rst b/Documentation/networking/devlink/ptp_ocp.rst
index f94b759d9..2515dcccd 100644
--- a/Documentation/networking/devlink/ptp_ocp.rst
+++ b/Documentation/networking/devlink/ptp_ocp.rst
@@ -54,7 +54,8 @@ selected with the component name.
- Description
* - (none)
- The card's own flash, written through the SPI controller the driver
- exposes. The card runs the new image after its next reset.
+ exposes. Not supported on WiWi. The card runs the new image after
+ its next reset.
* - ``fw.cpld``
- The configuration flash of the TAP CPLD on ADVA TimeCard X1 boards,
programmed over I2C with the MachXO3 in-system programming commands
@@ -73,3 +74,36 @@ with the standard devlink status notifications.
Example::
$ devlink dev flash pci/0000:02:00.0 file adva-cpld.bin component fw.cpld
+
+WiWi production firmware
+========================
+
+WiWi Time Cards with PCI ID ``2163:1008`` and subsystem ID ``10ee:0007``
+use the PCI Revision ID to identify the register interface. The driver
+supports revision ``02`` (LitePCIe/MSI-X) and rejects unknown revisions
+before accessing FPGA registers. Incompatible interface changes require
+a new revision. The driver also checks the BAR and MSI-X layout before
+initializing the card.
+
+The image ID at BAR0 offset ``0x02020000`` identifies a firmware build,
+not the register interface. The running ``fw`` version in devlink reports
+the full image ID, for example ``0x0000800f``. Compatible builds need not
+have the same image ID or individual core versions. PCIe access to the
+CoreList is not required.
+
+The image uses the Celestica LitePCIe production map: add ``0x02000000``
+to the peripheral offsets and use aligned 32-bit MMIO. Interrupt input
+``n`` uses MSI-X vector ``n + 32``. The per-input enable mask is at BAR0
+offset ``0x1800``. The driver enables the SPI interrupt before probing
+the flash and defers timing interrupts until the PHC is ready. GNSS2 is
+not wired to pins on the tested image; no second GNSS port is registered.
+The separate EEPROM and RGB I2C inputs (17 and 18) have no handlers in
+this driver and stay masked; these are distinct from its I2C input 7.
+
+WiWi firmware updates through ``devlink dev flash`` are not supported.
+The WiWi image has a different flash header from the Celestica image.
+The golden image at flash offset zero boots the update image via MultiBoot
+with watchdog fallback. The vendor's programming path requires a modified
+``spi-xilinx`` driver. Recognizing the SPI NOR does not validate that path
+or the image header. Successful clock registration does not establish
+GNSS synchronization or valid UTC.
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 625a85b2d..10ad2fbeb 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -34,6 +34,23 @@
#define PCI_VENDOR_ID_CELESTICA 0x18d4
#define PCI_DEVICE_ID_CELESTICA_TIMECARD 0x1008
+#define PCI_VENDOR_ID_WIWI 0x2163
+#define PCI_DEVICE_ID_WIWI_TIMECARD 0x1008
+
+/* WiWi production firmware uses the Celestica map behind LitePCIe. */
+#define OCP_WIWI_MMIO_OFFSET 0x02000000
+#define OCP_WIWI_IRQ_OFFSET 32
+#define OCP_WIWI_MSI_ENABLE 0x1800
+/* Upper 32 bits: UARTs, I2C and SPI can interrupt during probe. */
+#define OCP_WIWI_PERIPHERAL_IRQS (BIT(3) | BIT(5) | BIT(7) | \
+ BIT(9) | BIT(10))
+/* PPS/TS0/TS1, TS2, GEN1-4 and TS3/TS4. */
+#define OCP_WIWI_TIMING_IRQS (GENMASK(2, 0) | BIT(6) | \
+ GENMASK(16, 11))
+/* Leave unwired GNSS2 (4), HWICAP (8) and EEPROM/RGB I2C (17/18) masked. */
+#define OCP_WIWI_IRQS (OCP_WIWI_PERIPHERAL_IRQS | \
+ OCP_WIWI_TIMING_IRQS)
+
#define PCI_VENDOR_ID_OROLIA 0x1ad7
#define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000
@@ -404,6 +421,9 @@ struct ptp_ocp {
struct delayed_work sync_work;
int id;
int n_irqs;
+ bool wiwi;
+ u32 wiwi_image_id;
+ void __iomem *wiwi_msi;
struct ptp_ocp_serial_port port[__PORT_COUNT];
bool fw_loader;
u8 fw_tag;
@@ -1321,6 +1341,13 @@ static struct ocp_resource ocp_adva_x1_resource[] = {
static const struct pci_device_id ptp_ocp_pcidev_id[] = {
{ PCI_DEVICE_DATA(META, TIMECARD, &ocp_fb_resource) },
{ PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_WIWI, PCI_DEVICE_ID_WIWI_TIMECARD,
+ PCI_VENDOR_ID_XILINX, 0x0007),
+ .class = PCI_CLASS_MEMORY_OTHER << 8,
+ .class_mask = 0xffffff,
+ .driver_data = (kernel_ulong_t)ocp_fb_resource,
+ },
{ PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) },
{ PCI_DEVICE_DATA(ADVA, TIMECARD, &ocp_adva_resource) },
{ PCI_DEVICE_DATA(ADVA, TIMECARD_X1, &ocp_adva_x1_resource) },
@@ -2173,6 +2200,12 @@ ptp_ocp_devlink_flash_update(struct devlink *devlink,
const char *msg;
int err;
+ if (bp->wiwi) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "WiWi flash updates are not supported");
+ return -EOPNOTSUPP;
+ }
+
if (params->component) {
if (!bp->has_cpld ||
strcmp(params->component, ADVA_CPLD_COMPONENT)) {
@@ -2219,7 +2252,10 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
u32 id;
fw_image = bp->fw_loader ? "loader" : "fw";
- sprintf(buf, "%d.%d", bp->fw_tag, bp->fw_version);
+ if (bp->wiwi)
+ snprintf(buf, sizeof(buf), "0x%08x", bp->wiwi_image_id);
+ else
+ sprintf(buf, "%d.%d", bp->fw_tag, bp->fw_version);
err = devlink_info_version_running_put(req, fw_image, buf);
if (err)
return err;
@@ -2331,20 +2367,29 @@ ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r)
}
static struct platform_device *
-ptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id)
+ptp_ocp_i2c_bus(struct ptp_ocp *bp, struct ocp_resource *r, int id)
{
+ struct xiic_i2c_platform_data wiwi_data;
+ struct pci_dev *pdev = bp->pdev;
struct ptp_ocp_i2c_info *info;
struct resource res[2];
resource_size_t start;
+ const void *data;
info = r->extra;
+ data = info->data;
+ if (bp->wiwi) {
+ wiwi_data = *(struct xiic_i2c_platform_data *)info->data;
+ wiwi_data.force_32bit_access = true;
+ data = &wiwi_data;
+ }
start = pci_resource_start(pdev, 0) + r->offset;
res[0] = DEFINE_RES_MEM(start, r->size);
res[1] = DEFINE_RES_IRQ(pci_irq_vector(pdev, r->irq_vec));
return platform_device_register_resndata(&pdev->dev, info->name,
id, res, ARRAY_SIZE(res),
- info->data, info->data_size);
+ data, info->data_size);
}
static int
@@ -2369,7 +2414,7 @@ ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r)
sprintf(buf, "%s.%d", info->name, id);
devm_clk_hw_register_clkdev(&pdev->dev, clk, NULL, buf);
- p = ptp_ocp_i2c_bus(bp->pdev, r, id);
+ p = ptp_ocp_i2c_bus(bp, r, id);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -2640,7 +2685,7 @@ ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r)
*/
memset(&uart, 0, sizeof(uart));
uart.port.dev = &pdev->dev;
- uart.port.iotype = UPIO_MEM;
+ uart.port.iotype = bp->wiwi ? UPIO_MEM32 : UPIO_MEM;
uart.port.regshift = 2;
uart.port.mapbase = pci_resource_start(pdev, 0) + r->offset;
uart.port.irq = pci_irq_vector(pdev, r->irq_vec);
@@ -3036,6 +3081,13 @@ ptp_ocp_fb_set_version(struct ptp_ocp *bp)
version = ioread32(&bp->image->version);
+ if (bp->wiwi) {
+ /* Revision 02 defines capabilities; report the build ID. */
+ bp->wiwi_image_id = version;
+ bp->fw_cap = OCP_CAP_BASIC | OCP_CAP_SIGNAL | OCP_CAP_FREQ;
+ return;
+ }
+
/* if lower 16 bits are empty, this is the fw loader. */
if ((version & 0xffff) == 0) {
version = version >> 16;
@@ -3068,7 +3120,6 @@ ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
bp->flash_start = 1024 * 4096;
bp->eeprom_map = fb_eeprom_map;
- bp->fw_version = ioread32(&bp->image->version);
bp->sma_op = &ocp_fb_sma_op;
bp->signals_nr = 4;
bp->freq_in_nr = 4;
@@ -3109,7 +3160,26 @@ ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data)
int err = 0;
table = (struct ocp_resource *)driver_data;
- for (r = table; r->setup; r++) {
+ for (; table->setup; table++) {
+ struct ocp_resource translated = *table;
+
+ r = table;
+ if (bp->wiwi) {
+ /* GNSS2 is instantiated but not routed to FPGA pins. */
+ if (r->setup == ptp_ocp_register_serial &&
+ r->bp_offset == offsetof(struct ptp_ocp,
+ port[PORT_GNSS2]))
+ continue;
+ /* Leave the shared resource table unchanged. */
+ if (translated.offset)
+ translated.offset += OCP_WIWI_MMIO_OFFSET;
+ if (r->setup == ptp_ocp_register_ext ||
+ r->setup == ptp_ocp_register_serial ||
+ r->setup == ptp_ocp_register_i2c ||
+ r->setup == ptp_ocp_register_spi)
+ translated.irq_vec += OCP_WIWI_IRQ_OFFSET;
+ r = &translated;
+ }
if (!ptp_ocp_allow_irq(bp, r))
continue;
err = r->setup(bp, r);
@@ -5786,6 +5856,12 @@ ptp_ocp_detach(struct ptp_ocp *bp)
platform_device_unregister(bp->i2c_ctrl);
if (bp->i2c_clk)
clk_hw_unregister_fixed_rate(bp->i2c_clk);
+ /* Child removal can need interrupts, notably SPI NOR reset. */
+ if (bp->wiwi_msi) {
+ iowrite32(0, bp->wiwi_msi);
+ iowrite32(0, bp->wiwi_msi + 4);
+ ioread32(bp->wiwi_msi);
+ }
if (bp->n_irqs)
pci_free_irq_vectors(bp->pdev);
mutex_destroy(&bp->cpld_lock);
@@ -5951,6 +6027,49 @@ ptp_ocp_sync_work(struct work_struct *work)
queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ);
}
+/* The PCI revision identifies the register interface, not the FPGA build. */
+static int ptp_ocp_wiwi_validate(struct pci_dev *pdev)
+{
+ u32 table, pba;
+ int cap;
+
+ if (pdev->revision != 0x02)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Unsupported WiWi PCI revision %#02x\n",
+ pdev->revision);
+
+ cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(pdev, 0) != 0x04000000 || !cap ||
+ pci_msix_vec_count(pdev) != 64 ||
+ pci_read_config_dword(pdev, cap + PCI_MSIX_TABLE, &table) ||
+ pci_read_config_dword(pdev, cap + PCI_MSIX_PBA, &pba) ||
+ table != 0x2000 || pba != 0x1808)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Unsupported WiWi PCI layout\n");
+
+ return 0;
+}
+
+static int ptp_ocp_wiwi_irq_init(struct ptp_ocp *bp)
+{
+ void __iomem *msi;
+
+ msi = __ptp_ocp_get_mem(bp, pci_resource_start(bp->pdev, 0) +
+ OCP_WIWI_MSI_ENABLE, 8);
+ if (IS_ERR(msi))
+ return PTR_ERR(msi);
+ bp->wiwi_msi = msi;
+
+ /* LiteX stores bits 63:32 before bits 31:0, as little-endian words. */
+ iowrite32(0, msi);
+ iowrite32(0, msi + 4);
+ if (ioread32(msi) || ioread32(msi + 4))
+ return -EIO;
+
+ return 0;
+}
+
static int
ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -5972,6 +6091,14 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
bp = devlink_priv(devlink);
+ bp->wiwi = pdev->vendor == PCI_VENDOR_ID_WIWI &&
+ pdev->device == PCI_DEVICE_ID_WIWI_TIMECARD;
+ if (bp->wiwi) {
+ /* Validate before IRQ setup, bus mastering or FPGA writes. */
+ err = ptp_ocp_wiwi_validate(pdev);
+ if (err)
+ goto out_disable;
+ }
err = ptp_ocp_device_init(bp, pdev);
if (err)
goto out_disable;
@@ -5987,18 +6114,33 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_DELAYED_WORK(&bp->sync_work, ptp_ocp_sync_work);
+ if (bp->wiwi) {
+ err = ptp_ocp_wiwi_irq_init(bp);
+ if (err)
+ goto out;
+ }
+
/* compat mode.
* Older FPGA firmware only returns 2 irq's.
* allow this - if not all of the IRQ's are returned, skip the
* extra devices and just register the clock.
*/
- err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ if (bp->wiwi)
+ err = pci_alloc_irq_vectors(pdev, 49, 64, PCI_IRQ_MSIX);
+ else
+ err = pci_alloc_irq_vectors(pdev, 1, 17,
+ PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (err < 0) {
dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err);
goto out;
}
bp->n_irqs = err;
pci_set_master(pdev);
+ /* SPI NOR needs IRQs now; timestamp consumers are not ready. */
+ if (bp->wiwi_msi) {
+ iowrite32(OCP_WIWI_PERIPHERAL_IRQS, bp->wiwi_msi);
+ ioread32(bp->wiwi_msi);
+ }
err = ptp_ocp_register_resources(bp, id->driver_data);
if (err)
@@ -6047,6 +6189,11 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_dpll;
}
}
+ /* All handlers and the PHC are ready for timestamp interrupts. */
+ if (bp->wiwi_msi) {
+ iowrite32(OCP_WIWI_IRQS, bp->wiwi_msi);
+ ioread32(bp->wiwi_msi);
+ }
queue_delayed_work(system_power_efficient_wq, &bp->sync_work, HZ);
return 0;
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-12 16:33 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 16:33 [PATCH net-next v2 0/3] ptp: ocp: support the WiWi production Time Card Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 1/3] i2c: xiic: allow platforms to require 32-bit register accesses Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 2/3] i2c: xiic: add KUnit coverage for register access modes Ahmad Byagowi
2026-11-12 16:33 ` [PATCH net-next v2 3/3] ptp: ocp: support the WiWi revision 02 Time Card Ahmad Byagowi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox