mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-15 01:50:40 +09:00
support rockcihp iommu
This commit is contained in:
@@ -503,4 +503,65 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&mac_clk &mac_txpins &mac_rxpins &mac_mdpins>;
|
||||
};
|
||||
gpu{
|
||||
compatible = "arm,malit764",
|
||||
"arm,malit76x",
|
||||
"arm,malit7xx",
|
||||
"arm,mali-midgard";
|
||||
reg = <0xffa40000 0x1000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "JOB",
|
||||
"MMU",
|
||||
"GPU";
|
||||
};
|
||||
|
||||
iep_mmu{
|
||||
dbgname = "iep";
|
||||
compatible = "iommu,iep_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "iep_mmu";
|
||||
};
|
||||
|
||||
vip_mmu{
|
||||
dbgname = "vip";
|
||||
compatible = "iommu,vip_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "vip_mmu";
|
||||
};
|
||||
|
||||
isp0_mmu{
|
||||
dbgname = "isp0";
|
||||
compatible = "iommu,isp0_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "isp0_mmu";
|
||||
};
|
||||
|
||||
isp1_mmu{
|
||||
dbgname = "isp1";
|
||||
compatible = "iommu,isp1_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "isp1_mmu";
|
||||
};
|
||||
|
||||
vopb_mmu{
|
||||
dbgname = "vopb";
|
||||
compatible = "iommu,vopb_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "vopb_mmu";
|
||||
};
|
||||
|
||||
vopl_mmu{
|
||||
dbgname = "vopl";
|
||||
compatible = "iommu,vopl_mmu";
|
||||
reg = <0xffa40000 0x10000>;
|
||||
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "vopl_mmu";
|
||||
};
|
||||
};
|
||||
|
||||
1088
drivers/iommu/rockchip-iommu.c
Executable file
1088
drivers/iommu/rockchip-iommu.c
Executable file
File diff suppressed because it is too large
Load Diff
69
drivers/iommu/rockchip-iommu.h
Executable file
69
drivers/iommu/rockchip-iommu.h
Executable file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Data structure definition for Rockchip IOMMU driver
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include <linux/rockchip/sysmmu.h>
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_IOVMM
|
||||
|
||||
#define IOVA_START 0x10000000
|
||||
#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */
|
||||
|
||||
struct rk_vm_region {
|
||||
struct list_head node;
|
||||
dma_addr_t start;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct rk_iovmm {
|
||||
struct iommu_domain *domain; /* iommu domain for this iovmm */
|
||||
struct gen_pool *vmm_pool;
|
||||
struct list_head regions_list; /* list of rk_vm_region */
|
||||
spinlock_t lock; /* lock for updating regions_list */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct sysmmu_drvdata {
|
||||
struct list_head node; /* entry of rk_iommu_domain.clients */
|
||||
struct device *sysmmu; /* System MMU's device descriptor */
|
||||
struct device *dev; /* Owner of system MMU */
|
||||
int num_res_mem;
|
||||
int num_res_irq;
|
||||
const char *dbgname;
|
||||
void __iomem **res_bases;
|
||||
int activations;
|
||||
rwlock_t lock;
|
||||
struct iommu_domain *domain; /* domain given to iommu_attach_device() */
|
||||
sysmmu_fault_handler_t fault_handler;
|
||||
unsigned long pgtable;
|
||||
#ifdef CONFIG_ROCKCHIP_IOVMM
|
||||
struct rk_iovmm vmm;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_IOVMM
|
||||
static inline struct rk_iovmm *rockchip_get_iovmm(struct device *dev)
|
||||
{
|
||||
struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
|
||||
|
||||
BUG_ON(!dev->archdata.iommu || !data);
|
||||
|
||||
return &data->vmm;
|
||||
}
|
||||
|
||||
int rockchip_init_iovmm(struct device *sysmmu, struct rk_iovmm *vmm);
|
||||
#else
|
||||
#define rockchip_init_iovmm(sysmmu, vmm) 0
|
||||
#endif
|
||||
331
drivers/iommu/rockchip-iovmm.c
Executable file
331
drivers/iommu/rockchip-iovmm.c
Executable file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_IOMMU_DEBUG
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "rockchip-iommu.h"
|
||||
|
||||
static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
|
||||
list_for_each_entry(region, &vmm->regions_list, node)
|
||||
if (region->start == iova)
|
||||
return region;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int iovmm_activate(struct device *dev)
|
||||
{
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
|
||||
return iommu_attach_device(vmm->domain, dev);
|
||||
}
|
||||
|
||||
void iovmm_deactivate(struct device *dev)
|
||||
{
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
|
||||
iommu_detach_device(vmm->domain, dev);
|
||||
}
|
||||
|
||||
dma_addr_t iovmm_map(struct device *dev,struct scatterlist *sg, off_t offset,size_t size)
|
||||
{
|
||||
off_t start_off;
|
||||
dma_addr_t addr, start = 0;
|
||||
size_t mapped_size = 0;
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
int order;
|
||||
int ret;
|
||||
|
||||
for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
|
||||
offset -= sg_dma_len(sg);
|
||||
|
||||
start_off = offset_in_page(sg_phys(sg) + offset);
|
||||
size = PAGE_ALIGN(size + start_off);
|
||||
|
||||
order = __fls(min_t(size_t, size, SZ_1M));
|
||||
|
||||
region = kmalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto err_map_nomem;
|
||||
}
|
||||
|
||||
//start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, size, order);
|
||||
|
||||
start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool, size);
|
||||
if (!start)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto err_map_noiomem;
|
||||
}
|
||||
|
||||
addr = start;
|
||||
do {
|
||||
phys_addr_t phys;
|
||||
size_t len;
|
||||
|
||||
phys = sg_phys(sg);
|
||||
len = sg_dma_len(sg);
|
||||
|
||||
/* if back to back sg entries are contiguous consolidate them */
|
||||
while (sg_next(sg) &&sg_phys(sg) + sg_dma_len(sg) == sg_phys(sg_next(sg)))
|
||||
{
|
||||
len += sg_dma_len(sg_next(sg));
|
||||
sg = sg_next(sg);
|
||||
}
|
||||
|
||||
if (offset > 0)
|
||||
{
|
||||
len -= offset;
|
||||
phys += offset;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (offset_in_page(phys))
|
||||
{
|
||||
len += offset_in_page(phys);
|
||||
phys = round_down(phys, PAGE_SIZE);
|
||||
}
|
||||
|
||||
len = PAGE_ALIGN(len);
|
||||
|
||||
if (len > (size - mapped_size))
|
||||
len = size - mapped_size;
|
||||
|
||||
ret = iommu_map(vmm->domain, addr, phys, len, 0);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
addr += len;
|
||||
mapped_size += len;
|
||||
} while ((sg = sg_next(sg)) && (mapped_size < size));
|
||||
|
||||
BUG_ON(mapped_size > size);
|
||||
|
||||
if (mapped_size < size)
|
||||
goto err_map_map;
|
||||
|
||||
region->start = start + start_off;
|
||||
region->size = size;
|
||||
|
||||
INIT_LIST_HEAD(®ion->node);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
list_add(®ion->node, &vmm->regions_list);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
dev_dbg(dev, "IOVMM: Allocated VM region @ %#x/%#X bytes.\n",region->start, region->size);
|
||||
|
||||
return region->start;
|
||||
|
||||
err_map_map:
|
||||
iommu_unmap(vmm->domain, start, mapped_size);
|
||||
gen_pool_free(vmm->vmm_pool, start, size);
|
||||
err_map_noiomem:
|
||||
kfree(region);
|
||||
err_map_nomem:
|
||||
dev_dbg(dev, "IOVMM: Failed to allocated VM region for %#x bytes.\n",size);
|
||||
return (dma_addr_t)ret;
|
||||
}
|
||||
|
||||
void iovmm_unmap(struct device *dev, dma_addr_t iova)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
size_t unmapped_size;
|
||||
|
||||
/* This function must not be called in IRQ handlers */
|
||||
BUG_ON(in_irq());
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
region = find_region(vmm, iova);
|
||||
if (WARN_ON(!region))
|
||||
{
|
||||
spin_unlock(&vmm->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(®ion->node);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
region->start = round_down(region->start, PAGE_SIZE);
|
||||
|
||||
unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
|
||||
|
||||
rockchip_sysmmu_tlb_invalidate(dev);
|
||||
|
||||
gen_pool_free(vmm->vmm_pool, region->start, region->size);
|
||||
|
||||
WARN_ON(unmapped_size != region->size);
|
||||
dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n",unmapped_size, region->start);
|
||||
|
||||
kfree(region);
|
||||
}
|
||||
|
||||
int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON((phys + size) >= IOVA_START))
|
||||
{
|
||||
dev_err(dev,"Unable to create one to one mapping for %#x @ %#x\n",size, phys);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
region = kmalloc(sizeof(*region), GFP_KERNEL);
|
||||
if (!region)
|
||||
return -ENOMEM;
|
||||
|
||||
if (WARN_ON(phys & ~PAGE_MASK))
|
||||
phys = round_down(phys, PAGE_SIZE);
|
||||
|
||||
|
||||
ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
kfree(region);
|
||||
return ret;
|
||||
}
|
||||
|
||||
region->start = (dma_addr_t)phys;
|
||||
region->size = size;
|
||||
INIT_LIST_HEAD(®ion->node);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
list_add(®ion->node, &vmm->regions_list);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
|
||||
{
|
||||
struct rk_vm_region *region;
|
||||
struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
|
||||
size_t unmapped_size;
|
||||
|
||||
/* This function must not be called in IRQ handlers */
|
||||
BUG_ON(in_irq());
|
||||
|
||||
if (WARN_ON(phys & ~PAGE_MASK))
|
||||
phys = round_down(phys, PAGE_SIZE);
|
||||
|
||||
spin_lock(&vmm->lock);
|
||||
|
||||
region = find_region(vmm, (dma_addr_t)phys);
|
||||
if (WARN_ON(!region))
|
||||
{
|
||||
spin_unlock(&vmm->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(®ion->node);
|
||||
|
||||
spin_unlock(&vmm->lock);
|
||||
|
||||
unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
|
||||
rockchip_sysmmu_tlb_invalidate(dev);
|
||||
WARN_ON(unmapped_size != region->size);
|
||||
dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n",unmapped_size, region->start);
|
||||
|
||||
kfree(region);
|
||||
}
|
||||
|
||||
int rockchip_init_iovmm(struct device *sysmmu, struct rk_iovmm *vmm)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
|
||||
if (!vmm->vmm_pool)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto err_setup_genalloc;
|
||||
}
|
||||
|
||||
/* (1GB - 4KB) addr space from 0x10000000 */
|
||||
ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
|
||||
if (ret)
|
||||
goto err_setup_domain;
|
||||
|
||||
vmm->domain = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!vmm->domain)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto err_setup_domain;
|
||||
}
|
||||
|
||||
spin_lock_init(&vmm->lock);
|
||||
|
||||
INIT_LIST_HEAD(&vmm->regions_list);
|
||||
|
||||
pr_info("IOVMM: Created %#x B IOVMM from %#x.\n",IOVM_SIZE, IOVA_START);
|
||||
dev_dbg(sysmmu, "IOVMM: Created %#x B IOVMM from %#x.\n",IOVM_SIZE, IOVA_START);
|
||||
return 0;
|
||||
err_setup_domain:
|
||||
gen_pool_destroy(vmm->vmm_pool);
|
||||
err_setup_genalloc:
|
||||
dev_dbg(sysmmu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****
|
||||
1,success : pointer to the device inside of platform device
|
||||
2,fail : NULL
|
||||
****/
|
||||
struct device *rockchip_get_sysmmu_device_by_compatible(const char *compt)
|
||||
{
|
||||
struct device_node *dn = NULL;
|
||||
struct platform_device *pd = NULL;
|
||||
struct device *ret = NULL ;
|
||||
|
||||
#if 0
|
||||
dn = of_find_node_by_name(NULL,name);
|
||||
#endif
|
||||
|
||||
dn = of_find_compatible_node(NULL,NULL,compt);
|
||||
if(!dn)
|
||||
{
|
||||
printk("can't find device node %s \r\n",compt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pd = of_find_device_by_node(dn);
|
||||
if(!pd)
|
||||
{
|
||||
printk("can't find platform device in device node %s \r\n",compt);
|
||||
return NULL;
|
||||
}
|
||||
ret = &pd->dev;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
75
include/linux/rockchip/iovmm.h
Executable file
75
include/linux/rockchip/iovmm.h
Executable file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_PLAT_IOVMM_H
|
||||
#define __ASM_PLAT_IOVMM_H
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_IOVMM
|
||||
struct scatterlist;
|
||||
struct device;
|
||||
|
||||
int iovmm_activate(struct device *dev);
|
||||
void iovmm_deactivate(struct device *dev);
|
||||
|
||||
/* iovmm_map() - Maps a list of physical memory chunks
|
||||
* @dev: the owner of the IO address space where the mapping is created
|
||||
* @sg: list of physical memory chunks to map
|
||||
* @offset: length in bytes where the mapping starts
|
||||
* @size: how much memory to map in bytes. @offset + @size must not exceed
|
||||
* total size of @sg
|
||||
*
|
||||
* This function returns mapped IO address in the address space of @dev.
|
||||
* Returns minus error number if mapping fails.
|
||||
* Caller must check its return code with IS_ERROR_VALUE() if the function
|
||||
* succeeded.
|
||||
*
|
||||
* The caller of this function must ensure that iovmm_cleanup() is not called
|
||||
* while this function is called.
|
||||
*
|
||||
*/
|
||||
dma_addr_t iovmm_map(struct device *dev, struct scatterlist *sg, off_t offset,
|
||||
size_t size);
|
||||
|
||||
/* iovmm_unmap() - unmaps the given IO address
|
||||
* @dev: the owner of the IO address space where @iova belongs
|
||||
* @iova: IO address that needs to be unmapped and freed.
|
||||
*
|
||||
* The caller of this function must ensure that iovmm_cleanup() is not called
|
||||
* while this function is called.
|
||||
*/
|
||||
void iovmm_unmap(struct device *dev, dma_addr_t iova);
|
||||
|
||||
/* iovmm_map_oto - create one to one mapping for the given physical address
|
||||
* @dev: the owner of the IO address space to map
|
||||
* @phys: physical address to map
|
||||
* @size: size of the mapping to create
|
||||
*
|
||||
* This function return 0 if mapping is successful. Otherwise, minus error
|
||||
* value.
|
||||
*/
|
||||
int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size);
|
||||
|
||||
/* iovmm_unmap_oto - remove one to one mapping
|
||||
* @dev: the owner ofthe IO address space
|
||||
* @phys: physical address to remove mapping
|
||||
*/
|
||||
void iovmm_unmap_oto(struct device *dev, phys_addr_t phys);
|
||||
|
||||
struct device *rockchip_get_sysmmu_device_by_compatible(const char *compt);
|
||||
|
||||
|
||||
#else
|
||||
#define iovmm_activate(dev) (-ENOSYS)
|
||||
#define iovmm_deactivate(dev) do { } while (0)
|
||||
#define iovmm_map(dev, sg, offset, size) (-ENOSYS)
|
||||
#define iovmm_unmap(dev, iova) do { } while (0)
|
||||
#define iovmm_map_oto(dev, phys, size) (-ENOSYS)
|
||||
#define iovmm_unmap_oto(dev, phys) do { } while (0)
|
||||
#define rockchip_get_sysmmu_device_by_compatible(compt) do { } while (0)
|
||||
|
||||
#endif /* CONFIG_ROCKCHIP_IOVMM */
|
||||
|
||||
#endif /*__ASM_PLAT_IOVMM_H*/
|
||||
124
include/linux/rockchip/sysmmu.h
Executable file
124
include/linux/rockchip/sysmmu.h
Executable file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Rockchip - 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.
|
||||
*/
|
||||
|
||||
#ifndef _ARM_MACH_RK_SYSMMU_H_
|
||||
#define _ARM_MACH_RK_SYSMMU_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define IEP_SYSMMU_COMPATIBLE_NAME "iommu,iep_mmu"
|
||||
#define VIP_SYSMMU_COMPATIBLE_NAME "iommu,vip_mmu"
|
||||
|
||||
#define ISP0_SYSMMU_COMPATIBLE_NAME "iommu,isp0_mmu"
|
||||
#define ISP1_SYSMMU_COMPATIBLE_NAME "iommu,isp1_mmu"
|
||||
|
||||
#define VOPB_SYSMMU_COMPATIBLE_NAME "iommu,vopb_mmu"
|
||||
#define VOPL_SYSMMU_COMPATIBLE_NAME "iommu,vopl_mmu"
|
||||
|
||||
|
||||
|
||||
enum rk_sysmmu_inttype {
|
||||
SYSMMU_PAGEFAULT,
|
||||
SYSMMU_BUSERROR,
|
||||
SYSMMU_FAULT_UNKNOWN,
|
||||
SYSMMU_FAULTS_NUM
|
||||
};
|
||||
|
||||
struct sysmmu_drvdata;
|
||||
/*
|
||||
* @itype: type of fault.
|
||||
* @pgtable_base: the physical address of page table base. This is 0 if @itype
|
||||
* is SYSMMU_BUSERROR.
|
||||
* @fault_addr: the device (virtual) address that the System MMU tried to
|
||||
* translated. This is 0 if @itype is SYSMMU_BUSERROR.
|
||||
*/
|
||||
typedef int (*sysmmu_fault_handler_t)(struct device *dev,
|
||||
enum rk_sysmmu_inttype itype,
|
||||
unsigned long pgtable_base,
|
||||
unsigned long fault_addr,
|
||||
unsigned int statu
|
||||
);
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_IOMMU
|
||||
/**
|
||||
* rockchip_sysmmu_enable() - enable system mmu
|
||||
* @owner: The device whose System MMU is about to be enabled.
|
||||
* @pgd: Base physical address of the 1st level page table
|
||||
*
|
||||
* This function enable system mmu to transfer address
|
||||
* from virtual address to physical address.
|
||||
* Return non-zero if it fails to enable System MMU.
|
||||
*/
|
||||
int rockchip_sysmmu_enable(struct device *owner, unsigned long pgd);
|
||||
|
||||
/**
|
||||
* rockchip_sysmmu_disable() - disable sysmmu mmu of ip
|
||||
* @owner: The device whose System MMU is about to be disabled.
|
||||
*
|
||||
* This function disable system mmu to transfer address
|
||||
* from virtual address to physical address
|
||||
*/
|
||||
bool rockchip_sysmmu_disable(struct device *owner);
|
||||
|
||||
/**
|
||||
* rockchip_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
|
||||
* @owner: The device whose System MMU.
|
||||
*
|
||||
* This function flush all TLB entry in system mmu
|
||||
*/
|
||||
void rockchip_sysmmu_tlb_invalidate(struct device *owner);
|
||||
|
||||
/** rockchip_sysmmu_set_fault_handler() - Fault handler for System MMUs
|
||||
* Called when interrupt occurred by the System MMUs
|
||||
* The device drivers of peripheral devices that has a System MMU can implement
|
||||
* a fault handler to resolve address translation fault by System MMU.
|
||||
* The meanings of return value and parameters are described below.
|
||||
*
|
||||
* return value: non-zero if the fault is correctly resolved.
|
||||
* zero if the fault is not handled.
|
||||
*/
|
||||
void rockchip_sysmmu_set_fault_handler(struct device *dev,sysmmu_fault_handler_t handler);
|
||||
|
||||
/** rockchip_sysmmu_set_prefbuf() - Initialize prefetch buffers of System MMU v3
|
||||
* @owner: The device which need to set the prefetch buffers
|
||||
* @base0: The start virtual address of the area of the @owner device that the
|
||||
* first prefetch buffer loads translation descriptors
|
||||
* @size0: The last virtual address of the area of the @owner device that the
|
||||
* first prefetch buffer loads translation descriptors.
|
||||
* @base1: The start virtual address of the area of the @owner device that the
|
||||
* second prefetch buffer loads translation descriptors. This will be
|
||||
* ignored if @size1 is 0 and this function assigns the 2 prefetch
|
||||
* buffers with each half of the area specified by @base0 and @size0
|
||||
* @size1: The last virtual address of the area of the @owner device that the
|
||||
* prefetch buffer loads translation descriptors. This can be 0. See
|
||||
* the description of @base1 for more information with @size1 = 0
|
||||
*/
|
||||
void rockchip_sysmmu_set_prefbuf(struct device *owner,
|
||||
unsigned long base0, unsigned long size0,
|
||||
unsigned long base1, unsigned long size1);
|
||||
#else /* CONFIG_ROCKCHIP_IOMMU */
|
||||
#define rockchip_sysmmu_enable(owner, pgd) do { } while (0)
|
||||
#define rockchip_sysmmu_disable(owner) do { } while (0)
|
||||
#define rockchip_sysmmu_tlb_invalidate(owner) do { } while (0)
|
||||
#define rockchip_sysmmu_set_fault_handler(sysmmu, handler) do { } while (0)
|
||||
#define rockchip_sysmmu_set_prefbuf(owner, b0, s0, b1, s1) do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
#include <linux/device.h>
|
||||
static inline void platform_set_sysmmu(struct device *sysmmu, struct device *dev)
|
||||
{
|
||||
dev->archdata.iommu = sysmmu;
|
||||
}
|
||||
#else
|
||||
#define platform_set_sysmmu(dev, sysmmu) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _ARM_MACH_RK_SYSMMU_H_ */
|
||||
Reference in New Issue
Block a user