summaryrefslogtreecommitdiff
path: root/drivers/mailbox/mtk-cmdq-mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mailbox/mtk-cmdq-mailbox.c')
-rw-r--r--drivers/mailbox/mtk-cmdq-mailbox.c115
1 files changed, 72 insertions, 43 deletions
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index ead2200f39ba..d186865b8dce 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -22,7 +22,6 @@
#define CMDQ_OP_CODE_MASK (0xff << CMDQ_OP_CODE_SHIFT)
#define CMDQ_NUM_CMD(t) (t->cmd_buf_size / CMDQ_INST_SIZE)
-#define CMDQ_GCE_NUM_MAX (2)
#define CMDQ_CURR_IRQ_STATUS 0x10
#define CMDQ_SYNC_TOKEN_UPDATE 0x68
@@ -81,7 +80,7 @@ struct cmdq {
u32 irq_mask;
const struct gce_plat *pdata;
struct cmdq_thread *thread;
- struct clk_bulk_data clocks[CMDQ_GCE_NUM_MAX];
+ struct clk_bulk_data *clocks;
bool suspended;
};
@@ -398,7 +397,7 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
task = kzalloc(sizeof(*task), GFP_ATOMIC);
if (!task) {
- pm_runtime_put_autosuspend(cmdq->mbox.dev);
+ __pm_runtime_put_autosuspend(cmdq->mbox.dev);
return -ENOMEM;
}
@@ -448,7 +447,7 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
list_move_tail(&task->list_entry, &thread->task_busy_list);
pm_runtime_mark_last_busy(cmdq->mbox.dev);
- pm_runtime_put_autosuspend(cmdq->mbox.dev);
+ __pm_runtime_put_autosuspend(cmdq->mbox.dev);
return 0;
}
@@ -465,7 +464,7 @@ static void cmdq_mbox_shutdown(struct mbox_chan *chan)
struct cmdq_task *task, *tmp;
unsigned long flags;
- WARN_ON(pm_runtime_get_sync(cmdq->mbox.dev));
+ WARN_ON(pm_runtime_get_sync(cmdq->mbox.dev) < 0);
spin_lock_irqsave(&thread->chan->lock, flags);
if (list_empty(&thread->task_busy_list))
@@ -496,7 +495,7 @@ done:
spin_unlock_irqrestore(&thread->chan->lock, flags);
pm_runtime_mark_last_busy(cmdq->mbox.dev);
- pm_runtime_put_autosuspend(cmdq->mbox.dev);
+ __pm_runtime_put_autosuspend(cmdq->mbox.dev);
}
static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
@@ -536,7 +535,7 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout)
out:
spin_unlock_irqrestore(&thread->chan->lock, flags);
pm_runtime_mark_last_busy(cmdq->mbox.dev);
- pm_runtime_put_autosuspend(cmdq->mbox.dev);
+ __pm_runtime_put_autosuspend(cmdq->mbox.dev);
return 0;
@@ -551,7 +550,7 @@ wait:
return -EFAULT;
}
pm_runtime_mark_last_busy(cmdq->mbox.dev);
- pm_runtime_put_autosuspend(cmdq->mbox.dev);
+ __pm_runtime_put_autosuspend(cmdq->mbox.dev);
return 0;
}
@@ -578,16 +577,64 @@ static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
return &mbox->chans[ind];
}
+static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
+{
+ static const char * const gce_name = "gce";
+ struct device_node *node, *parent = dev->of_node->parent;
+ struct clk_bulk_data *clks;
+
+ cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num,
+ sizeof(*cmdq->clocks), GFP_KERNEL);
+ if (!cmdq->clocks)
+ return -ENOMEM;
+
+ if (cmdq->pdata->gce_num == 1) {
+ clks = &cmdq->clocks[0];
+
+ clks->id = gce_name;
+ clks->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(clks->clk))
+ return dev_err_probe(dev, PTR_ERR(clks->clk),
+ "failed to get gce clock\n");
+
+ return 0;
+ }
+
+ /*
+ * If there is more than one GCE, get the clocks for the others too,
+ * as the clock of the main GCE must be enabled for additional IPs
+ * to be reachable.
+ */
+ for_each_child_of_node(parent, node) {
+ int alias_id = of_alias_get_id(node, gce_name);
+
+ if (alias_id < 0 || alias_id >= cmdq->pdata->gce_num)
+ continue;
+
+ clks = &cmdq->clocks[alias_id];
+
+ clks->id = devm_kasprintf(dev, GFP_KERNEL, "gce%d", alias_id);
+ if (!clks->id) {
+ of_node_put(node);
+ return -ENOMEM;
+ }
+
+ clks->clk = of_clk_get(node, 0);
+ if (IS_ERR(clks->clk)) {
+ of_node_put(node);
+ return dev_err_probe(dev, PTR_ERR(clks->clk),
+ "failed to get gce%d clock\n", alias_id);
+ }
+ }
+
+ return 0;
+}
+
static int cmdq_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cmdq *cmdq;
int err, i;
- struct device_node *phandle = dev->of_node;
- struct device_node *node;
- int alias_id = 0;
- static const char * const clk_name = "gce";
- static const char * const clk_names[] = { "gce0", "gce1" };
cmdq = devm_kzalloc(dev, sizeof(*cmdq), GFP_KERNEL);
if (!cmdq)
@@ -612,29 +659,9 @@ static int cmdq_probe(struct platform_device *pdev)
dev_dbg(dev, "cmdq device: addr:0x%p, va:0x%p, irq:%d\n",
dev, cmdq->base, cmdq->irq);
- if (cmdq->pdata->gce_num > 1) {
- for_each_child_of_node(phandle->parent, node) {
- alias_id = of_alias_get_id(node, clk_name);
- if (alias_id >= 0 && alias_id < cmdq->pdata->gce_num) {
- cmdq->clocks[alias_id].id = clk_names[alias_id];
- cmdq->clocks[alias_id].clk = of_clk_get(node, 0);
- if (IS_ERR(cmdq->clocks[alias_id].clk)) {
- of_node_put(node);
- return dev_err_probe(dev,
- PTR_ERR(cmdq->clocks[alias_id].clk),
- "failed to get gce clk: %d\n",
- alias_id);
- }
- }
- }
- } else {
- cmdq->clocks[alias_id].id = clk_name;
- cmdq->clocks[alias_id].clk = devm_clk_get(&pdev->dev, clk_name);
- if (IS_ERR(cmdq->clocks[alias_id].clk)) {
- return dev_err_probe(dev, PTR_ERR(cmdq->clocks[alias_id].clk),
- "failed to get gce clk\n");
- }
- }
+ err = cmdq_get_clocks(dev, cmdq);
+ if (err)
+ return err;
cmdq->mbox.dev = dev;
cmdq->mbox.chans = devm_kcalloc(dev, cmdq->pdata->thread_nr,
@@ -662,12 +689,6 @@ static int cmdq_probe(struct platform_device *pdev)
cmdq->mbox.chans[i].con_priv = (void *)&cmdq->thread[i];
}
- err = devm_mbox_controller_register(dev, &cmdq->mbox);
- if (err < 0) {
- dev_err(dev, "failed to register mailbox: %d\n", err);
- return err;
- }
-
platform_set_drvdata(pdev, cmdq);
WARN_ON(clk_bulk_prepare(cmdq->pdata->gce_num, cmdq->clocks));
@@ -695,6 +716,12 @@ static int cmdq_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(dev, CMDQ_MBOX_AUTOSUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
+ err = devm_mbox_controller_register(dev, &cmdq->mbox);
+ if (err < 0) {
+ dev_err(dev, "failed to register mailbox: %d\n", err);
+ return err;
+ }
+
return 0;
}
@@ -765,10 +792,11 @@ static const struct of_device_id cmdq_of_ids[] = {
{.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_mt8195},
{}
};
+MODULE_DEVICE_TABLE(of, cmdq_of_ids);
static struct platform_driver cmdq_drv = {
.probe = cmdq_probe,
- .remove_new = cmdq_remove,
+ .remove = cmdq_remove,
.driver = {
.name = "mtk_cmdq",
.pm = &cmdq_pm_ops,
@@ -789,4 +817,5 @@ static void __exit cmdq_drv_exit(void)
subsys_initcall(cmdq_drv_init);
module_exit(cmdq_drv_exit);
+MODULE_DESCRIPTION("Mediatek Command Queue(CMDQ) Mailbox driver");
MODULE_LICENSE("GPL v2");