1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */
5 #include <linux/kernel.h>
6 #include <linux/math64.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
10 #include <linux/time64.h>
11 #include <linux/timer.h>
14 #include "qaic_timesync.h"
16 #define QTIMER_REG_OFFSET 0xa28
17 #define QAIC_TIMESYNC_SIGNATURE 0x55aa
18 #define QAIC_CONV_QTIMER_TO_US(qtimer) (mul_u64_u32_div(qtimer, 10, 192))
20 static unsigned int timesync_delay_ms
= 1000; /* 1 sec default */
21 module_param(timesync_delay_ms
, uint
, 0600);
22 MODULE_PARM_DESC(timesync_delay_ms
, "Delay in ms between two consecutive timesync operations");
32 * struct qts_hdr - Timesync message header structure.
33 * @signature: Unique signature to identify the timesync message.
34 * @reserved_1: Reserved for future use.
35 * @reserved_2: Reserved for future use.
36 * @msg_type: sub-type of the timesync message.
37 * @reserved_3: Reserved for future use.
48 * struct qts_timeval - Structure to carry time information.
49 * @tv_sec: Seconds part of the time.
50 * @tv_usec: uS (microseconds) part of the time.
58 * struct qts_host_time_sync_msg_data - Structure to denote the timesync message.
59 * @header: Header of the timesync message.
60 * @data: Time information.
62 struct qts_host_time_sync_msg_data
{
63 struct qts_hdr header
;
64 struct qts_timeval data
;
68 * struct mqts_dev - MHI QAIC Timesync Control device.
69 * @qdev: Pointer to the root device struct driven by QAIC driver.
70 * @mhi_dev: Pointer to associated MHI device.
71 * @timer: Timer handle used for timesync.
72 * @qtimer_addr: Device QTimer register pointer.
73 * @buff_in_use: atomic variable to track if the sync_msg buffer is in use.
74 * @dev: Device pointer to qdev->pdev->dev stored for easy access.
75 * @sync_msg: Buffer used to send timesync message over MHI.
78 struct qaic_device
*qdev
;
79 struct mhi_device
*mhi_dev
;
80 struct timer_list timer
;
81 void __iomem
*qtimer_addr
;
84 struct qts_host_time_sync_msg_data
*sync_msg
;
92 struct qts_resp_msg data
;
93 struct work_struct work
;
94 struct qaic_device
*qdev
;
98 static u64
read_qtimer(const volatile void __iomem
*addr
)
103 static u64
read_qtimer(const volatile void __iomem
*addr
)
108 high
= readl(addr
+ sizeof(u32
));
109 return low
| (high
<< 32);
113 static void qaic_timesync_ul_xfer_cb(struct mhi_device
*mhi_dev
, struct mhi_result
*mhi_result
)
115 struct mqts_dev
*mqtsdev
= dev_get_drvdata(&mhi_dev
->dev
);
117 dev_dbg(mqtsdev
->dev
, "%s status: %d xfer_len: %zu\n", __func__
,
118 mhi_result
->transaction_status
, mhi_result
->bytes_xferd
);
120 atomic_set(&mqtsdev
->buff_in_use
, 0);
123 static void qaic_timesync_dl_xfer_cb(struct mhi_device
*mhi_dev
, struct mhi_result
*mhi_result
)
125 struct mqts_dev
*mqtsdev
= dev_get_drvdata(&mhi_dev
->dev
);
127 dev_err(mqtsdev
->dev
, "%s no data expected on dl channel\n", __func__
);
130 static void qaic_timesync_timer(struct timer_list
*t
)
132 struct mqts_dev
*mqtsdev
= from_timer(mqtsdev
, t
, timer
);
133 struct qts_host_time_sync_msg_data
*sync_msg
;
134 u64 device_qtimer_us
;
141 if (atomic_read(&mqtsdev
->buff_in_use
)) {
142 dev_dbg(mqtsdev
->dev
, "%s buffer not free, schedule next cycle\n", __func__
);
145 atomic_set(&mqtsdev
->buff_in_use
, 1);
147 sync_msg
= mqtsdev
->sync_msg
;
148 sync_msg
->header
.signature
= cpu_to_le16(QAIC_TIMESYNC_SIGNATURE
);
149 sync_msg
->header
.msg_type
= QAIC_TS_SYNC_REQ
;
150 /* Read host UTC time and convert to uS*/
151 host_time_us
= div_u64(ktime_get_real_ns(), NSEC_PER_USEC
);
152 device_qtimer
= read_qtimer(mqtsdev
->qtimer_addr
);
153 device_qtimer_us
= QAIC_CONV_QTIMER_TO_US(device_qtimer
);
154 /* Offset between host UTC and device time */
155 offset_us
= host_time_us
- device_qtimer_us
;
157 host_sec
= div_u64(offset_us
, USEC_PER_SEC
);
158 sync_msg
->data
.tv_usec
= cpu_to_le64(offset_us
- host_sec
* USEC_PER_SEC
);
159 sync_msg
->data
.tv_sec
= cpu_to_le64(host_sec
);
160 ret
= mhi_queue_buf(mqtsdev
->mhi_dev
, DMA_TO_DEVICE
, sync_msg
, sizeof(*sync_msg
), MHI_EOT
);
161 if (ret
&& (ret
!= -EAGAIN
)) {
162 dev_err(mqtsdev
->dev
, "%s unable to queue to mhi:%d\n", __func__
, ret
);
164 } else if (ret
== -EAGAIN
) {
165 atomic_set(&mqtsdev
->buff_in_use
, 0);
169 ret
= mod_timer(t
, jiffies
+ msecs_to_jiffies(timesync_delay_ms
));
171 dev_err(mqtsdev
->dev
, "%s mod_timer error:%d\n", __func__
, ret
);
174 static int qaic_timesync_probe(struct mhi_device
*mhi_dev
, const struct mhi_device_id
*id
)
176 struct qaic_device
*qdev
= pci_get_drvdata(to_pci_dev(mhi_dev
->mhi_cntrl
->cntrl_dev
));
177 struct mqts_dev
*mqtsdev
;
178 struct timer_list
*timer
;
181 mqtsdev
= kzalloc(sizeof(*mqtsdev
), GFP_KERNEL
);
187 timer
= &mqtsdev
->timer
;
188 mqtsdev
->mhi_dev
= mhi_dev
;
189 mqtsdev
->qdev
= qdev
;
190 mqtsdev
->dev
= &qdev
->pdev
->dev
;
192 mqtsdev
->sync_msg
= kzalloc(sizeof(*mqtsdev
->sync_msg
), GFP_KERNEL
);
193 if (!mqtsdev
->sync_msg
) {
197 atomic_set(&mqtsdev
->buff_in_use
, 0);
199 ret
= mhi_prepare_for_transfer(mhi_dev
);
203 /* Qtimer register pointer */
204 mqtsdev
->qtimer_addr
= qdev
->bar_0
+ QTIMER_REG_OFFSET
;
205 timer_setup(timer
, qaic_timesync_timer
, 0);
206 timer
->expires
= jiffies
+ msecs_to_jiffies(timesync_delay_ms
);
208 dev_set_drvdata(&mhi_dev
->dev
, mqtsdev
);
213 kfree(mqtsdev
->sync_msg
);
220 static void qaic_timesync_remove(struct mhi_device
*mhi_dev
)
222 struct mqts_dev
*mqtsdev
= dev_get_drvdata(&mhi_dev
->dev
);
224 del_timer_sync(&mqtsdev
->timer
);
225 mhi_unprepare_from_transfer(mqtsdev
->mhi_dev
);
226 kfree(mqtsdev
->sync_msg
);
230 static const struct mhi_device_id qaic_timesync_match_table
[] = {
231 { .chan
= "QAIC_TIMESYNC_PERIODIC"},
235 MODULE_DEVICE_TABLE(mhi
, qaic_timesync_match_table
);
237 static struct mhi_driver qaic_timesync_driver
= {
238 .id_table
= qaic_timesync_match_table
,
239 .remove
= qaic_timesync_remove
,
240 .probe
= qaic_timesync_probe
,
241 .ul_xfer_cb
= qaic_timesync_ul_xfer_cb
,
242 .dl_xfer_cb
= qaic_timesync_dl_xfer_cb
,
244 .name
= "qaic_timesync_periodic",
248 static void qaic_boot_timesync_worker(struct work_struct
*work
)
250 struct qts_resp
*resp
= container_of(work
, struct qts_resp
, work
);
251 struct qts_host_time_sync_msg_data
*req
;
252 struct qts_resp_msg data
= resp
->data
;
253 struct qaic_device
*qdev
= resp
->qdev
;
254 struct mhi_device
*mhi_dev
;
255 struct timespec64 ts
;
258 mhi_dev
= qdev
->qts_ch
;
259 /* Queue the response message beforehand to avoid race conditions */
260 ret
= mhi_queue_buf(mhi_dev
, DMA_FROM_DEVICE
, &resp
->data
, sizeof(resp
->data
), MHI_EOT
);
263 dev_warn(&mhi_dev
->dev
, "Failed to re-queue response buffer %d\n", ret
);
267 switch (data
.hdr
.msg_type
) {
268 case QAIC_TS_CMD_TO_HOST
:
269 req
= kzalloc(sizeof(*req
), GFP_KERNEL
);
273 req
->header
= data
.hdr
;
274 req
->header
.msg_type
= QAIC_TS_SYNC_REQ
;
275 ktime_get_real_ts64(&ts
);
276 req
->data
.tv_sec
= cpu_to_le64(ts
.tv_sec
);
277 req
->data
.tv_usec
= cpu_to_le64(div_u64(ts
.tv_nsec
, NSEC_PER_USEC
));
279 ret
= mhi_queue_buf(mhi_dev
, DMA_TO_DEVICE
, req
, sizeof(*req
), MHI_EOT
);
282 dev_dbg(&mhi_dev
->dev
, "Failed to send request message. Error %d\n", ret
);
285 case QAIC_TS_ACK_TO_HOST
:
286 dev_dbg(&mhi_dev
->dev
, "ACK received from device\n");
289 dev_err(&mhi_dev
->dev
, "Invalid message type %u.\n", data
.hdr
.msg_type
);
293 static int qaic_boot_timesync_queue_resp(struct mhi_device
*mhi_dev
, struct qaic_device
*qdev
)
295 struct qts_resp
*resp
;
298 resp
= kzalloc(sizeof(*resp
), GFP_KERNEL
);
303 INIT_WORK(&resp
->work
, qaic_boot_timesync_worker
);
305 ret
= mhi_queue_buf(mhi_dev
, DMA_FROM_DEVICE
, &resp
->data
, sizeof(resp
->data
), MHI_EOT
);
308 dev_warn(&mhi_dev
->dev
, "Failed to queue response buffer %d\n", ret
);
315 static void qaic_boot_timesync_remove(struct mhi_device
*mhi_dev
)
317 struct qaic_device
*qdev
;
319 qdev
= dev_get_drvdata(&mhi_dev
->dev
);
320 mhi_unprepare_from_transfer(qdev
->qts_ch
);
324 static int qaic_boot_timesync_probe(struct mhi_device
*mhi_dev
, const struct mhi_device_id
*id
)
326 struct qaic_device
*qdev
= pci_get_drvdata(to_pci_dev(mhi_dev
->mhi_cntrl
->cntrl_dev
));
329 ret
= mhi_prepare_for_transfer(mhi_dev
);
333 qdev
->qts_ch
= mhi_dev
;
334 dev_set_drvdata(&mhi_dev
->dev
, qdev
);
336 ret
= qaic_boot_timesync_queue_resp(mhi_dev
, qdev
);
338 dev_set_drvdata(&mhi_dev
->dev
, NULL
);
340 mhi_unprepare_from_transfer(mhi_dev
);
346 static void qaic_boot_timesync_ul_xfer_cb(struct mhi_device
*mhi_dev
, struct mhi_result
*mhi_result
)
348 kfree(mhi_result
->buf_addr
);
351 static void qaic_boot_timesync_dl_xfer_cb(struct mhi_device
*mhi_dev
, struct mhi_result
*mhi_result
)
353 struct qts_resp
*resp
= container_of(mhi_result
->buf_addr
, struct qts_resp
, data
);
355 if (mhi_result
->transaction_status
|| mhi_result
->bytes_xferd
!= sizeof(resp
->data
)) {
360 queue_work(resp
->qdev
->qts_wq
, &resp
->work
);
363 static const struct mhi_device_id qaic_boot_timesync_match_table
[] = {
364 { .chan
= "QAIC_TIMESYNC"},
368 static struct mhi_driver qaic_boot_timesync_driver
= {
369 .id_table
= qaic_boot_timesync_match_table
,
370 .remove
= qaic_boot_timesync_remove
,
371 .probe
= qaic_boot_timesync_probe
,
372 .ul_xfer_cb
= qaic_boot_timesync_ul_xfer_cb
,
373 .dl_xfer_cb
= qaic_boot_timesync_dl_xfer_cb
,
375 .name
= "qaic_timesync",
379 int qaic_timesync_init(void)
383 ret
= mhi_driver_register(&qaic_timesync_driver
);
386 ret
= mhi_driver_register(&qaic_boot_timesync_driver
);
391 void qaic_timesync_deinit(void)
393 mhi_driver_unregister(&qaic_boot_timesync_driver
);
394 mhi_driver_unregister(&qaic_timesync_driver
);