tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / common / mali_pmu.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 /**
12  * @file mali_pmu.c
13  * Mali driver functions for Mali 400 PMU hardware
14  */
15 #include "mali_hw_core.h"
16 #include "mali_pmu.h"
17 #include "mali_pp.h"
18 #include "mali_kernel_common.h"
19 #include "mali_osk.h"
20
21 static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches);
22
23 /** @brief MALI inbuilt PMU hardware info and PMU hardware has knowledge of cores power mask
24  */
25 struct mali_pmu_core
26 {
27         struct mali_hw_core hw_core;
28         u32 mali_registered_cores_power_mask;
29 };
30
31 static struct mali_pmu_core *mali_global_pmu_core = NULL;
32
33 /** @brief Register layout for hardware PMU
34  */
35 typedef enum {
36         PMU_REG_ADDR_MGMT_POWER_UP                  = 0x00,     /*< Power up register */
37         PMU_REG_ADDR_MGMT_POWER_DOWN                = 0x04,     /*< Power down register */
38         PMU_REG_ADDR_MGMT_STATUS                    = 0x08,     /*< Core sleep status register */
39         PMU_REG_ADDR_MGMT_INT_MASK                  = 0x0C,     /*< Interrupt mask register */
40         PMU_REGISTER_ADDRESS_SPACE_SIZE             = 0x10,     /*< Size of register space */
41 } pmu_reg_addr_mgmt_addr;
42
43 struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource, u32 number_of_pp_cores, u32 number_of_l2_caches)
44 {
45         struct mali_pmu_core* pmu;
46
47         MALI_DEBUG_ASSERT(NULL == mali_global_pmu_core);
48         MALI_DEBUG_PRINT(2, ("Mali PMU: Creating Mali PMU core\n"));
49
50         pmu = (struct mali_pmu_core *)_mali_osk_malloc(sizeof(struct mali_pmu_core));
51         if (NULL != pmu)
52         {
53                 pmu->mali_registered_cores_power_mask = mali_pmu_detect_mask(number_of_pp_cores, number_of_l2_caches);
54                 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&pmu->hw_core, resource, PMU_REGISTER_ADDRESS_SPACE_SIZE))
55                 {
56                         if (_MALI_OSK_ERR_OK == mali_pmu_reset(pmu))
57                         {
58                                 mali_global_pmu_core = pmu;
59                                 return pmu;
60                         }
61                         mali_hw_core_delete(&pmu->hw_core);
62                 }
63                 _mali_osk_free(pmu);
64         }
65
66         return NULL;
67 }
68
69 void mali_pmu_delete(struct mali_pmu_core *pmu)
70 {
71         MALI_DEBUG_ASSERT_POINTER(pmu);
72
73         mali_hw_core_delete(&pmu->hw_core);
74         _mali_osk_free(pmu);
75         pmu = NULL;
76 }
77
78 _mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu)
79 {
80         /* Don't use interrupts - just poll status */
81         mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0);
82         return _MALI_OSK_ERR_OK;
83 }
84
85 _mali_osk_errcode_t mali_pmu_powerdown_all(struct mali_pmu_core *pmu)
86 {
87         u32 stat;
88         u32 timeout;
89
90         MALI_DEBUG_ASSERT_POINTER(pmu);
91         MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 );
92         MALI_DEBUG_PRINT( 4, ("Mali PMU: power down (0x%08X)\n", pmu->mali_registered_cores_power_mask) );
93
94         mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_DOWN, pmu->mali_registered_cores_power_mask);
95
96         /* Wait for cores to be powered down (100 x 100us = 100ms) */
97         timeout = MALI_REG_POLL_COUNT_SLOW ;
98         do
99         {
100                 /* Get status of sleeping cores */
101                 stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS);
102                 stat &= pmu->mali_registered_cores_power_mask;
103                 if( stat == pmu->mali_registered_cores_power_mask ) break; /* All cores we wanted are now asleep */
104                 timeout--;
105         } while( timeout > 0 );
106
107         if( timeout == 0 )
108         {
109                 return _MALI_OSK_ERR_TIMEOUT;
110         }
111
112         return _MALI_OSK_ERR_OK;
113 }
114
115 _mali_osk_errcode_t mali_pmu_powerup_all(struct mali_pmu_core *pmu)
116 {
117         u32 stat;
118         u32 timeout;
119        
120         MALI_DEBUG_ASSERT_POINTER(pmu);
121         MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 ); /* Shouldn't be zero */
122         MALI_DEBUG_PRINT( 4, ("Mali PMU: power up (0x%08X)\n", pmu->mali_registered_cores_power_mask) );
123
124         mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_UP, pmu->mali_registered_cores_power_mask);
125
126         /* Wait for cores to be powered up (100 x 100us = 100ms) */
127         timeout = MALI_REG_POLL_COUNT_SLOW;
128         do
129         {
130                 /* Get status of sleeping cores */
131                 stat = mali_hw_core_register_read(&pmu->hw_core,PMU_REG_ADDR_MGMT_STATUS);
132                 stat &= pmu->mali_registered_cores_power_mask;
133                 if ( stat == 0 ) break; /* All cores we wanted are now awake */
134                 timeout--;
135         } while ( timeout > 0 );
136
137         if ( timeout == 0 )
138         {
139                 return _MALI_OSK_ERR_TIMEOUT;
140         }
141
142         return _MALI_OSK_ERR_OK;
143 }
144
145 struct mali_pmu_core *mali_pmu_get_global_pmu_core(void)
146 {
147         return mali_global_pmu_core;
148 }
149
150 static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches)
151 {
152         u32 mask = 0;
153
154         if (number_of_l2_caches == 1)
155         {
156                 /* Mali-300 or Mali-400 */
157                 u32 i;
158
159                 /* GP */
160                 mask = 0x01;
161
162                 /* L2 cache */
163                 mask |= 0x01<<1;
164
165                 /* Set bit for each PP core */
166                 for (i = 0; i < number_of_pp_cores; i++)
167                 {
168                         mask |= 0x01<<(i+2);
169                 }
170         }
171         else if (number_of_l2_caches > 1)
172         {
173                 /* Mali-450 */
174
175                 /* GP (including its L2 cache) */
176                 mask = 0x01;
177
178                 /* There is always at least one PP (including its L2 cache) */
179                 mask |= 0x01<<1;
180
181                 /* Additional PP cores in same L2 cache */
182                 if (number_of_pp_cores >= 2)
183                 {
184                         mask |= 0x01<<2;
185                 }
186
187                 /* Additional PP cores in a third L2 cache */
188                 if (number_of_pp_cores >= 5)
189                 {
190                         mask |= 0x01<<3;
191                 }
192         }
193
194         MALI_DEBUG_PRINT(4, ("Mali PMU: Power mask is 0x%08X (%u + %u)\n", mask, number_of_pp_cores, number_of_l2_caches));
195
196         return mask;
197 }