mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
bca10b906f
Handling System MMUs with an identifier is not flexible to manage System MMU platform devices because of the following reasons: 1. A device driver which needs to handle System MMU must know the ID. 2. A System MMU may not present in some implementations of Exynos family. 3. Handling System MMU with IOMMU API does not require an ID. This patch is the result of removing ID of System MMUs. Instead, a device driver that needs to handle its System MMU must use IOMMU API while its descriptor of platform device is given. This patch also includes the following enhancements: - A System MMU device becomes a child if its power domain device. - clkdev Signed-off-by: KyongHo Cho <pullip.cho@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
275 lines
9.2 KiB
C
275 lines
9.2 KiB
C
/* 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);
|