| /* linux/arch/arm/mach-exynos/dev-sysmmu.c |
| * |
| * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. |
| * http://www.samsung.com |
| * |
| * EXYNOS - System MMU support |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <linux/platform_device.h> |
| #include <linux/dma-mapping.h> |
| |
| #include <plat/cpu.h> |
| |
| #include <mach/map.h> |
| #include <mach/irqs.h> |
| #include <mach/sysmmu.h> |
| |
| static u64 exynos_sysmmu_dma_mask = DMA_BIT_MASK(32); |
| |
| #define SYSMMU_PLATFORM_DEVICE(ipname, devid) \ |
| static struct sysmmu_platform_data platdata_##ipname = { \ |
| .dbgname = #ipname, \ |
| }; \ |
| struct platform_device SYSMMU_PLATDEV(ipname) = \ |
| { \ |
| .name = SYSMMU_DEVNAME_BASE, \ |
| .id = devid, \ |
| .dev = { \ |
| .dma_mask = &exynos_sysmmu_dma_mask, \ |
| .coherent_dma_mask = DMA_BIT_MASK(32), \ |
| .platform_data = &platdata_##ipname, \ |
| }, \ |
| } |
| |
| SYSMMU_PLATFORM_DEVICE(mfc_l, 0); |
| SYSMMU_PLATFORM_DEVICE(mfc_r, 1); |
| SYSMMU_PLATFORM_DEVICE(tv, 2); |
| SYSMMU_PLATFORM_DEVICE(jpeg, 3); |
| SYSMMU_PLATFORM_DEVICE(rot, 4); |
| SYSMMU_PLATFORM_DEVICE(fimc0, 5); /* fimc* and gsc* exist exclusively */ |
| SYSMMU_PLATFORM_DEVICE(fimc1, 6); |
| SYSMMU_PLATFORM_DEVICE(fimc2, 7); |
| SYSMMU_PLATFORM_DEVICE(fimc3, 8); |
| SYSMMU_PLATFORM_DEVICE(gsc0, 5); |
| SYSMMU_PLATFORM_DEVICE(gsc1, 6); |
| SYSMMU_PLATFORM_DEVICE(gsc2, 7); |
| SYSMMU_PLATFORM_DEVICE(gsc3, 8); |
| SYSMMU_PLATFORM_DEVICE(isp, 9); |
| SYSMMU_PLATFORM_DEVICE(fimd0, 10); |
| SYSMMU_PLATFORM_DEVICE(fimd1, 11); |
| SYSMMU_PLATFORM_DEVICE(camif0, 12); |
| SYSMMU_PLATFORM_DEVICE(camif1, 13); |
| SYSMMU_PLATFORM_DEVICE(2d, 14); |
| |
| #define SYSMMU_RESOURCE_NAME(core, ipname) sysmmures_##core##_##ipname |
| |
| #define SYSMMU_RESOURCE(core, ipname) \ |
| static struct resource SYSMMU_RESOURCE_NAME(core, ipname)[] __initdata = |
| |
| #define DEFINE_SYSMMU_RESOURCE(core, mem, irq) \ |
| DEFINE_RES_MEM_NAMED(core##_PA_SYSMMU_##mem, SZ_4K, #mem), \ |
| DEFINE_RES_IRQ_NAMED(core##_IRQ_SYSMMU_##irq##_0, #mem) |
| |
| #define SYSMMU_RESOURCE_DEFINE(core, ipname, mem, irq) \ |
| SYSMMU_RESOURCE(core, ipname) { \ |
| DEFINE_SYSMMU_RESOURCE(core, mem, irq) \ |
| } |
| |
| struct sysmmu_resource_map { |
| struct platform_device *pdev; |
| struct resource *res; |
| u32 rnum; |
| struct device *pdd; |
| char *clocknames; |
| }; |
| |
| #define SYSMMU_RESOURCE_MAPPING(core, ipname, resname) { \ |
| .pdev = &SYSMMU_PLATDEV(ipname), \ |
| .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ |
| .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ |
| .clocknames = SYSMMU_CLOCK_NAME, \ |
| } |
| |
| #define SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) { \ |
| .pdev = &SYSMMU_PLATDEV(ipname), \ |
| .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ |
| .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ |
| .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \ |
| } |
| |
| #ifdef CONFIG_EXYNOS_DEV_PD |
| #define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) { \ |
| .pdev = &SYSMMU_PLATDEV(ipname), \ |
| .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ |
| .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ |
| .clocknames = SYSMMU_CLOCK_NAME, \ |
| .pdd = &exynos##core##_device_pd[pd].dev, \ |
| } |
| |
| #define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) {\ |
| .pdev = &SYSMMU_PLATDEV(ipname), \ |
| .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ |
| .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ |
| .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \ |
| .pdd = &exynos##core##_device_pd[pd].dev, \ |
| } |
| #else |
| #define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) \ |
| SYSMMU_RESOURCE_MAPPING(core, ipname, resname) |
| #define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) \ |
| SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) |
| |
| #endif /* CONFIG_EXYNOS_DEV_PD */ |
| |
| #ifdef CONFIG_ARCH_EXYNOS4 |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc0, FIMC0, FIMC0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc1, FIMC1, FIMC1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc2, FIMC2, FIMC2); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc3, FIMC3, FIMC3); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, jpeg, JPEG, JPEG); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d, G2D, 2D); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, tv, TV, TV_M0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d_acp, 2D_ACP, 2D); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, rot, ROTATOR, ROTATOR); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd0, FIMD0, LCD0_M0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd1, FIMD1, LCD1_M1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite0, FIMC_LITE0, FIMC_LITE0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite1, FIMC_LITE1, FIMC_LITE1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_r, MFC_R, MFC_M0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_l, MFC_L, MFC_M1); |
| SYSMMU_RESOURCE(EXYNOS4, isp) { |
| DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_ISP, FIMC_ISP), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_DRC, FIMC_DRC), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_FD, FIMC_FD), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS4, ISPCPU, FIMC_CX), |
| }; |
| |
| static struct sysmmu_resource_map sysmmu_resmap4[] __initdata = { |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimc0, fimc0, PD_CAM), |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimc1, fimc1, PD_CAM), |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimc2, fimc2, PD_CAM), |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimc3, fimc3, PD_CAM), |
| SYSMMU_RESOURCE_MAPPING_PD(4, tv, tv, PD_TV), |
| SYSMMU_RESOURCE_MAPPING_PD(4, mfc_r, mfc_r, PD_MFC), |
| SYSMMU_RESOURCE_MAPPING_PD(4, mfc_l, mfc_l, PD_MFC), |
| SYSMMU_RESOURCE_MAPPING_PD(4, rot, rot, PD_LCD0), |
| SYSMMU_RESOURCE_MAPPING_PD(4, jpeg, jpeg, PD_CAM), |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimd0, fimd0, PD_LCD0), |
| }; |
| |
| static struct sysmmu_resource_map sysmmu_resmap4210[] __initdata = { |
| SYSMMU_RESOURCE_MAPPING_PD(4, 2d, 2d, PD_LCD0), |
| SYSMMU_RESOURCE_MAPPING_PD(4, fimd1, fimd1, PD_LCD1), |
| }; |
| |
| static struct sysmmu_resource_map sysmmu_resmap4212[] __initdata = { |
| SYSMMU_RESOURCE_MAPPING(4, 2d, 2d_acp), |
| SYSMMU_RESOURCE_MAPPING_PD(4, camif0, flite0, PD_ISP), |
| SYSMMU_RESOURCE_MAPPING_PD(4, camif1, flite1, PD_ISP), |
| SYSMMU_RESOURCE_MAPPING_PD(4, isp, isp, PD_ISP), |
| }; |
| #endif /* CONFIG_ARCH_EXYNOS4 */ |
| |
| #ifdef CONFIG_ARCH_EXYNOS5 |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, jpeg, JPEG, JPEG); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, fimd1, FIMD1, FIMD1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, 2d, 2D, 2D); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, rot, ROTATOR, ROTATOR); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, tv, TV, TV); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite0, LITE0, LITE0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite1, LITE1, LITE1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc0, GSC0, GSC0); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc1, GSC1, GSC1); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc2, GSC2, GSC2); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc3, GSC3, GSC3); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_r, MFC_R, MFC_R); |
| SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_l, MFC_L, MFC_L); |
| SYSMMU_RESOURCE(EXYNOS5, isp) { |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISP, ISP), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, DRC, DRC), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, FD, FD), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISPCPU, MCUISP), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERC, SCALERCISP), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERP, SCALERPISP), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, ODC, ODC), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS0, DIS0), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS1, DIS1), |
| DEFINE_SYSMMU_RESOURCE(EXYNOS5, 3DNR, 3DNR), |
| }; |
| |
| static struct sysmmu_resource_map sysmmu_resmap5[] __initdata = { |
| SYSMMU_RESOURCE_MAPPING(5, jpeg, jpeg), |
| SYSMMU_RESOURCE_MAPPING(5, fimd1, fimd1), |
| SYSMMU_RESOURCE_MAPPING(5, 2d, 2d), |
| SYSMMU_RESOURCE_MAPPING(5, rot, rot), |
| SYSMMU_RESOURCE_MAPPING_PD(5, tv, tv, PD_DISP1), |
| SYSMMU_RESOURCE_MAPPING_PD(5, camif0, flite0, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, camif1, flite1, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, gsc0, gsc0, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, gsc1, gsc1, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, gsc2, gsc2, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, gsc3, gsc3, PD_GSCL), |
| SYSMMU_RESOURCE_MAPPING_PD(5, mfc_r, mfc_r, PD_MFC), |
| SYSMMU_RESOURCE_MAPPING_PD(5, mfc_l, mfc_l, PD_MFC), |
| SYSMMU_RESOURCE_MAPPING_MCPD(5, isp, isp, PD_ISP, mc_platdata), |
| }; |
| #endif /* CONFIG_ARCH_EXYNOS5 */ |
| |
| static int __init init_sysmmu_platform_device(void) |
| { |
| int i, j; |
| struct sysmmu_resource_map *resmap[2] = {NULL, NULL}; |
| int nmap[2] = {0, 0}; |
| |
| #ifdef CONFIG_ARCH_EXYNOS5 |
| if (soc_is_exynos5250()) { |
| resmap[0] = sysmmu_resmap5; |
| nmap[0] = ARRAY_SIZE(sysmmu_resmap5); |
| nmap[1] = 0; |
| } |
| #endif |
| |
| #ifdef CONFIG_ARCH_EXYNOS4 |
| if (resmap[0] == NULL) { |
| resmap[0] = sysmmu_resmap4; |
| nmap[0] = ARRAY_SIZE(sysmmu_resmap4); |
| } |
| |
| if (soc_is_exynos4210()) { |
| resmap[1] = sysmmu_resmap4210; |
| nmap[1] = ARRAY_SIZE(sysmmu_resmap4210); |
| } |
| |
| if (soc_is_exynos4412() || soc_is_exynos4212()) { |
| resmap[1] = sysmmu_resmap4212; |
| nmap[1] = ARRAY_SIZE(sysmmu_resmap4212); |
| } |
| #endif |
| |
| for (j = 0; j < 2; j++) { |
| for (i = 0; i < nmap[j]; i++) { |
| struct sysmmu_resource_map *map; |
| struct sysmmu_platform_data *platdata; |
| |
| map = &resmap[j][i]; |
| |
| map->pdev->dev.parent = map->pdd; |
| |
| platdata = map->pdev->dev.platform_data; |
| platdata->clockname = map->clocknames; |
| |
| if (platform_device_add_resources(map->pdev, map->res, |
| map->rnum)) { |
| pr_err("%s: Failed to add device resources for " |
| "%s.%d\n", __func__, |
| map->pdev->name, map->pdev->id); |
| continue; |
| } |
| |
| if (platform_device_register(map->pdev)) { |
| pr_err("%s: Failed to register %s.%d\n", |
| __func__, map->pdev->name, |
| map->pdev->id); |
| } |
| } |
| } |
| |
| return 0; |
| } |
| arch_initcall(init_sysmmu_platform_device); |