iommu/rockchip: correct pm runtime when remove device
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / rockchip-iommu.c
index 616d8481a7778c27bb7c51caafda1b67fa5017c9..c4c2c54a6127992b12c4ff0a269cebeb2076736a 100644 (file)
@@ -4,6 +4,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clk.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -19,6 +20,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
@@ -79,8 +81,8 @@ struct rk_iommu_domain {
        struct platform_device *pdev;
        u32 *dt; /* page directory table */
        dma_addr_t dt_dma;
-       spinlock_t iommus_lock; /* lock for iommus list */
-       spinlock_t dt_lock; /* lock for modifying page directory table */
+       struct mutex iommus_lock; /* lock for iommus list */
+       struct mutex dt_lock; /* lock for modifying page directory table */
 
        struct iommu_domain domain;
 };
@@ -90,8 +92,11 @@ struct rk_iommu {
        void __iomem **bases;
        int num_mmu;
        int irq;
+       bool reset_disabled; /* isp iommu reset operation would failed */
        struct list_head node; /* entry in rk_iommu_domain.iommus */
        struct iommu_domain *domain; /* domain to which iommu is attached */
+       struct clk *aclk; /* aclock belong to master */
+       struct clk *hclk; /* hclock belong to master */
 };
 
 static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
@@ -255,6 +260,26 @@ static u32 rk_mk_pte_invalid(u32 pte)
 #define RK_IOVA_PAGE_MASK   0x00000fff
 #define RK_IOVA_PAGE_SHIFT  0
 
