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.c86
1 files changed, 76 insertions, 10 deletions
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index 5791f80f995a..9da16b30eb41 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
#include <linux/mailbox_controller.h>
#include <linux/mailbox/mtk-cmdq-mailbox.h>
#include <linux/of.h>
@@ -43,6 +44,13 @@
#define GCE_CTRL_BY_SW GENMASK(2, 0)
#define GCE_DDR_EN GENMASK(18, 16)
+#define GCE_VM_ID_MAP(n) (0x5018 + (n) / 10 * 4)
+#define GCE_VM_ID_MAP_THR_FLD_SHIFT(n) ((n) % 10 * 3)
+#define GCE_VM_ID_MAP_HOST_VM GENMASK(2, 0)
+#define GCE_VM_CPR_GSIZE 0x50c4
+#define GCE_VM_CPR_GSIZE_FLD_SHIFT(vm_id) ((vm_id) * 4)
+#define GCE_VM_CPR_GSIZE_MAX GENMASK(3, 0)
+
#define CMDQ_THR_ACTIVE_SLOT_CYCLES 0x3200
#define CMDQ_THR_ENABLED 0x1
#define CMDQ_THR_DISABLED 0x0
@@ -87,22 +95,33 @@ struct cmdq {
struct gce_plat {
u32 thread_nr;
u8 shift;
+ dma_addr_t mminfra_offset;
bool control_by_sw;
bool sw_ddr_en;
+ bool gce_vm;
u32 gce_num;
};
static inline u32 cmdq_convert_gce_addr(dma_addr_t addr, const struct gce_plat *pdata)
{
/* Convert DMA addr (PA or IOVA) to GCE readable addr */
- return addr >> pdata->shift;
+ return (addr + pdata->mminfra_offset) >> pdata->shift;
}
static inline dma_addr_t cmdq_revert_gce_addr(u32 addr, const struct gce_plat *pdata)
{
/* Revert GCE readable addr to DMA addr (PA or IOVA) */
- return (dma_addr_t)addr << pdata->shift;
+ return ((dma_addr_t)addr << pdata->shift) - pdata->mminfra_offset;
+}
+
+void cmdq_get_mbox_priv(struct mbox_chan *chan, struct cmdq_mbox_priv *priv)
+{
+ struct cmdq *cmdq = container_of(chan->mbox, struct cmdq, mbox);
+
+ priv->shift_pa = cmdq->pdata->shift;
+ priv->mminfra_offset = cmdq->pdata->mminfra_offset;
}
+EXPORT_SYMBOL(cmdq_get_mbox_priv);
u8 cmdq_get_shift_pa(struct mbox_chan *chan)
{
@@ -112,6 +131,45 @@ u8 cmdq_get_shift_pa(struct mbox_chan *chan)
}
EXPORT_SYMBOL(cmdq_get_shift_pa);
+static void cmdq_vm_init(struct cmdq *cmdq)
+{
+ int i;
+ u32 vm_cpr_gsize = 0, vm_id_map = 0;
+ u32 *vm_map = NULL;
+
+ if (!cmdq->pdata->gce_vm)
+ return;
+
+ vm_map = kcalloc(cmdq->pdata->thread_nr, sizeof(*vm_map), GFP_KERNEL);
+ if (!vm_map)
+ return;
+
+ /* only configure the max CPR SRAM size to host vm (vm_id = 0) currently */
+ vm_cpr_gsize = GCE_VM_CPR_GSIZE_MAX << GCE_VM_CPR_GSIZE_FLD_SHIFT(0);
+
+ /* set all thread mapping to host vm currently */
+ for (i = 0; i < cmdq->pdata->thread_nr; i++)
+ vm_map[i] = GCE_VM_ID_MAP_HOST_VM << GCE_VM_ID_MAP_THR_FLD_SHIFT(i);
+
+ /* set the amount of CPR SRAM to allocate to each VM */
+ writel(vm_cpr_gsize, cmdq->base + GCE_VM_CPR_GSIZE);
+
+ /* config CPR_GSIZE before setting VM_ID_MAP to avoid data leakage */
+ for (i = 0; i < cmdq->pdata->thread_nr; i++) {
+ vm_id_map |= vm_map[i];
+ /* config every 10 threads, e.g., thread id=0~9, 10~19, ..., into one register */
+ if ((i + 1) % 10 == 0) {
+ writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(i));
+ vm_id_map = 0;
+ }
+ }
+ /* config remaining threads settings */
+ if (cmdq->pdata->thread_nr % 10 != 0)
+ writel(vm_id_map, cmdq->base + GCE_VM_ID_MAP(cmdq->pdata->thread_nr - 1));
+
+ kfree(vm_map);
+}
+
static void cmdq_gctl_value_toggle(struct cmdq *cmdq, bool ddr_enable)
{
u32 val = cmdq->pdata->control_by_sw ? GCE_CTRL_BY_SW : 0;
@@ -156,6 +214,7 @@ static void cmdq_init(struct cmdq *cmdq)
WARN_ON(clk_bulk_enable(cmdq->pdata->gce_num, cmdq->clocks));
+ cmdq_vm_init(cmdq);
cmdq_gctl_value_toggle(cmdq, true);
writel(CMDQ_THR_ACTIVE_SLOT_CYCLES, cmdq->base + CMDQ_THR_SLOT_CYCLES);
@@ -577,7 +636,7 @@ static struct mbox_chan *cmdq_xlate(struct mbox_controller *mbox,
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 device_node *parent = dev->of_node->parent;
struct clk_bulk_data *clks;
cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num,
@@ -602,7 +661,7 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
* as the clock of the main GCE must be enabled for additional IPs
* to be reachable.
*/
- for_each_child_of_node(parent, node) {
+ for_each_child_of_node_scoped(parent, node) {
int alias_id = of_alias_get_id(node, gce_name);
if (alias_id < 0 || alias_id >= cmdq->pdata->gce_num)
@@ -611,17 +670,13 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq)
clks = &cmdq->clocks[alias_id];
clks->id = devm_kasprintf(dev, GFP_KERNEL, "gce%d", alias_id);
- if (!clks->id) {
- of_node_put(node);
+ if (!clks->id)
return -ENOMEM;
- }
clks->clk = of_clk_get(node, 0);
- if (IS_ERR(clks->clk)) {
- of_node_put(node);
+ if (IS_ERR(clks->clk))
return dev_err_probe(dev, PTR_ERR(clks->clk),
"failed to get gce%d clock\n", alias_id);
- }
}
return 0;
@@ -782,6 +837,16 @@ static const struct gce_plat gce_plat_mt8195 = {
.gce_num = 2
};
+static const struct gce_plat gce_plat_mt8196 = {
+ .thread_nr = 32,
+ .shift = 3,
+ .mminfra_offset = SZ_2G,
+ .control_by_sw = true,
+ .sw_ddr_en = true,
+ .gce_vm = true,
+ .gce_num = 2
+};
+
static const struct of_device_id cmdq_of_ids[] = {
{.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_mt6779},
{.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_mt8173},
@@ -790,6 +855,7 @@ static const struct of_device_id cmdq_of_ids[] = {
{.compatible = "mediatek,mt8188-gce", .data = (void *)&gce_plat_mt8188},
{.compatible = "mediatek,mt8192-gce", .data = (void *)&gce_plat_mt8192},
{.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_mt8195},
+ {.compatible = "mediatek,mt8196-gce", .data = (void *)&gce_plat_mt8196},
{}
};
MODULE_DEVICE_TABLE(of, cmdq_of_ids);