linux/drivers/iommu/shmobile-ipmmu.c
<<
>>
Prefs
   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