SmartAudio/lichee/linux-4.9/drivers/iommu/sunxi-iommu.h

414 lines
12 KiB
C
Raw Permalink Normal View History

2018-07-13 01:31:50 +00:00
/*
* sunxi iommu: main structures
*
* Copyright (C) 2008-2009 Nokia Corporation
*
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
*
* 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.
*/
/*
* Register of IOMMU device
*/
#define IOMMU_VERSION_REG 0x0000
#define IOMMU_RESET_REG 0x0010
#define IOMMU_ENABLE_REG 0x0020
#define IOMMU_BYPASS_REG 0x0030
#define IOMMU_AUTO_GATING_REG 0x0040
#define IOMMU_WBUF_CTRL_REG 0x0044
#define IOMMU_OOO_CTRL_REG 0x0048
#define IOMMU_4KB_BDY_PRT_CTRL_REG 0x004C
#define IOMMU_TTB_REG 0x0050
#define IOMMU_TLB_ENABLE_REG 0x0060
#define IOMMU_TLB_PREFETCH_REG 0x0070
#define IOMMU_TLB_FLUSH_ENABLE_REG 0x0080
#define IOMMU_TLB_IVLD_ADDR_REG 0x0090
#define IOMMU_TLB_IVLD_ADDR_MASK_REG 0x0094
#define IOMMU_TLB_IVLD_ENABLE_REG 0x0098
#define IOMMU_PC_IVLD_ADDR_REG 0x00A0
#define IOMMU_PC_IVLD_ENABLE_REG 0x00A8
#define IOMMU_DM_AUT_CTRL_REG0 0x00B0
#define IOMMU_DM_AUT_CTRL_REG1 0x00B4
#define IOMMU_DM_AUT_CTRL_REG2 0x00B8
#define IOMMU_DM_AUT_CTRL_REG3 0x00BC
#define IOMMU_DM_AUT_CTRL_REG4 0x00C0
#define IOMMU_DM_AUT_CTRL_REG5 0x00C4
#define IOMMU_DM_AUT_CTRL_REG6 0x00C8
#define IOMMU_DM_AUT_CTRL_REG7 0x00CC
#define IOMMU_DM_AUT_OVWT_REG 0x00D0
#define IOMMU_INT_ENABLE_REG 0x0100
#define IOMMU_INT_CLR_REG 0x0104
#define IOMMU_INT_STA_REG 0x0108
#define IOMMU_INT_ERR_ADDR_REG0 0x0110
#define IOMMU_INT_ERR_ADDR_REG1 0x0114 /**/
#define IOMMU_INT_ERR_ADDR_REG2 0x0118 /**/
#define IOMMU_INT_ERR_ADDR_REG3 0x011C
#define IOMMU_INT_ERR_ADDR_REG4 0x0120
#define IOMMU_INT_ERR_ADDR_REG5 0x0124
#ifndef CONFIG_ARCH_SUN8IW15
#define IOMMU_INT_ERR_ADDR_REG6 0x0130
#define IOMMU_INT_ERR_ADDR_REG7 0x0134
#else
#define IOMMU_INT_ERR_ADDR_REG6 0x0128
#define IOMMU_INT_ERR_ADDR_REG7 0x0130
#define IOMMU_INT_ERR_ADDR_REG8 0x0134
#endif
#define IOMMU_INT_ERR_DATA_REG0 0x0150
#define IOMMU_INT_ERR_DATA_REG1 0x0154 /**/
#define IOMMU_INT_ERR_DATA_REG2 0x0158 /**/
#define IOMMU_INT_ERR_DATA_REG3 0x015C
#define IOMMU_INT_ERR_DATA_REG4 0x0160
#define IOMMU_INT_ERR_DATA_REG5 0x0164
#ifndef CONFIG_ARCH_SUN8IW15
#define IOMMU_INT_ERR_DATA_REG6 0x0170
#define IOMMU_INT_ERR_DATA_REG7 0x0174
#else
#define IOMMU_INT_ERR_DATA_REG6 0x0168
#define IOMMU_INT_ERR_DATA_REG7 0x0170
#define IOMMU_INT_ERR_DATA_REG8 0x0174
#endif
#define IOMMU_L1PG_INT_REG 0x0180
#define IOMMU_L2PG_INT_REG 0x0184
#define IOMMU_VA_REG 0x0190
#define IOMMU_VA_DATA_REG 0x0194
#define IOMMU_VA_CONFIG_REG 0x0198
#define IOMMU_PMU_ENABLE_REG 0x0200
#define IOMMU_PMU_CLR_REG 0x0210
#define IOMMU_PMU_ACCESS_LOW_REG0 0x0230
#define IOMMU_PMU_ACCESS_HIGH_REG0 0x0234
#define IOMMU_PMU_HIT_LOW_REG0 0x0238
#define IOMMU_PMU_HIT_HIGH_REG0 0x023C
#define IOMMU_PMU_ACCESS_LOW_REG1 0x0240 /**/
#define IOMMU_PMU_ACCESS_HIGH_REG1 0x0244 /**/
#define IOMMU_PMU_HIT_LOW_REG1 0x0248 /**/
#define IOMMU_PMU_HIT_HIGH_REG1 0x024C /**/
#define IOMMU_PMU_ACCESS_LOW_REG2 0x0250
#define IOMMU_PMU_ACCESS_HIGH_REG2 0x0254
#define IOMMU_PMU_HIT_LOW_REG2 0x0258
#define IOMMU_PMU_HIT_HIGH_REG2 0x025C
#define IOMMU_PMU_ACCESS_LOW_REG3 0x0260
#define IOMMU_PMU_ACCESS_HIGH_REG3 0x0264
#define IOMMU_PMU_HIT_LOW_REG3 0x0268
#define IOMMU_PMU_HIT_HIGH_REG3 0x026C
#define IOMMU_PMU_ACCESS_LOW_REG4 0x0270
#define IOMMU_PMU_ACCESS_HIGH_REG4 0x0274
#define IOMMU_PMU_HIT_LOW_REG4 0x0278
#define IOMMU_PMU_HIT_HIGH_REG4 0x027C
#define IOMMU_PMU_ACCESS_LOW_REG5 0x0280
#define IOMMU_PMU_ACCESS_HIGH_REG5 0x0284
#define IOMMU_PMU_HIT_LOW_REG5 0x0288
#define IOMMU_PMU_HIT_HIGH_REG5 0x028C
#ifndef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ACCESS_LOW_REG6 0x02D0
#define IOMMU_PMU_ACCESS_HIGH_REG6 0x02D4
#define IOMMU_PMU_HIT_LOW_REG6 0x02D8
#define IOMMU_PMU_HIT_HIGH_REG6 0x02DC
#define IOMMU_PMU_ACCESS_LOW_REG7 0x02E0
#define IOMMU_PMU_ACCESS_HIGH_REG7 0x02E4
#define IOMMU_PMU_HIT_LOW_REG7 0x02E8
#define IOMMU_PMU_HIT_HIGH_REG7 0x02EC
#else
#define IOMMU_PMU_ACCESS_LOW_REG6 0x0290
#define IOMMU_PMU_ACCESS_HIGH_REG6 0x0294
#define IOMMU_PMU_HIT_LOW_REG6 0x0298
#define IOMMU_PMU_HIT_HIGH_REG6 0x029C
#define IOMMU_PMU_ACCESS_LOW_REG7 0x02D0
#define IOMMU_PMU_ACCESS_HIGH_REG7 0x02D4
#define IOMMU_PMU_HIT_LOW_REG7 0x02D8
#define IOMMU_PMU_HIT_HIGH_REG7 0x02DC
#define IOMMU_PMU_ACCESS_LOW_REG8 0x02E0
#define IOMMU_PMU_ACCESS_HIGH_REG8 0x02E4
#define IOMMU_PMU_HIT_LOW_REG8 0x02E8
#define IOMMU_PMU_HIT_HIGH_REG8 0x02EC
#endif
#define IOMMU_PMU_TL_LOW_REG0 0x0300
#define IOMMU_PMU_TL_HIGH_REG0 0x0304
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG0 0x0308
#endif
#define IOMMU_PMU_TL_LOW_REG1 0x0310
#define IOMMU_PMU_TL_HIGH_REG1 0x0314
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG1 0x0318
#endif
#define IOMMU_PMU_TL_LOW_REG2 0x0320
#define IOMMU_PMU_TL_HIGH_REG2 0x0324
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG2 0x0328
#endif
#define IOMMU_PMU_TL_LOW_REG3 0x0330
#define IOMMU_PMU_TL_HIGH_REG3 0x0334
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG3 0x0338
#endif
#define IOMMU_PMU_TL_LOW_REG4 0x0340
#define IOMMU_PMU_TL_HIGH_REG4 0x0344
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG4 0x0348
#endif
#define IOMMU_PMU_TL_LOW_REG5 0x0350
#define IOMMU_PMU_TL_HIGH_REG5 0x0354
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG5 0x0358
#endif
#define IOMMU_PMU_TL_LOW_REG6 0x0360
#define IOMMU_PMU_TL_HIGH_REG6 0x0364
#ifdef CONFIG_ARCH_SUN8IW15
#define IOMMU_PMU_ML_REG6 0x0368
#endif
#define IOMMU_RESET_SHIFT 31
#define IOMMU_RESET_MASK (1 << IOMMU_RESET_SHIFT)
#define IOMMU_RESET_SET (0 << 31)
#define IOMMU_RESET_RELEASE (1 << 31)
/*
* IOMMU enable register field
*/
#define IOMMU_ENABLE 0x1
/*
* IOMMU interrupt id mask
*/
#define MICRO_TLB0_INVALID_INTER_MASK 0x1
#define MICRO_TLB1_INVALID_INTER_MASK 0x2
#define MICRO_TLB2_INVALID_INTER_MASK 0x4
#define MICRO_TLB3_INVALID_INTER_MASK 0x8
#define MICRO_TLB4_INVALID_INTER_MASK 0x10
#define MICRO_TLB5_INVALID_INTER_MASK 0x20
#define MICRO_TLB6_INVALID_INTER_MASK 0x40
#define L1_PAGETABLE_INVALID_INTER_MASK 0x10000
#define L2_PAGETABLE_INVALID_INTER_MASK 0x20000
/*
* This version Hardware just only support 4KB page. It have
* a two level page table structure, where the first level has
* 4096 entries, and the second level has 256 entries. And, the
* first level is "Page Directory(PG)", every entry include a
* Page Table base address and a few of control bits. Second
* level is "Page Table(PT)", every entry include a physical
* page address and a few of control bits. Each entry is one
* 32-bit word. Most of the bits in the second level entry are
* used by hardware.
*
* Virtual Address Format:
* 31 20|19 12|11 0
* +-----------------+------------+--------+
* | PDE Index | PTE Index | offset |
* +-----------------+------------+--------+
*
* Table Layout:
*
* First Level Second Level
* (Page Directory) (Page Table)
* ----+---------+0
* | PDE | ---> -+--------+----
* | ----------+1 | PTE |
* | | | +--------+ |
* ----------+2 | | 1K
* 16K | | +--------+ |
* ----------+3 | |
* | | | +--------+----
* | ----------
* | | |
* | |
* ----+--------+
*
* IOPDE:
* 31 10|9 0
* +------------------------+--------+
* | PTE Base Address |CTRL BIT|
* +------------------------+--------+
*
* IOPTE:
* 31 12|11 0
* +---------------------+-----------+
* | Phy Page Address | CTRL BIT |
* +---------------------+-----------+
*
*/
#define NUM_ENTRIES_PDE 4096
#define NUM_ENTRIES_PTE 256
#define PD_SIZE (NUM_ENTRIES_PDE * sizeof(u32))
#define PT_SIZE (NUM_ENTRIES_PTE * sizeof(u32))
#define IOMMU_PD_SHIFT 20
#define IOMMU_PD_MASK (~((1UL << IOMMU_PD_SHIFT) - 1))
#define IOMMU_PT_SHIFT 12
#define IOMMU_PT_MASK (~((1UL << IOMMU_PT_SHIFT) - 1))
#define PAGE_OFFSET_MASK ((1UL << IOMMU_PT_SHIFT) - 1)
#define IOPTE_BASE_MASK (~(PT_SIZE - 1))
/*
* Page Directory Entry Control Bits
*/
#define DENT_VALID 0x01
#define DENT_PTE_SHFIT 10
#define DENT_WRITABLE BIT(3)
#define DENT_READABLE BIT(2)
/*
* Page Table Entry Control Bits
*/
#define SUNXI_PTE_PAGE_WRITABLE BIT(3)
#define SUNXI_PTE_PAGE_READABLE BIT(2)
#define SUNXI_PTE_PAGE_VALID BIT(1)
#define IS_VALID(x) (((x) & 0x03) == DENT_VALID)
#define IOPDE_INDEX(va) (((va) >> IOMMU_PD_SHIFT) & (NUM_ENTRIES_PDE - 1))
#define IOPTE_INDEX(va) (((va) >> IOMMU_PT_SHIFT) & (NUM_ENTRIES_PTE - 1))
#define IOPTE_BASE(ent) ((ent) & IOPTE_BASE_MASK)
#define IOPTE_TO_PFN(ent) ((*ent) & IOMMU_PT_MASK)
#define IOVA_PAGE_OFT(va) ((va) & PAGE_OFFSET_MASK)
#define SPAGE_SIZE (1 << IOMMU_PT_SHIFT)
#define SPD_SIZE (1 << IOMMU_PD_SHIFT)
#define SPAGE_ALIGN(addr) ALIGN(addr, SPAGE_SIZE)
#define SPDE_ALIGN(addr) ALIGN(addr, SPD_SIZE)
#define MAX_SG_SIZE (128 << 20)
#define MAX_SG_TABLE_SIZE ((MAX_SG_SIZE / SPAGE_SIZE) * sizeof(u32))
/* IO virtual address start page frame number */
#define IOVA_START_PFN (1)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
#ifdef CONFIG_ARCH_SUN50IW3
#define DEFAULT_BYPASS_VALUE 0x3f
static const u32 master_id_bitmap[] = {0x3, 0x0, 0x0, 0xc, 0x10, 0x20};
#endif
#ifdef CONFIG_ARCH_SUN50IW6
#define DEFAULT_BYPASS_VALUE 0x3f
static const u32 master_id_bitmap[] = {0x1, 0x0, 0x4, 0xa, 0x10, 0x20};
#endif
/**
* DE : masterID 0
* E_EDMA: masterID 1
* E_FE: masterID 2
* VE: masterID 3
* CSI: masterID 4
* G2D: masterID 5
* E_BE: masterID 6
*/
#ifdef CONFIG_ARCH_SUN8IW15
#define DEFAULT_BYPASS_VALUE 0x7f
static const u32 master_id_bitmap[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40};
#endif
#define sunxi_wait_when(COND, MS) ({ \
unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \
int ret__ = 0; \
while ((COND)) { \
if (time_after(jiffies, timeout__)) { \
ret__ = (!COND) ? 0 : -ETIMEDOUT; \
break; \
} \
udelay(1); \
} \
ret__; \
})
/*
* The format of device tree, and client device how to use it.
*
* /{
* ....
* smmu: iommu@xxxxx {
* compatible = "allwinner,iommu";
* reg = <xxx xxx xxx xxx>;
* interrupts = <GIC_SPI xxx IRQ_TYPE_LEVEL_HIGH>;
* interrupt-names = "iommu-irq";
* clocks = <&iommu_clk>;
* clock-name = "iommu-clk";
* #iommu-cells = <1>;
* status = "enabled";
* };
*
* de@xxxxx {
* .....
* iommus = <&smmu ID>;
* };
*
* }
*
* Here, ID number is 0 ~ 5, every client device have a unique id.
* Every id represent a micro TLB, also represent a master device.
*
*/
struct sunxi_iommu {
struct device *dev;
void __iomem *base;
struct clk *clk;
int irq;
u32 bypass;
spinlock_t iommu_lock;
};
struct sunxi_iommu_domain {
unsigned int *pgtable; /* first page directory, size is 16KB */
u32 *sg_buffer;
struct mutex dt_lock; /* lock for modifying page table @ pgtable */
struct dma_iommu_mapping *mapping;
struct iommu_domain domain;
//struct iova_domain iovad;
/* list of master device, it represent a micro TLB */
struct list_head mdevs;
spinlock_t lock;
};
/*
* sunxi master device which use iommu.
*/
struct sunxi_mdev {
struct list_head node; /* for sunxi_iommu mdevs list */
struct device *dev; /* the master device */
unsigned int tlbid; /* micro TLB id, distinguish device by it */
bool flag;
};
struct sunxi_iommu_owner {
unsigned int tlbid;
bool flag;
struct sunxi_iommu *data;
struct device *dev;
struct dma_iommu_mapping *mapping;
};
int sunxi_iova_test_write(dma_addr_t iova, u32 val);
unsigned long sunxi_iova_test_read(dma_addr_t iova);
void sunxi_set_debug_mode(void);
void sunxi_set_prefetch_mode(void);
extern struct iommu_domain *global_iommu_domain;