diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index bbd1f724963e..672f422c9c0f 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -2,6 +2,7 @@ qcom-iris-objs += iris_buffer.o \ iris_common.o \ iris_core.o \ iris_ctrls.o \ + iris_debugfs.o \ iris_firmware.o \ iris_hfi_common.o \ iris_hfi_gen1.o \ diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 4e0f16c565d3..c5348fb7c257 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -31,6 +31,7 @@ enum domain_type { }; struct qcom_ubwc_cfg_data; +struct dentry; /** * struct iris_core - holds core parameters valid for all instances @@ -68,7 +69,9 @@ struct qcom_ubwc_cfg_data; * @command_queue: shared interface queue to send commands to firmware * @message_queue: shared interface queue to receive responses from firmware * @debug_queue: shared interface queue to receive debug info from firmware - * @lock: a lock for this strucure + * @root: debugfs root directory + * @fw_debug: firmware debug log mask + * @lock: a lock for this structure * @response_packet: a pointer to response packet from fw to driver * @header_id: id of packet header * @packet_id: id of packet @@ -121,6 +124,8 @@ struct iris_core { struct iris_iface_q_info command_queue; struct iris_iface_q_info message_queue; struct iris_iface_q_info debug_queue; + struct dentry *root; + u32 fw_debug; struct mutex lock; /* lock for core related operations */ u8 *response_packet; u32 header_id; diff --git a/drivers/media/platform/qcom/iris/iris_debugfs.c b/drivers/media/platform/qcom/iris/iris_debugfs.c new file mode 100644 index 000000000000..6122b994ad0a --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_debugfs.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "iris_core.h" +#include "iris_debugfs.h" + +static int iris_fw_level_get(void *data, u64 *val) +{ + struct iris_core *core = data; + + *val = READ_ONCE(core->fw_debug); + + return 0; +} + +static int iris_fw_level_set(void *data, u64 val) +{ + struct iris_core *core = data; + + WRITE_ONCE(core->fw_debug, (u32)val & IRIS_FW_DEBUG_LOGMASK); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(iris_fw_level_fops, iris_fw_level_get, + iris_fw_level_set, "0x%08llx\n"); + +void iris_debugfs_init(struct iris_core *core) +{ + core->root = debugfs_create_dir("iris", NULL); + debugfs_create_file("fw_level", 0600, core->root, core, + &iris_fw_level_fops); +} + +void iris_debugfs_deinit(struct iris_core *core) +{ + debugfs_remove(core->root); +} diff --git a/drivers/media/platform/qcom/iris/iris_debugfs.h b/drivers/media/platform/qcom/iris/iris_debugfs.h new file mode 100644 index 000000000000..aa3cb97eb2b2 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_debugfs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_DEBUGFS_H__ +#define __IRIS_DEBUGFS_H__ + +struct iris_core; + +void iris_debugfs_init(struct iris_core *core); +void iris_debugfs_deinit(struct iris_core *core); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.c b/drivers/media/platform/qcom/iris/iris_hfi_common.c index 8f04f3793d9a..1f570e8b13e4 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.c @@ -87,9 +87,44 @@ int iris_hfi_core_init(struct iris_core *core) if (ret) return ret; + if (hfi_ops->sys_set_debug) { + ret = hfi_ops->sys_set_debug(core); + if (ret) + dev_warn(core->dev, + "failed to configure firmware debug logging: %d\n", + ret); + } + return hfi_ops->sys_interframe_powercollapse(core); } +int iris_hfi_set_debug(struct iris_core *core) +{ + const struct iris_hfi_sys_ops *hfi_ops = core->hfi_sys_ops; + int ret = 0; + + if (!hfi_ops->sys_set_debug) + return 0; + + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + + mutex_lock(&core->lock); + if (core->state != IRIS_CORE_INIT) { + ret = 0; + goto unlock; + } + + ret = hfi_ops->sys_set_debug(core); + +unlock: + mutex_unlock(&core->lock); + pm_runtime_put_autosuspend(core->dev); + + return ret; +} + irqreturn_t iris_hfi_isr(int irq, void *data) { disable_irq_nosync(irq); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h index 16099f9a25b6..e30dd5eb8575 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h @@ -105,9 +105,18 @@ struct iris_hfi_prop_type_handle { int (*handle)(struct iris_inst *inst, u32 plane); }; +#define IRIS_FW_DEBUG_LOW 0x00000001 +#define IRIS_FW_DEBUG_MEDIUM 0x00000002 +#define IRIS_FW_DEBUG_HIGH 0x00000004 +#define IRIS_FW_DEBUG_ERROR 0x00000008 +#define IRIS_FW_DEBUG_FATAL 0x00000010 +#define IRIS_FW_DEBUG_PERF 0x00000020 +#define IRIS_FW_DEBUG_LOGMASK 0x0fffffff + struct iris_hfi_sys_ops { int (*sys_init)(struct iris_core *core); int (*sys_image_version)(struct iris_core *core); + int (*sys_set_debug)(struct iris_core *core); int (*sys_interframe_powercollapse)(struct iris_core *core); int (*sys_pc_prep)(struct iris_core *core); @@ -154,6 +163,7 @@ u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries); u32 iris_hfi_get_v4l2_transfer_char(u32 hfi_characterstics); u32 iris_hfi_get_v4l2_matrix_coefficients(u32 hfi_coefficients); int iris_hfi_core_init(struct iris_core *core); +int iris_hfi_set_debug(struct iris_core *core); int iris_hfi_pm_suspend(struct iris_core *core); int iris_hfi_pm_resume(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index c7e396b8a71c..89d2de5ba295 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -53,6 +53,35 @@ static int iris_hfi_gen1_sys_image_version(struct iris_core *core) return iris_hfi_queue_cmd_write_locked(core, &packet, packet.hdr.size); } +static int iris_hfi_gen1_sys_set_debug(struct iris_core *core) +{ + struct hfi_sys_set_property_pkt *pkt; + struct hfi_debug_config *hfi; + u32 fw_debug; + u32 packet_size; + int ret; + + packet_size = struct_size(pkt, data, 1) + sizeof(*hfi); + pkt = kzalloc(packet_size, GFP_KERNEL); + if (!pkt) + return -ENOMEM; + + hfi = (struct hfi_debug_config *)&pkt->data[1]; + + pkt->hdr.size = packet_size; + pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG; + fw_debug = READ_ONCE(core->fw_debug) & IRIS_FW_DEBUG_LOGMASK; + hfi->config = fw_debug; + hfi->mode = fw_debug ? HFI_DEBUG_MODE_QUEUE : 0; + + ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt->hdr.size); + kfree(pkt); + + return ret; +} + static int iris_hfi_gen1_sys_interframe_powercollapse(struct iris_core *core) { struct hfi_sys_set_property_pkt *pkt; @@ -1170,6 +1199,7 @@ static struct iris_inst *iris_hfi_gen1_get_instance(void) static const struct iris_hfi_sys_ops iris_hfi_gen1_sys_ops = { .sys_init = iris_hfi_gen1_sys_init, .sys_image_version = iris_hfi_gen1_sys_image_version, + .sys_set_debug = iris_hfi_gen1_sys_set_debug, .sys_interframe_powercollapse = iris_hfi_gen1_sys_interframe_powercollapse, .sys_pc_prep = iris_hfi_gen1_sys_pc_prep, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 6981e6e84fd8..5a6b8a1efa77 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -81,6 +81,13 @@ #define HFI_BUFFER_INTERNAL_SCRATCH_1 0x7 #define HFI_BUFFER_INTERNAL_SCRATCH_2 0x8 +#define HFI_DEBUG_MODE_QUEUE 0x01 +struct hfi_debug_config { + u32 config; + u32 mode; +}; + +#define HFI_PROPERTY_SYS_DEBUG_CONFIG 0x1 #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c index ee996eb1f41f..b15bf9d3c894 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c @@ -752,16 +752,35 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response static void iris_hfi_gen1_flush_debug_queue(struct iris_core *core, u8 *packet) { - struct hfi_msg_sys_coverage_pkt *pkt; + struct hfi_msg_sys_debug_pkt *pkt; + struct hfi_pkt_hdr *hdr; + u32 log_size; + u8 *log; while (!iris_hfi_queue_dbg_read(core, packet)) { - pkt = (struct hfi_msg_sys_coverage_pkt *)packet; + hdr = (struct hfi_pkt_hdr *)packet; - if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) { - struct hfi_msg_sys_debug_pkt *pkt = - (struct hfi_msg_sys_debug_pkt *)packet; + if (hdr->size <= sizeof(*hdr)) + continue; + + if (hdr->size >= IFACEQ_CORE_PKT_SIZE) + continue; + + if (hdr->pkt_type != HFI_MSG_SYS_COV) { + pkt = (struct hfi_msg_sys_debug_pkt *)packet; + + if (hdr->size <= sizeof(*pkt)) + continue; + + log = pkt->msg_data; + log_size = hdr->size - sizeof(*pkt); + if (pkt->msg_size < log_size) + log_size = pkt->msg_size; - dev_dbg(core->dev, "%s", pkt->msg_data); + if (pkt->msg_type & (IRIS_FW_DEBUG_ERROR | IRIS_FW_DEBUG_FATAL)) + dev_err_ratelimited(core->dev, "%.*s", (int)log_size, log); + else + dev_dbg(core->dev, "%.*s", (int)log_size, log); } } } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 83727605d6ef..922c4625e184 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -17,6 +17,9 @@ #define SYS_IFPC_PKT_SIZE (sizeof(struct iris_hfi_header) + \ sizeof(struct iris_hfi_packet) + sizeof(u32)) +#define SYS_DEBUG_PKT_SIZE (sizeof(struct iris_hfi_header) + \ + 2 * (sizeof(struct iris_hfi_packet) + sizeof(u32))) + #define SYS_NO_PAYLOAD_PKT_SIZE (sizeof(struct iris_hfi_header) + \ sizeof(struct iris_hfi_packet)) @@ -54,6 +57,23 @@ static int iris_hfi_gen2_sys_image_version(struct iris_core *core) return ret; } +static int iris_hfi_gen2_sys_set_debug(struct iris_core *core) +{ + struct iris_hfi_header *hdr; + int ret; + + hdr = kzalloc(SYS_DEBUG_PKT_SIZE, GFP_KERNEL); + if (!hdr) + return -ENOMEM; + + iris_hfi_gen2_packet_set_debug(core, hdr); + ret = iris_hfi_queue_cmd_write_locked(core, hdr, hdr->size); + + kfree(hdr); + + return ret; +} + static int iris_hfi_gen2_sys_interframe_powercollapse(struct iris_core *core) { struct iris_hfi_header *hdr; @@ -1392,6 +1412,7 @@ static struct iris_inst *iris_hfi_gen2_get_instance(void) static const struct iris_hfi_sys_ops iris_hfi_gen2_sys_ops = { .sys_init = iris_hfi_gen2_sys_init, .sys_image_version = iris_hfi_gen2_sys_image_version, + .sys_set_debug = iris_hfi_gen2_sys_set_debug, .sys_interframe_powercollapse = iris_hfi_gen2_sys_interframe_powercollapse, .sys_pc_prep = iris_hfi_gen2_sys_pc_prep, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index f43aea10090d..1d4ded82ecda 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -39,6 +39,9 @@ #define HFI_PROP_UBWC_BANK_SWZL_LEVEL2 0x03000007 #define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 #define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 +#define HFI_PROP_DEBUG_CONFIG 0x0300000a +#define HFI_PROP_DEBUG_LOG_LEVEL 0x0300000b +#define HFI_DEBUG_CONFIG_DEFAULT 0x00000000 #define HFI_PROP_CODEC 0x03000100 #define HFI_PROP_COLOR_FORMAT 0x03000101 #define HFI_PROP_BITSTREAM_RESOLUTION 0x03000103 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c index 6e04175eb904..452a68ce97bc 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.c @@ -229,6 +229,35 @@ void iris_hfi_gen2_packet_image_version(struct iris_core *core, struct iris_hfi_ NULL, 0); } +void iris_hfi_gen2_packet_set_debug(struct iris_core *core, struct iris_hfi_header *hdr) +{ + u32 fw_debug; + u32 payload; + + iris_hfi_gen2_create_header(hdr, 0, core->header_id++); + + payload = HFI_DEBUG_CONFIG_DEFAULT; + iris_hfi_gen2_create_packet(hdr, + HFI_PROP_DEBUG_CONFIG, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + + fw_debug = READ_ONCE(core->fw_debug) & IRIS_FW_DEBUG_LOGMASK; + payload = fw_debug; + iris_hfi_gen2_create_packet(hdr, + HFI_PROP_DEBUG_LOG_LEVEL, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); +} + void iris_hfi_gen2_packet_session_command(struct iris_inst *inst, u32 pkt_type, u32 flags, u32 port, u32 session_id, u32 payload_type, void *payload, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h index 25b9582349ca..aff025fbf5ea 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_packet.h @@ -111,6 +111,7 @@ u32 iris_hfi_gen2_get_color_info(u32 matrix_coeff, u32 transfer_char, u32 primar void iris_hfi_gen2_packet_sys_init(struct iris_core *core, struct iris_hfi_header *hdr); void iris_hfi_gen2_packet_image_version(struct iris_core *core, struct iris_hfi_header *hdr); +void iris_hfi_gen2_packet_set_debug(struct iris_core *core, struct iris_hfi_header *hdr); void iris_hfi_gen2_packet_session_command(struct iris_inst *inst, u32 pkt_type, u32 flags, u32 port, u32 session_id, u32 payload_type, void *payload, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index 25162ae71357..6922c3191282 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -989,20 +989,24 @@ static int iris_hfi_gen2_handle_response(struct iris_core *core, void *response) static void iris_hfi_gen2_flush_debug_queue(struct iris_core *core, u8 *packet) { struct hfi_debug_header *pkt; + u32 log_size; u8 *log; while (!iris_hfi_queue_dbg_read(core, packet)) { pkt = (struct hfi_debug_header *)packet; - if (pkt->size < sizeof(*pkt)) + if (pkt->size <= sizeof(*pkt) + 1) continue; if (pkt->size >= IFACEQ_CORE_PKT_SIZE) continue; - packet[pkt->size] = '\0'; log = (u8 *)packet + sizeof(*pkt) + 1; - dev_dbg(core->dev, "%s", log); + log_size = pkt->size - sizeof(*pkt) - 1; + if (pkt->debug_level & (IRIS_FW_DEBUG_ERROR | IRIS_FW_DEBUG_FATAL)) + dev_err_ratelimited(core->dev, "%.*s", (int)log_size, log); + else + dev_dbg(core->dev, "%.*s", (int)log_size, log); } } diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 6e7a9fc39038..2dfca8b11f4c 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -12,6 +12,7 @@ #include #include +#include "iris_debugfs.h" #include "iris_core.h" #include "iris_ctrls.h" #include "iris_vidc.h" @@ -215,6 +216,8 @@ static void iris_remove(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); + iris_debugfs_deinit(core); + mutex_destroy(&core->lock); } @@ -238,6 +241,7 @@ static int iris_probe(struct platform_device *pdev) if (!core) return -ENOMEM; core->dev = dev; + core->fw_debug = IRIS_FW_DEBUG_ERROR | IRIS_FW_DEBUG_FATAL; core->state = IRIS_CORE_DEINIT; mutex_init(&core->lock); @@ -312,6 +316,8 @@ static int iris_probe(struct platform_device *pdev) if (ret) goto err_vdev_unreg_enc; + iris_debugfs_init(core); + return 0; err_vdev_unreg_enc: diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index a2ea2d67f60d..e4b874a7119f 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -127,7 +127,9 @@ int iris_vb2_queue_setup(struct vb2_queue *q, goto unlock; if (!inst->once_per_session_set) { - inst->once_per_session_set = true; + ret = iris_hfi_set_debug(core); + if (ret) + dev_warn(core->dev, "failed to set firmware debug level: %d\n", ret); ret = inst->hfi_session_ops->session_open(inst); if (ret) { @@ -136,6 +138,8 @@ int iris_vb2_queue_setup(struct vb2_queue *q, goto unlock; } + inst->once_per_session_set = true; + ret = iris_inst_change_state(inst, IRIS_INST_INIT); if (ret) goto unlock;