tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / common / mali_dlbu.c
1 /*
2  * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 #include "mali_dlbu.h"
12 #include "mali_memory.h"
13 #include "mali_pp.h"
14 #include "mali_group.h"
15 #include "mali_osk.h"
16 #include "mali_hw_core.h"
17
18 /**
19  * Size of DLBU registers in bytes
20  */
21 #define MALI_DLBU_SIZE 0x400
22
23 u32 mali_dlbu_phys_addr = 0;
24 static mali_io_address mali_dlbu_cpu_addr = 0;
25
26 /**
27  * DLBU register numbers
28  * Used in the register read/write routines.
29  * See the hardware documentation for more information about each register
30  */
31 typedef enum mali_dlbu_register {
32         MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR = 0x0000, /**< Master tile list physical base address;
33                                                              31:12 Physical address to the page used for the DLBU
34                                                              0 DLBU enable - set this bit to 1 enables the AXI bus
35                                                              between PPs and L2s, setting to 0 disables the router and
36                                                              no further transactions are sent to DLBU */
37         MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR     = 0x0004, /**< Master tile list virtual base address;
38                                                              31:12 Virtual address to the page used for the DLBU */
39         MALI_DLBU_REGISTER_TLLIST_VBASEADDR        = 0x0008, /**< Tile list virtual base address;
40                                                              31:12 Virtual address to the tile list. This address is used when
41                                                              calculating the call address sent to PP.*/
42         MALI_DLBU_REGISTER_FB_DIM                  = 0x000C, /**< Framebuffer dimension;
43                                                              23:16 Number of tiles in Y direction-1
44                                                              7:0 Number of tiles in X direction-1 */
45         MALI_DLBU_REGISTER_TLLIST_CONF             = 0x0010, /**< Tile list configuration;
46                                                              29:28 select the size of each allocated block: 0=128 bytes, 1=256, 2=512, 3=1024
47                                                              21:16 2^n number of tiles to be binned to one tile list in Y direction
48                                                              5:0 2^n number of tiles to be binned to one tile list in X direction */
49         MALI_DLBU_REGISTER_START_TILE_POS          = 0x0014, /**< Start tile positions;
50                                                              31:24 start position in Y direction for group 1
51                                                              23:16 start position in X direction for group 1
52                                                              15:8 start position in Y direction for group 0
53                                                              7:0 start position in X direction for group 0 */
54         MALI_DLBU_REGISTER_PP_ENABLE_MASK          = 0x0018, /**< PP enable mask;
55                                                              7 enable PP7 for load balancing
56                                                              6 enable PP6 for load balancing
57                                                              5 enable PP5 for load balancing
58                                                              4 enable PP4 for load balancing
59                                                              3 enable PP3 for load balancing
60                                                              2 enable PP2 for load balancing
61                                                              1 enable PP1 for load balancing
62                                                              0 enable PP0 for load balancing */
63 } mali_dlbu_register;
64
65 typedef enum
66 {
67         PP0ENABLE = 0,
68         PP1ENABLE,
69         PP2ENABLE,
70         PP3ENABLE,
71         PP4ENABLE,
72         PP5ENABLE,
73         PP6ENABLE,
74         PP7ENABLE
75 } mali_dlbu_pp_enable;
76
77 struct mali_dlbu_core
78 {
79         struct mali_hw_core     hw_core;           /**< Common for all HW cores */
80         u32                     pp_cores_mask;     /**< This is a mask for the PP cores whose operation will be controlled by LBU
81                                                       see MALI_DLBU_REGISTER_PP_ENABLE_MASK register */
82 };
83
84 _mali_osk_errcode_t mali_dlbu_initialize(void)
85 {
86
87         MALI_DEBUG_PRINT(2, ("Mali DLBU: Initializing\n"));
88
89         if (_MALI_OSK_ERR_OK == mali_mmu_get_table_page(&mali_dlbu_phys_addr, &mali_dlbu_cpu_addr))
90         {
91                 MALI_SUCCESS;
92         }
93
94         return _MALI_OSK_ERR_FAULT;
95 }
96
97 void mali_dlbu_terminate(void)
98 {
99         MALI_DEBUG_PRINT(3, ("Mali DLBU: terminating\n"));
100
101         mali_mmu_release_table_page(mali_dlbu_phys_addr);
102 }
103
104 struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource)
105 {
106         struct mali_dlbu_core *core = NULL;
107
108         MALI_DEBUG_PRINT(2, ("Mali DLBU: Creating Mali dynamic load balancing unit: %s\n", resource->description));
109
110         core = _mali_osk_malloc(sizeof(struct mali_dlbu_core));
111         if (NULL != core)
112         {
113                 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI_DLBU_SIZE))
114                 {
115                         core->pp_cores_mask = 0;
116                         if (_MALI_OSK_ERR_OK == mali_dlbu_reset(core))
117                         {
118                                 return core;
119                         }
120                         MALI_PRINT_ERROR(("Failed to reset DLBU %s\n", core->hw_core.description));
121                         mali_hw_core_delete(&core->hw_core);
122                 }
123
124                 _mali_osk_free(core);
125         }
126         else
127         {
128                 MALI_PRINT_ERROR(("Mali DLBU: Failed to allocate memory for DLBU core\n"));
129         }
130
131         return NULL;
132 }
133
134 void mali_dlbu_delete(struct mali_dlbu_core *dlbu)
135 {
136         MALI_DEBUG_ASSERT_POINTER(dlbu);
137
138         mali_dlbu_reset(dlbu);
139         mali_hw_core_delete(&dlbu->hw_core);
140         _mali_osk_free(dlbu);
141 }
142
143 _mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu)
144 {
145         u32 dlbu_registers[7];
146         _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
147         MALI_DEBUG_ASSERT_POINTER(dlbu);
148
149         MALI_DEBUG_PRINT(4, ("Mali DLBU: mali_dlbu_reset: %s\n", dlbu->hw_core.description));
150
151         dlbu_registers[0] = mali_dlbu_phys_addr | 1; /* bit 0 enables the whole core */
152         dlbu_registers[1] = MALI_DLBU_VIRT_ADDR;
153         dlbu_registers[2] = 0;
154         dlbu_registers[3] = 0;
155         dlbu_registers[4] = 0;
156         dlbu_registers[5] = 0;
157         dlbu_registers[6] = dlbu->pp_cores_mask;
158
159         /* write reset values to core registers */
160         mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, dlbu_registers, 7);
161
162         err = _MALI_OSK_ERR_OK;
163
164         return err;
165 }
166
167 void mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group)
168 {
169         struct mali_pp_core *pp_core;
170         u32 core_id;
171
172         MALI_DEBUG_ASSERT_POINTER( dlbu );
173         MALI_DEBUG_ASSERT_POINTER( group );
174
175         pp_core = mali_group_get_pp_core(group);
176         core_id = mali_pp_core_get_id(pp_core);
177
178         dlbu->pp_cores_mask |= (0x1 << core_id);
179         MALI_DEBUG_PRINT(3, ("Mali DLBU: Adding core[%d] New mask= 0x%02x\n",core_id , dlbu->pp_cores_mask));
180
181         mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask);
182 }
183
184 /* Remove a group from the DLBU */
185 void mali_dlbu_remove_group(struct mali_dlbu_core *dlbu, struct mali_group *group)
186 {
187         struct mali_pp_core *pp_core;
188         u32 core_id;
189
190         MALI_DEBUG_ASSERT_POINTER( dlbu );
191         MALI_DEBUG_ASSERT_POINTER( group );
192
193         pp_core = mali_group_get_pp_core(group);
194         core_id = mali_pp_core_get_id(pp_core);
195
196         dlbu->pp_cores_mask &= ~(0x1 << core_id);
197                 MALI_DEBUG_PRINT(3, ("Mali DLBU: Removing core[%d] New mask= 0x%02x\n", core_id, dlbu->pp_cores_mask));
198
199         mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask);
200 }
201
202 /* Configure the DLBU for \a job. This needs to be done before the job is started on the groups in the DLBU. */
203 void mali_dlbu_config_job(struct mali_dlbu_core *dlbu, struct mali_pp_job *job)
204 {
205         u32 *registers;
206         MALI_DEBUG_ASSERT(job);
207         registers = mali_pp_job_get_dlbu_registers(job);
208         MALI_DEBUG_PRINT(4, ("Mali DLBU: Starting job\n"));
209
210         /* Writing 4 registers:
211          * DLBU registers except the first two (written once at DLBU initialisation / reset) and the PP_ENABLE_MASK register */
212         mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, registers, 4);
213
214 }