Skip to content

Commit

Permalink
iommu/exynos: Gating clocks of master H/W
Browse files Browse the repository at this point in the history
This patch gates clocks of master H/W as well as clocks of System MMU
if master clocks are specified.

Some Exynos SoCs (i.e. GScalers in Exynos5250) have dependencies in
the gating clocks of master H/W and its System MMU. If a H/W is the
case, accessing control registers of System MMU is prohibited unless
both of the gating clocks of System MMU and its master H/W.

CC: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
Cho KyongHo authored and Joerg Roedel committed May 13, 2014
1 parent 46c16d1 commit 7060587
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions drivers/iommu/exynos-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ struct sysmmu_drvdata {
struct device *dev; /* Owner of system MMU */
void __iomem *sfrbase;
struct clk *clk;
struct clk *clk_master;
int activations;
rwlock_t lock;
struct iommu_domain *domain;
Expand Down Expand Up @@ -300,6 +301,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)

WARN_ON(!is_sysmmu_active(data));

if (!IS_ERR(data->clk_master))
clk_enable(data->clk_master);
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data->sfrbase + REG_INT_STATUS));
if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
Expand All @@ -326,6 +329,9 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data->sfrbase);

if (!IS_ERR(data->clk_master))
clk_disable(data->clk_master);

read_unlock(&data->lock);

return IRQ_HANDLED;
Expand All @@ -341,9 +347,14 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
if (!set_sysmmu_inactive(data))
goto finish;

if (!IS_ERR(data->clk_master))
clk_enable(data->clk_master);

__raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);

clk_disable(data->clk);
if (!IS_ERR(data->clk_master))
clk_disable(data->clk_master);

disabled = true;
data->pgtable = 0;
Expand Down Expand Up @@ -386,14 +397,19 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data,
goto finish;
}

clk_enable(data->clk);

data->pgtable = pgtable;

if (!IS_ERR(data->clk_master))
clk_enable(data->clk_master);
clk_enable(data->clk);

__sysmmu_set_ptbase(data->sfrbase, pgtable);

__raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL);

if (!IS_ERR(data->clk_master))
clk_disable(data->clk_master);

data->domain = domain;

dev_dbg(data->sysmmu, "Enabled\n");
Expand Down Expand Up @@ -450,6 +466,10 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova,
if (is_sysmmu_active(data)) {
unsigned int maj;
unsigned int num_inv = 1;

if (!IS_ERR(data->clk_master))
clk_enable(data->clk_master);

maj = __raw_readl(data->sfrbase + REG_MMU_VERSION);
/*
* L2TLB invalidation required
Expand All @@ -469,6 +489,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova,
data->sfrbase, iova, num_inv);
sysmmu_unblock(data->sfrbase);
}
if (!IS_ERR(data->clk_master))
clk_disable(data->clk_master);
} else {
dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n");
}
Expand All @@ -484,10 +506,14 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
read_lock_irqsave(&data->lock, flags);

if (is_sysmmu_active(data)) {
if (!IS_ERR(data->clk_master))
clk_enable(data->clk_master);
if (sysmmu_block(data->sfrbase)) {
__sysmmu_tlb_invalidate(data->sfrbase);
sysmmu_unblock(data->sfrbase);
}
if (!IS_ERR(data->clk_master))
clk_disable(data->clk_master);
} else {
dev_dbg(data->sysmmu, "Disabled. Skipping invalidating TLB.\n");
}
Expand Down Expand Up @@ -536,6 +562,16 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
}
}

data->clk_master = devm_clk_get(dev, "master");
if (!IS_ERR(data->clk_master)) {
ret = clk_prepare(data->clk_master);
if (ret) {
clk_unprepare(data->clk);
dev_err(dev, "Failed to prepare master's clk\n");
return ret;
}
}

data->sysmmu = dev;
rwlock_init(&data->lock);
INIT_LIST_HEAD(&data->node);
Expand Down

0 comments on commit 7060587

Please sign in to comment.