* [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
@ 2026-09-17 7:08 Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 1/6] bus: mhi: host: Add support to read MHI capabilities Krishna Chaitanya Chundru
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev,
Krishna Chaitanya Chundru, Vivek Pernamitta, Sivareddy Surasani,
Taniya Das, Imran Shaik, Vivek Pernamitta
This series adds support for exposing the device-side timestamp provided
by the MHI TSC Timesync capability as a PTP Hardware Clock (PHC).
The series introduces an MHI PHC driver that registers a PTP clock and
uses the TSC Timesync capability to retrieve device timestamps. These
timestamps are exposed through the Linux PTP framework, enabling host
and device clock correlation using standard userspace PTP interfaces.
To support efficient timestamp retrieval, the series also adds generic
64-bit MHI register access support and capability discovery APIs used by
the PHC driver.
The following diagram illustrates the architecture and data flow:
+---------------+ +----------------------+ +----------------+
| Userspace App | | Kernel PTP framework | | MHI PHC Driver |
+---------------+ +----------------------+ +----------------+
|
v
+--------------------+
| Endpoint Device |
| (Timestamp source) |
+--------------------+
- User space applications use the standard Linux PTP interface.
- The PTP subsystem routes IOCTLs to the MHI PHC driver.
- The PHC driver communicates with the MHI device to get the time data.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
Changes in v3:
- Use mutex instead of spinlock & couple of nits (Jie).
- Move all tsc timesync to mhi_phc.c (Mani). Moved the init part also as
it is easy to control from controller without mhi core dependency.
- Couple of nits & de-register ptp driver in case of syserror and enable
back in mission mode (Mani)
- use PTP_SYS_OFFSET_EXTENDED to read multiple samples and also support
multiple clock ids by using ptp_read_system_prets & ptp_read_system_postts (Vadim Fedorenko)
- Link to v2: https://lore.kernel.org/r/20260411-tsc_timesync-v2-0-6f25f72987b3@oss.qualcomm.com
Changes in V2:
- Rebases to the latest code.
- Patch 1 (bus: mhi: host: Add support to read MHI capabilities) which
is dependent change was brought it here as the series which this patch
is part need to re-designed and will take time https://lore.kernel.org/all/CAFEp6-0ik4B20cRyid9w0f+UgibGciPof9HCWTJ=uBOPvHG35Q@mail.gmail.com/.
- Link to v1: https://lore.kernel.org/all/20250818-tsc_time_sync-v1-0-2747710693ba@oss.qualcomm.com/
---
Krishna Chaitanya Chundru (5):
bus: mhi: host: mhi_phc: Add support for PHC over MHI
bus: mhi: host: Add support for 64bit register reads and writes
bus: mhi: pci_generic: Add support for 64 bit register read & write
bus: mhi: host: Export mhi_read_reg
bus: mhi: host: mhi_phc: Update the Time sync logic to read 64 bit register value
Vivek Pernamitta (1):
bus: mhi: host: Add support to read MHI capabilities
drivers/bus/mhi/common.h | 15 ++++
drivers/bus/mhi/host/Kconfig | 9 +++
drivers/bus/mhi/host/Makefile | 2 +
drivers/bus/mhi/host/init.c | 65 +++++++++++++++
drivers/bus/mhi/host/internal.h | 35 ++++++++
drivers/bus/mhi/host/main.c | 14 ++++
drivers/bus/mhi/host/mhi_phc.c | 161 +++++++++++++++++++++++++++++++++++++
drivers/bus/mhi/host/mhi_phc.h | 21 +++++
drivers/bus/mhi/host/pci_generic.c | 29 +++++++
include/linux/mhi.h | 11 +++
10 files changed, 362 insertions(+)
---
base-commit: 238650ef6c7c7cca08e032527329424c9fbd70e5
change-id: 20260411-tsc_timesync-f877a0394393
Best regards,
--
Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/6] bus: mhi: host: Add support to read MHI capabilities
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 2/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev,
Krishna Chaitanya Chundru, Vivek Pernamitta, Sivareddy Surasani
From: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
As per MHI spec v1.2,sec 6.6, MHI has capability registers which are
located after the ERDB array. The location of this group of registers is
indicated by the MISCOFF register. Each capability has a capability ID to
determine which functionality is supported and each capability will point
to the next capability supported.
Add a basic function to read those capabilities offsets.
Signed-off-by: Vivek Pernamitta <vivek.pernamitta@oss.qualcomm.com>
Signed-off-by: Sivareddy Surasani <sivareddy.surasani@oss.qualcomm.com>
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/common.h | 11 +++++++++++
drivers/bus/mhi/host/init.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
index dda340aaed95..4c316f3d5a68 100644
--- a/drivers/bus/mhi/common.h
+++ b/drivers/bus/mhi/common.h
@@ -16,6 +16,7 @@
#define MHICFG 0x10
#define CHDBOFF 0x18
#define ERDBOFF 0x20
+#define MISCOFF 0x24
#define BHIOFF 0x28
#define BHIEOFF 0x2c
#define DEBUGOFF 0x30
@@ -113,6 +114,9 @@
#define MHISTATUS_MHISTATE_MASK GENMASK(15, 8)
#define MHISTATUS_SYSERR_MASK BIT(2)
#define MHISTATUS_READY_MASK BIT(0)
+#define MISC_CAP_MASK GENMASK(31, 0)
+#define CAP_CAPID_MASK GENMASK(31, 24)
+#define CAP_NEXT_CAP_MASK GENMASK(23, 12)
/* Command Ring Element macros */
/* No operation command */
@@ -204,6 +208,13 @@
#define MHI_RSCTRE_DATA_DWORD1 cpu_to_le32(FIELD_PREP(GENMASK(23, 16), \
MHI_PKT_TYPE_COALESCING))
+#define MHI_CAP_ID_INTX 0x1
+#define MHI_CAP_ID_TIME_SYNC 0x2
+#define MHI_CAP_ID_BW_SCALE 0x3
+#define MHI_CAP_ID_TSC_TIME_SYNC 0x4
+#define MHI_CAP_ID_MAX_TRB_LEN 0x5
+#define MHI_CAP_ID_MAX 0x6
+
enum mhi_pkt_type {
MHI_PKT_TYPE_INVALID = 0x0,
MHI_PKT_TYPE_NOOP_CMD = 0x1,
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index fd3050889412..7ca2fe48c9ac 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -465,6 +465,38 @@ static int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
return ret;
}
+static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability)
+{
+ u32 val, cur_cap, next_offset, cur_offset;
+ int ret;
+
+ /* Get the first supported capability offset */
+ ret = mhi_read_reg_field(mhi_cntrl, mhi_cntrl->regs, MISCOFF, MISC_CAP_MASK, &cur_offset);
+ if (ret)
+ return 0;
+
+ do {
+ if (cur_offset >= mhi_cntrl->reg_len)
+ return 0;
+
+ ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, cur_offset, &val);
+ if (ret)
+ return 0;
+
+ cur_cap = FIELD_GET(CAP_CAPID_MASK, val);
+ next_offset = FIELD_GET(CAP_NEXT_CAP_MASK, val);
+ if (cur_cap >= MHI_CAP_ID_MAX)
+ return 0;
+
+ if (cur_cap == capability)
+ return cur_offset;
+
+ cur_offset = next_offset;
+ } while (next_offset);
+
+ return 0;
+}
+
int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
{
u32 val;
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 1/6] bus: mhi: host: Add support to read MHI capabilities Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 3/6] bus: mhi: host: Add support for 64bit register reads and writes Krishna Chaitanya Chundru
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev,
Krishna Chaitanya Chundru, Taniya Das, Imran Shaik,
Vivek Pernamitta
Implement the non-posted time synchronization mechanism described in
section 5.1.1 of the MHI v1.2 specification and expose the device clock
as a PTP Hardware Clock.
Discover the TSC Timesync capability during MHI controller
initialization and use the capability offset to access the device TIME
registers. Register the PHC when the device enters mission mode and
unregister it when the device encounters a fatal error, enters a system
error state, or is removed.
When userspace requests a timestamp, keep the MHI device runtime-active
and bring it to the M0 state before accessing the device registers.
Capture system timestamps immediately before and after reading the
device timestamp, allowing userspace to correlate the host and device
clocks through the standard Linux PTP interface.
Co-developed-by: Taniya Das <taniya.das@oss.qualcomm.com>
Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
Co-developed-by: Imran Shaik <imran.shaik@oss.qualcomm.com>
Signed-off-by: Imran Shaik <imran.shaik@oss.qualcomm.com>
Co-developed-by: Vivek Pernamitta <quic_vpernami@quicinc.com>
Signed-off-by: Vivek Pernamitta <quic_vpernami@quicinc.com>
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/common.h | 4 +
drivers/bus/mhi/host/Kconfig | 9 +++
drivers/bus/mhi/host/Makefile | 2 +
drivers/bus/mhi/host/init.c | 33 ++++++++
drivers/bus/mhi/host/internal.h | 31 ++++++++
drivers/bus/mhi/host/mhi_phc.c | 154 +++++++++++++++++++++++++++++++++++++
drivers/bus/mhi/host/mhi_phc.h | 21 +++++
drivers/bus/mhi/host/pci_generic.c | 6 ++
include/linux/mhi.h | 5 ++
9 files changed, 265 insertions(+)
diff --git a/drivers/bus/mhi/common.h b/drivers/bus/mhi/common.h
index 4c316f3d5a68..64f9b2b94387 100644
--- a/drivers/bus/mhi/common.h
+++ b/drivers/bus/mhi/common.h
@@ -118,6 +118,10 @@
#define CAP_CAPID_MASK GENMASK(31, 24)
#define CAP_NEXT_CAP_MASK GENMASK(23, 12)
+/* MHI TSC Timesync */
+#define TSC_TIMESYNC_TIME_LOW_OFFSET (0x8)
+#define TSC_TIMESYNC_TIME_HIGH_OFFSET (0xC)
+
/* Command Ring Element macros */
/* No operation command */
#define MHI_TRE_CMD_NOOP_PTR 0
diff --git a/drivers/bus/mhi/host/Kconfig b/drivers/bus/mhi/host/Kconfig
index da5cd0c9fc62..7609768c0efe 100644
--- a/drivers/bus/mhi/host/Kconfig
+++ b/drivers/bus/mhi/host/Kconfig
@@ -29,3 +29,12 @@ config MHI_BUS_PCI_GENERIC
This driver provides MHI PCI controller driver for devices such as
Qualcomm SDX55 based PCIe modems.
+config MHI_BUS_PHC
+ tristate "MHI PHC driver"
+ depends on MHI_BUS
+ depends on PTP_1588_CLOCK
+ help
+ This driver provides Precision Time Protocol (PTP) clock and
+ communicates with MHI PCI driver to get the device side timestamp,
+ which enables precise time synchronization between the host and
+ the device.
diff --git a/drivers/bus/mhi/host/Makefile b/drivers/bus/mhi/host/Makefile
index 859c2f38451c..f16b3195a03a 100644
--- a/drivers/bus/mhi/host/Makefile
+++ b/drivers/bus/mhi/host/Makefile
@@ -4,3 +4,5 @@ mhi-$(CONFIG_MHI_BUS_DEBUG) += debugfs.o
obj-$(CONFIG_MHI_BUS_PCI_GENERIC) += mhi_pci_generic.o
mhi_pci_generic-y += pci_generic.o
+
+obj-$(CONFIG_MHI_BUS_PHC) += mhi_phc.o
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index 7ca2fe48c9ac..caa307c71890 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -497,6 +497,32 @@ static int mhi_find_capability(struct mhi_controller *mhi_cntrl, u32 capability)
return 0;
}
+#if IS_ENABLED(CONFIG_MHI_BUS_PHC)
+int mhi_init_tsc_timesync(struct mhi_controller *mhi_cntrl)
+{
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ struct mhi_timesync *mhi_tsync;
+ u32 time_offset;
+
+ time_offset = mhi_find_capability(mhi_cntrl, MHI_CAP_ID_TSC_TIME_SYNC);
+ if (!time_offset)
+ return -ENXIO;
+
+ mhi_tsync = devm_kzalloc(dev, sizeof(*mhi_tsync), GFP_KERNEL);
+ if (!mhi_tsync)
+ return -ENOMEM;
+
+ mutex_init(&mhi_tsync->ts_mutex);
+
+ /* save time_offset for obtaining time via MMIO register reads */
+ mhi_tsync->time_reg = mhi_cntrl->regs + time_offset;
+
+ mhi_cntrl->tsc_timesync = mhi_tsync;
+
+ return 0;
+}
+#endif
+
int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
{
u32 val;
@@ -634,6 +660,13 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
return ret;
}
+ /* Discover TSC time sync capability, if present */
+ ret = mhi_init_tsc_timesync(mhi_cntrl);
+ if (ret && ret != -ENXIO) {
+ dev_err(dev, "Error configuring TSC time sync\n");
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 7b0ee5e3a12d..ca50961769fa 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -9,6 +9,10 @@
#include "../common.h"
+#if IS_ENABLED(CONFIG_MHI_BUS_PHC)
+#include <linux/ptp_clock_kernel.h>
+#endif
+
extern const struct bus_type mhi_bus_type;
/* Host request register */
@@ -24,6 +28,24 @@ struct mhi_ctxt {
dma_addr_t cmd_ctxt_addr;
};
+#if IS_ENABLED(CONFIG_MHI_BUS_PHC)
+/**
+ * struct mhi_timesync - MHI time synchronization structure
+ * @time_reg: Points to address of Timesync register
+ * @ts_mutex: Mutex for synchronization
+ * @ptp_clock: associated PTP clock
+ * @ptp_clock_info: PTP clock information
+ * @mhi_dev: associated mhi device object
+ */
+struct mhi_timesync {
+ void __iomem *time_reg;
+ struct mutex ts_mutex;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_info;
+ struct mhi_device *mhi_dev;
+};
+#endif
+
struct bhi_vec_entry {
__le64 dma_addr;
__le64 size;
@@ -388,6 +410,15 @@ int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
struct image_info *img_info);
void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl);
+#if IS_ENABLED(CONFIG_MHI_BUS_PHC)
+int mhi_init_tsc_timesync(struct mhi_controller *mhi_cntrl);
+#else
+static inline int mhi_init_tsc_timesync(struct mhi_controller *mhi_cntrl)
+{
+ return 0;
+}
+#endif
+
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
struct mhi_chan *mhi_chan);
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
diff --git a/drivers/bus/mhi/host/mhi_phc.c b/drivers/bus/mhi/host/mhi_phc.c
new file mode 100644
index 000000000000..783f05b5d144
--- /dev/null
+++ b/drivers/bus/mhi/host/mhi_phc.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/mhi.h>
+#include <linux/ptp_clock_kernel.h>
+#include "../common.h"
+#include "internal.h"
+#include "mhi_phc.h"
+
+/**
+ * struct mhi_timesync_info - MHI time sync info structure
+ * @t_dev_lo: MHI device time of lower dword
+ * @t_dev_hi: MHI device time of higher dword
+ */
+struct mhi_timesync_info {
+ u32 t_dev_lo;
+ u32 t_dev_hi;
+};
+
+static int mhi_get_remote_tsc_time_sync(struct mhi_device *mhi_dev, struct mhi_timesync_info *time,
+ struct ptp_system_timestamp *sts)
+{
+ struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
+ struct mhi_timesync *mhi_tsync = mhi_cntrl->tsc_timesync;
+ struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ u64 val = U64_MAX;
+ u32 hi, lo = 0;
+ int ret;
+
+ if (!mhi_tsync || !mhi_tsync->time_reg) {
+ dev_err(dev, "Time sync is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ mhi_cntrl->runtime_get(mhi_cntrl);
+
+ /* bring to M0 state */
+ ret = mhi_device_get_sync(mhi_cntrl->mhi_dev);
+ if (ret) {
+ mhi_cntrl->runtime_put(mhi_cntrl);
+ return ret;
+ }
+
+ guard(mutex)(&mhi_tsync->ts_mutex);
+
+ // TODO: Disable ASPM
+
+ /*
+ * time critical code to fetch device time, delay between these two steps
+ * should be deterministic as possible.
+ */
+ preempt_disable();
+ local_irq_disable();
+
+ ptp_read_system_prets(sts);
+
+ /*
+ * Read the high dword twice around the low dword and retry if it
+ * changed, to avoid a torn read across a device-side rollover.
+ */
+ do {
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_HIGH_OFFSET, &hi);
+ if (ret)
+ break;
+
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_LOW_OFFSET, &lo);
+ if (ret)
+ break;
+
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_HIGH_OFFSET, &time->t_dev_hi);
+ } while (!ret && hi != time->t_dev_hi);
+
+ time->t_dev_lo = lo;
+
+ ptp_read_system_postts(sts);
+
+ local_irq_enable();
+ preempt_enable();
+
+ mhi_device_put(mhi_cntrl->mhi_dev);
+
+ mhi_cntrl->runtime_put(mhi_cntrl);
+
+ return ret;
+}
+
+static int qcom_ptp_gettimex64(struct ptp_clock_info *ptp, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct mhi_timesync *mhi_tsync = container_of(ptp, struct mhi_timesync, ptp_clock_info);
+ struct mhi_timesync_info time;
+ ktime_t ktime_cur;
+ int ret;
+
+ ret = mhi_get_remote_tsc_time_sync(mhi_tsync->mhi_dev, &time, sts);
+ if (ret)
+ return ret;
+
+ ktime_cur = time.t_dev_hi * NSEC_PER_SEC + time.t_dev_lo;
+ *ts = ktime_to_timespec64(ktime_cur);
+
+ return 0;
+}
+
+static struct ptp_clock_info qcom_ptp_clock_info = {
+ .owner = THIS_MODULE,
+ .gettimex64 = qcom_ptp_gettimex64,
+};
+
+int mhi_phc_init(struct mhi_controller *mhi_cntrl)
+{
+ struct mhi_device *mhi_dev = mhi_cntrl->mhi_dev;
+ struct mhi_timesync *mhi_tsync = mhi_cntrl->tsc_timesync;
+ int ret;
+
+ if (!mhi_tsync)
+ return -ENODEV;
+
+ mhi_tsync->mhi_dev = mhi_dev;
+
+ mhi_tsync->ptp_clock_info = qcom_ptp_clock_info;
+ strscpy(mhi_tsync->ptp_clock_info.name, mhi_dev->name, PTP_CLOCK_NAME_LEN);
+
+ mhi_tsync->ptp_clock = ptp_clock_register(&mhi_tsync->ptp_clock_info, &mhi_dev->dev);
+ if (IS_ERR(mhi_tsync->ptp_clock)) {
+ ret = PTR_ERR(mhi_tsync->ptp_clock);
+ dev_err(&mhi_dev->dev, "Failed to register PTP clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mhi_phc_init);
+
+void mhi_phc_exit(struct mhi_controller *mhi_cntrl)
+{
+ struct mhi_timesync *mhi_tsync = mhi_cntrl->tsc_timesync;
+
+ if (!mhi_tsync || !mhi_tsync->ptp_clock)
+ return;
+
+ ptp_clock_unregister(mhi_tsync->ptp_clock);
+ mhi_tsync->ptp_clock = NULL;
+}
+EXPORT_SYMBOL_GPL(mhi_phc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MHI PHC driver");
diff --git a/drivers/bus/mhi/host/mhi_phc.h b/drivers/bus/mhi/host/mhi_phc.h
new file mode 100644
index 000000000000..263574ca53da
--- /dev/null
+++ b/drivers/bus/mhi/host/mhi_phc.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _MHI_PHC_H
+#define _MHI_PHC_H
+
+#if IS_ENABLED(CONFIG_MHI_BUS_PHC)
+int mhi_phc_init(struct mhi_controller *mhi_cntrl);
+void mhi_phc_exit(struct mhi_controller *mhi_cntrl);
+#else
+static inline int mhi_phc_init(struct mhi_controller *mhi_cntrl)
+{
+ return 0;
+}
+
+static inline void mhi_phc_exit(struct mhi_controller *mhi_cntrl) {}
+#endif
+
+#endif /* _MHI_PHC_H */
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index b636e2c23b4d..f47867ced1d6 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include "mhi_phc.h"
#define MHI_PCI_DEFAULT_BAR_NUM 0
@@ -1123,9 +1124,11 @@ static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
case MHI_CB_FATAL_ERROR:
case MHI_CB_SYS_ERROR:
dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb);
+ mhi_phc_exit(mhi_cntrl);
pm_runtime_forbid(&pdev->dev);
break;
case MHI_CB_EE_MISSION_MODE:
+ mhi_phc_init(mhi_cntrl);
pm_runtime_allow(&pdev->dev);
break;
default:
@@ -1491,6 +1494,9 @@ static void mhi_pci_remove(struct pci_dev *pdev)
timer_delete_sync(&mhi_pdev->health_check_timer);
cancel_work_sync(&mhi_pdev->recovery_work);
+ /* Remove PHC */
+ mhi_phc_exit(mhi_cntrl);
+
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
mhi_power_down(mhi_cntrl, true);
mhi_unprepare_after_power_down(mhi_cntrl);
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 8616bacd8675..e994ca4f9810 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -23,6 +23,8 @@ struct mhi_event;
struct mhi_ctxt;
struct mhi_cmd;
struct mhi_buf_info;
+struct mhi_timesync;
+
/**
* enum mhi_callback - MHI callback
@@ -341,6 +343,7 @@ struct mhi_controller_config {
* @mhi_event: MHI event ring configurations table
* @mhi_cmd: MHI command ring configurations table
* @mhi_ctxt: MHI device context, shared memory between host and device
+ * @tsc_timesync: MHI TSC timesync
* @pm_mutex: Mutex for suspend/resume operation
* @pm_lock: Lock for protecting MHI power management state
* @timeout_ms: Timeout in ms for state transitions
@@ -422,6 +425,8 @@ struct mhi_controller {
struct mhi_cmd *mhi_cmd;
struct mhi_ctxt *mhi_ctxt;
+ struct mhi_timesync *tsc_timesync;
+
struct mutex pm_mutex;
rwlock_t pm_lock;
u32 timeout_ms;
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/6] bus: mhi: host: Add support for 64bit register reads and writes
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 1/6] bus: mhi: host: Add support to read MHI capabilities Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 2/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 4/6] bus: mhi: pci_generic: Add support for 64 bit register read & write Krishna Chaitanya Chundru
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev, Krishna Chaitanya Chundru
Some mhi registers are of 64 bit size, instead of reading high value
and low value separately provide a new function op to read & write to
64 bit register.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/host/internal.h | 4 ++++
drivers/bus/mhi/host/main.c | 13 +++++++++++++
include/linux/mhi.h | 6 ++++++
3 files changed, 23 insertions(+)
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index ca50961769fa..bb96dfffabb6 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -386,6 +386,8 @@ void mhi_db_brstmode_disable(struct mhi_controller *mhi_cntrl,
dma_addr_t db_val);
int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 *out);
+int __must_check mhi_read_reg64(struct mhi_controller *mhi_cntrl,
+ void __iomem *base, u32 offset, u64 *out);
int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 mask,
u32 *out);
@@ -394,6 +396,8 @@ int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
u32 val, u32 delayus, u32 timeout_ms);
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
u32 offset, u32 val);
+void __maybe_unused mhi_write_reg64(struct mhi_controller *mhi_cntrl, void __iomem *base,
+ u32 offset, u64 val);
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 mask,
u32 val);
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index 4d458396233a..bfeb5cf53448 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -67,6 +67,19 @@ void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
mhi_cntrl->write_reg(mhi_cntrl, base + offset, val);
}
+int __must_check mhi_read_reg64(struct mhi_controller *mhi_cntrl,
+ void __iomem *base, u32 offset, u64 *out)
+{
+ return mhi_cntrl->read_reg64(mhi_cntrl, base + offset, out);
+}
+EXPORT_SYMBOL_GPL(mhi_read_reg64);
+
+void __maybe_unused mhi_write_reg64(struct mhi_controller *mhi_cntrl, void __iomem *base,
+ u32 offset, u64 val)
+{
+ mhi_cntrl->write_reg64(mhi_cntrl, base + offset, val);
+}
+
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 mask,
u32 val)
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index e994ca4f9810..3dc1844222cd 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -374,6 +374,8 @@ struct mhi_controller_config {
* @unmap_single: CB function to destroy TRE buffer
* @read_reg: Read a MHI register via the physical link (required)
* @write_reg: Write a MHI register via the physical link (required)
+ * @read_reg64: Read a 64 bit MHI register via the physical link (optional)
+ * @write_reg64: Write a 64 bit MHI register via the physical link (optional)
* @reset: Controller specific reset function (optional)
* @edl_trigger: CB function to trigger EDL mode (optional)
* @buffer_len: Bounce buffer length
@@ -461,6 +463,10 @@ struct mhi_controller {
u32 *out);
void (*write_reg)(struct mhi_controller *mhi_cntrl, void __iomem *addr,
u32 val);
+ int (*read_reg64)(struct mhi_controller *mhi_cntrl, void __iomem *addr,
+ u64 *out);
+ void (*write_reg64)(struct mhi_controller *mhi_cntrl, void __iomem *addr,
+ u64 val);
void (*reset)(struct mhi_controller *mhi_cntrl);
int (*edl_trigger)(struct mhi_controller *mhi_cntrl);
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 4/6] bus: mhi: pci_generic: Add support for 64 bit register read & write
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
` (2 preceding siblings ...)
2026-09-17 7:08 ` [PATCH v3 3/6] bus: mhi: host: Add support for 64bit register reads and writes Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 5/6] bus: mhi: host: Export mhi_read_reg Krishna Chaitanya Chundru
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev, Krishna Chaitanya Chundru
Add support for reading and writing 64 bit mhi pcie registers.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/host/pci_generic.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index f47867ced1d6..0aa5cee49bdc 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -1101,6 +1101,27 @@ struct mhi_pci_device {
bool reset_on_remove;
};
+#ifdef readq
+static int mhi_pci_read_reg64(struct mhi_controller *mhi_cntrl,
+ void __iomem *addr, u64 *out)
+{
+ *out = readq(addr);
+ return 0;
+}
+#else
+#define mhi_pci_read_reg64 NULL
+#endif
+
+#ifdef writeq
+static void mhi_pci_write_reg64(struct mhi_controller *mhi_cntrl,
+ void __iomem *addr, u64 val)
+{
+ writeq(val, addr);
+}
+#else
+#define mhi_pci_write_reg64 NULL
+#endif
+
static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl,
void __iomem *addr, u32 *out)
{
@@ -1406,6 +1427,8 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mhi_cntrl->read_reg = mhi_pci_read_reg;
mhi_cntrl->write_reg = mhi_pci_write_reg;
+ mhi_cntrl->read_reg64 = mhi_pci_read_reg64;
+ mhi_cntrl->write_reg64 = mhi_pci_write_reg64;
mhi_cntrl->status_cb = mhi_pci_status_cb;
mhi_cntrl->runtime_get = mhi_pci_runtime_get;
mhi_cntrl->runtime_put = mhi_pci_runtime_put;
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 5/6] bus: mhi: host: Export mhi_read_reg
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
` (3 preceding siblings ...)
2026-09-17 7:08 ` [PATCH v3 4/6] bus: mhi: pci_generic: Add support for 64 bit register read & write Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 6/6] bus: mhi: host: mhi_phc: Update the Time sync logic to read 64 bit register value Krishna Chaitanya Chundru
2026-09-17 14:48 ` [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Jakub Kicinski
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev, Krishna Chaitanya Chundru
Export mhi_read_reg() so it can be called from other MHI bus modules
that are built separately from mhi.ko.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/host/main.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index bfeb5cf53448..1ca9f781bbdb 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -22,6 +22,7 @@ int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
{
return mhi_cntrl->read_reg(mhi_cntrl, base + offset, out);
}
+EXPORT_SYMBOL_GPL(mhi_read_reg);
int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset,
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 6/6] bus: mhi: host: mhi_phc: Update the Time sync logic to read 64 bit register value
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
` (4 preceding siblings ...)
2026-09-17 7:08 ` [PATCH v3 5/6] bus: mhi: host: Export mhi_read_reg Krishna Chaitanya Chundru
@ 2026-09-17 7:08 ` Krishna Chaitanya Chundru
2026-09-17 14:48 ` [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Jakub Kicinski
6 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-17 7:08 UTC (permalink / raw)
To: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran
Cc: mhi, linux-arm-msm, linux-kernel, netdev, Krishna Chaitanya Chundru
Instead of reading low and high of the mhi registers twice use 64 bit
register value to avoid any time penalty.
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
---
drivers/bus/mhi/host/mhi_phc.c | 47 ++++++++++++++++++++++++------------------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/drivers/bus/mhi/host/mhi_phc.c b/drivers/bus/mhi/host/mhi_phc.c
index 783f05b5d144..b1d10431bd30 100644
--- a/drivers/bus/mhi/host/mhi_phc.c
+++ b/drivers/bus/mhi/host/mhi_phc.c
@@ -57,26 +57,33 @@ static int mhi_get_remote_tsc_time_sync(struct mhi_device *mhi_dev, struct mhi_t
ptp_read_system_prets(sts);
- /*
- * Read the high dword twice around the low dword and retry if it
- * changed, to avoid a torn read across a device-side rollover.
- */
- do {
- ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
- TSC_TIMESYNC_TIME_HIGH_OFFSET, &hi);
- if (ret)
- break;
-
- ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
- TSC_TIMESYNC_TIME_LOW_OFFSET, &lo);
- if (ret)
- break;
-
- ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
- TSC_TIMESYNC_TIME_HIGH_OFFSET, &time->t_dev_hi);
- } while (!ret && hi != time->t_dev_hi);
-
- time->t_dev_lo = lo;
+ if (mhi_cntrl->read_reg64) {
+ ret = mhi_read_reg64(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_LOW_OFFSET, &val);
+ time->t_dev_lo = (u32)val;
+ time->t_dev_hi = (u32)(val >> 32);
+ } else {
+ /*
+ * Read the high dword twice around the low dword and retry if it
+ * changed, to avoid a torn read across a device-side rollover.
+ */
+ do {
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_HIGH_OFFSET, &hi);
+ if (ret)
+ break;
+
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_LOW_OFFSET, &lo);
+ if (ret)
+ break;
+
+ ret = mhi_read_reg(mhi_cntrl, mhi_tsync->time_reg,
+ TSC_TIMESYNC_TIME_HIGH_OFFSET, &time->t_dev_hi);
+ } while (!ret && hi != time->t_dev_hi);
+
+ time->t_dev_lo = lo;
+ }
ptp_read_system_postts(sts);
--
2.34.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
` (5 preceding siblings ...)
2026-09-17 7:08 ` [PATCH v3 6/6] bus: mhi: host: mhi_phc: Update the Time sync logic to read 64 bit register value Krishna Chaitanya Chundru
@ 2026-09-17 14:48 ` Jakub Kicinski
2026-09-18 10:52 ` Krishna Chaitanya Chundru
6 siblings, 1 reply; 9+ messages in thread
From: Jakub Kicinski @ 2026-09-17 14:48 UTC (permalink / raw)
To: Krishna Chaitanya Chundru
Cc: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran, mhi,
linux-arm-msm, linux-kernel, netdev, Vivek Pernamitta,
Sivareddy Surasani, Taniya Das, Imran Shaik, Vivek Pernamitta
On Thu, 17 Sep 2026 12:38:01 +0530 Krishna Chaitanya Chundru wrote:
> Subject: [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
The MHI "bus" is the worst abstraction I've seen. You're turning it
into "qualcomms corner of the kernel". The PHC drivers belong in
drivers/ptp/
Carry this until told otherwise:
Nacked-by: Jakub Kicinski <kuba@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
2026-09-17 14:48 ` [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Jakub Kicinski
@ 2026-09-18 10:52 ` Krishna Chaitanya Chundru
0 siblings, 0 replies; 9+ messages in thread
From: Krishna Chaitanya Chundru @ 2026-09-18 10:52 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Manivannan Sadhasivam, Jeff Hugo, Richard Cochran, mhi,
linux-arm-msm, linux-kernel, netdev, Vivek Pernamitta,
Sivareddy Surasani, Taniya Das, Imran Shaik, Vivek Pernamitta
On 9/17/2026 8:18 PM, Jakub Kicinski wrote:
> On Thu, 17 Sep 2026 12:38:01 +0530 Krishna Chaitanya Chundru wrote:
>> Subject: [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI
> The MHI "bus" is the worst abstraction I've seen. You're turning it
> into "qualcomms corner of the kernel". The PHC drivers belong in
> drivers/ptp/
>
> Carry this until told otherwise:
>
> Nacked-by: Jakub Kicinski <kuba@kernel.org>
Thanks for the feedback.
We agree that the PHC driver does not belong under the MHI bus.
In the next revision, we'll move the PHC driver to drivers/ptp
Since the concern raised by the NAK is being addressed by moving the
driver out of drivers/bus/mhi, I'll drop the Nacked-by tag in the next
revision.
- Krishna Chaitanya.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-18 10:52 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-17 7:08 [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 1/6] bus: mhi: host: Add support to read MHI capabilities Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 2/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 3/6] bus: mhi: host: Add support for 64bit register reads and writes Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 4/6] bus: mhi: pci_generic: Add support for 64 bit register read & write Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 5/6] bus: mhi: host: Export mhi_read_reg Krishna Chaitanya Chundru
2026-09-17 7:08 ` [PATCH v3 6/6] bus: mhi: host: mhi_phc: Update the Time sync logic to read 64 bit register value Krishna Chaitanya Chundru
2026-09-17 14:48 ` [PATCH v3 0/6] bus: mhi: host: mhi_phc: Add support for PHC over MHI Jakub Kicinski
2026-09-18 10:52 ` Krishna Chaitanya Chundru
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®