aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/mali400/r3p2/mali/common/mali_dlbu.c
blob: 01816637938cbad5310bbaffc6aa65a46483d295 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * Copyright (C) 2012 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 licence.
 * 
 * A copy of the licence is included with the program, and can also be obtained from Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "mali_dlbu.h"
#include "mali_memory.h"
#include "mali_pp.h"
#include "mali_group.h"
#include "mali_osk.h"
#include "mali_hw_core.h"

/**
 * Size of DLBU registers in bytes
 */
#define MALI_DLBU_SIZE 0x400

u32 mali_dlbu_phys_addr = 0;
static mali_io_address mali_dlbu_cpu_addr = 0;

/**
 * DLBU register numbers
 * Used in the register read/write routines.
 * See the hardware documentation for more information about each register
 */
typedef enum mali_dlbu_register {
	MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR = 0x0000, /**< Master tile list physical base address;
	                                                     31:12 Physical address to the page used for the DLBU
	                                                     0 DLBU enable - set this bit to 1 enables the AXI bus
	                                                     between PPs and L2s, setting to 0 disables the router and
	                                                     no further transactions are sent to DLBU */
	MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR     = 0x0004, /**< Master tile list virtual base address;
	                                                     31:12 Virtual address to the page used for the DLBU */
	MALI_DLBU_REGISTER_TLLIST_VBASEADDR        = 0x0008, /**< Tile list virtual base address;
	                                                     31:12 Virtual address to the tile list. This address is used when
	                                                     calculating the call address sent to PP.*/
	MALI_DLBU_REGISTER_FB_DIM                  = 0x000C, /**< Framebuffer dimension;
	                                                     23:16 Number of tiles in Y direction-1
	                                                     7:0 Number of tiles in X direction-1 */
	MALI_DLBU_REGISTER_TLLIST_CONF             = 0x0010, /**< Tile list configuration;
	                                                     29:28 select the size of each allocated block: 0=128 bytes, 1=256, 2=512, 3=1024
	                                                     21:16 2^n number of tiles to be binned to one tile list in Y direction
	                                                     5:0 2^n number of tiles to be binned to one tile list in X direction */
	MALI_DLBU_REGISTER_START_TILE_POS          = 0x0014, /**< Start tile positions;
	                                                     31:24 start position in Y direction for group 1
	                                                     23:16 start position in X direction for group 1
	                                                     15:8 start position in Y direction for group 0
	                                                     7:0 start position in X direction for group 0 */
	MALI_DLBU_REGISTER_PP_ENABLE_MASK          = 0x0018, /**< PP enable mask;
	                                                     7 enable PP7 for load balancing
	                                                     6 enable PP6 for load balancing
	                                                     5 enable PP5 for load balancing
	                                                     4 enable PP4 for load balancing
	                                                     3 enable PP3 for load balancing
	                                                     2 enable PP2 for load balancing
	                                                     1 enable PP1 for load balancing
	                                                     0 enable PP0 for load balancing */
} mali_dlbu_register;

typedef enum
{
	PP0ENABLE = 0,
	PP1ENABLE,
	PP2ENABLE,
	PP3ENABLE,
	PP4ENABLE,
	PP5ENABLE,
	PP6ENABLE,
	PP7ENABLE
} mali_dlbu_pp_enable;

struct mali_dlbu_core
{
	struct mali_hw_core     hw_core;           /**< Common for all HW cores */
	u32                     pp_cores_mask;     /**< This is a mask for the PP cores whose operation will be controlled by LBU
	                                              see MALI_DLBU_REGISTER_PP_ENABLE_MASK register */
};

_mali_osk_errcode_t mali_dlbu_initialize(void)
{

	MALI_DEBUG_PRINT(2, ("Mali DLBU: Initializing\n"));

	if (_MALI_OSK_ERR_OK == mali_mmu_get_table_page(&mali_dlbu_phys_addr, &mali_dlbu_cpu_addr))
	{
		MALI_SUCCESS;
	}

	return _MALI_OSK_ERR_FAULT;
}

void mali_dlbu_terminate(void)
{
	MALI_DEBUG_PRINT(3, ("Mali DLBU: terminating\n"));

	mali_mmu_release_table_page(mali_dlbu_phys_addr);
}

struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource)
{
	struct mali_dlbu_core *core = NULL;

	MALI_DEBUG_PRINT(2, ("Mali DLBU: Creating Mali dynamic load balancing unit: %s\n", resource->description));

	core = _mali_osk_malloc(sizeof(struct mali_dlbu_core));
	if (NULL != core)
	{
		if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI_DLBU_SIZE))
		{
			core->pp_cores_mask = 0;
			if (_MALI_OSK_ERR_OK == mali_dlbu_reset(core))
			{
				return core;
			}
			MALI_PRINT_ERROR(("Failed to reset DLBU %s\n", core->hw_core.description));
			mali_hw_core_delete(&core->hw_core);
		}

		_mali_osk_free(core);
	}
	else
	{
		MALI_PRINT_ERROR(("Mali DLBU: Failed to allocate memory for DLBU core\n"));
	}

	return NULL;
}

void mali_dlbu_delete(struct mali_dlbu_core *dlbu)
{
	MALI_DEBUG_ASSERT_POINTER(dlbu);

	mali_dlbu_reset(dlbu);
	mali_hw_core_delete(&dlbu->hw_core);
	_mali_osk_free(dlbu);
}

_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu)
{
	u32 dlbu_registers[7];
	_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
	MALI_DEBUG_ASSERT_POINTER(dlbu);

	MALI_DEBUG_PRINT(4, ("Mali DLBU: mali_dlbu_reset: %s\n", dlbu->hw_core.description));

	dlbu_registers[0] = mali_dlbu_phys_addr | 1; /* bit 0 enables the whole core */
	dlbu_registers[1] = MALI_DLBU_VIRT_ADDR;
	dlbu_registers[2] = 0;
	dlbu_registers[3] = 0;
	dlbu_registers[4] = 0;
	dlbu_registers[5] = 0;
	dlbu_registers[6] = dlbu->pp_cores_mask;

	/* write reset values to core registers */
	mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, dlbu_registers, 7);

	err = _MALI_OSK_ERR_OK;

	return err;
}

void mali_dlbu_update_mask(struct mali_dlbu_core *dlbu)
{
	MALI_DEBUG_ASSERT_POINTER(dlbu);

	mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask);
}

void mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group)
{
	struct mali_pp_core *pp_core;
	u32 bcast_id;

	MALI_DEBUG_ASSERT_POINTER( dlbu );
	MALI_DEBUG_ASSERT_POINTER( group );

	pp_core = mali_group_get_pp_core(group);
	bcast_id = mali_pp_core_get_bcast_id(pp_core);

	dlbu->pp_cores_mask |= bcast_id;
	MALI_DEBUG_PRINT(3, ("Mali DLBU: Adding core[%d] New mask= 0x%02x\n", bcast_id , dlbu->pp_cores_mask));
}

/* Remove a group from the DLBU */
void mali_dlbu_remove_group(struct mali_dlbu_core *dlbu, struct mali_group *group)
{
	struct mali_pp_core *pp_core;
	u32 bcast_id;

	MALI_DEBUG_ASSERT_POINTER( dlbu );
	MALI_DEBUG_ASSERT_POINTER( group );

	pp_core = mali_group_get_pp_core(group);
	bcast_id = mali_pp_core_get_bcast_id(pp_core);

	dlbu->pp_cores_mask &= ~bcast_id;
		MALI_DEBUG_PRINT(3, ("Mali DLBU: Removing core[%d] New mask= 0x%02x\n", bcast_id, dlbu->pp_cores_mask));
}

/* Configure the DLBU for \a job. This needs to be done before the job is started on the groups in the DLBU. */
void mali_dlbu_config_job(struct mali_dlbu_core *dlbu, struct mali_pp_job *job)
{
	u32 *registers;
	MALI_DEBUG_ASSERT(job);
	registers = mali_pp_job_get_dlbu_registers(job);
	MALI_DEBUG_PRINT(4, ("Mali DLBU: Starting job\n"));

	/* Writing 4 registers:
	 * DLBU registers except the first two (written once at DLBU initialisation / reset) and the PP_ENABLE_MASK register */
	mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, registers, 4);

}