kernel_samsung_a53x/drivers/iommu/samsung-iommu.h
2024-06-15 16:02:09 -03:00

241 lines
6.3 KiB
C
Executable file

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
*/
#ifndef __SAMSUNG_IOMMU_H
#define __SAMSUNG_IOMMU_H
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
#define SYSMMU_EVENT_MAX 2048
enum sysmmu_event_type {
/* init value */
SYSMMU_EVENT_NONE,
/* event for sysmmu drvdata */
SYSMMU_EVENT_ENABLE,
SYSMMU_EVENT_DISABLE,
SYSMMU_EVENT_POWERON,
SYSMMU_EVENT_POWEROFF,
SYSMMU_EVENT_TLB_RANGE,
SYSMMU_EVENT_TLB_ALL,
SYSMMU_EVENT_IOTLB_SYNC,
/* event for iommu domain */
SYSMMU_EVENT_MAP,
SYSMMU_EVENT_UNMAP,
};
struct sysmmu_log {
unsigned long long time;
enum sysmmu_event_type type;
u32 start;
u32 end;
};
struct samsung_iommu_log {
atomic_t index;
int len;
struct sysmmu_log *log;
};
struct tlb_config {
unsigned int index;
u32 cfg;
u32 match_cfg;
u32 match_id;
};
struct tlb_props {
int id_cnt;
u32 default_cfg;
struct tlb_config *cfg;
};
struct sysmmu_drvdata {
struct list_head list;
struct iommu_device iommu;
struct device *dev;
struct iommu_group *group;
void __iomem *sfrbase;
struct clk *clk;
phys_addr_t pgtable;
spinlock_t lock; /* protect atomic update to H/W status */
u32 version;
int num_tlb;
int qos;
int attached_count;
int rpm_count;
int secure_irq;
int max_vm;
int vmid_mask;
unsigned int secure_base;
const unsigned int *reg_set;
struct tlb_props tlb_props;
struct samsung_iommu_log log;
bool no_block_mode;
bool has_vcr;
bool async_fault_mode;
};
struct sysmmu_clientdata {
struct device *dev;
struct sysmmu_drvdata **sysmmus;
struct device_link **dev_link;
int sysmmu_count;
};
enum {
REG_IDX_DEFAULT = 0,
REG_IDX_VM,
MAX_SET_IDX,
};
enum {
IDX_FLPT_BASE = 0,
IDX_ALL_INV,
IDX_VPN_INV,
IDX_RANGE_INV,
IDX_RANGE_INV_START,
IDX_RANGE_INV_END,
IDX_FAULT_VA,
IDX_FAULT_TRANS_INFO,
IDX_TLB_READ,
IDX_TLB_VPN,
IDX_TLB_PPN,
IDX_TLB_ATTR,
IDX_SBB_READ,
IDX_SBB_VPN,
IDX_SBB_LINK,
IDX_SBB_ATTR,
IDX_SEC_FLPT_BASE,
MAX_REG_IDX,
};
#define MMU_REG(data, idx) ((data)->sfrbase + (data)->reg_set[idx])
#define MMU_VM_REG(data, idx, vmid) (MMU_REG(data, idx) + (vmid) * 0x10)
#define MMU_SEC_REG(data, offset_idx) ((data)->secure_base + (data)->reg_set[offset_idx])
#define MMU_SEC_VM_REG(data, offset_idx, vmid) (MMU_SEC_REG(data, offset_idx) + (vmid) * 0x10)
typedef u32 sysmmu_iova_t;
typedef u32 sysmmu_pte_t;
#define SECT_ORDER 20
#define LPAGE_ORDER 16
#define SPAGE_ORDER 12
#define SECT_SIZE (1UL << SECT_ORDER)
#define LPAGE_SIZE (1UL << LPAGE_ORDER)
#define SPAGE_SIZE (1UL << SPAGE_ORDER)
#define SECT_MASK (~(SECT_SIZE - 1))
#define LPAGE_MASK (~(LPAGE_SIZE - 1))
#define SPAGE_MASK (~(SPAGE_SIZE - 1))
#define SECT_ENT_MASK ~((SECT_SIZE >> PG_ENT_SHIFT) - 1)
#define LPAGE_ENT_MASK ~((LPAGE_SIZE >> PG_ENT_SHIFT) - 1)
#define SPAGE_ENT_MASK ~((SPAGE_SIZE >> PG_ENT_SHIFT) - 1)
#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
#define NUM_LV1ENTRIES 4096
#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE)
#define LV1TABLE_SIZE (NUM_LV1ENTRIES * sizeof(sysmmu_pte_t))
#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t))
#define lv1ent_offset(iova) ((iova) >> SECT_ORDER)
#define lv2ent_offset(iova) (((iova) & ~SECT_MASK) >> SPAGE_ORDER)
#define FLPD_FLAG_MASK 7
#define SLPD_FLAG_MASK 3
#define SECT_FLAG 2
#define SLPD_FLAG 1
#define LPAGE_FLAG 1
#define SPAGE_FLAG 2
#define PG_ENT_SHIFT 4
#define lv1ent_unmapped(sent) ((*(sent) & 7) == 0)
#define lv1ent_page(sent) ((*(sent) & 7) == 1)
#define lv1ent_section(sent) ((*(sent) & FLPD_FLAG_MASK) == SECT_FLAG)
#define lv2table_base(sent) ((phys_addr_t)(*(sent) & ~0x3F) << PG_ENT_SHIFT)
#define lv2ent_unmapped(pent) ((*(pent) & SLPD_FLAG_MASK) == 0)
#define lv2ent_small(pent) ((*(pent) & SLPD_FLAG_MASK) == SPAGE_FLAG)
#define lv2ent_large(pent) ((*(pent) & SLPD_FLAG_MASK) == LPAGE_FLAG)
#define PGBASE_TO_PHYS(pgent) ((phys_addr_t)(pgent) << PG_ENT_SHIFT)
#define ENT_TO_PHYS(ent) (phys_addr_t)(*(ent))
#define section_phys(sent) PGBASE_TO_PHYS(ENT_TO_PHYS(sent) & SECT_ENT_MASK)
#define section_offs(iova) ((iova) & (SECT_SIZE - 1))
#define lpage_phys(pent) PGBASE_TO_PHYS(ENT_TO_PHYS(pent) & LPAGE_ENT_MASK)
#define lpage_offs(iova) ((iova) & (LPAGE_SIZE - 1))
#define spage_phys(pent) PGBASE_TO_PHYS(ENT_TO_PHYS(pent) & SPAGE_ENT_MASK)
#define spage_offs(iova) ((iova) & (SPAGE_SIZE - 1))
static inline sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova)
{
return (sysmmu_pte_t *)(phys_to_virt(lv2table_base(sent))) +
lv2ent_offset(iova);
}
static inline sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable,
sysmmu_iova_t iova)
{
return pgtable + lv1ent_offset(iova);
}
#define REG_MMU_CTRL 0x000
#define REG_MMU_CFG 0x004
#define REG_MMU_STATUS 0x008
#define REG_MMU_FLPT_BASE 0x00C
#define REG_MMU_VERSION 0x034
#define REG_MMU_CAPA0_V7 0x870
#define REG_MMU_CAPA1_V7 0x874
#define SYSMMU_VM_OFFSET 0x1000
#define REG_VMID_OFFSET(offset, vmid) ((offset) + (vmid) * SYSMMU_VM_OFFSET)
#define REG_MMU_CTRL_VM(vmid) REG_VMID_OFFSET(0x8000, vmid)
#define REG_MMU_CFG_VM(vmid) REG_VMID_OFFSET(0x8004, vmid)
#define MMU_CAPA_NUM_TLB_WAY(reg) ((reg) & 0xFF)
#define MMU_CAPA_NUM_SBB_ENTRY(reg) (((reg) >> 12) & 0xF)
#define MMU_CAPA_NUM_PAGE_TABLE(reg) (((reg) >> 16) & 0xF)
#define MMU_CAPA1_EXIST(reg) (((reg) >> 11) & 0x1)
#define MMU_CAPA1_TYPE(reg) (((reg) >> 28) & 0xF)
#define MMU_CAPA1_NO_BLOCK_MODE(reg) (((reg) >> 15) & 0x1)
#define MMU_CAPA1_VCR_ENABLED(reg) (((reg) >> 14) & 0x1)
#define MMU_CAPA1_NUM_TLB(reg) (((reg) >> 4) & 0xFF)
#define MMU_CAPA1_NUM_PORT(reg) ((reg) & 0xF)
#define MMU_MAJ_VER(val) ((val) >> 11)
#define MMU_MIN_VER(val) (((val) >> 4) & 0x7F)
#define MMU_REV_VER(val) ((val) & 0xF)
#define MMU_RAW_VER(reg) (((reg) >> 17) & 0x7FFF)
#define MMU_VERSION(x, y, z) ((z) | ((y) << 4) | ((x) << 11))
#define CTRL_VID_ENABLE 0x1
#define CTRL_MMU_ENABLE BIT(0)
#define CTRL_MMU_BLOCK BIT(1)
#define CTRL_INT_ENABLE BIT(2)
#define CTRL_FAULT_STALL_MODE BIT(3)
#define CTRL_RESP_SLAVE_ERROR 0x20
#define CFG_MASK_GLOBAL 0x00000F80 /* Bit 11, 10-7 */
#define CFG_MASK_VM 0xB00F1004 /* Bit 31, 29, 28, 19-16, 12, 2 */
#define CFG_QOS_OVRRIDE BIT(11)
#define CFG_QOS(n) (((n) & 0xF) << 7)
irqreturn_t samsung_sysmmu_irq_thread(int irq, void *dev_id);
irqreturn_t samsung_sysmmu_irq(int irq, void *dev_id);
#endif /* __SAMSUNG_IOMMU_H */