+static void rk_iommu_power_on(struct rk_iommu *iommu)
+{
+       if (iommu->aclk && iommu->hclk) {
+               clk_enable(iommu->aclk);
+               clk_enable(iommu->hclk);
+       }
+
+       pm_runtime_get_sync(iommu->dev);
+}
+
+static void rk_iommu_power_off(struct rk_iommu *iommu)
+{
+       pm_runtime_put_sync(iommu->dev);
+
+       if (iommu->aclk && iommu->hclk) {
+               clk_disable(iommu->aclk);
+               clk_disable(iommu->hclk);
+       }
+}
+
 static u32 rk_iova_dte_index(dma_addr_t iova)
 {
        return (u32)(iova & RK_IOVA_DTE_MASK) >> RK_IOVA_DTE_SHIFT;
@@ -292,39 +317,48 @@ static void rk_iommu_base_command(void __iomem *base, u32 command)
 {
        writel(command, base + RK_MMU_COMMAND);
 }
-static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova,
+static void rk_iommu_zap_lines(struct rk_iommu *iommu, dma_addr_t iova_start,
                               size_t size)
 {
        int i;
-
-       dma_addr_t iova_end = iova + size;
+       dma_addr_t iova_end = iova_start + size;
        /*
         * TODO(djkurtz): Figure out when it is more efficient to shootdown the
         * entire iotlb rather than iterate over individual iovas.
         */
-       for (i = 0; i < iommu->num_mmu; i++)
-               for (; iova < iova_end; iova += SPAGE_SIZE)
+
+       rk_iommu_power_on(iommu);
+
+       for (i = 0; i < iommu->num_mmu; i++) {
+               dma_addr_t iova;
+
+               for (iova = iova_start; iova < iova_end; iova += SPAGE_SIZE)
                        rk_iommu_write(iommu->bases[i], RK_MMU_ZAP_ONE_LINE, iova);
+       }
+
+       rk_iommu_power_off(iommu);
 }
 
 static bool rk_iommu_is_stall_active(struct rk_iommu *iommu)
 {
-       u32 active = RK_MMU_STATUS_STALL_ACTIVE;
+       bool active = true;
        int i;
 
        for (i = 0; i < iommu->num_mmu; i++)
-               active &= !!rk_iommu_read(iommu->bases[i], RK_MMU_STATUS);
+               active &= !!(rk_iommu_read(iommu->bases[i], RK_MMU_STATUS) &
+                                       RK_MMU_STATUS_STALL_ACTIVE);
 
        return active;
 }
 
 static bool rk_iommu_is_paging_enabled(struct rk_iommu *iommu)
 {
-       u32 enable = RK_MMU_STATUS_PAGING_ENABLED;
+       bool enable = true;
        int i;
 
        for (i = 0; i < iommu->num_mmu; i++)
-               enable &= !!rk_iommu_read(iommu->bases[i], RK_MMU_STATUS);
+               enable &= !!(rk_iommu_read(iommu->bases[i], RK_MMU_STATUS) &
+                                       RK_MMU_STATUS_PAGING_ENABLED);
 
        return enable;
 }
@@ -410,6 +444,10 @@ static int rk_iommu_force_reset(struct rk_iommu *iommu)
        int ret, i;
        u32 dte_addr;
 
+       /* Workaround for isp mmus */
+       if (iommu->reset_disabled)
+               return 0;
+
        /*
         * Check if register DTE_ADDR is working by writing DTE_ADDR_DUMMY
         * and verifying that upper 5 nybbles are read back.
@@ -547,12 +585,11 @@ static phys_addr_t rk_iommu_iova_to_phys(struct iommu_domain *domain,
                                         dma_addr_t iova)
 {
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-       unsigned long flags;
        phys_addr_t pt_phys, phys = 0;
        u32 dte, pte;
        u32 *page_table;
 
-       spin_lock_irqsave(&rk_domain->dt_lock, flags);
+       mutex_lock(&rk_domain->dt_lock);
 
        dte = rk_domain->dt[rk_iova_dte_index(iova)];
        if (!rk_dte_is_pt_valid(dte))
@@ -566,7 +603,7 @@ static phys_addr_t rk_iommu_iova_to_phys(struct iommu_domain *domain,
 
        phys = rk_pte_page_address(pte) + rk_iova_page_offset(iova);
 out:
-       spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
+       mutex_unlock(&rk_domain->dt_lock);
 
        return phys;
 }
@@ -575,16 +612,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
                              dma_addr_t iova, size_t size)
 {
        struct list_head *pos;
-       unsigned long flags;
 
        /* shootdown these iova from all iommus using this domain */
-       spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+       mutex_lock(&rk_domain->iommus_lock);
        list_for_each(pos, &rk_domain->iommus) {
                struct rk_iommu *iommu;
                iommu = list_entry(pos, struct rk_iommu, node);
                rk_iommu_zap_lines(iommu, iova, size);
        }
-       spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
+       mutex_unlock(&rk_domain->iommus_lock);
 }
 
 static void rk_iommu_zap_iova_first_last(struct rk_iommu_domain *rk_domain,
@@ -605,7 +641,7 @@ static u32 *rk_dte_get_page_table(struct rk_iommu_domain *rk_domain,
        phys_addr_t pt_phys;
        dma_addr_t pt_dma;
 
-       assert_spin_locked(&rk_domain->dt_lock);
+       WARN_ON(!mutex_is_locked(&rk_domain->dt_lock));
 
        dte_index = rk_iova_dte_index(iova);
        dte_addr = &rk_domain->dt[dte_index];
@@ -642,7 +678,7 @@ static size_t rk_iommu_unmap_iova(struct rk_iommu_domain *rk_domain,
        unsigned int pte_count;
        unsigned int pte_total = size / SPAGE_SIZE;
 
-       assert_spin_locked(&rk_domain->dt_lock);
+       WARN_ON(!mutex_is_locked(&rk_domain->dt_lock));
 
        for (pte_count = 0; pte_count < pte_total; pte_count++) {
                u32 pte = pte_addr[pte_count];
@@ -665,7 +701,7 @@ static int rk_iommu_map_iova(struct rk_iommu_domain *rk_domain, u32 *pte_addr,
        unsigned int pte_total = size / SPAGE_SIZE;
        phys_addr_t page_phys;
 
-       assert_spin_locked(&rk_domain->dt_lock);
+       WARN_ON(!mutex_is_locked(&rk_domain->dt_lock));
 
        for (pte_count = 0; pte_count < pte_total; pte_count++) {
                u32 pte = pte_addr[pte_count];
@@ -706,13 +742,12 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
                        phys_addr_t paddr, size_t size, int prot)
 {
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-       unsigned long flags;
        dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
        u32 *page_table, *pte_addr;
        u32 dte_index, pte_index;
        int ret;
 
-       spin_lock_irqsave(&rk_domain->dt_lock, flags);
+       mutex_lock(&rk_domain->dt_lock);
 
        /*
         * pgsize_bitmap specifies iova sizes that fit in one page table
@@ -723,7 +758,7 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
         */
        page_table = rk_dte_get_page_table(rk_domain, iova);
        if (IS_ERR(page_table)) {
-               spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
+               mutex_unlock(&rk_domain->dt_lock);
                return PTR_ERR(page_table);
        }
 
@@ -734,7 +769,7 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
        ret = rk_iommu_map_iova(rk_domain, pte_addr, pte_dma, iova,
                                paddr, size, prot);
 
-       spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
+       mutex_unlock(&rk_domain->dt_lock);
 
        return ret;
 }
@@ -743,14 +778,13 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
                             size_t size)
 {
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-       unsigned long flags;
        dma_addr_t pte_dma, iova = (dma_addr_t)_iova;
        phys_addr_t pt_phys;
        u32 dte;
        u32 *pte_addr;
        size_t unmap_size;
 
-       spin_lock_irqsave(&rk_domain->dt_lock, flags);
+       mutex_lock(&rk_domain->dt_lock);
 
        /*
         * pgsize_bitmap specifies iova sizes that fit in one page table
@@ -762,7 +796,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
        dte = rk_domain->dt[rk_iova_dte_index(iova)];
        /* Just return 0 if iova is unmapped */
        if (!rk_dte_is_pt_valid(dte)) {
-               spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
+               mutex_unlock(&rk_domain->dt_lock);
                return 0;
        }
 
@@ -771,7 +805,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _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);
 
-       spin_unlock_irqrestore(&rk_domain->dt_lock, flags);
+       mutex_unlock(&rk_domain->dt_lock);
 
        /* Shootdown iotlb entries for iova range that was just unmapped */
        rk_iommu_zap_iova(rk_domain, iova, unmap_size);
@@ -805,7 +839,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 {
        struct rk_iommu *iommu;
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-       unsigned long flags;
        int ret, i;
 
        /*
@@ -816,6 +849,8 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
        if (!iommu)
                return 0;
 
+       rk_iommu_power_on(iommu);
+
        ret = rk_iommu_enable_stall(iommu);
        if (ret)
                return ret;
@@ -842,9 +877,9 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+       mutex_lock(&rk_domain->iommus_lock);
        list_add_tail(&iommu->node, &rk_domain->iommus);
-       spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
+       mutex_unlock(&rk_domain->iommus_lock);
 
        dev_dbg(dev, "Attached to iommu domain\n");
 
@@ -858,7 +893,6 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
 {
        struct rk_iommu *iommu;
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
-       unsigned long flags;
        int i;
 
        /* Allow 'virtual devices' (eg drm) to detach from domain */
@@ -866,9 +900,9 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
        if (!iommu)
                return;
 
-       spin_lock_irqsave(&rk_domain->iommus_lock, flags);
+       mutex_lock(&rk_domain->iommus_lock);
        list_del_init(&iommu->node);
-       spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
+       mutex_unlock(&rk_domain->iommus_lock);
 
        /* Ignore error while disabling, just keep going */
        rk_iommu_enable_stall(iommu);
@@ -883,6 +917,8 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
 
        iommu->domain = NULL;
 
+       rk_iommu_power_off(iommu);
+
        dev_dbg(dev, "Detached from iommu domain\n");
 }
 
@@ -892,7 +928,7 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
        struct platform_device *pdev;
        struct device *iommu_dev;
 
-       if (type != IOMMU_DOMAIN_UNMANAGED)
+       if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
                return NULL;
 
        /* Register a pdev per domain, so DMA API can base on this *dev
@@ -909,8 +945,8 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 
        rk_domain->pdev = pdev;
 
-       /* To init the iovad which is required by iommu_dma_init_domain() */
-       if (iommu_get_dma_cookie(&rk_domain->domain))
+       if (type == IOMMU_DOMAIN_DMA &&
+           iommu_get_dma_cookie(&rk_domain->domain))
                goto err_unreg_pdev;
 
        /*
@@ -932,16 +968,21 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
 
        rk_table_flush(rk_domain, rk_domain->dt_dma, NUM_DT_ENTRIES);
 
-       spin_lock_init(&rk_domain->iommus_lock);
-       spin_lock_init(&rk_domain->dt_lock);
+       mutex_init(&rk_domain->iommus_lock);
+       mutex_init(&rk_domain->dt_lock);
        INIT_LIST_HEAD(&rk_domain->iommus);
 
+       rk_domain->domain.geometry.aperture_start = 0;
+       rk_domain->domain.geometry.aperture_end   = DMA_BIT_MASK(32);
+       rk_domain->domain.geometry.force_aperture = true;
+
        return &rk_domain->domain;
 
 err_free_dt:
        free_page((unsigned long)rk_domain->dt);
 err_put_cookie:
-       iommu_put_dma_cookie(&rk_domain->domain);
+       if (type == IOMMU_DOMAIN_DMA)
+               iommu_put_dma_cookie(&rk_domain->domain);
 err_unreg_pdev:
        platform_device_unregister(pdev);
 
@@ -970,7 +1011,8 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
                         SPAGE_SIZE, DMA_TO_DEVICE);
        free_page((unsigned long)rk_domain->dt);
 
-       iommu_put_dma_cookie(&rk_domain->domain);
+       if (domain->type == IOMMU_DOMAIN_DMA)
+               iommu_put_dma_cookie(&rk_domain->domain);
 
        platform_device_unregister(rk_domain->pdev);
 }
@@ -1134,6 +1176,8 @@ static int rk_iommu_probe(struct platform_device *pdev)
                if (!res)
                        continue;
                iommu->bases[i] = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(iommu->bases[i]))
+                       continue;
                iommu->num_mmu++;
        }
        if (iommu->num_mmu == 0)
@@ -1145,11 +1189,35 @@ static int rk_iommu_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
+       iommu->reset_disabled = device_property_read_bool(dev,
+                               "rk_iommu,disable_reset_quirk");
+
+       iommu->aclk = devm_clk_get(dev, "aclk");
+       if (IS_ERR(iommu->aclk)) {
+               dev_info(dev, "can't get aclk\n");
+               iommu->aclk = NULL;
+       }
+
+       iommu->hclk = devm_clk_get(dev, "hclk");
+       if (IS_ERR(iommu->hclk)) {
+               dev_info(dev, "can't get hclk\n");
+               iommu->hclk = NULL;
+       }
+
+       if (iommu->aclk && iommu->hclk) {
+               clk_prepare(iommu->aclk);
+               clk_prepare(iommu->hclk);
+       }
+
+       pm_runtime_enable(dev);
+
        return 0;
 }
 
 static int rk_iommu_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
+
        return 0;
 }