tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / common / mali_dma.c
1 /*
2  * Copyright (C) 2010-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_kernel_common.h"
12 #include "mali_osk.h"
13 #include "mali_hw_core.h"
14 #include "mali_dma.h"
15
16 /**
17  * Size of the Mali-450 DMA unit registers in bytes.
18  */
19 #define MALI450_DMA_REG_SIZE 0x08
20
21 /**
22  * Value that appears in MEMSIZE if an error occurs when reading the command list.
23  */
24 #define MALI450_DMA_BUS_ERR_VAL 0xffffffff
25
26 /**
27  * Mali DMA registers
28  * Used in the register read/write routines.
29  * See the hardware documentation for more information about each register.
30  */
31 typedef enum mali_dma_register {
32
33         MALI450_DMA_REG_SOURCE_ADDRESS = 0x0000,
34         MALI450_DMA_REG_SOURCE_SIZE = 0x0004,
35 } mali_dma_register;
36
37 struct mali_dma_core {
38         struct mali_hw_core  hw_core;      /**< Common for all HW cores */
39         _mali_osk_spinlock_t *lock;            /**< Lock protecting access to DMA core */
40         mali_dma_pool pool;                /**< Memory pool for command buffers */
41 };
42
43 static struct mali_dma_core *mali_global_dma_core = NULL;
44
45 struct mali_dma_core *mali_dma_create(_mali_osk_resource_t *resource)
46 {
47         struct mali_dma_core* dma;
48         _mali_osk_errcode_t err;
49
50         MALI_DEBUG_ASSERT(NULL == mali_global_dma_core);
51
52         dma = _mali_osk_malloc(sizeof(struct mali_dma_core));
53         if (dma == NULL) goto alloc_failed;
54
55         dma->lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_DMA_COMMAND);
56         if (NULL == dma->lock) goto lock_init_failed;
57
58         dma->pool = mali_dma_pool_create(MALI_DMA_CMD_BUF_SIZE, 4, 0);
59         if (NULL == dma->pool) goto dma_pool_failed;
60
61         err = mali_hw_core_create(&dma->hw_core, resource, MALI450_DMA_REG_SIZE);
62         if (_MALI_OSK_ERR_OK != err) goto hw_core_failed;
63
64         mali_global_dma_core = dma;
65         MALI_DEBUG_PRINT(2, ("Mali DMA: Created Mali APB DMA unit\n"));
66         return dma;
67
68         /* Error handling */
69
70 hw_core_failed:
71         mali_dma_pool_destroy(dma->pool);
72 dma_pool_failed:
73         _mali_osk_spinlock_term(dma->lock);
74 lock_init_failed:
75         _mali_osk_free(dma);
76 alloc_failed:
77         MALI_DEBUG_PRINT(2, ("Mali DMA: Failed to create APB DMA unit\n"));
78         return NULL;
79 }
80
81 void mali_dma_delete(struct mali_dma_core *dma)
82 {
83         MALI_DEBUG_ASSERT_POINTER(dma);
84
85         MALI_DEBUG_PRINT(2, ("Mali DMA: Deleted Mali APB DMA unit\n"));
86
87         mali_hw_core_delete(&dma->hw_core);
88         _mali_osk_spinlock_term(dma->lock);
89         mali_dma_pool_destroy(dma->pool);
90         _mali_osk_free(dma);
91 }
92
93 static void mali_dma_bus_error(struct mali_dma_core *dma)
94 {
95         u32 addr = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS);
96
97         MALI_PRINT_ERROR(("Mali DMA: Bus error when reading command list from 0x%lx\n", addr));
98
99         /* Clear the bus error */
100         mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, 0);
101 }
102
103 static mali_bool mali_dma_is_busy(struct mali_dma_core *dma)
104 {
105         u32 val;
106         mali_bool dma_busy_flag = MALI_FALSE;
107
108         MALI_DEBUG_ASSERT_POINTER(dma);
109
110         val = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE);
111
112         if (MALI450_DMA_BUS_ERR_VAL == val) {
113                 /* Bus error reading command list */
114                 mali_dma_bus_error(dma);
115                 return MALI_FALSE;
116         }
117         if (val > 0) {
118                 dma_busy_flag = MALI_TRUE;
119         }
120
121         return dma_busy_flag;
122 }
123
124 static void mali_dma_start_transfer(struct mali_dma_core* dma, mali_dma_cmd_buf *buf)
125 {
126         u32 memsize = buf->size * 4;
127         u32 addr = buf->phys_addr;
128
129         MALI_DEBUG_ASSERT_POINTER(dma);
130         MALI_DEBUG_ASSERT(memsize < (1 << 16));
131         MALI_DEBUG_ASSERT(0 == (memsize & 0x3)); /* 4 byte aligned */
132
133         MALI_DEBUG_ASSERT(!mali_dma_is_busy(dma));
134
135         /* Writes the physical source memory address of chunk containing command headers and data */
136         mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS, addr);
137
138         /* Writes the length of transfer */
139         mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, memsize);
140 }
141
142 _mali_osk_errcode_t mali_dma_get_cmd_buf(mali_dma_cmd_buf *buf)
143 {
144         MALI_DEBUG_ASSERT_POINTER(buf);
145
146         buf->virt_addr = (u32*)mali_dma_pool_alloc(mali_global_dma_core->pool, &buf->phys_addr);
147         if (NULL == buf->virt_addr) {
148                 return _MALI_OSK_ERR_NOMEM;
149         }
150
151         /* size contains the number of words in the buffer and is incremented
152          * as commands are added to the buffer. */
153         buf->size = 0;
154
155         return _MALI_OSK_ERR_OK;
156 }
157
158 void mali_dma_put_cmd_buf(mali_dma_cmd_buf *buf)
159 {
160         MALI_DEBUG_ASSERT_POINTER(buf);
161
162         if (NULL == buf->virt_addr) return;
163
164         mali_dma_pool_free(mali_global_dma_core->pool, buf->virt_addr, buf->phys_addr);
165
166         buf->virt_addr = NULL;
167 }
168
169 _mali_osk_errcode_t mali_dma_start(struct mali_dma_core* dma, mali_dma_cmd_buf *buf)
170 {
171         _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
172
173         _mali_osk_spinlock_lock(dma->lock);
174
175         if (mali_dma_is_busy(dma)) {
176                 err = _MALI_OSK_ERR_BUSY;
177                 goto out;
178         }
179
180         mali_dma_start_transfer(dma, buf);
181
182 out:
183         _mali_osk_spinlock_unlock(dma->lock);
184         return err;
185 }
186
187 void mali_dma_debug(struct mali_dma_core *dma)
188 {
189         MALI_DEBUG_ASSERT_POINTER(dma);
190         MALI_DEBUG_PRINT(1, ("DMA unit registers:\n\t%08x, %08x\n",
191                              mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS),
192                              mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE)
193                             ));
194
195 }
196
197 struct mali_dma_core *mali_dma_get_global_dma_core(void)
198 {
199         /* Returns the global dma core object */
200         return mali_global_dma_core;
201 }