summaryrefslogtreecommitdiff
path: root/mali_kbase/backend/gpu/mali_kbase_l2_mmu_config.c
blob: 6eedc004e3ce37bedea06d7264299a41a7c5c1b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
 *
 * (C) COPYRIGHT 2019-2023 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU license.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you can access it online at
 * http://www.gnu.org/licenses/gpl-2.0.html.
 *
 */

#include <linux/version_compat_defs.h>

#include <mali_kbase.h>
#include <mali_kbase_config_defaults.h>
#include <device/mali_kbase_device.h>
#include "mali_kbase_l2_mmu_config.h"

/**
 * struct l2_mmu_config_limit_region - L2 MMU limit field
 *
 * @value:    The default value to load into the L2_MMU_CONFIG register
 * @mask:     The shifted mask of the field in the L2_MMU_CONFIG register
 * @shift:    The shift of where the field starts in the L2_MMU_CONFIG register
 *            This should be the same value as the smaller of the two mask
 *            values
 */
struct l2_mmu_config_limit_region {
	u32 value, mask, shift;
};

/**
 * struct l2_mmu_config_limit - L2 MMU read and write limit
 *
 * @product_model:    The GPU for which this entry applies
 * @read:             Values for the read limit field
 * @write:            Values for the write limit field
 */
struct l2_mmu_config_limit {
	u32 product_model;
	struct l2_mmu_config_limit_region read;
	struct l2_mmu_config_limit_region write;
};

/*
 * Zero represents no limit
 *
 * For LBEX TBEX TBAX TTRX and TNAX:
 *   The value represents the number of outstanding reads (6 bits) or writes (5 bits)
 *
 * For all other GPUS it is a fraction see: mali_kbase_config_defaults.h
 */
static const struct l2_mmu_config_limit limits[] = {
	/* GPU, read, write */
	{GPU_ID2_PRODUCT_LBEX,
		{0, GENMASK(10, 5), 5},
		{0, GENMASK(16, 12), 12} },
	{GPU_ID2_PRODUCT_TBEX,
		{0, GENMASK(10, 5), 5},
		{0, GENMASK(16, 12), 12} },
	{GPU_ID2_PRODUCT_TBAX,
		{0, GENMASK(10, 5), 5},
		{0, GENMASK(16, 12), 12} },
	{GPU_ID2_PRODUCT_TTRX,
		{0, GENMASK(12, 7), 7},
		{0, GENMASK(17, 13), 13} },
	{GPU_ID2_PRODUCT_TNAX,
		{0, GENMASK(12, 7), 7},
		{0, GENMASK(17, 13), 13} },
	{GPU_ID2_PRODUCT_TGOX,
		{KBASE_3BIT_AID_32, GENMASK(14, 12), 12},
		{KBASE_3BIT_AID_32, GENMASK(17, 15), 15} },
	{GPU_ID2_PRODUCT_TNOX,
		{KBASE_3BIT_AID_32, GENMASK(14, 12), 12},
		{KBASE_3BIT_AID_32, GENMASK(17, 15), 15} },
};

int kbase_set_mmu_quirks(struct kbase_device *kbdev)
{
	/* All older GPUs had 2 bits for both fields, this is a default */
	struct l2_mmu_config_limit limit = {
		  0, /* Any GPU not in the limits array defined above */
		 {KBASE_AID_32, GENMASK(25, 24), 24},
		 {KBASE_AID_32, GENMASK(27, 26), 26}
		};
	u32 product_model, gpu_id;
	u32 mmu_config;
	int i;

	gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
	product_model = gpu_id & GPU_ID2_PRODUCT_MODEL;

	/* Limit the GPU bus bandwidth if the platform needs this. */
	for (i = 0; i < ARRAY_SIZE(limits); i++) {
		if (product_model == limits[i].product_model) {
			limit = limits[i];
			break;
		}
	}

	mmu_config = kbase_reg_read(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG));

	if (kbase_is_gpu_removed(kbdev))
		return -EIO;

	mmu_config &= ~(limit.read.mask | limit.write.mask);
	/* Can't use FIELD_PREP() macro here as the mask isn't constant */
	mmu_config |= (limit.read.value << limit.read.shift) |
			(limit.write.value << limit.write.shift);

	kbdev->hw_quirks_mmu = mmu_config;

	if (kbdev->system_coherency == COHERENCY_ACE) {
		/* Allow memory configuration disparity to be ignored,
		 * we optimize the use of shared memory and thus we
		 * expect some disparity in the memory configuration.
		 */
		kbdev->hw_quirks_mmu |= L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY;
	}

	return 0;
}