Loading drivers/media/platform/msm/npu/npu_common.h +22 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/uaccess.h> #include <linux/mailbox/qmp.h> #include <linux/msm-bus.h> #include <linux/mailbox_controller.h> #include "npu_mgr.h" Loading @@ -30,7 +31,7 @@ * Defines * ------------------------------------------------------------------------- */ #define NPU_MAX_MBOX_NUM 2 #define NPU_MAX_MBOX_NUM 4 #define NPU_MBOX_LOW_PRI 0 #define NPU_MBOX_HIGH_PRI 1 Loading Loading @@ -117,6 +118,9 @@ struct npu_mbox { struct mbox_chan *chan; struct npu_device *npu_dev; uint32_t id; uint32_t client_id; uint32_t signal_id; bool send_data_pending; }; /** Loading Loading @@ -217,6 +221,12 @@ struct npu_bwctrl { uint32_t num_paths; }; struct mbox_bridge_data { struct mbox_controller mbox; struct mbox_chan *chans; void *priv_data; }; struct npu_device { struct mutex dev_lock; Loading Loading @@ -249,7 +259,9 @@ struct npu_device { struct npu_smmu_ctx smmu_ctx; struct npu_debugfs_ctx debugfs_ctx; struct npu_mbox mbox_aop; struct npu_mbox *mbox_aop; struct npu_mbox mbox[NPU_MAX_MBOX_NUM]; struct mbox_bridge_data mbox_bridge_data; struct thermal_cooling_device *tcdev; struct npu_pwrctrl pwrctrl; Loading Loading @@ -278,6 +290,14 @@ struct npu_client { struct list_head mapped_buffer_list; }; struct ipcc_mbox_chan { u16 client_id; u16 signal_id; struct mbox_chan *chan; struct npu_mbox *npu_mbox; struct npu_device *npu_dev; }; /* ------------------------------------------------------------------------- * Function Prototypes * ------------------------------------------------------------------------- Loading drivers/media/platform/msm/npu/npu_dev.c +209 −16 Original line number Diff line number Diff line Loading @@ -1727,32 +1727,225 @@ static int npu_irq_init(struct npu_device *npu_dev) return ret; } /* ------------------------------------------------------------------------- * Mailbox * ------------------------------------------------------------------------- */ static int npu_ipcc_bridge_mbox_send_data(struct mbox_chan *chan, void *data) { struct ipcc_mbox_chan *ipcc_mbox_chan = chan->con_priv; struct npu_device *npu_dev = ipcc_mbox_chan->npu_dev; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; unsigned long flags; NPU_DBG("Generating IRQ for client_id: %u; signal_id: %u\n", ipcc_mbox_chan->client_id, ipcc_mbox_chan->signal_id); spin_lock_irqsave(&host_ctx->bridge_mbox_lock, flags); ipcc_mbox_chan->npu_mbox->send_data_pending = true; queue_work(host_ctx->wq, &host_ctx->bridge_mbox_work); spin_unlock_irqrestore(&host_ctx->bridge_mbox_lock, flags); return 0; } static void npu_ipcc_bridge_mbox_shutdown(struct mbox_chan *chan) { struct ipcc_mbox_chan *ipcc_mbox_chan = chan->con_priv; chan->con_priv = NULL; kfree(ipcc_mbox_chan); } static struct mbox_chan *npu_ipcc_bridge_mbox_xlate( struct mbox_controller *mbox, const struct of_phandle_args *ph) { int chan_id, i; struct npu_device *npu_dev; struct mbox_bridge_data *bridge_data; struct ipcc_mbox_chan *ipcc_mbox_chan; bridge_data = container_of(mbox, struct mbox_bridge_data, mbox); if (WARN_ON(!bridge_data)) return ERR_PTR(-EINVAL); npu_dev = bridge_data->priv_data; if (ph->args_count != 2) return ERR_PTR(-EINVAL); for (chan_id = 0; chan_id < mbox->num_chans; chan_id++) { ipcc_mbox_chan = bridge_data->chans[chan_id].con_priv; if (!ipcc_mbox_chan) break; else if (ipcc_mbox_chan->client_id == ph->args[0] && ipcc_mbox_chan->signal_id == ph->args[1]) return ERR_PTR(-EBUSY); } if (chan_id >= mbox->num_chans) return ERR_PTR(-EBUSY); /* search for target mailbox */ for (i = 0; i < NPU_MAX_MBOX_NUM; i++) { if (npu_dev->mbox[i].chan && (npu_dev->mbox[i].client_id == ph->args[0]) && (npu_dev->mbox[i].signal_id == ph->args[1])) { NPU_DBG("Find matched target mailbox %d\n", i); break; } } if (i == NPU_MAX_MBOX_NUM) { NPU_ERR("Can't find matched target mailbox %d:%d\n", ph->args[0], ph->args[1]); return ERR_PTR(-EINVAL); } ipcc_mbox_chan = kzalloc(sizeof(*ipcc_mbox_chan), GFP_KERNEL); if (!ipcc_mbox_chan) return ERR_PTR(-ENOMEM); ipcc_mbox_chan->client_id = ph->args[0]; ipcc_mbox_chan->signal_id = ph->args[1]; ipcc_mbox_chan->chan = &bridge_data->chans[chan_id]; ipcc_mbox_chan->npu_dev = npu_dev; ipcc_mbox_chan->chan->con_priv = ipcc_mbox_chan; ipcc_mbox_chan->npu_mbox = &npu_dev->mbox[i]; NPU_DBG("New mailbox channel: %u for client_id: %u; signal_id: %u\n", chan_id, ipcc_mbox_chan->client_id, ipcc_mbox_chan->signal_id); return ipcc_mbox_chan->chan; } static const struct mbox_chan_ops ipcc_mbox_chan_ops = { .send_data = npu_ipcc_bridge_mbox_send_data, .shutdown = npu_ipcc_bridge_mbox_shutdown }; static int npu_setup_ipcc_bridge_mbox(struct npu_device *npu_dev) { int i, j, ret; int num_chans = 0; struct mbox_controller *mbox; struct device_node *client_dn; struct of_phandle_args curr_ph; struct device *dev = &npu_dev->pdev->dev; struct device_node *controller_dn = dev->of_node; struct mbox_bridge_data *mbox_data = &npu_dev->mbox_bridge_data; NPU_DBG("Setup ipcc brige mbox\n"); /* * Find out the number of clients interested in this mailbox * and create channels accordingly. */ for_each_node_with_property(client_dn, "mboxes") { if (!of_device_is_available(client_dn)) { NPU_DBG("No node available\n"); continue; } i = of_count_phandle_with_args(client_dn, "mboxes", "#mbox-cells"); for (j = 0; j < i; j++) { ret = of_parse_phandle_with_args(client_dn, "mboxes", "#mbox-cells", j, &curr_ph); of_node_put(curr_ph.np); if (!ret && curr_ph.np == controller_dn) { NPU_DBG("Found a client\n"); num_chans++; break; } } } /* If no clients are found, skip registering as a mbox controller */ if (!num_chans) { NPU_WARN("Can't find ipcc bridge mbox client\n"); return 0; } mbox_data->chans = devm_kcalloc(dev, num_chans, sizeof(struct mbox_chan), GFP_KERNEL); if (!mbox_data->chans) return -ENOMEM; mbox_data->priv_data = npu_dev; mbox = &mbox_data->mbox; mbox->dev = dev; mbox->num_chans = num_chans; mbox->chans = mbox_data->chans; mbox->ops = &ipcc_mbox_chan_ops; mbox->of_xlate = npu_ipcc_bridge_mbox_xlate; mbox->txdone_irq = false; mbox->txdone_poll = false; return mbox_controller_register(mbox); } static int npu_mbox_init(struct npu_device *npu_dev) { struct platform_device *pdev = npu_dev->pdev; struct npu_mbox *mbox_aop = &npu_dev->mbox_aop; struct npu_mbox *mbox = NULL; struct property *prop; const char *mbox_name; uint32_t index = 0; int ret = 0; struct of_phandle_args curr_ph; if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { mbox_aop->client.dev = &pdev->dev; mbox_aop->client.tx_block = true; mbox_aop->client.tx_tout = MBOX_OP_TIMEOUTMS; mbox_aop->client.knows_txdone = false; if (!of_get_property(pdev->dev.of_node, "mbox-names", NULL) || !of_find_property(pdev->dev.of_node, "mboxes", NULL)) { NPU_WARN("requires mbox-names and mboxes property\n"); return 0; } mbox_aop->chan = mbox_request_channel(&mbox_aop->client, 0); if (IS_ERR(mbox_aop->chan)) { NPU_WARN("aop mailbox is not available\n"); mbox_aop->chan = NULL; of_property_for_each_string(pdev->dev.of_node, "mbox-names", prop, mbox_name) { NPU_DBG("setup mbox[%d] %s\n", index, mbox_name); mbox = &npu_dev->mbox[index]; mbox->client.dev = &pdev->dev; mbox->client.knows_txdone = true; mbox->chan = mbox_request_channel(&mbox->client, index); if (IS_ERR(mbox->chan)) { NPU_WARN("mailbox %s is not available\n", mbox_name); mbox->chan = NULL; } else if (!strcmp(mbox_name, "aop")) { npu_dev->mbox_aop = mbox; } else { ret = of_parse_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells", index, &curr_ph); of_node_put(curr_ph.np); if (ret) { NPU_WARN("can't get mailbox %s args\n", mbox_name); } else { mbox->client_id = curr_ph.args[0]; mbox->signal_id = curr_ph.args[1]; NPU_DBG("argument for mailbox %x is %x %x\n", mbox_name, curr_ph.args[0], curr_ph.args[1]); } } index++; } return 0; return npu_setup_ipcc_bridge_mbox(npu_dev); } static void npu_mbox_deinit(struct npu_device *npu_dev) { if (npu_dev->mbox_aop.chan) { mbox_free_channel(npu_dev->mbox_aop.chan); npu_dev->mbox_aop.chan = NULL; int i; mbox_controller_unregister(&npu_dev->mbox_bridge_data.mbox); for (i = 0; i < NPU_MAX_MBOX_NUM; i++) { if (!npu_dev->mbox[i].chan) continue; mbox_free_channel(npu_dev->mbox[i].chan); npu_dev->mbox[i].chan = NULL; } } Loading drivers/media/platform/msm/npu/npu_mgr.c +95 −9 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ */ static void npu_ipc_irq_work(struct work_struct *work); static void npu_wdg_err_irq_work(struct work_struct *work); static void npu_bridge_mbox_work(struct work_struct *work); static void npu_disable_fw_work(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_status_ready(struct npu_device *npu_dev, uint32_t status_reg, uint32_t status_bits); Loading Loading @@ -193,19 +195,16 @@ int unload_fw(struct npu_device *npu_dev) return 0; } int enable_fw(struct npu_device *npu_dev) static int enable_fw_nolock(struct npu_device *npu_dev) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret = 0; mutex_lock(&host_ctx->lock); if (host_ctx->fw_state == FW_UNLOADED) { ret = load_fw_nolock(npu_dev, host_ctx->auto_pil_disable ? true : false); if (ret) { NPU_ERR("load fw failed\n"); mutex_unlock(&host_ctx->lock); return ret; } Loading @@ -220,7 +219,6 @@ int enable_fw(struct npu_device *npu_dev) if (host_ctx->fw_state == FW_ENABLED) { host_ctx->fw_ref_cnt++; NPU_DBG("fw_ref_cnt %d\n", host_ctx->fw_ref_cnt); mutex_unlock(&host_ctx->lock); return 0; } Loading Loading @@ -275,7 +273,7 @@ int enable_fw(struct npu_device *npu_dev) host_ctx->fw_error = false; host_ctx->fw_ref_cnt++; mutex_unlock(&host_ctx->lock); enable_log: /* Set logging state */ Loading @@ -294,7 +292,18 @@ int enable_fw(struct npu_device *npu_dev) enable_sys_cache_fail: npu_disable_core_power(npu_dev); enable_pw_fail: return ret; } int enable_fw(struct npu_device *npu_dev) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret; mutex_lock(&host_ctx->lock); ret = enable_fw_nolock(npu_dev); mutex_unlock(&host_ctx->lock); return ret; } Loading Loading @@ -449,7 +458,7 @@ static int npu_notifier_cb(struct notifier_block *this, unsigned long code, break; } npu_cc_reg_write(npu_dev, NPU_CC_NPU_CPC_RSC_CTRL, 0); npu_cc_reg_write(npu_dev, NPU_CC_NPU_CPC_RSC_CTRL, 3); /* Clear control/status registers */ REGW(npu_dev, REG_NPU_FW_CTRL_STATUS, 0x0); Loading Loading @@ -516,6 +525,7 @@ int npu_host_init(struct npu_device *npu_dev) init_completion(&host_ctx->fw_bringup_done); init_completion(&host_ctx->fw_shutdown_done); mutex_init(&host_ctx->lock); spin_lock_init(&host_ctx->bridge_mbox_lock); atomic_set(&host_ctx->ipc_trans_id, 1); host_ctx->npu_dev = npu_dev; Loading @@ -534,6 +544,9 @@ int npu_host_init(struct npu_device *npu_dev) } else { INIT_WORK(&host_ctx->ipc_irq_work, npu_ipc_irq_work); INIT_WORK(&host_ctx->wdg_err_irq_work, npu_wdg_err_irq_work); INIT_WORK(&host_ctx->bridge_mbox_work, npu_bridge_mbox_work); INIT_DELAYED_WORK(&host_ctx->disable_fw_work, npu_disable_fw_work); } if (npu_dev->hw_version != 0x20000000) Loading Loading @@ -768,6 +781,79 @@ static void npu_wdg_err_irq_work(struct work_struct *work) host_error_hdlr(npu_dev, false); } static void npu_disable_fw_work(struct work_struct *work) { struct npu_host_ctx *host_ctx; struct npu_device *npu_dev; NPU_DBG("Enter disable fw work\n"); host_ctx = container_of(work, struct npu_host_ctx, disable_fw_work.work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); mutex_lock(&host_ctx->lock); disable_fw_nolock(npu_dev); host_ctx->bridge_mbox_pwr_on = false; mutex_unlock(&host_ctx->lock); NPU_DBG("Exit disable fw work\n"); } static int npu_bridge_mbox_send_data(struct npu_host_ctx *host_ctx, struct npu_mbox *mbox, void *data) { NPU_DBG("Generating IRQ for client_id: %u; signal_id: %u\n", mbox->client_id, mbox->signal_id); mbox_send_message(mbox->chan, NULL); mbox_client_txdone(mbox->chan, 0); mbox->send_data_pending = false; return 0; } static void npu_bridge_mbox_work(struct work_struct *work) { int i, ret; struct npu_host_ctx *host_ctx; struct npu_device *npu_dev; unsigned long flags; NPU_DBG("Enter bridge mbox work\n"); host_ctx = container_of(work, struct npu_host_ctx, bridge_mbox_work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); /* queue or modify delayed work to disable fw */ mod_delayed_work(host_ctx->wq, &host_ctx->disable_fw_work, NPU_MBOX_IDLE_TIMEOUT); mutex_lock(&host_ctx->lock); if (host_ctx->fw_state == FW_UNLOADED) { NPU_WARN("NPU fw is not loaded\n"); mutex_unlock(&host_ctx->lock); return; } if (!host_ctx->bridge_mbox_pwr_on) { ret = enable_fw_nolock(npu_dev); if (ret) { mutex_unlock(&host_ctx->lock); NPU_ERR("Enable fw failed\n"); return; } host_ctx->bridge_mbox_pwr_on = true; NPU_DBG("Fw is enabled by mbox\n"); } spin_lock_irqsave(&host_ctx->bridge_mbox_lock, flags); for (i = 0; i < NPU_MAX_MBOX_NUM; i++) if (npu_dev->mbox[i].send_data_pending) npu_bridge_mbox_send_data(host_ctx, &npu_dev->mbox[i], NULL); spin_unlock_irqrestore(&host_ctx->bridge_mbox_lock, flags); mutex_unlock(&host_ctx->lock); NPU_DBG("Exit bridge mbox work\n"); } static void turn_off_fw_logging(struct npu_device *npu_dev) { struct ipc_cmd_log_state_pkt log_packet; Loading Loading @@ -828,7 +914,7 @@ static int npu_notify_aop(struct npu_device *npu_dev, bool on) struct qmp_pkt pkt; int buf_size, rc = 0; if (!npu_dev->mbox_aop.chan) { if (!npu_dev->mbox_aop || !npu_dev->mbox_aop->chan) { NPU_WARN("aop mailbox channel is not available\n"); return 0; } Loading @@ -845,7 +931,7 @@ static int npu_notify_aop(struct npu_device *npu_dev, bool on) pkt.size = (buf_size + 3) & ~0x3; pkt.data = buf; rc = mbox_send_message(npu_dev->mbox_aop.chan, &pkt); rc = mbox_send_message(npu_dev->mbox_aop->chan, &pkt); if (rc < 0) NPU_ERR("qmp message send failed, ret=%d\n", rc); Loading drivers/media/platform/msm/npu/npu_mgr.h +6 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #define NW_CMD_TIMEOUT msecs_to_jiffies(NW_CMD_TIMEOUT_MS) #define NW_DEBUG_TIMEOUT_MS (1000 * 60 * 30) /* set for 30 minutes */ #define NW_DEBUG_TIMEOUT msecs_to_jiffies(NW_DEBUG_TIMEOUT_MS) #define NPU_MBOX_IDLE_TIMEOUT_MS 500 /* set for 500ms */ #define NPU_MBOX_IDLE_TIMEOUT msecs_to_jiffies(NPU_MBOX_IDLE_TIMEOUT_MS) #define FIRMWARE_VERSION 0x00001000 #define MAX_LOADED_NETWORK 32 #define NPU_IPC_BUF_LENGTH 512 Loading Loading @@ -74,6 +76,8 @@ struct npu_host_ctx { int32_t power_vote_num; struct work_struct ipc_irq_work; struct work_struct wdg_err_irq_work; struct work_struct bridge_mbox_work; struct delayed_work disable_fw_work; struct workqueue_struct *wq; struct completion misc_cmd_done; struct completion fw_deinit_done; Loading @@ -96,6 +100,8 @@ struct npu_host_ctx { uint32_t misc_cmd_result; struct notifier_block nb; void *notif_hdle; spinlock_t bridge_mbox_lock; bool bridge_mbox_pwr_on; }; struct npu_device; Loading Loading
drivers/media/platform/msm/npu/npu_common.h +22 −2 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/uaccess.h> #include <linux/mailbox/qmp.h> #include <linux/msm-bus.h> #include <linux/mailbox_controller.h> #include "npu_mgr.h" Loading @@ -30,7 +31,7 @@ * Defines * ------------------------------------------------------------------------- */ #define NPU_MAX_MBOX_NUM 2 #define NPU_MAX_MBOX_NUM 4 #define NPU_MBOX_LOW_PRI 0 #define NPU_MBOX_HIGH_PRI 1 Loading Loading @@ -117,6 +118,9 @@ struct npu_mbox { struct mbox_chan *chan; struct npu_device *npu_dev; uint32_t id; uint32_t client_id; uint32_t signal_id; bool send_data_pending; }; /** Loading Loading @@ -217,6 +221,12 @@ struct npu_bwctrl { uint32_t num_paths; }; struct mbox_bridge_data { struct mbox_controller mbox; struct mbox_chan *chans; void *priv_data; }; struct npu_device { struct mutex dev_lock; Loading Loading @@ -249,7 +259,9 @@ struct npu_device { struct npu_smmu_ctx smmu_ctx; struct npu_debugfs_ctx debugfs_ctx; struct npu_mbox mbox_aop; struct npu_mbox *mbox_aop; struct npu_mbox mbox[NPU_MAX_MBOX_NUM]; struct mbox_bridge_data mbox_bridge_data; struct thermal_cooling_device *tcdev; struct npu_pwrctrl pwrctrl; Loading Loading @@ -278,6 +290,14 @@ struct npu_client { struct list_head mapped_buffer_list; }; struct ipcc_mbox_chan { u16 client_id; u16 signal_id; struct mbox_chan *chan; struct npu_mbox *npu_mbox; struct npu_device *npu_dev; }; /* ------------------------------------------------------------------------- * Function Prototypes * ------------------------------------------------------------------------- Loading
drivers/media/platform/msm/npu/npu_dev.c +209 −16 Original line number Diff line number Diff line Loading @@ -1727,32 +1727,225 @@ static int npu_irq_init(struct npu_device *npu_dev) return ret; } /* ------------------------------------------------------------------------- * Mailbox * ------------------------------------------------------------------------- */ static int npu_ipcc_bridge_mbox_send_data(struct mbox_chan *chan, void *data) { struct ipcc_mbox_chan *ipcc_mbox_chan = chan->con_priv; struct npu_device *npu_dev = ipcc_mbox_chan->npu_dev; struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; unsigned long flags; NPU_DBG("Generating IRQ for client_id: %u; signal_id: %u\n", ipcc_mbox_chan->client_id, ipcc_mbox_chan->signal_id); spin_lock_irqsave(&host_ctx->bridge_mbox_lock, flags); ipcc_mbox_chan->npu_mbox->send_data_pending = true; queue_work(host_ctx->wq, &host_ctx->bridge_mbox_work); spin_unlock_irqrestore(&host_ctx->bridge_mbox_lock, flags); return 0; } static void npu_ipcc_bridge_mbox_shutdown(struct mbox_chan *chan) { struct ipcc_mbox_chan *ipcc_mbox_chan = chan->con_priv; chan->con_priv = NULL; kfree(ipcc_mbox_chan); } static struct mbox_chan *npu_ipcc_bridge_mbox_xlate( struct mbox_controller *mbox, const struct of_phandle_args *ph) { int chan_id, i; struct npu_device *npu_dev; struct mbox_bridge_data *bridge_data; struct ipcc_mbox_chan *ipcc_mbox_chan; bridge_data = container_of(mbox, struct mbox_bridge_data, mbox); if (WARN_ON(!bridge_data)) return ERR_PTR(-EINVAL); npu_dev = bridge_data->priv_data; if (ph->args_count != 2) return ERR_PTR(-EINVAL); for (chan_id = 0; chan_id < mbox->num_chans; chan_id++) { ipcc_mbox_chan = bridge_data->chans[chan_id].con_priv; if (!ipcc_mbox_chan) break; else if (ipcc_mbox_chan->client_id == ph->args[0] && ipcc_mbox_chan->signal_id == ph->args[1]) return ERR_PTR(-EBUSY); } if (chan_id >= mbox->num_chans) return ERR_PTR(-EBUSY); /* search for target mailbox */ for (i = 0; i < NPU_MAX_MBOX_NUM; i++) { if (npu_dev->mbox[i].chan && (npu_dev->mbox[i].client_id == ph->args[0]) && (npu_dev->mbox[i].signal_id == ph->args[1])) { NPU_DBG("Find matched target mailbox %d\n", i); break; } } if (i == NPU_MAX_MBOX_NUM) { NPU_ERR("Can't find matched target mailbox %d:%d\n", ph->args[0], ph->args[1]); return ERR_PTR(-EINVAL); } ipcc_mbox_chan = kzalloc(sizeof(*ipcc_mbox_chan), GFP_KERNEL); if (!ipcc_mbox_chan) return ERR_PTR(-ENOMEM); ipcc_mbox_chan->client_id = ph->args[0]; ipcc_mbox_chan->signal_id = ph->args[1]; ipcc_mbox_chan->chan = &bridge_data->chans[chan_id]; ipcc_mbox_chan->npu_dev = npu_dev; ipcc_mbox_chan->chan->con_priv = ipcc_mbox_chan; ipcc_mbox_chan->npu_mbox = &npu_dev->mbox[i]; NPU_DBG("New mailbox channel: %u for client_id: %u; signal_id: %u\n", chan_id, ipcc_mbox_chan->client_id, ipcc_mbox_chan->signal_id); return ipcc_mbox_chan->chan; } static const struct mbox_chan_ops ipcc_mbox_chan_ops = { .send_data = npu_ipcc_bridge_mbox_send_data, .shutdown = npu_ipcc_bridge_mbox_shutdown }; static int npu_setup_ipcc_bridge_mbox(struct npu_device *npu_dev) { int i, j, ret; int num_chans = 0; struct mbox_controller *mbox; struct device_node *client_dn; struct of_phandle_args curr_ph; struct device *dev = &npu_dev->pdev->dev; struct device_node *controller_dn = dev->of_node; struct mbox_bridge_data *mbox_data = &npu_dev->mbox_bridge_data; NPU_DBG("Setup ipcc brige mbox\n"); /* * Find out the number of clients interested in this mailbox * and create channels accordingly. */ for_each_node_with_property(client_dn, "mboxes") { if (!of_device_is_available(client_dn)) { NPU_DBG("No node available\n"); continue; } i = of_count_phandle_with_args(client_dn, "mboxes", "#mbox-cells"); for (j = 0; j < i; j++) { ret = of_parse_phandle_with_args(client_dn, "mboxes", "#mbox-cells", j, &curr_ph); of_node_put(curr_ph.np); if (!ret && curr_ph.np == controller_dn) { NPU_DBG("Found a client\n"); num_chans++; break; } } } /* If no clients are found, skip registering as a mbox controller */ if (!num_chans) { NPU_WARN("Can't find ipcc bridge mbox client\n"); return 0; } mbox_data->chans = devm_kcalloc(dev, num_chans, sizeof(struct mbox_chan), GFP_KERNEL); if (!mbox_data->chans) return -ENOMEM; mbox_data->priv_data = npu_dev; mbox = &mbox_data->mbox; mbox->dev = dev; mbox->num_chans = num_chans; mbox->chans = mbox_data->chans; mbox->ops = &ipcc_mbox_chan_ops; mbox->of_xlate = npu_ipcc_bridge_mbox_xlate; mbox->txdone_irq = false; mbox->txdone_poll = false; return mbox_controller_register(mbox); } static int npu_mbox_init(struct npu_device *npu_dev) { struct platform_device *pdev = npu_dev->pdev; struct npu_mbox *mbox_aop = &npu_dev->mbox_aop; struct npu_mbox *mbox = NULL; struct property *prop; const char *mbox_name; uint32_t index = 0; int ret = 0; struct of_phandle_args curr_ph; if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { mbox_aop->client.dev = &pdev->dev; mbox_aop->client.tx_block = true; mbox_aop->client.tx_tout = MBOX_OP_TIMEOUTMS; mbox_aop->client.knows_txdone = false; if (!of_get_property(pdev->dev.of_node, "mbox-names", NULL) || !of_find_property(pdev->dev.of_node, "mboxes", NULL)) { NPU_WARN("requires mbox-names and mboxes property\n"); return 0; } mbox_aop->chan = mbox_request_channel(&mbox_aop->client, 0); if (IS_ERR(mbox_aop->chan)) { NPU_WARN("aop mailbox is not available\n"); mbox_aop->chan = NULL; of_property_for_each_string(pdev->dev.of_node, "mbox-names", prop, mbox_name) { NPU_DBG("setup mbox[%d] %s\n", index, mbox_name); mbox = &npu_dev->mbox[index]; mbox->client.dev = &pdev->dev; mbox->client.knows_txdone = true; mbox->chan = mbox_request_channel(&mbox->client, index); if (IS_ERR(mbox->chan)) { NPU_WARN("mailbox %s is not available\n", mbox_name); mbox->chan = NULL; } else if (!strcmp(mbox_name, "aop")) { npu_dev->mbox_aop = mbox; } else { ret = of_parse_phandle_with_args(pdev->dev.of_node, "mboxes", "#mbox-cells", index, &curr_ph); of_node_put(curr_ph.np); if (ret) { NPU_WARN("can't get mailbox %s args\n", mbox_name); } else { mbox->client_id = curr_ph.args[0]; mbox->signal_id = curr_ph.args[1]; NPU_DBG("argument for mailbox %x is %x %x\n", mbox_name, curr_ph.args[0], curr_ph.args[1]); } } index++; } return 0; return npu_setup_ipcc_bridge_mbox(npu_dev); } static void npu_mbox_deinit(struct npu_device *npu_dev) { if (npu_dev->mbox_aop.chan) { mbox_free_channel(npu_dev->mbox_aop.chan); npu_dev->mbox_aop.chan = NULL; int i; mbox_controller_unregister(&npu_dev->mbox_bridge_data.mbox); for (i = 0; i < NPU_MAX_MBOX_NUM; i++) { if (!npu_dev->mbox[i].chan) continue; mbox_free_channel(npu_dev->mbox[i].chan); npu_dev->mbox[i].chan = NULL; } } Loading
drivers/media/platform/msm/npu/npu_mgr.c +95 −9 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ */ static void npu_ipc_irq_work(struct work_struct *work); static void npu_wdg_err_irq_work(struct work_struct *work); static void npu_bridge_mbox_work(struct work_struct *work); static void npu_disable_fw_work(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_status_ready(struct npu_device *npu_dev, uint32_t status_reg, uint32_t status_bits); Loading Loading @@ -193,19 +195,16 @@ int unload_fw(struct npu_device *npu_dev) return 0; } int enable_fw(struct npu_device *npu_dev) static int enable_fw_nolock(struct npu_device *npu_dev) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret = 0; mutex_lock(&host_ctx->lock); if (host_ctx->fw_state == FW_UNLOADED) { ret = load_fw_nolock(npu_dev, host_ctx->auto_pil_disable ? true : false); if (ret) { NPU_ERR("load fw failed\n"); mutex_unlock(&host_ctx->lock); return ret; } Loading @@ -220,7 +219,6 @@ int enable_fw(struct npu_device *npu_dev) if (host_ctx->fw_state == FW_ENABLED) { host_ctx->fw_ref_cnt++; NPU_DBG("fw_ref_cnt %d\n", host_ctx->fw_ref_cnt); mutex_unlock(&host_ctx->lock); return 0; } Loading Loading @@ -275,7 +273,7 @@ int enable_fw(struct npu_device *npu_dev) host_ctx->fw_error = false; host_ctx->fw_ref_cnt++; mutex_unlock(&host_ctx->lock); enable_log: /* Set logging state */ Loading @@ -294,7 +292,18 @@ int enable_fw(struct npu_device *npu_dev) enable_sys_cache_fail: npu_disable_core_power(npu_dev); enable_pw_fail: return ret; } int enable_fw(struct npu_device *npu_dev) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret; mutex_lock(&host_ctx->lock); ret = enable_fw_nolock(npu_dev); mutex_unlock(&host_ctx->lock); return ret; } Loading Loading @@ -449,7 +458,7 @@ static int npu_notifier_cb(struct notifier_block *this, unsigned long code, break; } npu_cc_reg_write(npu_dev, NPU_CC_NPU_CPC_RSC_CTRL, 0); npu_cc_reg_write(npu_dev, NPU_CC_NPU_CPC_RSC_CTRL, 3); /* Clear control/status registers */ REGW(npu_dev, REG_NPU_FW_CTRL_STATUS, 0x0); Loading Loading @@ -516,6 +525,7 @@ int npu_host_init(struct npu_device *npu_dev) init_completion(&host_ctx->fw_bringup_done); init_completion(&host_ctx->fw_shutdown_done); mutex_init(&host_ctx->lock); spin_lock_init(&host_ctx->bridge_mbox_lock); atomic_set(&host_ctx->ipc_trans_id, 1); host_ctx->npu_dev = npu_dev; Loading @@ -534,6 +544,9 @@ int npu_host_init(struct npu_device *npu_dev) } else { INIT_WORK(&host_ctx->ipc_irq_work, npu_ipc_irq_work); INIT_WORK(&host_ctx->wdg_err_irq_work, npu_wdg_err_irq_work); INIT_WORK(&host_ctx->bridge_mbox_work, npu_bridge_mbox_work); INIT_DELAYED_WORK(&host_ctx->disable_fw_work, npu_disable_fw_work); } if (npu_dev->hw_version != 0x20000000) Loading Loading @@ -768,6 +781,79 @@ static void npu_wdg_err_irq_work(struct work_struct *work) host_error_hdlr(npu_dev, false); } static void npu_disable_fw_work(struct work_struct *work) { struct npu_host_ctx *host_ctx; struct npu_device *npu_dev; NPU_DBG("Enter disable fw work\n"); host_ctx = container_of(work, struct npu_host_ctx, disable_fw_work.work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); mutex_lock(&host_ctx->lock); disable_fw_nolock(npu_dev); host_ctx->bridge_mbox_pwr_on = false; mutex_unlock(&host_ctx->lock); NPU_DBG("Exit disable fw work\n"); } static int npu_bridge_mbox_send_data(struct npu_host_ctx *host_ctx, struct npu_mbox *mbox, void *data) { NPU_DBG("Generating IRQ for client_id: %u; signal_id: %u\n", mbox->client_id, mbox->signal_id); mbox_send_message(mbox->chan, NULL); mbox_client_txdone(mbox->chan, 0); mbox->send_data_pending = false; return 0; } static void npu_bridge_mbox_work(struct work_struct *work) { int i, ret; struct npu_host_ctx *host_ctx; struct npu_device *npu_dev; unsigned long flags; NPU_DBG("Enter bridge mbox work\n"); host_ctx = container_of(work, struct npu_host_ctx, bridge_mbox_work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); /* queue or modify delayed work to disable fw */ mod_delayed_work(host_ctx->wq, &host_ctx->disable_fw_work, NPU_MBOX_IDLE_TIMEOUT); mutex_lock(&host_ctx->lock); if (host_ctx->fw_state == FW_UNLOADED) { NPU_WARN("NPU fw is not loaded\n"); mutex_unlock(&host_ctx->lock); return; } if (!host_ctx->bridge_mbox_pwr_on) { ret = enable_fw_nolock(npu_dev); if (ret) { mutex_unlock(&host_ctx->lock); NPU_ERR("Enable fw failed\n"); return; } host_ctx->bridge_mbox_pwr_on = true; NPU_DBG("Fw is enabled by mbox\n"); } spin_lock_irqsave(&host_ctx->bridge_mbox_lock, flags); for (i = 0; i < NPU_MAX_MBOX_NUM; i++) if (npu_dev->mbox[i].send_data_pending) npu_bridge_mbox_send_data(host_ctx, &npu_dev->mbox[i], NULL); spin_unlock_irqrestore(&host_ctx->bridge_mbox_lock, flags); mutex_unlock(&host_ctx->lock); NPU_DBG("Exit bridge mbox work\n"); } static void turn_off_fw_logging(struct npu_device *npu_dev) { struct ipc_cmd_log_state_pkt log_packet; Loading Loading @@ -828,7 +914,7 @@ static int npu_notify_aop(struct npu_device *npu_dev, bool on) struct qmp_pkt pkt; int buf_size, rc = 0; if (!npu_dev->mbox_aop.chan) { if (!npu_dev->mbox_aop || !npu_dev->mbox_aop->chan) { NPU_WARN("aop mailbox channel is not available\n"); return 0; } Loading @@ -845,7 +931,7 @@ static int npu_notify_aop(struct npu_device *npu_dev, bool on) pkt.size = (buf_size + 3) & ~0x3; pkt.data = buf; rc = mbox_send_message(npu_dev->mbox_aop.chan, &pkt); rc = mbox_send_message(npu_dev->mbox_aop->chan, &pkt); if (rc < 0) NPU_ERR("qmp message send failed, ret=%d\n", rc); Loading
drivers/media/platform/msm/npu/npu_mgr.h +6 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #define NW_CMD_TIMEOUT msecs_to_jiffies(NW_CMD_TIMEOUT_MS) #define NW_DEBUG_TIMEOUT_MS (1000 * 60 * 30) /* set for 30 minutes */ #define NW_DEBUG_TIMEOUT msecs_to_jiffies(NW_DEBUG_TIMEOUT_MS) #define NPU_MBOX_IDLE_TIMEOUT_MS 500 /* set for 500ms */ #define NPU_MBOX_IDLE_TIMEOUT msecs_to_jiffies(NPU_MBOX_IDLE_TIMEOUT_MS) #define FIRMWARE_VERSION 0x00001000 #define MAX_LOADED_NETWORK 32 #define NPU_IPC_BUF_LENGTH 512 Loading Loading @@ -74,6 +76,8 @@ struct npu_host_ctx { int32_t power_vote_num; struct work_struct ipc_irq_work; struct work_struct wdg_err_irq_work; struct work_struct bridge_mbox_work; struct delayed_work disable_fw_work; struct workqueue_struct *wq; struct completion misc_cmd_done; struct completion fw_deinit_done; Loading @@ -96,6 +100,8 @@ struct npu_host_ctx { uint32_t misc_cmd_result; struct notifier_block nb; void *notif_hdle; spinlock_t bridge_mbox_lock; bool bridge_mbox_pwr_on; }; struct npu_device; Loading