xref: /openbmc/linux/drivers/gpu/drm/lima/lima_gp.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
1a1d2a633SQiang Yu // SPDX-License-Identifier: GPL-2.0 OR MIT
2a1d2a633SQiang Yu /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
3a1d2a633SQiang Yu 
4a1d2a633SQiang Yu #include <linux/interrupt.h>
5a1d2a633SQiang Yu #include <linux/iopoll.h>
6a1d2a633SQiang Yu #include <linux/device.h>
7a1d2a633SQiang Yu #include <linux/slab.h>
8a1d2a633SQiang Yu 
9a1d2a633SQiang Yu #include <drm/lima_drm.h>
10a1d2a633SQiang Yu 
11a1d2a633SQiang Yu #include "lima_device.h"
12a1d2a633SQiang Yu #include "lima_gp.h"
13a1d2a633SQiang Yu #include "lima_regs.h"
142081e8dcSQiang Yu #include "lima_gem.h"
152081e8dcSQiang Yu #include "lima_vm.h"
16a1d2a633SQiang Yu 
17a1d2a633SQiang Yu #define gp_write(reg, data) writel(data, ip->iomem + reg)
18a1d2a633SQiang Yu #define gp_read(reg) readl(ip->iomem + reg)
19a1d2a633SQiang Yu 
lima_gp_irq_handler(int irq,void * data)20a1d2a633SQiang Yu static irqreturn_t lima_gp_irq_handler(int irq, void *data)
21a1d2a633SQiang Yu {
22a1d2a633SQiang Yu 	struct lima_ip *ip = data;
23a1d2a633SQiang Yu 	struct lima_device *dev = ip->dev;
24a1d2a633SQiang Yu 	struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
252081e8dcSQiang Yu 	struct lima_sched_task *task = pipe->current_task;
26a1d2a633SQiang Yu 	u32 state = gp_read(LIMA_GP_INT_STAT);
27a1d2a633SQiang Yu 	u32 status = gp_read(LIMA_GP_STATUS);
28a1d2a633SQiang Yu 	bool done = false;
29a1d2a633SQiang Yu 
30a1d2a633SQiang Yu 	/* for shared irq case */
31a1d2a633SQiang Yu 	if (!state)
32a1d2a633SQiang Yu 		return IRQ_NONE;
33a1d2a633SQiang Yu 
34a1d2a633SQiang Yu 	if (state & LIMA_GP_IRQ_MASK_ERROR) {
352081e8dcSQiang Yu 		if ((state & LIMA_GP_IRQ_MASK_ERROR) ==
362081e8dcSQiang Yu 		    LIMA_GP_IRQ_PLBU_OUT_OF_MEM) {
372081e8dcSQiang Yu 			dev_dbg(dev->dev, "gp out of heap irq status=%x\n",
382081e8dcSQiang Yu 				status);
392081e8dcSQiang Yu 		} else {
40a1d2a633SQiang Yu 			dev_err(dev->dev, "gp error irq state=%x status=%x\n",
41a1d2a633SQiang Yu 				state, status);
422081e8dcSQiang Yu 			if (task)
432081e8dcSQiang Yu 				task->recoverable = false;
442081e8dcSQiang Yu 		}
45a1d2a633SQiang Yu 
46a1d2a633SQiang Yu 		/* mask all interrupts before hard reset */
47a1d2a633SQiang Yu 		gp_write(LIMA_GP_INT_MASK, 0);
48a1d2a633SQiang Yu 
49a1d2a633SQiang Yu 		pipe->error = true;
50a1d2a633SQiang Yu 		done = true;
51a1d2a633SQiang Yu 	} else {
52a1d2a633SQiang Yu 		bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST |
53a1d2a633SQiang Yu 				      LIMA_GP_IRQ_PLBU_END_CMD_LST);
54a1d2a633SQiang Yu 		bool active = status & (LIMA_GP_STATUS_VS_ACTIVE |
55a1d2a633SQiang Yu 					LIMA_GP_STATUS_PLBU_ACTIVE);
56a1d2a633SQiang Yu 		done = valid && !active;
572081e8dcSQiang Yu 		pipe->error = false;
58a1d2a633SQiang Yu 	}
59a1d2a633SQiang Yu 
60a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_CLEAR, state);
61a1d2a633SQiang Yu 
62a1d2a633SQiang Yu 	if (done)
63a1d2a633SQiang Yu 		lima_sched_pipe_task_done(pipe);
64a1d2a633SQiang Yu 
65a1d2a633SQiang Yu 	return IRQ_HANDLED;
66a1d2a633SQiang Yu }
67a1d2a633SQiang Yu 
lima_gp_soft_reset_async(struct lima_ip * ip)68a1d2a633SQiang Yu static void lima_gp_soft_reset_async(struct lima_ip *ip)
69a1d2a633SQiang Yu {
70a1d2a633SQiang Yu 	if (ip->data.async_reset)
71a1d2a633SQiang Yu 		return;
72a1d2a633SQiang Yu 
73a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_MASK, 0);
74a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED);
75a1d2a633SQiang Yu 	gp_write(LIMA_GP_CMD, LIMA_GP_CMD_SOFT_RESET);
76a1d2a633SQiang Yu 	ip->data.async_reset = true;
77a1d2a633SQiang Yu }
78a1d2a633SQiang Yu 
lima_gp_soft_reset_async_wait(struct lima_ip * ip)79a1d2a633SQiang Yu static int lima_gp_soft_reset_async_wait(struct lima_ip *ip)
80a1d2a633SQiang Yu {
81a1d2a633SQiang Yu 	struct lima_device *dev = ip->dev;
82a1d2a633SQiang Yu 	int err;
83a1d2a633SQiang Yu 	u32 v;
84a1d2a633SQiang Yu 
85a1d2a633SQiang Yu 	if (!ip->data.async_reset)
86a1d2a633SQiang Yu 		return 0;
87a1d2a633SQiang Yu 
88a1d2a633SQiang Yu 	err = readl_poll_timeout(ip->iomem + LIMA_GP_INT_RAWSTAT, v,
89a1d2a633SQiang Yu 				 v & LIMA_GP_IRQ_RESET_COMPLETED,
90a1d2a633SQiang Yu 				 0, 100);
91a1d2a633SQiang Yu 	if (err) {
92a1d2a633SQiang Yu 		dev_err(dev->dev, "gp soft reset time out\n");
93a1d2a633SQiang Yu 		return err;
94a1d2a633SQiang Yu 	}
95a1d2a633SQiang Yu 
96a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
97a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
98a1d2a633SQiang Yu 
99a1d2a633SQiang Yu 	ip->data.async_reset = false;
100a1d2a633SQiang Yu 	return 0;
101a1d2a633SQiang Yu }
102a1d2a633SQiang Yu 
lima_gp_task_validate(struct lima_sched_pipe * pipe,struct lima_sched_task * task)103a1d2a633SQiang Yu static int lima_gp_task_validate(struct lima_sched_pipe *pipe,
104a1d2a633SQiang Yu 				 struct lima_sched_task *task)
105a1d2a633SQiang Yu {
106a1d2a633SQiang Yu 	struct drm_lima_gp_frame *frame = task->frame;
107a1d2a633SQiang Yu 	u32 *f = frame->frame;
108a1d2a633SQiang Yu 	(void)pipe;
109a1d2a633SQiang Yu 
110a1d2a633SQiang Yu 	if (f[LIMA_GP_VSCL_START_ADDR >> 2] >
111a1d2a633SQiang Yu 	    f[LIMA_GP_VSCL_END_ADDR >> 2] ||
112a1d2a633SQiang Yu 	    f[LIMA_GP_PLBUCL_START_ADDR >> 2] >
113a1d2a633SQiang Yu 	    f[LIMA_GP_PLBUCL_END_ADDR >> 2] ||
114a1d2a633SQiang Yu 	    f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] >
115a1d2a633SQiang Yu 	    f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2])
116a1d2a633SQiang Yu 		return -EINVAL;
117a1d2a633SQiang Yu 
118a1d2a633SQiang Yu 	if (f[LIMA_GP_VSCL_START_ADDR >> 2] ==
119a1d2a633SQiang Yu 	    f[LIMA_GP_VSCL_END_ADDR >> 2] &&
120a1d2a633SQiang Yu 	    f[LIMA_GP_PLBUCL_START_ADDR >> 2] ==
121a1d2a633SQiang Yu 	    f[LIMA_GP_PLBUCL_END_ADDR >> 2])
122a1d2a633SQiang Yu 		return -EINVAL;
123a1d2a633SQiang Yu 
124a1d2a633SQiang Yu 	return 0;
125a1d2a633SQiang Yu }
126a1d2a633SQiang Yu 
lima_gp_task_run(struct lima_sched_pipe * pipe,struct lima_sched_task * task)127a1d2a633SQiang Yu static void lima_gp_task_run(struct lima_sched_pipe *pipe,
128a1d2a633SQiang Yu 			     struct lima_sched_task *task)
129a1d2a633SQiang Yu {
130a1d2a633SQiang Yu 	struct lima_ip *ip = pipe->processor[0];
131a1d2a633SQiang Yu 	struct drm_lima_gp_frame *frame = task->frame;
132a1d2a633SQiang Yu 	u32 *f = frame->frame;
133a1d2a633SQiang Yu 	u32 cmd = 0;
134a1d2a633SQiang Yu 	int i;
135a1d2a633SQiang Yu 
1362081e8dcSQiang Yu 	/* update real heap buffer size for GP */
1372081e8dcSQiang Yu 	for (i = 0; i < task->num_bos; i++) {
1382081e8dcSQiang Yu 		struct lima_bo *bo = task->bos[i];
1392081e8dcSQiang Yu 
1402081e8dcSQiang Yu 		if (bo->heap_size &&
1412081e8dcSQiang Yu 		    lima_vm_get_va(task->vm, bo) ==
1422081e8dcSQiang Yu 		    f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2]) {
1432081e8dcSQiang Yu 			f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
1442081e8dcSQiang Yu 				f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] +
1452081e8dcSQiang Yu 				bo->heap_size;
1462081e8dcSQiang Yu 			task->recoverable = true;
1472081e8dcSQiang Yu 			task->heap = bo;
1482081e8dcSQiang Yu 			break;
1492081e8dcSQiang Yu 		}
1502081e8dcSQiang Yu 	}
1512081e8dcSQiang Yu 
152a1d2a633SQiang Yu 	if (f[LIMA_GP_VSCL_START_ADDR >> 2] !=
153a1d2a633SQiang Yu 	    f[LIMA_GP_VSCL_END_ADDR >> 2])
154a1d2a633SQiang Yu 		cmd |= LIMA_GP_CMD_START_VS;
155a1d2a633SQiang Yu 	if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] !=
156a1d2a633SQiang Yu 	    f[LIMA_GP_PLBUCL_END_ADDR >> 2])
157a1d2a633SQiang Yu 		cmd |= LIMA_GP_CMD_START_PLBU;
158a1d2a633SQiang Yu 
159a1d2a633SQiang Yu 	/* before any hw ops, wait last success task async soft reset */
160a1d2a633SQiang Yu 	lima_gp_soft_reset_async_wait(ip);
161a1d2a633SQiang Yu 
162a1d2a633SQiang Yu 	for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++)
163a1d2a633SQiang Yu 		writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4);
164a1d2a633SQiang Yu 
165a1d2a633SQiang Yu 	gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
166a1d2a633SQiang Yu 	gp_write(LIMA_GP_CMD, cmd);
167a1d2a633SQiang Yu }
168a1d2a633SQiang Yu 
lima_gp_bus_stop_poll(struct lima_ip * ip)169*93249026SErico Nunes static int lima_gp_bus_stop_poll(struct lima_ip *ip)
170*93249026SErico Nunes {
171*93249026SErico Nunes 	return !!(gp_read(LIMA_GP_STATUS) & LIMA_GP_STATUS_BUS_STOPPED);
172*93249026SErico Nunes }
173*93249026SErico Nunes 
lima_gp_hard_reset_poll(struct lima_ip * ip)174a1d2a633SQiang Yu static int lima_gp_hard_reset_poll(struct lima_ip *ip)
175a1d2a633SQiang Yu {
176a1d2a633SQiang Yu 	gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000);
177a1d2a633SQiang Yu 	return gp_read(LIMA_GP_PERF_CNT_0_LIMIT) == 0xC01A0000;
178a1d2a633SQiang Yu }
179a1d2a633SQiang Yu 
lima_gp_hard_reset(struct lima_ip * ip)180a1d2a633SQiang Yu static int lima_gp_hard_reset(struct lima_ip *ip)
181a1d2a633SQiang Yu {
182a1d2a633SQiang Yu 	struct lima_device *dev = ip->dev;
183a1d2a633SQiang Yu 	int ret;
184a1d2a633SQiang Yu 
185a1d2a633SQiang Yu 	gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000);
186a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_MASK, 0);
187*93249026SErico Nunes 
188*93249026SErico Nunes 	gp_write(LIMA_GP_CMD, LIMA_GP_CMD_STOP_BUS);
189*93249026SErico Nunes 	ret = lima_poll_timeout(ip, lima_gp_bus_stop_poll, 10, 100);
190*93249026SErico Nunes 	if (ret) {
191*93249026SErico Nunes 		dev_err(dev->dev, "%s bus stop timeout\n", lima_ip_name(ip));
192*93249026SErico Nunes 		return ret;
193*93249026SErico Nunes 	}
194a1d2a633SQiang Yu 	gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET);
195a1d2a633SQiang Yu 	ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100);
196a1d2a633SQiang Yu 	if (ret) {
197a1d2a633SQiang Yu 		dev_err(dev->dev, "gp hard reset timeout\n");
198a1d2a633SQiang Yu 		return ret;
199a1d2a633SQiang Yu 	}
200a1d2a633SQiang Yu 
201a1d2a633SQiang Yu 	gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0);
202a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL);
203a1d2a633SQiang Yu 	gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
204a1d2a633SQiang Yu 	return 0;
205a1d2a633SQiang Yu }
206a1d2a633SQiang Yu 
lima_gp_task_fini(struct lima_sched_pipe * pipe)207a1d2a633SQiang Yu static void lima_gp_task_fini(struct lima_sched_pipe *pipe)
208a1d2a633SQiang Yu {
209a1d2a633SQiang Yu 	lima_gp_soft_reset_async(pipe->processor[0]);
210a1d2a633SQiang Yu }
211a1d2a633SQiang Yu 
lima_gp_task_error(struct lima_sched_pipe * pipe)212a1d2a633SQiang Yu static void lima_gp_task_error(struct lima_sched_pipe *pipe)
213a1d2a633SQiang Yu {
214a1d2a633SQiang Yu 	struct lima_ip *ip = pipe->processor[0];
215a1d2a633SQiang Yu 
216a1d2a633SQiang Yu 	dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n",
217a1d2a633SQiang Yu 		gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS));
218a1d2a633SQiang Yu 
219a1d2a633SQiang Yu 	lima_gp_hard_reset(ip);
220a1d2a633SQiang Yu }
221a1d2a633SQiang Yu 
lima_gp_task_mmu_error(struct lima_sched_pipe * pipe)222a1d2a633SQiang Yu static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe)
223a1d2a633SQiang Yu {
224a1d2a633SQiang Yu 	lima_sched_pipe_task_done(pipe);
225a1d2a633SQiang Yu }
226a1d2a633SQiang Yu 
lima_gp_task_mask_irq(struct lima_sched_pipe * pipe)227022db5d6SErico Nunes static void lima_gp_task_mask_irq(struct lima_sched_pipe *pipe)
228022db5d6SErico Nunes {
229022db5d6SErico Nunes 	struct lima_ip *ip = pipe->processor[0];
230022db5d6SErico Nunes 
231022db5d6SErico Nunes 	gp_write(LIMA_GP_INT_MASK, 0);
232022db5d6SErico Nunes }
233022db5d6SErico Nunes 
lima_gp_task_recover(struct lima_sched_pipe * pipe)2342081e8dcSQiang Yu static int lima_gp_task_recover(struct lima_sched_pipe *pipe)
2352081e8dcSQiang Yu {
2362081e8dcSQiang Yu 	struct lima_ip *ip = pipe->processor[0];
2372081e8dcSQiang Yu 	struct lima_sched_task *task = pipe->current_task;
2382081e8dcSQiang Yu 	struct drm_lima_gp_frame *frame = task->frame;
2392081e8dcSQiang Yu 	u32 *f = frame->frame;
2402081e8dcSQiang Yu 	size_t fail_size =
2412081e8dcSQiang Yu 		f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] -
2422081e8dcSQiang Yu 		f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2];
2432081e8dcSQiang Yu 
2442081e8dcSQiang Yu 	if (fail_size == task->heap->heap_size) {
2452081e8dcSQiang Yu 		int ret;
2462081e8dcSQiang Yu 
2472081e8dcSQiang Yu 		ret = lima_heap_alloc(task->heap, task->vm);
2482081e8dcSQiang Yu 		if (ret < 0)
2492081e8dcSQiang Yu 			return ret;
2502081e8dcSQiang Yu 	}
2512081e8dcSQiang Yu 
2522081e8dcSQiang Yu 	gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED);
2536707b755SVasily Khoruzhick 	/* Resume from where we stopped, i.e. new start is old end */
2546707b755SVasily Khoruzhick 	gp_write(LIMA_GP_PLBU_ALLOC_START_ADDR,
2556707b755SVasily Khoruzhick 		 f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
2566707b755SVasily Khoruzhick 	f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2] =
2576707b755SVasily Khoruzhick 		f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] + task->heap->heap_size;
2582081e8dcSQiang Yu 	gp_write(LIMA_GP_PLBU_ALLOC_END_ADDR,
2596707b755SVasily Khoruzhick 		 f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]);
2602081e8dcSQiang Yu 	gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC);
2612081e8dcSQiang Yu 	return 0;
2622081e8dcSQiang Yu }
2632081e8dcSQiang Yu 
lima_gp_print_version(struct lima_ip * ip)264a1d2a633SQiang Yu static void lima_gp_print_version(struct lima_ip *ip)
265a1d2a633SQiang Yu {
266a1d2a633SQiang Yu 	u32 version, major, minor;
267a1d2a633SQiang Yu 	char *name;
268a1d2a633SQiang Yu 
269a1d2a633SQiang Yu 	version = gp_read(LIMA_GP_VERSION);
270a1d2a633SQiang Yu 	major = (version >> 8) & 0xFF;
271a1d2a633SQiang Yu 	minor = version & 0xFF;
272a1d2a633SQiang Yu 	switch (version >> 16) {
273a1d2a633SQiang Yu 	case 0xA07:
274a1d2a633SQiang Yu 	    name = "mali200";
275a1d2a633SQiang Yu 		break;
276a1d2a633SQiang Yu 	case 0xC07:
277a1d2a633SQiang Yu 		name = "mali300";
278a1d2a633SQiang Yu 		break;
279a1d2a633SQiang Yu 	case 0xB07:
280a1d2a633SQiang Yu 		name = "mali400";
281a1d2a633SQiang Yu 		break;
282a1d2a633SQiang Yu 	case 0xD07:
283a1d2a633SQiang Yu 		name = "mali450";
284a1d2a633SQiang Yu 		break;
285a1d2a633SQiang Yu 	default:
286a1d2a633SQiang Yu 		name = "unknown";
287a1d2a633SQiang Yu 		break;
288a1d2a633SQiang Yu 	}
289a1d2a633SQiang Yu 	dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n",
290a1d2a633SQiang Yu 		 lima_ip_name(ip), name, major, minor);
291a1d2a633SQiang Yu }
292a1d2a633SQiang Yu 
293a1d2a633SQiang Yu static struct kmem_cache *lima_gp_task_slab;
294a1d2a633SQiang Yu static int lima_gp_task_slab_refcnt;
295a1d2a633SQiang Yu 
lima_gp_hw_init(struct lima_ip * ip)2963446d7e9SQiang Yu static int lima_gp_hw_init(struct lima_ip *ip)
2973446d7e9SQiang Yu {
2983446d7e9SQiang Yu 	ip->data.async_reset = false;
2993446d7e9SQiang Yu 	lima_gp_soft_reset_async(ip);
3003446d7e9SQiang Yu 	return lima_gp_soft_reset_async_wait(ip);
3013446d7e9SQiang Yu }
3023446d7e9SQiang Yu 
lima_gp_resume(struct lima_ip * ip)3033446d7e9SQiang Yu int lima_gp_resume(struct lima_ip *ip)
3043446d7e9SQiang Yu {
3053446d7e9SQiang Yu 	return lima_gp_hw_init(ip);
3063446d7e9SQiang Yu }
3073446d7e9SQiang Yu 
lima_gp_suspend(struct lima_ip * ip)3083446d7e9SQiang Yu void lima_gp_suspend(struct lima_ip *ip)
3093446d7e9SQiang Yu {
3103446d7e9SQiang Yu 
3113446d7e9SQiang Yu }
3123446d7e9SQiang Yu 
lima_gp_init(struct lima_ip * ip)313a1d2a633SQiang Yu int lima_gp_init(struct lima_ip *ip)
314a1d2a633SQiang Yu {
315a1d2a633SQiang Yu 	struct lima_device *dev = ip->dev;
316a1d2a633SQiang Yu 	int err;
317a1d2a633SQiang Yu 
318a1d2a633SQiang Yu 	lima_gp_print_version(ip);
319a1d2a633SQiang Yu 
3203446d7e9SQiang Yu 	err = lima_gp_hw_init(ip);
321a1d2a633SQiang Yu 	if (err)
322a1d2a633SQiang Yu 		return err;
323a1d2a633SQiang Yu 
324a1d2a633SQiang Yu 	err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler,
325a1d2a633SQiang Yu 			       IRQF_SHARED, lima_ip_name(ip), ip);
326a1d2a633SQiang Yu 	if (err) {
327a1d2a633SQiang Yu 		dev_err(dev->dev, "gp %s fail to request irq\n",
328a1d2a633SQiang Yu 			lima_ip_name(ip));
329a1d2a633SQiang Yu 		return err;
330a1d2a633SQiang Yu 	}
331a1d2a633SQiang Yu 
332a1d2a633SQiang Yu 	dev->gp_version = gp_read(LIMA_GP_VERSION);
333a1d2a633SQiang Yu 
334a1d2a633SQiang Yu 	return 0;
335a1d2a633SQiang Yu }
336a1d2a633SQiang Yu 
lima_gp_fini(struct lima_ip * ip)337a1d2a633SQiang Yu void lima_gp_fini(struct lima_ip *ip)
338a1d2a633SQiang Yu {
33904d531b9SErico Nunes 	struct lima_device *dev = ip->dev;
340a1d2a633SQiang Yu 
34104d531b9SErico Nunes 	devm_free_irq(dev->dev, ip->irq, ip);
342a1d2a633SQiang Yu }
343a1d2a633SQiang Yu 
lima_gp_pipe_init(struct lima_device * dev)344a1d2a633SQiang Yu int lima_gp_pipe_init(struct lima_device *dev)
345a1d2a633SQiang Yu {
346a1d2a633SQiang Yu 	int frame_size = sizeof(struct drm_lima_gp_frame);
347a1d2a633SQiang Yu 	struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp;
348a1d2a633SQiang Yu 
349a1d2a633SQiang Yu 	if (!lima_gp_task_slab) {
350a1d2a633SQiang Yu 		lima_gp_task_slab = kmem_cache_create_usercopy(
351a1d2a633SQiang Yu 			"lima_gp_task", sizeof(struct lima_sched_task) + frame_size,
352a1d2a633SQiang Yu 			0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task),
353a1d2a633SQiang Yu 			frame_size, NULL);
354a1d2a633SQiang Yu 		if (!lima_gp_task_slab)
355a1d2a633SQiang Yu 			return -ENOMEM;
356a1d2a633SQiang Yu 	}
357a1d2a633SQiang Yu 	lima_gp_task_slab_refcnt++;
358a1d2a633SQiang Yu 
359a1d2a633SQiang Yu 	pipe->frame_size = frame_size;
360a1d2a633SQiang Yu 	pipe->task_slab = lima_gp_task_slab;
361a1d2a633SQiang Yu 
362a1d2a633SQiang Yu 	pipe->task_validate = lima_gp_task_validate;
363a1d2a633SQiang Yu 	pipe->task_run = lima_gp_task_run;
364a1d2a633SQiang Yu 	pipe->task_fini = lima_gp_task_fini;
365a1d2a633SQiang Yu 	pipe->task_error = lima_gp_task_error;
366a1d2a633SQiang Yu 	pipe->task_mmu_error = lima_gp_task_mmu_error;
3672081e8dcSQiang Yu 	pipe->task_recover = lima_gp_task_recover;
368022db5d6SErico Nunes 	pipe->task_mask_irq = lima_gp_task_mask_irq;
369a1d2a633SQiang Yu 
370a1d2a633SQiang Yu 	return 0;
371a1d2a633SQiang Yu }
372a1d2a633SQiang Yu 
lima_gp_pipe_fini(struct lima_device * dev)373a1d2a633SQiang Yu void lima_gp_pipe_fini(struct lima_device *dev)
374a1d2a633SQiang Yu {
375a1d2a633SQiang Yu 	if (!--lima_gp_task_slab_refcnt) {
376a1d2a633SQiang Yu 		kmem_cache_destroy(lima_gp_task_slab);
377a1d2a633SQiang Yu 		lima_gp_task_slab = NULL;
378a1d2a633SQiang Yu 	}
379a1d2a633SQiang Yu }
380