MT6589 DRM and Blade panels - #63
Draft
akku1139 wants to merge 48 commits into
Draft
Conversation
for 7.1 dev Link: #33 Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
Member
Author
diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
index 67107e42358b..94f48005fd65 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
@@ -72,7 +72,7 @@ properties:
- enum:
- mediatek,mt2701-m4u # generation one
- mediatek,mt2712-m4u # generation two
- - mediatek,mt6589-m4u
+ - mediatek,mt6589-m4u # generation one (dual core)
- mediatek,mt6779-m4u # generation two
- mediatek,mt6795-m4u # generation two
- mediatek,mt6893-iommu-mm # generation two
@@ -98,10 +98,20 @@ properties:
- const: mediatek,mt2701-m4u
reg:
- maxItems: 1
+ minItems: 1
+ maxItems: 4 # MT6589 needs 4 regions (global, m4u0, m4u1, l2cache)
+
+ reg-names:
+ minItems: 1
+ maxItems: 4
interrupts:
- maxItems: 1
+ minItems: 1
+ maxItems: 2 # MT6589 has one IRQ per core
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 2
clocks:
items:
@@ -134,6 +144,7 @@ properties:
dt-binding/memory/mediatek,mt8188-memory-port.h for mt8188,
dt-binding/memory/mediatek,mt8189-memory-port.h for mt8189,
dt-binding/memory/mt2701-larb-port.h for mt2701 and mt7623,
+ dt-binding/memory/mt6589-larb-port.h for mt6589,
dt-binding/memory/mt2712-larb-port.h for mt2712,
dt-binding/memory/mt6779-larb-port.h for mt6779,
dt-binding/memory/mt6795-larb-port.h for mt6795,
@@ -156,6 +167,42 @@ required:
- '#iommu-cells'
allOf:
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ const: mediatek,mt6589-m4u
+ then:
+ properties:
+ reg:
+ maxItems: 1
+ interrupts:
+ maxItems: 1
+ required:
+ - reg
+ else:
+ properties:
+ reg:
+ minItems: 4
+ maxItems: 4
+ interrupts:
+ minItems: 2
+ maxItems: 2
+ reg-names:
+ items:
+ - const: global
+ - const: m4u0
+ - const: m4u1
+ - const: l2cache
+ interrupt-names:
+ items:
+ - const: m4u0
+ - const: m4u1
+ required:
+ - reg-names
+ - interrupt-names
+
- if:
properties:
compatible:
@@ -163,6 +210,7 @@ allOf:
enum:
- mediatek,mt2701-m4u
- mediatek,mt2712-m4u
+ - mediatek,mt6589-m4u
- mediatek,mt6795-m4u
- mediatek,mt6893-iommu-mm
- mediatek,mt8173-m4u
@@ -241,3 +289,23 @@ examples:
<&larb3>, <&larb4>, <&larb5>;
#iommu-cells = <1>;
};
+
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ iommu@10208000 {
+ compatible = "mediatek,mt6589-m4u";
+ reg = <0x10205000 0x200>,
+ <0x10205200 0x600>,
+ <0x10205800 0x600>,
+ <0x10205100 0x100>;
+ reg-names = "global", "m4u0", "m4u1", "l2cache";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "m4u0", "m4u1";
+ clocks = <&infracfg CLK_INFRA_M4U>;
+ clock-names = "bclk";
+ mediatek,larbs = <&larb0>, <&larb1>, <&larb2>,
+ <&larb3>, <&larb4>, <&larb5>;
+ #iommu-cells = <1>;
+ };
diff --git a/arch/arm/boot/dts/mediatek/mt6589.dtsi b/arch/arm/boot/dts/mediatek/mt6589.dtsi
index 6ea8b76af910..241fa2afbd86 100644
--- a/arch/arm/boot/dts/mediatek/mt6589.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt6589.dtsi
@@ -431,8 +431,9 @@ iommu: iommu@10205000 {
compatible = "mediatek,mt6589-m4u";
reg = <0x10205000 0x200>,
<0x10205200 0x600>,
- <0x10205800 0x600>;
- reg-names = "global", "m4u0", "m4u1";
+ <0x10205800 0x600>,
+ <0x10205100 0x100>;
+ reg-names = "global", "m4u0", "m4u1", "l2cache";
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
<GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 591ffa66a728..dd822b95a7ed 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,6 +7,8 @@
*
* Based on driver/iommu/mtk_iommu.c
*/
+#include "linux/types.h"
+#include <linux/array_size.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
@@ -29,6 +31,7 @@
#include <asm/barrier.h>
#include <dt-bindings/memory/mtk-memory-port.h>
#include <dt-bindings/memory/mt2701-larb-port.h>
+#include <dt-bindings/memory/mt6589-larb-port.h>
#include <soc/mediatek/smi.h>
#if defined(CONFIG_ARM)
@@ -51,6 +54,7 @@ struct dma_iommu_mapping {
#define F_MMU_FAULT_VA_MSK 0xfffff000
#define MTK_PROTECT_PA_ALIGN 128
+/* -------- Common M4U v1 register definitions (MT2701 and MT6589 core) -------- */
#define REG_MMU_CTRL_REG 0x210
#define F_MMU_CTRL_COHERENT_EN BIT(8)
#define REG_MMU_IVRP_PADDR 0x214
@@ -71,6 +75,8 @@ struct dma_iommu_mapping {
#define REG_MMU_FAULT_VA 0x228
#define REG_MMU_INVLD_PA 0x22C
#define REG_MMU_INT_ID 0x388
+
+/* MT2701 specific (core space) */
#define REG_MMU_INVALIDATE 0x5c0
#define REG_MMU_INVLD_START_A 0x5c4
#define REG_MMU_INVLD_END_A 0x5c8
@@ -81,14 +87,80 @@ struct dma_iommu_mapping {
#define REG_MMU_DCM 0x5f0
#define F_MMU_DCM_ON BIT(1)
#define REG_MMU_CPE_DONE 0x60c
+
+/* MT6589 global space registers */
+#define REG_MMUg_CTRL 0x00
+#define F_MMUg_CTRL_INV_EN0 BIT(0)
+#define F_MMUg_CTRL_INV_EN1 BIT(1)
+#define F_MMUg_CTRL_INV_EN2 BIT(2) /* L2 */
+#define F_MMUg_CTRL_PRE_LOCK(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_CTRL_PRE_EN BIT(4)
+
+#define REG_MMUg_INVLD 0x04
+#define F_MMUg_INV_ALL 0x2
+#define F_MMUg_INV_RANGE 0x1
+
+#define REG_MMUg_INVLD_SA 0x08
+#define REG_MMUg_INVLD_EA 0x0C
+#define REG_MMUg_PT_BASE 0x10
+#define F_MMUg_PT_VA_MSK 0xffff0000
+
+#define REG_MMUg_L2_SEL 0x18
+#define F_MMUg_L2_SEL_FLUSH_EN(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_L2_SEL_L2_ULTRA(en) ((en) ? BIT(2) : 0)
+#define F_MMUg_L2_SEL_L2_SHARE(en) ((en) ? BIT(1) : 0)
+#define F_MMUg_L2_SEL_L2_BUS_SEL(go_emi) ((go_emi) ? BIT(0) : 0)
+
+#define REG_MMUg_DCM 0x1C
+#define F_MMUg_DCM_ON(on) ((on) ? BIT(0) : 0)
+
+/* L2 cache registers (MT6589) */
+#define REG_L2_GDC_STATE 0x00
+#define F_L2_GDC_ST_EVENT_MSK GENMASK(7,6)
+#define F_L2_GDC_ST_EVENT_VAL(val) (((val) & 0x3) << 6)
+
+#define REG_L2_GDC_OP 0x04
+#define F_L2_GDC_BYPASS(en) ((en) ? BIT(10) : 0)
+#define F_L2_GDC_PERF_MASK(msk) (((msk) & 0x7) << 7)
+#define GDC_PERF_MASK_HIT_MISS 0
+#define F_L2_GDC_LOCK_ALERT_DIS(dis) ((dis) ? BIT(6) : 0)
+#define F_L2_GDC_PERF_EN(en) ((en) ? BIT(5) : 0)
+#define F_L2_GDC_LOCK_TH(th) (((th) & 0x3) << 2)
+#define F_L2_GDC_PAUSE_OP(op) ((op) & 0x3)
+#define GDC_NO_PAUSE 0
+
+#define REG_L2_GPE_STATUS 0x18
+#define F_L2_GPE_ST_RANGE_INV_DONE BIT(1)
+#define F_L2_GPE_ST_PREFETCH_DONE BIT(0)
+
+/* MT6589 core PFH distance / direction registers */
+#define REG_MMU_PFH_DIST(port) (0x80 + (((port) >> 3) << 2))
+#define F_MMU_PFH_DIST_VAL(port, val) (((val) & 0xf) << (((port) & 0x7) << 2))
+#define F_MMU_PFH_DIST_MASK(port) F_MMU_PFH_DIST_VAL(port, 0xf)
+
+#define REG_MMU_PFH_DIR(port) (((port) < 32) ? 0xF0 : 0xF4)
+#define F_MMU_PFH_DIR(port, val) ((!!(val)) << ((port) & 0x1f))
+
+/* SMI common registers (temporary, to be moved to SMI driver) */
+#define SMI_COMMON_EXT_BASE 0x10202000
+#define SMI_COMMON_AO_BASE 0x1000E000
+#define REG_SMI_L1LEN 0x200
+#define F_SMI_L1LEN_AXROUTE_G3D_EMI(en) ((en) ? BIT(2) : 0)
+#define F_SMI_L1LEN_AXROUTE_AUDIO_EMI(en) ((en) ? BIT(5) : 0)
+#define REG_SMI_BUS_SEL 0x220
+#define F_SMI_BUS_SEL_larb0(mmu) (((mmu) & 0x3) << 0)
+#define F_SMI_BUS_SEL_larb1(mmu) (((mmu) & 0x3) << 2)
+#define F_SMI_BUS_SEL_larb2(mmu) (((mmu) & 0x3) << 4)
+#define F_SMI_BUS_SEL_larb3(mmu) (((mmu) & 0x3) << 6)
+#define F_SMI_BUS_SEL_larb4(mmu) (((mmu) & 0x3) << 8)
+#define REG_SMI_SECUR_CON(x) (0x05C0 + ((x) << 2))
+
+/* Common page table descriptor bits */
#define F_DESC_VALID 0x2
#define F_DESC_NONSEC BIT(3)
-#define MT2701_M4U_TF_LARB(TF) (6 - (((TF) >> 13) & 0x7))
-#define MT2701_M4U_TF_PORT(TF) (((TF) >> 8) & 0xF)
/* MTK generation one iommu HW only support 4K size mapping */
#define MT2701_IOMMU_PAGE_SHIFT 12
#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX 3
/*
* MTK m4u support 4GB iova address space, and only support 4K page
@@ -96,26 +168,75 @@ struct dma_iommu_mapping {
*/
#define M2701_IOMMU_PGT_SIZE SZ_4M
+#define MAX_M4U_CORES 2
+
+struct mtk_iommu_v1_data;
+
+struct mtk_iommu_v1_soc_data {
+ const char *compatible;
+ unsigned int num_cores;
+ bool has_global_base;
+ bool has_l2_cache;
+
+ void (*tlb_flush_all)(struct mtk_iommu_v1_data *data);
+ void (*tlb_flush_range)(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size);
+
+ void (*get_fault_larb_port)(u32 int_id, unsigned int *larb,
+ unsigned int *port);
+
+ int (*hw_init)(struct mtk_iommu_v1_data *data);
+
+ u32 pt_base_reg_offset;
+ bool pt_base_in_global;
+
+ const int *larb_port_offsets;
+ unsigned int num_larb;
+};
+
+struct mtk_iommu_v1_core {
+ void __iomem *base;
+ int irq;
+ struct mtk_iommu_v1_data *data;
+ unsigned int id;
+};
+
struct mtk_iommu_v1_suspend_reg {
+ /* MT2701 fields */
u32 standard_axi_mode;
u32 dcm_dis;
u32 ctrl_reg;
u32 int_control0;
+
+ /* MT6589 additional fields */
+ u32 mmug_ctrl;
+ u32 mmug_pt_base;
+ u32 mmug_l2_sel;
+ u32 mmug_dcm;
+ u32 l2_gdc_op;
+ u32 smi_l1len;
+ u32 smi_bus_sel;
+ u32 smi_secur_con[7];
};
struct mtk_iommu_v1_data {
- void __iomem *base;
- int irq;
- struct device *dev;
- struct clk *bclk;
- phys_addr_t protect_base; /* protect memory base */
- struct mtk_iommu_v1_domain *m4u_dom;
-
- struct iommu_device iommu;
- struct dma_iommu_mapping *mapping;
- struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
-
- struct mtk_iommu_v1_suspend_reg reg;
+ const struct mtk_iommu_v1_soc_data *soc;
+ struct device *dev;
+
+ struct mtk_iommu_v1_core cores[MAX_M4U_CORES];
+ void __iomem *global_base;
+ void __iomem *l2_base;
+
+ struct clk *bclk;
+ phys_addr_t protect_base;
+ struct mtk_iommu_v1_domain *m4u_dom;
+
+ struct iommu_device iommu;
+ struct dma_iommu_mapping *mapping;
+ struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
+
+ struct mtk_iommu_v1_suspend_reg reg;
+ struct page *dummy_page; /* Physical address of guard dummy page */
};
struct mtk_iommu_v1_domain {
@@ -150,73 +271,143 @@ static const int mt2701_m4u_in_larb[] = {
MT2701_LARB2_PORT_OFFSET, MT2701_LARB3_PORT_OFFSET
};
-static inline int mt2701_m4u_to_larb(int id)
+static const int mt6589_m4u_in_larb[] = {
+ MT6589_LARB0_PORT_OFFSET, MT6589_LARB1_PORT_OFFSET,
+ MT6589_LARB2_PORT_OFFSET, MT6589_LARB3_PORT_OFFSET,
+ MT6589_LARB4_PORT_OFFSET, MT6589_LARB5_PORT_OFFSET
+};
+
+static inline int mtk_iommu_v1_to_larb(struct mtk_iommu_v1_data *data, int id)
{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num = data->soc->num_larb;
int i;
- for (i = ARRAY_SIZE(mt2701_m4u_in_larb) - 1; i >= 0; i--)
- if ((id) >= mt2701_m4u_in_larb[i])
+ for (i = num - 1; i >= 0; i--)
+ if (id >= offsets[i])
return i;
return 0;
}
-static inline int mt2701_m4u_to_port(int id)
+static inline int mtk_iommu_v1_to_port(struct mtk_iommu_v1_data *data, int id)
{
- int larb = mt2701_m4u_to_larb(id);
+ int larb = mtk_iommu_v1_to_larb(data, id);
+ return id - data->soc->larb_port_offsets[larb];
+}
- return id - mt2701_m4u_in_larb[larb];
+static inline void m4u_set_field(void __iomem *base, u32 reg, u32 mask, u32 val)
+{
+ u32 regval = readl_relaxed(base + reg);
+ regval = (regval & ~mask) | val;
+ writel_relaxed(regval, base + reg);
}
-static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
+/* MT2701 (single core, no global space) */
+static void mt2701_tlb_flush_all(struct mtk_iommu_v1_data *data)
{
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
- wmb(); /* Make sure the tlb flush all done */
+ void __iomem *base = data->cores[0].base;
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
+ wmb();
}
-static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
- unsigned long iova, size_t size)
+static void mt2701_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
{
- int ret;
+ void __iomem *base = data->cores[0].base;
u32 tmp;
+ int ret;
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_START_A);
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK, base + REG_MMU_INVLD_START_A);
writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_END_A);
- writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
+ base + REG_MMU_INVLD_END_A);
+ writel_relaxed(F_MMU_INV_RANGE, base + REG_MMU_INVALIDATE);
- ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
- tmp, tmp != 0, 10, 100000);
+ ret = readl_poll_timeout_atomic(base + REG_MMU_CPE_DONE,
+ tmp, tmp != 0, 10, 100000);
if (ret) {
dev_warn(data->dev,
"Partial TLB flush timed out, falling back to full flush\n");
- mtk_iommu_v1_tlb_flush_all(data);
+ mt2701_tlb_flush_all(data);
+ }
+ writel_relaxed(0, base + REG_MMU_CPE_DONE);
+}
+
+/* MT6589 (global control, L2) */
+static void mt6589_tlb_flush_all(struct mtk_iommu_v1_data *data)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(F_MMUg_INV_ALL, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 event;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GDC_STATE,
+ event,
+ event & F_L2_GDC_ST_EVENT_MSK,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GDC_STATE);
}
- /* Clear the CPE status */
- writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+}
+
+static void mt6589_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_SA);
+ writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_EA);
+ writel_relaxed(F_MMUg_INV_RANGE, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 status;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GPE_STATUS,
+ status,
+ status & F_L2_GPE_ST_RANGE_INV_DONE,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GPE_STATUS);
+ }
+}
+
+static void mt2701_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - ((int_id >> 13) & 0x7);
+ *port = (int_id >> 8) & 0xF;
+}
+
+static void mt6589_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - (int_id >> 12) & 0x7;
+ *port = (int_id >> 8) & 0xF;
}
static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
{
- struct mtk_iommu_v1_data *data = dev_id;
+ struct mtk_iommu_v1_core *core = dev_id;
+ struct mtk_iommu_v1_data *data = core->data;
struct mtk_iommu_v1_domain *dom = data->m4u_dom;
u32 int_state, regval, fault_iova, fault_pa;
unsigned int fault_larb, fault_port;
/* Read error information from registers */
- int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST);
- fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+ int_state = readl_relaxed(core->base + REG_MMU_FAULT_ST);
+ fault_iova = readl_relaxed(core->base + REG_MMU_FAULT_VA) & F_MMU_FAULT_VA_MSK;
+ fault_pa = readl_relaxed(core->base + REG_MMU_INVLD_PA);
+ regval = readl_relaxed(core->base + REG_MMU_INT_ID);
- fault_iova &= F_MMU_FAULT_VA_MSK;
- fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
- regval = readl_relaxed(data->base + REG_MMU_INT_ID);
- fault_larb = MT2701_M4U_TF_LARB(regval);
- fault_port = MT2701_M4U_TF_PORT(regval);
+ data->soc->get_fault_larb_port(regval, &fault_larb, &fault_port);
/*
* MTK v1 iommu HW could not determine whether the fault is read or
@@ -225,16 +416,16 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
IOMMU_FAULT_READ))
dev_err_ratelimited(data->dev,
- "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d\n",
+ "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d core=%d\n",
int_state, fault_iova, fault_pa,
- fault_larb, fault_port);
+ fault_larb, fault_port, core->id);
/* Interrupt clear */
- regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL);
+ regval = readl_relaxed(core->base + REG_MMU_INT_CONTROL);
regval |= F_INT_CLR_BIT;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, core->base + REG_MMU_INT_CONTROL);
- mtk_iommu_v1_tlb_flush_all(data);
+ data->soc->tlb_flush_all(data);
return IRQ_HANDLED;
}
@@ -242,14 +433,14 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
struct device *dev, bool enable)
{
- struct mtk_smi_larb_iommu *larb_mmu;
- unsigned int larbid, portid;
+ struct mtk_smi_larb_iommu *larb_mmu;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- int i;
+ unsigned int larbid, portid, i, mmu_id;
+ void __iomem *base;
for (i = 0; i < fwspec->num_ids; ++i) {
- larbid = mt2701_m4u_to_larb(fwspec->ids[i]);
- portid = mt2701_m4u_to_port(fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
larb_mmu = &data->larb_imu[larbid];
dev_dbg(dev, "%s iommu port: %d\n",
@@ -260,6 +451,26 @@ static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
else
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
}
+
+ /* MT6589 specific: set default prefetch distance & direction */
+ if (data->soc->has_global_base) {
+ for (i = 0; i < fwspec->num_ids; i++) {
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+
+ /* Determine which M4U core this LARB is connected to */
+ mmu_id = (larbid == 0 || larbid == 2) ? 0 : 1;
+ base = data->cores[mmu_id].base;
+
+ /* Set distance = 1 */
+ m4u_set_field(base, REG_MMU_PFH_DIST(portid),
+ F_MMU_PFH_DIST_MASK(portid),
+ F_MMU_PFH_DIST_VAL(portid, 1));
+ /* Set direction = 0 */
+ m4u_set_field(base, REG_MMU_PFH_DIR(portid),
+ 1 << (portid & 0x1f), 0);
+ }
+ }
}
static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
@@ -273,7 +484,10 @@ static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
if (!dom->pgt_va)
return -ENOMEM;
- writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
+ if (data->soc->pt_base_in_global)
+ writel(dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel(dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
dom->data = data;
@@ -354,10 +568,12 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
int prot, gfp_t gfp, size_t *mapped)
{
struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain);
+ struct mtk_iommu_v1_data *data = dom->data;
unsigned long flags;
- unsigned int i;
- u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
+ unsigned int i, guard_pages = (data->soc->has_global_base) ? 4 : 0;
+ u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
u32 pabase = (u32)paddr;
+ phys_addr_t dummy_pa = page_to_phys(data->dummy_page);
spin_lock_irqsave(&dom->pgtlock, flags);
for (i = 0; i < pgcount; i++) {
@@ -367,10 +583,19 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
pabase += MT2701_IOMMU_PAGE_SIZE;
}
+ if (guard_pages && i == pgcount) {
+ for (i = pgcount; i < pgcount + guard_pages; i++) {
+ if ((iova >> MT2701_IOMMU_PAGE_SHIFT) + i >= (M2701_IOMMU_PGT_SIZE / sizeof(u32)))
+ break;
+ if (pgt_base_iova[i] == 0)
+ pgt_base_iova[i] = dummy_pa | F_DESC_VALID | F_DESC_NONSEC;
+ }
+ }
+
spin_unlock_irqrestore(&dom->pgtlock, flags);
*mapped = i * MT2701_IOMMU_PAGE_SIZE;
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, *mapped);
+ data->soc->tlb_flush_range(data, iova, *mapped);
return i == pgcount ? 0 : -EEXIST;
}
@@ -388,7 +613,7 @@ static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova
memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags);
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, size);
+ dom->data->soc->tlb_flush_range(dom->data, iova, size);
return size;
}
@@ -489,12 +714,12 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
data = dev_iommu_priv_get(dev);
/* Link the consumer device with the smi-larb device(supplier) */
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
- if (larbid >= MT2701_LARB_NR_MAX)
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
+ if (larbid >= MTK_LARB_NR_MAX)
return ERR_PTR(-EINVAL);
for (idx = 1; idx < fwspec->num_ids; idx++) {
- larbidx = mt2701_m4u_to_larb(fwspec->ids[idx]);
+ larbidx = mtk_iommu_v1_to_larb(data, fwspec->ids[idx]);
if (larbid != larbidx) {
dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n",
larbid, larbidx);
@@ -532,12 +757,12 @@ static void mtk_iommu_v1_release_device(struct device *dev)
unsigned int larbid;
data = dev_iommu_priv_get(dev);
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
larbdev = data->larb_imu[larbid].dev;
device_link_remove(dev, larbdev);
}
-static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
+static int mt2701_hw_init(struct mtk_iommu_v1_data *data)
{
u32 regval;
int ret;
@@ -549,7 +774,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
}
regval = F_MMU_CTRL_COHERENT_EN | F_MMU_TF_PROTECT_SEL(2);
- writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_CTRL_REG);
regval = F_INT_TRANSLATION_FAULT |
F_INT_MAIN_MULTI_HIT_FAULT |
@@ -559,23 +784,104 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
F_INT_TLB_MISS_FAULT |
F_INT_PFH_DMA_FIFO_OVERFLOW |
F_INT_MISS_DMA_FIFO_OVERFLOW;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_INT_CONTROL);
- /* protect memory,hw will write here while translation fault */
- writel_relaxed(data->protect_base,
- data->base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(data->protect_base, data->cores[0].base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(F_MMU_DCM_ON, data->cores[0].base + REG_MMU_DCM);
- writel_relaxed(F_MMU_DCM_ON, data->base + REG_MMU_DCM);
+ return 0;
+}
- if (devm_request_irq(data->dev, data->irq, mtk_iommu_v1_isr, 0,
- dev_name(data->dev), (void *)data)) {
- writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
- clk_disable_unprepare(data->bclk);
- dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
- return -ENODEV;
+static int mt6589_hw_init(struct mtk_iommu_v1_data *data)
+{
+ u32 regval;
+ int i, ret;
+ void __iomem *smi_ext, *smi_ao;
+
+ /* Map SMI common regions temporarily (should be done by SMI driver) */
+ smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (!smi_ext || !smi_ao) {
+ dev_err(data->dev, "Failed to map SMI common registers\n");
+ ret = -ENOMEM;
+ goto err_iomap;
+ }
+
+ ret = clk_prepare_enable(data->bclk);
+ if (ret) {
+ dev_err(data->dev, "Failed to enable bclk\n");
+ goto err_clk;
}
+ /* ---- SMI routing (LARB to M4U core) ---- */
+ /* LARB 0 -> M4U0, 1 -> M4U1, 2 -> M4U0, 3 -> M4U1, 4 -> M4U1 */
+ regval = F_SMI_BUS_SEL_larb0(0) | F_SMI_BUS_SEL_larb1(1) |
+ F_SMI_BUS_SEL_larb2(0) | F_SMI_BUS_SEL_larb3(1) |
+ F_SMI_BUS_SEL_larb4(1);
+ writel_relaxed(regval, smi_ext + REG_SMI_BUS_SEL);
+
+ /* Default security: non-secure, domain=3, physical */
+ for (i = 0; i < 7; i++)
+ writel_relaxed(0x66666666, smi_ao + REG_SMI_SECUR_CON(i));
+
+ /* Route G3D and AUDIO to EMI */
+ m4u_set_field(smi_ext, REG_SMI_L1LEN,
+ F_SMI_L1LEN_AXROUTE_G3D_EMI(1),
+ F_SMI_L1LEN_AXROUTE_G3D_EMI(1));
+ m4u_set_field(smi_ext, REG_SMI_L1LEN,
+ F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1),
+ F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1));
+
+ /* ---- Global registers ---- */
+ writel_relaxed(F_MMUg_L2_SEL_FLUSH_EN(1) | F_MMUg_L2_SEL_L2_ULTRA(1) |
+ F_MMUg_L2_SEL_L2_SHARE(0) | F_MMUg_L2_SEL_L2_BUS_SEL(1),
+ data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(F_MMUg_DCM_ON(1), data->global_base + REG_MMUg_DCM);
+
+ /* ---- L2 cache ---- */
+ if (data->l2_base) {
+ regval = F_L2_GDC_BYPASS(0) |
+ F_L2_GDC_PERF_MASK(GDC_PERF_MASK_HIT_MISS) |
+ F_L2_GDC_LOCK_ALERT_DIS(0) |
+ F_L2_GDC_LOCK_TH(3) |
+ F_L2_GDC_PAUSE_OP(GDC_NO_PAUSE);
+ writel_relaxed(regval, data->l2_base + REG_L2_GDC_OP);
+ }
+
+ /* ---- Per-core setup ---- */
+ for (i = 0; i < data->soc->num_cores; i++) {
+ void __iomem *base = data->cores[i].base;
+
+ regval = 0; /* PFH enabled, walk enabled, cohere disabled */
+ regval |= F_MMU_TF_PROTECT_SEL(2);
+ writel_relaxed(regval, base + REG_MMU_CTRL_REG);
+
+ regval = F_INT_TRANSLATION_FAULT |
+ F_INT_MAIN_MULTI_HIT_FAULT |
+ F_INT_INVALID_PA_FAULT |
+ F_INT_ENTRY_REPLACEMENT_FAULT |
+ F_INT_TABLE_WALK_FAULT |
+ F_INT_TLB_MISS_FAULT |
+ F_INT_PFH_DMA_FIFO_OVERFLOW |
+ F_INT_MISS_DMA_FIFO_OVERFLOW;
+ writel_relaxed(regval, base + REG_MMU_INT_CONTROL);
+
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ /* Release temporary mappings */
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+
return 0;
+
+err_clk:
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+err_iomap:
+ if (smi_ext) iounmap(smi_ext);
+ if (smi_ao) iounmap(smi_ao);
+ return ret;
}
static const struct iommu_ops mtk_iommu_v1_ops = {
@@ -595,8 +901,39 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
}
};
+static const struct mtk_iommu_v1_soc_data mt2701_soc_data = {
+ .compatible = "mediatek,mt2701-m4u",
+ .num_cores = 1,
+ .has_global_base = false,
+ .has_l2_cache = false,
+ .tlb_flush_all = mt2701_tlb_flush_all,
+ .tlb_flush_range = mt2701_tlb_flush_range,
+ .get_fault_larb_port = mt2701_get_fault_larb_port,
+ .hw_init = mt2701_hw_init,
+ .pt_base_reg_offset = REG_MMU_PT_BASE_ADDR,
+ .pt_base_in_global = false,
+ .larb_port_offsets = mt2701_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt2701_m4u_in_larb),
+};
+
+static const struct mtk_iommu_v1_soc_data mt6589_soc_data = {
+ .compatible = "mediatek,mt6589-m4u",
+ .num_cores = 2,
+ .has_global_base = true,
+ .has_l2_cache = true,
+ .tlb_flush_all = mt6589_tlb_flush_all,
+ .tlb_flush_range = mt6589_tlb_flush_range,
+ .get_fault_larb_port = mt6589_get_fault_larb_port,
+ .hw_init = mt6589_hw_init,
+ .pt_base_reg_offset = REG_MMUg_PT_BASE,
+ .pt_base_in_global = true,
+ .larb_port_offsets = mt6589_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt6589_m4u_in_larb),
+};
+
static const struct of_device_id mtk_iommu_v1_of_ids[] = {
- { .compatible = "mediatek,mt2701-m4u", },
+ { .compatible = "mediatek,mt2701-m4u", .data = &mt2701_soc_data },
+ { .compatible = "mediatek,mt6589-m4u", .data = &mt6589_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, mtk_iommu_v1_of_ids);
@@ -610,16 +947,19 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_iommu_v1_data *data;
- struct resource *res;
+ const struct mtk_iommu_v1_soc_data *soc;
struct component_match *match = NULL;
void *protect;
int larb_nr, ret, i;
+ struct page *dummy_page;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
+ soc = of_device_get_match_data(dev);
+ data->soc = soc;
/* Protect memory. HW will access here while translation fault.*/
protect = devm_kcalloc(dev, 2, MTK_PROTECT_PA_ALIGN,
@@ -628,26 +968,69 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
return -ENOMEM;
data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ if (soc->has_global_base) {
+ data->global_base = devm_platform_ioremap_resource_byname(pdev,
+ "global");
+ if (IS_ERR(data->global_base))
+ return PTR_ERR(data->global_base);
+ }
+ for (i = 0; i < soc->num_cores; i++) {
+ char name[8];
+ snprintf(name, sizeof(name), "m4u%d", i);
+ data->cores[i].base = devm_platform_ioremap_resource_byname(pdev,
+ name);
+ if (IS_ERR(data->cores[i].base))
+ return PTR_ERR(data->cores[i].base);
+ data->cores[i].data = data;
+ data->cores[i].id = i;
+ }
+ if (soc->has_l2_cache) {
+ data->l2_base = devm_platform_ioremap_resource_byname(pdev,
+ "l2cache");
+ if (IS_ERR(data->l2_base))
+ return PTR_ERR(data->l2_base);
+ }
data->bclk = devm_clk_get(dev, "bclk");
if (IS_ERR(data->bclk))
return PTR_ERR(data->bclk);
+ /* Interrupts - request after hw_init to avoid spurious IRQs? but
+ we need the core IRQs ready before registering ISR. We'll request
+ them after hw_init for simplicity. */
+ ret = soc->hw_init(data);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < soc->num_cores; i++) {
+ struct mtk_iommu_v1_core *core = &data->cores[i];
+ char irqname[8];
+ snprintf(irqname, sizeof(irqname), "m4u%d", i);
+ core->irq = platform_get_irq_byname(pdev, irqname);
+ if (core->irq < 0) {
+ ret = core->irq;
+ goto out_clk_unprepare;
+ }
+ ret = devm_request_irq(dev, core->irq, mtk_iommu_v1_isr, 0,
+ dev_name(dev), core);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d for core%d\n",
+ core->irq, i);
+ goto out_clk_unprepare;
+ }
+ }
+
larb_nr = of_count_phandle_with_args(dev->of_node,
"mediatek,larbs", NULL);
- if (larb_nr < 0)
- return larb_nr;
+ if (larb_nr < 0) {
+ ret = larb_nr;
+ goto out_clk_unprepare;
+ }
- if (larb_nr > MTK_LARB_NR_MAX)
- return -EINVAL;
+ if (larb_nr > MTK_LARB_NR_MAX) {
+ ret = -EINVAL;
+ goto out_clk_unprepare;
+ }
for (i = 0; i < larb_nr; i++) {
struct device_node *larbnode;
@@ -682,17 +1065,20 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
component_compare_of, larbnode);
}
+ dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!dummy_page) {
+ ret = -ENOMEM;
+ goto out_put_larbs;
+ }
+ data->dummy_page = dummy_page;
+
platform_set_drvdata(pdev, data);
- ret = mtk_iommu_v1_hw_init(data);
+ ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
+ dev_name(dev));
if (ret)
goto out_put_larbs;
- ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
- dev_name(&pdev->dev));
- if (ret)
- goto out_clk_unprepare;
-
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
if (ret)
goto out_sysfs_remove;
@@ -706,12 +1092,14 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu);
-out_clk_unprepare:
- clk_disable_unprepare(data->bclk);
out_put_larbs:
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
-
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
+ if (data->dummy_page)
+ __free_page(data->dummy_page);
+out_clk_unprepare:
+ clk_disable_unprepare(data->bclk);
return ret;
}
@@ -724,40 +1112,128 @@ static void mtk_iommu_v1_remove(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
clk_disable_unprepare(data->bclk);
- devm_free_irq(&pdev->dev, data->irq, data);
+ for (i = 0; i < data->soc->num_cores; i++)
+ devm_free_irq(&pdev->dev, data->cores[i].irq, &data->cores[i]);
component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops);
+ __free_page(data->dummy_page);
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
}
static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
+ void __iomem *base = data->cores[0].base;
- reg->standard_axi_mode = readl_relaxed(base +
- REG_MMU_STANDARD_AXI_MODE);
- reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ /* Common core registers */
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL);
+
+ if (data->soc->has_global_base) {
+ reg->mmug_ctrl = readl_relaxed(data->global_base + REG_MMUg_CTRL);
+ reg->mmug_pt_base = readl_relaxed(data->global_base + REG_MMUg_PT_BASE);
+ reg->mmug_l2_sel = readl_relaxed(data->global_base + REG_MMUg_L2_SEL);
+ reg->mmug_dcm = readl_relaxed(data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ reg->l2_gdc_op = readl_relaxed(data->l2_base + REG_L2_GDC_OP);
+
+ /* Save SMI registers (temporary) */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ reg->smi_l1len = readl_relaxed(smi_ext + REG_SMI_L1LEN);
+ reg->smi_bus_sel = readl_relaxed(smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ reg->smi_secur_con[i] = readl_relaxed(smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ } else {
+ /* MT2701 specific */
+ base = data->cores[0].base;
+ reg->standard_axi_mode = readl_relaxed(base + REG_MMU_STANDARD_AXI_MODE);
+ reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ }
+
return 0;
}
+static void mt6589_restore_pfh_settings(struct mtk_iommu_v1_data *data)
+{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num_larb = data->soc->num_larb;
+ int larb, port;
+
+ for (larb = 0; larb < num_larb; larb++) {
+ int mmu_id = (larb == 0 || larb == 2) ? 0 : 1;
+ void __iomem *base = data->cores[mmu_id].base;
+ int max_port = (larb == num_larb - 1) ? 32 : offsets[larb+1] - offsets[larb];
+ for (port = 0; port < max_port; port++) {
+ int global_port = offsets[larb] + port;
+ m4u_set_field(base, REG_MMU_PFH_DIST(global_port),
+ F_MMU_PFH_DIST_MASK(global_port),
+ F_MMU_PFH_DIST_VAL(global_port, 1));
+ m4u_set_field(base, REG_MMU_PFH_DIR(global_port),
+ 1 << (global_port & 0x1f), 0);
+ }
+ }
+}
+
static int __maybe_unused mtk_iommu_v1_resume(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
-
- writel_relaxed(data->m4u_dom->pgt_pa, base + REG_MMU_PT_BASE_ADDR);
- writel_relaxed(reg->standard_axi_mode,
- base + REG_MMU_STANDARD_AXI_MODE);
- writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
- writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
- writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
- writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ void __iomem *base = data->cores[0].base;
+
+ if (data->soc->has_global_base) {
+ writel_relaxed(reg->mmug_ctrl, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(reg->mmug_pt_base, data->global_base + REG_MMUg_PT_BASE);
+ writel_relaxed(reg->mmug_l2_sel, data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(reg->mmug_dcm, data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ writel_relaxed(reg->l2_gdc_op, data->l2_base + REG_L2_GDC_OP);
+
+ /* Restore SMI registers */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ writel_relaxed(reg->smi_l1len, smi_ext + REG_SMI_L1LEN);
+ writel_relaxed(reg->smi_bus_sel, smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ writel_relaxed(reg->smi_secur_con[i], smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ }
+
+ /* Per-core restore (common) */
+ for (int i = 0; i < data->soc->num_cores; i++) {
+ base = data->cores[i].base;
+ writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
+ writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ if (!data->soc->has_global_base) {
+ /* MT2701 extra */
+ base = data->cores[0].base;
+ writel_relaxed(reg->standard_axi_mode, base + REG_MMU_STANDARD_AXI_MODE);
+ writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
+ }
+
+ if (data->m4u_dom && data->m4u_dom->pgt_pa) {
+ if (data->soc->pt_base_in_global)
+ writel_relaxed(data->m4u_dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel_relaxed(data->m4u_dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
+ }
+
+ if (data->soc->has_global_base)
+ mt6589_restore_pfh_settings(data);
+
return 0;
}
|
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
index 67107e42358b..94f48005fd65 100644
--- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml
@@ -72,7 +72,7 @@ properties:
- enum:
- mediatek,mt2701-m4u # generation one
- mediatek,mt2712-m4u # generation two
- - mediatek,mt6589-m4u
+ - mediatek,mt6589-m4u # generation one (dual core)
- mediatek,mt6779-m4u # generation two
- mediatek,mt6795-m4u # generation two
- mediatek,mt6893-iommu-mm # generation two
@@ -98,10 +98,20 @@ properties:
- const: mediatek,mt2701-m4u
reg:
- maxItems: 1
+ minItems: 1
+ maxItems: 4 # MT6589 needs 4 regions (global, m4u0, m4u1, l2cache)
+
+ reg-names:
+ minItems: 1
+ maxItems: 4
interrupts:
- maxItems: 1
+ minItems: 1
+ maxItems: 2 # MT6589 has one IRQ per core
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 2
clocks:
items:
@@ -134,6 +144,7 @@ properties:
dt-binding/memory/mediatek,mt8188-memory-port.h for mt8188,
dt-binding/memory/mediatek,mt8189-memory-port.h for mt8189,
dt-binding/memory/mt2701-larb-port.h for mt2701 and mt7623,
+ dt-binding/memory/mt6589-larb-port.h for mt6589,
dt-binding/memory/mt2712-larb-port.h for mt2712,
dt-binding/memory/mt6779-larb-port.h for mt6779,
dt-binding/memory/mt6795-larb-port.h for mt6795,
@@ -156,6 +167,42 @@ required:
- '#iommu-cells'
allOf:
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ const: mediatek,mt6589-m4u
+ then:
+ properties:
+ reg:
+ maxItems: 1
+ interrupts:
+ maxItems: 1
+ required:
+ - reg
+ else:
+ properties:
+ reg:
+ minItems: 4
+ maxItems: 4
+ interrupts:
+ minItems: 2
+ maxItems: 2
+ reg-names:
+ items:
+ - const: global
+ - const: m4u0
+ - const: m4u1
+ - const: l2cache
+ interrupt-names:
+ items:
+ - const: m4u0
+ - const: m4u1
+ required:
+ - reg-names
+ - interrupt-names
+
- if:
properties:
compatible:
@@ -163,6 +210,7 @@ allOf:
enum:
- mediatek,mt2701-m4u
- mediatek,mt2712-m4u
+ - mediatek,mt6589-m4u
- mediatek,mt6795-m4u
- mediatek,mt6893-iommu-mm
- mediatek,mt8173-m4u
@@ -241,3 +289,23 @@ examples:
<&larb3>, <&larb4>, <&larb5>;
#iommu-cells = <1>;
};
+
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ iommu@10208000 {
+ compatible = "mediatek,mt6589-m4u";
+ reg = <0x10205000 0x200>,
+ <0x10205200 0x600>,
+ <0x10205800 0x600>,
+ <0x10205100 0x100>;
+ reg-names = "global", "m4u0", "m4u1", "l2cache";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 142 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "m4u0", "m4u1";
+ clocks = <&infracfg CLK_INFRA_M4U>;
+ clock-names = "bclk";
+ mediatek,larbs = <&larb0>, <&larb1>, <&larb2>,
+ <&larb3>, <&larb4>, <&larb5>;
+ #iommu-cells = <1>;
+ };
diff --git a/arch/arm/boot/dts/mediatek/mt6589.dtsi b/arch/arm/boot/dts/mediatek/mt6589.dtsi
index 6ea8b76af910..241fa2afbd86 100644
--- a/arch/arm/boot/dts/mediatek/mt6589.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt6589.dtsi
@@ -431,8 +431,9 @@ iommu: iommu@10205000 {
compatible = "mediatek,mt6589-m4u";
reg = <0x10205000 0x200>,
<0x10205200 0x600>,
- <0x10205800 0x600>;
- reg-names = "global", "m4u0", "m4u1";
+ <0x10205800 0x600>,
+ <0x10205100 0x100>;
+ reg-names = "global", "m4u0", "m4u1", "l2cache";
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
<GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 591ffa66a728..39c3b18dbc23 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,6 +7,8 @@
*
* Based on driver/iommu/mtk_iommu.c
*/
+#include "linux/types.h"
+#include <linux/array_size.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
@@ -29,6 +31,7 @@
#include <asm/barrier.h>
#include <dt-bindings/memory/mtk-memory-port.h>
#include <dt-bindings/memory/mt2701-larb-port.h>
+#include <dt-bindings/memory/mt6589-larb-port.h>
#include <soc/mediatek/smi.h>
#if defined(CONFIG_ARM)
@@ -51,6 +54,7 @@ struct dma_iommu_mapping {
#define F_MMU_FAULT_VA_MSK 0xfffff000
#define MTK_PROTECT_PA_ALIGN 128
+/* -------- Common M4U v1 register definitions (MT2701 and MT6589 core) -------- */
#define REG_MMU_CTRL_REG 0x210
#define F_MMU_CTRL_COHERENT_EN BIT(8)
#define REG_MMU_IVRP_PADDR 0x214
@@ -71,6 +75,8 @@ struct dma_iommu_mapping {
#define REG_MMU_FAULT_VA 0x228
#define REG_MMU_INVLD_PA 0x22C
#define REG_MMU_INT_ID 0x388
+
+/* MT2701 specific (core space) */
#define REG_MMU_INVALIDATE 0x5c0
#define REG_MMU_INVLD_START_A 0x5c4
#define REG_MMU_INVLD_END_A 0x5c8
@@ -81,14 +87,66 @@ struct dma_iommu_mapping {
#define REG_MMU_DCM 0x5f0
#define F_MMU_DCM_ON BIT(1)
#define REG_MMU_CPE_DONE 0x60c
+
+/* MT6589 global space registers */
+#define REG_MMUg_CTRL 0x00
+#define F_MMUg_CTRL_INV_EN0 BIT(0)
+#define F_MMUg_CTRL_INV_EN1 BIT(1)
+#define F_MMUg_CTRL_INV_EN2 BIT(2) /* L2 */
+#define F_MMUg_CTRL_PRE_LOCK(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_CTRL_PRE_EN BIT(4)
+
+#define REG_MMUg_INVLD 0x04
+#define F_MMUg_INV_ALL 0x2
+#define F_MMUg_INV_RANGE 0x1
+
+#define REG_MMUg_INVLD_SA 0x08
+#define REG_MMUg_INVLD_EA 0x0C
+#define REG_MMUg_PT_BASE 0x10
+#define F_MMUg_PT_VA_MSK 0xffff0000
+
+#define REG_MMUg_L2_SEL 0x18
+#define F_MMUg_L2_SEL_FLUSH_EN(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_L2_SEL_L2_ULTRA(en) ((en) ? BIT(2) : 0)
+#define F_MMUg_L2_SEL_L2_SHARE(en) ((en) ? BIT(1) : 0)
+#define F_MMUg_L2_SEL_L2_BUS_SEL(go_emi) ((go_emi) ? BIT(0) : 0)
+
+#define REG_MMUg_DCM 0x1C
+#define F_MMUg_DCM_ON(on) ((on) ? BIT(0) : 0)
+
+/* L2 cache registers (MT6589) */
+#define REG_L2_GDC_STATE 0x00
+#define F_L2_GDC_ST_EVENT_MSK GENMASK(7,6)
+#define F_L2_GDC_ST_EVENT_VAL(val) (((val) & 0x3) << 6)
+
+#define REG_L2_GDC_OP 0x04
+#define F_L2_GDC_BYPASS(en) ((en) ? BIT(10) : 0)
+#define F_L2_GDC_PERF_MASK(msk) (((msk) & 0x7) << 7)
+#define GDC_PERF_MASK_HIT_MISS 0
+#define F_L2_GDC_LOCK_ALERT_DIS(dis) ((dis) ? BIT(6) : 0)
+#define F_L2_GDC_PERF_EN(en) ((en) ? BIT(5) : 0)
+#define F_L2_GDC_LOCK_TH(th) (((th) & 0x3) << 2)
+#define F_L2_GDC_PAUSE_OP(op) ((op) & 0x3)
+#define GDC_NO_PAUSE 0
+
+#define REG_L2_GPE_STATUS 0x18
+#define F_L2_GPE_ST_RANGE_INV_DONE BIT(1)
+#define F_L2_GPE_ST_PREFETCH_DONE BIT(0)
+
+/* MT6589 core PFH distance / direction registers */
+#define REG_MMU_PFH_DIST(port) (0x80 + (((port) >> 3) << 2))
+#define F_MMU_PFH_DIST_VAL(port, val) (((val) & 0xf) << (((port) & 0x7) << 2))
+#define F_MMU_PFH_DIST_MASK(port) F_MMU_PFH_DIST_VAL(port, 0xf)
+
+#define REG_MMU_PFH_DIR(port) (((port) < 32) ? 0xF0 : 0xF4)
+#define F_MMU_PFH_DIR(port, val) ((!!(val)) << ((port) & 0x1f))
+
+/* Common page table descriptor bits */
#define F_DESC_VALID 0x2
#define F_DESC_NONSEC BIT(3)
-#define MT2701_M4U_TF_LARB(TF) (6 - (((TF) >> 13) & 0x7))
-#define MT2701_M4U_TF_PORT(TF) (((TF) >> 8) & 0xF)
/* MTK generation one iommu HW only support 4K size mapping */
#define MT2701_IOMMU_PAGE_SHIFT 12
#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX 3
/*
* MTK m4u support 4GB iova address space, and only support 4K page
@@ -96,26 +154,75 @@ struct dma_iommu_mapping {
*/
#define M2701_IOMMU_PGT_SIZE SZ_4M
+#define MAX_M4U_CORES 2
+
+struct mtk_iommu_v1_data;
+
+struct mtk_iommu_v1_soc_data {
+ const char *compatible;
+ unsigned int num_cores;
+ bool has_global_base;
+ bool has_l2_cache;
+
+ void (*tlb_flush_all)(struct mtk_iommu_v1_data *data);
+ void (*tlb_flush_range)(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size);
+
+ void (*get_fault_larb_port)(u32 int_id, unsigned int *larb,
+ unsigned int *port);
+
+ int (*hw_init)(struct mtk_iommu_v1_data *data);
+
+ u32 pt_base_reg_offset;
+ bool pt_base_in_global;
+
+ const int *larb_port_offsets;
+ unsigned int num_larb;
+};
+
+struct mtk_iommu_v1_core {
+ void __iomem *base;
+ int irq;
+ struct mtk_iommu_v1_data *data;
+ unsigned int id;
+};
+
struct mtk_iommu_v1_suspend_reg {
+ /* MT2701 fields */
u32 standard_axi_mode;
u32 dcm_dis;
u32 ctrl_reg;
u32 int_control0;
+
+ /* MT6589 additional fields */
+ u32 mmug_ctrl;
+ u32 mmug_pt_base;
+ u32 mmug_l2_sel;
+ u32 mmug_dcm;
+ u32 l2_gdc_op;
+ u32 smi_l1len;
+ u32 smi_bus_sel;
+ u32 smi_secur_con[7];
};
struct mtk_iommu_v1_data {
- void __iomem *base;
- int irq;
- struct device *dev;
- struct clk *bclk;
- phys_addr_t protect_base; /* protect memory base */
- struct mtk_iommu_v1_domain *m4u_dom;
-
- struct iommu_device iommu;
- struct dma_iommu_mapping *mapping;
- struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
-
- struct mtk_iommu_v1_suspend_reg reg;
+ const struct mtk_iommu_v1_soc_data *soc;
+ struct device *dev;
+
+ struct mtk_iommu_v1_core cores[MAX_M4U_CORES];
+ void __iomem *global_base;
+ void __iomem *l2_base;
+
+ struct clk *bclk;
+ phys_addr_t protect_base;
+ struct mtk_iommu_v1_domain *m4u_dom;
+
+ struct iommu_device iommu;
+ struct dma_iommu_mapping *mapping;
+ struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
+
+ struct mtk_iommu_v1_suspend_reg reg;
+ struct page *dummy_page; /* Physical address of guard dummy page */
};
struct mtk_iommu_v1_domain {
@@ -150,73 +257,143 @@ static const int mt2701_m4u_in_larb[] = {
MT2701_LARB2_PORT_OFFSET, MT2701_LARB3_PORT_OFFSET
};
-static inline int mt2701_m4u_to_larb(int id)
+static const int mt6589_m4u_in_larb[] = {
+ MT6589_LARB0_PORT_OFFSET, MT6589_LARB1_PORT_OFFSET,
+ MT6589_LARB2_PORT_OFFSET, MT6589_LARB3_PORT_OFFSET,
+ MT6589_LARB4_PORT_OFFSET, MT6589_LARB5_PORT_OFFSET
+};
+
+static inline int mtk_iommu_v1_to_larb(struct mtk_iommu_v1_data *data, int id)
{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num = data->soc->num_larb;
int i;
- for (i = ARRAY_SIZE(mt2701_m4u_in_larb) - 1; i >= 0; i--)
- if ((id) >= mt2701_m4u_in_larb[i])
+ for (i = num - 1; i >= 0; i--)
+ if (id >= offsets[i])
return i;
return 0;
}
-static inline int mt2701_m4u_to_port(int id)
+static inline int mtk_iommu_v1_to_port(struct mtk_iommu_v1_data *data, int id)
{
- int larb = mt2701_m4u_to_larb(id);
+ int larb = mtk_iommu_v1_to_larb(data, id);
+ return id - data->soc->larb_port_offsets[larb];
+}
- return id - mt2701_m4u_in_larb[larb];
+static inline void m4u_set_field(void __iomem *base, u32 reg, u32 mask, u32 val)
+{
+ u32 regval = readl_relaxed(base + reg);
+ regval = (regval & ~mask) | val;
+ writel_relaxed(regval, base + reg);
}
-static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
+/* MT2701 (single core, no global space) */
+static void mt2701_tlb_flush_all(struct mtk_iommu_v1_data *data)
{
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
- wmb(); /* Make sure the tlb flush all done */
+ void __iomem *base = data->cores[0].base;
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
+ wmb();
}
-static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
- unsigned long iova, size_t size)
+static void mt2701_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
{
- int ret;
+ void __iomem *base = data->cores[0].base;
u32 tmp;
+ int ret;
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_START_A);
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK, base + REG_MMU_INVLD_START_A);
writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_END_A);
- writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
+ base + REG_MMU_INVLD_END_A);
+ writel_relaxed(F_MMU_INV_RANGE, base + REG_MMU_INVALIDATE);
- ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
- tmp, tmp != 0, 10, 100000);
+ ret = readl_poll_timeout_atomic(base + REG_MMU_CPE_DONE,
+ tmp, tmp != 0, 10, 100000);
if (ret) {
dev_warn(data->dev,
"Partial TLB flush timed out, falling back to full flush\n");
- mtk_iommu_v1_tlb_flush_all(data);
+ mt2701_tlb_flush_all(data);
+ }
+ writel_relaxed(0, base + REG_MMU_CPE_DONE);
+}
+
+/* MT6589 (global control, L2) */
+static void mt6589_tlb_flush_all(struct mtk_iommu_v1_data *data)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(F_MMUg_INV_ALL, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 event;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GDC_STATE,
+ event,
+ event & F_L2_GDC_ST_EVENT_MSK,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GDC_STATE);
}
- /* Clear the CPE status */
- writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+}
+
+static void mt6589_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_SA);
+ writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_EA);
+ writel_relaxed(F_MMUg_INV_RANGE, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 status;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GPE_STATUS,
+ status,
+ status & F_L2_GPE_ST_RANGE_INV_DONE,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GPE_STATUS);
+ }
+}
+
+static void mt2701_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - ((int_id >> 13) & 0x7);
+ *port = (int_id >> 8) & 0xF;
+}
+
+static void mt6589_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - (int_id >> 12) & 0x7;
+ *port = (int_id >> 8) & 0xF;
}
static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
{
- struct mtk_iommu_v1_data *data = dev_id;
+ struct mtk_iommu_v1_core *core = dev_id;
+ struct mtk_iommu_v1_data *data = core->data;
struct mtk_iommu_v1_domain *dom = data->m4u_dom;
u32 int_state, regval, fault_iova, fault_pa;
unsigned int fault_larb, fault_port;
/* Read error information from registers */
- int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST);
- fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+ int_state = readl_relaxed(core->base + REG_MMU_FAULT_ST);
+ fault_iova = readl_relaxed(core->base + REG_MMU_FAULT_VA) & F_MMU_FAULT_VA_MSK;
+ fault_pa = readl_relaxed(core->base + REG_MMU_INVLD_PA);
+ regval = readl_relaxed(core->base + REG_MMU_INT_ID);
- fault_iova &= F_MMU_FAULT_VA_MSK;
- fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
- regval = readl_relaxed(data->base + REG_MMU_INT_ID);
- fault_larb = MT2701_M4U_TF_LARB(regval);
- fault_port = MT2701_M4U_TF_PORT(regval);
+ data->soc->get_fault_larb_port(regval, &fault_larb, &fault_port);
/*
* MTK v1 iommu HW could not determine whether the fault is read or
@@ -225,16 +402,16 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
IOMMU_FAULT_READ))
dev_err_ratelimited(data->dev,
- "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d\n",
+ "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d core=%d\n",
int_state, fault_iova, fault_pa,
- fault_larb, fault_port);
+ fault_larb, fault_port, core->id);
/* Interrupt clear */
- regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL);
+ regval = readl_relaxed(core->base + REG_MMU_INT_CONTROL);
regval |= F_INT_CLR_BIT;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, core->base + REG_MMU_INT_CONTROL);
- mtk_iommu_v1_tlb_flush_all(data);
+ data->soc->tlb_flush_all(data);
return IRQ_HANDLED;
}
@@ -242,14 +419,14 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
struct device *dev, bool enable)
{
- struct mtk_smi_larb_iommu *larb_mmu;
- unsigned int larbid, portid;
+ struct mtk_smi_larb_iommu *larb_mmu;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- int i;
+ unsigned int larbid, portid, i, mmu_id;
+ void __iomem *base;
for (i = 0; i < fwspec->num_ids; ++i) {
- larbid = mt2701_m4u_to_larb(fwspec->ids[i]);
- portid = mt2701_m4u_to_port(fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
larb_mmu = &data->larb_imu[larbid];
dev_dbg(dev, "%s iommu port: %d\n",
@@ -260,6 +437,26 @@ static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
else
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
}
+
+ /* MT6589 specific: set default prefetch distance & direction */
+ if (data->soc->has_global_base) {
+ for (i = 0; i < fwspec->num_ids; i++) {
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+
+ /* Determine which M4U core this LARB is connected to */
+ mmu_id = (larbid == 0 || larbid == 2) ? 0 : 1;
+ base = data->cores[mmu_id].base;
+
+ /* Set distance = 1 */
+ m4u_set_field(base, REG_MMU_PFH_DIST(portid),
+ F_MMU_PFH_DIST_MASK(portid),
+ F_MMU_PFH_DIST_VAL(portid, 1));
+ /* Set direction = 0 */
+ m4u_set_field(base, REG_MMU_PFH_DIR(portid),
+ 1 << (portid & 0x1f), 0);
+ }
+ }
}
static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
@@ -273,7 +470,10 @@ static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
if (!dom->pgt_va)
return -ENOMEM;
- writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
+ if (data->soc->pt_base_in_global)
+ writel(dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel(dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
dom->data = data;
@@ -354,10 +554,12 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
int prot, gfp_t gfp, size_t *mapped)
{
struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain);
+ struct mtk_iommu_v1_data *data = dom->data;
unsigned long flags;
- unsigned int i;
- u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
+ unsigned int i, guard_pages = (data->soc->has_global_base) ? 4 : 0;
+ u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
u32 pabase = (u32)paddr;
+ phys_addr_t dummy_pa = page_to_phys(data->dummy_page);
spin_lock_irqsave(&dom->pgtlock, flags);
for (i = 0; i < pgcount; i++) {
@@ -367,10 +569,19 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
pabase += MT2701_IOMMU_PAGE_SIZE;
}
+ if (guard_pages && i == pgcount) {
+ for (i = pgcount; i < pgcount + guard_pages; i++) {
+ if ((iova >> MT2701_IOMMU_PAGE_SHIFT) + i >= (M2701_IOMMU_PGT_SIZE / sizeof(u32)))
+ break;
+ if (pgt_base_iova[i] == 0)
+ pgt_base_iova[i] = dummy_pa | F_DESC_VALID | F_DESC_NONSEC;
+ }
+ }
+
spin_unlock_irqrestore(&dom->pgtlock, flags);
*mapped = i * MT2701_IOMMU_PAGE_SIZE;
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, *mapped);
+ data->soc->tlb_flush_range(data, iova, *mapped);
return i == pgcount ? 0 : -EEXIST;
}
@@ -388,7 +599,7 @@ static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova
memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags);
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, size);
+ dom->data->soc->tlb_flush_range(dom->data, iova, size);
return size;
}
@@ -489,12 +700,12 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
data = dev_iommu_priv_get(dev);
/* Link the consumer device with the smi-larb device(supplier) */
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
- if (larbid >= MT2701_LARB_NR_MAX)
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
+ if (larbid >= MTK_LARB_NR_MAX)
return ERR_PTR(-EINVAL);
for (idx = 1; idx < fwspec->num_ids; idx++) {
- larbidx = mt2701_m4u_to_larb(fwspec->ids[idx]);
+ larbidx = mtk_iommu_v1_to_larb(data, fwspec->ids[idx]);
if (larbid != larbidx) {
dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n",
larbid, larbidx);
@@ -532,12 +743,12 @@ static void mtk_iommu_v1_release_device(struct device *dev)
unsigned int larbid;
data = dev_iommu_priv_get(dev);
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
larbdev = data->larb_imu[larbid].dev;
device_link_remove(dev, larbdev);
}
-static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
+static int mt2701_hw_init(struct mtk_iommu_v1_data *data)
{
u32 regval;
int ret;
@@ -549,7 +760,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
}
regval = F_MMU_CTRL_COHERENT_EN | F_MMU_TF_PROTECT_SEL(2);
- writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_CTRL_REG);
regval = F_INT_TRANSLATION_FAULT |
F_INT_MAIN_MULTI_HIT_FAULT |
@@ -559,23 +770,66 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
F_INT_TLB_MISS_FAULT |
F_INT_PFH_DMA_FIFO_OVERFLOW |
F_INT_MISS_DMA_FIFO_OVERFLOW;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_INT_CONTROL);
- /* protect memory,hw will write here while translation fault */
- writel_relaxed(data->protect_base,
- data->base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(data->protect_base, data->cores[0].base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(F_MMU_DCM_ON, data->cores[0].base + REG_MMU_DCM);
- writel_relaxed(F_MMU_DCM_ON, data->base + REG_MMU_DCM);
+ return 0;
+}
- if (devm_request_irq(data->dev, data->irq, mtk_iommu_v1_isr, 0,
- dev_name(data->dev), (void *)data)) {
- writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
- clk_disable_unprepare(data->bclk);
- dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
- return -ENODEV;
+static int mt6589_hw_init(struct mtk_iommu_v1_data *data)
+{
+ u32 regval;
+ int i, ret;
+
+ ret = clk_prepare_enable(data->bclk);
+ if (ret) {
+ dev_err(data->dev, "Failed to enable bclk\n");
+ goto err_clk;
+ }
+
+ /* ---- Global registers ---- */
+ writel_relaxed(F_MMUg_L2_SEL_FLUSH_EN(1) | F_MMUg_L2_SEL_L2_ULTRA(1) |
+ F_MMUg_L2_SEL_L2_SHARE(0) | F_MMUg_L2_SEL_L2_BUS_SEL(1),
+ data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(F_MMUg_DCM_ON(1), data->global_base + REG_MMUg_DCM);
+
+ /* ---- L2 cache ---- */
+ if (data->l2_base) {
+ regval = F_L2_GDC_BYPASS(0) |
+ F_L2_GDC_PERF_MASK(GDC_PERF_MASK_HIT_MISS) |
+ F_L2_GDC_LOCK_ALERT_DIS(0) |
+ F_L2_GDC_LOCK_TH(3) |
+ F_L2_GDC_PAUSE_OP(GDC_NO_PAUSE);
+ writel_relaxed(regval, data->l2_base + REG_L2_GDC_OP);
+ }
+
+ /* ---- Per-core setup ---- */
+ for (i = 0; i < data->soc->num_cores; i++) {
+ void __iomem *base = data->cores[i].base;
+
+ regval = 0; /* PFH enabled, walk enabled, cohere disabled */
+ regval |= F_MMU_TF_PROTECT_SEL(2);
+ writel_relaxed(regval, base + REG_MMU_CTRL_REG);
+
+ regval = F_INT_TRANSLATION_FAULT |
+ F_INT_MAIN_MULTI_HIT_FAULT |
+ F_INT_INVALID_PA_FAULT |
+ F_INT_ENTRY_REPLACEMENT_FAULT |
+ F_INT_TABLE_WALK_FAULT |
+ F_INT_TLB_MISS_FAULT |
+ F_INT_PFH_DMA_FIFO_OVERFLOW |
+ F_INT_MISS_DMA_FIFO_OVERFLOW;
+ writel_relaxed(regval, base + REG_MMU_INT_CONTROL);
+
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
}
return 0;
+
+err_clk:
+ return ret;
}
static const struct iommu_ops mtk_iommu_v1_ops = {
@@ -595,8 +849,39 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
}
};
+static const struct mtk_iommu_v1_soc_data mt2701_soc_data = {
+ .compatible = "mediatek,mt2701-m4u",
+ .num_cores = 1,
+ .has_global_base = false,
+ .has_l2_cache = false,
+ .tlb_flush_all = mt2701_tlb_flush_all,
+ .tlb_flush_range = mt2701_tlb_flush_range,
+ .get_fault_larb_port = mt2701_get_fault_larb_port,
+ .hw_init = mt2701_hw_init,
+ .pt_base_reg_offset = REG_MMU_PT_BASE_ADDR,
+ .pt_base_in_global = false,
+ .larb_port_offsets = mt2701_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt2701_m4u_in_larb),
+};
+
+static const struct mtk_iommu_v1_soc_data mt6589_soc_data = {
+ .compatible = "mediatek,mt6589-m4u",
+ .num_cores = 2,
+ .has_global_base = true,
+ .has_l2_cache = true,
+ .tlb_flush_all = mt6589_tlb_flush_all,
+ .tlb_flush_range = mt6589_tlb_flush_range,
+ .get_fault_larb_port = mt6589_get_fault_larb_port,
+ .hw_init = mt6589_hw_init,
+ .pt_base_reg_offset = REG_MMUg_PT_BASE,
+ .pt_base_in_global = true,
+ .larb_port_offsets = mt6589_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt6589_m4u_in_larb),
+};
+
static const struct of_device_id mtk_iommu_v1_of_ids[] = {
- { .compatible = "mediatek,mt2701-m4u", },
+ { .compatible = "mediatek,mt2701-m4u", .data = &mt2701_soc_data },
+ { .compatible = "mediatek,mt6589-m4u", .data = &mt6589_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, mtk_iommu_v1_of_ids);
@@ -610,16 +895,19 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_iommu_v1_data *data;
- struct resource *res;
+ const struct mtk_iommu_v1_soc_data *soc;
struct component_match *match = NULL;
void *protect;
int larb_nr, ret, i;
+ struct page *dummy_page;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
+ soc = of_device_get_match_data(dev);
+ data->soc = soc;
/* Protect memory. HW will access here while translation fault.*/
protect = devm_kcalloc(dev, 2, MTK_PROTECT_PA_ALIGN,
@@ -628,26 +916,69 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
return -ENOMEM;
data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ if (soc->has_global_base) {
+ data->global_base = devm_platform_ioremap_resource_byname(pdev,
+ "global");
+ if (IS_ERR(data->global_base))
+ return PTR_ERR(data->global_base);
+ }
+ for (i = 0; i < soc->num_cores; i++) {
+ char name[8];
+ snprintf(name, sizeof(name), "m4u%d", i);
+ data->cores[i].base = devm_platform_ioremap_resource_byname(pdev,
+ name);
+ if (IS_ERR(data->cores[i].base))
+ return PTR_ERR(data->cores[i].base);
+ data->cores[i].data = data;
+ data->cores[i].id = i;
+ }
+ if (soc->has_l2_cache) {
+ data->l2_base = devm_platform_ioremap_resource_byname(pdev,
+ "l2cache");
+ if (IS_ERR(data->l2_base))
+ return PTR_ERR(data->l2_base);
+ }
data->bclk = devm_clk_get(dev, "bclk");
if (IS_ERR(data->bclk))
return PTR_ERR(data->bclk);
+ /* Interrupts - request after hw_init to avoid spurious IRQs? but
+ we need the core IRQs ready before registering ISR. We'll request
+ them after hw_init for simplicity. */
+ ret = soc->hw_init(data);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < soc->num_cores; i++) {
+ struct mtk_iommu_v1_core *core = &data->cores[i];
+ char irqname[8];
+ snprintf(irqname, sizeof(irqname), "m4u%d", i);
+ core->irq = platform_get_irq_byname(pdev, irqname);
+ if (core->irq < 0) {
+ ret = core->irq;
+ goto out_clk_unprepare;
+ }
+ ret = devm_request_irq(dev, core->irq, mtk_iommu_v1_isr, 0,
+ dev_name(dev), core);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d for core%d\n",
+ core->irq, i);
+ goto out_clk_unprepare;
+ }
+ }
+
larb_nr = of_count_phandle_with_args(dev->of_node,
"mediatek,larbs", NULL);
- if (larb_nr < 0)
- return larb_nr;
+ if (larb_nr < 0) {
+ ret = larb_nr;
+ goto out_clk_unprepare;
+ }
- if (larb_nr > MTK_LARB_NR_MAX)
- return -EINVAL;
+ if (larb_nr > MTK_LARB_NR_MAX) {
+ ret = -EINVAL;
+ goto out_clk_unprepare;
+ }
for (i = 0; i < larb_nr; i++) {
struct device_node *larbnode;
@@ -682,17 +1013,20 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
component_compare_of, larbnode);
}
+ dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!dummy_page) {
+ ret = -ENOMEM;
+ goto out_put_larbs;
+ }
+ data->dummy_page = dummy_page;
+
platform_set_drvdata(pdev, data);
- ret = mtk_iommu_v1_hw_init(data);
+ ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
+ dev_name(dev));
if (ret)
goto out_put_larbs;
- ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
- dev_name(&pdev->dev));
- if (ret)
- goto out_clk_unprepare;
-
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
if (ret)
goto out_sysfs_remove;
@@ -706,12 +1040,14 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu);
-out_clk_unprepare:
- clk_disable_unprepare(data->bclk);
out_put_larbs:
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
-
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
+ if (data->dummy_page)
+ __free_page(data->dummy_page);
+out_clk_unprepare:
+ clk_disable_unprepare(data->bclk);
return ret;
}
@@ -724,40 +1060,128 @@ static void mtk_iommu_v1_remove(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
clk_disable_unprepare(data->bclk);
- devm_free_irq(&pdev->dev, data->irq, data);
+ for (i = 0; i < data->soc->num_cores; i++)
+ devm_free_irq(&pdev->dev, data->cores[i].irq, &data->cores[i]);
component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops);
+ __free_page(data->dummy_page);
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
}
static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
+ void __iomem *base = data->cores[0].base;
- reg->standard_axi_mode = readl_relaxed(base +
- REG_MMU_STANDARD_AXI_MODE);
- reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ /* Common core registers */
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL);
+
+ if (data->soc->has_global_base) {
+ reg->mmug_ctrl = readl_relaxed(data->global_base + REG_MMUg_CTRL);
+ reg->mmug_pt_base = readl_relaxed(data->global_base + REG_MMUg_PT_BASE);
+ reg->mmug_l2_sel = readl_relaxed(data->global_base + REG_MMUg_L2_SEL);
+ reg->mmug_dcm = readl_relaxed(data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ reg->l2_gdc_op = readl_relaxed(data->l2_base + REG_L2_GDC_OP);
+
+ /* Save SMI registers (temporary) */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ reg->smi_l1len = readl_relaxed(smi_ext + REG_SMI_L1LEN);
+ reg->smi_bus_sel = readl_relaxed(smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ reg->smi_secur_con[i] = readl_relaxed(smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ } else {
+ /* MT2701 specific */
+ base = data->cores[0].base;
+ reg->standard_axi_mode = readl_relaxed(base + REG_MMU_STANDARD_AXI_MODE);
+ reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ }
+
return 0;
}
+static void mt6589_restore_pfh_settings(struct mtk_iommu_v1_data *data)
+{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num_larb = data->soc->num_larb;
+ int larb, port;
+
+ for (larb = 0; larb < num_larb; larb++) {
+ int mmu_id = (larb == 0 || larb == 2) ? 0 : 1;
+ void __iomem *base = data->cores[mmu_id].base;
+ int max_port = (larb == num_larb - 1) ? 32 : offsets[larb+1] - offsets[larb];
+ for (port = 0; port < max_port; port++) {
+ int global_port = offsets[larb] + port;
+ m4u_set_field(base, REG_MMU_PFH_DIST(global_port),
+ F_MMU_PFH_DIST_MASK(global_port),
+ F_MMU_PFH_DIST_VAL(global_port, 1));
+ m4u_set_field(base, REG_MMU_PFH_DIR(global_port),
+ 1 << (global_port & 0x1f), 0);
+ }
+ }
+}
+
static int __maybe_unused mtk_iommu_v1_resume(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
-
- writel_relaxed(data->m4u_dom->pgt_pa, base + REG_MMU_PT_BASE_ADDR);
- writel_relaxed(reg->standard_axi_mode,
- base + REG_MMU_STANDARD_AXI_MODE);
- writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
- writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
- writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
- writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ void __iomem *base = data->cores[0].base;
+
+ if (data->soc->has_global_base) {
+ writel_relaxed(reg->mmug_ctrl, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(reg->mmug_pt_base, data->global_base + REG_MMUg_PT_BASE);
+ writel_relaxed(reg->mmug_l2_sel, data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(reg->mmug_dcm, data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ writel_relaxed(reg->l2_gdc_op, data->l2_base + REG_L2_GDC_OP);
+
+ /* Restore SMI registers */
+ void __iomem *smi_ext = ioremap(SMI_COMMON_EXT_BASE, 0x500);
+ void __iomem *smi_ao = ioremap(SMI_COMMON_AO_BASE, 0x1000);
+ if (smi_ext && smi_ao) {
+ writel_relaxed(reg->smi_l1len, smi_ext + REG_SMI_L1LEN);
+ writel_relaxed(reg->smi_bus_sel, smi_ext + REG_SMI_BUS_SEL);
+ for (int i = 0; i < 7; i++)
+ writel_relaxed(reg->smi_secur_con[i], smi_ao + REG_SMI_SECUR_CON(i));
+ }
+ iounmap(smi_ext);
+ iounmap(smi_ao);
+ }
+
+ /* Per-core restore (common) */
+ for (int i = 0; i < data->soc->num_cores; i++) {
+ base = data->cores[i].base;
+ writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
+ writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ if (!data->soc->has_global_base) {
+ /* MT2701 extra */
+ base = data->cores[0].base;
+ writel_relaxed(reg->standard_axi_mode, base + REG_MMU_STANDARD_AXI_MODE);
+ writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
+ }
+
+ if (data->m4u_dom && data->m4u_dom->pgt_pa) {
+ if (data->soc->pt_base_in_global)
+ writel_relaxed(data->m4u_dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel_relaxed(data->m4u_dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
+ }
+
+ if (data->soc->has_global_base)
+ mt6589_restore_pfh_settings(data);
+
return 0;
}
|
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
//config G3D route to EMI (MCI in default)
m4uHw_set_field_by_mask(0, REG_SMI_L1LEN, F_SMI_L1LEN_AXROUTE_G3D_EMI(1), F_SMI_L1LEN_AXROUTE_G3D_EMI(1));
//config AUDIO route to EMI (MCI in default)
m4uHw_set_field_by_mask(0, REG_SMI_L1LEN, F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1), F_SMI_L1LEN_AXROUTE_AUDIO_EMI(1)); |
Member
Author
//===============================
// LARB
//===============================
/* cache coherent operations:
SMI_SHARE_EN SMI_ROUTE_ENABLE coherent_EN+pagetable_coherent operation
0 1 0 EMI
0 1 1 MCI+snoop
0 0 0 MCI
0 0 1 MCI+snoop
1 1 0 MCI+snoop
1 1 1 MCI+snoop
1 0 0 MCI+snoop
1 0 1 MCI+snoop
*/
{
int i;
for(i=0; i<SMI_LARB_NR; i++)
{
larb_clock_on(i);
//set SMI_SHARE_EN to 0
M4U_WriteReg32(gLarbBaseAddr[i], SMI_SHARE_EN, 0x0);
//set SMI_ROUTE_SEL to 1
if(i==2)
M4U_WriteReg32(gLarbBaseAddr[i], SMI_ROUTE_SEL, 0x1e);
else if(i==4)
M4U_WriteReg32(gLarbBaseAddr[i], SMI_ROUTE_SEL, 0xffffffff);
else
M4U_WriteReg32(gLarbBaseAddr[i], SMI_ROUTE_SEL, 0x0);
M4UMSG("larb clock on %d\n", i);
larb_clock_off(i);
}
}MT8135: FPGA only MT8127: partially MT6589 old: SMI_ROUTE_SEL is always 1 |
Link: #63 (comment) Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 591ffa66a728..bd2deee19ec5 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -7,6 +7,7 @@
*
* Based on driver/iommu/mtk_iommu.c
*/
+#include <linux/array_size.h>
#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/component.h>
@@ -26,9 +27,11 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string_choices.h>
+#include <linux/types.h>
#include <asm/barrier.h>
#include <dt-bindings/memory/mtk-memory-port.h>
#include <dt-bindings/memory/mt2701-larb-port.h>
+#include <dt-bindings/memory/mt6589-larb-port.h>
#include <soc/mediatek/smi.h>
#if defined(CONFIG_ARM)
@@ -51,6 +54,7 @@ struct dma_iommu_mapping {
#define F_MMU_FAULT_VA_MSK 0xfffff000
#define MTK_PROTECT_PA_ALIGN 128
+/* -------- Common M4U v1 register definitions (MT2701 and MT6589 core) -------- */
#define REG_MMU_CTRL_REG 0x210
#define F_MMU_CTRL_COHERENT_EN BIT(8)
#define REG_MMU_IVRP_PADDR 0x214
@@ -71,6 +75,8 @@ struct dma_iommu_mapping {
#define REG_MMU_FAULT_VA 0x228
#define REG_MMU_INVLD_PA 0x22C
#define REG_MMU_INT_ID 0x388
+
+/* MT2701 specific (core space) */
#define REG_MMU_INVALIDATE 0x5c0
#define REG_MMU_INVLD_START_A 0x5c4
#define REG_MMU_INVLD_END_A 0x5c8
@@ -81,14 +87,66 @@ struct dma_iommu_mapping {
#define REG_MMU_DCM 0x5f0
#define F_MMU_DCM_ON BIT(1)
#define REG_MMU_CPE_DONE 0x60c
+
+/* MT6589 global space registers */
+#define REG_MMUg_CTRL 0x00
+#define F_MMUg_CTRL_INV_EN0 BIT(0)
+#define F_MMUg_CTRL_INV_EN1 BIT(1)
+#define F_MMUg_CTRL_INV_EN2 BIT(2) /* L2 */
+#define F_MMUg_CTRL_PRE_LOCK(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_CTRL_PRE_EN BIT(4)
+
+#define REG_MMUg_INVLD 0x04
+#define F_MMUg_INV_ALL 0x2
+#define F_MMUg_INV_RANGE 0x1
+
+#define REG_MMUg_INVLD_SA 0x08
+#define REG_MMUg_INVLD_EA 0x0C
+#define REG_MMUg_PT_BASE 0x10
+#define F_MMUg_PT_VA_MSK 0xffff0000
+
+#define REG_MMUg_L2_SEL 0x18
+#define F_MMUg_L2_SEL_FLUSH_EN(en) ((en) ? BIT(3) : 0)
+#define F_MMUg_L2_SEL_L2_ULTRA(en) ((en) ? BIT(2) : 0)
+#define F_MMUg_L2_SEL_L2_SHARE(en) ((en) ? BIT(1) : 0)
+#define F_MMUg_L2_SEL_L2_BUS_SEL(go_emi) ((go_emi) ? BIT(0) : 0)
+
+#define REG_MMUg_DCM 0x1C
+#define F_MMUg_DCM_ON(on) ((on) ? BIT(0) : 0)
+
+/* L2 cache registers (MT6589) */
+#define REG_L2_GDC_STATE 0x00
+#define F_L2_GDC_ST_EVENT_MSK GENMASK(7,6)
+#define F_L2_GDC_ST_EVENT_VAL(val) (((val) & 0x3) << 6)
+
+#define REG_L2_GDC_OP 0x04
+#define F_L2_GDC_BYPASS(en) ((en) ? BIT(10) : 0)
+#define F_L2_GDC_PERF_MASK(msk) (((msk) & 0x7) << 7)
+#define GDC_PERF_MASK_HIT_MISS 0
+#define F_L2_GDC_LOCK_ALERT_DIS(dis) ((dis) ? BIT(6) : 0)
+#define F_L2_GDC_PERF_EN(en) ((en) ? BIT(5) : 0)
+#define F_L2_GDC_LOCK_TH(th) (((th) & 0x3) << 2)
+#define F_L2_GDC_PAUSE_OP(op) ((op) & 0x3)
+#define GDC_NO_PAUSE 0
+
+#define REG_L2_GPE_STATUS 0x18
+#define F_L2_GPE_ST_RANGE_INV_DONE BIT(1)
+#define F_L2_GPE_ST_PREFETCH_DONE BIT(0)
+
+/* MT6589 core PFH distance / direction registers */
+#define REG_MMU_PFH_DIST(port) (0x80 + (((port) >> 3) << 2))
+#define F_MMU_PFH_DIST_VAL(port, val) (((val) & 0xf) << (((port) & 0x7) << 2))
+#define F_MMU_PFH_DIST_MASK(port) F_MMU_PFH_DIST_VAL(port, 0xf)
+
+#define REG_MMU_PFH_DIR(port) (((port) < 32) ? 0xF0 : 0xF4)
+#define F_MMU_PFH_DIR(port, val) ((!!(val)) << ((port) & 0x1f))
+
+/* Common page table descriptor bits */
#define F_DESC_VALID 0x2
#define F_DESC_NONSEC BIT(3)
-#define MT2701_M4U_TF_LARB(TF) (6 - (((TF) >> 13) & 0x7))
-#define MT2701_M4U_TF_PORT(TF) (((TF) >> 8) & 0xF)
/* MTK generation one iommu HW only support 4K size mapping */
#define MT2701_IOMMU_PAGE_SHIFT 12
#define MT2701_IOMMU_PAGE_SIZE (1UL << MT2701_IOMMU_PAGE_SHIFT)
-#define MT2701_LARB_NR_MAX 3
/*
* MTK m4u support 4GB iova address space, and only support 4K page
@@ -96,26 +154,72 @@ struct dma_iommu_mapping {
*/
#define M2701_IOMMU_PGT_SIZE SZ_4M
+#define MAX_M4U_CORES 2
+
+struct mtk_iommu_v1_data;
+
+struct mtk_iommu_v1_soc_data {
+ const char *compatible;
+ unsigned int num_cores;
+ bool has_global_base;
+ bool has_l2_cache;
+
+ void (*tlb_flush_all)(struct mtk_iommu_v1_data *data);
+ void (*tlb_flush_range)(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size);
+
+ void (*get_fault_larb_port)(u32 int_id, unsigned int *larb,
+ unsigned int *port);
+
+ int (*hw_init)(struct mtk_iommu_v1_data *data);
+
+ u32 pt_base_reg_offset;
+ bool pt_base_in_global;
+
+ const int *larb_port_offsets;
+ unsigned int num_larb;
+};
+
+struct mtk_iommu_v1_core {
+ void __iomem *base;
+ int irq;
+ struct mtk_iommu_v1_data *data;
+ unsigned int id;
+};
+
struct mtk_iommu_v1_suspend_reg {
+ /* MT2701 fields */
u32 standard_axi_mode;
u32 dcm_dis;
u32 ctrl_reg;
u32 int_control0;
+
+ /* MT6589 additional fields */
+ u32 mmug_ctrl;
+ u32 mmug_pt_base;
+ u32 mmug_l2_sel;
+ u32 mmug_dcm;
+ u32 l2_gdc_op;
};
struct mtk_iommu_v1_data {
- void __iomem *base;
- int irq;
- struct device *dev;
- struct clk *bclk;
- phys_addr_t protect_base; /* protect memory base */
- struct mtk_iommu_v1_domain *m4u_dom;
-
- struct iommu_device iommu;
- struct dma_iommu_mapping *mapping;
- struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
-
- struct mtk_iommu_v1_suspend_reg reg;
+ const struct mtk_iommu_v1_soc_data *soc;
+ struct device *dev;
+
+ struct mtk_iommu_v1_core cores[MAX_M4U_CORES];
+ void __iomem *global_base;
+ void __iomem *l2_base;
+
+ struct clk *bclk;
+ phys_addr_t protect_base;
+ struct mtk_iommu_v1_domain *m4u_dom;
+
+ struct iommu_device iommu;
+ struct dma_iommu_mapping *mapping;
+ struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
+
+ struct mtk_iommu_v1_suspend_reg reg;
+ struct page *dummy_page; /* Physical address of guard dummy page */
};
struct mtk_iommu_v1_domain {
@@ -150,73 +254,143 @@ static const int mt2701_m4u_in_larb[] = {
MT2701_LARB2_PORT_OFFSET, MT2701_LARB3_PORT_OFFSET
};
-static inline int mt2701_m4u_to_larb(int id)
+static const int mt6589_m4u_in_larb[] = {
+ MT6589_LARB0_PORT_OFFSET, MT6589_LARB1_PORT_OFFSET,
+ MT6589_LARB2_PORT_OFFSET, MT6589_LARB3_PORT_OFFSET,
+ MT6589_LARB4_PORT_OFFSET, MT6589_LARB5_PORT_OFFSET
+};
+
+static inline int mtk_iommu_v1_to_larb(struct mtk_iommu_v1_data *data, int id)
{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num = data->soc->num_larb;
int i;
- for (i = ARRAY_SIZE(mt2701_m4u_in_larb) - 1; i >= 0; i--)
- if ((id) >= mt2701_m4u_in_larb[i])
+ for (i = num - 1; i >= 0; i--)
+ if (id >= offsets[i])
return i;
return 0;
}
-static inline int mt2701_m4u_to_port(int id)
+static inline int mtk_iommu_v1_to_port(struct mtk_iommu_v1_data *data, int id)
{
- int larb = mt2701_m4u_to_larb(id);
+ int larb = mtk_iommu_v1_to_larb(data, id);
+ return id - data->soc->larb_port_offsets[larb];
+}
- return id - mt2701_m4u_in_larb[larb];
+static inline void m4u_set_field(void __iomem *base, u32 reg, u32 mask, u32 val)
+{
+ u32 regval = readl_relaxed(base + reg);
+ regval = (regval & ~mask) | val;
+ writel_relaxed(regval, base + reg);
}
-static void mtk_iommu_v1_tlb_flush_all(struct mtk_iommu_v1_data *data)
+/* MT2701 (single core, no global space) */
+static void mt2701_tlb_flush_all(struct mtk_iommu_v1_data *data)
{
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
- wmb(); /* Make sure the tlb flush all done */
+ void __iomem *base = data->cores[0].base;
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(F_ALL_INVLD, base + REG_MMU_INVALIDATE);
+ wmb();
}
-static void mtk_iommu_v1_tlb_flush_range(struct mtk_iommu_v1_data *data,
- unsigned long iova, size_t size)
+static void mt2701_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
{
- int ret;
+ void __iomem *base = data->cores[0].base;
u32 tmp;
+ int ret;
- writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0,
- data->base + REG_MMU_INV_SEL);
- writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_START_A);
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, base + REG_MMU_INV_SEL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK, base + REG_MMU_INVLD_START_A);
writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
- data->base + REG_MMU_INVLD_END_A);
- writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
+ base + REG_MMU_INVLD_END_A);
+ writel_relaxed(F_MMU_INV_RANGE, base + REG_MMU_INVALIDATE);
- ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE,
- tmp, tmp != 0, 10, 100000);
+ ret = readl_poll_timeout_atomic(base + REG_MMU_CPE_DONE,
+ tmp, tmp != 0, 10, 100000);
if (ret) {
dev_warn(data->dev,
"Partial TLB flush timed out, falling back to full flush\n");
- mtk_iommu_v1_tlb_flush_all(data);
+ mt2701_tlb_flush_all(data);
+ }
+ writel_relaxed(0, base + REG_MMU_CPE_DONE);
+}
+
+/* MT6589 (global control, L2) */
+static void mt6589_tlb_flush_all(struct mtk_iommu_v1_data *data)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(F_MMUg_INV_ALL, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 event;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GDC_STATE,
+ event,
+ event & F_L2_GDC_ST_EVENT_MSK,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GDC_STATE);
+ }
+}
+
+static void mt6589_tlb_flush_range(struct mtk_iommu_v1_data *data,
+ unsigned long iova, size_t size)
+{
+ u32 reg = F_MMUg_CTRL_INV_EN0 | F_MMUg_CTRL_INV_EN1;
+ if (data->l2_base)
+ reg |= F_MMUg_CTRL_INV_EN2;
+
+ writel_relaxed(reg, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(iova & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_SA);
+ writel_relaxed((iova + size - 1) & F_MMU_FAULT_VA_MSK,
+ data->global_base + REG_MMUg_INVLD_EA);
+ writel_relaxed(F_MMUg_INV_RANGE, data->global_base + REG_MMUg_INVLD);
+
+ if (data->l2_base) {
+ u32 status;
+ readl_poll_timeout_atomic(data->l2_base + REG_L2_GPE_STATUS,
+ status,
+ status & F_L2_GPE_ST_RANGE_INV_DONE,
+ 10, 100000);
+ writel_relaxed(0, data->l2_base + REG_L2_GPE_STATUS);
}
- /* Clear the CPE status */
- writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+}
+
+static void mt2701_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - ((int_id >> 13) & 0x7);
+ *port = (int_id >> 8) & 0xF;
+}
+
+static void mt6589_get_fault_larb_port(u32 int_id, unsigned int *larb,
+ unsigned int *port)
+{
+ *larb = 6 - (int_id >> 12) & 0x7;
+ *port = (int_id >> 8) & 0xF;
}
static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
{
- struct mtk_iommu_v1_data *data = dev_id;
+ struct mtk_iommu_v1_core *core = dev_id;
+ struct mtk_iommu_v1_data *data = core->data;
struct mtk_iommu_v1_domain *dom = data->m4u_dom;
u32 int_state, regval, fault_iova, fault_pa;
unsigned int fault_larb, fault_port;
/* Read error information from registers */
- int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST);
- fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+ int_state = readl_relaxed(core->base + REG_MMU_FAULT_ST);
+ fault_iova = readl_relaxed(core->base + REG_MMU_FAULT_VA) & F_MMU_FAULT_VA_MSK;
+ fault_pa = readl_relaxed(core->base + REG_MMU_INVLD_PA);
+ regval = readl_relaxed(core->base + REG_MMU_INT_ID);
- fault_iova &= F_MMU_FAULT_VA_MSK;
- fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
- regval = readl_relaxed(data->base + REG_MMU_INT_ID);
- fault_larb = MT2701_M4U_TF_LARB(regval);
- fault_port = MT2701_M4U_TF_PORT(regval);
+ data->soc->get_fault_larb_port(regval, &fault_larb, &fault_port);
/*
* MTK v1 iommu HW could not determine whether the fault is read or
@@ -225,16 +399,16 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
IOMMU_FAULT_READ))
dev_err_ratelimited(data->dev,
- "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d\n",
+ "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d core=%d\n",
int_state, fault_iova, fault_pa,
- fault_larb, fault_port);
+ fault_larb, fault_port, core->id);
/* Interrupt clear */
- regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL);
+ regval = readl_relaxed(core->base + REG_MMU_INT_CONTROL);
regval |= F_INT_CLR_BIT;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, core->base + REG_MMU_INT_CONTROL);
- mtk_iommu_v1_tlb_flush_all(data);
+ data->soc->tlb_flush_all(data);
return IRQ_HANDLED;
}
@@ -242,14 +416,14 @@ static irqreturn_t mtk_iommu_v1_isr(int irq, void *dev_id)
static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
struct device *dev, bool enable)
{
- struct mtk_smi_larb_iommu *larb_mmu;
- unsigned int larbid, portid;
+ struct mtk_smi_larb_iommu *larb_mmu;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- int i;
+ unsigned int larbid, portid, i, mmu_id;
+ void __iomem *base;
for (i = 0; i < fwspec->num_ids; ++i) {
- larbid = mt2701_m4u_to_larb(fwspec->ids[i]);
- portid = mt2701_m4u_to_port(fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
larb_mmu = &data->larb_imu[larbid];
dev_dbg(dev, "%s iommu port: %d\n",
@@ -260,6 +434,26 @@ static void mtk_iommu_v1_config(struct mtk_iommu_v1_data *data,
else
larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
}
+
+ /* MT6589 specific: set default prefetch distance & direction */
+ if (data->soc->has_global_base) {
+ for (i = 0; i < fwspec->num_ids; i++) {
+ portid = mtk_iommu_v1_to_port(data, fwspec->ids[i]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[i]);
+
+ /* Determine which M4U core this LARB is connected to */
+ mmu_id = (larbid == 0 || larbid == 2) ? 0 : 1;
+ base = data->cores[mmu_id].base;
+
+ /* Set distance = 1 */
+ m4u_set_field(base, REG_MMU_PFH_DIST(portid),
+ F_MMU_PFH_DIST_MASK(portid),
+ F_MMU_PFH_DIST_VAL(portid, 1));
+ /* Set direction = 0 */
+ m4u_set_field(base, REG_MMU_PFH_DIR(portid),
+ 1 << (portid & 0x1f), 0);
+ }
+ }
}
static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
@@ -273,7 +467,10 @@ static int mtk_iommu_v1_domain_finalise(struct mtk_iommu_v1_data *data)
if (!dom->pgt_va)
return -ENOMEM;
- writel(dom->pgt_pa, data->base + REG_MMU_PT_BASE_ADDR);
+ if (data->soc->pt_base_in_global)
+ writel(dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel(dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
dom->data = data;
@@ -354,10 +551,12 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
int prot, gfp_t gfp, size_t *mapped)
{
struct mtk_iommu_v1_domain *dom = to_mtk_domain(domain);
+ struct mtk_iommu_v1_data *data = dom->data;
unsigned long flags;
- unsigned int i;
- u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
+ unsigned int i, guard_pages = (data->soc->has_global_base) ? 4 : 0;
+ u32 *pgt_base_iova = dom->pgt_va + (iova >> MT2701_IOMMU_PAGE_SHIFT);
u32 pabase = (u32)paddr;
+ phys_addr_t dummy_pa = page_to_phys(data->dummy_page);
spin_lock_irqsave(&dom->pgtlock, flags);
for (i = 0; i < pgcount; i++) {
@@ -367,10 +566,19 @@ static int mtk_iommu_v1_map(struct iommu_domain *domain, unsigned long iova,
pabase += MT2701_IOMMU_PAGE_SIZE;
}
+ if (guard_pages && i == pgcount) {
+ for (i = pgcount; i < pgcount + guard_pages; i++) {
+ if ((iova >> MT2701_IOMMU_PAGE_SHIFT) + i >= (M2701_IOMMU_PGT_SIZE / sizeof(u32)))
+ break;
+ if (pgt_base_iova[i] == 0)
+ pgt_base_iova[i] = dummy_pa | F_DESC_VALID | F_DESC_NONSEC;
+ }
+ }
+
spin_unlock_irqrestore(&dom->pgtlock, flags);
*mapped = i * MT2701_IOMMU_PAGE_SIZE;
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, *mapped);
+ data->soc->tlb_flush_range(data, iova, *mapped);
return i == pgcount ? 0 : -EEXIST;
}
@@ -388,7 +596,7 @@ static size_t mtk_iommu_v1_unmap(struct iommu_domain *domain, unsigned long iova
memset(pgt_base_iova, 0, pgcount * sizeof(u32));
spin_unlock_irqrestore(&dom->pgtlock, flags);
- mtk_iommu_v1_tlb_flush_range(dom->data, iova, size);
+ dom->data->soc->tlb_flush_range(dom->data, iova, size);
return size;
}
@@ -489,12 +697,12 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
data = dev_iommu_priv_get(dev);
/* Link the consumer device with the smi-larb device(supplier) */
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
- if (larbid >= MT2701_LARB_NR_MAX)
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
+ if (larbid >= MTK_LARB_NR_MAX)
return ERR_PTR(-EINVAL);
for (idx = 1; idx < fwspec->num_ids; idx++) {
- larbidx = mt2701_m4u_to_larb(fwspec->ids[idx]);
+ larbidx = mtk_iommu_v1_to_larb(data, fwspec->ids[idx]);
if (larbid != larbidx) {
dev_err(dev, "Can only use one larb. Fail@larb%d-%d.\n",
larbid, larbidx);
@@ -532,12 +740,12 @@ static void mtk_iommu_v1_release_device(struct device *dev)
unsigned int larbid;
data = dev_iommu_priv_get(dev);
- larbid = mt2701_m4u_to_larb(fwspec->ids[0]);
+ larbid = mtk_iommu_v1_to_larb(data, fwspec->ids[0]);
larbdev = data->larb_imu[larbid].dev;
device_link_remove(dev, larbdev);
}
-static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
+static int mt2701_hw_init(struct mtk_iommu_v1_data *data)
{
u32 regval;
int ret;
@@ -549,7 +757,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
}
regval = F_MMU_CTRL_COHERENT_EN | F_MMU_TF_PROTECT_SEL(2);
- writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_CTRL_REG);
regval = F_INT_TRANSLATION_FAULT |
F_INT_MAIN_MULTI_HIT_FAULT |
@@ -559,23 +767,66 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data)
F_INT_TLB_MISS_FAULT |
F_INT_PFH_DMA_FIFO_OVERFLOW |
F_INT_MISS_DMA_FIFO_OVERFLOW;
- writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL);
+ writel_relaxed(regval, data->cores[0].base + REG_MMU_INT_CONTROL);
- /* protect memory,hw will write here while translation fault */
- writel_relaxed(data->protect_base,
- data->base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(data->protect_base, data->cores[0].base + REG_MMU_IVRP_PADDR);
+ writel_relaxed(F_MMU_DCM_ON, data->cores[0].base + REG_MMU_DCM);
- writel_relaxed(F_MMU_DCM_ON, data->base + REG_MMU_DCM);
+ return 0;
+}
- if (devm_request_irq(data->dev, data->irq, mtk_iommu_v1_isr, 0,
- dev_name(data->dev), (void *)data)) {
- writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
- clk_disable_unprepare(data->bclk);
- dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
- return -ENODEV;
+static int mt6589_hw_init(struct mtk_iommu_v1_data *data)
+{
+ u32 regval;
+ int i, ret;
+
+ ret = clk_prepare_enable(data->bclk);
+ if (ret) {
+ dev_err(data->dev, "Failed to enable bclk\n");
+ goto err_clk;
+ }
+
+ /* ---- Global registers ---- */
+ writel_relaxed(F_MMUg_L2_SEL_FLUSH_EN(1) | F_MMUg_L2_SEL_L2_ULTRA(1) |
+ F_MMUg_L2_SEL_L2_SHARE(0) | F_MMUg_L2_SEL_L2_BUS_SEL(1),
+ data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(F_MMUg_DCM_ON(1), data->global_base + REG_MMUg_DCM);
+
+ /* ---- L2 cache ---- */
+ if (data->l2_base) {
+ regval = F_L2_GDC_BYPASS(0) |
+ F_L2_GDC_PERF_MASK(GDC_PERF_MASK_HIT_MISS) |
+ F_L2_GDC_LOCK_ALERT_DIS(0) |
+ F_L2_GDC_LOCK_TH(3) |
+ F_L2_GDC_PAUSE_OP(GDC_NO_PAUSE);
+ writel_relaxed(regval, data->l2_base + REG_L2_GDC_OP);
+ }
+
+ /* ---- Per-core setup ---- */
+ for (i = 0; i < data->soc->num_cores; i++) {
+ void __iomem *base = data->cores[i].base;
+
+ regval = 0; /* PFH enabled, walk enabled, cohere disabled */
+ regval |= F_MMU_TF_PROTECT_SEL(2);
+ writel_relaxed(regval, base + REG_MMU_CTRL_REG);
+
+ regval = F_INT_TRANSLATION_FAULT |
+ F_INT_MAIN_MULTI_HIT_FAULT |
+ F_INT_INVALID_PA_FAULT |
+ F_INT_ENTRY_REPLACEMENT_FAULT |
+ F_INT_TABLE_WALK_FAULT |
+ F_INT_TLB_MISS_FAULT |
+ F_INT_PFH_DMA_FIFO_OVERFLOW |
+ F_INT_MISS_DMA_FIFO_OVERFLOW;
+ writel_relaxed(regval, base + REG_MMU_INT_CONTROL);
+
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
}
return 0;
+
+err_clk:
+ return ret;
}
static const struct iommu_ops mtk_iommu_v1_ops = {
@@ -595,8 +846,39 @@ static const struct iommu_ops mtk_iommu_v1_ops = {
}
};
+static const struct mtk_iommu_v1_soc_data mt2701_soc_data = {
+ .compatible = "mediatek,mt2701-m4u",
+ .num_cores = 1,
+ .has_global_base = false,
+ .has_l2_cache = false,
+ .tlb_flush_all = mt2701_tlb_flush_all,
+ .tlb_flush_range = mt2701_tlb_flush_range,
+ .get_fault_larb_port = mt2701_get_fault_larb_port,
+ .hw_init = mt2701_hw_init,
+ .pt_base_reg_offset = REG_MMU_PT_BASE_ADDR,
+ .pt_base_in_global = false,
+ .larb_port_offsets = mt2701_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt2701_m4u_in_larb),
+};
+
+static const struct mtk_iommu_v1_soc_data mt6589_soc_data = {
+ .compatible = "mediatek,mt6589-m4u",
+ .num_cores = 2,
+ .has_global_base = true,
+ .has_l2_cache = true,
+ .tlb_flush_all = mt6589_tlb_flush_all,
+ .tlb_flush_range = mt6589_tlb_flush_range,
+ .get_fault_larb_port = mt6589_get_fault_larb_port,
+ .hw_init = mt6589_hw_init,
+ .pt_base_reg_offset = REG_MMUg_PT_BASE,
+ .pt_base_in_global = true,
+ .larb_port_offsets = mt6589_m4u_in_larb,
+ .num_larb = ARRAY_SIZE(mt6589_m4u_in_larb),
+};
+
static const struct of_device_id mtk_iommu_v1_of_ids[] = {
- { .compatible = "mediatek,mt2701-m4u", },
+ { .compatible = "mediatek,mt2701-m4u", .data = &mt2701_soc_data },
+ { .compatible = "mediatek,mt6589-m4u", .data = &mt6589_soc_data },
{}
};
MODULE_DEVICE_TABLE(of, mtk_iommu_v1_of_ids);
@@ -610,16 +892,19 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_iommu_v1_data *data;
- struct resource *res;
+ const struct mtk_iommu_v1_soc_data *soc;
struct component_match *match = NULL;
void *protect;
int larb_nr, ret, i;
+ struct page *dummy_page;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->dev = dev;
+ soc = of_device_get_match_data(dev);
+ data->soc = soc;
/* Protect memory. HW will access here while translation fault.*/
protect = devm_kcalloc(dev, 2, MTK_PROTECT_PA_ALIGN,
@@ -628,26 +913,69 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
return -ENOMEM;
data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->irq = platform_get_irq(pdev, 0);
- if (data->irq < 0)
- return data->irq;
+ if (soc->has_global_base) {
+ data->global_base = devm_platform_ioremap_resource_byname(pdev,
+ "global");
+ if (IS_ERR(data->global_base))
+ return PTR_ERR(data->global_base);
+ }
+ for (i = 0; i < soc->num_cores; i++) {
+ char name[8];
+ snprintf(name, sizeof(name), "m4u%d", i);
+ data->cores[i].base = devm_platform_ioremap_resource_byname(pdev,
+ name);
+ if (IS_ERR(data->cores[i].base))
+ return PTR_ERR(data->cores[i].base);
+ data->cores[i].data = data;
+ data->cores[i].id = i;
+ }
+ if (soc->has_l2_cache) {
+ data->l2_base = devm_platform_ioremap_resource_byname(pdev,
+ "l2cache");
+ if (IS_ERR(data->l2_base))
+ return PTR_ERR(data->l2_base);
+ }
data->bclk = devm_clk_get(dev, "bclk");
if (IS_ERR(data->bclk))
return PTR_ERR(data->bclk);
+ /* Interrupts - request after hw_init to avoid spurious IRQs? but
+ we need the core IRQs ready before registering ISR. We'll request
+ them after hw_init for simplicity. */
+ ret = soc->hw_init(data);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < soc->num_cores; i++) {
+ struct mtk_iommu_v1_core *core = &data->cores[i];
+ char irqname[8];
+ snprintf(irqname, sizeof(irqname), "m4u%d", i);
+ core->irq = platform_get_irq_byname(pdev, irqname);
+ if (core->irq < 0) {
+ ret = core->irq;
+ goto out_clk_unprepare;
+ }
+ ret = devm_request_irq(dev, core->irq, mtk_iommu_v1_isr, 0,
+ dev_name(dev), core);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d for core%d\n",
+ core->irq, i);
+ goto out_clk_unprepare;
+ }
+ }
+
larb_nr = of_count_phandle_with_args(dev->of_node,
"mediatek,larbs", NULL);
- if (larb_nr < 0)
- return larb_nr;
+ if (larb_nr < 0) {
+ ret = larb_nr;
+ goto out_clk_unprepare;
+ }
- if (larb_nr > MTK_LARB_NR_MAX)
- return -EINVAL;
+ if (larb_nr > MTK_LARB_NR_MAX) {
+ ret = -EINVAL;
+ goto out_clk_unprepare;
+ }
for (i = 0; i < larb_nr; i++) {
struct device_node *larbnode;
@@ -682,17 +1010,20 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
component_compare_of, larbnode);
}
+ dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!dummy_page) {
+ ret = -ENOMEM;
+ goto out_put_larbs;
+ }
+ data->dummy_page = dummy_page;
+
platform_set_drvdata(pdev, data);
- ret = mtk_iommu_v1_hw_init(data);
+ ret = iommu_device_sysfs_add(&data->iommu, dev, NULL,
+ dev_name(dev));
if (ret)
goto out_put_larbs;
- ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
- dev_name(&pdev->dev));
- if (ret)
- goto out_clk_unprepare;
-
ret = iommu_device_register(&data->iommu, &mtk_iommu_v1_ops, dev);
if (ret)
goto out_sysfs_remove;
@@ -706,12 +1037,14 @@ static int mtk_iommu_v1_probe(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
out_sysfs_remove:
iommu_device_sysfs_remove(&data->iommu);
-out_clk_unprepare:
- clk_disable_unprepare(data->bclk);
out_put_larbs:
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
-
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
+ if (data->dummy_page)
+ __free_page(data->dummy_page);
+out_clk_unprepare:
+ clk_disable_unprepare(data->bclk);
return ret;
}
@@ -724,40 +1057,104 @@ static void mtk_iommu_v1_remove(struct platform_device *pdev)
iommu_device_unregister(&data->iommu);
clk_disable_unprepare(data->bclk);
- devm_free_irq(&pdev->dev, data->irq, data);
+ for (i = 0; i < data->soc->num_cores; i++)
+ devm_free_irq(&pdev->dev, data->cores[i].irq, &data->cores[i]);
component_master_del(&pdev->dev, &mtk_iommu_v1_com_ops);
+ __free_page(data->dummy_page);
for (i = 0; i < MTK_LARB_NR_MAX; i++)
- put_device(data->larb_imu[i].dev);
+ if (data->larb_imu[i].dev)
+ put_device(data->larb_imu[i].dev);
}
static int __maybe_unused mtk_iommu_v1_suspend(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
+ void __iomem *base = data->cores[0].base;
- reg->standard_axi_mode = readl_relaxed(base +
- REG_MMU_STANDARD_AXI_MODE);
- reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ /* Common core registers */
reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL);
+
+ if (data->soc->has_global_base) {
+ reg->mmug_ctrl = readl_relaxed(data->global_base + REG_MMUg_CTRL);
+ reg->mmug_pt_base = readl_relaxed(data->global_base + REG_MMUg_PT_BASE);
+ reg->mmug_l2_sel = readl_relaxed(data->global_base + REG_MMUg_L2_SEL);
+ reg->mmug_dcm = readl_relaxed(data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ reg->l2_gdc_op = readl_relaxed(data->l2_base + REG_L2_GDC_OP);
+ } else {
+ /* MT2701 specific */
+ base = data->cores[0].base;
+ reg->standard_axi_mode = readl_relaxed(base + REG_MMU_STANDARD_AXI_MODE);
+ reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM);
+ }
+
return 0;
}
+static void mt6589_restore_pfh_settings(struct mtk_iommu_v1_data *data)
+{
+ const int *offsets = data->soc->larb_port_offsets;
+ int num_larb = data->soc->num_larb;
+ int larb, port;
+
+ for (larb = 0; larb < num_larb; larb++) {
+ int mmu_id = (larb == 0 || larb == 2) ? 0 : 1;
+ void __iomem *base = data->cores[mmu_id].base;
+ int max_port = (larb == num_larb - 1) ? 32 : offsets[larb+1] - offsets[larb];
+ for (port = 0; port < max_port; port++) {
+ int global_port = offsets[larb] + port;
+ m4u_set_field(base, REG_MMU_PFH_DIST(global_port),
+ F_MMU_PFH_DIST_MASK(global_port),
+ F_MMU_PFH_DIST_VAL(global_port, 1));
+ m4u_set_field(base, REG_MMU_PFH_DIR(global_port),
+ 1 << (global_port & 0x1f), 0);
+ }
+ }
+}
+
static int __maybe_unused mtk_iommu_v1_resume(struct device *dev)
{
struct mtk_iommu_v1_data *data = dev_get_drvdata(dev);
struct mtk_iommu_v1_suspend_reg *reg = &data->reg;
- void __iomem *base = data->base;
-
- writel_relaxed(data->m4u_dom->pgt_pa, base + REG_MMU_PT_BASE_ADDR);
- writel_relaxed(reg->standard_axi_mode,
- base + REG_MMU_STANDARD_AXI_MODE);
- writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
- writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
- writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
- writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ void __iomem *base = data->cores[0].base;
+
+ if (data->soc->has_global_base) {
+ writel_relaxed(reg->mmug_ctrl, data->global_base + REG_MMUg_CTRL);
+ writel_relaxed(reg->mmug_pt_base, data->global_base + REG_MMUg_PT_BASE);
+ writel_relaxed(reg->mmug_l2_sel, data->global_base + REG_MMUg_L2_SEL);
+ writel_relaxed(reg->mmug_dcm, data->global_base + REG_MMUg_DCM);
+ if (data->l2_base)
+ writel_relaxed(reg->l2_gdc_op, data->l2_base + REG_L2_GDC_OP);
+ }
+
+ /* Per-core restore (common) */
+ for (int i = 0; i < data->soc->num_cores; i++) {
+ base = data->cores[i].base;
+ writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
+ writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL);
+ writel_relaxed(data->protect_base, base + REG_MMU_IVRP_PADDR);
+ }
+
+ if (!data->soc->has_global_base) {
+ /* MT2701 extra */
+ base = data->cores[0].base;
+ writel_relaxed(reg->standard_axi_mode, base + REG_MMU_STANDARD_AXI_MODE);
+ writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM);
+ }
+
+ if (data->m4u_dom && data->m4u_dom->pgt_pa) {
+ if (data->soc->pt_base_in_global)
+ writel_relaxed(data->m4u_dom->pgt_pa, data->global_base + data->soc->pt_base_reg_offset);
+ else
+ writel_relaxed(data->m4u_dom->pgt_pa, data->cores[0].base + data->soc->pt_base_reg_offset);
+ }
+
+ if (data->soc->has_global_base)
+ mt6589_restore_pfh_settings(data);
+
return 0;
}
|
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assited-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
The RDMA SIZE_CON0 and SIZE_CON1 values vary across different SoCs. Prepare for supporting new SoCs by moving these values into the mtk_disp_rdma_data and updating existing SoC data to use their respective values. Signed-off-by: rva3 <rva333@protonmail.com>
RDMA uses different values for memory formats. Currently, these are hardcoded using macros. Move the format conversion logic into function pointer instead of raw call. This allows other SoCs to provide their own mapping logic without breaking others. Also drop unused parameter in the rdma_fmt_convert method. Signed-off-by: rva3 <rva333@protonmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
got white screen |
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Member
Author
|
iommu is broken |
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
This reverts commit 655f321.
[ 0.164904] mtk-iommu-v1: mtk_iommu_v1_probe: probe failed with -517 [ 1.958301] mtk-iommu-v1: mtk_iommu_v1_probe: probe success I don't know why, but the probe fails the first time. Also, stopping <&infracfg CLK_INFRA_M4U> causes system hung. ~ # dmesg [ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 7.1.0-g1387b01de957-dirty (akku@buffalo-ssd) (clang version 22.1.8, LLD 22.1.8) #22 SMP Tue Jul 28 23:47:23 JST 2026 [ 0.000000] CPU: ARMv7 Processor [410fc072] revision 2 (ARMv7), cr=50c5387d [ 0.000000] CPU: div instructions available: patching division code [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache [ 0.000000] OF: fdt: Machine model: Lenovo YOGA Tablet 10 (Wi-Fi) [ 0.000000] Memory policy: Data cache writealloc [ 0.000000] Ignoring RAM at 0xbf600000-0xc0000000 [ 0.000000] Consider using a HIGHMEM enabled kernel. [ 0.000000] OF: reserved mem: 0x0010dc00..0x0010f7ff (7 KiB) map non-reusable ramoops@0010dc00 [ 0.000000] OF: reserved mem: 0xbf600000..0xbfffffff (10240 KiB) nomap non-reusable memory@bf600000 [ 0.000000] Zone ranges: [ 0.000000] Normal [mem 0x0000000080000000-0x00000000bf5fffff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x0000000080000000-0x00000000bf5fffff] [ 0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x00000000bf5fffff] [ 0.000000] On node 0, zone Normal: 512 pages in unavailable ranges [ 0.000000] percpu: Embedded 12 pages/cpu s16844 r8192 d24116 u49152 [ 0.000000] pcpu-alloc: s16844 r8192 d24116 u49152 alloc=12*4096 [ 0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3 [ 0.000000] Kernel command line: clk_ignore_unused printk.always_kmsg_dump=1 console=tty0 console=ttyMT0,921600n1 root=/dev/ram lcm=1-cm_hx8896a01_dsi_vdo_boe fps=5797 bootprof.pl_t=3601 bootprof.lk_t=2153 printk.disable_uart=1 boot_reason=4 [ 0.000000] Unknown kernel command line parameters "lcm=1-cm_hx8896a01_dsi_vdo_boe fps=5797 boot_reason=4", will be passed to user space. [ 0.000000] printk: log buffer data + meta data: 131072 + 409600 = 540672 bytes [ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes, linear) [ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes, linear) [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 259584 [ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 [ 0.000000] rcu: Hierarchical RCU implementation. [ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies. [ 0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16 [ 0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention. [ 0.000000] arch_timer: cp15 timer running at 13.00MHz (phys). [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x2ff89eacb, max_idle_ns: 440795202429 ns [ 0.000001] sched_clock: 56 bits at 13MHz, resolution 76ns, wraps every 4398046511101ns [ 0.000014] Switching to timer-based delay loop, resolution 76ns [ 0.000265] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 147020034397 ns [ 0.000281] sched_clock: 32 bits at 13MHz, resolution 76ns, wraps every 165191050201ns [ 0.000587] Console: colour dummy device 80x30 [ 0.000602] printk: legacy console [tty0] enabled [ 0.001023] Calibrating delay loop (skipped), value calculated using timer frequency.. 26.00 BogoMIPS (lpj=130000) [ 0.001057] CPU: Testing write buffer coherency: ok [ 0.001131] pid_max: default: 32768 minimum: 301 [ 0.001346] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes, linear) [ 0.001380] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes, linear) [ 0.001725] VFS: Finished mounting rootfs on nullfs [ 0.002304] /cpus/cpu@0 missing clock-frequency property [ 0.002346] /cpus/cpu@1 missing clock-frequency property [ 0.002377] /cpus/cpu@2 missing clock-frequency property [ 0.002408] /cpus/cpu@3 missing clock-frequency property [ 0.002431] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000 [ 0.003641] Setting up static identity map for 0x80100000 - 0x80100052 [ 0.003819] rcu: Hierarchical SRCU implementation. [ 0.003840] rcu: Max phase no-delay instances is 1000. [ 0.004475] smp: Bringing up secondary CPUs ... [ 0.005166] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001 [ 0.006062] CPU2: thread -1, cpu 2, socket 0, mpidr 80000002 [ 0.006894] CPU3: thread -1, cpu 3, socket 0, mpidr 80000003 [ 0.007107] smp: Brought up 1 node, 4 CPUs [ 0.007160] SMP: Total of 4 processors activated (104.00 BogoMIPS). [ 0.007180] CPU: All CPU(s) started in SVC mode. [ 0.007415] Memory: 1013520K/1038336K available (6144K kernel code, 632K rwdata, 2184K rodata, 1024K init, 214K bss, 21704K reserved, 0K cma-reserved) [ 0.007986] devtmpfs: initialized [ 0.016424] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 2 [ 0.016668] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns [ 0.016724] posixtimers hash table entries: 2048 (order: 2, 16384 bytes, linear) [ 0.016840] futex hash table entries: 1024 (65536 bytes on 1 NUMA nodes, total 64 KiB, linear). [ 0.018284] NET: Registered PF_NETLINK/PF_ROUTE protocol family [ 0.018607] DMA: preallocated 256 KiB pool for atomic coherent allocations [ 0.019801] cpuidle: using governor ladder [ 0.020511] pstore: Using crash dump compression: deflate [ 0.020540] printk: legacy console [ramoops-1] enabled [ 0.020910] pstore: Registered ramoops as persistent store backend [ 0.020932] ramoops: using 0x1c00@0x10dc00, ecc: 0 [ 0.025480] /soc/dsi@1400d000: Fixed dependency cycle(s) with /soc/dsi@1400d000/panel@0 [ 0.025541] /soc/dsi@1400d000/panel@0: Fixed dependency cycle(s) with /soc/dsi@1400d000 [ 0.042952] /soc/dsi@1400d000: Fixed dependency cycle(s) with /soc/dsi@1400d000/panel@0 [ 0.043204] /soc/dsi@1400d000/panel@0: Fixed dependency cycle(s) with /soc/dsi@1400d000 [ 0.045802] iommu: Default domain type: Translated [ 0.045834] iommu: DMA domain TLB invalidation policy: strict mode [ 0.046263] usbcore: registered new interface driver usbfs [ 0.046348] usbcore: registered new interface driver hub [ 0.046406] usbcore: registered new device driver usb [ 0.046695] pps_core: LinuxPPS API ver. 1 registered [ 0.046719] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> [ 0.046761] PTP clock support registered [ 0.049169] clocksource: Switched to clocksource arch_sys_counter [ 0.057888] NET: Registered PF_INET protocol family [ 0.058150] IP idents hash table entries: 16384 (order: 5, 131072 bytes, linear) [ 0.060090] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear) [ 0.060140] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear) [ 0.060175] TCP established hash table entries: 8192 (order: 3, 32768 bytes, linear) [ 0.060278] TCP bind hash table entries: 8192 (order: 5, 131072 bytes, linear) [ 0.060515] TCP: Hash tables configured (established 8192 bind 8192) [ 0.060634] UDP hash table entries: 512 (order: 3, 28672 bytes, linear) [ 0.060850] NET: Registered PF_UNIX/PF_LOCAL protocol family [ 0.061386] Trying to unpack rootfs image as initramfs... [ 0.061871] workingset: timestamp_bits=30 (anon: 26) max_order=18 bucket_order=0 (anon: 0) [ 0.062440] io scheduler mq-deadline registered [ 0.062473] io scheduler kyber registered [ 0.062513] io scheduler bfq registered [ 0.070982] mediatek-mipi-tx 10012000.dsi-phy: can't get nvmem_cell_get, ignore it [ 0.083116] mtk-socinfo mtk-socinfo.0.auto: error -ENOENT: Failed to get socinfo data [ 0.083170] mtk-socinfo mtk-socinfo.0.auto: probe with driver mtk-socinfo failed with error -2 [ 0.083261] mtk-socinfo mtk-socinfo.1.auto: error -ENOENT: Failed to get socinfo data [ 0.083293] mtk-socinfo mtk-socinfo.1.auto: probe with driver mtk-socinfo failed with error -2 [ 0.126019] Freeing initrd memory: 1348K [ 0.140064] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.163050] 11006000.serial: ttyS0 at MMIO 0x11006000 (irq = 223, base_baud = 1625000) is a ST16650V2 [ 0.164029] mtk-iommu-v1: mtk_iommu_v1_probe: start probing 10205000.iommu [ 0.164064] mtk-iommu-v1: mtk_iommu_v1_probe: compatible=mediatek,mt6589-m4u, cores=2 [ 0.164093] mtk-iommu-v1: mtk_iommu_v1_probe: protect_base=0x820f2280 [ 0.164132] mtk-iommu-v1: mtk_iommu_v1_probe: global_base=ef9af000 [ 0.164167] mtk-iommu-v1: mtk_iommu_v1_probe: core[0] base=ef9b1200 [ 0.164201] mtk-iommu-v1: mtk_iommu_v1_probe: core[1] base=ef9b3800 [ 0.164234] mtk-iommu-v1: mtk_iommu_v1_probe: l2_base=ef9b5100 [ 0.164269] mtk-iommu-v1: mtk_iommu_v1_probe: dummy_page allocated [ 0.164291] mtk-iommu-v1: mt6589_hw_init called [ 0.164319] mtk-iommu-v1: mt6589_hw_init: global L2_SEL & DCM set [ 0.164341] mtk-iommu-v1: mt6589_hw_init: L2 GDC_OP = 0xc [ 0.164362] mtk-iommu-v1: mt6589_hw_init: core[0] CTRL_REG = 0x43 [ 0.164385] mtk-iommu-v1: mt6589_hw_init: core[0] INT_CONTROL & IVRP set [ 0.164408] mtk-iommu-v1: mt6589_hw_init: core[1] CTRL_REG = 0x43 [ 0.164431] mtk-iommu-v1: mt6589_hw_init: core[1] INT_CONTROL & IVRP set [ 0.164563] mtk-iommu-v1: mtk_iommu_v1_probe: IRQ 224 requested for core0 [ 0.164671] mtk-iommu-v1: mtk_iommu_v1_probe: IRQ 225 requested for core1 [ 0.164699] mtk-iommu-v1: mtk_iommu_v1_probe: larb count = 5 [ 0.164741] mtk-iommu-v1: mtk_iommu_v1_probe: larb 0 driver not ready, defer [ 0.164765] mtk-iommu-v1: mtk_iommu_v1_probe: larb 0: of_node_put done [ 0.164788] mtk-iommu-v1: mtk_iommu_v1_probe: larb 0 put_device done [ 0.164810] mtk-iommu-v1: mtk_iommu_v1_probe: start out_put_larbs: [ 0.164836] mtk-iommu-v1: mtk_iommu_v1_probe: __free_page done [ 0.164858] mtk-iommu-v1: mtk_iommu_v1_probe: core 0 REG_MMU_INT_CONTROL done [ 0.164881] mtk-iommu-v1: mtk_iommu_v1_probe: core 1 REG_MMU_INT_CONTROL done [ 0.164904] mtk-iommu-v1: mtk_iommu_v1_probe: probe failed with -517 [ 0.167634] /soc/dsi@1400d000: Fixed dependency cycle(s) with /soc/dsi@1400d000/panel@0 [ 0.167746] /soc/dsi@1400d000/panel@0: Fixed dependency cycle(s) with /soc/dsi@1400d000 [ 0.181002] brd: module loaded [ 0.186955] loop: module loaded [ 0.319174] mt6320-regulator mt6320-regulator: Chip ID = 0x2020 [ 1.202208] input: mt6779-keypad as /devices/platform/soc/10015000.keyboard/input/input0 [ 1.249337] input: mtk-pmic-keys as /devices/platform/soc/1000f000.pwrap/1000f000.pwrap:mt6320/mt6320-keys/input/input1 [ 1.559543] mt6397-rtc mt6320-rtc: registered as rtc0 [ 1.649257] i2c_dev: i2c /dev entries driver [ 1.749172] vgp6: Bringing 2800000uV into 1800000-1800000uV [ 1.860716] power_supply bq27541-0: driver failed to report `status' property: -6 [ 1.862649] bq24190-charger 6-006b: using polling mode, interval 10000 ms [ 1.863387] mtk-wdt 10000000.watchdog: Watchdog enabled (timeout=31 sec, nowayout=0) [ 1.879347] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.879502] power_supply bq27541-0: driver failed to report `status' property: -6 [ 1.879561] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.879596] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.879851] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.879900] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.880156] bq24190-charger 6-006b: warning: /sys/class/power_supply/bq24190-battery is deprecated [ 1.901383] usbcore: registered new interface driver usbhid [ 1.901418] usbhid: USB HID core driver [ 1.901559] mtk-smi: mtk_smi_init: initializing [ 1.902044] mtk-smi: mtk_smi_common_probe: probing 10202000.smi [ 1.902082] mtk-smi: mtk_smi_common_probe: type=0 has_gals=0 clk_required=2 [ 1.902107] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=0 [ 1.902143] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 2 [ 1.902190] mtk-smi: mtk_smi_common_probe: Gen0 mapped ao_base and base [ 1.902214] mtk-smi: mtk_smi_common_probe: probe success [ 1.903084] mtk-smi: mtk_smi_larb_probe: probing 17001000.larb [ 1.903150] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=1 [ 1.903189] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 3 [ 1.903213] mtk-smi: mtk_smi_device_link_common: linking device 17001000.larb [ 1.903321] mtk-smi: mtk_smi_device_link_common: linked to 10202000.smi [ 1.903348] mtk-smi: mtk_smi_larb_probe: probe success [ 1.903453] mtk-smi: mtk_smi_larb_probe: probing 16010000.larb [ 1.903501] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=1 [ 1.903538] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 3 [ 1.903561] mtk-smi: mtk_smi_device_link_common: linking device 16010000.larb [ 1.903661] mtk-smi: mtk_smi_device_link_common: linked to 10202000.smi [ 1.903687] mtk-smi: mtk_smi_larb_probe: probe success [ 1.903789] mtk-smi: mtk_smi_larb_probe: probing 14010000.larb [ 1.903836] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=1 [ 1.903873] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 3 [ 1.903896] mtk-smi: mtk_smi_device_link_common: linking device 14010000.larb [ 1.903993] mtk-smi: mtk_smi_device_link_common: linked to 10202000.smi [ 1.904019] mtk-smi: mtk_smi_larb_probe: probe success [ 1.904119] mtk-smi: mtk_smi_larb_probe: probing 15001000.larb [ 1.904165] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=1 [ 1.904201] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 3 [ 1.904225] mtk-smi: mtk_smi_device_link_common: linking device 15001000.larb [ 1.904339] mtk-smi: mtk_smi_device_link_common: linked to 10202000.smi [ 1.904366] mtk-smi: mtk_smi_larb_probe: probe success [ 1.904468] mtk-smi: mtk_smi_larb_probe: probing 15002000.larb [ 1.904514] mtk-smi: mtk_smi_dts_clk_init: required=2 optional=1 [ 1.904549] mtk-smi: mtk_smi_dts_clk_init: clocks acquired, total 3 [ 1.904573] mtk-smi: mtk_smi_device_link_common: linking device 15002000.larb [ 1.904674] mtk-smi: mtk_smi_device_link_common: linked to 10202000.smi [ 1.904699] mtk-smi: mtk_smi_larb_probe: probe success [ 1.905365] NET: Registered PF_INET6 protocol family [ 1.906303] Segment Routing with IPv6 [ 1.906383] In-situ OAM (IOAM) with IPv6 [ 1.906487] NET: Registered PF_PACKET protocol family [ 1.906593] ThumbEE CPU extension supported. [ 1.906620] Registering SWP/SWPB emulation handler [ 1.957149] mtk-iommu-v1: mtk_iommu_v1_probe: start probing 10205000.iommu [ 1.957201] mtk-iommu-v1: mtk_iommu_v1_probe: compatible=mediatek,mt6589-m4u, cores=2 [ 1.957226] mtk-iommu-v1: mtk_iommu_v1_probe: protect_base=0x819c5a80 [ 1.957256] mtk-iommu-v1: mtk_iommu_v1_probe: global_base=efab3000 [ 1.957286] mtk-iommu-v1: mtk_iommu_v1_probe: core[0] base=efab5200 [ 1.957314] mtk-iommu-v1: mtk_iommu_v1_probe: core[1] base=efab7800 [ 1.957342] mtk-iommu-v1: mtk_iommu_v1_probe: l2_base=efab9100 [ 1.957371] mtk-iommu-v1: mtk_iommu_v1_probe: dummy_page allocated [ 1.957390] mtk-iommu-v1: mt6589_hw_init called [ 1.957408] mtk-iommu-v1: mt6589_hw_init: global L2_SEL & DCM set [ 1.957425] mtk-iommu-v1: mt6589_hw_init: L2 GDC_OP = 0xc [ 1.957443] mtk-iommu-v1: mt6589_hw_init: core[0] CTRL_REG = 0x43 [ 1.957462] mtk-iommu-v1: mt6589_hw_init: core[0] INT_CONTROL & IVRP set [ 1.957481] mtk-iommu-v1: mt6589_hw_init: core[1] CTRL_REG = 0x43 [ 1.957500] mtk-iommu-v1: mt6589_hw_init: core[1] INT_CONTROL & IVRP set [ 1.957570] mtk-iommu-v1: mtk_iommu_v1_probe: IRQ 224 requested for core0 [ 1.957613] mtk-iommu-v1: mtk_iommu_v1_probe: IRQ 225 requested for core1 [ 1.957635] mtk-iommu-v1: mtk_iommu_v1_probe: larb count = 5 [ 1.957953] mtk-smi: mtk_smi_larb_bind: binding device 17001000.larb [ 1.957976] mtk-smi: mtk_smi_larb_bind: found larb id=0 mmu=b22c68a4 bank=b22c68a8 [ 1.958005] mtk-iommu-v1 10205000.iommu: bound 17001000.larb (ops 0xb07b714c) [ 1.958033] mtk-smi: mtk_smi_larb_bind: binding device 16010000.larb [ 1.958052] mtk-smi: mtk_smi_larb_bind: found larb id=1 mmu=b22c68cc bank=b22c68d0 [ 1.958077] mtk-iommu-v1 10205000.iommu: bound 16010000.larb (ops 0xb07b714c) [ 1.958101] mtk-smi: mtk_smi_larb_bind: binding device 14010000.larb [ 1.958120] mtk-smi: mtk_smi_larb_bind: found larb id=2 mmu=b22c68f4 bank=b22c68f8 [ 1.958145] mtk-iommu-v1 10205000.iommu: bound 14010000.larb (ops 0xb07b714c) [ 1.958168] mtk-smi: mtk_smi_larb_bind: binding device 15001000.larb [ 1.958187] mtk-smi: mtk_smi_larb_bind: found larb id=3 mmu=b22c691c bank=b22c6920 [ 1.958212] mtk-iommu-v1 10205000.iommu: bound 15001000.larb (ops 0xb07b714c) [ 1.958235] mtk-smi: mtk_smi_larb_bind: binding device 15002000.larb [ 1.958254] mtk-smi: mtk_smi_larb_bind: found larb id=4 mmu=b22c6944 bank=b22c6948 [ 1.958278] mtk-iommu-v1 10205000.iommu: bound 15002000.larb (ops 0xb07b714c) [ 1.958301] mtk-iommu-v1: mtk_iommu_v1_probe: probe success [ 1.958675] OVL: RDMA0 didn't complete frame [ 1.960732] RDMA reset stage 1 timeout [ 1.964103] clk: Not disabling unused clocks [ 1.964132] PM: genpd: Disabling unused power domains [ 1.975330] OVL: OVL frame underflow [ 1.975350] OVL: RDMA0 didn't complete frame [ 1.975366] OVL: RDMA0 FIFO underflow [ 2.009768] OVL: RDMA0 didn't complete frame [ 2.041979] mtk-msdc 11240000.mmc: Got CD GPIO [ 2.042626] usb_phy_generic usb_phy_generic.3.auto: dummy supplies not allowed for exclusive requests (id=vbus) [ 2.044230] OVL: RDMA0 didn't complete frame [ 2.049356] musb-hdrc musb-hdrc.4.auto: MUSB HDRC host driver [ 2.049396] musb-hdrc musb-hdrc.4.auto: new USB bus registered, assigned bus number 1 [ 2.050055] hub 1-0:1.0: USB hub found [ 2.050107] hub 1-0:1.0: 1 port detected [ 2.319914] OVL: RDMA0 didn't complete frame [ 2.337144] OVL: RDMA0 didn't complete frame [ 2.354375] OVL: RDMA0 didn't complete frame Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
Assisted-by: DeepSeek:deepseek-v4-pro Signed-off-by: Akari Tsuyukusa <akkun11.open@gmail.com>
akku1139
force-pushed
the
dev/v7.1/mt6589-drm
branch
from
August 1, 2026 11:22
5d02652 to
440d0c8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
from: #33