diff options
Diffstat (limited to 'drivers/media/platform/omap3isp/isp.c')
-rw-r--r-- | drivers/media/platform/omap3isp/isp.c | 102 |
1 files changed, 76 insertions, 26 deletions
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 06a0df434249..5a4801b76282 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
@@ -69,6 +69,8 @@ | |||
69 | #include <linux/sched.h> | 69 | #include <linux/sched.h> |
70 | #include <linux/vmalloc.h> | 70 | #include <linux/vmalloc.h> |
71 | 71 | ||
72 | #include <asm/dma-iommu.h> | ||
73 | |||
72 | #include <media/v4l2-common.h> | 74 | #include <media/v4l2-common.h> |
73 | #include <media/v4l2-device.h> | 75 | #include <media/v4l2-device.h> |
74 | 76 | ||
@@ -1625,7 +1627,7 @@ struct isp_device *omap3isp_get(struct isp_device *isp) | |||
1625 | * Decrement the reference count on the ISP. If the last reference is released, | 1627 | * Decrement the reference count on the ISP. If the last reference is released, |
1626 | * power-down all submodules, disable clocks and free temporary buffers. | 1628 | * power-down all submodules, disable clocks and free temporary buffers. |
1627 | */ | 1629 | */ |
1628 | void omap3isp_put(struct isp_device *isp) | 1630 | static void __omap3isp_put(struct isp_device *isp, bool save_ctx) |
1629 | { | 1631 | { |
1630 | if (isp == NULL) | 1632 | if (isp == NULL) |
1631 | return; | 1633 | return; |
@@ -1634,7 +1636,7 @@ void omap3isp_put(struct isp_device *isp) | |||
1634 | BUG_ON(isp->ref_count == 0); | 1636 | BUG_ON(isp->ref_count == 0); |
1635 | if (--isp->ref_count == 0) { | 1637 | if (--isp->ref_count == 0) { |
1636 | isp_disable_interrupts(isp); | 1638 | isp_disable_interrupts(isp); |
1637 | if (isp->domain) { | 1639 | if (save_ctx) { |
1638 | isp_save_ctx(isp); | 1640 | isp_save_ctx(isp); |
1639 | isp->has_context = 1; | 1641 | isp->has_context = 1; |
1640 | } | 1642 | } |
@@ -1648,6 +1650,11 @@ void omap3isp_put(struct isp_device *isp) | |||
1648 | mutex_unlock(&isp->isp_mutex); | 1650 | mutex_unlock(&isp->isp_mutex); |
1649 | } | 1651 | } |
1650 | 1652 | ||
1653 | void omap3isp_put(struct isp_device *isp) | ||
1654 | { | ||
1655 | __omap3isp_put(isp, true); | ||
1656 | } | ||
1657 | |||
1651 | /* -------------------------------------------------------------------------- | 1658 | /* -------------------------------------------------------------------------- |
1652 | * Platform device driver | 1659 | * Platform device driver |
1653 | */ | 1660 | */ |
@@ -2120,6 +2127,61 @@ error_csiphy: | |||
2120 | return ret; | 2127 | return ret; |
2121 | } | 2128 | } |
2122 | 2129 | ||
2130 | static void isp_detach_iommu(struct isp_device *isp) | ||
2131 | { | ||
2132 | arm_iommu_release_mapping(isp->mapping); | ||
2133 | isp->mapping = NULL; | ||
2134 | iommu_group_remove_device(isp->dev); | ||
2135 | } | ||
2136 | |||
2137 | static int isp_attach_iommu(struct isp_device *isp) | ||
2138 | { | ||
2139 | struct dma_iommu_mapping *mapping; | ||
2140 | struct iommu_group *group; | ||
2141 | int ret; | ||
2142 | |||
2143 | /* Create a device group and add the device to it. */ | ||
2144 | group = iommu_group_alloc(); | ||
2145 | if (IS_ERR(group)) { | ||
2146 | dev_err(isp->dev, "failed to allocate IOMMU group\n"); | ||
2147 | return PTR_ERR(group); | ||
2148 | } | ||
2149 | |||
2150 | ret = iommu_group_add_device(group, isp->dev); | ||
2151 | iommu_group_put(group); | ||
2152 | |||
2153 | if (ret < 0) { | ||
2154 | dev_err(isp->dev, "failed to add device to IPMMU group\n"); | ||
2155 | return ret; | ||
2156 | } | ||
2157 | |||
2158 | /* | ||
2159 | * Create the ARM mapping, used by the ARM DMA mapping core to allocate | ||
2160 | * VAs. This will allocate a corresponding IOMMU domain. | ||
2161 | */ | ||
2162 | mapping = arm_iommu_create_mapping(&platform_bus_type, SZ_1G, SZ_2G); | ||
2163 | if (IS_ERR(mapping)) { | ||
2164 | dev_err(isp->dev, "failed to create ARM IOMMU mapping\n"); | ||
2165 | ret = PTR_ERR(mapping); | ||
2166 | goto error; | ||
2167 | } | ||
2168 | |||
2169 | isp->mapping = mapping; | ||
2170 | |||
2171 | /* Attach the ARM VA mapping to the device. */ | ||
2172 | ret = arm_iommu_attach_device(isp->dev, mapping); | ||
2173 | if (ret < 0) { | ||
2174 | dev_err(isp->dev, "failed to attach device to VA mapping\n"); | ||
2175 | goto error; | ||
2176 | } | ||
2177 | |||
2178 | return 0; | ||
2179 | |||
2180 | error: | ||
2181 | isp_detach_iommu(isp); | ||
2182 | return ret; | ||
2183 | } | ||
2184 | |||
2123 | /* | 2185 | /* |
2124 | * isp_remove - Remove ISP platform device | 2186 | * isp_remove - Remove ISP platform device |
2125 | * @pdev: Pointer to ISP platform device | 2187 | * @pdev: Pointer to ISP platform device |
@@ -2135,10 +2197,8 @@ static int isp_remove(struct platform_device *pdev) | |||
2135 | isp_xclk_cleanup(isp); | 2197 | isp_xclk_cleanup(isp); |
2136 | 2198 | ||
2137 | __omap3isp_get(isp, false); | 2199 | __omap3isp_get(isp, false); |
2138 | iommu_detach_device(isp->domain, &pdev->dev); | 2200 | isp_detach_iommu(isp); |
2139 | iommu_domain_free(isp->domain); | 2201 | __omap3isp_put(isp, false); |
2140 | isp->domain = NULL; | ||
2141 | omap3isp_put(isp); | ||
2142 | 2202 | ||
2143 | return 0; | 2203 | return 0; |
2144 | } | 2204 | } |
@@ -2265,39 +2325,32 @@ static int isp_probe(struct platform_device *pdev) | |||
2265 | } | 2325 | } |
2266 | } | 2326 | } |
2267 | 2327 | ||
2268 | isp->domain = iommu_domain_alloc(pdev->dev.bus); | 2328 | /* IOMMU */ |
2269 | if (!isp->domain) { | 2329 | ret = isp_attach_iommu(isp); |
2270 | dev_err(isp->dev, "can't alloc iommu domain\n"); | 2330 | if (ret < 0) { |
2271 | ret = -ENOMEM; | 2331 | dev_err(&pdev->dev, "unable to attach to IOMMU\n"); |
2272 | goto error_isp; | 2332 | goto error_isp; |
2273 | } | 2333 | } |
2274 | 2334 | ||
2275 | ret = iommu_attach_device(isp->domain, &pdev->dev); | ||
2276 | if (ret) { | ||
2277 | dev_err(&pdev->dev, "can't attach iommu device: %d\n", ret); | ||
2278 | ret = -EPROBE_DEFER; | ||
2279 | goto free_domain; | ||
2280 | } | ||
2281 | |||
2282 | /* Interrupt */ | 2335 | /* Interrupt */ |
2283 | isp->irq_num = platform_get_irq(pdev, 0); | 2336 | isp->irq_num = platform_get_irq(pdev, 0); |
2284 | if (isp->irq_num <= 0) { | 2337 | if (isp->irq_num <= 0) { |
2285 | dev_err(isp->dev, "No IRQ resource\n"); | 2338 | dev_err(isp->dev, "No IRQ resource\n"); |
2286 | ret = -ENODEV; | 2339 | ret = -ENODEV; |
2287 | goto detach_dev; | 2340 | goto error_iommu; |
2288 | } | 2341 | } |
2289 | 2342 | ||
2290 | if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, | 2343 | if (devm_request_irq(isp->dev, isp->irq_num, isp_isr, IRQF_SHARED, |
2291 | "OMAP3 ISP", isp)) { | 2344 | "OMAP3 ISP", isp)) { |
2292 | dev_err(isp->dev, "Unable to request IRQ\n"); | 2345 | dev_err(isp->dev, "Unable to request IRQ\n"); |
2293 | ret = -EINVAL; | 2346 | ret = -EINVAL; |
2294 | goto detach_dev; | 2347 | goto error_iommu; |
2295 | } | 2348 | } |
2296 | 2349 | ||
2297 | /* Entities */ | 2350 | /* Entities */ |
2298 | ret = isp_initialize_modules(isp); | 2351 | ret = isp_initialize_modules(isp); |
2299 | if (ret < 0) | 2352 | if (ret < 0) |
2300 | goto detach_dev; | 2353 | goto error_iommu; |
2301 | 2354 | ||
2302 | ret = isp_register_entities(isp); | 2355 | ret = isp_register_entities(isp); |
2303 | if (ret < 0) | 2356 | if (ret < 0) |
@@ -2310,14 +2363,11 @@ static int isp_probe(struct platform_device *pdev) | |||
2310 | 2363 | ||
2311 | error_modules: | 2364 | error_modules: |
2312 | isp_cleanup_modules(isp); | 2365 | isp_cleanup_modules(isp); |
2313 | detach_dev: | 2366 | error_iommu: |
2314 | iommu_detach_device(isp->domain, &pdev->dev); | 2367 | isp_detach_iommu(isp); |
2315 | free_domain: | ||
2316 | iommu_domain_free(isp->domain); | ||
2317 | isp->domain = NULL; | ||
2318 | error_isp: | 2368 | error_isp: |
2319 | isp_xclk_cleanup(isp); | 2369 | isp_xclk_cleanup(isp); |
2320 | omap3isp_put(isp); | 2370 | __omap3isp_put(isp, false); |
2321 | error: | 2371 | error: |
2322 | mutex_destroy(&isp->isp_mutex); | 2372 | mutex_destroy(&isp->isp_mutex); |
2323 | 2373 | ||