From 0d8657dd3056063fb115946b10157477b5c70451 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 20 Nov 2023 09:09:45 +0000
Subject: [PATCH] enable lvds 1280x800
---
kernel/drivers/iommu/rockchip-iommu.c | 213 ++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 169 insertions(+), 44 deletions(-)
diff --git a/kernel/drivers/iommu/rockchip-iommu.c b/kernel/drivers/iommu/rockchip-iommu.c
index 38e70c1..4a8481a 100644
--- a/kernel/drivers/iommu/rockchip-iommu.c
+++ b/kernel/drivers/iommu/rockchip-iommu.c
@@ -114,6 +114,7 @@
dma_addr_t dt_dma;
spinlock_t iommus_lock; /* lock for iommus list */
spinlock_t dt_lock; /* lock for modifying page directory table */
+ bool shootdown_entire;
struct iommu_domain domain;
};
@@ -132,11 +133,14 @@
bool skip_read; /* rk3126/rk3128 can't read vop iommu registers */
bool dlr_disable; /* avoid access iommu when runtime ops called */
bool cmd_retry;
+ bool master_handle_irq;
struct iommu_device iommu;
struct list_head node; /* entry in rk_iommu_domain.iommus */
struct iommu_domain *domain; /* domain to which iommu is attached */
struct iommu_group *group;
u32 version;
+ bool shootdown_entire;
+ bool need_res_map;
};
struct rk_iommudata {
@@ -146,6 +150,9 @@
};
static struct device *dma_dev;
+static struct rk_iommu *rk_iommu_from_dev(struct device *dev);
+static char reserve_range[PAGE_SIZE] __aligned(PAGE_SIZE);
+static phys_addr_t res_page;
static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
unsigned int count)
@@ -290,6 +297,8 @@
#define RK_PTE_PAGE_READABLE_V2 BIT(2)
#define RK_PTE_PAGE_WRITABLE_V2 BIT(1)
+#define RK_PTE_PAGE_REPRESENT BIT(3)
+
static inline phys_addr_t rk_pte_page_address(u32 pte)
{
return (phys_addr_t)pte & RK_PTE_PAGE_ADDRESS_MASK;
@@ -311,6 +320,11 @@
return pte & RK_PTE_PAGE_VALID;
}
+static inline bool rk_pte_is_page_represent(u32 pte)
+{
+ return pte & RK_PTE_PAGE_REPRESENT;
+}
+
/* TODO: set cache flags per prot IOMMU_CACHE */
static u32 rk_mk_pte(phys_addr_t page, int prot)
{
@@ -318,6 +332,8 @@
flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE : 0;
flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE : 0;
+ flags |= (prot & IOMMU_PRIV) ? RK_PTE_PAGE_REPRESENT : 0;
+
page &= RK_PTE_PAGE_ADDRESS_MASK;
return page | flags | RK_PTE_PAGE_VALID;
}
@@ -328,6 +344,12 @@
flags |= (prot & IOMMU_READ) ? RK_PTE_PAGE_READABLE_V2 : 0;
flags |= (prot & IOMMU_WRITE) ? RK_PTE_PAGE_WRITABLE_V2 : 0;
+ /* If BIT(3) set, don't break iommu_map if BIT(0) set.
+ * Means we can reupdate a page that already presented. We can use
+ * this bit to reupdate a pre-mapped 4G range.
+ */
+ flags |= (prot & IOMMU_PRIV) ? RK_PTE_PAGE_REPRESENT : 0;
+
page = (page & PAGE_DESC_LO_MASK) |
((page & PAGE_DESC_HI_MASK1) >> PAGE_DESC_HI_SHIFT1) |
(page & PAGE_DESC_HI_MASK2) >> PAGE_DESC_HI_SHIFT2;
@@ -337,7 +359,7 @@
static u32 rk_mk_pte_invalid(u32 pte)
{
- return pte & ~RK_PTE_PAGE_VALID;
+ return pte & ~(RK_PTE_PAGE_VALID | RK_PTE_PAGE_REPRESENT);
}
/*
@@ -686,22 +708,14 @@
rk_pte_is_page_valid(pte), &page_addr_phys, page_flags);
}
-static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
+static int rk_pagefault_done(struct rk_iommu *iommu)
{
- struct rk_iommu *iommu = dev_id;
u32 status;
u32 int_status;
- u32 int_mask;
dma_addr_t iova;
+ int i;
+ u32 int_mask;
irqreturn_t ret = IRQ_NONE;
- int i, err;
-
- err = pm_runtime_get_if_in_use(iommu->dev);
- if (WARN_ON_ONCE(err <= 0))
- return ret;
-
- if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
- goto out;
for (i = 0; i < iommu->num_mmu; i++) {
int_status = rk_iommu_read(iommu->bases[i], RK_MMU_INT_STATUS);
@@ -724,16 +738,18 @@
log_iova(iommu, i, iova);
- /*
- * Report page fault to any installed handlers.
- * Ignore the return code, though, since we always zap cache
- * and clear the page fault anyway.
- */
- if (iommu->domain)
- report_iommu_fault(iommu->domain, iommu->dev, iova,
+ if (!iommu->master_handle_irq) {
+ /*
+ * Report page fault to any installed handlers.
+ * Ignore the return code, though, since we always zap cache
+ * and clear the page fault anyway.
+ */
+ if (iommu->domain)
+ report_iommu_fault(iommu->domain, iommu->dev, iova,
status);
- else
- dev_err(iommu->dev, "Page fault while iommu not attached to domain?\n");
+ else
+ dev_err(iommu->dev, "Page fault while iommu not attached to domain?\n");
+ }
rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
@@ -755,6 +771,46 @@
int_status);
rk_iommu_write(iommu->bases[i], RK_MMU_INT_CLEAR, int_status);
+ }
+
+ return ret;
+}
+
+int rockchip_pagefault_done(struct device *master_dev)
+{
+ struct rk_iommu *iommu = rk_iommu_from_dev(master_dev);
+
+ return rk_pagefault_done(iommu);
+}
+EXPORT_SYMBOL_GPL(rockchip_pagefault_done);
+
+void __iomem *rockchip_get_iommu_base(struct device *master_dev, int idx)
+{
+ struct rk_iommu *iommu = rk_iommu_from_dev(master_dev);
+
+ return iommu->bases[idx];
+}
+EXPORT_SYMBOL_GPL(rockchip_get_iommu_base);
+
+static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
+{
+ struct rk_iommu *iommu = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ int err;
+
+ err = pm_runtime_get_if_in_use(iommu->dev);
+ if (WARN_ON_ONCE(err <= 0))
+ return ret;
+
+ if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
+ goto out;
+
+ /* Master must call rockchip_pagefault_done to handle pagefault */
+ if (iommu->master_handle_irq) {
+ if (iommu->domain)
+ ret = report_iommu_fault(iommu->domain, iommu->dev, -1, 0x0);
+ } else {
+ ret = rk_pagefault_done(iommu);
}
clk_bulk_disable(iommu->num_clocks, iommu->clocks);
@@ -825,6 +881,10 @@
{
struct list_head *pos;
unsigned long flags;
+
+ /* Do not zap tlb cache line if shootdown_entire set */
+ if (rk_domain->shootdown_entire)
+ return;
/* shootdown these iova from all iommus using this domain */
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
@@ -936,10 +996,11 @@
static size_t rk_iommu_unmap_iova(struct rk_iommu_domain *rk_domain,
u32 *pte_addr, dma_addr_t pte_dma,
- size_t size)
+ size_t size, struct rk_iommu *iommu)
{
unsigned int pte_count;
unsigned int pte_total = size / SPAGE_SIZE;
+ int prot = IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV;
assert_spin_locked(&rk_domain->dt_lock);
@@ -948,12 +1009,36 @@
if (!rk_pte_is_page_valid(pte))
break;
- pte_addr[pte_count] = rk_mk_pte_invalid(pte);
+ if (iommu && iommu->need_res_map) {
+ if (iommu->version >= 0x2)
+ pte_addr[pte_count] = rk_mk_pte_v2(res_page,
+ prot);
+ else
+ pte_addr[pte_count] = rk_mk_pte(res_page, prot);
+ } else {
+ pte_addr[pte_count] = rk_mk_pte_invalid(pte);
+ }
}
rk_table_flush(rk_domain, pte_dma, pte_count);
return pte_count * SPAGE_SIZE;
+}
+
+static struct rk_iommu *rk_iommu_get(struct rk_iommu_domain *rk_domain)
+{
+ unsigned long flags;
+ struct list_head *pos;
+ struct rk_iommu *iommu = NULL;
+
+ spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+ list_for_each(pos, &rk_domain->iommus) {
+ iommu = list_entry(pos, struct rk_iommu, node);
+ if (iommu->need_res_map)
+ break;
+ }
+ spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
+ return iommu;
}
static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
@@ -969,12 +1054,15 @@
for (pte_count = 0; pte_count < pte_total; pte_count++) {
u32 pte = pte_addr[pte_count];
- if (rk_pte_is_page_valid(pte))
+ if (rk_pte_is_page_valid(pte) && !rk_pte_is_page_represent(pte))
goto unwind;
- pte_addr[pte_count] = rk_mk_pte(paddr, prot);
-
- paddr += SPAGE_SIZE;
+ if (prot & IOMMU_PRIV) {
+ pte_addr[pte_count] = rk_mk_pte(res_page, prot);
+ } else {
+ pte_addr[pte_count] = rk_mk_pte(paddr, prot);
+ paddr += SPAGE_SIZE;
+ }
}
rk_table_flush(rk_domain, pte_dma, pte_total);
@@ -985,16 +1073,13 @@
* We only zap the first and last iova, since only they could have
* dte or pte shared with an existing mapping.
*/
-
- /* Do not zap tlb cache line if IOMMU_TLB_SHOT_ENTIRE set */
- if (!(prot & IOMMU_TLB_SHOT_ENTIRE))
- rk_iommu_zap_iova_first_last(rk_domain, iova, size);
+ rk_iommu_zap_iova_first_last(rk_domain, iova, size);
return 0;
unwind:
/* Unmap the range of iovas that we just mapped */
rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma,
- pte_count * SPAGE_SIZE);
+ pte_count * SPAGE_SIZE, NULL);
iova += pte_count * SPAGE_SIZE;
page_phys = rk_pte_page_address(pte_addr[pte_count]);
@@ -1017,12 +1102,15 @@
for (pte_count = 0; pte_count < pte_total; pte_count++) {
u32 pte = pte_addr[pte_count];
- if (rk_pte_is_page_valid(pte))
+ if (rk_pte_is_page_valid(pte) && !rk_pte_is_page_represent(pte))
goto unwind;
- pte_addr[pte_count] = rk_mk_pte_v2(paddr, prot);
-
- paddr += SPAGE_SIZE;
+ if (prot & IOMMU_PRIV) {
+ pte_addr[pte_count] = rk_mk_pte_v2(res_page, prot);
+ } else {
+ pte_addr[pte_count] = rk_mk_pte_v2(paddr, prot);
+ paddr += SPAGE_SIZE;
+ }
}
rk_table_flush(rk_domain, pte_dma, pte_total);
@@ -1033,16 +1121,13 @@
* We only zap the first and last iova, since only they could have
* dte or pte shared with an existing mapping.
*/
-
- /* Do not zap tlb cache line if IOMMU_TLB_SHOT_ENTIRE set */
- if (!(prot & IOMMU_TLB_SHOT_ENTIRE))
- rk_iommu_zap_iova_first_last(rk_domain, iova, size);
+ rk_iommu_zap_iova_first_last(rk_domain, iova, size);
return 0;
unwind:
/* Unmap the range of iovas that we just mapped */
rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma,
- pte_count * SPAGE_SIZE);
+ pte_count * SPAGE_SIZE, NULL);
iova += pte_count * SPAGE_SIZE;
page_phys = rk_pte_page_address_v2(pte_addr[pte_count]);
@@ -1136,6 +1221,7 @@
u32 dte;
u32 *pte_addr;
size_t unmap_size;
+ struct rk_iommu *iommu = rk_iommu_get(rk_domain);
spin_lock_irqsave(&rk_domain->dt_lock, flags);
@@ -1156,7 +1242,8 @@
pt_phys = rk_dte_pt_address(dte);
pte_addr = (u32 *)phys_to_virt(pt_phys) + rk_iova_pte_index(iova);
pte_dma = pt_phys + rk_iova_pte_index(iova) * sizeof(u32);
- unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size);
+ unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size,
+ iommu);
spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
@@ -1176,6 +1263,7 @@
u32 dte;
u32 *pte_addr;
size_t unmap_size;
+ struct rk_iommu *iommu = rk_iommu_get(rk_domain);
spin_lock_irqsave(&rk_domain->dt_lock, flags);
@@ -1196,7 +1284,8 @@
pt_phys = rk_dte_pt_address_v2(dte);
pte_addr = (u32 *)phys_to_virt(pt_phys) + rk_iova_pte_index(iova);
pte_dma = pt_phys + rk_iova_pte_index(iova) * sizeof(u32);
- unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size);
+ unmap_size = rk_iommu_unmap_iova(rk_domain, pte_addr, pte_dma, size,
+ iommu);
spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
@@ -1345,6 +1434,28 @@
}
EXPORT_SYMBOL(rockchip_iommu_is_enabled);
+int rockchip_iommu_force_reset(struct device *dev)
+{
+ struct rk_iommu *iommu;
+ int ret;
+
+ iommu = rk_iommu_from_dev(dev);
+ if (!iommu)
+ return -ENODEV;
+
+ ret = rk_iommu_enable_stall(iommu);
+ if (ret)
+ return ret;
+
+ ret = rk_iommu_force_reset(iommu);
+
+ rk_iommu_disable_stall(iommu);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(rockchip_iommu_force_reset);
+
static void rk_iommu_detach_device(struct iommu_domain *domain,
struct device *dev)
{
@@ -1413,6 +1524,7 @@
list_add_tail(&iommu->node, &rk_domain->iommus);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
+ rk_domain->shootdown_entire = iommu->shootdown_entire;
ret = pm_runtime_get_if_in_use(iommu->dev);
if (!ret || WARN_ON_ONCE(ret < 0))
return 0;
@@ -1764,11 +1876,16 @@
"rockchip,skip-mmu-read");
iommu->dlr_disable = device_property_read_bool(dev,
"rockchip,disable-device-link-resume");
-
+ iommu->shootdown_entire = device_property_read_bool(dev,
+ "rockchip,shootdown-entire");
+ iommu->master_handle_irq = device_property_read_bool(dev,
+ "rockchip,master-handle-irq");
if (of_machine_is_compatible("rockchip,rv1126") ||
of_machine_is_compatible("rockchip,rv1109"))
iommu->cmd_retry = device_property_read_bool(dev,
"rockchip,enable-cmd-retry");
+ iommu->need_res_map = device_property_read_bool(dev,
+ "rockchip,reserve-map");
/*
* iommu clocks should be present for all new devices and devicetrees
@@ -1839,6 +1956,10 @@
}
skip_request_irq:
+ if (!res_page && iommu->need_res_map) {
+ res_page = __pa_symbol(reserve_range);
+ pr_info("%s,%d, res_page = 0x%pa\n", __func__, __LINE__, &res_page);
+ }
return 0;
err_remove_sysfs:
iommu_device_sysfs_remove(&iommu->iommu);
@@ -1854,9 +1975,13 @@
struct rk_iommu *iommu = platform_get_drvdata(pdev);
int i = 0, irq;
+ if (iommu->skip_read)
+ goto skip_free_irq;
+
while ((irq = platform_get_irq(pdev, i++)) != -ENXIO)
devm_free_irq(iommu->dev, irq, iommu);
+skip_free_irq:
pm_runtime_force_suspend(&pdev->dev);
}
--
Gitblit v1.6.2