diff options
Diffstat (limited to 'arch/arm/mach-tegra/iovmm-gart.c')
-rw-r--r-- | arch/arm/mach-tegra/iovmm-gart.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/arch/arm/mach-tegra/iovmm-gart.c b/arch/arm/mach-tegra/iovmm-gart.c index 9616af6672a1..fa4534d0167b 100644 --- a/arch/arm/mach-tegra/iovmm-gart.c +++ b/arch/arm/mach-tegra/iovmm-gart.c @@ -4,7 +4,7 @@ * Tegra I/O VMM implementation for GART devices in Tegra and Tegra 2 series * systems-on-a-chip. * - * Copyright (c) 2010-2011, NVIDIA Corporation. + * Copyright (c) 2010-2012, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,6 +54,20 @@ struct gart_device { bool enable; }; +/* + * Any interaction between any block on PPSB and a block on APB or AHB + * must have these read-back to ensure the APB/AHB bus transaction is + * complete before initiating activity on the PPSB block. + */ +#define FLUSH_GART_REGS(gart) (void)readl((gart)->regs + GART_CONFIG) + +static inline void gart_set_pte(struct gart_device *gart, + tegra_iovmm_addr_t offs, u32 pte) +{ + writel(offs, gart->regs + GART_ENTRY_ADDR); + writel(pte, gart->regs + GART_ENTRY_DATA); +} + static int gart_map(struct tegra_iovmm_domain *, struct tegra_iovmm_area *); static void gart_unmap(struct tegra_iovmm_domain *, struct tegra_iovmm_area *, bool); @@ -102,7 +116,6 @@ static int gart_suspend(struct tegra_iovmm_device *dev) for (i = 0; i < gart->page_count; i++) { writel(reg, gart->regs + GART_ENTRY_ADDR); gart->savedata[i] = readl(gart->regs + GART_ENTRY_DATA); - dmb(); reg += 1 << GART_PAGE_SHIFT; } spin_unlock(&gart->pte_lock); @@ -118,11 +131,10 @@ static void do_gart_setup(struct gart_device *gart, const u32 *data) reg = gart->iovmm_base; for (i = 0; i < gart->page_count; i++) { - writel(reg, gart->regs + GART_ENTRY_ADDR); - writel((data) ? data[i] : 0, gart->regs + GART_ENTRY_DATA); - wmb(); + gart_set_pte(gart, reg, data ? data[i] : 0); reg += 1 << GART_PAGE_SHIFT; } + FLUSH_GART_REGS(gart); } static void gart_resume(struct tegra_iovmm_device *dev) @@ -189,7 +201,7 @@ static int gart_probe(struct platform_device *pdev) return -ENOMEM; } - gart_regs = ioremap_wc(res->start, res->end - res->start + 1); + gart_regs = ioremap(res->start, res->end - res->start + 1); if (!gart_regs) { pr_err(DRIVER_NAME ": failed to remap GART registers\n"); e = -ENXIO; @@ -249,7 +261,7 @@ static void __exit gart_exit(void) platform_driver_unregister(&tegra_iovmm_gart_drv); } -#define GART_PTE(_pfn) (0x80000000ul | ((_pfn)<<PAGE_SHIFT)) +#define GART_PTE(_pfn) (0x80000000ul | ((_pfn) << PAGE_SHIFT)) static int gart_map(struct tegra_iovmm_domain *domain, @@ -272,11 +284,9 @@ static int gart_map(struct tegra_iovmm_domain *domain, spin_lock(&gart->pte_lock); - writel(gart_page, gart->regs + GART_ENTRY_ADDR); - writel(GART_PTE(pfn), gart->regs + GART_ENTRY_DATA); - wmb(); + gart_set_pte(gart, gart_page, GART_PTE(pfn)); + FLUSH_GART_REGS(gart); gart_page += 1 << GART_PAGE_SHIFT; - spin_unlock(&gart->pte_lock); } @@ -287,10 +297,9 @@ fail: while (i--) { iovma->ops->release(iovma, i << PAGE_SHIFT); gart_page -= 1 << GART_PAGE_SHIFT; - writel(gart_page, gart->regs + GART_ENTRY_ADDR); - writel(0, gart->regs + GART_ENTRY_DATA); - wmb(); + gart_set_pte(gart, gart_page, 0); } + FLUSH_GART_REGS(gart); spin_unlock(&gart->pte_lock); return -ENOMEM; @@ -312,11 +321,10 @@ static void gart_unmap(struct tegra_iovmm_domain *domain, if (iovma->ops && iovma->ops->release) iovma->ops->release(iovma, i << PAGE_SHIFT); - writel(gart_page, gart->regs + GART_ENTRY_ADDR); - writel(0, gart->regs + GART_ENTRY_DATA); - wmb(); + gart_set_pte(gart, gart_page, 0); gart_page += 1 << GART_PAGE_SHIFT; } + FLUSH_GART_REGS(gart); spin_unlock(&gart->pte_lock); } @@ -329,9 +337,8 @@ static void gart_map_pfn(struct tegra_iovmm_domain *domain, BUG_ON(!pfn_valid(pfn)); spin_lock(&gart->pte_lock); - writel(offs, gart->regs + GART_ENTRY_ADDR); - writel(GART_PTE(pfn), gart->regs + GART_ENTRY_DATA); - wmb(); + gart_set_pte(gart, offs, GART_PTE(pfn)); + FLUSH_GART_REGS(gart); spin_unlock(&gart->pte_lock); } |