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