Expose timestamp information supported by the GPU with a new device query. Mali uses an external timer as GPU system time. On ARM, this is wired to the generic arch timer so we wire cntfrq_el0 as device frequency. This new uAPI will be used in Mesa to implement timestamp queries and VK_KHR_calibrated_timestamps. Since this extends the uAPI and because userland needs a way to advertise those features conditionally, this also bumps the driver minor version. v2: - Rewrote to use GPU timestamp register - Added timestamp_offset to drm_panthor_timestamp_info - Add missing include for arch_timer_get_cntfrq - Rework commit message v3: - Add panthor_gpu_read_64bit_counter - Change panthor_gpu_read_timestamp to use panthor_gpu_read_64bit_counter v4: - Fix multiple typos in uAPI documentation - Mention behavior when the timestamp frequency is unknown - Use u64 instead of unsigned long long for panthor_gpu_read_timestamp - Apply r-b from Mihail
Unified · Split
| @@ -3,6 +3,10 @@ · 2 unmodified lines | ||
| 3 | 3 | /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ |
| 4 | 4 | /* Copyright 2019 Collabora ltd. */ |
| 5 | 5 | |
| 6 | +#ifdef CONFIG_ARM_ARCH_TIMER | |
| 7 | +#include <asm/arch_timer.h> | |
| 8 | +#endif | |
| 9 | + | |
| 6 | 10 | #include <linux/list.h> |
| 7 | 11 | #include <linux/module.h> |
| 8 | 12 | #include <linux/of_platform.h> |
| @@ -164,6 +168,7 @@ panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, · 155 unmodified lines | ||
| 164 | 168 | _Generic(_obj_name, \ |
| 165 | 169 | PANTHOR_UOBJ_DECL(struct drm_panthor_gpu_info, tiler_present), \ |
| 166 | 170 | PANTHOR_UOBJ_DECL(struct drm_panthor_csif_info, pad), \ |
| 171 | + PANTHOR_UOBJ_DECL(struct drm_panthor_timestamp_info, current_timestamp), \ | |
| 167 | 172 | PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ |
| 168 | 173 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ |
| 169 | 174 | PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ |
| @@ -750,10 +755,33 @@ static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx, · 580 unmodified lines | ||
| 750 | 755 | kvfree(ctx->jobs); |
| 751 | 756 | } |
| 752 | 757 | |
| 758 | +static int panthor_query_timestamp_info(struct panthor_device *ptdev, | |
| 759 | + struct drm_panthor_timestamp_info *arg) | |
| 760 | +{ | |
| 761 | + int ret; | |
| 762 | + | |
| 763 | + ret = pm_runtime_resume_and_get(ptdev->base.dev); | |
| 764 | + if (ret) | |
| 765 | + return ret; | |
| 766 | + | |
| 767 | +#ifdef CONFIG_ARM_ARCH_TIMER | |
| 768 | + arg->timestamp_frequency = arch_timer_get_cntfrq(); | |
| 769 | +#else | |
| 770 | + arg->timestamp_frequency = 0; | |
| 771 | +#endif | |
| 772 | + arg->current_timestamp = panthor_gpu_read_timestamp(ptdev); | |
| 773 | + arg->timestamp_offset = panthor_gpu_read_timestamp_offset(ptdev); | |
| 774 | + | |
| 775 | + pm_runtime_put(ptdev->base.dev); | |
| 776 | + return 0; | |
| 777 | +} | |
| 778 | + | |
| 753 | 779 | static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file) |
| 754 | 780 | { |
| 755 | 781 | struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); |
| 756 | 782 | struct drm_panthor_dev_query *args = data; |
| 783 | + struct drm_panthor_timestamp_info timestamp_info; | |
| 784 | + int ret; | |
| 757 | 785 | |
| 758 | 786 | if (!args->pointer) { |
| 759 | 787 | switch (args->type) { |
| @@ -765,6 +793,10 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d · 5 unmodified lines | ||
| 765 | 793 | args->size = sizeof(ptdev->csif_info); |
| 766 | 794 | return 0; |
| 767 | 795 | |
| 796 | + case DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: | |
| 797 | + args->size = sizeof(timestamp_info); | |
| 798 | + return 0; | |
| 799 | + | |
| 768 | 800 | default: |
| 769 | 801 | return -EINVAL; |
| 770 | 802 | } |
| @@ -777,6 +809,14 @@ static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct d · 6 unmodified lines | ||
| 777 | 809 | case DRM_PANTHOR_DEV_QUERY_CSIF_INFO: |
| 778 | 810 | return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info); |
| 779 | 811 | |
| 812 | + case DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: | |
| 813 | + ret = panthor_query_timestamp_info(ptdev, ×tamp_info); | |
| 814 | + | |
| 815 | + if (ret) | |
| 816 | + return ret; | |
| 817 | + | |
| 818 | + return PANTHOR_UOBJ_SET(args->pointer, args->size, timestamp_info); | |
| 819 | + | |
| 780 | 820 | default: |
| 781 | 821 | return -EINVAL; |
| 782 | 822 | } |
| @@ -1372,6 +1412,7 @@ static void panthor_debugfs_init(struct drm_minor *minor) · 589 unmodified lines | ||
| 1372 | 1412 | /* |
| 1373 | 1413 | * PanCSF driver version: |
| 1374 | 1414 | * - 1.0 - initial interface |
| 1415 | + * - 1.1 - adds DEV_QUERY_TIMESTAMP_INFO query | |
| 1375 | 1416 | */ |
| 1376 | 1417 | static const struct drm_driver panthor_drm_driver = { |
| 1377 | 1418 | .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | |
| @@ -1385,7 +1426,7 @@ static const struct drm_driver panthor_drm_driver = { · 7 unmodified lines | ||
| 1385 | 1426 | .desc = "Panthor DRM driver", |
| 1386 | 1427 | .date = "20230801", |
| 1387 | 1428 | .major = 1, |
| 1388 | − .minor = 0, | |
| 1429 | + .minor = 1, | |
| 1389 | 1430 | |
| 1390 | 1431 | .gem_create_object = panthor_gem_create_object, |
| 1391 | 1432 | .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, |
| @@ -480,3 +480,50 @@ void panthor_gpu_resume(struct panthor_device *ptdev) · 479 unmodified lines | ||
| 480 | 480 | panthor_gpu_irq_resume(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK); |
| 481 | 481 | panthor_gpu_l2_power_on(ptdev); |
| 482 | 482 | } |
| 483 | + | |
| 484 | +/** | |
| 485 | + * panthor_gpu_read_64bit_counter() - Read a 64-bit counter at a given offset. | |
| 486 | + * @ptdev: Device. | |
| 487 | + * @reg: The offset of the register to read. | |
| 488 | + * | |
| 489 | + * Return: The counter value. | |
| 490 | + */ | |
| 491 | +static u64 | |
| 492 | +panthor_gpu_read_64bit_counter(struct panthor_device *ptdev, u32 reg) | |
| 493 | +{ | |
| 494 | + u32 hi, lo; | |
| 495 | + | |
| 496 | + do { | |
| 497 | + hi = gpu_read(ptdev, reg + 0x4); | |
| 498 | + lo = gpu_read(ptdev, reg); | |
| 499 | + } while (hi != gpu_read(ptdev, reg + 0x4)); | |
| 500 | + | |
| 501 | + return ((u64)hi << 32) | lo; | |
| 502 | +} | |
| 503 | + | |
| 504 | +/** | |
| 505 | + * panthor_gpu_read_timestamp() - Read the timestamp register. | |
| 506 | + * @ptdev: Device. | |
| 507 | + * | |
| 508 | + * Return: The GPU timestamp value. | |
| 509 | + */ | |
| 510 | +u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev) | |
| 511 | +{ | |
| 512 | + return panthor_gpu_read_64bit_counter(ptdev, GPU_TIMESTAMP_LO); | |
| 513 | +} | |
| 514 | + | |
| 515 | +/** | |
| 516 | + * panthor_gpu_read_timestamp_offset() - Read the timestamp offset register. | |
| 517 | + * @ptdev: Device. | |
| 518 | + * | |
| 519 | + * Return: The GPU timestamp offset value. | |
| 520 | + */ | |
| 521 | +u64 panthor_gpu_read_timestamp_offset(struct panthor_device *ptdev) | |
| 522 | +{ | |
| 523 | + u32 hi, lo; | |
| 524 | + | |
| 525 | + hi = gpu_read(ptdev, GPU_TIMESTAMP_OFFSET_HI); | |
| 526 | + lo = gpu_read(ptdev, GPU_TIMESTAMP_OFFSET_LO); | |
| 527 | + | |
| 528 | + return ((u64)hi << 32) | lo; | |
| 529 | +} | |
| @@ -5,6 +5,8 @@ · 4 unmodified lines | ||
| 5 | 5 | #ifndef __PANTHOR_GPU_H__ |
| 6 | 6 | #define __PANTHOR_GPU_H__ |
| 7 | 7 | |
| 8 | +#include <linux/types.h> | |
| 9 | + | |
| 8 | 10 | struct panthor_device; |
| 9 | 11 | |
| 10 | 12 | int panthor_gpu_init(struct panthor_device *ptdev); |
| @@ -48,5 +50,7 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev); · 37 unmodified lines | ||
| 48 | 50 | int panthor_gpu_flush_caches(struct panthor_device *ptdev, |
| 49 | 51 | u32 l2, u32 lsc, u32 other); |
| 50 | 52 | int panthor_gpu_soft_reset(struct panthor_device *ptdev); |
| 53 | +u64 panthor_gpu_read_timestamp(struct panthor_device *ptdev); | |
| 54 | +u64 panthor_gpu_read_timestamp_offset(struct panthor_device *ptdev); | |
| 51 | 55 | |
| 52 | 56 | #endif |
| @@ -260,6 +260,9 @@ enum drm_panthor_dev_query_type { · 259 unmodified lines | ||
| 260 | 260 | |
| 261 | 261 | /** @DRM_PANTHOR_DEV_QUERY_CSIF_INFO: Query command-stream interface information. */ |
| 262 | 262 | DRM_PANTHOR_DEV_QUERY_CSIF_INFO, |
| 263 | + | |
| 264 | + /** @DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO: Query timestamp information. */ | |
| 265 | + DRM_PANTHOR_DEV_QUERY_TIMESTAMP_INFO, | |
| 263 | 266 | }; |
| 264 | 267 | |
| 265 | 268 | /** |
| @@ -377,6 +380,25 @@ struct drm_panthor_csif_info { · 111 unmodified lines | ||
| 377 | 380 | __u32 pad; |
| 378 | 381 | }; |
| 379 | 382 | |
| 383 | +/** | |
| 384 | + * struct drm_panthor_timestamp_info - Timestamp information | |
| 385 | + * | |
| 386 | + * Structure grouping all queryable information relating to the GPU timestamp. | |
| 387 | + */ | |
| 388 | +struct drm_panthor_timestamp_info { | |
| 389 | + /** | |
| 390 | + * @timestamp_frequency: The frequency of the timestamp timer or 0 if | |
| 391 | + * unknown. | |
| 392 | + */ | |
| 393 | + __u64 timestamp_frequency; | |
| 394 | + | |
| 395 | + /** @current_timestamp: The current timestamp. */ | |
| 396 | + __u64 current_timestamp; | |
| 397 | + | |
| 398 | + /** @timestamp_offset: The offset of the timestamp timer. */ | |
| 399 | + __u64 timestamp_offset; | |
| 400 | +}; | |
| 401 | + | |
| 380 | 402 | /** |
| 381 | 403 | * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DEV_QUERY |
| 382 | 404 | */ |