Merge tag 'v4.4-rc2'
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_osk_mali.c
1 /*
2  * Copyright (C) 2010-2014 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
12 /**
13  * @file mali_osk_mali.c
14  * Implementation of the OS abstraction layer which is specific for the Mali kernel device driver
15  */
16 #include "../platform/rk30/custom_log.h"
17
18 #include <linux/kernel.h>
19 #include <asm/uaccess.h>
20 #include <linux/platform_device.h>
21 #include <linux/mali/mali_utgard.h>
22 #include <linux/of.h>
23 #include <linux/of_device.h>
24
25 #include "mali_osk_mali.h"
26 #include "mali_kernel_common.h" /* MALI_xxx macros */
27 #include "mali_osk.h"           /* kernel side OS functions */
28 #include "mali_kernel_linux.h"
29
30
31
32 #ifdef CONFIG_MALI_DT
33
34 #define MALI_OSK_INVALID_RESOURCE_ADDRESS 0xFFFFFFFF
35
36 /**
37  * Define the max number of resource we could have.
38  */
39 #define MALI_OSK_MAX_RESOURCE_NUMBER 27
40
41 /**
42  * Define the max number of resource with interrupts, and they are
43  * the first 20 elements in array mali_osk_resource_bank.
44  */
45 #define MALI_OSK_RESOURCE_WITH_IRQ_NUMBER 20
46
47 /**
48  * pp core start and end location in mali_osk_resource_bank array.
49  */
50 #define MALI_OSK_RESOURCE_PP_LOCATION_START 2
51 #define MALI_OSK_RESOURCE_PP_LOCATION_END 17
52
53 /**
54  * L2 cache start and end location in mali_osk_resource_bank array.
55  */
56 #define MALI_OSK_RESOURCE_L2_LOCATION_START 20
57 #define MALI_OSK_RESOURCE_l2_LOCATION_END 22
58
59 static _mali_osk_resource_t mali_osk_resource_bank[MALI_OSK_MAX_RESOURCE_NUMBER] = {
60 /*-------------------------------------------------------*/
61 /* rk_ext : to use dts_for_mali_ko_befor_r5p0-01rel0. */
62 // {.description = "Mali_GP", .base = MALI_OFFSET_GP, .irq_name = "IRQGP",},
63 {.description = "Mali_GP", .base = MALI_OFFSET_GP, .irq_name = "Mali_GP_IRQ",},
64 // {.description = "Mali_GP_MMU", .base = MALI_OFFSET_GP_MMU, .irq_name = "IRQGPMMU",},
65 {.description = "Mali_GP_MMU", .base = MALI_OFFSET_GP_MMU, .irq_name = "Mali_GP_MMU_IRQ",},
66 // {.description = "Mali_PP0", .base = MALI_OFFSET_PP0, .irq_name = "IRQPP0",},
67 {.description = "Mali_PP0", .base = MALI_OFFSET_PP0, .irq_name = "Mali_PP0_IRQ",},
68 // {.description = "Mali_PP0_MMU", .base = MALI_OFFSET_PP0_MMU, .irq_name = "IRQPPMMU0",},
69 {.description = "Mali_PP0_MMU", .base = MALI_OFFSET_PP0_MMU, .irq_name = "Mali_PP0_MMU_IRQ",},
70 // {.description = "Mali_PP1", .base = MALI_OFFSET_PP1, .irq_name = "IRQPP1",},
71 {.description = "Mali_PP1", .base = MALI_OFFSET_PP1, .irq_name = "Mali_PP1_IRQ",},
72 // {.description = "Mali_PP1_MMU", .base = MALI_OFFSET_PP1_MMU, .irq_name = "IRQPPMMU1",},
73 {.description = "Mali_PP1_MMU", .base = MALI_OFFSET_PP1_MMU, .irq_name = "Mali_PP1_MMU_IRQ",},
74 /*-------------------------------------------------------*/
75 {.description = "Mali_PP2", .base = MALI_OFFSET_PP2, .irq_name = "IRQPP2",},
76 {.description = "Mali_PP2_MMU", .base = MALI_OFFSET_PP2_MMU, .irq_name = "IRQPPMMU2",},
77 {.description = "Mali_PP3", .base = MALI_OFFSET_PP3, .irq_name = "IRQPP3",},
78 {.description = "Mali_PP3_MMU", .base = MALI_OFFSET_PP3_MMU, .irq_name = "IRQPPMMU3",},
79 {.description = "Mali_PP4", .base = MALI_OFFSET_PP4, .irq_name = "IRQPP4",},
80 {.description = "Mali_PP4_MMU", .base = MALI_OFFSET_PP4_MMU, .irq_name = "IRQPPMMU4",},
81 {.description = "Mali_PP5", .base = MALI_OFFSET_PP5, .irq_name = "IRQPP5",},
82 {.description = "Mali_PP5_MMU", .base = MALI_OFFSET_PP5_MMU, .irq_name = "IRQPPMMU5",},
83 {.description = "Mali_PP6", .base = MALI_OFFSET_PP6, .irq_name = "IRQPP6",},
84 {.description = "Mali_PP6_MMU", .base = MALI_OFFSET_PP6_MMU, .irq_name = "IRQPPMMU6",},
85 {.description = "Mali_PP7", .base = MALI_OFFSET_PP7, .irq_name = "IRQPP7",},
86 {.description = "Mali_PP7_MMU", .base = MALI_OFFSET_PP7_MMU, .irq_name = "IRQPPMMU",},
87 {.description = "Mali_PP_Broadcast", .base = MALI_OFFSET_PP_BCAST, .irq_name = "IRQPP",},
88 {.description = "Mali_PMU", .base = MALI_OFFSET_PMU, .irq_name = "IRQPMU",},
89 {.description = "Mali_L2", .base = MALI_OFFSET_L2_RESOURCE0,},
90 {.description = "Mali_L2", .base = MALI_OFFSET_L2_RESOURCE1,},
91 {.description = "Mali_L2", .base = MALI_OFFSET_L2_RESOURCE2,},
92 {.description = "Mali_PP_MMU_Broadcast", .base = MALI_OFFSET_PP_BCAST_MMU,},
93 {.description = "Mali_Broadcast", .base = MALI_OFFSET_BCAST,},
94 {.description = "Mali_DLBU", .base = MALI_OFFSET_DLBU,},
95 {.description = "Mali_DMA", .base = MALI_OFFSET_DMA,},
96 };
97
98 _mali_osk_errcode_t _mali_osk_resource_initialize(void)
99 {
100         mali_bool mali_is_450 = MALI_FALSE;
101         int i, pp_core_num = 0, l2_core_num = 0;
102         struct resource *res;
103
104         for (i = 0; i < MALI_OSK_RESOURCE_WITH_IRQ_NUMBER; i++) {
105                 res = platform_get_resource_byname(mali_platform_device, IORESOURCE_IRQ, mali_osk_resource_bank[i].irq_name);
106                 if (res) {
107                         mali_osk_resource_bank[i].irq = res->start;
108                         if (0 == strncmp("Mali_PP_Broadcast", mali_osk_resource_bank[i].description,
109                                         strlen(mali_osk_resource_bank[i].description))) {
110                                 mali_is_450 = MALI_TRUE;
111                         }
112                 } else {
113                         mali_osk_resource_bank[i].base = MALI_OSK_INVALID_RESOURCE_ADDRESS;
114                 }
115         }
116
117         for (i = MALI_OSK_RESOURCE_PP_LOCATION_START; i <= MALI_OSK_RESOURCE_PP_LOCATION_END; i++) {
118                 if (MALI_OSK_INVALID_RESOURCE_ADDRESS != mali_osk_resource_bank[i].base) {
119                         pp_core_num++;
120                 }
121         }
122
123         /* We have to divide by 2, because we caculate twice for only one pp(pp_core and pp_mmu_core). */
124         if (0 != pp_core_num % 2) {
125                 MALI_DEBUG_PRINT(2, ("The value of pp core number isn't normal."));
126                 return _MALI_OSK_ERR_FAULT;
127         }
128
129         pp_core_num /= 2;
130
131         /**
132          * we can caculate the number of l2 cache core according the number of pp core number
133          * and device type(mali400/mali450).
134          */
135         if (mali_is_450 && 4 < pp_core_num) {
136                 l2_core_num = 3;
137         } else if (mali_is_450 && 4 >= pp_core_num) {
138                 l2_core_num = 2;
139         } else {
140                 l2_core_num = 1;
141         }
142
143         for (i = MALI_OSK_RESOURCE_l2_LOCATION_END; i > MALI_OSK_RESOURCE_L2_LOCATION_START + l2_core_num - 1; i--) {
144                 mali_osk_resource_bank[i].base = MALI_OSK_INVALID_RESOURCE_ADDRESS;
145         }
146
147         /* If device is not mali-450 type, we have to remove related resource from resource bank. */
148         if (!mali_is_450) {
149                 for (i = MALI_OSK_RESOURCE_l2_LOCATION_END + 1; i < MALI_OSK_MAX_RESOURCE_NUMBER; i++) {
150                         mali_osk_resource_bank[i].base = MALI_OSK_INVALID_RESOURCE_ADDRESS;
151                 }
152         }
153
154         return _MALI_OSK_ERR_OK;
155 }
156
157 _mali_osk_errcode_t _mali_osk_resource_find(u32 addr, _mali_osk_resource_t *res)
158 {
159         int i;
160
161         if (NULL == mali_platform_device) {
162                 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
163         }
164
165         /* Traverse all of resources in resources bank to find the matching one. */
166         for (i = 0; i < MALI_OSK_MAX_RESOURCE_NUMBER; i++) {
167                 if (mali_osk_resource_bank[i].base == addr) {
168                         if (NULL != res) {
169                                 res->base = addr + _mali_osk_resource_base_address();
170                                 res->description = mali_osk_resource_bank[i].description;
171                                 res->irq = mali_osk_resource_bank[i].irq;
172                         }
173                         return _MALI_OSK_ERR_OK;
174                 }
175         }
176
177         return _MALI_OSK_ERR_ITEM_NOT_FOUND;
178 }
179
180 uintptr_t _mali_osk_resource_base_address(void)
181 {
182         struct resource *reg_res = NULL;
183         uintptr_t ret = 0;
184
185         // reg_res = platform_get_resource(mali_platform_device, IORESOURCE_MEM, 0);
186     /* 
187      * rk_ext : to use dts_for_mali_ko_befor_r5p0-01rel0. 
188      * 关于下面的 "1" : 
189      *      dts_for_mali_ko_befor_r5p0-01rel0 中,
190      *      base_addr 定义在 reg 的 第二个 (index 为 "1") 的 item.
191      */
192         reg_res = platform_get_resource(mali_platform_device, IORESOURCE_MEM, 1);
193
194         if (NULL != reg_res) {
195                 ret = reg_res->start;
196         }
197     // D_HEX( (unsigned int)ret);
198
199         return ret;
200 }
201
202 void _mali_osk_device_data_pmu_config_get(u16 *domain_config_array, int array_size)
203 {
204         struct device_node *node = mali_platform_device->dev.of_node;
205         struct property *prop;
206         const __be32 *p;
207         int length = 0, i = 0;
208         u32 u;
209
210         MALI_DEBUG_ASSERT(NULL != node);
211
212         if (!of_get_property(node, "pmu_domain_config", &length)) {
213                 return;
214         }
215
216         if (array_size != length/sizeof(u32)) {
217                 MALI_PRINT_ERROR(("Wrong pmu domain config in device tree."));
218                 return;
219         }
220
221         of_property_for_each_u32(node, "pmu_domain_config", prop, p, u) {
222                 domain_config_array[i] = (u16)u;
223                 i++;
224         }
225
226         return;
227 }
228
229 u32 _mali_osk_get_pmu_switch_delay(void)
230 {
231         struct device_node *node = mali_platform_device->dev.of_node;
232         u32 switch_delay;
233
234         MALI_DEBUG_ASSERT(NULL != node);
235
236         if (0 == of_property_read_u32(node, "pmu_switch_delay", &switch_delay)) {
237                 return switch_delay;
238         } else {
239                 MALI_DEBUG_PRINT(2, ("Couldn't find pmu_switch_delay in device tree configuration.\n"));
240         }
241
242         return 0;
243 }
244
245 #else /* CONFIG_MALI_DT */  /* 若未 定义 CONFIG_MALI_DT. */
246
247 _mali_osk_errcode_t _mali_osk_resource_find(u32 addr, _mali_osk_resource_t *res)
248 {
249         int i;
250         uintptr_t phys_addr;
251
252         if (NULL == mali_platform_device) {
253                 /* Not connected to a device */
254                 return _MALI_OSK_ERR_ITEM_NOT_FOUND;
255         }
256
257         phys_addr = addr + _mali_osk_resource_base_address();
258         for (i = 0; i < mali_platform_device->num_resources; i++) {
259                 if (IORESOURCE_MEM == resource_type(&(mali_platform_device->resource[i])) &&
260                     mali_platform_device->resource[i].start == phys_addr) {
261                         if (NULL != res) {
262                                 res->base = phys_addr;
263                                 res->description = mali_platform_device->resource[i].name;
264
265                                 /* Any (optional) IRQ resource belonging to this resource will follow */
266                                 if ((i + 1) < mali_platform_device->num_resources &&
267                                     IORESOURCE_IRQ == resource_type(&(mali_platform_device->resource[i + 1]))) {
268                                         res->irq = mali_platform_device->resource[i + 1].start;
269                                 } else {
270                                         res->irq = -1;
271                                 }
272                         }
273                         return _MALI_OSK_ERR_OK;
274                 }
275         }
276
277         return _MALI_OSK_ERR_ITEM_NOT_FOUND;
278 }
279
280 uintptr_t _mali_osk_resource_base_address(void)
281 {
282         uintptr_t lowest_addr = (uintptr_t)(0 - 1);
283         uintptr_t ret = 0;
284
285         if (NULL != mali_platform_device) {
286                 int i;
287                 for (i = 0; i < mali_platform_device->num_resources; i++) {
288                         if (mali_platform_device->resource[i].flags & IORESOURCE_MEM &&
289                             mali_platform_device->resource[i].start < lowest_addr) {
290                                 lowest_addr = mali_platform_device->resource[i].start;
291                                 ret = lowest_addr;
292                         }
293                 }
294         }
295
296         return ret;
297 }
298
299 void _mali_osk_device_data_pmu_config_get(u16 *domain_config_array, int array_size)
300 {
301         _mali_osk_device_data data = { 0, };
302
303         if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) {
304                 /* Copy the custom customer power domain config */
305                 _mali_osk_memcpy(domain_config_array, data.pmu_domain_config, sizeof(data.pmu_domain_config));
306         }
307
308         return;
309 }
310
311 u32 _mali_osk_get_pmu_switch_delay(void)
312 {
313         _mali_osk_errcode_t err;
314         _mali_osk_device_data data = { 0, };
315
316         err = _mali_osk_device_data_get(&data);
317
318         if (_MALI_OSK_ERR_OK == err) {
319                 return data.pmu_switch_delay;
320         }
321
322         return 0;
323 }
324 #endif /* CONFIG_MALI_DT */
325
326 _mali_osk_errcode_t _mali_osk_device_data_get(_mali_osk_device_data *data)
327 {
328         MALI_DEBUG_ASSERT_POINTER(data);
329
330         if (NULL != mali_platform_device) {
331                 struct mali_gpu_device_data *os_data = NULL;
332
333                 os_data = (struct mali_gpu_device_data *)mali_platform_device->dev.platform_data;
334                 if (NULL != os_data) {
335                         /* Copy data from OS dependant struct to Mali neutral struct (identical!) */
336                         BUILD_BUG_ON(sizeof(*os_data) != sizeof(*data));
337                         _mali_osk_memcpy(data, os_data, sizeof(*os_data));
338
339                         return _MALI_OSK_ERR_OK;
340                 }
341         }
342
343         return _MALI_OSK_ERR_ITEM_NOT_FOUND;
344 }
345
346 u32 _mali_osk_l2_resource_count(void)
347 {
348         u32 l2_core_num = 0;
349
350         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_L2_RESOURCE0, NULL))
351                 l2_core_num++;
352
353         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_L2_RESOURCE1, NULL))
354                 l2_core_num++;
355
356         if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(MALI_OFFSET_L2_RESOURCE2, NULL))
357                 l2_core_num++;
358
359         MALI_DEBUG_ASSERT(0 < l2_core_num);
360
361         return l2_core_num;
362 }
363
364 mali_bool _mali_osk_shared_interrupts(void)
365 {
366         u32 irqs[128];
367         u32 i, j, irq, num_irqs_found = 0;
368
369         MALI_DEBUG_ASSERT_POINTER(mali_platform_device);
370         MALI_DEBUG_ASSERT(128 >= mali_platform_device->num_resources);
371
372         for (i = 0; i < mali_platform_device->num_resources; i++) {
373                 if (IORESOURCE_IRQ & mali_platform_device->resource[i].flags) {
374                         irq = mali_platform_device->resource[i].start;
375
376                         for (j = 0; j < num_irqs_found; ++j) {
377                                 if (irq == irqs[j]) {
378                                         return MALI_TRUE;
379                                 }
380                         }
381
382                         irqs[num_irqs_found++] = irq;
383                 }
384         }
385
386         return MALI_FALSE;
387 }