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))