1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
4 #include <linux/dma-mapping.h>
8 #include "adreno/adreno_gpu.h"
9 #include "adreno/a2xx.xml.h"
17 #define to_msm_gpummu(x) container_of(x, struct msm_gpummu, base)
19 #define GPUMMU_VA_START SZ_16M
20 #define GPUMMU_VA_RANGE (0xfff * SZ_64K)
21 #define GPUMMU_PAGE_SIZE SZ_4K
22 #define TABLE_SIZE (sizeof(uint32_t) * GPUMMU_VA_RANGE / GPUMMU_PAGE_SIZE)
24 static void msm_gpummu_detach(struct msm_mmu
*mmu
)
28 static int msm_gpummu_map(struct msm_mmu
*mmu
, uint64_t iova
,
29 struct sg_table
*sgt
, size_t len
, int prot
)
31 struct msm_gpummu
*gpummu
= to_msm_gpummu(mmu
);
32 unsigned idx
= (iova
- GPUMMU_VA_START
) / GPUMMU_PAGE_SIZE
;
33 struct sg_dma_page_iter dma_iter
;
34 unsigned prot_bits
= 0;
36 if (prot
& IOMMU_WRITE
)
38 if (prot
& IOMMU_READ
)
41 for_each_sgtable_dma_page(sgt
, &dma_iter
, 0) {
42 dma_addr_t addr
= sg_page_iter_dma_address(&dma_iter
);
45 for (i
= 0; i
< PAGE_SIZE
; i
+= GPUMMU_PAGE_SIZE
)
46 gpummu
->table
[idx
++] = (addr
+ i
) | prot_bits
;
49 /* we can improve by deferring flush for multiple map() */
50 gpu_write(gpummu
->gpu
, REG_A2XX_MH_MMU_INVALIDATE
,
51 A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL
|
52 A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC
);
56 static int msm_gpummu_unmap(struct msm_mmu
*mmu
, uint64_t iova
, size_t len
)
58 struct msm_gpummu
*gpummu
= to_msm_gpummu(mmu
);
59 unsigned idx
= (iova
- GPUMMU_VA_START
) / GPUMMU_PAGE_SIZE
;
62 for (i
= 0; i
< len
/ GPUMMU_PAGE_SIZE
; i
++, idx
++)
63 gpummu
->table
[idx
] = 0;
65 gpu_write(gpummu
->gpu
, REG_A2XX_MH_MMU_INVALIDATE
,
66 A2XX_MH_MMU_INVALIDATE_INVALIDATE_ALL
|
67 A2XX_MH_MMU_INVALIDATE_INVALIDATE_TC
);
71 static void msm_gpummu_destroy(struct msm_mmu
*mmu
)
73 struct msm_gpummu
*gpummu
= to_msm_gpummu(mmu
);
75 dma_free_attrs(mmu
->dev
, TABLE_SIZE
, gpummu
->table
, gpummu
->pt_base
,
76 DMA_ATTR_FORCE_CONTIGUOUS
);
81 static const struct msm_mmu_funcs funcs
= {
82 .detach
= msm_gpummu_detach
,
83 .map
= msm_gpummu_map
,
84 .unmap
= msm_gpummu_unmap
,
85 .destroy
= msm_gpummu_destroy
,
88 struct msm_mmu
*msm_gpummu_new(struct device
*dev
, struct msm_gpu
*gpu
)
90 struct msm_gpummu
*gpummu
;
92 gpummu
= kzalloc(sizeof(*gpummu
), GFP_KERNEL
);
94 return ERR_PTR(-ENOMEM
);
96 gpummu
->table
= dma_alloc_attrs(dev
, TABLE_SIZE
+ 32, &gpummu
->pt_base
,
97 GFP_KERNEL
| __GFP_ZERO
, DMA_ATTR_FORCE_CONTIGUOUS
);
100 return ERR_PTR(-ENOMEM
);
104 msm_mmu_init(&gpummu
->base
, dev
, &funcs
, MSM_MMU_GPUMMU
);
106 return &gpummu
->base
;
109 void msm_gpummu_params(struct msm_mmu
*mmu
, dma_addr_t
*pt_base
,
110 dma_addr_t
*tran_error
)
112 dma_addr_t base
= to_msm_gpummu(mmu
)->pt_base
;
115 *tran_error
= base
+ TABLE_SIZE
; /* 32-byte aligned */