diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-03-16 20:02:46 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2015-01-16 11:03:04 -0500 |
commit | 275f5053c7786285d2f20d2dd12908f834c47ad8 (patch) | |
tree | 9c7482c5617eec8f267a34ed709c41978716fe42 /drivers/iommu/ipmmu-vmsa.c | |
parent | 4a93f21d87e769477c0cb2b98d7e7911b8d37c03 (diff) |
iommu/ipmmu-vmsa: Add device tree support
Make platform data optional when the device is instantiated from DT and
look up the micro-TLB number in the bus master DT node.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/iommu/ipmmu-vmsa.c')
-rw-r--r-- | drivers/iommu/ipmmu-vmsa.c | 55 |
1 files changed, 47 insertions, 8 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 3a61103ef108..368c852d9ee7 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/iommu.h> | 17 | #include <linux/iommu.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/of.h> | ||
19 | #include <linux/platform_data/ipmmu-vmsa.h> | 20 | #include <linux/platform_data/ipmmu-vmsa.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <linux/sizes.h> | 22 | #include <linux/sizes.h> |
@@ -58,6 +59,8 @@ static LIST_HEAD(ipmmu_devices); | |||
58 | * Registers Definition | 59 | * Registers Definition |
59 | */ | 60 | */ |
60 | 61 | ||
62 | #define IM_NS_ALIAS_OFFSET 0x800 | ||
63 | |||
61 | #define IM_CTX_SIZE 0x40 | 64 | #define IM_CTX_SIZE 0x40 |
62 | 65 | ||
63 | #define IMCTR 0x0000 | 66 | #define IMCTR 0x0000 |
@@ -1002,16 +1005,33 @@ static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, | |||
1002 | 1005 | ||
1003 | static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) | 1006 | static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) |
1004 | { | 1007 | { |
1005 | const struct ipmmu_vmsa_master *master = mmu->pdata->masters; | 1008 | struct of_phandle_args args; |
1006 | const char *devname = dev_name(dev); | 1009 | int ret; |
1007 | unsigned int i; | 1010 | |
1011 | if (mmu->pdata) { | ||
1012 | const struct ipmmu_vmsa_master *master = mmu->pdata->masters; | ||
1013 | const char *devname = dev_name(dev); | ||
1014 | unsigned int i; | ||
1008 | 1015 | ||
1009 | for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { | 1016 | for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { |
1010 | if (strcmp(master->name, devname) == 0) | 1017 | if (strcmp(master->name, devname) == 0) |
1011 | return master->utlb; | 1018 | return master->utlb; |
1019 | } | ||
1020 | |||
1021 | return -1; | ||
1012 | } | 1022 | } |
1013 | 1023 | ||
1014 | return -1; | 1024 | ret = of_parse_phandle_with_args(dev->of_node, "iommus", |
1025 | "#iommu-cells", 0, &args); | ||
1026 | if (ret < 0) | ||
1027 | return -1; | ||
1028 | |||
1029 | of_node_put(args.np); | ||
1030 | |||
1031 | if (args.np != mmu->dev->of_node || args.args_count != 1) | ||
1032 | return -1; | ||
1033 | |||
1034 | return args.args[0]; | ||
1015 | } | 1035 | } |
1016 | 1036 | ||
1017 | static int ipmmu_add_device(struct device *dev) | 1037 | static int ipmmu_add_device(struct device *dev) |
@@ -1157,7 +1177,7 @@ static int ipmmu_probe(struct platform_device *pdev) | |||
1157 | int irq; | 1177 | int irq; |
1158 | int ret; | 1178 | int ret; |
1159 | 1179 | ||
1160 | if (!pdev->dev.platform_data) { | 1180 | if (!IS_ENABLED(CONFIG_OF) && !pdev->dev.platform_data) { |
1161 | dev_err(&pdev->dev, "missing platform data\n"); | 1181 | dev_err(&pdev->dev, "missing platform data\n"); |
1162 | return -EINVAL; | 1182 | return -EINVAL; |
1163 | } | 1183 | } |
@@ -1178,6 +1198,20 @@ static int ipmmu_probe(struct platform_device *pdev) | |||
1178 | if (IS_ERR(mmu->base)) | 1198 | if (IS_ERR(mmu->base)) |
1179 | return PTR_ERR(mmu->base); | 1199 | return PTR_ERR(mmu->base); |
1180 | 1200 | ||
1201 | /* | ||
1202 | * The IPMMU has two register banks, for secure and non-secure modes. | ||
1203 | * The bank mapped at the beginning of the IPMMU address space | ||
1204 | * corresponds to the running mode of the CPU. When running in secure | ||
1205 | * mode the non-secure register bank is also available at an offset. | ||
1206 | * | ||
1207 | * Secure mode operation isn't clearly documented and is thus currently | ||
1208 | * not implemented in the driver. Furthermore, preliminary tests of | ||
1209 | * non-secure operation with the main register bank were not successful. | ||
1210 | * Offset the registers base unconditionally to point to the non-secure | ||
1211 | * alias space for now. | ||
1212 | */ | ||
1213 | mmu->base += IM_NS_ALIAS_OFFSET; | ||
1214 | |||
1181 | irq = platform_get_irq(pdev, 0); | 1215 | irq = platform_get_irq(pdev, 0); |
1182 | if (irq < 0) { | 1216 | if (irq < 0) { |
1183 | dev_err(&pdev->dev, "no IRQ found\n"); | 1217 | dev_err(&pdev->dev, "no IRQ found\n"); |
@@ -1223,9 +1257,14 @@ static int ipmmu_remove(struct platform_device *pdev) | |||
1223 | return 0; | 1257 | return 0; |
1224 | } | 1258 | } |
1225 | 1259 | ||
1260 | static const struct of_device_id ipmmu_of_ids[] = { | ||
1261 | { .compatible = "renesas,ipmmu-vmsa", }, | ||
1262 | }; | ||
1263 | |||
1226 | static struct platform_driver ipmmu_driver = { | 1264 | static struct platform_driver ipmmu_driver = { |
1227 | .driver = { | 1265 | .driver = { |
1228 | .name = "ipmmu-vmsa", | 1266 | .name = "ipmmu-vmsa", |
1267 | .of_match_table = of_match_ptr(ipmmu_of_ids), | ||
1229 | }, | 1268 | }, |
1230 | .probe = ipmmu_probe, | 1269 | .probe = ipmmu_probe, |
1231 | .remove = ipmmu_remove, | 1270 | .remove = ipmmu_remove, |