Blame view
drivers/iommu/shmobile-ipmmu.c
3.2 KB
c2c460f7c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/* * IPMMU/IPMMUI * Copyright (C) 2012 Hideki EIRAKU * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. */ #include <linux/err.h> #include <linux/export.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/platform_data/sh_ipmmu.h> #include "shmobile-ipmmu.h" #define IMCTR1 0x000 #define IMCTR2 0x004 #define IMASID 0x010 #define IMTTBR 0x014 #define IMTTBCR 0x018 #define IMCTR1_TLBEN (1 << 0) #define IMCTR1_FLUSH (1 << 1) static void ipmmu_reg_write(struct shmobile_ipmmu *ipmmu, unsigned long reg_off, unsigned long data) { iowrite32(data, ipmmu->ipmmu_base + reg_off); } void ipmmu_tlb_flush(struct shmobile_ipmmu *ipmmu) { if (!ipmmu) return; |
e87c621dc
|
37 |
spin_lock(&ipmmu->flush_lock); |
c2c460f7c
|
38 39 40 41 |
if (ipmmu->tlb_enabled) ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH | IMCTR1_TLBEN); else ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH); |
e87c621dc
|
42 |
spin_unlock(&ipmmu->flush_lock); |
c2c460f7c
|
43 44 45 46 47 48 49 |
} void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size, int asid) { if (!ipmmu) return; |
e87c621dc
|
50 |
spin_lock(&ipmmu->flush_lock); |
c2c460f7c
|
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
switch (size) { default: ipmmu->tlb_enabled = 0; break; case 0x2000: ipmmu_reg_write(ipmmu, IMTTBCR, 1); ipmmu->tlb_enabled = 1; break; case 0x1000: ipmmu_reg_write(ipmmu, IMTTBCR, 2); ipmmu->tlb_enabled = 1; break; case 0x800: ipmmu_reg_write(ipmmu, IMTTBCR, 3); ipmmu->tlb_enabled = 1; break; case 0x400: ipmmu_reg_write(ipmmu, IMTTBCR, 4); ipmmu->tlb_enabled = 1; break; case 0x200: ipmmu_reg_write(ipmmu, IMTTBCR, 5); ipmmu->tlb_enabled = 1; break; case 0x100: ipmmu_reg_write(ipmmu, IMTTBCR, 6); ipmmu->tlb_enabled = 1; break; case 0x80: ipmmu_reg_write(ipmmu, IMTTBCR, 7); ipmmu->tlb_enabled = 1; break; } ipmmu_reg_write(ipmmu, IMTTBR, phys); ipmmu_reg_write(ipmmu, IMASID, asid); |
e87c621dc
|
86 |
spin_unlock(&ipmmu->flush_lock); |
c2c460f7c
|
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
} static int ipmmu_probe(struct platform_device *pdev) { struct shmobile_ipmmu *ipmmu; struct resource *res; struct shmobile_ipmmu_platform_data *pdata = pdev->dev.platform_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "cannot get platform resources "); return -ENOENT; } ipmmu = devm_kzalloc(&pdev->dev, sizeof(*ipmmu), GFP_KERNEL); if (!ipmmu) { dev_err(&pdev->dev, "cannot allocate device data "); return -ENOMEM; } |
e87c621dc
|
107 |
spin_lock_init(&ipmmu->flush_lock); |
c2c460f7c
|
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
ipmmu->dev = &pdev->dev; ipmmu->ipmmu_base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!ipmmu->ipmmu_base) { dev_err(&pdev->dev, "ioremap_nocache failed "); return -ENOMEM; } ipmmu->dev_names = pdata->dev_names; ipmmu->num_dev_names = pdata->num_dev_names; platform_set_drvdata(pdev, ipmmu); ipmmu_reg_write(ipmmu, IMCTR1, 0x0); /* disable TLB */ ipmmu_reg_write(ipmmu, IMCTR2, 0x0); /* disable PMB */ ipmmu_iommu_init(ipmmu); return 0; } static struct platform_driver ipmmu_driver = { .probe = ipmmu_probe, .driver = { .owner = THIS_MODULE, .name = "ipmmu", }, }; static int __init ipmmu_init(void) { return platform_driver_register(&ipmmu_driver); } subsys_initcall(ipmmu_init); |