From 02a104cbb2fb7831ddcc1f7a628b69454043f9c1 Mon Sep 17 00:00:00 2001 From: Mohit Ingale Date: Thu, 3 Apr 2025 08:28:25 +0000 Subject: [PATCH] rtcpu: Add Doxygen documentation to RTCPU subsystem Add detailed Doxygen documentation across all files in the RTCPU subsystem. This documentation effort follows SWUD Doxygen guidelines and provides complete API documentation for the entire RTCPU codebase. Use Cursor Agent to generate SWUD doxygen headers Jira CAMERASW-31120 Change-Id: I3095ff2e321402e72f0f8f5762bad798ea0ecf19 Signed-off-by: Mohit Ingale Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3332472 Reviewed-by: Semi Malinen Reviewed-by: Vincent Chung GVS: buildbot_gerritrpt Reviewed-by: Frank Chen --- drivers/platform/tegra/rtcpu/capture-ivc.c | 328 ++++++ drivers/platform/tegra/rtcpu/clk-group.c | 148 +++ drivers/platform/tegra/rtcpu/device-group.c | 91 ++ .../platform/tegra/rtcpu/hsp-mailbox-client.c | 631 +++++++++++- drivers/platform/tegra/rtcpu/ivc-bus.c | 361 ++++++- drivers/platform/tegra/rtcpu/reset-group.c | 88 ++ drivers/platform/tegra/rtcpu/rtcpu-debug.c | 930 +++++++++++++++++- drivers/platform/tegra/rtcpu/rtcpu-monitor.c | 86 ++ .../tegra/rtcpu/tegra-camera-rtcpu-base.c | 732 +++++++++++++- .../platform/tegra/rtcpu/tegra-rtcpu-trace.c | 809 ++++++++++++++- 10 files changed, 4177 insertions(+), 27 deletions(-) diff --git a/drivers/platform/tegra/rtcpu/capture-ivc.c b/drivers/platform/tegra/rtcpu/capture-ivc.c index 3d6ad36c..b4b9c985 100644 --- a/drivers/platform/tegra/rtcpu/capture-ivc.c +++ b/drivers/platform/tegra/rtcpu/capture-ivc.c @@ -23,6 +23,30 @@ #include "capture-ivc-priv.h" +/** + * @brief Transmit a message over IVC channel with mutex protection + * + * This function transmits a message over the specified IVC channel with mutex + * protection. + * - Validates that the channel is valid and ready + * - Acquires the write lock to ensure exclusive access to the channel using + * @ref mutex_lock_interruptible() + * - Waits for the channel to be available for writing using @ref wait_event_interruptible() + * - Calls @ref tegra_ivc_write() to write the message to the channel + * - Releases the write lock using @ref mutex_unlock() + * + * @param[in] civc Pointer to the capture IVC context + * Valid value: non-NULL + * @param[in] req Pointer to the message to be transmitted + * Valid value: non-NULL + * @param[in] len Length of the message in bytes + * Valid range: > 0 + * + * @retval -EIO If channel is NULL or not ready + * @retval -ERESTARTSYS If signal received while waiting for the write queue + * @retval (int) Return code propagated from @ref mutex_lock_interruptible() or + * @ref tegra_ivc_write() or @ref wait_event_interruptible() + */ static int tegra_capture_ivc_tx_(struct tegra_capture_ivc *civc, const void *req, size_t len) { @@ -52,6 +76,28 @@ static int tegra_capture_ivc_tx_(struct tegra_capture_ivc *civc, return ret; } +/** + * @brief Transmit a message over IVC channel with tracing + * + * This function wraps @ref tegra_capture_ivc_tx_() to provide tracing + * functionality for IVC transmissions. + * - Gets the channel name using @ref dev_name() + * - If len is less than the header length, sets the header to zero and + * copies the message header using @ref memcpy() + * - Otherwise, copies the header from the message using @ref memcpy() + * - Calls @ref tegra_capture_ivc_tx_() to transmit the message + * - Records the transmission via trace events for debugging and monitoring + * using @ref trace_capture_ivc_send() or @ref trace_capture_ivc_send_error() + * based on the return value of @ref tegra_capture_ivc_tx_() + * @param[in] civc Pointer to the capture IVC context + * Valid value: non-NULL + * @param[in] req Pointer to the message to be transmitted + * Valid value: non-NULL + * @param[in] len Length of the message in bytes + * Valid range: > 0 + * + * @retval (int) Value returned by @ref tegra_capture_ivc_tx_() + */ static int tegra_capture_ivc_tx(struct tegra_capture_ivc *civc, const void *req, size_t len) { @@ -80,6 +126,21 @@ static int tegra_capture_ivc_tx(struct tegra_capture_ivc *civc, return ret; } +/** + * @brief Submit a control message over the capture-control IVC channel + * + * This function submits a control message to the capture-control IVC channel. + * - Verifies that the capture-control IVC context is initialized + * - Calls @ref tegra_capture_ivc_tx() to transmit the control message + * + * @param[in] control_desc Pointer to the control message descriptor + * Valid value: non-NULL + * @param[in] len Length of the control message in bytes + * Valid range: > 0 + * + * @retval (int) Value returned by @ref tegra_capture_ivc_tx() + * @retval -ENODEV If the control IVC context is not initialized + */ int tegra_capture_ivc_control_submit(const void *control_desc, size_t len) { if (WARN_ON(__scivc_control == NULL)) @@ -89,6 +150,21 @@ int tegra_capture_ivc_control_submit(const void *control_desc, size_t len) } EXPORT_SYMBOL(tegra_capture_ivc_control_submit); +/** + * @brief Submit a capture message over the capture IVC channel + * + * This function submits a capture message to the capture IVC channel. + * - Verifies that the capture IVC context is initialized + * - Calls @ref tegra_capture_ivc_tx() to transmit the capture message + * + * @param[in] capture_desc Pointer to the capture message descriptor + * Valid value: non-NULL + * @param[in] len Length of the capture message in bytes + * Valid range: > 0 + * + * @retval (int) Value returned by @ref tegra_capture_ivc_tx() + * @retval -ENODEV If the capture IVC context is not initialized + */ int tegra_capture_ivc_capture_submit(const void *capture_desc, size_t len) { if (WARN_ON(__scivc_capture == NULL)) @@ -98,6 +174,40 @@ int tegra_capture_ivc_capture_submit(const void *capture_desc, size_t len) } EXPORT_SYMBOL(tegra_capture_ivc_capture_submit); +/** + * @brief Register a callback function for capture-control IVC responses + * + * This function registers a callback function that will be invoked when a + * response is received on the capture-control IVC channel. + * - Validates input parameters + * - Gets a runtime reference to the IVC channel using @ref tegra_ivc_channel_runtime_get() + * - Acquires the callback context list lock using @ref spin_lock() + * - Checks if the list is empty using @ref list_empty() + * - If the list is empty, releases the lock using @ref spin_unlock(). + * - Otherwise, acquires an available callback context from the list using @ref list_first_entry() + * - Removes the callback context from the list using @ref list_del() + * - Releases the callback context list lock using @ref spin_unlock() + * - Acquires the callback context lock using @ref mutex_lock() + * - Checks if the callback function is already registered using @ref cb_ctx->cb_func + * - If the callback function is already registered, releases the callback context lock using + * @ref mutex_unlock() + * - Otherwise, associates the callback function with the context using @ref cb_ctx->cb_func + * - Releases the callback context lock using @ref mutex_unlock() + * - Adds back the channel using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] control_resp_cb Callback function to be invoked for responses + * Valid value: non-NULL + * @param[out] trans_id Pointer to store the transaction ID + * Valid value: non-NULL + * @param[in] priv_context Private context to be passed to the callback + * Valid value: any value + * + * @retval 0 On successful registration + * @retval -EINVAL If input validation fails + * @retval -ENODEV If control IVC context is not initialized + * @retval -EAGAIN If no callback contexts are available + * @retval -EIO If an internal error occurs during registration + */ int tegra_capture_ivc_register_control_cb( tegra_capture_ivc_cb_func control_resp_cb, uint32_t *trans_id, const void *priv_context) @@ -167,6 +277,37 @@ fail: } EXPORT_SYMBOL(tegra_capture_ivc_register_control_cb); +/** + * @brief Update callback context from transaction ID to channel ID + * + * This function updates the callback context from a temporary transaction ID to + * a permanent channel ID. This is typically called after the RTCPU has assigned + * a channel ID in response to a channel setup request. + * - Validates input parameters + * - Gets the channel ID and transaction ID using @ref array_index_nospec() + * - Gets the capture IVC context using @ref __scivc_control + * - Locks the callback context lock using @ref mutex_lock() + * - Validates the transaction context using @ref civc->cb_ctx[trans_id].cb_func + * - Validates the channel context using @ref civc->cb_ctx[chan_id].cb_func + * - Moves the callback function from the transaction context to the channel context + * - Adds the transaction context back to the available list + * - Releases the callback context lock using @ref mutex_unlock() + * - Locks the callback context list lock using @ref spin_lock() + * - Adds the transaction context back to the available list using @ref list_add_tail() + * - Releases the callback context list lock using @ref spin_unlock() + * + * @param[in] chan_id Channel ID assigned by RTCPU + * Valid range: [0, @ref NUM_CAPTURE_CHANNELS-1] + * @param[in] trans_id Transaction ID previously returned by + * @ref tegra_capture_ivc_register_control_cb() + * Valid range: [@ref TRANS_ID_START_IDX, @ref TOTAL_CHANNELS-1] + * + * @retval 0 On successful notification + * @retval -EINVAL If input validation fails + * @retval -ENODEV If control IVC context is not initialized + * @retval -EBADF If transaction context is idle + * @retval -EBUSY If channel context is busy + */ int tegra_capture_ivc_notify_chan_id(uint32_t chan_id, uint32_t trans_id) { struct tegra_capture_ivc *civc; @@ -217,6 +358,34 @@ int tegra_capture_ivc_notify_chan_id(uint32_t chan_id, uint32_t trans_id) } EXPORT_SYMBOL(tegra_capture_ivc_notify_chan_id); +/** + * @brief Register a callback function for capture IVC status indications + * + * This function registers a callback function that will be invoked when a + * status indication is received on the capture IVC channel for a specific + * channel ID. + * - Validates input parameters + * - Gets a runtime reference to the IVC channel using @ref tegra_ivc_channel_runtime_get() + * - Gets lock to the callback context lock using @ref mutex_lock() + * - Checks if the channel ID already has a registered callback using @ref cb_ctx->cb_func + * - If the channel ID already has a registered callback, releases the callback context lock using + * @ref mutex_unlock() + * - Otherwise, associates the callback function with the channel ID using @ref cb_ctx->cb_func + * - Releases the callback context lock using @ref mutex_unlock() + * - Releases the runtime reference to the IVC channel using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] capture_status_ind_cb Callback function to be invoked for status indications + * Valid value: non-NULL + * @param[in] chan_id Channel ID for which to register the callback + * Valid range: [0, @ref NUM_CAPTURE_CHANNELS-1] + * @param[in] priv_context Private context to be passed to the callback + * Valid value: any value + * + * @retval 0 On successful registration + * @retval -EINVAL If input validation fails + * @retval -ENODEV If capture IVC context is not initialized + * @retval -EBUSY If channel ID already has a registered callback + */ int tegra_capture_ivc_register_capture_cb( tegra_capture_ivc_cb_func capture_status_ind_cb, uint32_t chan_id, const void *priv_context) @@ -262,6 +431,30 @@ fail: } EXPORT_SYMBOL(tegra_capture_ivc_register_capture_cb); +/** + * @brief Unregister a control callback function for a specified ID + * + * This function unregisters a previously registered callback function from + * either a transaction ID or a channel ID. + * - Validates the input ID + * - Gets the capture IVC context using @ref __scivc_control + * - Gets the id using @ref array_index_nospec() + * - Locks the callback context lock using @ref mutex_lock() + * - Clears the callback function and context from the specified ID using @ref cb_ctx->cb_func + * - Acquires the callback context list lock using @ref spin_lock() + * - If the ID is a transaction ID, adds it back to the available list using @ref list_add_tail() + * - Releases the callback context list lock using @ref spin_unlock() + * - Releases the callback context lock using @ref mutex_unlock() + * - Releases the runtime reference to the IVC channel using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] id Transaction ID or channel ID to unregister + * Valid range: [0, @ref TOTAL_CHANNELS-1] + * + * @retval 0 On successful unregistration + * @retval -EINVAL If ID validation fails + * @retval -ENODEV If control IVC context is not initialized + * @retval -EBADF If the specified ID has no registered callback + */ int tegra_capture_ivc_unregister_control_cb(uint32_t id) { struct tegra_capture_ivc *civc; @@ -306,6 +499,26 @@ int tegra_capture_ivc_unregister_control_cb(uint32_t id) } EXPORT_SYMBOL(tegra_capture_ivc_unregister_control_cb); +/** + * @brief Unregister a capture callback function for a specified channel ID + * + * This function unregisters a previously registered capture callback function. + * - Validates the channel ID + * - Gets the capture IVC context using @ref __scivc_capture + * - Locks the callback context lock using @ref mutex_lock() + * - Clears the callback function and context from the specified channel ID using + * @ref cb_ctx->cb_func + * - Releases the callback context lock using @ref mutex_unlock() + * - Releases the runtime reference to the IVC channel using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] chan_id Channel ID to unregister + * Valid range: [0, @ref NUM_CAPTURE_CHANNELS-1] + * + * @retval 0 On successful unregistration + * @retval -EINVAL If channel ID validation fails + * @retval -ENODEV If capture IVC context is not initialized + * @retval -EBADF If the specified channel ID has no registered callback + */ int tegra_capture_ivc_unregister_capture_cb(uint32_t chan_id) { struct tegra_capture_ivc *civc; @@ -339,6 +552,23 @@ int tegra_capture_ivc_unregister_capture_cb(uint32_t chan_id) } EXPORT_SYMBOL(tegra_capture_ivc_unregister_capture_cb); +/** + * @brief Process an IVC message by invoking the appropriate callback + * + * This inline function processes an incoming IVC message by invoking the registered + * callback function for the specified channel ID. + * - Checks if a callback function is registered for the channel ID using + * @ref civc->cb_ctx[id].cb_func + * - If registered, invokes the callback with the message and private context using + * @ref civc->cb_ctx[id].cb_func() + * + * @param[in] civc Pointer to the capture IVC context + * Valid value: non-NULL + * @param[in] id Channel ID associated with the message + * Valid range: [0, @ref TOTAL_CHANNELS-1] + * @param[in] msg Pointer to the received message + * Valid value: non-NULL + */ static inline void tegra_capture_ivc_recv_msg( struct tegra_capture_ivc *civc, uint32_t id, @@ -355,6 +585,22 @@ static inline void tegra_capture_ivc_recv_msg( } } +/** + * @brief Process all pending received IVC messages + * + * This inline function processes all pending messages in the IVC receive queue. + * - Loops while messages are available for reading using @ref tegra_ivc_can_read() + * - Retrieves the next message from the queue using @ref tegra_ivc_read_get_next_frame() + * - Extracts the channel ID from the message header using @ref hdr->channel_id + * - Records the message reception via trace events using @ref trace_capture_ivc_recv() + * - Gets the id using @ref array_index_nospec() + * - Validates the channel ID and dispatches the message to the appropriate callback using + * @ref tegra_capture_ivc_recv_msg() + * - Advances the IVC read queue to the next message using @ref tegra_ivc_read_advance() + * + * @param[in] civc Pointer to the capture IVC context + * Valid value: non-NULL + */ static inline void tegra_capture_ivc_recv(struct tegra_capture_ivc *civc) { struct tegra_ivc *ivc = &civc->chan->ivc; @@ -393,6 +639,21 @@ static inline void tegra_capture_ivc_recv(struct tegra_capture_ivc *civc) } } +/** + * @brief Worker function to process IVC notifications + * + * This function is invoked when an IVC notification is received from the RTCPU. + * - Retrieves the capture IVC context from the work structure using @ref container_of() + * - Acquires a runtime PM reference to prevent suspended operation using + * @ref pm_runtime_get_if_in_use() + * - If channel is not ready, logs a warning using @ref WARN_ON() + * - Verifies that the channel is ready using @ref chan->is_ready + * - Calls @ref tegra_capture_ivc_recv() to process all pending messages + * - Releases the runtime PM reference using @ref pm_runtime_put() + * + * @param[in] work Pointer to the kthread work structure + * Valid value: non-NULL + */ static void tegra_capture_ivc_worker(struct kthread_work *work) { struct tegra_capture_ivc *civc; @@ -417,6 +678,20 @@ static void tegra_capture_ivc_worker(struct kthread_work *work) } } +/** + * @brief IVC notification callback from the IVC subsystem + * + * This function is called by the IVC subsystem when a notification is received + * from the remote processor (RTCPU). + * - Retrieves the capture IVC context from the channel driver data using + * @ref tegra_ivc_channel_get_drvdata() + * - Records the notification via trace events using @ref trace_capture_ivc_notify() + * - Wakes up any threads waiting to write to the IVC channel using @ref wake_up() + * - Queues the worker to process any received messages using @ref kthread_queue_work() + * + * @param[in] chan Pointer to the IVC channel that received the notification + * Valid value: non-NULL + */ static void tegra_capture_ivc_notify(struct tegra_ivc_channel *chan) { struct tegra_capture_ivc *civc = tegra_ivc_channel_get_drvdata(chan); @@ -430,6 +705,44 @@ static void tegra_capture_ivc_notify(struct tegra_ivc_channel *chan) #define NV(x) "nvidia," #x +/** + * @brief Probe function for the tegra capture IVC driver + * + * This function is called when a matching IVC channel is found. + * - Allocates and initializes the capture IVC context using @ref devm_kzalloc() + * - Reads the service type from device tree using @ref of_property_read_string() + * - Stores the channel reference in the IVC context (civc->chan = chan) + * - Initializes synchronization primitives using @ref mutex_init() + * - Initializes the work structure for processing IVC notifications using @ref kthread_init_work() + * - Initializes the worker thread using @ref kthread_init_worker() + * - Creates a kernel worker thread using @ref kthread_create() + * - Sets the worker thread to FIFO scheduling using @ref sched_set_fifo_low() + * - Wakes up the worker thread using @ref wake_up_process() + * - Initializes the IVC write queue using @ref init_waitqueue_head() + * - Initializes the spinlock for available context list using @ref spin_lock_init() + * - Initializes the transaction context list using @ref INIT_LIST_HEAD() + * - Locks the callback context lock using @ref mutex_lock() + * - Adds the transaction contexts to the available list using @ref list_add_tail() + * - Unlocks the callback context lock using @ref mutex_unlock() + * - Associates the context with the IVC channel using @ref tegra_ivc_channel_set_drvdata() + * - Checks if the service type is "capture-control" using @ref strcmp() + * - Verifies that no control channel already exists using @ref WARN_ON() + * - Registers the context as a control service by setting @ref __scivc_control + * - If not control, checks if service type is "capture" using @ref strcmp() + * - Verifies that no capture channel already exists using @ref WARN_ON() + * - Registers the context as a capture service by setting @ref __scivc_capture + * - Returns error if service type is neither control nor capture + * - Stops the worker thread using @ref kthread_stop() if an error occurs + * + * @param[in] chan Pointer to the IVC channel to be probed + * Valid value: non-NULL + * + * @retval 0 On successful probe + * @retval -ENOMEM If memory allocation fails + * @retval -EEXIST If a channel for the same service already exists + * @retval -EINVAL If the service type is invalid or missing + * @retval (int) Value returned by @ref of_property_read_string() or @ref kthread_create() + */ static int tegra_capture_ivc_probe(struct tegra_ivc_channel *chan) { struct device *dev = &chan->dev; @@ -510,6 +823,21 @@ err: return ret; } +/** + * @brief Remove function for the tegra capture IVC driver + * + * This function is called when an IVC channel is being removed. + * - Gets the capture IVC context from the channel driver data using + * @ref tegra_ivc_channel_get_drvdata() + * - Ensures any pending work on the worker thread is complete using + * @ref kthread_flush_worker() + * - Stops the worker thread using @ref kthread_stop() + * - Unregisters the IVC context from the global context using + * @ref __scivc_control or @ref __scivc_capture + * + * @param[in] chan Pointer to the IVC channel to be removed + * Valid value: non-NULL + */ static void tegra_capture_ivc_remove(struct tegra_ivc_channel *chan) { struct tegra_capture_ivc *civc = tegra_ivc_channel_get_drvdata(chan); diff --git a/drivers/platform/tegra/rtcpu/clk-group.c b/drivers/platform/tegra/rtcpu/clk-group.c index 4d23b1b5..8238b9d8 100644 --- a/drivers/platform/tegra/rtcpu/clk-group.c +++ b/drivers/platform/tegra/rtcpu/clk-group.c @@ -24,6 +24,19 @@ struct camrtc_clk_group { } clocks[]; }; +/** + * @brief Release function for the camera RTCPU clock group + * + * This function releases all the clocks in the clock group. + * - Iterates through all clocks in the group + * - Puts back each clock using @ref clk_put() + * - Puts back the parent clocks (slow and fast) + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] res Pointer to the clock group resource + * Valid value: non-NULL + */ static void camrtc_clk_group_release(struct device *dev, void *res) { const struct camrtc_clk_group *grp = res; @@ -40,6 +53,28 @@ static void camrtc_clk_group_release(struct device *dev, void *res) clk_put(grp->parents.fast); } +/** + * @brief Retrieve a parent clock from device tree + * + * This function retrieves a parent clock using the device tree. + * - Validates the input index + * - Parses a phandle with arguments using @ref of_parse_phandle_with_args() + * - Gets the clock from the provider using @ref of_clk_get_from_provider() + * - Releases the node pointer using @ref of_node_put() + * - Returns the clock via the return_clk parameter + * + * @param[in] np Pointer to device node + * Valid value: non-NULL + * @param[in] index Index of the parent clock + * Valid range: >= 0 + * @param[out] return_clk Pointer to store the retrieved clock + * Valid value: non-NULL + * + * @retval 0 On successful retrieval + * @retval -EINVAL If index is negative + * @retval (int) Error value returned by @ref of_parse_phandle_with_args() + * or @ref of_clk_get_from_provider() + */ static int camrtc_clk_group_get_parent( struct device_node *np, int index, @@ -69,6 +104,29 @@ static int camrtc_clk_group_get_parent( return 0; } +/** + * @brief Get a clock group for a device + * + * This function creates and initializes a clock group for a device. + * - Validates the input device + * - Gets the device node + * - Counts the number of clocks, clock rates, and parent clocks + * - Allocates memory for the clock group using @ref devres_alloc() + * - Gets each clock using @ref of_clk_get() + * - Gets the clock rates for each clock + * - Gets the parent clocks using @ref camrtc_clk_group_get_parent() + * - Registers the resource with the device using @ref devres_add() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (struct camrtc_clk_group*) Pointer to the clock group on success + * @retval ERR_PTR(-EINVAL) If device is invalid or does not have a device node + * @retval ERR_PTR(-ENOENT) If no clocks are found + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(ret) Error returned by @ref camrtc_clk_group_get_parent() + * or @ref of_clk_get() + */ struct camrtc_clk_group *camrtc_clk_group_get( struct device *dev) { @@ -152,6 +210,22 @@ error: } EXPORT_SYMBOL_GPL(camrtc_clk_group_get); +/** + * @brief Reports an error related to a clock in a clock group + * + * This function reports an error related to a specific clock in a clock group. + * - Attempts to get the clock name from the device tree using @ref of_property_read_string_index() + * - Prints a warning message about the operation that failed using @ref dev_warn() + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL + * @param[in] op String describing the operation that failed + * Valid value: non-NULL + * @param[in] index Index of the clock in the clock group + * Valid range: [0, grp->nclocks-1] + * @param[in] error Error code + * Valid value: any + */ static void camrtc_clk_group_error( const struct camrtc_clk_group *grp, char const *op, @@ -171,6 +245,22 @@ static void camrtc_clk_group_error( op, name, index, error); } +/** + * @brief Enable all clocks in a clock group + * + * This function enables all clocks in the specified clock group. + * - Checks if the clock group is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all clocks in the group + * - Prepares and enables each clock using @ref clk_prepare_enable() + * - Reports errors using @ref camrtc_clk_group_error() if a clock fails to enable + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL and not an error pointer + * + * @retval 0 On successful enablement of all clocks + * @retval -ENODEV If the clock group is invalid + * @retval (int) Error returned by @ref clk_prepare_enable() + */ int camrtc_clk_group_enable(const struct camrtc_clk_group *grp) { int index, err; @@ -190,6 +280,17 @@ int camrtc_clk_group_enable(const struct camrtc_clk_group *grp) } EXPORT_SYMBOL_GPL(camrtc_clk_group_enable); +/** + * @brief Disable all clocks in a clock group + * + * This function disables all clocks in the specified clock group. + * - Checks if the clock group is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all clocks in the group + * - Disables and unprepares each clock using @ref clk_disable_unprepare() + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL and not an error pointer + */ void camrtc_clk_group_disable(const struct camrtc_clk_group *grp) { int index; @@ -202,6 +303,20 @@ void camrtc_clk_group_disable(const struct camrtc_clk_group *grp) } EXPORT_SYMBOL_GPL(camrtc_clk_group_disable); +/** + * @brief Set the parent clock for all clocks in a clock group + * + * This function sets the specified parent clock for all clocks in the group. + * - Checks if the parent clock is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all clocks in the group + * - Sets the parent clock for each clock using @ref clk_set_parent() + * - Reports errors using @ref pr_err() if parent clock cannot be set + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL + * @param[in] parent Pointer to the parent clock + * Valid value: non-NULL and not an error pointer + */ static void camrtc_clk_group_set_parent(const struct camrtc_clk_group *grp, struct clk *parent) { @@ -219,6 +334,23 @@ static void camrtc_clk_group_set_parent(const struct camrtc_clk_group *grp, } } +/** + * @brief Adjust clocks in a clock group to slow mode + * + * This function adjusts all clocks in the specified clock group to their slow + * rates and sets the slow parent clock. + * - Checks if the clock group is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all clocks in the group + * - Sets the rate of each clock to its slow rate using @ref clk_set_rate() if + * the slow rate is non-zero + * - Sets the parent clock to the slow parent using @ref camrtc_clk_group_set_parent() + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL and not an error pointer + * + * @retval 0 On successful adjustment + * @retval -ENODEV If the clock group is invalid + */ int camrtc_clk_group_adjust_slow(const struct camrtc_clk_group *grp) { int index; @@ -239,6 +371,22 @@ int camrtc_clk_group_adjust_slow(const struct camrtc_clk_group *grp) } EXPORT_SYMBOL_GPL(camrtc_clk_group_adjust_slow); +/** + * @brief Adjusts all clocks in a clock group to their fast rates + * + * This function adjusts all clocks in the specified clock group to their fast rates + * and sets the fast parent clock. It performs the following operations: + * - Validates the clock group using @ref IS_ERR_OR_NULL() + * - Sets the parent clock to the fast parent using @ref camrtc_clk_group_set_parent() + * - Iterates through all clocks in the group + * - Sets the rate of each clock to its fast rate using @ref clk_set_rate() if the fast rate is non-zero + * + * @param[in] grp Pointer to the clock group + * Valid value: non-NULL and not an error pointer + * + * @retval 0 On successful adjustment + * @retval -ENODEV If the clock group is invalid + */ int camrtc_clk_group_adjust_fast(const struct camrtc_clk_group *grp) { int index; diff --git a/drivers/platform/tegra/rtcpu/device-group.c b/drivers/platform/tegra/rtcpu/device-group.c index 3c2f1555..5c66906d 100644 --- a/drivers/platform/tegra/rtcpu/device-group.c +++ b/drivers/platform/tegra/rtcpu/device-group.c @@ -17,6 +17,27 @@ struct camrtc_device_group { struct platform_device *devices[]; }; +/** + * @brief Gets a platform device from a device tree node + * + * This function retrieves a platform device from a device tree node specified by + * a phandle property. It performs the following operations: + * 1. Gets the device node using @ref of_parse_phandle() + * 2. Checks if the device is available using @ref of_device_is_available() + * 3. Finds the platform device using @ref of_find_device_by_node() + * 4. Stores the device in the group's device array + * + * @param[in] grp Pointer to the device group + * Valid value: non-NULL + * @param[in] dev Pointer to the parent device + * Valid value: non-NULL + * @param[in] name Name of the phandle property + * Valid value: non-NULL + * @param[in] index Index in the phandle array + * Valid range: >= 0 + * + * @retval 0 Device retrieved successfully or skipped if disabled + */ static int get_grouped_device(struct camrtc_device_group *grp, struct device *dev, char const *name, int index) { @@ -46,6 +67,20 @@ static int get_grouped_device(struct camrtc_device_group *grp, return 0; } +/** + * @brief Releases resources associated with a device group + * + * This function is called to release resources when a device group is being destroyed. + * It performs the following operations: + * 1. Releases the reference to the parent device using @ref put_device() + * 2. Iterates through all devices in the group + * 3. Releases each platform device using @ref platform_device_put() + * + * @param[in] dev Pointer to the parent device + * Valid value: non-NULL + * @param[in] res Pointer to the device group resource + * Valid value: non-NULL + */ static void camrtc_device_group_release(struct device *dev, void *res) { const struct camrtc_device_group *grp = res; @@ -57,6 +92,31 @@ static void camrtc_device_group_release(struct device *dev, void *res) platform_device_put(grp->devices[i]); } +/** + * @brief Gets a device group based on device tree properties + * + * This function creates and initializes a device group based on device tree properties. + * It performs the following operations: + * 1. Validates the device and its device tree node + * 2. Counts phandle arguments using @ref of_count_phandle_with_args() + * 3. Allocates memory for the device group using @ref devres_alloc() + * 4. Gets device references using @ref get_device() + * 5. Retrieves each device in the group using @ref get_grouped_device() + * 6. Adds the device group to device resources using @ref devres_add() + * + * @param[in] dev Pointer to the parent device + * Valid value: non-NULL with valid device tree node + * @param[in] property_name Name of the device tree property containing device phandles + * Valid value: non-NULL + * @param[in] names_property_name Name of the device tree property containing device names + * Valid value: non-NULL + * + * @retval struct camrtc_device_group* Device group on success + * @retval ERR_PTR(-EINVAL) If device or device tree node is invalid + * @retval ERR_PTR(-ENOENT) If no devices are found + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(err) If device retrieval fails + */ struct camrtc_device_group *camrtc_device_group_get( struct device *dev, char const *property_name, @@ -97,6 +157,17 @@ struct camrtc_device_group *camrtc_device_group_get( } EXPORT_SYMBOL(camrtc_device_group_get); +/** + * @brief Gets a reference to a platform device + * + * This function gets a reference to a platform device by incrementing its + * reference count using @ref get_device() if the device is not NULL. + * + * @param[in] pdev Pointer to the platform device + * Valid value: any value including NULL + * + * @retval struct platform_device* The input platform device pointer + */ static inline struct platform_device *platform_device_get( struct platform_device *pdev) { @@ -105,6 +176,26 @@ static inline struct platform_device *platform_device_get( return pdev; } +/** + * @brief Gets a platform device from a device group by name + * + * This function retrieves a platform device from a device group by matching + * the device name in the device tree property. It performs the following operations: + * 1. Validates the device group + * 2. Checks if the names property exists + * 3. Finds the device index using @ref of_property_match_string() + * 4. Gets a reference to the device using @ref platform_device_get() + * + * @param[in] grp Pointer to the device group + * Valid value: non-NULL + * @param[in] device_name Name of the device to find + * Valid value: non-NULL + * + * @retval struct platform_device* Device pointer on success + * @retval ERR_PTR(-EINVAL) If device group is NULL + * @retval ERR_PTR(-ENOENT) If names property is not found + * @retval ERR_PTR(-ENODEV) If device is not found or index is invalid + */ struct platform_device *camrtc_device_get_byname( struct camrtc_device_group *grp, const char *device_name) diff --git a/drivers/platform/tegra/rtcpu/hsp-mailbox-client.c b/drivers/platform/tegra/rtcpu/hsp-mailbox-client.c index 251b03a3..711ba85c 100644 --- a/drivers/platform/tegra/rtcpu/hsp-mailbox-client.c +++ b/drivers/platform/tegra/rtcpu/hsp-mailbox-client.c @@ -54,6 +54,26 @@ struct camrtc_hsp_op { int (*set_operating_point)(struct camrtc_hsp *, u32 operating_point, long *timeout); }; +/** + * @brief Sends a request message over the HSP mailbox + * + * This function sends a request message over the HSP mailbox and handles error reporting. + * It acts as a wrapper for the implementation-specific send operation. + * - Calls the implementation-specific send operation using @ref camhsp->op->send() + * - Performs error reporting using @ref dev_err() or @ref dev_dbg() based on the return value + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] request Request message to send + * Valid value: any integer value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 On successful transmission + * @retval -ETIME If the mailbox is not empty within the timeout period + * @retval -EINVAL If the mailbox channel is invalid + * @retval -ENOBUFS If there is no space left in the mailbox message queue + */ static int camrtc_hsp_send(struct camrtc_hsp *camhsp, int request, long *timeout) { @@ -75,6 +95,26 @@ static int camrtc_hsp_send(struct camrtc_hsp *camhsp, return ret; } +/** + * @brief Receives a response message from the HSP mailbox + * + * This function waits for a response message from the HSP mailbox within + * the specified timeout period. + * - Waits for a response using @ref wait_event_timeout() + * - Atomically exchanges the response value using @ref atomic_xchg() + * - Reports a timeout error using @ref dev_err() if no response is received + * - Logs the response using @ref dev_dbg() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] command The original command sent + * Valid value: any integer value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 The response value on success + * @retval -ETIMEDOUT If no response is received within the timeout period + */ static int camrtc_hsp_recv(struct camrtc_hsp *camhsp, int command, long *timeout) { @@ -96,6 +136,23 @@ static int camrtc_hsp_recv(struct camrtc_hsp *camhsp, return response; } +/** + * @brief Sends a command and waits for a response from the HSP mailbox + * + * This function combines sending a command and receiving a response in a single call. + * - Sends the command using @ref camrtc_hsp_send() + * - If the send operation is successful, waits for a response using @ref camrtc_hsp_recv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] command Command to send + * Valid value: any integer value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 The response value on success + * @retval <0 Error code from @ref camrtc_hsp_send() or @ref camrtc_hsp_recv() + */ static int camrtc_hsp_sendrecv(struct camrtc_hsp *camhsp, int command, long *timeout) { @@ -110,6 +167,23 @@ static int camrtc_hsp_sendrecv(struct camrtc_hsp *camhsp, /* ---------------------------------------------------------------------- */ /* Protocol nvidia,tegra-camrtc-hsp-vm */ +/** + * @brief Handles notification of mailbox receive events + * + * This function is called by the mailbox framework when data is received. + * It processes the received message and performs the appropriate action: + * - Retrieves the HSP context using @ref dev_get_drvdata() + * - Extracts status and group information from the message + * - Validates the HSP context using @ref WARN_ON() + * - Handles unknown messages using @ref dev_dbg() + * - Calls the group notification callback if a group notification is received + * - For response messages, sets the response and wakes up waiters using @ref atomic_set() and @ref wake_up() + * + * @param[in] cl Pointer to the mailbox client + * Valid value: non-NULL + * @param[in] data Received message data + * Valid value: any value + */ static void camrtc_hsp_rx_full_notify(mbox_client *cl, void *data) { struct camrtc_hsp *camhsp = dev_get_drvdata(cl->dev); @@ -142,6 +216,20 @@ static void camrtc_hsp_rx_full_notify(mbox_client *cl, void *data) } } +/** + * @brief Handles notification of mailbox transmit completion + * + * This function is called by the mailbox framework when the transmit queue + * is emptied. It signals completion to any waiting threads. + * - Completes the "emptied" completion using @ref complete() + * + * @param[in] cl Pointer to the mailbox client + * Valid value: non-NULL + * @param[in] data Data from the mailbox controller + * Valid value: any value + * @param[in] empty_value Completion status + * Valid value: any value + */ static void camrtc_hsp_tx_empty_notify(mbox_client *cl, void *data, int empty_value) { struct camrtc_hsp *camhsp = dev_get_drvdata(cl->dev); @@ -183,6 +271,25 @@ static const struct camrtc_hsp_op camrtc_hsp_vm_ops = { .set_operating_point = camrtc_hsp_vm_set_operating_point, }; +/** + * @brief Sends a message over the VM HSP mailbox + * + * This function sends a message over the VM HSP mailbox using the provided channel. + * It performs the following operations: + * - Acquires the send lock using @ref spin_lock_irqsave() + * - Clears any previous response using @ref atomic_set() + * - Sends the message using @ref mbox_send_message() + * - Releases the send lock using @ref spin_unlock_irqrestore() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] request Message to send + * Valid value: any integer value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) response from @ref mbox_send_message() + */ static int camrtc_hsp_vm_send(struct camrtc_hsp *camhsp, int request, long *timeout) { @@ -197,12 +304,37 @@ static int camrtc_hsp_vm_send(struct camrtc_hsp *camhsp, return response; } +/** + * @brief Rings a group doorbell by sending an IRQ message + * + * This function rings a group doorbell by sending an IRQ message to the RTCPU. + * It performs the following operations: + * - Calls @ref camrtc_hsp_vm_send_irqmsg() to send an IRQ message + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] group Group identifier to ring the doorbell for + * Valid value: any 16-bit value + */ static void camrtc_hsp_vm_group_ring(struct camrtc_hsp *camhsp, u16 group) { camrtc_hsp_vm_send_irqmsg(camhsp); } +/** + * @brief Sends an IRQ message to the RTCPU via HSP + * + * This function sends an interrupt request message to the RTCPU over the HSP + * mailbox. It performs the following operations: + * - Creates an IRQ message with parameter value 1 using @ref CAMRTC_HSP_MSG() + * - Acquires a spinlock to ensure thread safety using @ref spin_lock_irqsave() + * - Sends the message using @ref mbox_send_message() + * - Releases the spinlock using @ref spin_unlock_irqrestore() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + */ static void camrtc_hsp_vm_send_irqmsg(struct camrtc_hsp *camhsp) { int irqmsg = CAMRTC_HSP_MSG(CAMRTC_HSP_IRQ, 1); @@ -214,6 +346,28 @@ static void camrtc_hsp_vm_send_irqmsg(struct camrtc_hsp *camhsp) spin_unlock_irqrestore(&camhsp->sendlock, flags); } +/** + * @brief Sends a message and waits for a response over the VM HSP mailbox + * + * This function sends a message and waits for a response using the common + * send/receive function. It performs additional validation on the response + * message to ensure it matches the request. The operations include: + * - Calls @ref camrtc_hsp_sendrecv() to send the message and receive a response + * - Validates that the message ID in the response matches the request using @ref CAMRTC_HSP_MSG_ID() + * - Reports errors using @ref dev_err() if the response doesn't match the request + * - Extracts and returns only the parameter portion of the response using @ref CAMRTC_HSP_MSG_PARAM() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] request Request message to send + * Valid value: any integer value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 The parameter portion of the response message + * @retval <0 Error code from @ref camrtc_hsp_sendrecv() + * @retval -EIO If the response message ID doesn't match the request + */ static int camrtc_hsp_vm_sendrecv(struct camrtc_hsp *camhsp, int request, long *timeout) { @@ -233,6 +387,23 @@ static int camrtc_hsp_vm_sendrecv(struct camrtc_hsp *camhsp, return CAMRTC_HSP_MSG_PARAM(response); } +/** + * @brief Reads boot log messages from the RTCPU + * + * This function reads and processes boot log messages from the RTCPU during + * the initialization process. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Uses @ref camrtc_hsp_recv() to wait for and receive boot log messages + * - Processes different types of boot messages (complete, stage, error) + * - Logs messages at appropriate log levels using @ref dev_info(), @ref dev_dbg(), and @ref dev_err() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval 0 On successful completion of the boot log reading + * @retval -ETIMEDOUT If timed out waiting for boot messages + * @retval -EINVAL If received a boot error message or invalid HSP context + */ static int camrtc_hsp_vm_read_boot_log(struct camrtc_hsp *camhsp) { uint32_t boot_log; @@ -273,6 +444,25 @@ static int camrtc_hsp_vm_read_boot_log(struct camrtc_hsp *camhsp) return 0U; } +/** + * @brief Synchronizes with the RTCPU via HSP + * + * This function performs the initial handshake with the RTCPU by reading + * boot logs and establishing communication. It performs the following operations: + * - Reads boot logs using @ref camrtc_hsp_vm_read_boot_log() + * - Logs a warning if boot logs cannot be read but continues with handshake + * - Sends a hello message using @ref camrtc_hsp_vm_hello() to establish communication + * - Stores the cookie (response) returned from hello message + * - Negotiates protocol version using @ref camrtc_hsp_vm_protocol() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 On successful synchronization (protocol version) + * @retval <0 Error code from @ref camrtc_hsp_vm_hello() or @ref camrtc_hsp_vm_protocol() + */ static int camrtc_hsp_vm_sync(struct camrtc_hsp *camhsp, long *timeout) { int response; @@ -295,6 +485,18 @@ static int camrtc_hsp_vm_sync(struct camrtc_hsp *camhsp, long *timeout) return response; } +/** + * @brief Generates a cookie value for HSP handshake + * + * This function generates a 24-bit cookie value used for handshake and + * subsequent communication with the RTCPU. The cookie serves as an + * identifier for the session. It performs the following operations: + * - Uses @ref sched_clock() to get a timestamp + * - Extracts the lower bits using @ref CAMRTC_HSP_MSG_PARAM() + * - Ensures the cookie is never zero by incrementing if needed + * + * @return u32 Cookie value (non-zero 24-bit value) + */ static u32 camrtc_hsp_vm_cookie(void) { u32 value = CAMRTC_HSP_MSG_PARAM(sched_clock() >> 5U); @@ -305,6 +507,24 @@ static u32 camrtc_hsp_vm_cookie(void) return value; } +/** + * @brief Sends a HELLO message to the RTCPU and waits for echo + * + * This function initiates communication with the RTCPU by sending a HELLO + * message with a unique cookie and waiting for the same message to be echoed + * back. It performs the following operations: + * - Creates a HELLO message with a unique cookie using @ref CAMRTC_HSP_MSG() and @ref camrtc_hsp_vm_cookie() + * - Sends the message using @ref camrtc_hsp_send() + * - Repeatedly calls @ref camrtc_hsp_recv() until the echoed message is received or timeout + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval request On successful handshake (value of the HELLO message with cookie) + * @retval <0 Error code from @ref camrtc_hsp_send() or @ref camrtc_hsp_recv() + */ static int camrtc_hsp_vm_hello(struct camrtc_hsp *camhsp, long *timeout) { int request = CAMRTC_HSP_MSG(CAMRTC_HSP_HELLO, camrtc_hsp_vm_cookie()); @@ -328,6 +548,22 @@ static int camrtc_hsp_vm_hello(struct camrtc_hsp *camhsp, long *timeout) return response; } +/** + * @brief Negotiates protocol version with RTCPU + * + * This function negotiates the protocol version to use for communication with + * the RTCPU. It performs the following operations: + * - Creates a protocol message with the driver's version using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval >=0 On successful negotiation (protocol version) + * @retval <0 Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_protocol(struct camrtc_hsp *camhsp, long *timeout) { int request = CAMRTC_HSP_MSG(CAMRTC_HSP_PROTOCOL, @@ -336,6 +572,21 @@ static int camrtc_hsp_vm_protocol(struct camrtc_hsp *camhsp, long *timeout) return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Resumes the RTCPU firmware + * + * This function resumes the RTCPU firmware by sending a RESUME message with + * the current cookie value. It performs the following operations: + * - Creates a RESUME message with the current cookie using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_resume(struct camrtc_hsp *camhsp, long *timeout) { int request = CAMRTC_HSP_MSG(CAMRTC_HSP_RESUME, camhsp->cookie); @@ -343,6 +594,21 @@ static int camrtc_hsp_vm_resume(struct camrtc_hsp *camhsp, long *timeout) return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Suspends the RTCPU firmware + * + * This function suspends the RTCPU firmware by sending a SUSPEND message with + * a zero cookie value. It performs the following operations: + * - Creates a SUSPEND message with a zero cookie using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_suspend(struct camrtc_hsp *camhsp, long *timeout) { u32 request = CAMRTC_HSP_MSG(CAMRTC_HSP_SUSPEND, 0); @@ -350,6 +616,21 @@ static int camrtc_hsp_vm_suspend(struct camrtc_hsp *camhsp, long *timeout) return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Sends a BYE message to the RTCPU + * + * This function sends a BYE message to the RTCPU to terminate the communication + * session. It performs the following operations: + * - Creates a BYE message with a zero cookie using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_bye(struct camrtc_hsp *camhsp, long *timeout) { u32 request = CAMRTC_HSP_MSG(CAMRTC_HSP_BYE, 0); @@ -359,6 +640,23 @@ static int camrtc_hsp_vm_bye(struct camrtc_hsp *camhsp, long *timeout) return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Sets up the channel for communication with the RTCPU + * + * This function sets up the channel for communication with the RTCPU by sending + * a CH_SETUP message with the provided IOVA value. It performs the following operations: + * - Creates a CH_SETUP message with the IOVA value using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] iova IOVA value to set up the channel with + * Valid value: any DMA address + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_ch_setup(struct camrtc_hsp *camhsp, dma_addr_t iova, long *timeout) { @@ -367,6 +665,23 @@ static int camrtc_hsp_vm_ch_setup(struct camrtc_hsp *camhsp, return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Pings the RTCPU + * + * This function pings the RTCPU by sending a PING message with the provided data. + * It performs the following operations: + * - Creates a PING message with the provided data using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] data Data to send in the PING message + * Valid value: any 32-bit value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_ping(struct camrtc_hsp *camhsp, u32 data, long *timeout) { @@ -375,6 +690,23 @@ static int camrtc_hsp_vm_ping(struct camrtc_hsp *camhsp, u32 data, return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Gets the firmware hash from the RTCPU + * + * This function gets the firmware hash from the RTCPU by sending a FW_HASH + * message with the provided index. It performs the following operations: + * - Creates a FW_HASH message with the provided index using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] index Index of the firmware hash to get + * Valid value: any 32-bit value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_get_fw_hash(struct camrtc_hsp *camhsp, u32 index, long *timeout) { @@ -383,6 +715,23 @@ static int camrtc_hsp_vm_get_fw_hash(struct camrtc_hsp *camhsp, u32 index, return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Sets the operating point for the RTCPU + * + * This function sets the operating point for the RTCPU by sending a SET_OP_POINT + * message with the provided operating point value. It performs the following operations: + * - Creates a SET_OP_POINT message with the provided operating point value using @ref CAMRTC_HSP_MSG() + * - Sends the message and waits for response using @ref camrtc_hsp_vm_sendrecv() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] operating_point Operating point value to set + * Valid value: any 32-bit value + * @param[in,out] timeout Pointer to timeout value in jiffies + * Valid value: non-NULL + * + * @retval (int) Error code from @ref camrtc_hsp_vm_sendrecv() + */ static int camrtc_hsp_vm_set_operating_point(struct camrtc_hsp *camhsp, u32 operating_point, long *timeout) { @@ -391,6 +740,23 @@ static int camrtc_hsp_vm_set_operating_point(struct camrtc_hsp *camhsp, u32 oper return camrtc_hsp_vm_sendrecv(camhsp, request, timeout); } +/** + * @brief Probes for a VM HSP device + * + * This function probes for a VM HSP device by searching through the device tree + * for a compatible node with the name "nvidia,tegra-camrtc-hsp-vm". It performs + * the following operations: + * - Gets the parent device node using @ref of_node_get() + * - Searches for a child node with the compatible string "nvidia,tegra-camrtc-hsp-vm" + * - Returns the first available child node if found + * - Returns NULL if no compatible node is found + * + * @param[in] parent Pointer to the parent device node + * Valid value: non-NULL + * + * @retval Pointer to the available child node if found + * @retval NULL if no compatible node is found + */ static struct device_node *hsp_vm_get_available(const struct device_node *parent) { const char *compatible = "nvidia,tegra-camrtc-hsp-vm"; @@ -404,6 +770,24 @@ static struct device_node *hsp_vm_get_available(const struct device_node *parent return child; } +/** + * @brief Probes and initializes an HSP VM device + * + * This function probes and initializes a VM HSP device. It performs the following operations: + * - Gets an available HSP VM device node using @ref hsp_vm_get_available() + * - Requests mailbox channels for RX and TX using @ref mbox_request_channel_byname() + * - Sets up the operations structure and device name using @ref dev_set_name() + * - Reports errors using @ref dev_err() if channel requests fail + * - Releases resources on failure using @ref of_node_put() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval 0 On successful probe + * @retval -ENOTSUPP If no compatible HSP VM device is found + * @retval -EPROBE_DEFER If probe should be deferred + * @retval (int) Error code from @ref mbox_request_channel_byname() + */ static int camrtc_hsp_vm_probe(struct camrtc_hsp *camhsp) { struct device_node *np = camhsp->dev.parent->of_node; @@ -450,6 +834,19 @@ fail: /* ---------------------------------------------------------------------- */ /* Public interface */ +/** + * @brief Rings a group doorbell + * + * This function rings a group doorbell by calling the group_ring operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Calls the group_ring operation on the HSP context using @ref group_ring() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] group Group identifier to ring the doorbell for + * Valid value: any 16-bit value + */ void camrtc_hsp_group_ring(struct camrtc_hsp *camhsp, u16 group) { @@ -458,8 +855,21 @@ void camrtc_hsp_group_ring(struct camrtc_hsp *camhsp, } EXPORT_SYMBOL(camrtc_hsp_group_ring); -/* - * Synchronize the HSP +/** + * @brief Synchronizes the HSP + * + * This function synchronizes the HSP by calling the sync operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the sync operation on the HSP context using @ref sync() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval (int) Return code from @ref sync() + * @retval -EINVAL If the HSP context is NULL */ int camrtc_hsp_sync(struct camrtc_hsp *camhsp) { @@ -478,8 +888,21 @@ int camrtc_hsp_sync(struct camrtc_hsp *camhsp) } EXPORT_SYMBOL(camrtc_hsp_sync); -/* - * Resume: resume the firmware +/** + * @brief Resumes the HSP + * + * This function resumes the HSP by calling the resume operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the resume operation on the HSP context using @ref resume() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval (int) Return code from @ref resume() + * @retval -EINVAL If the HSP context is NULL */ int camrtc_hsp_resume(struct camrtc_hsp *camhsp) { @@ -498,8 +921,22 @@ int camrtc_hsp_resume(struct camrtc_hsp *camhsp) } EXPORT_SYMBOL(camrtc_hsp_resume); -/* - * Suspend: set firmware to idle. +/** + * @brief Suspends the HSP + * + * This function suspends the HSP by calling the suspend operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the suspend operation on the HSP context using @ref suspend() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval (int) Return code from @ref suspend() + * @retval -EINVAL If the HSP context is NULL + * @retval -EIO If the suspend operation fails */ int camrtc_hsp_suspend(struct camrtc_hsp *camhsp) { @@ -522,8 +959,24 @@ int camrtc_hsp_suspend(struct camrtc_hsp *camhsp) } EXPORT_SYMBOL(camrtc_hsp_suspend); -/* - * Set Operating Point: set operating point +/** + * @brief Sets the operating point for the HSP + * + * This function sets the operating point for the HSP by calling the set_operating_point + * operation on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the set_operating_point operation on the HSP context using @ref set_operating_point() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] operating_point Operating point value to set + * Valid value: any 32-bit value + * + * @retval (int) Return code from @ref set_operating_point() + * @retval -EINVAL If the HSP context is NULL + * @retval -EIO If the set_operating_point operation fails */ int camrtc_hsp_set_operating_point(struct camrtc_hsp *camhsp, uint32_t operating_point) { @@ -546,8 +999,21 @@ int camrtc_hsp_set_operating_point(struct camrtc_hsp *camhsp, uint32_t operating } EXPORT_SYMBOL(camrtc_hsp_set_operating_point); -/* - * Bye: tell firmware that VM mappings are going away +/** + * @brief Sends a BYE message to the HSP + * + * This function sends a BYE message to the HSP by calling the bye operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the bye operation on the HSP context using @ref bye() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval (int) Return code from @ref bye() + * @retval -EINVAL If the HSP context is NULL */ int camrtc_hsp_bye(struct camrtc_hsp *camhsp) { @@ -569,6 +1035,24 @@ int camrtc_hsp_bye(struct camrtc_hsp *camhsp) } EXPORT_SYMBOL(camrtc_hsp_bye); +/** + * @brief Sets up the HSP channel + * + * This function sets up the HSP channel by calling the ch_setup operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the ch_setup operation on the HSP context using @ref ch_setup() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] iova IOVA value to set + * Valid value: any 32-bit value + * + * @retval (int) Error code from @ref ch_setup() + * @retval -EINVAL If the HSP context is NULL or the IOVA is invalid + */ int camrtc_hsp_ch_setup(struct camrtc_hsp *camhsp, dma_addr_t iova) { long timeout; @@ -595,6 +1079,26 @@ int camrtc_hsp_ch_setup(struct camrtc_hsp *camhsp, dma_addr_t iova) } EXPORT_SYMBOL(camrtc_hsp_ch_setup); +/** + * @brief Pings the HSP + * + * This function pings the HSP by calling the ping operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the ping operation on the HSP context using @ref ping() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] data Data value to ping + * Valid value: any 32-bit value + * @param[in] timeout Timeout value to use + * Valid value: any 32-bit value + * + * @retval (int) Error code from @ref ping() + * @retval -EINVAL If the HSP context is NULL + */ int camrtc_hsp_ping(struct camrtc_hsp *camhsp, u32 data, long timeout) { long left = timeout; @@ -614,6 +1118,28 @@ int camrtc_hsp_ping(struct camrtc_hsp *camhsp, u32 data, long timeout) } EXPORT_SYMBOL(camrtc_hsp_ping); +/** + * @brief Gets the firmware hash for the HSP + * + * This function gets the firmware hash for the HSP by calling the get_fw_hash operation + * on the HSP context. It performs the following operations: + * - Validates the HSP context using @ref WARN_ON() + * - Locks the mutex using @ref mutex_lock() + * - Calls the get_fw_hash operation on the HSP context using @ref get_fw_hash() + * - Unlocks the mutex using @ref mutex_unlock() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * @param[in] hash Hash value to get + * Valid value: any 32-bit value + * @param[in] hash_size Size of the hash value + * Valid value: any 32-bit value + * + * @retval (int) Error code from @ref get_fw_hash() + * @retval -EINVAL If the HSP context is NULL + * @retval -EIO If the get_fw_hash operation fails + * @retval 0 On success + */ int camrtc_hsp_get_fw_hash(struct camrtc_hsp *camhsp, u8 hash[], size_t hash_size) { @@ -652,6 +1178,19 @@ static const struct device_type camrtc_hsp_combo_dev_type = { .name = "camrtc-hsp-protocol", }; +/** + * @brief Releases resources for a camera HSP combo device + * + * This function is called when a camera HSP combo device is being destroyed. + * It performs the following operations: + * - Gets the camera HSP context using @ref container_of() + * - Frees the RX and TX mailbox channels using @ref mbox_free_channel() if they exist + * - Releases the device node using @ref of_node_put() + * - Frees the camera HSP context using @ref kfree() + * + * @param[in] dev Pointer to the device being released + * Valid value: non-NULL + */ static void camrtc_hsp_combo_dev_release(struct device *dev) { struct camrtc_hsp *camhsp = container_of(dev, struct camrtc_hsp, dev); @@ -665,6 +1204,23 @@ static void camrtc_hsp_combo_dev_release(struct device *dev) kfree(camhsp); } +/** + * @brief Probes for a camera HSP device + * + * This function attempts to probe for a camera HSP device by trying different + * probe methods. Currently, it only tries the VM HSP probe method. + * It performs the following operations: + * - Calls @ref camrtc_hsp_vm_probe() to attempt VM HSP probe + * - Returns success if VM probe succeeds + * - Returns -ENODEV if no supported HSP device is found + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval 0 On successful probe + * @retval -ENODEV If no supported HSP device is found + * @retval (int) Error code from @ref camrtc_hsp_vm_probe() + */ static int camrtc_hsp_probe(struct camrtc_hsp *camhsp) { int ret; @@ -676,6 +1232,47 @@ static int camrtc_hsp_probe(struct camrtc_hsp *camhsp) return -ENODEV; } +/** + * @brief Creates a camera HSP device + * + * This function creates a camera HSP device by allocating memory for the HSP context + * and initializing its fields. It performs the following operations: + * - Allocates memory for the HSP context using @ref kzalloc() + * - Initializes the HSP context fields + * - Sets the parent device using @ref dev_set_parent() + * - Sets the group notify function using @ref camrtc_hsp_set_group_notify() + * - Sets the command timeout using @ref camrtc_hsp_set_cmd_timeout() + * - Initializes the mutex using @ref mutex_init() + * - Initializes the send lock using @ref spin_lock_init() + * - Initializes the response wait queue using @ref init_waitqueue_head() + * - Initializes the emptied completion using @ref init_completion() + * - Sets the response atomic variable to -1 using @ref atomic_set() + * - Sets the device type using @ref camrtc_hsp_combo_dev_type + * - Sets the device release function using @ref camrtc_hsp_combo_dev_release() + * - Initializes the device using @ref device_initialize() + * - Sets the device name using @ref dev_set_name() + * - Disables runtime PM using @ref pm_runtime_no_callbacks() + * - Enables runtime PM using @ref pm_runtime_enable() + * - Sets the TX client block flag to false + * - Sets the RX callback function using @ref camrtc_hsp_rx_full_notify() + * - Sets the TX done function using @ref camrtc_hsp_tx_empty_notify() + * - Sets the TX and RX client device using @ref camhsp->tx.client.dev + * - Sets the device driver data using @ref dev_set_drvdata() + * - Calls @ref camrtc_hsp_probe() to attempt HSP probe + * - Adds the device using @ref device_add() + * + * @param[in] dev Pointer to the device creating the HSP + * Valid value: non-NULL + * @param[in] group_notify Function pointer to the group notify function + * Valid value: non-NULL + * @param[in] cmd_timeout Command timeout value + * Valid value: any 32-bit value + * + * @retval (struct camrtc_hsp *) Pointer to the HSP context on success + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(-EINVAL) If the HSP context is NULL + * @retval ERR_PTR(int) Error code from @ref camrtc_hsp_probe() or @ref device_add() + */ struct camrtc_hsp *camrtc_hsp_create( struct device *dev, void (*group_notify)(struct device *dev, u16 group), @@ -728,6 +1325,20 @@ fail: } EXPORT_SYMBOL(camrtc_hsp_create); +/** + * @brief Frees a camera HSP device + * + * This function frees a camera HSP device by disabling runtime PM, unregistering + * the device, and releasing the device structure. It performs the following operations: + * - Checks if the HSP context is valid using @ref IS_ERR_OR_NULL() + * - Disables runtime PM using @ref pm_runtime_disable() + * - Checks if the device driver data is not NULL using @ref dev_get_drvdata() + * - Unregisters the device using @ref device_unregister() + * - Releases the device using @ref put_device() + * + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + */ void camrtc_hsp_free(struct camrtc_hsp *camhsp) { if (IS_ERR_OR_NULL(camhsp)) diff --git a/drivers/platform/tegra/rtcpu/ivc-bus.c b/drivers/platform/tegra/rtcpu/ivc-bus.c index 0bd2911b..b5330d84 100644 --- a/drivers/platform/tegra/rtcpu/ivc-bus.c +++ b/drivers/platform/tegra/rtcpu/ivc-bus.c @@ -42,6 +42,19 @@ struct tegra_ivc_bus { struct tegra_ivc_region regions[]; }; +/** + * @brief Notification callback for IVC channel ring events + * + * This function is called when an IVC ring event occurs. It retrieves the channel + * context and notifies the HSP group. + * - Gets the channel context using @ref container_of() + * - Notifies the HSP group using @ref camrtc_hsp_group_ring() + * + * @param[in] ivc Pointer to the IVC channel + * Valid value: non-NULL + * @param[in] data Pointer to the HSP context + * Valid value: non-NULL + */ static void tegra_ivc_channel_ring(struct tegra_ivc *ivc, void *data) { struct tegra_ivc_channel *chan = @@ -56,6 +69,19 @@ struct device_type tegra_ivc_channel_type = { }; EXPORT_SYMBOL(tegra_ivc_channel_type); +/** + * @brief Gets a runtime PM reference for an IVC channel + * + * This function gets a runtime PM reference for the specified IVC channel. + * It ensures the channel is powered on and ready for use. + * - Validates the channel pointer using @ref BUG_ON() + * - Gets a runtime PM reference using @ref pm_runtime_get_sync() + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + * + * @retval (int) return value from @ref pm_runtime_get_sync() + */ int tegra_ivc_channel_runtime_get(struct tegra_ivc_channel *ch) { BUG_ON(ch == NULL); @@ -64,6 +90,17 @@ int tegra_ivc_channel_runtime_get(struct tegra_ivc_channel *ch) } EXPORT_SYMBOL(tegra_ivc_channel_runtime_get); +/** + * @brief Releases a runtime PM reference for an IVC channel + * + * This function releases a runtime PM reference for the specified IVC channel. + * It allows the channel to be powered down when not in use. + * - Validates the channel pointer using @ref BUG_ON() + * - Releases the runtime PM reference using @ref pm_runtime_put() + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + */ void tegra_ivc_channel_runtime_put(struct tegra_ivc_channel *ch) { BUG_ON(ch == NULL); @@ -72,6 +109,18 @@ void tegra_ivc_channel_runtime_put(struct tegra_ivc_channel *ch) } EXPORT_SYMBOL(tegra_ivc_channel_runtime_put); +/** + * @brief Releases resources associated with an IVC channel device + * + * This function is called when an IVC channel device is being destroyed. + * It performs cleanup of allocated resources. + * - Gets the channel context using @ref container_of() + * - Releases the device node using @ref of_node_put() + * - Frees the channel memory using @ref kfree() + * + * @param[in] dev Pointer to the device being released + * Valid value: non-NULL + */ static void tegra_ivc_channel_release(struct device *dev) { struct tegra_ivc_channel *chan = @@ -81,6 +130,37 @@ static void tegra_ivc_channel_release(struct device *dev) kfree(chan); } +/** + * @brief Creates and initializes a new IVC channel + * + * This function creates and initializes a new IVC channel with the specified parameters. + * It performs the following operations: + * - Validates the bus, channel node, region, and camhsp pointers + * - Sets the device name using @ref dev_set_name() + * - Initializes device properties and runtime PM using @ref pm_runtime_no_callbacks() and @ref pm_runtime_enable() + * - Reads channel configuration from device tree using @ref of_property_read_string(), @ref of_property_read_u32(), and @ref fls() + * - Check for overflows in size calculations using @ref __builtin_add_overflow() and @ref __builtin_mul_overflow() + * - Calculates total queue size using @ref tegra_ivc_total_queue_size() + * - Checks if buffers exceed IVC region using @ref __builtin_add_overflow() + * - Initializes IVC communication using @ref tegra_ivc_init() + * - Reset IVC communication using @ref tegra_ivc_reset() + * - Add device using @ref device_add() + * + * @param[in] bus Pointer to the IVC bus + * Valid value: non-NULL + * @param[in] ch_node Pointer to the device tree node + * Valid value: non-NULL + * @param[in] region Pointer to the IVC region + * Valid value: non-NULL + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval (struct tegra_ivc_channel *) Pointer to the created IVC channel on success + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(-ENOSPC) If buffers exceed IVC region + * @retval ERR_PTR(-EOVERFLOW) If size calculations overflow + * @retval ERR_PTR(-EIO) If IVC initialization fails + */ static struct tegra_ivc_channel *tegra_ivc_channel_create( struct tegra_ivc_bus *bus, struct device_node *ch_node, struct tegra_ivc_region *region, @@ -297,6 +377,20 @@ error: return ERR_PTR(ret); } +/** + * @brief Notifies a channel of an IVC event + * + * This function handles notification of IVC events for a specific channel. + * It performs the following operations: + * - Checks if the channel has been notified using @ref tegra_ivc_channel_notified() or @ref tegra_ivc_notified() + * - Verifies if the channel is ready using @ref chan->is_ready + * - Uses RCU locking to safely access channel operations using @ref rcu_read_lock() and @ref rcu_dereference() + * - Calls the channel's notify callback if available using @ref ops->notify() + * - Unlocks the RCU using @ref rcu_read_unlock() + * + * @param[in] chan Pointer to the IVC channel + * Valid value: non-NULL + */ static void tegra_ivc_channel_notify(struct tegra_ivc_channel *chan) { const struct tegra_ivc_channel_ops *ops; @@ -319,6 +413,19 @@ static void tegra_ivc_channel_notify(struct tegra_ivc_channel *chan) rcu_read_unlock(); } +/** + * @brief Notifies all channels in a group of an IVC event + * + * This function iterates through all channels in the IVC bus and notifies + * those belonging to the specified group of an IVC event. + * - Iterates through all channels using a linked list + * - For each channel in the specified group, calls @ref tegra_ivc_channel_notify() + * + * @param[in] bus Pointer to the IVC bus + * Valid value: non-NULL + * @param[in] group Group identifier to notify + * Valid value: any 16-bit value + */ void tegra_ivc_bus_notify(struct tegra_ivc_bus *bus, u16 group) { struct tegra_ivc_channel *chan; @@ -335,6 +442,19 @@ struct device_type tegra_ivc_bus_dev_type = { }; EXPORT_SYMBOL(tegra_ivc_bus_dev_type); +/** + * @brief Releases resources associated with an IVC bus device + * + * This function is called when an IVC bus device is being destroyed. + * It performs cleanup of allocated resources. + * - Gets the bus context using @ref container_of() + * - Releases the device node using @ref of_node_put() + * - Frees DMA memory for each region using @ref dma_free_coherent() + * - Frees the bus memory using @ref kfree() + * + * @param[in] dev Pointer to the device being released + * Valid value: non-NULL + */ static void tegra_ivc_bus_release(struct device *dev) { struct tegra_ivc_bus *bus = @@ -355,6 +475,23 @@ static void tegra_ivc_bus_release(struct device *dev) kfree(bus); } +/** + * @brief Matches an IVC bus device with a driver + * + * This function determines if a driver can handle a specific IVC bus device. + * It performs the following operations: + * - Gets the IVC driver using @ref to_tegra_ivc_driver() + * - Checks if device type matches driver type + * - Uses @ref of_driver_match_device() for device tree matching + * + * @param[in] dev Pointer to the device to match + * Valid value: non-NULL + * @param[in] drv Pointer to the driver to match + * Valid value: non-NULL + * + * @retval 1 If the driver matches the device + * @retval 0 If the driver does not match the device + */ #if defined(NV_BUS_TYPE_STRUCT_MATCH_HAS_CONST_DRV_ARG) static int tegra_ivc_bus_match(struct device *dev, const struct device_driver *drv) #else @@ -368,6 +505,19 @@ static int tegra_ivc_bus_match(struct device *dev, struct device_driver *drv) return of_driver_match_device(dev, drv); } +/** + * @brief Stops and cleans up all channels in an IVC bus + * + * This function stops all IVC channels associated with a bus and releases their resources. + * It performs the following operations: + * - Iterates through all channels in the linked list + * - Disables runtime PM for each channel using @ref pm_runtime_disable() + * - Unregisters each channel device using @ref device_unregister() + * - Updates the linked list as channels are removed + * + * @param[in] bus Pointer to the IVC bus + * Valid value: non-NULL + */ static void tegra_ivc_bus_stop(struct tegra_ivc_bus *bus) { while (bus->chans != NULL) { @@ -379,6 +529,25 @@ static void tegra_ivc_bus_stop(struct tegra_ivc_bus *bus) } } +/** + * @brief Starts all channels in an IVC bus + * + * This function initializes and starts all IVC channels associated with a bus. + * It performs the following operations: + * - Iterates through device tree nodes to find channel specifications + * - Checks if each channel is enabled in the device tree + * - Creates each channel using @ref tegra_ivc_channel_create() + * - Adds each channel to the linked list of channels in the bus + * - Cleans up on error using @ref tegra_ivc_bus_stop() + * + * @param[in] bus Pointer to the IVC bus + * Valid value: non-NULL + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval 0 On successful startup + * @retval (int) Error code from @ref tegra_ivc_channel_create() + */ static int tegra_ivc_bus_start(struct tegra_ivc_bus *bus, struct camrtc_hsp *camhsp) { @@ -426,9 +595,23 @@ error: return ret; } -/* - * This is called during RTCPU boot to synchronize - * (or re-synchronize in the case of PM resume). +/** + * @brief Synchronizes IVC bus during RTCPU boot or PM resume + * + * This function is called during RTCPU boot to synchronize or re-synchronize + * the IVC bus in the case of PM resume. It sets up the IOVM for each + * IVC region. + * - Checks if the bus is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all regions in the bus + * - Calls the provided IOVM setup function for each region + * + * @param[in] bus Pointer to the IVC bus + * Valid value: any value including NULL or error pointer + * @param[in] iovm_setup Function pointer to set up IOVM mappings + * Valid value: non-NULL function pointer + * + * @retval 0 On successful synchronization or if bus is NULL/error + * @retval -EIO If IOVM setup fails */ int tegra_ivc_bus_boot_sync(struct tegra_ivc_bus *bus, int (*iovm_setup)(struct device*, dma_addr_t)) @@ -451,6 +634,25 @@ int tegra_ivc_bus_boot_sync(struct tegra_ivc_bus *bus, } EXPORT_SYMBOL(tegra_ivc_bus_boot_sync); +/** + * @brief Probes an IVC bus device + * + * This function is called when a device is added to the IVC bus. + * It initializes the device and calls the driver's probe function. + * Currently, it only supports IVC channel devices. + * - Checks if the device is an IVC channel using its type + * - Gets the driver and channel from the device + * - Initializes the channel's mutex + * - Calls the driver's probe function if available + * - Sets up the RCU-protected operations pointer + * + * @param[in] dev Pointer to the device to probe + * Valid value: non-NULL + * + * @retval 0 On successful probe + * @retval -ENXIO If the device is not supported + * @retval (int) Error code from driver's probe function + */ static int tegra_ivc_bus_probe(struct device *dev) { int ret = -ENXIO; @@ -477,6 +679,22 @@ static int tegra_ivc_bus_probe(struct device *dev) return ret; } +/** + * @brief Removes an IVC bus device + * + * This function is called when a device is removed from the IVC bus. + * It cleans up the device and calls the driver's remove function. + * Currently, it only supports IVC channel devices. + * - Checks if the device is an IVC channel using its type + * - Gets the driver and channel from the device + * - Safely removes the RCU-protected operations pointer + * - Calls the driver's remove function if available + * + * @param[in] dev Pointer to the device to remove + * Valid value: non-NULL + * + * @retval 0 On successful removal (for Linux v5.15+ only) + */ #if defined(NV_BUS_TYPE_STRUCT_REMOVE_HAS_INT_RETURN_TYPE) /* Linux v5.15 */ static int tegra_ivc_bus_remove(struct device *dev) #else @@ -502,6 +720,26 @@ static void tegra_ivc_bus_remove(struct device *dev) #endif } +/** + * @brief Sets the ready state for a child device in the IVC bus + * + * This function is called for each child device in the IVC bus to set its ready state. + * It notifies the driver about the readiness of the device. + * - Gets the driver for the device using @ref to_tegra_ivc_driver() + * - Processes ready state from the data parameter + * - If the device is an IVC channel, gets the channel using @ref to_tegra_ivc_channel() + * - Updates the ready flag and resets counter using @ref atomic_inc() and @ref smp_wmb() + * - If the driver is not NULL, reads the RCU-protected operations pointer using @ref rcu_read_lock() and @ref rcu_dereference() + * - Calls the driver's ready callback if available using @ref ops->ready() + * - Releases the RCU read lock using @ref rcu_read_unlock() + * + * @param[in] dev Pointer to the child device + * Valid value: non-NULL + * @param[in] data Pointer to the ready state data (boolean) + * Valid value: NULL (interpreted as true) or pointer to boolean + * + * @retval 0 Always returns success + */ static int tegra_ivc_bus_ready_child(struct device *dev, void *data) { struct tegra_ivc_driver *drv = to_tegra_ivc_driver(dev->driver); @@ -538,18 +776,60 @@ struct bus_type tegra_ivc_bus_type = { }; EXPORT_SYMBOL(tegra_ivc_bus_type); +/** + * @brief Registers an IVC driver with the IVC bus + * + * This function registers a driver with the IVC bus system. + * It allows the driver to handle IVC channel devices. + * - Calls @ref driver_register() to register the driver with the kernel + * + * @param[in] drv Pointer to the IVC driver to register + * Valid value: non-NULL + * + * @retval (int) return value from @ref driver_register() + */ int tegra_ivc_driver_register(struct tegra_ivc_driver *drv) { return driver_register(&drv->driver); } EXPORT_SYMBOL(tegra_ivc_driver_register); +/** + * @brief Unregisters an IVC driver from the IVC bus + * + * This function unregisters a driver from the IVC bus system. + * It removes the driver's ability to handle IVC channel devices. + * - Calls @ref driver_unregister() to unregister the driver from the kernel + * + * @param[in] drv Pointer to the IVC driver to unregister + * Valid value: non-NULL + */ void tegra_ivc_driver_unregister(struct tegra_ivc_driver *drv) { return driver_unregister(&drv->driver); } EXPORT_SYMBOL(tegra_ivc_driver_unregister); +/** + * @brief Parses IVC regions from device tree + * + * This function parses IVC region specifications from the device tree. + * It allocates memory for each region and initializes region parameters. + * - Iterates through device tree nodes to find channel specifications + * - Validates region specifications + * - Counts frames and calculates sizes + * - Allocates DMA-coherent memory for each region + * - Initializes region parameters + * + * @param[in] bus Pointer to the IVC bus + * Valid value: non-NULL + * @param[in] dev_node Pointer to the device tree node + * Valid value: non-NULL + * + * @retval 0 On successful parsing + * @retval -EINVAL If region specification is invalid + * @retval -ENOMEM If memory allocation fails + */ static int tegra_ivc_bus_parse_regions(struct tegra_ivc_bus *bus, struct device_node *dev_node) { @@ -633,6 +913,17 @@ static int tegra_ivc_bus_parse_regions(struct tegra_ivc_bus *bus, return 0; } +/** + * @brief Counts the number of IVC regions in a device tree node + * + * This function counts the number of IVC regions specified in a device tree node. + * It uses @ref of_parse_phandle_with_fixed_args() to iterate through all ivc-channels. + * + * @param[in] dev_node Pointer to the device tree node + * Valid value: non-NULL + * + * @retval (unsigned) The number of IVC regions found + */ static unsigned tegra_ivc_bus_count_regions(const struct device_node *dev_node) { unsigned i; @@ -644,6 +935,27 @@ static unsigned tegra_ivc_bus_count_regions(const struct device_node *dev_node) return i; } +/** + * @brief Creates and initializes an IVC bus + * + * This function creates and initializes an IVC bus with the specified parameters. + * It performs the following operations: + * - Counts the number of regions using @ref tegra_ivc_bus_count_regions() + * - Allocates memory for the bus and regions using @ref kzalloc() + * - Initializes bus properties and device parameters + * - Parses regions using @ref tegra_ivc_bus_parse_regions() + * - Adds the device using @ref device_add() + * - Starts the bus using @ref tegra_ivc_bus_start() + * + * @param[in] dev Pointer to the parent device + * Valid value: non-NULL + * @param[in] camhsp Pointer to the camera HSP context + * Valid value: non-NULL + * + * @retval struct tegra_ivc_bus* Pointer to the created IVC bus on success + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(ret) Error code from one of the called functions + */ struct tegra_ivc_bus *tegra_ivc_bus_create(struct device *dev, struct camrtc_hsp *camhsp) { @@ -694,8 +1006,19 @@ error: } EXPORT_SYMBOL(tegra_ivc_bus_create); -/* - * Communicate RTCPU UP/DOWN state to IVC devices. +/** + * @brief Communicates RTCPU UP/DOWN state to IVC devices + * + * This function communicates the RTCPU UP/DOWN state to IVC devices. + * It notifies all child devices of the bus about the RTCPU state. + * - Checks if the bus is valid using @ref IS_ERR_OR_NULL() + * - Calls @ref device_for_each_child() with @ref tegra_ivc_bus_ready_child() + * - If online, notifies all channels using @ref tegra_ivc_bus_notify() + * + * @param[in] bus Pointer to the IVC bus + * Valid value: any value including NULL or error pointer + * @param[in] online Boolean indicating if RTCPU is online (true) or offline (false) + * Valid value: true or false */ void tegra_ivc_bus_ready(struct tegra_ivc_bus *bus, bool online) { @@ -709,6 +1032,19 @@ void tegra_ivc_bus_ready(struct tegra_ivc_bus *bus, bool online) } EXPORT_SYMBOL(tegra_ivc_bus_ready); +/** + * @brief Destroys an IVC bus + * + * This function destroys an IVC bus and releases all associated resources. + * It performs the following operations: + * - Checks if the bus is valid using @ref IS_ERR_OR_NULL() and returns if invalid + * - Disables runtime PM for the device using @ref pm_runtime_disable() + * - Stops all channels using @ref tegra_ivc_bus_stop() + * - Unregisters the device using @ref device_unregister() + * + * @param[in] bus Pointer to the IVC bus + * Valid value: any value including NULL or error pointer + */ void tegra_ivc_bus_destroy(struct tegra_ivc_bus *bus) { if (IS_ERR_OR_NULL(bus)) @@ -720,11 +1056,26 @@ void tegra_ivc_bus_destroy(struct tegra_ivc_bus *bus) } EXPORT_SYMBOL(tegra_ivc_bus_destroy); +/** + * @brief Initializes the Tegra IVC bus subsystem + * + * This function initializes the IVC bus subsystem by registering the IVC bus type using + * @ref bus_register() + * @pre It is called during module initialization. + * + * @retval (int) return value from @ref bus_register() + */ static __init int tegra_ivc_bus_init(void) { return bus_register(&tegra_ivc_bus_type); } +/** + * @brief Cleans up the Tegra IVC bus subsystem + * + * This function performs cleanup of the IVC bus subsystem by unregistering the IVC bus type using @ref bus_unregister() + * @pre It is called during module exit. + */ static __exit void tegra_ivc_bus_exit(void) { bus_unregister(&tegra_ivc_bus_type); diff --git a/drivers/platform/tegra/rtcpu/reset-group.c b/drivers/platform/tegra/rtcpu/reset-group.c index 7daeb75c..5bc12451 100644 --- a/drivers/platform/tegra/rtcpu/reset-group.c +++ b/drivers/platform/tegra/rtcpu/reset-group.c @@ -16,6 +16,19 @@ struct camrtc_reset_group { struct reset_control *resets[]; }; +/** + * @brief Releases resources associated with a reset group + * + * This function is called when a reset group is being destroyed. + * It performs the following operations: + * - Iterates through all resets in the group + * - For each reset, if it exists, calls @ref reset_control_put() to release it + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] res Pointer to the reset group resource + * Valid value: non-NULL + */ static void camrtc_reset_group_release(struct device *dev, void *res) { const struct camrtc_reset_group *grp = res; @@ -27,6 +40,33 @@ static void camrtc_reset_group_release(struct device *dev, void *res) } } +/** + * @brief Gets a reset group based on device tree properties + * + * This function creates and initializes a reset group based on device tree properties. + * It performs the following operations: + * - Validates the device and its device tree node + * - Determines the appropriate property name based on the group_name parameter + * - Counts reset strings using @ref of_property_count_strings() + * - Checks for size overflows using @ref __builtin_add_overflow() + * - Allocates memory for the reset group using @ref devres_alloc() + * - Initializes group properties (nresets, device, group_name) + * - Iterates through all reset names in the group + * - Gets each reset control using @ref of_reset_control_get() + * - Adds the reset group to device resources using @ref devres_add() + * + * @param[in] dev Pointer to the parent device + * Valid value: non-NULL with valid device tree node + * @param[in] group_name Name of the reset group property + * Valid value: NULL (defaults to "reset-names") or a valid string + * + * @retval struct camrtc_reset_group* Reset group on success + * @retval ERR_PTR(-EINVAL) If device or device tree node is invalid + * @retval ERR_PTR(-ENOENT) If reset names property is not found + * @retval ERR_PTR(-EOVERFLOW) If size calculations overflow + * @retval ERR_PTR(-ENOMEM) If memory allocation fails + * @retval ERR_PTR(ret) If reset control retrieval fails + */ struct camrtc_reset_group *camrtc_reset_group_get( struct device *dev, const char *group_name) @@ -101,6 +141,23 @@ error: } EXPORT_SYMBOL_GPL(camrtc_reset_group_get); +/** + * @brief Reports an error related to a reset in a reset group + * + * This function reports an error related to a specific reset in a reset group. + * It performs the following operations: + * - Attempts to get the reset name from the device tree using @ref of_property_read_string_index() + * - Prints a warning message about the operation that failed using @ref dev_warn() + * + * @param[in] grp Pointer to the reset group + * Valid value: non-NULL + * @param[in] op String describing the operation that failed + * Valid value: non-NULL + * @param[in] index Index of the reset in the reset group + * Valid range: [0, grp->nresets-1] + * @param[in] error Error code + * Valid value: [INT_MIN, INT_MAX] + */ static void camrtc_reset_group_error( const struct camrtc_reset_group *grp, char const *op, @@ -119,6 +176,19 @@ static void camrtc_reset_group_error( op, name, grp->group_name, index, error); } +/** + * @brief Asserts all resets in a reset group + * + * This function asserts all resets in the specified reset group in reverse order. + * It performs the following operations: + * - Checks if the reset group is valid using @ref IS_ERR_OR_NULL() + * - Iterates through all resets in the group in reverse order + * - Asserts each reset using @ref reset_control_assert() + * - Reports errors using @ref camrtc_reset_group_error() if a reset fails to assert + * + * @param[in] grp Pointer to the reset group + * Valid value: any value including NULL or error pointer + */ void camrtc_reset_group_assert(const struct camrtc_reset_group *grp) { int index, index0, err; @@ -135,6 +205,24 @@ void camrtc_reset_group_assert(const struct camrtc_reset_group *grp) } EXPORT_SYMBOL_GPL(camrtc_reset_group_assert); +/** + * @brief Deasserts all resets in a reset group + * + * This function deasserts all resets in the specified reset group in forward order. + * It performs the following operations: + * - Checks if the reset group is valid using null check and @ref IS_ERR() + * - Iterates through all resets in the group in forward order + * - Deasserts each reset using @ref reset_control_deassert() + * - Reports errors using @ref camrtc_reset_group_error() if a reset fails to deassert + * - Returns an error code if any reset fails to deassert + * + * @param[in] grp Pointer to the reset group + * Valid value: any value including NULL or error pointer + * + * @retval 0 On successful deassertion of all resets + * @retval -ENODEV If the reset group is an error pointer + * @retval (int) Error code from @ref reset_control_deassert() + */ int camrtc_reset_group_deassert(const struct camrtc_reset_group *grp) { int index, err; diff --git a/drivers/platform/tegra/rtcpu/rtcpu-debug.c b/drivers/platform/tegra/rtcpu/rtcpu-debug.c index 4ae0a2c9..4b676d24 100644 --- a/drivers/platform/tegra/rtcpu/rtcpu-debug.c +++ b/drivers/platform/tegra/rtcpu/rtcpu-debug.c @@ -112,6 +112,22 @@ struct camrtc_dbgfs_rmem { static struct camrtc_dbgfs_rmem _camdbg_rmem; +/** + * @brief Initializes the camera debug reserved memory + * + * This function initializes the camera debug reserved memory area by dividing it into + * equal-sized memory contexts. It performs the following operations: + * - Stores the base address and total size of the reserved memory + * - Divides the memory into CAMRTC_DBG_NUM_MEM_TEST_MEM equal contexts + * - Sets up each memory context with its address and size + * - Uses @ref __builtin_uaddll_overflow to safely compute addresses + * - Enables the reserved memory flag + * + * @param[in] rmem Pointer to the reserved memory descriptor + * Valid value: non-NULL + * + * @retval 0 Operation successful + */ static int __init camrtc_dbgfs_rmem_init(struct reserved_mem *rmem) { int i; @@ -135,7 +151,21 @@ static int __init camrtc_dbgfs_rmem_init(struct reserved_mem *rmem) RESERVEDMEM_OF_DECLARE(tegra_cam_rtcpu, "nvidia,camdbg_carveout", camrtc_dbgfs_rmem_init); -/* Get a camera-rtcpu device */ +/** + * @brief Gets the camera-rtcpu device from an IVC channel + * + * This function retrieves the camera-rtcpu device associated with an IVC channel. + * It performs the following operations: + * - Checks if the channel pointer is valid using @ref unlikely() + * - Verifies both parent and grandparent device pointers exist using @ref BUG_ON() + * - Returns the grandparent device which is the camera-rtcpu device + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL (NULL check handled internally) + * + * @retval (struct device *) Pointer to the camera-rtcpu device + * @retval NULL if channel is NULL + */ static struct device *camrtc_get_device(struct tegra_ivc_channel *ch) { if (unlikely(ch == NULL)) @@ -161,6 +191,22 @@ static int _fops_ ## _open(struct inode *inode, struct file *file) \ } \ static const struct file_operations _fops_ = INIT_OPEN_FOPS(_fops_ ## _open) +/** + * @brief Outputs the camera-rtcpu version information + * + * This function retrieves and displays the camera-rtcpu version. + * It performs the following operations: + * - Gets the camera-rtcpu device using @ref camrtc_get_device() + * - Calls @ref tegra_camrtc_print_version() to get the version string + * - Writes the version string to the sequence file using @ref seq_puts() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Operation successful + */ static int camrtc_show_version(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -177,6 +223,25 @@ static int camrtc_show_version(struct seq_file *file, void *data) DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_version, camrtc_show_version); +/** + * @brief Reboots the camera-rtcpu and shows the result + * + * This function reboots the camera-rtcpu and writes the result to the sequence file. + * It performs the following operations: + * - Gets the camera-rtcpu device using @ref camrtc_get_device() + * - Brings rtcpu online using @ref tegra_ivc_channel_runtime_get() + * - Reboots the rtcpu using @ref tegra_camrtc_reboot() + * - Outputs "0" to the sequence file on success using @ref seq_puts() + * - Releases the runtime reference using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Reboot successful + * @retval negative Error code from @ref tegra_ivc_channel_runtime_get() or @ref tegra_camrtc_reboot() + */ static int camrtc_show_reboot(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -201,6 +266,17 @@ error: DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_reboot, camrtc_show_reboot); +/** + * @brief Notifies waiting threads about IVC activity + * + * This function wakes up all threads waiting on the debug wait queue. + * It performs the following operations: + * - Retrieves the camera debug data from the IVC channel using @ref tegra_ivc_channel_get_drvdata() + * - Wakes up all waiting threads using @ref wake_up_all() + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + */ static void camrtc_debug_notify(struct tegra_ivc_channel *ch) { struct camrtc_debug *crd = tegra_ivc_channel_get_drvdata(ch); @@ -208,6 +284,25 @@ static void camrtc_debug_notify(struct tegra_ivc_channel *ch) wake_up_all(&crd->waitq); } +/** + * @brief Forces a reset and restore of the camera-rtcpu + * + * This function forces a reset and restore of the camera-rtcpu and shows the result. + * It performs the following operations: + * - Gets the camera-rtcpu device using @ref camrtc_get_device() + * - Brings rtcpu online using @ref tegra_ivc_channel_runtime_get() + * - Restores the rtcpu using @ref tegra_camrtc_restore() + * - Outputs "0" to the sequence file on success using @ref seq_puts() + * - Releases the runtime reference using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Restore operation successful + * @retval negative Error code from @ref tegra_ivc_channel_runtime_get() or @ref tegra_camrtc_restore() + */ static int camrtc_show_forced_reset_restore(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -233,6 +328,41 @@ error: DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_forced_reset_restore, camrtc_show_forced_reset_restore); +/** + * @brief Performs a full-frame transaction with the camera-rtcpu debug interface + * + * This function sends a request to the camera-rtcpu and waits for a response. + * It performs the following operations: + * - Validates input parameters and acquires mutex lock using @ref mutex_lock_interruptible() + * - Gets runtime reference using @ref tegra_ivc_channel_runtime_get() + * - Verifies IVC channel is online with @ref tegra_ivc_channel_online_check() + * - Flushes any stray responses by calling @ref tegra_ivc_read_advance() + * - Waits for write availability using @ref wait_event_interruptible_timeout() + * - Writes request using @ref tegra_ivc_write() + * - Waits for and reads response using @ref tegra_ivc_read_peek() + * - Verifies response matches request type + * - Releases resources and lock using @ref tegra_ivc_channel_runtime_put() and @ref mutex_unlock() + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + * @param[in] req Pointer to the debug request structure + * Valid value: non-NULL + * @param[in] req_size Size of the request in bytes + * Valid range: > 0 + * @param[out] resp Pointer to the debug response structure + * Valid value: non-NULL + * @param[in] resp_size Size of the response in bytes + * Valid range: > 0 + * @param[in] timeout Timeout in milliseconds, 0 for default + * Valid range: >= 0 + * + * @retval 0 Transaction successful + * @retval -ENOMEM Input parameters invalid + * @retval -EINTR Interrupted while waiting + * @retval -ETIMEDOUT Timeout occurred + * @retval -ECONNRESET IVC channel was reset + * @retval negative Other error + */ static int camrtc_ivc_dbg_full_frame_xact( struct tegra_ivc_channel *ch, struct camrtc_dbg_request *req, @@ -327,6 +457,25 @@ unlock: return ret; } +/** + * @brief Performs a standard transaction with the camera-rtcpu debug interface + * + * This function is a wrapper around @ref camrtc_ivc_dbg_full_frame_xact that uses + * standard structure sizes for requests and responses. + * It performs the following operations: + * - Calls @ref camrtc_ivc_dbg_full_frame_xact with sizeof(*req) and sizeof(*resp) + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + * @param[in] req Pointer to the debug request structure + * Valid value: non-NULL + * @param[out] resp Pointer to the debug response structure + * Valid value: non-NULL + * @param[in] timeout Timeout in milliseconds, 0 for default + * Valid range: >= 0 + * + * @retval (int) Return value from @ref camrtc_ivc_dbg_full_frame_xact + */ static inline int camrtc_ivc_dbg_xact( struct tegra_ivc_channel *ch, struct camrtc_dbg_request *req, @@ -338,6 +487,26 @@ static inline int camrtc_ivc_dbg_xact( timeout); } +/** + * @brief Pings the camera-rtcpu and displays timing information + * + * This function sends a ping request to the camera-rtcpu and measures + * the round-trip time. It performs the following operations: + * - Gets current time using @ref sched_clock() + * - Prepares ping request with timestamp + * - Sends request using @ref camrtc_ivc_dbg_xact() + * - Calculates round-trip time and offset + * - Displays formatted timing information using @ref seq_printf() + * - Displays any response data + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Ping successful + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_show_ping(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -380,6 +549,26 @@ static int camrtc_show_ping(struct seq_file *file, void *data) DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_ping, camrtc_show_ping); +/** + * @brief Pings the camera-rtcpu using shared memory interface and displays timing information + * + * This function sends a ping request to the camera-rtcpu using the shared memory interface + * and measures the round-trip time. It performs the following operations: + * - Gets the camera-rtcpu device using @ref camrtc_get_device() + * - Acquires runtime reference using @ref tegra_ivc_channel_runtime_get() + * - Gets current time using @ref sched_clock() + * - Sends ping using @ref tegra_camrtc_ping() + * - Calculates and displays round-trip time using @ref seq_printf() + * - Releases runtime reference using @ref tegra_ivc_channel_runtime_put() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Ping successful + * @retval (int)) Error code from @ref tegra_ivc_channel_runtime_get() or @ref tegra_camrtc_ping() + */ static int camrtc_show_sm_ping(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -416,6 +605,25 @@ error: DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_sm_ping, camrtc_show_sm_ping); +/** + * @brief Gets the current log level of the camera-rtcpu + * + * This function retrieves the current log level setting from the camera-rtcpu. + * It performs the following operations: + * - Prepares a GET_LOGLEVEL request + * - Sends request using @ref camrtc_ivc_dbg_xact() + * - Verifies response status is OK + * - Sets the output parameter to the current log level + * + * @param[in] data Private data pointer (IVC channel) + * Valid value: non-NULL + * @param[out] val Pointer to store the retrieved log level + * Valid value: non-NULL + * + * @retval 0 Operation successful + * @retval -EPROTO Response status not OK + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_dbgfs_show_loglevel(void *data, u64 *val) { struct tegra_ivc_channel *ch = data; @@ -437,6 +645,26 @@ static int camrtc_dbgfs_show_loglevel(void *data, u64 *val) return 0; } +/** + * @brief Sets the log level of the camera-rtcpu + * + * This function sets a new log level for the camera-rtcpu. + * It performs the following operations: + * - Validates the input value can be represented as a u32 + * - Prepares a SET_LOGLEVEL request with the new level + * - Sends request using @ref camrtc_ivc_dbg_xact() + * - Handles different response status codes + * + * @param[in] data Private data pointer (IVC channel) + * Valid value: non-NULL + * @param[in] val New log level value + * Valid range: Can be represented as u32 + * + * @retval 0 Log level set successfully + * @retval -EINVAL Value out of range or invalid parameter + * @retval -EPROTO Unexpected response status + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_dbgfs_store_loglevel(void *data, u64 val) { struct tegra_ivc_channel *ch = data; @@ -468,6 +696,25 @@ DEFINE_SIMPLE_ATTRIBUTE(camrtc_dbgfs_fops_loglevel, camrtc_dbgfs_store_loglevel, "%lld\n"); +/** + * @brief Executes a MODS test on the camera-rtcpu and displays the result + * + * This function runs a MODS (Modular Operational Diagnostic Suite) test + * on the camera-rtcpu and shows the status code. + * It performs the following operations: + * - Retrieves test parameters from the debug structure + * - Prepares a MODS_TEST request with case, loops, and DMA channels + * - Sends request using @ref camrtc_ivc_dbg_xact() with adjusted timeout + * - Outputs status code to the sequence file using @ref seq_printf() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Test executed successfully + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_show_mods_result(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -493,6 +740,24 @@ static int camrtc_show_mods_result(struct seq_file *file, void *data) DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_mods_result, camrtc_show_mods_result); +/** + * @brief Retrieves and displays the FreeRTOS state from the camera-rtcpu + * + * This function retrieves the current state of the FreeRTOS running on the + * camera-rtcpu and displays it in the sequence file. + * It performs the following operations: + * - Prepares an RTOS_STATE request + * - Sends request using @ref camrtc_ivc_dbg_xact() + * - Outputs the RTOS state information to the sequence file using @ref seq_printf() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 State retrieved and displayed successfully + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_dbgfs_show_freertos_state(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -515,12 +780,46 @@ static int camrtc_dbgfs_show_freertos_state(struct seq_file *file, void *data) DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_freertos_state, camrtc_dbgfs_show_freertos_state); +/** + * @brief Converts a byte count to kilobytes, rounding up + * + * This function converts a byte count to kilobytes, rounding up to the + * nearest kilobyte. + * It performs the following operations: + * - Adds 1023 to the input value using @ref __builtin_uadd_overflow for + * safe arithmetic with overflow checking + * - Divides by 1024 to convert bytes to kilobytes with ceiling rounding + * + * @param[in] x Byte count to convert to kilobytes + * Valid range: Any uint32_t value + * + * @retval (uint32_t) The input value in kilobytes, rounded up + */ static inline uint32_t ToKilobytes(uint32_t x) { (void)__builtin_uadd_overflow(x, 1023U, &x); return (x / 1024U); } +/** + * @brief Retrieves and displays memory usage statistics from the camera-rtcpu + * + * This function retrieves memory usage information from the camera-rtcpu + * and formats it for display. It performs the following operations: + * - Prepares a GET_MEM_USAGE request + * - Sends request using @ref camrtc_ivc_dbg_xact() + * - Calculates total memory usage using @ref __builtin_uadd_overflow for safe arithmetic + * - Formats and displays memory usage statistics using @ref seq_printf() + * - Displays values in bytes and kilobytes using @ref ToKilobytes() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Statistics retrieved and displayed successfully + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact() + */ static int camrtc_dbgfs_show_memstat(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -555,6 +854,29 @@ static int camrtc_dbgfs_show_memstat(struct seq_file *file, void *data) DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_memstat, camrtc_dbgfs_show_memstat); +/** + * @brief Retrieves and displays interrupt statistics from the camera-rtcpu + * + * This function retrieves interrupt statistics from the camera-rtcpu + * and formats them for display. It performs the following operations: + * - Checks if IRQ statistics are supported in the build (CAMRTC_REQ_GET_IRQ_STAT) + * - Allocates memory for the response using @ref kzalloc() + * - Prepares a GET_IRQ_STAT request + * - Sends request using @ref camrtc_ivc_dbg_full_frame_xact() + * - Formats and displays IRQ statistics including count, runtime, and names using @ref seq_printf() + * - Tracks maximum runtime across all interrupts + * - Displays total statistics + * - Frees allocated memory using @ref kfree() + * + * @param[in] file Pointer to sequence file for output + * Valid value: non-NULL + * @param[in] data Private data pointer + * Valid value: any value + * + * @retval 0 Statistics retrieved and displayed successfully + * @retval -ENOMSG IRQ statistics not supported or enabled + * @retval (int) Error code from @ref camrtc_ivc_dbg_full_frame_xact() + */ static int camrtc_dbgfs_show_irqstat(struct seq_file *file, void *data) { int ret = -ENOMSG; @@ -599,6 +921,20 @@ done: DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_irqstat, camrtc_dbgfs_show_irqstat); +/** + * @brief Calculates the maximum size available for test data + * + * This function determines the maximum amount of data that can be included + * in a test request. It performs the following operations: + * - Uses @ref __builtin_uaddl_overflow to safely add the IVC frame size to the + * offset of the test data field in the request structure + * - Returns the calculated maximum size + * + * @param[in] ch Pointer to the IVC channel + * Valid value: non-NULL + * + * @retval (size_t) Maximum size in bytes that can be used for test data + */ static size_t camrtc_dbgfs_get_max_test_size( const struct tegra_ivc_channel *ch) { @@ -608,6 +944,26 @@ static size_t camrtc_dbgfs_get_max_test_size( return ret; } +/** + * @brief Reads test case data from the debugfs file + * + * This function implements the read file operation for test case data. + * It performs the following operations: + * - Retrieves the camera debug data for the IVC channel + * - Uses @ref simple_read_from_buffer to copy data from the test case buffer + * to user space + * + * @param[in] file Pointer to the file object + * Valid value: non-NULL + * @param[out] buf User space buffer to read into + * Valid value: non-NULL + * @param[in] count Number of bytes to read + * Valid range: >= 0 + * @param[in,out] f_pos Pointer to file position + * Valid value: non-NULL + * + * @retval (ssize_t) Number of bytes read on success, or negative error code + */ static ssize_t camrtc_dbgfs_read_test_case(struct file *file, char __user *buf, size_t count, loff_t *f_pos) { @@ -619,6 +975,28 @@ static ssize_t camrtc_dbgfs_read_test_case(struct file *file, crd->parameters.test_case_size); } +/** + * @brief Writes test case data to the debugfs file + * + * This function implements the write file operation for test case data. + * It performs the following operations: + * - Retrieves the camera debug data for the IVC channel + * - Validates the maximum size for the test case + * - Uses @ref simple_write_to_buffer to copy data from user space to the test case buffer + * - Updates the test case size with the current file position + * - Marks all input memory buffers as empty + * + * @param[in] file Pointer to the file object + * Valid value: non-NULL + * @param[in] buf User space buffer to write from + * Valid value: non-NULL + * @param[in] count Number of bytes to write + * Valid range: >= 0 + * @param[in,out] f_pos Pointer to file position + * Valid value: non-NULL + * + * @retval (ssize_t) Number of bytes written on success, or negative error code + */ static ssize_t camrtc_dbgfs_write_test_case(struct file *file, const char __user *buf, size_t count, loff_t *f_pos) { @@ -646,6 +1024,23 @@ static const struct file_operations camrtc_dbgfs_fops_test_case = { .write = camrtc_dbgfs_write_test_case, }; +/** + * @brief Gets the appropriate device for memory allocations + * + * This function determines the appropriate device to use for memory allocations. + * It performs the following operations: + * - Checks if the VI device is available (mem_devices[1]) + * - If VI is available, returns the VI device for consistent allocations + * - Otherwise, falls back to the primary memory device (mem_devices[0]) + * + * This selection is necessary because if VI misses stage-1 SMMU translation, + * allocations need to be contiguous. Using VI ensures compatibility across contexts. + * + * @param[in] crd Pointer to the camera debug structure + * Valid value: non-NULL + * + * @retval (struct device *) Pointer to the appropriate device for memory allocations + */ static struct device *camrtc_dbgfs_memory_dev( const struct camrtc_debug *crd) { @@ -660,6 +1055,25 @@ static struct device *camrtc_dbgfs_memory_dev( return crd->mem_devices[0]; } +/** + * @brief Reads test memory data from the debugfs file + * + * This function implements the read file operation for test memory data. + * It performs the following operations: + * - Retrieves the test memory structure for the specific memory region + * - Uses @ref simple_read_from_buffer to copy data from the memory buffer to user space + * + * @param[in] file Pointer to the file object + * Valid value: non-NULL + * @param[out] buf User space buffer to read into + * Valid value: non-NULL + * @param[in] count Number of bytes to read + * Valid range: >= 0 + * @param[in,out] f_pos Pointer to file position + * Valid value: non-NULL + * + * @retval (ssize_t) Number of bytes read on success, or negative error code + */ static ssize_t camrtc_dbgfs_read_test_mem(struct file *file, char __user *buf, size_t count, loff_t *f_pos) { @@ -668,6 +1082,31 @@ static ssize_t camrtc_dbgfs_read_test_mem(struct file *file, return simple_read_from_buffer(buf, count, f_pos, mem->ptr, mem->used); } +/** + * @brief Writes data to test memory through the debugfs file + * + * This function implements the write file operation for test memory. + * It performs the following operations: + * - Retrieves the test memory structure and camera debug container + * - Gets the appropriate memory device and IOMMU domain + * - Expands the memory buffer if needed, handling both reserved memory and normal allocation + * - For reserved memory, maps the physical address to IOVA using @ref dma_map_single() + * - For normal allocation, uses @ref dma_alloc_coherent() and copies existing content + * - Updates the physical address based on IOMMU state + * - Writes data to memory using @ref simple_write_to_buffer() + * - Updates usage information and handles cleanup on zero usage + * + * @param[in] file Pointer to the file object + * Valid value: non-NULL + * @param[in] buf User space buffer to write from + * Valid value: non-NULL + * @param[in] count Number of bytes to write + * Valid range: >= 0 + * @param[in,out] f_pos Pointer to file position + * Valid value: non-NULL + * + * @retval (ssize_t) Number of bytes written on success, or negative error code + */ static ssize_t camrtc_dbgfs_write_test_mem(struct file *file, const char __user *buf, size_t count, loff_t *f_pos) { @@ -750,6 +1189,15 @@ static ssize_t camrtc_dbgfs_write_test_mem(struct file *file, return ret; } +/** + * @brief File operations for test memory + * + * This structure defines the file operations for test memory in the debugfs + * interface, providing read and write access to the memory buffers used for + * testing the camera-rtcpu. + * - read: Implemented by @ref camrtc_dbgfs_read_test_mem + * - write: Implemented by @ref camrtc_dbgfs_write_test_mem + */ static const struct file_operations camrtc_dbgfs_fops_test_mem = { .read = camrtc_dbgfs_read_test_mem, .write = camrtc_dbgfs_write_test_mem, @@ -758,6 +1206,28 @@ static const struct file_operations camrtc_dbgfs_fops_test_mem = { #define BUILD_BUG_ON_MISMATCH(s1, f1, s2, f2) \ BUILD_BUG_ON(offsetof(s1, data.f1) != offsetof(s2, data.f2)) +/** + * @brief Runs a test and displays the result + * + * This function executes a test on the camera-rtcpu by sending the test case data + * via IVC channel and writes the test results to the sequence file. It performs + * the following operations: + * - Copies the test case data to the request buffer + * - Calculates the timeout in nanoseconds + * - Executes the transaction using @ref camrtc_ivc_dbg_full_frame_xact + * - Flushes the trace buffer using @ref tegra_camrtc_flush_trace + * - Displays the test result status and runtime + * - Writes the result text to the sequence file + * + * @param[in] file Pointer to the sequence file + * @param[in] req Pointer to the debug request structure + * @param[out] resp Pointer to the debug response structure + * @param[in] data_offset Offset in the request/response structure where data begins + * + * @retval 0 on success + * @retval (int) Return code from @ref camrtc_ivc_dbg_full_frame_xact() or + * @ref tegra_ivc_channel_runtime_get() + */ static int camrtc_test_run_and_show_result(struct seq_file *file, struct camrtc_dbg_request *req, struct camrtc_dbg_response *resp, @@ -832,6 +1302,22 @@ runtime_put: return ret; } +/** + * @brief Unmaps all or selected DMA mappings for a test memory buffer + * + * This function unmaps DMA mappings previously created for a test memory buffer + * across multiple devices. It performs the following operations: + * - Checks if the memory buffer is mapped (ptr is not NULL) + * - Iterates through all mapped devices in the memory structure + * - Unmaps the memory from each device using @ref dma_unmap_single + * - Optionally keeps the primary memory device mapping if 'all' is false + * + * @param[in] crd Pointer to the camera debug structure + * @param[in] mem Pointer to the test memory structure containing mappings + * @param[in] all Flag to indicate if all mappings should be unmapped + * - true: unmap all device mappings + * - false: keep the primary memory device mapping + */ static void camrtc_run_rmem_unmap_all(struct camrtc_debug *crd, struct camrtc_test_mem *mem, bool all) { @@ -858,8 +1344,40 @@ static void camrtc_run_rmem_unmap_all(struct camrtc_debug *crd, } } +/** + * @brief Maximum value for a signed integer + * + * This macro defines the maximum value that can be stored in a signed integer. + * It represents (2^31 - 1) for typical 32-bit systems. + */ #define INT_MAX ((int)(~0U >> 1)) +/** + * @brief Maps a memory buffer for DMA access from a specific device + * + * This function maps a memory buffer for DMA access from a given device, + * handling the mapping differently based on whether the target device is + * the same as the memory device or using reserved memory. It performs + * the following operations: + * - Validates that the device index hasn't exceeded maximum allowed devices + * - If mapping to the memory device, reuses the existing IOVA and syncs + * - For reserved memory, creates a new DMA mapping with @ref dma_map_single + * - For non-reserved memory, creates a scatter-gather table and maps it + * - Records the device and IOVA in the memory structure + * + * @param[in] ch Pointer to the IVC channel + * @param[in] mem_dev Pointer to the primary memory device + * @param[in] dev Pointer to the target device for mapping + * @param[in] sgt Pointer to the scatter-gather table + * @param[in,out] mem Pointer to the test memory structure + * @param[out] return_iova Pointer to store the resulting IOVA address + * + * @retval 0 on success + * @retval (int) Error code from @ref dma_get_sgtable + * @retval -ENOMEM if device list exhausted or failed to allocate memory with @ref dma_map_single() + * @retval -ENXIO if failed to map memory + * @retval -EINVAL if sync operation failed + */ static int camrtc_run_mem_map(struct tegra_ivc_channel *ch, struct device *mem_dev, struct device *dev, @@ -926,6 +1444,18 @@ done: return ret; } +/** + * @brief Sets the memory bandwidth for camera operation + * + * This function configures the memory bandwidth through the interconnect + * controller path for camera operations. It performs the following operations: + * - Checks if an interconnect path is available + * - Sets the bandwidth using @ref icc_set_bw with the provided value + * - Logs success or failure of the bandwidth setting operation + * + * @param[in] crd Pointer to the camera debug structure + * @param[in] bw Bandwidth value to set in bytes per second + */ static void camrtc_membw_set(struct camrtc_debug *crd, u32 bw) { int ret; @@ -940,6 +1470,27 @@ static void camrtc_membw_set(struct camrtc_debug *crd, u32 bw) } } +/** + * @brief Runs a memory test on the camera-rtcpu + * + * This function executes a memory test by setting up memory mappings across + * multiple devices (RCE, VI, ISP, VI2, ISP1), sending test data to the camera-rtcpu, + * and processing the results. It performs the following operations: + * - Sets the memory bandwidth using @ref camrtc_membw_set + * - Allocates scratch memory if not already allocated + * - Maps memory across multiple camera devices using @ref camrtc_run_mem_map + * - Runs the test and displays results using @ref camrtc_test_run_and_show_result + * - Synchronizes memory for CPU access + * - Cleans up by unmapping memory and resetting mapping information + * + * @param[in] file Pointer to the sequence file + * @param[in,out] req Pointer to the debug request structure + * @param[out] resp Pointer to the debug response structure + * + * @retval 0 on success + * @retval (int) Error code from @ref camrtc_ivc_dbg_full_frame_xact() + * @retval -ENOMEM if failed to map memory with @ref dma_map_single() or @ref dma_alloc_coherent() + */ static int camrtc_run_mem_test(struct seq_file *file, struct camrtc_dbg_request *req, struct camrtc_dbg_response *resp) @@ -1157,6 +1708,20 @@ unmap: return ret; } +/** + * @brief Show function for test result debugfs file + * + * This function is called when the test result debugfs file is read. + * It allocates memory for request and response structures, runs the + * memory test using @ref camrtc_run_mem_test, and displays the results. + * + * @param[in] file Pointer to the sequence file + * @param[in] data Private data pointer (unused) + * + * @retval 0 on success + * @retval (int) Error code from @ref camrtc_run_mem_test + * @retval -ENOMEM if failed to allocate memory with @ref kzalloc() + */ static int camrtc_dbgfs_show_test_result(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -1180,8 +1745,33 @@ static int camrtc_dbgfs_show_test_result(struct seq_file *file, void *data) return ret; } +/** + * @brief File operations for test result + * + * This macro defines the file operations for the test result debugfs file. + * It specifies that @ref camrtc_dbgfs_show_test_result should be called + * when the file is read. + */ DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_test_result, camrtc_dbgfs_show_test_result); +/** + * @brief Show function for test list debugfs file + * + * This function is called when the test list debugfs file is read. + * It sends a request to the camera-rtcpu to retrieve the list of available + * tests and displays the results in the sequence file. It performs the + * following operations: + * - Prepares a request to run the "list" test + * - Executes the transaction using @ref camrtc_ivc_dbg_full_frame_xact + * - Formats and writes the test list to the sequence file + * + * @param[in] file Pointer to the sequence file + * @param[in] data Private data pointer (unused) + * + * @retval 0 on success + * @retval (int) Error code from @ref camrtc_ivc_dbg_full_frame_xact() + * @retval -ENOMEM if failed to allocate memory with @ref kzalloc() + */ static int camrtc_dbgfs_show_test_list(struct seq_file *file, void *data) { struct tegra_ivc_channel *ch = file->private; @@ -1225,8 +1815,34 @@ static int camrtc_dbgfs_show_test_list(struct seq_file *file, void *data) return ret; } +/** + * @brief File operations for test list + * + * This macro defines the file operations for the test list debugfs file. + * It specifies that @ref camrtc_dbgfs_show_test_list should be called + * when the file is read. + */ DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_test_list, camrtc_dbgfs_show_test_list); +/** + * @brief Sends a coverage control message to the camera-rtcpu + * + * This function sends a message to control the Falcon coverage functionality. + * It performs the following operations: + * - Prepares a request with coverage control parameters + * - Executes the transaction using @ref camrtc_ivc_dbg_xact + * - Handles error cases and status checking + * + * @param[in] cov Pointer to the Falcon coverage structure + * @param[out] resp Pointer to the debug response structure + * @param[in] flush Flag to indicate if coverage data should be flushed + * @param[in] reset Flag to indicate if coverage data should be reset + * + * @retval 0 on success + * @retval (int) Error code from @ref camrtc_ivc_dbg_xact + * @retval -ENODEV if IVC error or bad status + * @retval -EOVERFLOW if coverage buffer is full + */ static int camrtc_coverage_msg(struct camrtc_falcon_coverage *cov, struct camrtc_dbg_response *resp, bool flush, bool reset) @@ -1259,6 +1875,17 @@ static int camrtc_coverage_msg(struct camrtc_falcon_coverage *cov, return ret; } +/** + * @brief Checks if Falcon coverage is supported + * + * This function determines whether the Falcon coverage functionality is + * supported by sending a test message to the camera-rtcpu. + * + * @param[in] cov Pointer to the Falcon coverage structure + * + * @retval true if coverage is supported + * @retval false otherwise + */ static bool camrtc_coverage_is_supported(struct camrtc_falcon_coverage *cov) { struct camrtc_dbg_response resp; @@ -1268,6 +1895,26 @@ static bool camrtc_coverage_is_supported(struct camrtc_falcon_coverage *cov) return (resp.status == CAMRTC_STATUS_OK); } +/** + * @brief Read callback for Falcon coverage debugfs file + * + * This function is called when the Falcon coverage debugfs file is read. + * It retrieves coverage data from the Falcon processor and copies it to + * user space. It performs the following operations: + * - Checks if coverage is enabled + * - Flushes coverage data from the Falcon if at the beginning of the file + * - Synchronizes memory for CPU access + * - Copies data to user space using @ref simple_read_from_buffer + * + * @param[in] file Pointer to the file structure + * @param[out] buf User space buffer + * @param[in] count Number of bytes to read + * @param[in,out] f_pos File position pointer + * + * @retval (ssize_t) Number of bytes read on success + * @retval (int) Error code from @ref simple_read_from_buffer or @ref camrtc_coverage_msg + * @retval -ENODEV if coverage is not enabled + */ static ssize_t camrtc_read_falcon_coverage(struct file *file, char __user *buf, size_t count, loff_t *f_pos) { @@ -1300,6 +1947,23 @@ done: return ret; } +/** + * @brief Write callback for Falcon coverage debugfs file + * + * This function is called when the Falcon coverage debugfs file is written. + * Writing to this file resets the coverage data. It performs the following operations: + * - Checks if coverage is enabled + * - Clears the coverage memory buffer + * - Sends a reset message to the Falcon using @ref camrtc_coverage_msg + * + * @param[in] file Pointer to the file structure + * @param[in] buf User space buffer (content ignored) + * @param[in] count Number of bytes written + * @param[in,out] f_pos File position pointer + * + * @retval (ssize_t) Number of bytes written on success + * @retval -ENODEV if coverage is not enabled + */ static ssize_t camrtc_write_falcon_coverage(struct file *file, const char __user *buf, size_t count, loff_t *f_pos) { @@ -1319,11 +1983,36 @@ static ssize_t camrtc_write_falcon_coverage(struct file *file, return ret; } + +/** + * @brief File operations for Falcon coverage + * + * This structure defines the file operations for the Falcon coverage debugfs file. + * - read: Implemented by @ref camrtc_read_falcon_coverage + * - write: Implemented by @ref camrtc_write_falcon_coverage + */ static const struct file_operations camrtc_dbgfs_fops_falcon_coverage = { .read = camrtc_read_falcon_coverage, .write = camrtc_write_falcon_coverage, }; +/** + * @brief Enables Falcon coverage functionality + * + * This function enables the coverage functionality for a Falcon processor. + * It performs the following operations: + * - Checks if coverage is already enabled + * - Verifies coverage is supported using @ref camrtc_coverage_is_supported + * - Allocates memory for coverage data using @ref dma_alloc_coherent + * - Maps the memory to the Falcon processor using @ref camrtc_run_mem_map + * - Acquires runtime PM reference to keep rtcpu alive + * + * @param[in,out] cov Pointer to the Falcon coverage structure + * + * @retval 0 on success + * @retval (int) Error code from @ref tegra_ivc_channel_runtime_get() + * @retval -ENODEV if coverage is not supported + */ static int camrtc_falcon_coverage_enable(struct camrtc_falcon_coverage *cov) { struct tegra_ivc_channel *ch = cov->ch; @@ -1387,6 +2076,19 @@ error: return ret; } +/** + * @brief Disables Falcon coverage functionality + * + * This function disables the coverage functionality for a Falcon processor + * and releases associated resources. It performs the following operations: + * - Checks if coverage is already disabled + * - Disables coverage by sending a control message to the Falcon + * - Unmaps DMA memory from the Falcon processor + * - Frees the coverage memory using @ref dma_free_coherent + * - Releases the runtime PM reference + * + * @param[in,out] cov Pointer to the Falcon coverage structure + */ static void camrtc_falcon_coverage_disable(struct camrtc_falcon_coverage *cov) { struct tegra_ivc_channel *ch = cov->ch; @@ -1416,6 +2118,17 @@ static void camrtc_falcon_coverage_disable(struct camrtc_falcon_coverage *cov) tegra_ivc_channel_runtime_put(ch); } +/** + * @brief Show callback for coverage enable debugfs file + * + * This function is called when the coverage enable debugfs file is read. + * It returns the current enabled state of the Falcon coverage. + * + * @param[in] data Private data pointer (Falcon coverage structure) + * @param[out] val Pointer to store the enabled state (1 = enabled, 0 = disabled) + * + * @retval 0 on success + */ static int camrtc_dbgfs_show_coverage_enable(void *data, u64 *val) { struct camrtc_falcon_coverage *cov = data; @@ -1425,6 +2138,18 @@ static int camrtc_dbgfs_show_coverage_enable(void *data, u64 *val) return 0; } +/** + * @brief Store callback for coverage enable debugfs file + * + * This function is called when the coverage enable debugfs file is written. + * It enables or disables the Falcon coverage based on the written value. + * + * @param[in] data Private data pointer (Falcon coverage structure) + * @param[in] val Value to set (non-zero = enable, zero = disable) + * + * @retval 0 on success + * @retval (int) Error code from @ref camrtc_falcon_coverage_enable + */ static int camrtc_dbgfs_store_coverage_enable(void *data, u64 val) { struct camrtc_falcon_coverage *cov = data; @@ -1489,6 +2214,21 @@ struct tegra_ast_region_info { u32 control; }; +/** + * @brief Gets AST region configuration information + * + * This function reads the configuration of an AST region from hardware + * registers and populates a region information structure. It performs + * the following operations: + * - Reads control register and extracts flags + * - Reads stream ID configuration + * - Reads slave, mask, and master address values + * - Formats the information into the provided structure + * + * @param[in] base Base address of the AST registers + * @param[in] region Region number to retrieve + * @param[out] info Pointer to store the region information + */ static void tegra_ast_get_region_info(void __iomem *base, u32 region, struct tegra_ast_region_info *info) @@ -1542,6 +2282,20 @@ static void tegra_ast_get_region_info(void __iomem *base, info->master = ((hi << 32U) + lo) & AST_ADDR_MASK64; } +/** + * @brief Maps I/O memory by name from device tree + * + * This function maps I/O memory based on a register name from the device tree. + * It performs the following operations: + * - Looks up the register index by name in the device tree + * - Maps the I/O memory using @ref of_iomap if found + * + * @param[in] dev Pointer to the device structure + * @param[in] name Name of the register to map + * + * @retval (void __iomem *) Mapped I/O memory address on success + * @retval (void __iomem *) Error pointer on failure + */ static void __iomem *iomap_byname(struct device *dev, const char *name) { int index = of_property_match_string(dev->of_node, "reg-names", name); @@ -1551,6 +2305,26 @@ static void __iomem *iomap_byname(struct device *dev, const char *name) return of_iomap(dev->of_node, index); } +/** + * @brief Show function for AST region debugfs file + * + * This function displays information about an AST (Address Space Translator) region + * in a sequence file. It performs the following operations: + * - Gets the region configuration using @ref tegra_ast_get_region_info + * - Displays whether the region is enabled or disabled + * - If enabled, displays details about the region's configuration: + * - Slave and master addresses + * - Region size + * - Security flags (lock, snoop, non-secure, etc.) + * - Carveout settings + * - VPR settings + * - VM index and physical mode + * - Stream ID information + * + * @param[in] file Pointer to the sequence file for output + * @param[in] base Base address of the AST registers + * @param[in] index AST region index to display + */ static void camrtc_dbgfs_show_ast_region(struct seq_file *file, void __iomem *base, u32 index) { @@ -1582,12 +2356,37 @@ static void camrtc_dbgfs_show_ast_region(struct seq_file *file, info.stream_id, info.stream_id_enabled); } +/** + * @brief Structure to hold information about an AST node in debugfs + * + * This structure represents an AST (Address Space Translator) node + * in the debugfs interface, containing references to the IVC channel, + * name of the AST, and a bitmask of regions to display. + */ struct camrtc_dbgfs_ast_node { - struct tegra_ivc_channel *ch; - const char *name; - uint8_t mask; + struct tegra_ivc_channel *ch; /**< IVC channel for the AST */ + const char *name; /**< Name of the AST */ + uint8_t mask; /**< Bitmask of regions to display */ }; +/** + * @brief Show function for AST debugfs file + * + * This function is called when an AST debugfs file is read. + * It displays information about the specified AST regions. + * It performs the following operations: + * - Gets the AST node from the private data + * - Maps the AST registers using @ref iomap_byname + * - Iterates through the regions specified in the mask + * - Displays each region using @ref camrtc_dbgfs_show_ast_region + * - Unmaps the registers with @ref iounmap + * + * @param[in] file Pointer to the sequence file + * @param[in] data Private data pointer (unused) + * + * @retval 0 on success + * @retval -ENOMEM if @ref iomap_byname fails + */ static int camrtc_dbgfs_show_ast(struct seq_file *file, void *data) { @@ -1613,8 +2412,21 @@ static int camrtc_dbgfs_show_ast(struct seq_file *file, return 0; } +/** + * @brief File operations for AST + * + * This macro defines the file operations for the AST debugfs file. + * It specifies that @ref camrtc_dbgfs_show_ast should be called + * when the file is read. + */ DEFINE_SEQ_FOPS(camrtc_dbgfs_fops_ast, camrtc_dbgfs_show_ast); +/** + * @brief Common AST register definitions + * + * This array defines the common registers in the AST (Address Space Translator) + * that are displayed in the debugfs interface. + */ static const struct debugfs_reg32 ast_common_regs[] = { { .name = "control", 0x0 }, { .name = "error_status", 0x4 }, @@ -1640,6 +2452,12 @@ static const struct debugfs_reg32 ast_common_regs[] = { { .name = "read_block_status", 0x64 }, }; +/** + * @brief AST region register definitions + * + * This array defines the registers for each AST region that are + * displayed in the debugfs interface. + */ static const struct debugfs_reg32 ast_region_regs[] = { { .name = "slave_lo", 0x100 }, { .name = "slave_hi", 0x104 }, @@ -1650,6 +2468,23 @@ static const struct debugfs_reg32 ast_region_regs[] = { { .name = "control", 0x118 }, }; +/** + * @brief Creates debugfs files for AST registers + * + * This function creates debugfs files to display AST registers. + * It performs the following operations: + * - Maps the AST registers using @ref iomap_byname + * - Sets up the common registers debugfs file + * - Creates a debugfs file for each region's registers + * + * @param[in] ch Pointer to the IVC channel + * @param[in] dir Parent debugfs directory + * @param[in] ars Pointer to the AST regset structure + * @param[in] ast_name Name of the AST + * + * @retval 0 on success + * @retval -ENOMEM if @ref iomap_byname fails + */ static int ast_regset_create_files(struct tegra_ivc_channel *ch, struct dentry *dir, struct ast_regset *ars, @@ -1683,6 +2518,23 @@ static int ast_regset_create_files(struct tegra_ivc_channel *ch, return 0; } +/** + * @brief Populates the debugfs directory with camera RTCPU debug files + * + * This function creates the debugfs directory structure and files for + * camera RTCPU debugging. It performs the following operations: + * - Creates the main debugfs directory with name from device tree or default "camrtc" + * - Creates coverage directories for VI and ISP + * - Creates files for falcon coverage data and enable controls + * - Creates files for version, reboot, ping, SM-ping, log-level, etc. + * - Sets up timeout, test case, and test memory debugfs files + * - Creates AST debugfs files if AST is available + * + * @param[in] ch Pointer to the IVC channel + * + * @retval 0 on success + * @retval -ENOMEM if @ref debugfs_create_dir fails + */ static int camrtc_debug_populate(struct tegra_ivc_channel *ch) { struct camrtc_debug *crd = tegra_ivc_channel_get_drvdata(ch); @@ -1854,6 +2706,23 @@ error: return -ENOMEM; } +/** + * @brief Gets a linked device from device tree + * + * This function retrieves a device linked through a phandle in the device tree. + * It performs the following operations: + * - Gets the device node using @ref of_parse_phandle + * - Checks if the node exists + * - Finds the platform device using @ref of_find_device_by_node + * - Returns the device pointer or NULL if not found + * + * @param[in] dev Pointer to the parent device + * @param[in] name Name of the phandle property + * @param[in] index Index in the phandle array + * + * @retval (struct device *) Pointer to the linked device on success + * @retval NULL if not found + */ static struct device *camrtc_get_linked_device( struct device *dev, char const *name, int index) { @@ -1875,6 +2744,28 @@ static struct device *camrtc_get_linked_device( return &pdev->dev; } +/** + * @brief Probe function for camera RTCPU debug driver + * + * This function initializes the camera RTCPU debug driver. + * It performs the following operations: + * - Validates IVC frame sizes using @ref BUG_ON + * - Allocates memory for the debug structure using @ref devm_kzalloc + * - Initializes parameters with default values + * - Reads configuration from device tree + * - Initializes mutex and wait queue + * - Sets up memory devices using @ref camrtc_get_linked_device + * - Configures falcon coverage structures + * - Gets the interconnect path for bandwidth control using @ref devm_of_icc_get + * - Populates the debugfs interface using @ref camrtc_debug_populate + * + * @param[in] ch Pointer to the IVC channel + * + * @retval 0 on success + * @retval -ENOMEM if @ref devm_kzalloc fails + * @retval -ENOMEM if @ref camrtc_debug_populate fails + * @retval (int) Error code from @ref dev_err_probe() + */ static int camrtc_debug_probe(struct tegra_ivc_channel *ch) { struct device *dev = &ch->dev; @@ -1947,6 +2838,18 @@ static int camrtc_debug_probe(struct tegra_ivc_channel *ch) return 0; } +/** + * @brief Remove function for camera RTCPU debug driver + * + * This function cleans up resources when the camera RTCPU debug driver is removed. + * It performs the following operations: + * - Disables falcon coverage using @ref camrtc_falcon_coverage_disable + * - Frees all allocated test memory using @ref dma_free_coherent + * - Releases references to memory devices using @ref put_device + * - Removes all debugfs entries using @ref debugfs_remove_recursive + * + * @param[in] ch Pointer to the IVC channel + */ static void camrtc_debug_remove(struct tegra_ivc_channel *ch) { struct camrtc_debug *crd = tegra_ivc_channel_get_drvdata(ch); @@ -1974,18 +2877,37 @@ static void camrtc_debug_remove(struct tegra_ivc_channel *ch) debugfs_remove_recursive(crd->root); } +/** + * @brief IVC channel operations for camera RTCPU debug driver + * + * This structure defines the operations for the camera RTCPU debug driver. + * - probe: @ref camrtc_debug_probe - Called when the driver is probed + * - remove: @ref camrtc_debug_remove - Called when the driver is removed + * - notify: @ref camrtc_debug_notify - Called when IVC notification is received + */ static const struct tegra_ivc_channel_ops tegra_ivc_channel_debug_ops = { .probe = camrtc_debug_probe, .remove = camrtc_debug_remove, .notify = camrtc_debug_notify, }; +/** + * @brief Device tree compatible strings for camera RTCPU debug driver + * + * This array defines the compatible strings that match this driver. + */ static const struct of_device_id camrtc_debug_of_match[] = { { .compatible = "nvidia,tegra186-camera-ivc-protocol-debug" }, { }, }; MODULE_DEVICE_TABLE(of, camrtc_debug_of_match); +/** + * @brief IVC driver structure for camera RTCPU debug driver + * + * This structure defines the IVC driver for camera RTCPU debugging. + * It includes basic driver information, device type, and operations. + */ static struct tegra_ivc_driver camrtc_debug_driver = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/platform/tegra/rtcpu/rtcpu-monitor.c b/drivers/platform/tegra/rtcpu/rtcpu-monitor.c index 151e0b97..d1952719 100644 --- a/drivers/platform/tegra/rtcpu/rtcpu-monitor.c +++ b/drivers/platform/tegra/rtcpu/rtcpu-monitor.c @@ -17,6 +17,18 @@ struct tegra_camrtc_mon { struct work_struct wdt_work; }; +/** + * @brief Restores the camera RTCPU by rebooting it + * + * This function reboots the camera RTCPU which broadcasts rtcpu-down and rtcpu-up + * events to all IVC channels. It performs the following operations: + * - Calls @ref tegra_camrtc_reboot to reboot the camera RTCPU + * + * @param[in] cam_rtcpu_mon Pointer to the camera RTCPU monitor + * Valid value: non-NULL + * + * @retval (int) return value from @ref tegra_camrtc_reboot + */ int tegra_camrtc_mon_restore_rtcpu(struct tegra_camrtc_mon *cam_rtcpu_mon) { /* (Re)boot the rtcpu */ @@ -25,6 +37,18 @@ int tegra_camrtc_mon_restore_rtcpu(struct tegra_camrtc_mon *cam_rtcpu_mon) } EXPORT_SYMBOL(tegra_camrtc_mon_restore_rtcpu); +/** + * @brief Handles camera RTCPU watchdog timeout work + * + * This function is called when the camera RTCPU watchdog timer expires. + * It performs the following operations: + * - Logs a warning message using @ref dev_info + * - Restores the camera RTCPU using @ref tegra_camrtc_mon_restore_rtcpu + * - Re-enables the watchdog IRQ using @ref enable_irq + * + * @param[in] work Pointer to the work structure + * Valid value: non-NULL + */ static void tegra_camrtc_mon_wdt_worker(struct work_struct *work) { struct tegra_camrtc_mon *cam_rtcpu_mon = container_of(work, @@ -39,6 +63,21 @@ static void tegra_camrtc_mon_wdt_worker(struct work_struct *work) enable_irq(cam_rtcpu_mon->wdt_irq); } +/** + * @brief ISR for camera RTCPU watchdog timer + * + * This function is the interrupt service routine called when the camera RTCPU + * watchdog timer expires. It performs the following operations: + * - Disables the IRQ using @ref disable_irq_nosync to prevent further interrupts + * - Schedules the watchdog worker using @ref schedule_work to handle the timeout + * + * @param[in] irq Interrupt number + * Valid value: any positive integer + * @param[in] data Pointer to driver data (tegra_camrtc_mon) + * Valid value: non-NULL + * + * @retval IRQ_HANDLED to indicate the interrupt was handled + */ static irqreturn_t tegra_camrtc_mon_wdt_remote_isr(int irq, void *data) { struct tegra_camrtc_mon *cam_rtcpu_mon = data; @@ -50,6 +89,23 @@ static irqreturn_t tegra_camrtc_mon_wdt_remote_isr(int irq, void *data) return IRQ_HANDLED; } +/** + * @brief Sets up the camera RTCPU watchdog timer IRQ + * + * This function sets up the interrupt request handler for the camera RTCPU + * watchdog timer. It performs the following operations: + * - Gets the platform device pointer using @ref to_platform_device + * - Gets the IRQ number using @ref platform_get_irq_byname + * - Registers the threaded IRQ handler using @ref devm_request_threaded_irq + * - Logs information about the IRQ + * + * @param[in,out] cam_rtcpu_mon Pointer to the camera RTCPU monitor structure + * Valid value: non-NULL + * + * @retval 0 On successful setup + * @retval -ENODEV If the IRQ is not found + * @retval (int) Error code from @ref devm_request_threaded_irq + */ static int tegra_camrtc_mon_wdt_irq_setup( struct tegra_camrtc_mon *cam_rtcpu_mon) { @@ -75,6 +131,22 @@ static int tegra_camrtc_mon_wdt_irq_setup( return 0; } +/** + * @brief Creates and initializes a camera RTCPU monitor + * + * This function creates and initializes a camera RTCPU monitor structure. + * It performs the following operations: + * - Allocates memory for the monitor structure using @ref devm_kzalloc + * - Initializes the RCE device pointer + * - Initializes the watchdog work using @ref INIT_WORK + * - Sets up the watchdog IRQ using @ref tegra_camrtc_mon_wdt_irq_setup + * + * @param[in] dev Pointer to the device structure + * Valid value: non-NULL + * + * @retval (struct tegra_camrtc_mon *) Pointer to the created camera RTCPU monitor on success + * @retval (ERR_PTR(-ENOMEM)) on failure + */ struct tegra_camrtc_mon *tegra_camrtc_mon_create(struct device *dev) { struct tegra_camrtc_mon *cam_rtcpu_mon; @@ -96,6 +168,20 @@ struct tegra_camrtc_mon *tegra_camrtc_mon_create(struct device *dev) } EXPORT_SYMBOL(tegra_camrtc_mon_create); +/** + * @brief Destroys a camera RTCPU monitor + * + * This function destroys a previously created camera RTCPU monitor structure. + * It performs the following operations: + * - Validates the input pointer using @ref IS_ERR_OR_NULL + * - Frees the allocated memory using @ref devm_kfree + * + * @param[in] cam_rtcpu_mon Pointer to the camera RTCPU monitor structure + * Valid value: any value including NULL or error pointer + * + * @retval 0 When successfully destroyed or input is NULL + * @retval -EINVAL If the input is an error pointer + */ int tegra_cam_rtcpu_mon_destroy(struct tegra_camrtc_mon *cam_rtcpu_mon) { if (IS_ERR_OR_NULL(cam_rtcpu_mon)) diff --git a/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c b/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c index 2c1a4876..1943da5b 100644 --- a/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c +++ b/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c @@ -214,6 +214,21 @@ static struct attribute_group attr_group = { static struct kobject *kobj; +/** + * @brief Initialize operating point sysfs entries + * + * This function creates sysfs entries for controlling the operating point. + * - Initializes the operating_point variable to 0 using assignment + * - Creates a kobject under kernel_kobj named "operating_point" using @ref kobject_create_and_add() + * - Checks if the kobject creation was successful + * - Returns -ENOMEM if kobject creation fails + * - Creates a sysfs attribute group using @ref sysfs_create_group() + * - Cleans up the kobject if attribute group creation fails using @ref kobject_put() + * - Returns the result (success or error) of the operations + * + * @retval -ENOMEM If kobject creation fails + * @retval (int) Value returned by @ref sysfs_create_group() + */ static int init_operating_point_sysfs(void) { int ret; @@ -229,11 +244,33 @@ static int init_operating_point_sysfs(void) return ret; } +/** + * @brief Clean up operating point sysfs entries + * + * This function removes the sysfs entries for controlling the operating point. + * - Releases the kobject created by @ref init_operating_point_sysfs() using @ref kobject_put() + */ static void deinit_operating_point_sysfs(void) { kobject_put(kobj); } +/** + * @brief Map a device resource to an ioremap + * + * This function maps a device resource to an ioremap + * - Retrieves the resource from the device tree using @ref of_address_to_resource() + * - Returns an error pointer if the resource retrieval fails + * - Maps the resource using @ref devm_ioremap_resource() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] index Index of the resource to map + * Valid value: [INT_MIN, INT_MAX] + * + * @retval (void *) Return value from @ref devm_ioremap_resource() + * @retval IOMEM_ERR_PTR(int) If the resource retrieval fails + */ static void __iomem *tegra_cam_ioremap(struct device *dev, int index) { struct resource mem; @@ -245,6 +282,22 @@ static void __iomem *tegra_cam_ioremap(struct device *dev, int index) return devm_ioremap_resource(dev, &mem); } +/** + * @brief Map a device resource by name + * + * This function maps a device resource by name + * - Retrieves the index of the resource from the device tree using @ref of_property_match_string() + * - Returns an error pointer if the resource retrieval fails + * - Maps the resource using @ref tegra_cam_ioremap() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] name Name of the resource to map + * Valid value: non-NULL + * + * @retval (void *) Return value from @ref tegra_cam_ioremap() + * @retval IOMEM_ERR_PTR(-ENOENT) If the resource retrieval fails + */ static void __iomem *tegra_cam_ioremap_byname(struct device *dev, const char *name) { @@ -254,6 +307,26 @@ static void __iomem *tegra_cam_ioremap_byname(struct device *dev, return tegra_cam_ioremap(dev, index); } +/** + * @brief Get resources for the camera RTCPU + * + * This function gets the resources for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the platform data for the device using @ref rtcpu->pdata + * - Retrieves the clocks for the device using @ref camrtc_clk_group_get() + * - Retrieves the device group for the device using @ref camrtc_device_group_get() + * - Retrieves the reset group for the device using @ref camrtc_reset_group_get() + * - Retrieves the registers for the device using @ref tegra_cam_ioremap_byname() + * - Returns an error if the resource retrieval fails + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval 0 On successful resource retrieval + * @retval PTR_ERR(err) If error from @ref camrtc_reset_group_get() or + * @ref camrtc_device_group_get() + * @retval -EPROBE_DEFER If the resource retrieval fails + */ static int tegra_camrtc_get_resources(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -328,6 +401,18 @@ static int tegra_camrtc_get_resources(struct device *dev) return 0; } +/** + * @brief Enable the clocks for the camera RTCPU + * + * This function enables the clocks for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the clocks for the device using @ref camrtc_clk_group_enable() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_clk_group_enable() + */ static int tegra_camrtc_enable_clks(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -335,6 +420,18 @@ static int tegra_camrtc_enable_clks(struct device *dev) return camrtc_clk_group_enable(rtcpu->clocks); } +/** + * @brief Disable the clocks for the camera RTCPU + * + * This function disables the clocks for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the clocks for the device using @ref camrtc_clk_group_disable() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_clk_group_disable() + */ static void tegra_camrtc_disable_clks(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -342,6 +439,17 @@ static void tegra_camrtc_disable_clks(struct device *dev) return camrtc_clk_group_disable(rtcpu->clocks); } +/** + * @brief Assert the resets for the camera RTCPU + * + * This function asserts the resets for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the platform data for the device using @ref rtcpu->pdata + * - Calls the platform data's assert_resets function + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_assert_resets(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -350,6 +458,19 @@ static void tegra_camrtc_assert_resets(struct device *dev) rtcpu->pdata->assert_resets(dev); } +/** + * @brief Deassert the resets for the camera RTCPU + * + * This function deasserts the resets for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the platform data for the device using @ref rtcpu->pdata + * - Calls the platform data's @ref deassert_resets function + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_reset_group_deassert() + */ static int tegra_camrtc_deassert_resets(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -367,6 +488,22 @@ static int tegra_camrtc_deassert_resets(struct device *dev) #define CAMRTC_MAX_BW (0xFFFFFFFFU) #define RCE_MAX_BW_MBPS (160) +/** + * @brief Initialize the ICC for the camera RTCPU + * + * This function initializes the ICC for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - If the bandwidth is CAMRTC_MAX_BW, sets the memory bandwidth to RCE_MAX_BW_MBPS using + * @ref MBps_to_icc() + * - Otherwise, sets the memory bandwidth to the provided bandwidth + * - Retrieves the ICC path for the device using @ref devm_of_icc_get() + * - Sets the icc path to NULL if the retrieval fails + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] bw Memory bandwidth to set + * Valid value: [0, CAMRTC_MAX_BW] + */ static void tegra_camrtc_init_icc(struct device *dev, u32 bw) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -387,11 +524,33 @@ static void tegra_camrtc_init_icc(struct device *dev, u32 bw) dev_dbg(dev, "using icc rate %u for power-on\n", rtcpu->mem_bw); } +/** + * @brief Initialize the memory bandwidth for the camera RTCPU + * + * This function initializes the memory bandwidth for the camera RTCPU + * - Calls @ref tegra_camrtc_init_icc() with CAMRTC_MAX_BW + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_init_membw(struct device *dev) { tegra_camrtc_init_icc(dev, CAMRTC_MAX_BW); } +/** + * @brief Set the full memory bandwidth for the camera RTCPU + * + * This function sets the full memory bandwidth for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the ICC path for the device using @ref rtcpu->icc_path + * - If the ICC path is not NULL, sets the memory bandwidth to the provided bandwidth using + * @ref icc_set_bw() + * - Returns an error if the memory bandwidth setting fails + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_full_mem_bw(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -406,6 +565,17 @@ static void tegra_camrtc_full_mem_bw(struct device *dev) } } +/** + * @brief Set the slow memory bandwidth for the camera RTCPU + * + * This function sets the slow memory bandwidth for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the ICC path for the device using @ref rtcpu->icc_path + * - If the ICC path is not NULL, sets the memory bandwidth to 0 using @ref icc_set_bw() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_slow_mem_bw(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -414,6 +584,21 @@ static void tegra_camrtc_slow_mem_bw(struct device *dev) (void)icc_set_bw(rtcpu->icc_path, 0, 0); } +/** + * @brief Set the fwloaddone flag for the camera RTCPU + * + * This function sets the fwloaddone flag for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the PM base for the device using @ref rtcpu->pm_base + * - Reads the PM R5 control register using @ref readl() + * - If the fwloaddone flag is true, sets the TEGRA_PM_FWLOADDONE bit using @ref writel() + * - Otherwise, clears the TEGRA_PM_FWLOADDONE bit using @ref writel() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] fwloaddone FWLOADDONE flag to set + * Valid value: true or false + */ static void tegra_camrtc_set_fwloaddone(struct device *dev, bool fwloaddone) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -430,6 +615,24 @@ static void tegra_camrtc_set_fwloaddone(struct device *dev, bool fwloaddone) } } +/** + * @brief Wait for the camera RTCPU to be idle + * + * This function waits for the camera RTCPU to be idle + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the PM base for the device using @ref rtcpu->pm_base + * - Reads the PM power status register using @ref readl() + * - If the PM power status register is not NULL, polls for the WFI assert using @ref readl() + * - If the timeout is less than 0, returns -EBUSY + * - Calls @ref msleep() with a delay stride of HZ / 50 + * - Returns 0 on success + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval 0 If @ref rtcpu->pm_base is NULL or successful + * @retval -EBUSY If timeout occurs + */ static int tegra_rce_cam_wait_for_idle(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -458,6 +661,23 @@ static int tegra_rce_cam_wait_for_idle(struct device *dev) return 0; } +/** + * @brief Set the operating point for the camera RTCPU + * + * This function sets the operating point for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the HSP for the device using @ref rtcpu->hsp + * - Returns 0 if the HSP is not NULL + * - Returns the return value from @ref camrtc_hsp_set_operating_point() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] op Operating point to set + * Valid value: [0, UINT32_MAX] + * + * @retval (int) Return value from @ref camrtc_hsp_set_operating_point() + * @retval 0 if the HSP is NULL + */ static int tegra_camrtc_fw_set_operating_point(struct device *dev, uint32_t op) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -468,6 +688,21 @@ static int tegra_camrtc_fw_set_operating_point(struct device *dev, uint32_t op) return camrtc_hsp_set_operating_point(rtcpu->hsp, op); } +/** + * @brief Deassert the resets for the camera RTCPU + * + * This function deasserts the resets for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the reset group for the device using @ref camrtc_reset_group_deassert() + * - Returns an error if the reset group deassertion fails + * - Sets the fwloaddone flag to true using @ref tegra_camrtc_set_fwloaddone() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_reset_group_deassert() + * @retval 0 On successful reset group deassertion + */ static int tegra_rce_cam_deassert_resets(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -483,6 +718,16 @@ static int tegra_rce_cam_deassert_resets(struct device *dev) return 0; } +/** + * @brief Assert the resets for the camera RTCPU + * + * This function asserts the resets for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the reset group for the device using @ref camrtc_reset_group_assert() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_rce_cam_assert_resets(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -490,6 +735,20 @@ static void tegra_rce_cam_assert_resets(struct device *dev) camrtc_reset_group_assert(rtcpu->resets[0]); } +/** + * @brief Wait for the camera RTCPU to be idle + * + * This function waits for the camera RTCPU to be idle + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Retrieves the wait_for_idle function from the platform data using + * @ref rtcpu->pdata->wait_for_idle + * - Returns the return value from @ref rtcpu->pdata->wait_for_idle + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref rtcpu->pdata->wait_for_idle + */ static int tegra_camrtc_wait_for_idle(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -497,6 +756,21 @@ static int tegra_camrtc_wait_for_idle(struct device *dev) return rtcpu->pdata->wait_for_idle(dev); } +/** + * @brief Suspend the camera RTCPU + * + * This function suspends the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the fw_active flag is true and the HSP is not NULL + * - Sets the fw_active flag to false + * - Calls @ref camrtc_hsp_suspend() to suspend the RTCPU + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_hsp_suspend() + * @retval 0 if the fw_active flag is false or the HSP is NULL + */ static int tegra_camrtc_fw_suspend(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -509,6 +783,19 @@ static int tegra_camrtc_fw_suspend(struct device *dev) return camrtc_hsp_suspend(rtcpu->hsp); } +/** + * @brief Setup the shared memory for the camera RTCPU + * + * This function sets up the shared memory for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_rtcpu_trace_boot_sync() to set up the trace + * - Calls @ref tegra_ivc_bus_boot_sync() to set up the IVC services + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_ivc_bus_boot_sync() + */ static int tegra_camrtc_setup_shared_memory(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -531,6 +818,22 @@ static int tegra_camrtc_setup_shared_memory(struct device *dev) return ret; } +/** + * @brief Set the online status for the camera RTCPU + * + * This function sets the online status for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the online status is already set + * - If the online status is already set, returns + * - If the online status is not set, calls @ref tegra_camrtc_setup_shared_memory() + * to set up the shared memory + * - Sets the online status to the provided status + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] online Online status to set + * Valid value: true or false + */ static void tegra_camrtc_set_online(struct device *dev, bool online) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -550,6 +853,22 @@ static void tegra_camrtc_set_online(struct device *dev, bool online) } } +/** + * @brief Ping the camera RTCPU + * + * This function pings the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref camrtc_hsp_ping() to ping the RTCPU + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] data Data to ping the RTCPU with + * Valid value: [0, UINT32_MAX] + * @param[in] timeout Timeout for the ping + * Valid value: [0, UINT32_MAX] + * + * @retval (int) Return value from @ref camrtc_hsp_ping() + */ int tegra_camrtc_ping(struct device *dev, u32 data, long timeout) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -558,6 +877,19 @@ int tegra_camrtc_ping(struct device *dev, u32 data, long timeout) } EXPORT_SYMBOL(tegra_camrtc_ping); +/** + * @brief Notify the camera RTCPU + * + * This function notifies the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the IVC bus is not NULL + * - Calls @ref tegra_ivc_bus_notify() to notify the RTCPU + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] group Group to notify the RTCPU with + * Valid value: [0, UINT16_MAX] + */ static void tegra_camrtc_ivc_notify(struct device *dev, u16 group) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -566,6 +898,26 @@ static void tegra_camrtc_ivc_notify(struct device *dev, u16 group) tegra_ivc_bus_notify(rtcpu->ivc, group); } +/** + * @brief Power on the camera RTCPU + * + * This function powers on the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the RTCPU is already powered + * - If the RTCPU is already powered, returns 0 + * - If the RTCPU is not powered, calls @ref tegra_camrtc_enable_clks() to enable the clocks + * - Calls @ref tegra_camrtc_deassert_resets() to deassert the resets + * - Sets the powered flag to true + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] full_speed Full speed flag to set + * Valid value: true or false + * + * @retval (int) Return value from @ref tegra_camrtc_enable_clks() or + * @ref tegra_camrtc_deassert_resets() + * @retval 0 On successful power on + */ static int tegra_camrtc_poweron(struct device *dev, bool full_speed) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -597,6 +949,20 @@ static int tegra_camrtc_poweron(struct device *dev, bool full_speed) return 0; } +/** + * @brief Power off the camera RTCPU + * + * This function powers off the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the RTCPU is already powered + * - If the RTCPU is not powered, returns + * - Calls @ref tegra_camrtc_assert_resets() to assert the resets + * - Calls @ref tegra_camrtc_disable_clks() to disable the clocks + * - Sets the powered flag to false + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_poweroff(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -612,6 +978,23 @@ static void tegra_camrtc_poweroff(struct device *dev) tegra_camrtc_disable_clks(dev); } +/** + * @brief Boot sync the camera RTCPU + * + * This function boots syncs the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the boot sync is already done + * - If the boot sync is already done, returns + * - Calls @ref camrtc_hsp_sync() to sync the RTCPU + * - Sets the boot sync done flag to true + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_hsp_sync() or + * @ref camrtc_hsp_resume() + * @retval 0 On successful boot sync + */ static int tegra_camrtc_boot_sync(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -637,8 +1020,23 @@ static int tegra_camrtc_boot_sync(struct device *dev) return 0; } -/* - * RTCPU boot sequence +/** + * @brief Boot the camera RTCPU + * + * This function boots the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_camrtc_poweron() to power on the RTCPU + * - Calls @ref tegra_camrtc_full_mem_bw() to set the full memory bandwidth + * - Loops until the RTCPU is online + * - If the RTCPU is online, breaks the loop + * - If the RTCPU is not online, retries the boot sequence + * - If the RTCPU is not online after the max number of retries, breaks the loop + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_poweron() + * @retval 0 On successful boot */ static int tegra_camrtc_boot(struct device *dev) { @@ -675,6 +1073,20 @@ static int tegra_camrtc_boot(struct device *dev) return 0; } +/** + * @brief Setup the IOVM for the camera RTCPU + * + * This function sets up the IOVM for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref camrtc_hsp_ch_setup() to setup the IOVM + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] iova IOVA to setup the IOVM with + * Valid value: [0, UINT64_MAX] + * + * @retval (int) Return value from @ref camrtc_hsp_ch_setup() + */ int tegra_camrtc_iovm_setup(struct device *dev, dma_addr_t iova) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -683,6 +1095,24 @@ int tegra_camrtc_iovm_setup(struct device *dev, dma_addr_t iova) } EXPORT_SYMBOL(tegra_camrtc_iovm_setup); +/** + * @brief Print the version of the camera RTCPU + * + * This function prints the version of the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref seq_buf_init() to initialize the sequence buffer + * - Calls @ref seq_buf_printf() to print the version of the RTCPU + * - Returns the number of bytes printed + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] buf Buffer to print the version to + * Valid value: non-NULL + * @param[in] size Size of the buffer + * Valid value: [0, UINT32_MAX] + * + * @retval (ssize_t) Number of bytes printed using @ref seq_buf_used() + */ ssize_t tegra_camrtc_print_version(struct device *dev, char *buf, size_t size) { @@ -701,6 +1131,16 @@ ssize_t tegra_camrtc_print_version(struct device *dev, } EXPORT_SYMBOL(tegra_camrtc_print_version); +/** + * @brief Log the firmware version of the camera RTCPU + * + * This function logs the firmware version of the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_camrtc_print_version() to print the version of the RTCPU + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ static void tegra_camrtc_log_fw_version(struct device *dev) { char version[TEGRA_CAMRTC_VERSION_LEN]; @@ -710,6 +1150,17 @@ static void tegra_camrtc_log_fw_version(struct device *dev) dev_info(dev, "firmware %s\n", version); } +/** + * @brief Start the PM of the camera RTCPU + * + * This function starts the PM of the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] op Operation to log + * Valid value: non-NULL + */ static void tegra_camrtc_pm_start(struct device *dev, char const *op) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -719,6 +1170,19 @@ static void tegra_camrtc_pm_start(struct device *dev, char const *op) rtcpu->fw_active, rtcpu->online); } +/** + * @brief Done the PM of the camera RTCPU + * + * This function done the PM of the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] op Operation to log + * Valid value: non-NULL + * @param[in] err Error code + * Valid value: [0, INT32_MAX] + */ static void tegra_camrtc_pm_done(struct device *dev, char const *op, int err) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -728,6 +1192,22 @@ static void tegra_camrtc_pm_done(struct device *dev, char const *op, int err) rtcpu->fw_active, rtcpu->online); } +/** + * @brief Runtime suspend the camera RTCPU + * + * This function runtime suspends the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_camrtc_pm_start() to start the PM + * - Calls @ref tegra_camrtc_fw_suspend() to suspend the RTCPU + * - If the RTCPU suspend fails, resets the RTCPU + * - Calls @ref tegra_camrtc_poweroff() to power off the RTCPU + * - Sets the online flag to false + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval 0 On successful runtime suspend + */ static int tegra_cam_rtcpu_runtime_suspend(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -755,6 +1235,21 @@ static int tegra_cam_rtcpu_runtime_suspend(struct device *dev) return 0; } +/** + * @brief Runtime resume the camera RTCPU + * + * This function runtime resumes the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_camrtc_pm_start() to start the PM + * - Calls @ref tegra_camrtc_boot() to boot the RTCPU + * - Calls @ref tegra_camrtc_pm_done() to done the PM + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_boot() + * @retval 0 On successful runtime resume + */ static int tegra_cam_rtcpu_runtime_resume(struct device *dev) { int err; @@ -768,6 +1263,18 @@ static int tegra_cam_rtcpu_runtime_resume(struct device *dev) return err; } +/** + * @brief Runtime idle the camera RTCPU + * + * This function runtime idles the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref pm_runtime_mark_last_busy() to mark the last busy time + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) 0 + */ static int tegra_cam_rtcpu_runtime_idle(struct device *dev) { pm_runtime_mark_last_busy(dev); @@ -775,6 +1282,23 @@ static int tegra_cam_rtcpu_runtime_idle(struct device *dev) return 0; } +/** + * @brief Initialize the HSP for the camera RTCPU + * + * This function initializes the HSP for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the HSP is already initialized + * - If the HSP is already initialized, returns 0 + * - Calls @ref camrtc_hsp_create() to create the HSP + * - If the HSP creation fails, returns the error code + * - Sets the HSP to the driver data + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref camrtc_hsp_create() + * @retval 0 On successful HSP initialization or if the HSP is already initialized + */ static int tegra_camrtc_hsp_init(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -794,6 +1318,30 @@ static int tegra_camrtc_hsp_init(struct device *dev) return 0; } +/** + * @brief Remove the camera RTCPU + * + * This function removes the camera RTCPU + * - Retrieves the driver data for the device using @ref platform_get_drvdata() + * - Checks if the HSP is already initialized + * - If the HSP is initialized, calls @ref camrtc_hsp_bye() to bye the HSP + * - Calls @ref camrtc_hsp_free() to free the HSP + * - Sets the HSP to NULL + * - Destroys the tracer using @ref tegra_rtcpu_trace_destroy() + * - Sets the tracer to NULL + * - Powers off the device using @ref tegra_camrtc_poweroff() + * - Sets the ICC path to NULL + * - Removes the device from the PM genpd using @ref pm_genpd_remove_device() + * - Destroys the monitor using @ref tegra_cam_rtcpu_mon_destroy() + * - Destroys the IVC bus using @ref tegra_ivc_bus_destroy() + * - Sets the DMA parameters to NULL + * - Deinitializes the operating point sysfs using @ref deinit_operating_point_sysfs() + * + * @param[in] pdev Pointer to the platform device + * Valid value: non-NULL + * + * @retval 0 On successful removal + */ static int tegra_cam_rtcpu_remove(struct platform_device *pdev) { struct tegra_cam_rtcpu *rtcpu = platform_get_drvdata(pdev); @@ -830,6 +1378,48 @@ static int tegra_cam_rtcpu_remove(struct platform_device *pdev) return 0; } +/** + * @brief Probe the camera RTCPU + * + * This function probes the camera RTCPU + * - Retrieves the driver data for the device using @ref of_device_get_match_data() + * - Reads the device name from the device tree using @ref of_property_read_string() + * - Reads the device properties using @ref of_property_read_u32() + * - Allocates memory for the camera RTCPU using @ref devm_kzalloc() + * - Sets the driver data for the device using @ref platform_set_drvdata() + * - Sets the DMA parameters for the device using @ref dma_set_mask_and_coherent() + * - Enables runtime power management for the device using @ref pm_runtime_enable() + * - Retrieves the resources for the device using @ref tegra_camrtc_get_resources() + * - Sets the reboot retry count using @ref of_property_read_u32() + * - Reads the command timeout using @ref of_property_read_u32() + * - Reads the autosuspend delay using @ref of_property_read_u32() + * - Sets the autosuspend delay using @ref pm_runtime_set_autosuspend_delay() + * - Initializes the memory bandwidth for the device using @ref tegra_camrtc_init_membw() + * - Sets the DMA parameters for the device using @ref dev->dma_parms + * - Sets the tracer for the device using @ref tegra_rtcpu_trace_create() + * - Initializes the HSP for the device using @ref tegra_camrtc_hsp_init() + * - Powers on the device using @ref pm_runtime_get_sync() + * - Creates the IVC bus for the device using @ref tegra_ivc_bus_create() + * - Creates the monitor for the device using @ref tegra_camrtc_mon_create() + * - Reads the firmware hash using @ref camrtc_hsp_get_fw_hash() + * - Logs the firmware version using @ref tegra_camrtc_log_fw_version() + * - Sets the online flag to true using @ref tegra_camrtc_set_online() + * - Puts the device using @ref pm_runtime_put() + * - Sets the device to the global variable s_dev + * - Initializes the operating point sysfs using @ref init_operating_point_sysfs() + * - In case of failure, call @ref pm_runtime_dont_use_autosuspend() and + * @ref pm_runtime_put_sync_suspend() + * - In case of failure, call @ref tegra_cam_rtcpu_remove() + * + * @param[in] pdev Pointer to the platform device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_get_resources() + * or @ref tegra_camrtc_hsp_init() or @ref pm_runtime_get_sync() or @ref camrtc_hsp_get_fw_hash() + * @retval -ENOMEM On memory allocation failure + * @retval -ENODEV On device match failure + * @retval 0 On successful probe + */ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) { struct tegra_cam_rtcpu *rtcpu; @@ -949,6 +1539,29 @@ fail: return ret; } +/** + * @brief Reboot the camera RTCPU + * + * This function reboots the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the device is suspended using @ref pm_runtime_suspended() + * - Checks if the RTCPU is powered using @ref rtcpu->powered + * - Sets the rebooting flag to 1 using @ref atomic_cmpxchg() + * - Calls @ref tegra_camrtc_pm_start() to start the PM operation + * - Calls @ref tegra_camrtc_set_online() to set the online flag to false + * - Calls @ref tegra_camrtc_wait_for_idle() to wait for the RTCPU to enter WFI + * - Calls @ref tegra_camrtc_assert_resets() to assert the resets + * - Sets the powered flag to false using @ref rtcpu->powered + * - Calls @ref tegra_camrtc_boot() to boot the RTCPU + * - Sets the rebooting flag to 0 using @ref atomic_set() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_boot() + * @retval -EIO On device suspended or RTCPU not powered + * @retval -EBUSY On rebooting flag already set + */ int tegra_camrtc_reboot(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -1001,6 +1614,22 @@ int tegra_camrtc_reboot(struct device *dev) } EXPORT_SYMBOL(tegra_camrtc_reboot); +/** + * @brief Restore the camera RTCPU + * + * This function restores the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the monitor is not NULL using @ref rtcpu->monitor + * - Calls @ref tegra_camrtc_mon_restore_rtcpu() to restore the RTCPU + * - Returns the return value from @ref tegra_camrtc_mon_restore_rtcpu() + * - If the monitor is NULL, calls @ref tegra_camrtc_reboot() to reboot the RTCPU + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_mon_restore_rtcpu() or + * @ref tegra_camrtc_reboot() + */ int tegra_camrtc_restore(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -1012,6 +1641,18 @@ int tegra_camrtc_restore(struct device *dev) } EXPORT_SYMBOL(tegra_camrtc_restore); +/** + * @brief Check if the camera RTCPU is alive + * + * This function checks if the camera RTCPU is alive + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Returns the online flag from @ref rtcpu->online + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (bool) Value of @ref rtcpu->online + */ bool tegra_camrtc_is_rtcpu_alive(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -1020,6 +1661,19 @@ bool tegra_camrtc_is_rtcpu_alive(struct device *dev) } EXPORT_SYMBOL(tegra_camrtc_is_rtcpu_alive); +/** + * @brief Check if the camera RTCPU is powered + * + * This function checks if the camera RTCPU is powered + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Returns the powered flag from @ref rtcpu->powered + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (bool) Value of @ref rtcpu->powered + * @retval false if the device is not found + */ bool tegra_camrtc_is_rtcpu_powered(void) { struct tegra_cam_rtcpu *rtcpu; @@ -1033,6 +1687,16 @@ bool tegra_camrtc_is_rtcpu_powered(void) } EXPORT_SYMBOL(tegra_camrtc_is_rtcpu_powered); +/** + * @brief Flush the trace for the camera RTCPU + * + * This function flushes the trace for the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Calls @ref tegra_rtcpu_trace_flush() to flush the trace + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + */ void tegra_camrtc_flush_trace(struct device *dev) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -1041,6 +1705,24 @@ void tegra_camrtc_flush_trace(struct device *dev) } EXPORT_SYMBOL(tegra_camrtc_flush_trace); +/** + * @brief Halt the camera RTCPU + * + * This function halts the camera RTCPU + * - Retrieves the driver data for the device using @ref dev_get_drvdata() + * - Checks if the online flag is true using @ref rtcpu->online + * - Calls @ref tegra_camrtc_pm_start() to start the PM operation + * - Calls @ref tegra_camrtc_set_online() to set the online flag to false + * - Checks if the powered flag is false using @ref rtcpu->powered + * - Calls @ref tegra_camrtc_pm_done() to finish the PM operation + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * @param[in] op Operation to perform + * Valid value: non-NULL + * + * @retval 0 if the RTCPU is not powered or the operation is successful + */ static int tegra_camrtc_halt(struct device *dev, char const *op) { struct tegra_cam_rtcpu *rtcpu = dev_get_drvdata(dev); @@ -1075,11 +1757,38 @@ static int tegra_camrtc_halt(struct device *dev, char const *op) return 0; } +/** + * @brief Suspend the camera RTCPU + * + * This function suspends the camera RTCPU + * - Calls @ref tegra_camrtc_halt() to halt the RTCPU + * - Returns the return value from @ref tegra_camrtc_halt() + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref tegra_camrtc_halt() + */ static int tegra_camrtc_suspend(struct device *dev) { return tegra_camrtc_halt(dev, "suspend"); } +/** + * @brief Resume the camera RTCPU + * + * This function resumes the camera RTCPU + * - Calls @ref tegra_camrtc_pm_start() to start the PM operation + * - Calls @ref pm_runtime_mark_last_busy() to mark the device as busy + * - Calls @ref pm_runtime_resume() to resume the device + * - Calls @ref tegra_camrtc_pm_done() to finish the PM operation + * + * @param[in] dev Pointer to the device + * Valid value: non-NULL + * + * @retval (int) Return value from @ref pm_runtime_resume() or + * @ref tegra_camrtc_boot() + */ static int tegra_camrtc_resume(struct device *dev) { int err; @@ -1099,6 +1808,16 @@ static int tegra_camrtc_resume(struct device *dev) return err; } +/** + * @brief Shutdown the camera RTCPU + * + * This function shuts down the camera RTCPU + * - Calls @ref tegra_camrtc_halt() to halt the RTCPU + * - Returns the return value from @ref tegra_camrtc_halt() + * + * @param[in] pdev Pointer to the platform device + * Valid value: non-NULL + */ static void tegra_cam_rtcpu_shutdown(struct platform_device *pdev) { tegra_camrtc_halt(&pdev->dev, "shutdown"); @@ -1123,6 +1842,15 @@ static const struct dev_pm_ops tegra_cam_rtcpu_pm_ops = { .runtime_idle = tegra_cam_rtcpu_runtime_idle, }; +/** + * @brief Remove the camera RTCPU + * + * This function removes the camera RTCPU + * - Calls @ref tegra_cam_rtcpu_remove() to remove the RTCPU + * + * @param[in] pdev Pointer to the platform device + * Valid value: non-NULL + */ #if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */ static void tegra_cam_rtcpu_remove_wrapper(struct platform_device *pdev) { diff --git a/drivers/platform/tegra/rtcpu/tegra-rtcpu-trace.c b/drivers/platform/tegra/rtcpu/tegra-rtcpu-trace.c index cec4e80b..9a91b26e 100644 --- a/drivers/platform/tegra/rtcpu/tegra-rtcpu-trace.c +++ b/drivers/platform/tegra/rtcpu/tegra-rtcpu-trace.c @@ -144,10 +144,22 @@ static inline u32 wrap_add_u32(u32 const a, u32 const b) return ret; } -/* - * Trace memory +/** + * @brief Sets up memory for RTCPU trace + * + * This function sets up memory for the RTCPU trace + * - Reads memory specifications from device tree using @ref of_parse_phandle_with_fixed_args() + * - Allocates coherent DMA memory using @ref dma_alloc_coherent() + * - Initializes the trace memory header with appropriate configuration values + * - In case of error, @ref of_node_put() is called to release the reference to the device node + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * + * @retval 0 on success + * @retval -EINVAL if invalid trace entry is found in device tree + * @retval -ENOMEM if memory allocation fails */ - static int rtcpu_trace_setup_memory(struct tegra_rtcpu_trace *tracer) { struct device *dev = tracer->dev; @@ -185,6 +197,25 @@ error: return ret; } +/** + * @brief Initializes the trace memory + * + * This function initializes the trace memory by mapping the DMA handle to the trace memory + * and setting up the exception base and exception entries. + * - Checks for overflow in the DMA handle and exception base using @ref check_add_overflow() and + * @ref offsetof() + * - Maps the DMA handle to the trace memory using @ref dma_handle_pointers + * - Sets up the exception base and exception entries + * - Initializes the trace memory header with appropriate configuration values + * - Checks for overflow in the DMA handle and event entries using @ref check_add_overflow() and + * @ref check_sub_overflow() + * - Sets up the event entries and DMA handle events + * - Copies the trace memory header to the trace memory using @ref memcpy() + * - Synchronizes the trace memory header for device using @ref dma_sync_single_for_device() + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_init_memory(struct tegra_rtcpu_trace *tracer) { u64 add_value = 0; @@ -246,10 +277,28 @@ static void rtcpu_trace_init_memory(struct tegra_rtcpu_trace *tracer) } } -/* - * Worker +/** + * @brief Invalidates cache entries for RTCPU trace + * + * This function invalidates cache entries for the RTCPU trace + * - If the new next is greater than the old next, it invalidates the cache entries for the device + * using @ref dma_sync_single_for_cpu() + * - Checks for overflow in the DMA handle and event entries using @ref check_add_overflow() and + * @ref check_sub_overflow() + * - Synchronizes the trace memory header for device using @ref dma_sync_single_for_cpu() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] dma_handle DMA handle for the trace memory. + * @param[in] old_next Old next value for the trace memory. + * Valid Range: 0 to UINT32_MAX + * @param[in] new_next New next value for the trace memory. + * Valid Range: 0 to UINT32_MAX + * @param[in] entry_size Entry size for the trace memory. + * Valid Range: 0 to UINT32_MAX + * @param[in] entry_count Entry count for the trace memory. + * Valid Range: 0 to UINT32_MAX */ - static void rtcpu_trace_invalidate_entries(struct tegra_rtcpu_trace *tracer, dma_addr_t dma_handle, u32 old_next, u32 new_next, u32 entry_size, u32 entry_count) @@ -307,6 +356,22 @@ static void rtcpu_trace_invalidate_entries(struct tegra_rtcpu_trace *tracer, } } +/** + * @brief Prints the exception trace + * + * This function prints the exception trace + * - constructs the sequence buffer using @ref seq_buf_init() + * - prints the exception type using @ref seq_buf_printf() + * - prints the exception registers using @ref seq_buf_printf() + * - prints the exception callstack using @ref seq_buf_printf() + * - If exception length is greater than the exception size, it prints multiple lines + * using @ref seq_buf_printf() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] exc Pointer to the camrtc_trace_armv7_exception structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_exception(struct tegra_rtcpu_trace *tracer, struct camrtc_trace_armv7_exception *exc) { @@ -389,6 +454,25 @@ static void rtcpu_trace_exception(struct tegra_rtcpu_trace *tracer, " ", " ", header, buf, trailer, " ", " "); } +/** + * @brief Prints the exception trace + * + * This function prints the exception trace + * - Gets the old and new next values from the trace memory header + * - Checks if the old and new next values are the same, if so, return + * - Checks if the new next value is greater than the exception entries, if so, print a warning and + * return + * - Sets the new next value to the exception entries using @ref array_index_nospec() + * - Invalidates the cache entries for the device using @ref rtcpu_trace_invalidate_entries + * - Copies the exception to the exception structure using @ref memcpy() + * - Prints the exception trace using @ref rtcpu_trace_exception() + * - Increments the exception count using @ref wrap_add_u32() + * - Increments the old next value using @ref wrap_add_u32() + * - Sets the exception last index to the new next value + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + */ static inline void rtcpu_trace_exceptions(struct tegra_rtcpu_trace *tracer) { const struct camrtc_trace_memory_header *header = tracer->trace_memory; @@ -436,6 +520,21 @@ static inline void rtcpu_trace_exceptions(struct tegra_rtcpu_trace *tracer) tracer->exception_last_idx = new_next; } +/** + * @brief Calculates the length of the event + * + * This function calculates the length of the event + * - If the length is greater than the event size, it sets the length to the + * @ref CAMRTC_TRACE_EVENT_SIZE minus @ref CAMRTC_TRACE_EVENT_HEADER_SIZE + * - If the length is greater than the header size, it sets the length to the + * length minus the @ref CAMRTC_TRACE_EVENT_HEADER_SIZE + * - Otherwise, it sets the length to 0 + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + * + * @retval (uint16_t) The length of the event. + */ static uint16_t rtcpu_trace_event_len(const struct camrtc_event_struct *event) { uint16_t len = event->header.len; @@ -450,6 +549,16 @@ static uint16_t rtcpu_trace_event_len(const struct camrtc_event_struct *event) return len; } +/** + * @brief Prints the unknown trace event + * + * This function prints the unknown trace event + * - Gets the id and length of the event + * - Prints the unknown trace event using @ref trace_rtcpu_unknown() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_unknown_trace_event(struct camrtc_event_struct *event) { uint32_t id = event->header.id; @@ -459,6 +568,20 @@ static void rtcpu_unknown_trace_event(struct camrtc_event_struct *event) trace_rtcpu_unknown(tstamp, id, len, &event->data.data8[0]); } +/** + * @brief Prints the base trace event + * + * This function prints the base trace event + * - Gets the id of the event + * - If the id is @ref camrtc_trace_base_target_init, it prints the base trace event using + * @ref trace_rtcpu_target_init() + * - If the id is @ref camrtc_trace_base_start_scheduler, it prints the base trace event using + * @ref trace_rtcpu_start_scheduler() + * - Otherwise, it prints the unknown trace event using @ref rtcpu_unknown_trace_event() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_base_event(struct camrtc_event_struct *event) { switch (event->header.id) { @@ -474,6 +597,142 @@ static void rtcpu_trace_base_event(struct camrtc_event_struct *event) } } +/** + * @brief Prints the RTOS trace event + * + * This function prints the RTOS trace event + * - Gets the id of the event + * - If the id is @ref camrtc_trace_rtos_task_switched_in, it prints the RTOS trace event using + * @ref trace_rtos_task_switched_in() + * - If the id is @ref camrtc_trace_rtos_increase_tick_count, it prints the RTOS trace event using + * @ref trace_rtos_increase_tick_count() + * - If the id is @ref camrtc_trace_rtos_low_power_idle_begin, it prints the RTOS trace event using + * @ref trace_rtos_low_power_idle_begin() + * - If the id is @ref camrtc_trace_rtos_low_power_idle_end, it prints the RTOS trace event using + * @ref trace_rtos_low_power_idle_end() + * - If the id is @ref camrtc_trace_rtos_task_switched_out, it prints the RTOS trace event using + * @ref trace_rtos_task_switched_out() + * - If the id is @ref camrtc_trace_rtos_task_priority_inherit, it prints the RTOS trace event using + * @ref trace_rtos_task_priority_inherit() + * - If the id is @ref camrtc_trace_rtos_task_priority_disinherit, it prints the RTOS trace event + * using @ref trace_rtos_task_priority_disinherit() + * - If the id is @ref camrtc_trace_rtos_blocking_on_queue_receive, it prints the RTOS trace event + * using @ref trace_rtos_blocking_on_queue_receive() + * - If the id is @ref camrtc_trace_rtos_blocking_on_queue_send, it prints the RTOS trace event + * using @ref trace_rtos_blocking_on_queue_send() + * - If the id is @ref camrtc_trace_rtos_moved_task_to_ready_state, it prints the RTOS trace event + * using @ref trace_rtos_moved_task_to_ready_state() + * - If the id is @ref camrtc_trace_rtos_queue_create, it prints the RTOS trace event using + * @ref trace_rtos_queue_create() + * - If the id is @ref camrtc_trace_rtos_queue_create_failed, it prints the RTOS trace event using + * @ref trace_rtos_queue_create_failed() + * - If the id is @ref camrtc_trace_rtos_create_mutex, it prints the RTOS trace event using + * @ref trace_rtos_create_mutex() + * - If the id is @ref camrtc_trace_rtos_create_mutex_failed, it prints the RTOS trace event using + * @ref trace_rtos_create_mutex_failed() + * - If the id is @ref camrtc_trace_rtos_give_mutex_recursive, it prints the RTOS trace event + * using @ref trace_rtos_give_mutex_recursive() + * - If the id is @ref camrtc_trace_rtos_give_mutex_recursive_failed, it prints the RTOS trace event + * using @ref trace_rtos_give_mutex_recursive_failed() + * - If the id is @ref camrtc_trace_rtos_take_mutex_recursive, it prints the RTOS trace event using + * @ref trace_rtos_take_mutex_recursive() + * - If the id is @ref camrtc_trace_rtos_take_mutex_recursive_failed, it prints the RTOS trace + * event using @ref trace_rtos_take_mutex_recursive_failed() + * - If the id is @ref camrtc_trace_rtos_create_counting_semaphore, it prints the RTOS trace event using + * @ref trace_rtos_create_counting_semaphore() + * - If the id is @ref camrtc_trace_rtos_create_counting_semaphore_failed, it prints the RTOS trace + * event using @ref trace_rtos_create_counting_semaphore_failed() + * - If the id is @ref camrtc_trace_rtos_queue_send, it prints the RTOS trace event using + * @ref trace_rtos_queue_send() + * - If the id is @ref camrtc_trace_rtos_queue_send_failed, it prints the RTOS trace event using + * @ref trace_rtos_queue_send_failed() + * - If the id is @ref camrtc_trace_rtos_queue_receive, it prints the RTOS trace event using + * @ref trace_rtos_queue_receive() + * - If the id is @ref camrtc_trace_rtos_queue_peek, it prints the RTOS trace event using + * @ref trace_rtos_queue_peek() + * - If the id is @ref camrtc_trace_rtos_queue_peek_from_isr, it prints the RTOS trace event using + * @ref trace_rtos_queue_peek_from_isr() + * - If the id is @ref camrtc_trace_rtos_queue_receive_failed, it prints the RTOS trace event using + * @ref trace_rtos_queue_receive_failed() + * - If the id is @ref camrtc_trace_rtos_queue_send_from_isr, it prints the RTOS trace event using + * @ref trace_rtos_queue_send_from_isr() + * - If the id is @ref camrtc_trace_rtos_queue_send_from_isr_failed, it prints the RTOS trace event + * using @ref trace_rtos_queue_send_from_isr_failed() + * - If the id is @ref camrtc_trace_rtos_queue_receive_from_isr, it prints the RTOS trace event + * using @ref trace_rtos_queue_receive_from_isr() + * - If the id is @ref camrtc_trace_rtos_queue_receive_from_isr_failed, it prints the RTOS trace + * event using @ref trace_rtos_queue_receive_from_isr_failed() + * - If the id is @ref camrtc_trace_rtos_queue_peek_from_isr_failed, it prints the RTOS trace event + * using @ref trace_rtos_queue_peek_from_isr_failed() + * - If the id is @ref camrtc_trace_rtos_queue_delete, it prints the RTOS trace event + * using @ref trace_rtos_queue_delete() + * - If the id is @ref camrtc_trace_rtos_task_create, it prints the RTOS trace event + * using @ref trace_rtos_task_create() + * - If the id is @ref camrtc_trace_rtos_task_create_failed, it prints the RTOS trace event + using @ref trace_rtos_task_create_failed() + * - If the id is @ref camrtc_trace_rtos_task_delete, it prints the RTOS trace event + using @ref trace_rtos_task_delete() + * - If the id is @ref camrtc_trace_rtos_task_delay_until, it prints the RTOS trace event + using @ref trace_rtos_task_delay_until() + * - If the id is @ref camrtc_trace_rtos_task_delay, it prints the RTOS trace event + using @ref trace_rtos_task_delay() + * - If the id is @ref camrtc_trace_rtos_task_priority_set, it prints the RTOS trace event + using @ref trace_rtos_task_priority_set() + * - If the id is @ref camrtc_trace_rtos_task_suspend, it prints the RTOS trace event + using @ref trace_rtos_task_suspend() + * - If the id is @ref camrtc_trace_rtos_task_resume, it prints the RTOS trace event + using @ref trace_rtos_task_resume() + * - If the id is @ref camrtc_trace_rtos_task_resume_from_isr, it prints the RTOS trace event + using @ref trace_rtos_task_resume_from_isr() + * - If the id is @ref camrtc_trace_rtos_task_increment_tick, it prints the RTOS trace event + using @ref trace_rtos_task_increment_tick() + * - If the id is @ref camrtc_trace_rtos_timer_create, it prints the RTOS trace event + using @ref trace_rtos_timer_create() + * - If the id is @ref camrtc_trace_rtos_timer_create_failed, it prints the RTOS trace event + using @ref trace_rtos_timer_create_failed() + * - If the id is @ref camrtc_trace_rtos_timer_command_send, it prints the RTOS trace event + using @ref trace_rtos_timer_command_send() + * - If the id is @ref camrtc_trace_rtos_timer_expired, it prints the RTOS trace event + using @ref trace_rtos_timer_expired() + * - If the id is @ref camrtc_trace_rtos_timer_command_received, it prints the RTOS trace event + using @ref trace_rtos_timer_command_received() + * - If the id is @ref camrtc_trace_rtos_malloc, it prints the RTOS trace event + using @ref trace_rtos_malloc() + * - If the id is @ref camrtc_trace_rtos_free, it prints the RTOS trace event + using @ref trace_rtos_free() + * - If the id is @ref camrtc_trace_rtos_event_group_create, it prints the RTOS trace event + using @ref trace_rtos_event_group_create() + * - If the id is @ref camrtc_trace_rtos_event_group_create_failed, it prints the RTOS trace event + using @ref trace_rtos_event_group_create_failed() + * - If the id is @ref camrtc_trace_rtos_event_group_sync_block, it prints the RTOS trace event + using @ref trace_rtos_event_group_sync_block() + * - If the id is @ref camrtc_trace_rtos_event_group_sync_end, it prints the RTOS trace event + using @ref trace_rtos_event_group_sync_end() + * - If the id is @ref camrtc_trace_rtos_event_group_wait_bits_block, it prints the RTOS trace event + using @ref trace_rtos_event_group_wait_bits_block() + * - If the id is @ref camrtc_trace_rtos_event_group_wait_bits_end, it prints the RTOS trace event + using @ref trace_rtos_event_group_wait_bits_end() + * - If the id is @ref camrtc_trace_rtos_event_group_clear_bits, it prints the RTOS trace event + using @ref trace_rtos_event_group_clear_bits() + * - If the id is @ref camrtc_trace_rtos_event_group_clear_bits_from_isr, it prints the RTOS + trace event using @ref trace_rtos_event_group_clear_bits_from_isr() + * - If the id is @ref camrtc_trace_rtos_event_group_set_bits, it prints the RTOS trace event + using @ref trace_rtos_event_group_set_bits() + * - If the id is @ref camrtc_trace_rtos_event_group_set_bits_from_isr, it prints the RTOS trace + event using @ref trace_rtos_event_group_set_bits_from_isr() + * - If the id is @ref camrtc_trace_rtos_event_group_delete, it prints the RTOS trace event + using @ref trace_rtos_event_group_delete() + * - If the id is @ref camrtc_trace_rtos_pend_func_call, it prints the RTOS trace event + using @ref trace_rtos_pend_func_call() + * - If the id is @ref camrtc_trace_rtos_pend_func_call_from_isr, it prints the RTOS trace event + using @ref trace_rtos_pend_func_call_from_isr() + * - If the id is @ref camrtc_trace_rtos_queue_registry_add, it prints the RTOS trace event + using @ref trace_rtos_queue_registry_add() + * - If id is not found, it prints the unknown trace event using @ref rtcpu_unknown_trace_event() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_rtos_event(struct camrtc_event_struct *event) { switch (event->header.id) { @@ -799,6 +1058,23 @@ const char * const g_trace_vinotify_tag_strs[] = { const unsigned int g_trace_vinotify_tag_str_count = ARRAY_SIZE(g_trace_vinotify_tag_strs); +/** + * @brief Trace VINOTIFY events + * + * This function traces VINOTIFY events based on the event ID. + * - It handles different VINOTIFY event types and their corresponding trace functions. + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * - If event ID is @ref camrtc_trace_vinotify_event_ts64, it prints the VINOTIFY trace event using + * @ref trace_rtcpu_vinotify_event_ts64() + * - If event ID is @ref camrtc_trace_vinotify_event, it prints the VINOTIFY trace event using + * @ref trace_rtcpu_vinotify_event() + * - If event ID is @ref camrtc_trace_vinotify_error, it prints the VINOTIFY trace event using + * @ref trace_rtcpu_vinotify_error() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_vinotify_event(struct camrtc_event_struct *event) { switch (event->header.id) { @@ -828,6 +1104,24 @@ static void rtcpu_trace_vinotify_event(struct camrtc_event_struct *event) } } +/** + * @brief Trace VI frame events + * + * This function traces VI frame events based on the event ID. + * - Gets the platform device data for the VI unit using @ref platform_get_drvdata() + * - If the platform device data is not found, it returns + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * - If event ID is @ref camrtc_trace_vi_frame_begin, it prints the VI frame begin trace event using + * @ref trace_vi_frame_begin() + * - If event ID is @ref camrtc_trace_vi_frame_end, it prints the VI frame end trace event using + * @ref trace_vi_frame_end() and @ref trace_task_fence() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_vi_frame_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -888,6 +1182,20 @@ static void rtcpu_trace_vi_frame_event(struct tegra_rtcpu_trace *tracer, } } +/** + * @brief Trace VI events + * + * This function traces VI events based on the event ID. + * - If the event ID is @ref camrtc_trace_vi_frame_begin or @ref camrtc_trace_vi_frame_end, + * it prints the VI frame event using @ref rtcpu_trace_vi_frame_event() + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_vi_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -921,6 +1229,21 @@ const unsigned int g_trace_isp_falcon_task_str_count = #define TRACE_ISP_FALCON_PROFILE_START 16U #define TRACE_ISP_FALCON_PROFILE_END 17U +/** + * @brief Trace ISP task events + * + * This function traces ISP task events based on the event ID. + * - It handles different ISP task event types and their corresponding trace functions. + * - If event ID is @ref camrtc_trace_isp_task_begin, it prints the ISP task begin trace event + * using @ref trace_isp_task_begin() and @ref trace_task_fence() + * - If event ID is @ref camrtc_trace_isp_task_end, it prints the ISP task end trace event using + * @ref trace_isp_task_end() and @ref trace_task_fence() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_isp_task_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -988,6 +1311,25 @@ static void rtcpu_trace_isp_task_event(struct tegra_rtcpu_trace *tracer, } } +/** + * @brief Trace ISP Falcon events + * + * This function traces ISP Falcon events based on the event ID. + * - It handles different ISP Falcon event types and their corresponding trace functions. + * - If event ID is @ref TRACE_ISP_FALCON_EVENT_TS, it prints the ISP Falcon tile start trace + * event using @ref trace_rtcpu_isp_falcon_tile_start() + * - If event ID is @ref TRACE_ISP_FALCON_EVENT_TE, it prints the ISP Falcon tile end trace event + * using @ref trace_rtcpu_isp_falcon_tile_end() + * - If event ID is @ref TRACE_ISP_FALCON_PROFILE_START, it prints the ISP Falcon task start trace + * event using @ref trace_rtcpu_isp_falcon_task_start() + * - If event ID is @ref TRACE_ISP_FALCON_PROFILE_END, it prints the ISP Falcon task end trace + * event using @ref trace_rtcpu_isp_falcon_task_end() + * - If event ID is not found, it prints the unknown trace event using + * @ref trace_rtcpu_isp_falcon() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_isp_falcon_event(struct camrtc_event_struct *event) { u8 ispfalcon_tag = (u8) ((event->data.data32[0] & 0xFF) >> 1U); @@ -1033,6 +1375,22 @@ static void rtcpu_trace_isp_falcon_event(struct camrtc_event_struct *event) } +/** + * @brief Trace ISP events + * + * This function traces ISP events based on the event ID. + * - If the event ID is @ref camrtc_trace_isp_task_begin or @ref camrtc_trace_isp_task_end, + * it prints the ISP task event using @ref rtcpu_trace_isp_task_event() + * - If the event ID is @ref camrtc_trace_isp_falcon_traces_event, it prints the ISP Falcon + * traces event using @ref rtcpu_trace_isp_falcon_event() + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_isp_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -1067,6 +1425,18 @@ const char * const g_trace_nvcsi_intr_type_strs[] = { const unsigned int g_trace_nvcsi_intr_type_str_count = ARRAY_SIZE(g_trace_nvcsi_intr_type_strs); +/** + * @brief Trace NVCSI events + * + * This function traces NVCSI events based on the event ID. + * - If the event ID is @ref camrtc_trace_nvcsi_intr, it prints the NVCSI interrupt trace + * event using @ref trace_rtcpu_nvcsi_intr() + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_nvcsi_event(struct camrtc_event_struct *event) { u64 ts_tsc = ((u64)event->data.data32[5] << 32) | @@ -1108,6 +1478,39 @@ struct capture_event { }; }; +/** + * @brief Trace capture events + * + * This function traces capture events based on the event ID. + * - If the event ID is @ref camrtc_trace_capture_event_sof, it prints the capture start of frame + * trace event using @ref trace_capture_event_sof() + * - If the event ID is @ref camrtc_trace_capture_event_eof, it prints the capture end of frame + * trace event using @ref trace_capture_event_eof() + * - If the event ID is @ref camrtc_trace_capture_event_error, it prints the capture error trace + * event using @ref trace_capture_event_error() + * - If the event ID is @ref camrtc_trace_capture_event_reschedule, it prints the capture + * reschedule trace event using @ref trace_capture_event_reschedule() + * - If the event ID is @ref camrtc_trace_capture_event_reschedule_isp, it prints the capture + * reschedule ISP trace event using @ref trace_capture_event_reschedule_isp() + * - If the event ID is @ref camrtc_trace_capture_event_isp_done, it prints the capture ISP + * done trace event using @ref trace_capture_event_isp_done() + * - If the event ID is @ref camrtc_trace_capture_event_isp_error, it prints the capture ISP error + * trace event using @ref trace_capture_event_isp_error() + * - If the event ID is @ref camrtc_trace_capture_event_wdt, it prints the capture WDT trace + * event using @ref trace_capture_event_wdt() + * - If the event ID is @ref camrtc_trace_capture_event_report_program, it prints the capture + * report program trace event using @ref trace_capture_event_report_program() + * - If the event ID is @ref camrtc_trace_capture_event_suspend, it prints the capture suspend + * trace event using @ref trace_capture_event_suspend() + * - If the event ID is @ref camrtc_trace_capture_event_suspend_isp, it prints the capture suspend + * ISP trace event using @ref trace_capture_event_suspend_isp() + * - If the event ID is @ref camrtc_trace_capture_event_inject or + * @ref camrtc_trace_capture_event_sensor or unknown, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_capture_event(struct camrtc_event_struct *event) { const struct capture_event *ev = (const void *)&event->data; @@ -1166,6 +1569,20 @@ static void rtcpu_trace_capture_event(struct camrtc_event_struct *event) } } +/** + * @brief Trace performance events + * + * This function traces performance events based on the event ID. + * - If the event ID is @ref camrtc_trace_perf_reset, it prints the performance reset trace + * event using @ref trace_rtcpu_perf_reset() + * - If the event ID is @ref camrtc_trace_perf_counters, it prints the performance counters + * trace event using @ref trace_rtcpu_perf_counters() + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_perf_event(struct camrtc_event_struct *event) { const struct camrtc_trace_perf_counter_data *perf = (const void *)&event->data; @@ -1184,6 +1601,38 @@ static void rtcpu_trace_perf_event(struct camrtc_event_struct *event) } } +/** + * @brief Trace array events + * + * This function traces array events based on the event ID. + * - If the event ID is @ref CAMRTC_EVENT_MODULE_BASE, it parses the base event using + * @ref rtcpu_trace_base_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_RTOS, it parses the RTOS event using + * @ref rtcpu_trace_rtos_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_DBG, it parses the debug event using + * @ref rtcpu_trace_dbg_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_VINOTIFY, it parses the VINOTIFY event + * using @ref rtcpu_trace_vinotify_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_I2C, it parses the I2C event using + * @ref rtcpu_trace_i2c_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_VI, it parses the VI event using + * @ref rtcpu_trace_vi_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_ISP, it parses the ISP event using + * @ref rtcpu_trace_isp_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_NVCSI, it parses the NVCSI event using + * @ref rtcpu_trace_nvcsi_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_CAPTURE, it parses the capture event using + * @ref rtcpu_trace_capture_event() + * - If the event ID is @ref CAMRTC_EVENT_MODULE_PERF, it parses the performance event using + * @ref rtcpu_trace_perf_event() + * - If the event ID is not found, it prints the unknown trace event using + * @ref rtcpu_unknown_trace_event() + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_array_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -1223,6 +1672,30 @@ static void rtcpu_trace_array_event(struct tegra_rtcpu_trace *tracer, } } +/** + * @brief Trace log events + * + * This function traces log events. + * - If the id is not @ref camrtc_trace_type_string, it returns. + * - If the length is greater than @ref CAMRTC_TRACE_EVENT_PAYLOAD_SIZE, it ignores the NULs at + * the end of the buffer. + * - If the used is greater than the printk buffer size, it prints the log event using + * @ref pr_info() + * - Copies the log event to the printk buffer using @ref memcpy() + * - Updates the used with the length of the log event + * - Logs the log event using @ref tracer->printk() + * - If end is '\r' or '\n', it prints the log event using @ref tracer->printk() + * - Update @ref tracer->printk_used with the used + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] id Event ID. + * Valid Range: @ref camrtc_trace_type_string. + * @param[in] len Length of the log event. + * Valid Range: @ref CAMRTC_TRACE_EVENT_PAYLOAD_SIZE. + * @param[in] data8 Pointer to the log event. + * Valid Range: Non-NULL pointer. + */ static void trace_rtcpu_log(struct tegra_rtcpu_trace *tracer, uint32_t id, uint32_t len, const uint8_t *data8) { @@ -1273,6 +1746,29 @@ static void trace_rtcpu_log(struct tegra_rtcpu_trace *tracer, tracer->printk_used = used; } +/** + * @brief Processes a single RTCPU trace event + * + * This function processes a single RTCPU trace event based on its type + * - Gets the event id using @ref event->header.id + * - Extracts the event type using @ref CAMRTC_EVENT_TYPE_FROM_ID + * - Gets the event length using @ref rtcpu_trace_event_len + * - Gets a pointer to the event data + * - Based on event type, calls appropriate handler: + * - If type is @ref CAMRTC_EVENT_TYPE_ARRAY, calls @ref rtcpu_trace_array_event + * - If type is @ref CAMRTC_EVENT_TYPE_ARMV7_EXCEPTION, calls @ref trace_rtcpu_armv7_exception + * - If type is @ref CAMRTC_EVENT_TYPE_PAD, ignores the event + * - If type is @ref CAMRTC_EVENT_TYPE_START, calls @ref trace_rtcpu_start + * - If type is @ref CAMRTC_EVENT_TYPE_STRING, calls @ref trace_rtcpu_string and + * optionally @ref trace_rtcpu_log if printk is enabled + * - If type is @ref CAMRTC_EVENT_TYPE_BULK, calls @ref trace_rtcpu_bulk + * - For any other type, calls @ref rtcpu_unknown_trace_event + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] event Pointer to the camrtc_event_struct structure. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_event(struct tegra_rtcpu_trace *tracer, struct camrtc_event_struct *event) { @@ -1309,6 +1805,30 @@ static void rtcpu_trace_event(struct tegra_rtcpu_trace *tracer, } } +/** + * @brief Processes RTCPU trace events + * + * This function processes multiple RTCPU trace events + * - Gets the memory header from @ref tracer->trace_memory + * - Gets the old and new next index values + * - Checks if the new next index is valid (less than @ref tracer->event_entries) + * - Uses @ref array_index_nospec to validate the new next index + * - If old and new indices are the same, returns (no new events) + * - Wakes up polling processes using @ref wake_up_all + * - Invalidates cache entries using @ref rtcpu_trace_invalidate_entries + * - Processes events in the range between old and new indices: + * - Uses @ref array_index_nospec to validate the old next index + * - Gets a pointer to the event + * - Processes the event using @ref rtcpu_trace_event + * - Increments the events counter using @ref wrap_add_u32 + * - Increments the old next index using @ref wrap_add_u32 + * - Handles wraparound of the index at the end of the buffer + * - Updates @ref tracer->event_last_idx with the new next index + * - Makes a copy of the last event + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + */ static inline void rtcpu_trace_events(struct tegra_rtcpu_trace *tracer) { const struct camrtc_trace_memory_header *header = tracer->trace_memory; @@ -1354,6 +1874,20 @@ static inline void rtcpu_trace_events(struct tegra_rtcpu_trace *tracer) tracer->copy_last_event = *last_event; } +/** + * @brief Flushes the RTCPU trace buffer + * + * This function flushes the RTCPU trace buffer by processing all available trace events + * - Checks if @ref tracer is NULL, returns if it is + * - Locks the tracer mutex using @ref mutex_lock + * - Invalidates the cache line for pointers using @ref dma_sync_single_for_cpu + * - Processes exceptions using @ref rtcpu_trace_exceptions + * - Processes events using @ref rtcpu_trace_events + * - Unlocks the mutex using @ref mutex_unlock + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: NULL or valid pointer. + */ void tegra_rtcpu_trace_flush(struct tegra_rtcpu_trace *tracer) { if (tracer == NULL) @@ -1373,6 +1907,17 @@ void tegra_rtcpu_trace_flush(struct tegra_rtcpu_trace *tracer) } EXPORT_SYMBOL(tegra_rtcpu_trace_flush); +/** + * @brief Worker function for periodic trace processing + * + * This function is executed periodically as a delayed work item + * - Retrieves the tracer structure using @ref container_of + * - Flushes the trace buffer using @ref tegra_rtcpu_trace_flush + * - Reschedules itself using @ref schedule_delayed_work + * + * @param[in] work Pointer to the work_struct within the tracer. + * Valid Range: Non-NULL pointer. + */ static void rtcpu_trace_worker(struct work_struct *work) { struct tegra_rtcpu_trace *tracer; @@ -1385,6 +1930,42 @@ static void rtcpu_trace_worker(struct work_struct *work) schedule_delayed_work(&tracer->work, tracer->work_interval_jiffies); } +/** + * @brief Implementation for reading raw trace events + * + * This function implements the raw trace reading mechanism + * - Gets the memory header from @ref tracer->trace_memory + * - Gets the old and new next index values + * - Validates that the new next index is within range + * - Uses @ref array_index_nospec to validate indices + * - If old and new indices are the same, returns (no new events) + * - Invalidates cache entries using @ref rtcpu_trace_invalidate_entries + * - Determines if buffer has wrapped around + * - Calculates number of events to copy based on available events and requested amount + * - Checks for multiplication overflow using @ref check_mul_overflow + * - Handles copying events to user space with or without buffer wraparound: + * - For non-wrapped buffer, copies events directly using @ref copy_to_user + * - For wrapped buffer, copies events in two parts using @ref copy_to_user + * - First part from old_next to end of buffer + * - Second part from beginning of buffer + * - Updates the last read event index + * - Updates the number of events copied + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * @param[in] user_buffer User space buffer to copy events to. + * Valid Range: Valid user space pointer. + * @param[in,out] events_copied Pointer to number of events already copied. + * Valid Range: Non-NULL pointer. + * @param[in,out] last_read_event_idx Pointer to the last read event index. + * Valid Range: Non-NULL pointer. + * @param[in] num_events_requested Number of events requested to be read. + * Valid Range: > 0. + * + * @retval 0 Success + * @retval -EIO Invalid trace entry + * @retval -EFAULT Error copying data to user space or overflow + */ static int32_t raw_trace_read_impl( struct tegra_rtcpu_trace *tracer, char __user *user_buffer, @@ -1488,6 +2069,25 @@ static int32_t raw_trace_read_impl( return 0; } +/** + * @brief Checks if new trace events are available for reading + * + * This function determines if there are new events available since the last read + * - Gets the last read event index from @ref fd_context + * - Gets the memory header from @ref tracer->trace_memory + * - For first read call, handles special case when buffer has wrapped: + * - If @ref header->wrapped_counter is greater than 0, sets read index to next position + * - Handles wraparound at the end of the buffer + * - Compares the current event index with last read index to determine if new events exist + * + * @param[in] fd_context Pointer to the rtcpu_raw_trace_context structure. + * Valid Range: Non-NULL pointer. + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * + * @retval true New events are available + * @retval false No new events are available + */ static bool check_event_availability( struct rtcpu_raw_trace_context *fd_context, struct tegra_rtcpu_trace *tracer) @@ -1515,6 +2115,38 @@ static bool check_event_availability( return ret; } +/** + * @brief Implements the read file operation for the RTCPU raw trace device + * + * This function reads trace events from the RTCPU trace buffer into a user-supplied buffer + * - Gets the file descriptor context from @ref file->private_data + * - Validates file context and tracer, returns error if either is invalid + * - Handles special case for first read when buffer has wrapped around + * - Truncates requested buffer size if it exceeds @ref MAX_READ_SIZE + * - Calculates number of requested events based on buffer size + * - Validates user buffer address using @ref access_ok + * - Reads events using @ref raw_trace_read_impl in a loop: + * - For non-blocking calls, performs a single read attempt + * - For blocking calls, waits for events using @ref wait_event_interruptible + * and @ref check_event_availability until requested number of events is read + * - Updates the file context with last read event index + * - Calculates total bytes read using @ref check_mul_overflow + * + * @param[in] file Pointer to the file structure. + * Valid Range: Non-NULL pointer. + * @param[out] user_buffer User space buffer to copy events to. + * Valid Range: Valid user space pointer. + * @param[in] buffer_size Size of the user buffer in bytes. + * Valid Range: > sizeof(struct camrtc_event_struct). + * @param[in,out] ppos Pointer to the file position (ignored). + * Valid Range: Any. + * + * @retval >0 Number of bytes successfully read + * @retval -ENODEV File descriptor context or tracer not set + * @retval -ENOMEM Requested buffer size too small for even one event + * @retval -EINVAL Invalid user buffer address or multiplication overflow + * @retval (int) Return code propagated from raw_trace_read_impl or wait_event_interruptible + */ static ssize_t rtcpu_raw_trace_read(struct file *file, char __user *user_buffer, size_t buffer_size, loff_t *ppos) { @@ -1612,6 +2244,29 @@ rtcpu_raw_trace_read(struct file *file, char __user *user_buffer, size_t buffer_ return events_amount; } +/** + * @brief Implements the write file operation for the RTCPU raw trace device + * + * This function is called when a user writes to the raw trace device file + * - Gets the file context from @ref file->private_data + * - Validates file context and tracer + * - Gets the memory header from @ref tracer->trace_memory + * - Updates the last read event index to the current event next index + * - Updates the file context in @ref file->private_data + * - Returns the buffer size (write is effectively a reset operation) + * + * @param[in/out] file Pointer to the file structure. + * Valid Range: Non-NULL pointer. + * @param[in] user_buffer User space buffer (not used). + * Valid Range: Any. + * @param[in] buffer_size Size of the user buffer in bytes. + * Valid Range: Any. + * @param[in,out] ppos Pointer to the file position (not used). + * Valid Range: Any. + * + * @retval buffer_size Size of the input buffer (always successful) + * @retval -ENODEV File descriptor context or tracer not set + */ static ssize_t rtcpu_raw_trace_write( struct file *file, const char __user *user_buffer, size_t buffer_size, loff_t *ppos) { @@ -1639,6 +2294,26 @@ static ssize_t rtcpu_raw_trace_write( return buffer_size; } +/** + * @brief Implements the poll file operation for the RTCPU raw trace device + * + * This function is called when a user polls the raw trace device file + * - Gets the file context from @ref file->private_data + * - Validates file context and tracer + * - Checks for event availability using @ref check_event_availability + * - If events are available, returns POLLIN and POLLRDNORM flags + * - If no events are available, registers the wait queue using @ref poll_wait + * - Wait queue will be woken up by @ref rtcpu_trace_events when new events arrive + * + * @param[in] file Pointer to the file structure. + * Valid Range: Non-NULL pointer. + * @param[in] wait Pointer to the poll_table structure. + * Valid Range: May be NULL. + * + * @retval 0 No events available + * @retval POLLIN|POLLRDNORM Events are available for reading + * @retval -ENODEV File descriptor context or tracer not set + */ static unsigned int rtcpu_raw_trace_poll(struct file *file, poll_table *wait) { struct tegra_rtcpu_trace *tracer; @@ -1670,6 +2345,29 @@ static unsigned int rtcpu_raw_trace_poll(struct file *file, poll_table *wait) return ret; } +/** + * @brief Implements the open file operation for the RTCPU raw trace device + * + * This function is called when a user opens the raw trace device file + * - Allocates a new file descriptor context using @ref kzalloc + * - Retrieves the tracer using @ref container_of from the inode's cdev + * - Validates the tracer + * - Initializes the file descriptor context: + * - Sets the tracer reference + * - Sets the last read event index to 0 + * - Sets first_read_call to true to handle special first read case + * - Stores the context in @ref file->private_data for future operations + * - Calls @ref nonseekable_open to complete the file opening + * + * @param[in] inode Pointer to the inode structure. + * Valid Range: Non-NULL pointer. + * @param[in] file Pointer to the file structure. + * Valid Range: Non-NULL pointer. + * + * @retval (int) Return code propagated from @ref nonseekable_open() + * @retval -ENOMEM Failed to allocate file descriptor context + * @retval -ENODEV Failed to retrieve tracer + */ static int rtcpu_raw_trace_open(struct inode *inode, struct file *file) { struct tegra_rtcpu_trace *tracer; @@ -1695,6 +2393,20 @@ static int rtcpu_raw_trace_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } +/** + * @brief Implements the release file operation for the RTCPU raw trace device + * + * This function is called when a user closes the raw trace device file + * - Frees the file descriptor context using @ref kfree + * - The context contains references to the tracer and read position state + * + * @param[in] inode Pointer to the inode structure (not used). + * Valid Range: Any. + * @param[in] file Pointer to the file structure containing private_data. + * Valid Range: Non-NULL pointer with valid private_data. + * + * @retval 0 Always successful + */ static int rtcpu_raw_trace_release(struct inode *inode, struct file *file) { kfree(file->private_data); @@ -1841,6 +2553,24 @@ failed_create: /* Character device */ static struct class *rtcpu_raw_trace_class; static int rtcpu_raw_trace_major; + +/** + * @brief Registers the RTCPU raw trace device driver + * + * This function registers the character device driver for the raw trace device + * - Registers a character device using @ref register_chrdev + * - Creates a device number using @ref MKDEV + * - Initializes the character device using @ref cdev_init + * - Adds the character device to the system using @ref cdev_add + * - Creates a device class using @ref class_create + * - Creates a device node using @ref device_create + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + * + * @retval 0 Success + * @retval <0 Error code from register_chrdev, cdev_add, or class_create + */ static int raw_trace_node_drv_register(struct tegra_rtcpu_trace *tracer) { dev_t devt; @@ -1883,6 +2613,19 @@ static int raw_trace_node_drv_register(struct tegra_rtcpu_trace *tracer) return 0; } +/** + * @brief Unregisters the RTCPU raw trace device driver + * + * This function cleans up the character device driver registration + * - Creates a device number using @ref MKDEV + * - Destroys the device node using @ref device_destroy + * - Deletes the character device using @ref cdev_del + * - Destroys the device class using @ref class_destroy + * - Unregisters the character device using @ref unregister_chrdev + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: Non-NULL pointer. + */ static void raw_trace_node_unregister( struct tegra_rtcpu_trace *tracer) { @@ -1903,6 +2646,30 @@ static void raw_trace_node_unregister( * Init/Cleanup */ +/** + * @brief Creates and initializes a new RTCPU trace structure + * + * This function allocates and initializes all resources needed for tracing + * - Allocates memory for the trace structure using @ref kzalloc + * - Initializes the mutex using @ref mutex_init + * - Sets up trace memory using @ref rtcpu_trace_setup_memory + * - Initializes trace memory using @ref rtcpu_trace_init_memory + * - Initializes debugfs entries using @ref rtcpu_trace_debugfs_init + * - Gets camera devices using @ref camrtc_device_get_byname for ISP and VI + * - Initializes the wait queue using @ref init_waitqueue_head + * - Reads device tree properties for configuration + * - Initializes and schedules the worker using @ref INIT_DELAYED_WORK and + * @ref schedule_delayed_work + * - Registers the character device driver using @ref raw_trace_node_drv_register + * + * @param[in] dev Pointer to the device structure. + * Valid Range: Non-NULL pointer. + * @param[in] camera_devices Pointer to the camera device group structure. + * Valid Range: NULL or valid pointer. + * + * @retval Non-NULL pointer to tegra_rtcpu_trace structure on success + * @retval NULL if memory allocation, device tree reading, or device registration fails + */ struct tegra_rtcpu_trace *tegra_rtcpu_trace_create(struct device *dev, struct camrtc_device_group *camera_devices) { @@ -2003,6 +2770,19 @@ struct tegra_rtcpu_trace *tegra_rtcpu_trace_create(struct device *dev, } EXPORT_SYMBOL(tegra_rtcpu_trace_create); +/** + * @brief Synchronizes the RTCPU trace memory with the device + * + * This function sets up the I/O virtual memory mapping for RTCPU trace buffer + * in the RTCPU memory space. This must be called after the RTCPU has booted + * to ensure the trace buffer is visible to the RTCPU. + * + * @param[in] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: NULL or valid pointer. + * + * @retval 0 Success or tracer was NULL + * @retval -EIO IOVM setup error + */ int tegra_rtcpu_trace_boot_sync(struct tegra_rtcpu_trace *tracer) { int ret; @@ -2020,6 +2800,23 @@ int tegra_rtcpu_trace_boot_sync(struct tegra_rtcpu_trace *tracer) } EXPORT_SYMBOL(tegra_rtcpu_trace_boot_sync); +/** + * @brief Cleans up and destroys an RTCPU trace structure + * + * This function frees all resources allocated for the RTCPU trace structure + * - Validates the tracer pointer is not NULL or ERR_PTR + * - Releases platform devices references using @ref platform_device_put + * - Releases device tree node using @ref of_node_put + * - Cancels and flushes the periodic worker using @ref cancel_delayed_work_sync + * and @ref flush_delayed_work + * - Unregisters the character device driver using @ref raw_trace_node_unregister + * - Cleans up debugfs entries using @ref rtcpu_trace_debugfs_deinit + * - Frees DMA memory using @ref dma_free_coherent + * - Frees the tracer structure using @ref kfree + * + * @param[in/out] tracer Pointer to the tegra_rtcpu_trace structure. + * Valid Range: NULL, ERR_PTR, or valid pointer. + */ void tegra_rtcpu_trace_destroy(struct tegra_rtcpu_trace *tracer) { if (IS_ERR_OR_NULL(tracer))