2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2012-2014 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
11 #include "mali_kernel_common.h"
13 #include "mali_hw_core.h"
17 * Size of the Mali-450 DMA unit registers in bytes.
19 #define MALI450_DMA_REG_SIZE 0x08
22 * Value that appears in MEMSIZE if an error occurs when reading the command list.
24 #define MALI450_DMA_BUS_ERR_VAL 0xffffffff
28 * Used in the register read/write routines.
29 * See the hardware documentation for more information about each register.
31 typedef enum mali_dma_register {
33 MALI450_DMA_REG_SOURCE_ADDRESS = 0x0000,
34 MALI450_DMA_REG_SOURCE_SIZE = 0x0004,
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 */
43 static struct mali_dma_core *mali_global_dma_core = NULL;
45 struct mali_dma_core *mali_dma_create(_mali_osk_resource_t *resource)
47 struct mali_dma_core *dma;
48 _mali_osk_errcode_t err;
50 MALI_DEBUG_ASSERT(NULL == mali_global_dma_core);
52 dma = _mali_osk_malloc(sizeof(struct mali_dma_core));
53 if (dma == NULL) goto alloc_failed;
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;
58 dma->pool = mali_dma_pool_create(MALI_DMA_CMD_BUF_SIZE, 4, 0);
59 if (NULL == dma->pool) goto dma_pool_failed;
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;
64 mali_global_dma_core = dma;
65 MALI_DEBUG_PRINT(2, ("Mali DMA: Created Mali APB DMA unit\n"));
71 mali_dma_pool_destroy(dma->pool);
73 _mali_osk_spinlock_term(dma->lock);
77 MALI_DEBUG_PRINT(2, ("Mali DMA: Failed to create APB DMA unit\n"));
81 void mali_dma_delete(struct mali_dma_core *dma)
83 MALI_DEBUG_ASSERT_POINTER(dma);
85 MALI_DEBUG_PRINT(2, ("Mali DMA: Deleted Mali APB DMA unit\n"));
87 mali_hw_core_delete(&dma->hw_core);
88 _mali_osk_spinlock_term(dma->lock);
89 mali_dma_pool_destroy(dma->pool);
93 static void mali_dma_bus_error(struct mali_dma_core *dma)
95 u32 addr = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS);
97 MALI_PRINT_ERROR(("Mali DMA: Bus error when reading command list from 0x%lx\n", addr));
100 /* Clear the bus error */
101 mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, 0);
104 static mali_bool mali_dma_is_busy(struct mali_dma_core *dma)
107 mali_bool dma_busy_flag = MALI_FALSE;
109 MALI_DEBUG_ASSERT_POINTER(dma);
111 val = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE);
113 if (MALI450_DMA_BUS_ERR_VAL == val) {
114 /* Bus error reading command list */
115 mali_dma_bus_error(dma);
119 dma_busy_flag = MALI_TRUE;
122 return dma_busy_flag;
125 static void mali_dma_start_transfer(struct mali_dma_core *dma, mali_dma_cmd_buf *buf)
127 u32 memsize = buf->size * 4;
128 u32 addr = buf->phys_addr;
130 MALI_DEBUG_ASSERT_POINTER(dma);
131 MALI_DEBUG_ASSERT(memsize < (1 << 16));
132 MALI_DEBUG_ASSERT(0 == (memsize & 0x3)); /* 4 byte aligned */
134 MALI_DEBUG_ASSERT(!mali_dma_is_busy(dma));
136 /* Writes the physical source memory address of chunk containing command headers and data */
137 mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS, addr);
139 /* Writes the length of transfer */
140 mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, memsize);
143 _mali_osk_errcode_t mali_dma_get_cmd_buf(mali_dma_cmd_buf *buf)
145 MALI_DEBUG_ASSERT_POINTER(buf);
147 buf->virt_addr = (u32 *)mali_dma_pool_alloc(mali_global_dma_core->pool, &buf->phys_addr);
148 if (NULL == buf->virt_addr) {
149 return _MALI_OSK_ERR_NOMEM;
152 /* size contains the number of words in the buffer and is incremented
153 * as commands are added to the buffer. */
156 return _MALI_OSK_ERR_OK;
159 void mali_dma_put_cmd_buf(mali_dma_cmd_buf *buf)
161 MALI_DEBUG_ASSERT_POINTER(buf);
163 if (NULL == buf->virt_addr) return;
165 mali_dma_pool_free(mali_global_dma_core->pool, buf->virt_addr, buf->phys_addr);
167 buf->virt_addr = NULL;
170 _mali_osk_errcode_t mali_dma_start(struct mali_dma_core *dma, mali_dma_cmd_buf *buf)
172 _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
174 _mali_osk_spinlock_lock(dma->lock);
176 if (mali_dma_is_busy(dma)) {
177 err = _MALI_OSK_ERR_BUSY;
181 mali_dma_start_transfer(dma, buf);
184 _mali_osk_spinlock_unlock(dma->lock);
188 void mali_dma_debug(struct mali_dma_core *dma)
190 MALI_DEBUG_ASSERT_POINTER(dma);
191 MALI_DEBUG_PRINT(1, ("DMA unit registers:\n\t%08x, %08x\n",
192 mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS),
193 mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE)
198 struct mali_dma_core *mali_dma_get_global_dma_core(void)
200 /* Returns the global dma core object */
201 return mali_global_dma_core;