| /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| #ifndef __KGSL_IOMMU_H |
| #define __KGSL_IOMMU_H |
| |
| #ifdef CONFIG_QCOM_IOMMU |
| #include <linux/qcom_iommu.h> |
| #endif |
| #include <linux/of.h> |
| #include "kgsl.h" |
| |
| /* |
| * These defines control the address range for allocations that |
| * are mapped into all pagetables. |
| */ |
| #define KGSL_IOMMU_GLOBAL_MEM_SIZE (20 * SZ_1M) |
| #define KGSL_IOMMU_GLOBAL_MEM_BASE32 0xf8000000 |
| #define KGSL_IOMMU_GLOBAL_MEM_BASE64 TASK_SIZE_32 |
| |
| #define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu) \ |
| (MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \ |
| KGSL_IOMMU_GLOBAL_MEM_BASE64 : KGSL_IOMMU_GLOBAL_MEM_BASE32) |
| |
| #define KGSL_IOMMU_SECURE_SIZE SZ_256M |
| #define KGSL_IOMMU_SECURE_END(_mmu) KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) |
| #define KGSL_IOMMU_SECURE_BASE(_mmu) \ |
| (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) - KGSL_IOMMU_SECURE_SIZE) |
| |
| #define KGSL_IOMMU_SVM_BASE32 0x300000 |
| #define KGSL_IOMMU_SVM_END32 (0xC0000000 - SZ_16M) |
| |
| #define KGSL_IOMMU_VA_BASE64 0x500000000ULL |
| #define KGSL_IOMMU_VA_END64 0x600000000ULL |
| /* |
| * Note: currently we only support 36 bit addresses, |
| * but the CPU supports 39. Eventually this range |
| * should change to high part of the 39 bit address |
| * space just like the CPU. |
| */ |
| #define KGSL_IOMMU_SVM_BASE64 0x700000000ULL |
| #define KGSL_IOMMU_SVM_END64 0x800000000ULL |
| |
| /* TLBSTATUS register fields */ |
| #define KGSL_IOMMU_CTX_TLBSTATUS_SACTIVE BIT(0) |
| |
| /* IMPLDEF_MICRO_MMU_CTRL register fields */ |
| #define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_HALT 0x00000004 |
| #define KGSL_IOMMU_IMPLDEF_MICRO_MMU_CTRL_IDLE 0x00000008 |
| |
| /* SCTLR fields */ |
| #define KGSL_IOMMU_SCTLR_HUPCF_SHIFT 8 |
| #define KGSL_IOMMU_SCTLR_CFCFG_SHIFT 7 |
| #define KGSL_IOMMU_SCTLR_CFIE_SHIFT 6 |
| |
| enum kgsl_iommu_reg_map { |
| KGSL_IOMMU_CTX_SCTLR = 0, |
| KGSL_IOMMU_CTX_TTBR0, |
| KGSL_IOMMU_CTX_CONTEXTIDR, |
| KGSL_IOMMU_CTX_FSR, |
| KGSL_IOMMU_CTX_FAR, |
| KGSL_IOMMU_CTX_TLBIALL, |
| KGSL_IOMMU_CTX_RESUME, |
| KGSL_IOMMU_CTX_FSYNR0, |
| KGSL_IOMMU_CTX_FSYNR1, |
| KGSL_IOMMU_CTX_TLBSYNC, |
| KGSL_IOMMU_CTX_TLBSTATUS, |
| KGSL_IOMMU_REG_MAX |
| }; |
| |
| /* Max number of iommu clks per IOMMU unit */ |
| #define KGSL_IOMMU_MAX_CLKS 5 |
| |
| enum kgsl_iommu_context_id { |
| KGSL_IOMMU_CONTEXT_USER = 0, |
| KGSL_IOMMU_CONTEXT_SECURE = 1, |
| KGSL_IOMMU_CONTEXT_MAX, |
| }; |
| |
| /* offset at which a nop command is placed in setstate */ |
| #define KGSL_IOMMU_SETSTATE_NOP_OFFSET 1024 |
| |
| /* |
| * struct kgsl_iommu_context - Structure holding data about an iommu context |
| * bank |
| * @dev: pointer to the iommu context's device |
| * @name: context name |
| * @id: The id of the context, used for deciding how it is used. |
| * @cb_num: The hardware context bank number, used for calculating register |
| * offsets. |
| * @kgsldev: The kgsl device that uses this context. |
| * @fault: Flag when set indicates that this iommu device has caused a page |
| * fault |
| * @gpu_offset: Offset of this context bank in the GPU register space |
| * @default_pt: The default pagetable for this context, |
| * it may be changed by self programming. |
| */ |
| struct kgsl_iommu_context { |
| struct device *dev; |
| const char *name; |
| enum kgsl_iommu_context_id id; |
| unsigned int cb_num; |
| struct kgsl_device *kgsldev; |
| int fault; |
| void __iomem *regbase; |
| unsigned int gpu_offset; |
| struct kgsl_pagetable *default_pt; |
| }; |
| |
| /* |
| * struct kgsl_iommu - Structure holding iommu data for kgsl driver |
| * @ctx: Array of kgsl_iommu_context structs |
| * @regbase: Virtual address of the IOMMU register base |
| * @regstart: Physical address of the iommu registers |
| * @regsize: Length of the iommu register region. |
| * @setstate: Scratch GPU memory for IOMMU operations |
| * @clk_enable_count: The ref count of clock enable calls |
| * @clks: Array of pointers to IOMMU clocks |
| * @micro_mmu_ctrl: GPU register offset of this glob al register |
| * @smmu_info: smmu info used in a5xx preemption |
| * @protect: register protection settings for the iommu. |
| * @pagefault_suppression_count: Total number of pagefaults |
| * suppressed since boot. |
| */ |
| struct kgsl_iommu { |
| struct kgsl_iommu_context ctx[KGSL_IOMMU_CONTEXT_MAX]; |
| void __iomem *regbase; |
| unsigned long regstart; |
| unsigned int regsize; |
| struct kgsl_memdesc setstate; |
| atomic_t clk_enable_count; |
| struct clk *clks[KGSL_IOMMU_MAX_CLKS]; |
| unsigned int micro_mmu_ctrl; |
| struct kgsl_memdesc smmu_info; |
| unsigned int version; |
| struct kgsl_protected_registers protect; |
| u32 pagefault_suppression_count; |
| }; |
| |
| /* |
| * struct kgsl_iommu_pt - Iommu pagetable structure private to kgsl driver |
| * @domain: Pointer to the iommu domain that contains the iommu pagetable |
| * @ttbr0: register value to set when using this pagetable |
| * @contextidr: register value to set when using this pagetable |
| * @attached: is the pagetable attached? |
| * @rbtree: all buffers mapped into the pagetable, indexed by gpuaddr |
| * @va_start: Start of virtual range used in this pagetable. |
| * @va_end: End of virtual range. |
| * @svm_start: Start of shared virtual memory range. Addresses in this |
| * range are also valid in the process's CPU address space. |
| * @svm_end: End of the shared virtual memory range. |
| * @svm_start: 32 bit compatible range, for old clients who lack bits |
| * @svm_end: end of 32 bit compatible range |
| */ |
| struct kgsl_iommu_pt { |
| struct iommu_domain *domain; |
| u64 ttbr0; |
| u32 contextidr; |
| bool attached; |
| |
| struct rb_root rbtree; |
| |
| uint64_t va_start; |
| uint64_t va_end; |
| uint64_t svm_start; |
| uint64_t svm_end; |
| uint64_t compat_va_start; |
| uint64_t compat_va_end; |
| }; |
| |
| /* |
| * offset of context bank 0 from the start of the SMMU register space. |
| */ |
| #define KGSL_IOMMU_CB0_OFFSET 0x8000 |
| /* size of each context bank's register space */ |
| #define KGSL_IOMMU_CB_SHIFT 12 |
| |
| /* Macros to read/write IOMMU registers */ |
| extern const unsigned int kgsl_iommu_reg_list[KGSL_IOMMU_REG_MAX]; |
| |
| /* |
| * Don't use this function directly. Use the macros below to read/write |
| * IOMMU registers. |
| */ |
| static inline void __iomem * |
| kgsl_iommu_reg(struct kgsl_iommu_context *ctx, enum kgsl_iommu_reg_map reg) |
| { |
| return ctx->regbase + kgsl_iommu_reg_list[reg]; |
| } |
| |
| #define KGSL_IOMMU_SET_CTX_REG_Q(_ctx, REG, val) \ |
| writeq_relaxed((val), \ |
| kgsl_iommu_reg((_ctx), KGSL_IOMMU_CTX_##REG)) |
| |
| #define KGSL_IOMMU_GET_CTX_REG_Q(_ctx, REG) \ |
| readq_relaxed(kgsl_iommu_reg((_ctx), KGSL_IOMMU_CTX_##REG)) |
| |
| #define KGSL_IOMMU_SET_CTX_REG(_ctx, REG, val) \ |
| writel_relaxed((val), \ |
| kgsl_iommu_reg((_ctx), KGSL_IOMMU_CTX_##REG)) |
| |
| #define KGSL_IOMMU_GET_CTX_REG(_ctx, REG) \ |
| readl_relaxed(kgsl_iommu_reg((_ctx), KGSL_IOMMU_CTX_##REG)) |
| |
| |
| #endif |