2 * Copyright (C) 2010-2013 Freescale Semiconductor, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Based on STMP378X PxP driver
21 * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
24 #include <linux/dma-mapping.h>
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/mutex.h>
31 #include <linux/platform_device.h>
32 #include <linux/slab.h>
33 #include <linux/vmalloc.h>
34 #include <linux/dmaengine.h>
35 #include <linux/pxp_dma.h>
36 #include <linux/timer.h>
37 #include <linux/clk.h>
38 #include <linux/workqueue.h>
39 #include <linux/sched.h>
41 #include <linux/kthread.h>
43 #include "regs-pxp_v2.h"
45 #define PXP_DOWNSCALE_THRESHOLD 0x4000
47 static LIST_HEAD(head);
48 static int timeout_in_ms = 600;
49 static unsigned int block_size;
50 static struct kmem_cache *tx_desc_cache;
53 struct dma_device dma;
57 struct platform_device *pdev;
60 int irq; /* PXP IRQ to the CPU */
63 struct mutex clk_mutex;
65 #define CLK_STAT_OFF 0
71 struct pxp_dma pxp_dma;
72 struct pxp_channel channel[NR_PXP_VIRT_CHANNEL];
73 struct work_struct work;
75 /* describes most recent processing configuration */
76 struct pxp_config_data pxp_conf_state;
78 /* to turn clock off when pxp is inactive */
79 struct timer_list clk_timer;
81 /* for pxp config dispatch asynchronously*/
82 struct task_struct *dispatch;
83 wait_queue_head_t thread_waitq;
84 struct completion complete;
87 #define to_pxp_dma(d) container_of(d, struct pxp_dma, dma)
88 #define to_tx_desc(tx) container_of(tx, struct pxp_tx_desc, txd)
89 #define to_pxp_channel(d) container_of(d, struct pxp_channel, dma_chan)
90 #define to_pxp(id) container_of(id, struct pxps, pxp_dma)
92 #define PXP_DEF_BUFS 2
95 static uint32_t pxp_s0_formats[] = {
104 * PXP common functions
106 static void dump_pxp_reg(struct pxps *pxp)
108 dev_dbg(pxp->dev, "PXP_CTRL 0x%x",
109 __raw_readl(pxp->base + HW_PXP_CTRL));
110 dev_dbg(pxp->dev, "PXP_STAT 0x%x",
111 __raw_readl(pxp->base + HW_PXP_STAT));
112 dev_dbg(pxp->dev, "PXP_OUT_CTRL 0x%x",
113 __raw_readl(pxp->base + HW_PXP_OUT_CTRL));
114 dev_dbg(pxp->dev, "PXP_OUT_BUF 0x%x",
115 __raw_readl(pxp->base + HW_PXP_OUT_BUF));
116 dev_dbg(pxp->dev, "PXP_OUT_BUF2 0x%x",
117 __raw_readl(pxp->base + HW_PXP_OUT_BUF2));
118 dev_dbg(pxp->dev, "PXP_OUT_PITCH 0x%x",
119 __raw_readl(pxp->base + HW_PXP_OUT_PITCH));
120 dev_dbg(pxp->dev, "PXP_OUT_LRC 0x%x",
121 __raw_readl(pxp->base + HW_PXP_OUT_LRC));
122 dev_dbg(pxp->dev, "PXP_OUT_PS_ULC 0x%x",
123 __raw_readl(pxp->base + HW_PXP_OUT_PS_ULC));
124 dev_dbg(pxp->dev, "PXP_OUT_PS_LRC 0x%x",
125 __raw_readl(pxp->base + HW_PXP_OUT_PS_LRC));
126 dev_dbg(pxp->dev, "PXP_OUT_AS_ULC 0x%x",
127 __raw_readl(pxp->base + HW_PXP_OUT_AS_ULC));
128 dev_dbg(pxp->dev, "PXP_OUT_AS_LRC 0x%x",
129 __raw_readl(pxp->base + HW_PXP_OUT_AS_LRC));
130 dev_dbg(pxp->dev, "PXP_PS_CTRL 0x%x",
131 __raw_readl(pxp->base + HW_PXP_PS_CTRL));
132 dev_dbg(pxp->dev, "PXP_PS_BUF 0x%x",
133 __raw_readl(pxp->base + HW_PXP_PS_BUF));
134 dev_dbg(pxp->dev, "PXP_PS_UBUF 0x%x",
135 __raw_readl(pxp->base + HW_PXP_PS_UBUF));
136 dev_dbg(pxp->dev, "PXP_PS_VBUF 0x%x",
137 __raw_readl(pxp->base + HW_PXP_PS_VBUF));
138 dev_dbg(pxp->dev, "PXP_PS_PITCH 0x%x",
139 __raw_readl(pxp->base + HW_PXP_PS_PITCH));
140 dev_dbg(pxp->dev, "PXP_PS_BACKGROUND 0x%x",
141 __raw_readl(pxp->base + HW_PXP_PS_BACKGROUND));
142 dev_dbg(pxp->dev, "PXP_PS_SCALE 0x%x",
143 __raw_readl(pxp->base + HW_PXP_PS_SCALE));
144 dev_dbg(pxp->dev, "PXP_PS_OFFSET 0x%x",
145 __raw_readl(pxp->base + HW_PXP_PS_OFFSET));
146 dev_dbg(pxp->dev, "PXP_PS_CLRKEYLOW 0x%x",
147 __raw_readl(pxp->base + HW_PXP_PS_CLRKEYLOW));
148 dev_dbg(pxp->dev, "PXP_PS_CLRKEYHIGH 0x%x",
149 __raw_readl(pxp->base + HW_PXP_PS_CLRKEYHIGH));
150 dev_dbg(pxp->dev, "PXP_AS_CTRL 0x%x",
151 __raw_readl(pxp->base + HW_PXP_AS_CTRL));
152 dev_dbg(pxp->dev, "PXP_AS_BUF 0x%x",
153 __raw_readl(pxp->base + HW_PXP_AS_BUF));
154 dev_dbg(pxp->dev, "PXP_AS_PITCH 0x%x",
155 __raw_readl(pxp->base + HW_PXP_AS_PITCH));
156 dev_dbg(pxp->dev, "PXP_AS_CLRKEYLOW 0x%x",
157 __raw_readl(pxp->base + HW_PXP_AS_CLRKEYLOW));
158 dev_dbg(pxp->dev, "PXP_AS_CLRKEYHIGH 0x%x",
159 __raw_readl(pxp->base + HW_PXP_AS_CLRKEYHIGH));
160 dev_dbg(pxp->dev, "PXP_CSC1_COEF0 0x%x",
161 __raw_readl(pxp->base + HW_PXP_CSC1_COEF0));
162 dev_dbg(pxp->dev, "PXP_CSC1_COEF1 0x%x",
163 __raw_readl(pxp->base + HW_PXP_CSC1_COEF1));
164 dev_dbg(pxp->dev, "PXP_CSC1_COEF2 0x%x",
165 __raw_readl(pxp->base + HW_PXP_CSC1_COEF2));
166 dev_dbg(pxp->dev, "PXP_CSC2_CTRL 0x%x",
167 __raw_readl(pxp->base + HW_PXP_CSC2_CTRL));
168 dev_dbg(pxp->dev, "PXP_CSC2_COEF0 0x%x",
169 __raw_readl(pxp->base + HW_PXP_CSC2_COEF0));
170 dev_dbg(pxp->dev, "PXP_CSC2_COEF1 0x%x",
171 __raw_readl(pxp->base + HW_PXP_CSC2_COEF1));
172 dev_dbg(pxp->dev, "PXP_CSC2_COEF2 0x%x",
173 __raw_readl(pxp->base + HW_PXP_CSC2_COEF2));
174 dev_dbg(pxp->dev, "PXP_CSC2_COEF3 0x%x",
175 __raw_readl(pxp->base + HW_PXP_CSC2_COEF3));
176 dev_dbg(pxp->dev, "PXP_CSC2_COEF4 0x%x",
177 __raw_readl(pxp->base + HW_PXP_CSC2_COEF4));
178 dev_dbg(pxp->dev, "PXP_CSC2_COEF5 0x%x",
179 __raw_readl(pxp->base + HW_PXP_CSC2_COEF5));
180 dev_dbg(pxp->dev, "PXP_LUT_CTRL 0x%x",
181 __raw_readl(pxp->base + HW_PXP_LUT_CTRL));
182 dev_dbg(pxp->dev, "PXP_LUT_ADDR 0x%x",
183 __raw_readl(pxp->base + HW_PXP_LUT_ADDR));
184 dev_dbg(pxp->dev, "PXP_LUT_DATA 0x%x",
185 __raw_readl(pxp->base + HW_PXP_LUT_DATA));
186 dev_dbg(pxp->dev, "PXP_LUT_EXTMEM 0x%x",
187 __raw_readl(pxp->base + HW_PXP_LUT_EXTMEM));
188 dev_dbg(pxp->dev, "PXP_CFA 0x%x",
189 __raw_readl(pxp->base + HW_PXP_CFA));
190 dev_dbg(pxp->dev, "PXP_HIST_CTRL 0x%x",
191 __raw_readl(pxp->base + HW_PXP_HIST_CTRL));
192 dev_dbg(pxp->dev, "PXP_HIST2_PARAM 0x%x",
193 __raw_readl(pxp->base + HW_PXP_HIST2_PARAM));
194 dev_dbg(pxp->dev, "PXP_HIST4_PARAM 0x%x",
195 __raw_readl(pxp->base + HW_PXP_HIST4_PARAM));
196 dev_dbg(pxp->dev, "PXP_HIST8_PARAM0 0x%x",
197 __raw_readl(pxp->base + HW_PXP_HIST8_PARAM0));
198 dev_dbg(pxp->dev, "PXP_HIST8_PARAM1 0x%x",
199 __raw_readl(pxp->base + HW_PXP_HIST8_PARAM1));
200 dev_dbg(pxp->dev, "PXP_HIST16_PARAM0 0x%x",
201 __raw_readl(pxp->base + HW_PXP_HIST16_PARAM0));
202 dev_dbg(pxp->dev, "PXP_HIST16_PARAM1 0x%x",
203 __raw_readl(pxp->base + HW_PXP_HIST16_PARAM1));
204 dev_dbg(pxp->dev, "PXP_HIST16_PARAM2 0x%x",
205 __raw_readl(pxp->base + HW_PXP_HIST16_PARAM2));
206 dev_dbg(pxp->dev, "PXP_HIST16_PARAM3 0x%x",
207 __raw_readl(pxp->base + HW_PXP_HIST16_PARAM3));
208 dev_dbg(pxp->dev, "PXP_POWER 0x%x",
209 __raw_readl(pxp->base + HW_PXP_POWER));
210 dev_dbg(pxp->dev, "PXP_NEXT 0x%x",
211 __raw_readl(pxp->base + HW_PXP_NEXT));
212 dev_dbg(pxp->dev, "PXP_DEBUGCTRL 0x%x",
213 __raw_readl(pxp->base + HW_PXP_DEBUGCTRL));
214 dev_dbg(pxp->dev, "PXP_DEBUG 0x%x",
215 __raw_readl(pxp->base + HW_PXP_DEBUG));
216 dev_dbg(pxp->dev, "PXP_VERSION 0x%x",
217 __raw_readl(pxp->base + HW_PXP_VERSION));
220 static bool is_yuv(u32 pix_fmt)
222 if ((pix_fmt == PXP_PIX_FMT_YUYV) |
223 (pix_fmt == PXP_PIX_FMT_UYVY) |
224 (pix_fmt == PXP_PIX_FMT_YVYU) |
225 (pix_fmt == PXP_PIX_FMT_VYUY) |
226 (pix_fmt == PXP_PIX_FMT_Y41P) |
227 (pix_fmt == PXP_PIX_FMT_YUV444) |
228 (pix_fmt == PXP_PIX_FMT_NV12) |
229 (pix_fmt == PXP_PIX_FMT_NV16) |
230 (pix_fmt == PXP_PIX_FMT_NV61) |
231 (pix_fmt == PXP_PIX_FMT_GREY) |
232 (pix_fmt == PXP_PIX_FMT_GY04) |
233 (pix_fmt == PXP_PIX_FMT_YVU410P) |
234 (pix_fmt == PXP_PIX_FMT_YUV410P) |
235 (pix_fmt == PXP_PIX_FMT_YVU420P) |
236 (pix_fmt == PXP_PIX_FMT_YUV420P) |
237 (pix_fmt == PXP_PIX_FMT_YUV420P2) |
238 (pix_fmt == PXP_PIX_FMT_YVU422P) |
239 (pix_fmt == PXP_PIX_FMT_YUV422P)) {
246 static void pxp_set_ctrl(struct pxps *pxp)
248 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
249 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
252 int need_swap = 0; /* to support YUYV and YVYU formats */
254 /* Configure S0 input format */
255 switch (pxp_conf->s0_param.pixel_fmt) {
256 case PXP_PIX_FMT_RGB32:
257 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB888;
259 case PXP_PIX_FMT_RGB565:
260 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB565;
262 case PXP_PIX_FMT_RGB555:
263 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB555;
265 case PXP_PIX_FMT_YUV420P:
266 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
268 case PXP_PIX_FMT_YVU420P:
269 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
271 case PXP_PIX_FMT_GREY:
272 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y8;
274 case PXP_PIX_FMT_GY04:
275 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y4;
277 case PXP_PIX_FMT_YUV422P:
278 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422;
280 case PXP_PIX_FMT_UYVY:
281 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
283 case PXP_PIX_FMT_YUYV:
284 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
287 case PXP_PIX_FMT_VYUY:
288 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
290 case PXP_PIX_FMT_YVYU:
291 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
294 case PXP_PIX_FMT_NV12:
295 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P420;
297 case PXP_PIX_FMT_NV21:
298 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P420;
300 case PXP_PIX_FMT_NV16:
301 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P422;
303 case PXP_PIX_FMT_NV61:
304 fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P422;
310 ctrl = BF_PXP_PS_CTRL_FORMAT(fmt_ctrl) | BF_PXP_PS_CTRL_SWAP(need_swap);
311 __raw_writel(ctrl, pxp->base + HW_PXP_PS_CTRL_SET);
313 /* Configure output format based on out_channel format */
314 switch (pxp_conf->out_param.pixel_fmt) {
315 case PXP_PIX_FMT_RGB32:
316 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888;
318 case PXP_PIX_FMT_BGRA32:
319 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
321 case PXP_PIX_FMT_RGB24:
322 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888P;
324 case PXP_PIX_FMT_RGB565:
325 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB565;
327 case PXP_PIX_FMT_RGB555:
328 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB555;
330 case PXP_PIX_FMT_GREY:
331 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y8;
333 case PXP_PIX_FMT_GY04:
334 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y4;
336 case PXP_PIX_FMT_UYVY:
337 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
339 case PXP_PIX_FMT_VYUY:
340 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
342 case PXP_PIX_FMT_NV12:
343 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
345 case PXP_PIX_FMT_NV21:
346 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
348 case PXP_PIX_FMT_NV16:
349 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
351 case PXP_PIX_FMT_NV61:
352 fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
358 ctrl = BF_PXP_OUT_CTRL_FORMAT(fmt_ctrl);
359 __raw_writel(ctrl, pxp->base + HW_PXP_OUT_CTRL);
362 if (proc_data->scaling)
364 if (proc_data->vflip)
365 ctrl |= BM_PXP_CTRL_VFLIP;
366 if (proc_data->hflip)
367 ctrl |= BM_PXP_CTRL_HFLIP;
368 if (proc_data->rotate) {
369 ctrl |= BF_PXP_CTRL_ROTATE(proc_data->rotate / 90);
370 if (proc_data->rot_pos)
371 ctrl |= BM_PXP_CTRL_ROT_POS;
374 /* In default, the block size is set to 8x8
375 * But block size can be set to 16x16 due to
376 * blocksize variable modification
378 ctrl |= block_size << 23;
380 __raw_writel(ctrl, pxp->base + HW_PXP_CTRL);
383 static int pxp_start(struct pxps *pxp)
385 __raw_writel(BM_PXP_CTRL_IRQ_ENABLE, pxp->base + HW_PXP_CTRL_SET);
386 __raw_writel(BM_PXP_CTRL_ENABLE, pxp->base + HW_PXP_CTRL_SET);
392 static void pxp_set_outbuf(struct pxps *pxp)
394 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
395 struct pxp_layer_param *out_params = &pxp_conf->out_param;
397 __raw_writel(out_params->paddr, pxp->base + HW_PXP_OUT_BUF);
399 __raw_writel(BF_PXP_OUT_LRC_X(out_params->width - 1) |
400 BF_PXP_OUT_LRC_Y(out_params->height - 1),
401 pxp->base + HW_PXP_OUT_LRC);
403 if (out_params->pixel_fmt == PXP_PIX_FMT_RGB24) {
404 __raw_writel(out_params->stride * 3,
405 pxp->base + HW_PXP_OUT_PITCH);
406 } else if (out_params->pixel_fmt == PXP_PIX_FMT_BGRA32 ||
407 out_params->pixel_fmt == PXP_PIX_FMT_RGB32) {
408 __raw_writel(out_params->stride << 2,
409 pxp->base + HW_PXP_OUT_PITCH);
410 } else if (out_params->pixel_fmt == PXP_PIX_FMT_RGB565) {
411 __raw_writel(out_params->stride << 1,
412 pxp->base + HW_PXP_OUT_PITCH);
413 } else if (out_params->pixel_fmt == PXP_PIX_FMT_UYVY ||
414 (out_params->pixel_fmt == PXP_PIX_FMT_VYUY)) {
415 __raw_writel(out_params->stride << 1,
416 pxp->base + HW_PXP_OUT_PITCH);
417 } else if (out_params->pixel_fmt == PXP_PIX_FMT_GREY ||
418 out_params->pixel_fmt == PXP_PIX_FMT_NV12 ||
419 out_params->pixel_fmt == PXP_PIX_FMT_NV21 ||
420 out_params->pixel_fmt == PXP_PIX_FMT_NV16 ||
421 out_params->pixel_fmt == PXP_PIX_FMT_NV61) {
422 __raw_writel(out_params->stride,
423 pxp->base + HW_PXP_OUT_PITCH);
424 } else if (out_params->pixel_fmt == PXP_PIX_FMT_GY04) {
425 __raw_writel(out_params->stride >> 1,
426 pxp->base + HW_PXP_OUT_PITCH);
428 __raw_writel(0, pxp->base + HW_PXP_OUT_PITCH);
431 /* set global alpha if necessary */
432 if (out_params->global_alpha_enable) {
433 __raw_writel(out_params->global_alpha << 24,
434 pxp->base + HW_PXP_OUT_CTRL_SET);
435 __raw_writel(BM_PXP_OUT_CTRL_ALPHA_OUTPUT,
436 pxp->base + HW_PXP_OUT_CTRL_SET);
440 static void pxp_set_s0colorkey(struct pxps *pxp)
442 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
443 struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
445 /* Low and high are set equal. V4L does not allow a chromakey range */
446 if (s0_params->color_key_enable == 0 || s0_params->color_key == -1) {
447 /* disable color key */
448 __raw_writel(0xFFFFFF, pxp->base + HW_PXP_PS_CLRKEYLOW);
449 __raw_writel(0, pxp->base + HW_PXP_PS_CLRKEYHIGH);
451 __raw_writel(s0_params->color_key,
452 pxp->base + HW_PXP_PS_CLRKEYLOW);
453 __raw_writel(s0_params->color_key,
454 pxp->base + HW_PXP_PS_CLRKEYHIGH);
458 static void pxp_set_olcolorkey(int layer_no, struct pxps *pxp)
460 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
461 struct pxp_layer_param *ol_params = &pxp_conf->ol_param[layer_no];
463 /* Low and high are set equal. V4L does not allow a chromakey range */
464 if (ol_params->color_key_enable != 0 && ol_params->color_key != -1) {
465 __raw_writel(ol_params->color_key,
466 pxp->base + HW_PXP_AS_CLRKEYLOW);
467 __raw_writel(ol_params->color_key,
468 pxp->base + HW_PXP_AS_CLRKEYHIGH);
470 /* disable color key */
471 __raw_writel(0xFFFFFF, pxp->base + HW_PXP_AS_CLRKEYLOW);
472 __raw_writel(0, pxp->base + HW_PXP_AS_CLRKEYHIGH);
476 static void pxp_set_oln(int layer_no, struct pxps *pxp)
478 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
479 struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no];
480 dma_addr_t phys_addr = olparams_data->paddr;
481 u32 pitch = olparams_data->stride ? olparams_data->stride :
482 olparams_data->width;
484 __raw_writel(phys_addr, pxp->base + HW_PXP_AS_BUF);
487 if (olparams_data->width == 0 && olparams_data->height == 0) {
488 __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_AS_ULC);
489 __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_LRC);
491 __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_ULC);
492 if (pxp_conf->proc_data.rotate == 90 ||
493 pxp_conf->proc_data.rotate == 270) {
494 if (pxp_conf->proc_data.rot_pos == 1) {
495 __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->height - 1) |
496 BF_PXP_OUT_AS_LRC_Y(olparams_data->width - 1),
497 pxp->base + HW_PXP_OUT_AS_LRC);
499 __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width - 1) |
500 BF_PXP_OUT_AS_LRC_Y(olparams_data->height - 1),
501 pxp->base + HW_PXP_OUT_AS_LRC);
504 __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width - 1) |
505 BF_PXP_OUT_AS_LRC_Y(olparams_data->height - 1),
506 pxp->base + HW_PXP_OUT_AS_LRC);
510 if ((olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) |
511 (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB32)) {
512 __raw_writel(pitch << 2,
513 pxp->base + HW_PXP_AS_PITCH);
514 } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) {
515 __raw_writel(pitch << 1,
516 pxp->base + HW_PXP_AS_PITCH);
518 __raw_writel(0, pxp->base + HW_PXP_AS_PITCH);
522 static void pxp_set_olparam(int layer_no, struct pxps *pxp)
524 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
525 struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no];
528 olparam = BF_PXP_AS_CTRL_ALPHA(olparams_data->global_alpha);
529 if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB32) {
531 BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB888);
532 } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) {
534 BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__ARGB8888);
535 if (!olparams_data->combine_enable) {
537 BF_PXP_AS_CTRL_ALPHA_CTRL
538 (BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs);
539 olparam |= 0x3 << 16;
541 } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) {
543 BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB565);
545 if (olparams_data->global_alpha_enable) {
546 if (olparams_data->global_override) {
548 BF_PXP_AS_CTRL_ALPHA_CTRL
549 (BV_PXP_AS_CTRL_ALPHA_CTRL__Override);
552 BF_PXP_AS_CTRL_ALPHA_CTRL
553 (BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply);
555 if (olparams_data->alpha_invert)
556 olparam |= BM_PXP_AS_CTRL_ALPHA_INVERT;
558 if (olparams_data->color_key_enable)
559 olparam |= BM_PXP_AS_CTRL_ENABLE_COLORKEY;
561 __raw_writel(olparam, pxp->base + HW_PXP_AS_CTRL);
564 static void pxp_set_s0param(struct pxps *pxp)
566 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
567 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
570 /* contains the coordinate for the PS in the OUTPUT buffer. */
571 if ((pxp_conf->s0_param).width == 0 &&
572 (pxp_conf->s0_param).height == 0) {
573 __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_PS_ULC);
574 __raw_writel(0x0, pxp->base + HW_PXP_OUT_PS_LRC);
576 s0param = BF_PXP_OUT_PS_ULC_X(proc_data->drect.left);
577 s0param |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.top);
578 __raw_writel(s0param, pxp->base + HW_PXP_OUT_PS_ULC);
579 s0param = BF_PXP_OUT_PS_LRC_X(proc_data->drect.left +
580 proc_data->drect.width - 1);
581 s0param |= BF_PXP_OUT_PS_LRC_Y(proc_data->drect.top +
582 proc_data->drect.height - 1);
583 __raw_writel(s0param, pxp->base + HW_PXP_OUT_PS_LRC);
587 /* crop behavior is re-designed in h/w. */
588 static void pxp_set_s0crop(struct pxps *pxp)
591 * place-holder, it's implemented in other functions in this driver.
592 * Refer to "Clipping source images" section in RM for detail.
596 static int pxp_set_scaling(struct pxps *pxp)
599 u32 xscale, yscale, s0scale;
600 u32 decx, decy, xdec = 0, ydec = 0;
601 struct pxp_proc_data *proc_data = &pxp->pxp_conf_state.proc_data;
603 if (((proc_data->srect.width == proc_data->drect.width) &&
604 (proc_data->srect.height == proc_data->drect.height)) ||
605 ((proc_data->srect.width == 0) && (proc_data->srect.height == 0))) {
606 proc_data->scaling = 0;
607 __raw_writel(0x10001000, pxp->base + HW_PXP_PS_SCALE);
608 __raw_writel(0, pxp->base + HW_PXP_PS_CTRL);
612 proc_data->scaling = 1;
613 decx = proc_data->srect.width / proc_data->drect.width;
614 decy = proc_data->srect.height / proc_data->drect.height;
616 if (decx >= 2 && decx < 4) {
619 } else if (decx >= 4 && decx < 8) {
622 } else if (decx >= 8) {
626 xscale = proc_data->srect.width * 0x1000 /
627 (proc_data->drect.width * decx);
629 xscale = proc_data->srect.width * 0x1000 /
630 proc_data->drect.width;
632 if (decy >= 2 && decy < 4) {
635 } else if (decy >= 4 && decy < 8) {
638 } else if (decy >= 8) {
642 yscale = proc_data->srect.height * 0x1000 /
643 (proc_data->drect.height * decy);
645 yscale = proc_data->srect.height * 0x1000 /
646 proc_data->drect.height;
648 __raw_writel((xdec << 10) | (ydec << 8), pxp->base + HW_PXP_PS_CTRL);
650 if (xscale > PXP_DOWNSCALE_THRESHOLD)
651 xscale = PXP_DOWNSCALE_THRESHOLD;
652 if (yscale > PXP_DOWNSCALE_THRESHOLD)
653 yscale = PXP_DOWNSCALE_THRESHOLD;
654 s0scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
655 BF_PXP_PS_SCALE_XSCALE(xscale);
656 __raw_writel(s0scale, pxp->base + HW_PXP_PS_SCALE);
664 static void pxp_set_bg(struct pxps *pxp)
666 __raw_writel(pxp->pxp_conf_state.proc_data.bgcolor,
667 pxp->base + HW_PXP_PS_BACKGROUND);
670 static void pxp_set_lut(struct pxps *pxp)
672 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
673 int lut_op = pxp_conf->proc_data.lut_transform;
676 bool use_cmap = (lut_op & PXP_LUT_USE_CMAP) ? true : false;
677 u8 *cmap = pxp_conf->proc_data.lut_map;
683 * If LUT already configured as needed, return...
684 * Unless CMAP is needed and it has been updated.
686 if ((pxp->lut_state == lut_op) &&
687 !(use_cmap && pxp_conf->proc_data.lut_map_updated))
690 if (lut_op == PXP_LUT_NONE) {
691 __raw_writel(BM_PXP_LUT_CTRL_BYPASS,
692 pxp->base + HW_PXP_LUT_CTRL);
693 } else if (((lut_op & PXP_LUT_INVERT) != 0)
694 && ((lut_op & PXP_LUT_BLACK_WHITE) != 0)) {
695 /* Fill out LUT table with inverted monochromized values */
697 /* clear bypass bit, set lookup mode & out mode */
698 __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
699 (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
700 BF_PXP_LUT_CTRL_OUT_MODE
701 (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
702 pxp->base + HW_PXP_LUT_CTRL);
704 /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
705 __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
707 /* LUT address pointer auto-increments after each data write */
708 for (pix_val = 0; pix_val < 256; pix_val += 4) {
709 for (i = 0; i < 4; i++) {
710 entry_src = use_cmap ?
711 cmap[pix_val + i] : pix_val + i;
712 entry[i] = (entry_src < 0x80) ? 0xFF : 0x00;
714 reg_val = (entry[3] << 24) | (entry[2] << 16) |
715 (entry[1] << 8) | entry[0];
716 __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
718 } else if ((lut_op & PXP_LUT_INVERT) != 0) {
719 /* Fill out LUT table with 8-bit inverted values */
721 /* clear bypass bit, set lookup mode & out mode */
722 __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
723 (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
724 BF_PXP_LUT_CTRL_OUT_MODE
725 (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
726 pxp->base + HW_PXP_LUT_CTRL);
728 /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
729 __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
731 /* LUT address pointer auto-increments after each data write */
732 for (pix_val = 0; pix_val < 256; pix_val += 4) {
733 for (i = 0; i < 4; i++) {
734 entry_src = use_cmap ?
735 cmap[pix_val + i] : pix_val + i;
736 entry[i] = ~entry_src & 0xFF;
738 reg_val = (entry[3] << 24) | (entry[2] << 16) |
739 (entry[1] << 8) | entry[0];
740 __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
742 } else if ((lut_op & PXP_LUT_BLACK_WHITE) != 0) {
743 /* Fill out LUT table with 8-bit monochromized values */
745 /* clear bypass bit, set lookup mode & out mode */
746 __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
747 (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
748 BF_PXP_LUT_CTRL_OUT_MODE
749 (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
750 pxp->base + HW_PXP_LUT_CTRL);
752 /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
753 __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
755 /* LUT address pointer auto-increments after each data write */
756 for (pix_val = 0; pix_val < 256; pix_val += 4) {
757 for (i = 0; i < 4; i++) {
758 entry_src = use_cmap ?
759 cmap[pix_val + i] : pix_val + i;
760 entry[i] = (entry_src < 0x80) ? 0x00 : 0xFF;
762 reg_val = (entry[3] << 24) | (entry[2] << 16) |
763 (entry[1] << 8) | entry[0];
764 __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
766 } else if (use_cmap) {
767 /* Fill out LUT table using colormap values */
769 /* clear bypass bit, set lookup mode & out mode */
770 __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
771 (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
772 BF_PXP_LUT_CTRL_OUT_MODE
773 (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
774 pxp->base + HW_PXP_LUT_CTRL);
776 /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
777 __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
779 /* LUT address pointer auto-increments after each data write */
780 for (pix_val = 0; pix_val < 256; pix_val += 4) {
781 for (i = 0; i < 4; i++)
782 entry[i] = cmap[pix_val + i];
783 reg_val = (entry[3] << 24) | (entry[2] << 16) |
784 (entry[1] << 8) | entry[0];
785 __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
789 pxp->lut_state = lut_op;
792 static void pxp_set_csc(struct pxps *pxp)
794 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
795 struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
796 struct pxp_layer_param *ol_params = &pxp_conf->ol_param[0];
797 struct pxp_layer_param *out_params = &pxp_conf->out_param;
799 bool input_is_YUV = is_yuv(s0_params->pixel_fmt);
800 bool output_is_YUV = is_yuv(out_params->pixel_fmt);
802 if (input_is_YUV && output_is_YUV) {
804 * Input = YUV, Output = YUV
805 * No CSC unless we need to do combining
807 if (ol_params->combine_enable) {
808 /* Must convert to RGB for combining with RGB overlay */
810 /* CSC1 - YUV->RGB */
811 __raw_writel(0x04030000, pxp->base + HW_PXP_CSC1_COEF0);
812 __raw_writel(0x01230208, pxp->base + HW_PXP_CSC1_COEF1);
813 __raw_writel(0x076b079c, pxp->base + HW_PXP_CSC1_COEF2);
815 /* CSC2 - RGB->YUV */
816 __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL);
817 __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0);
818 __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1);
819 __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2);
820 __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3);
821 __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4);
822 __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5);
824 /* Input & Output both YUV, so bypass both CSCs */
827 __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
830 __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
832 } else if (input_is_YUV && !output_is_YUV) {
834 * Input = YUV, Output = RGB
835 * Use CSC1 to convert to RGB
838 /* CSC1 - YUV->RGB */
839 __raw_writel(0x84ab01f0, pxp->base + HW_PXP_CSC1_COEF0);
840 __raw_writel(0x01980204, pxp->base + HW_PXP_CSC1_COEF1);
841 __raw_writel(0x0730079c, pxp->base + HW_PXP_CSC1_COEF2);
844 __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
845 } else if (!input_is_YUV && output_is_YUV) {
847 * Input = RGB, Output = YUV
848 * Use CSC2 to convert to YUV
852 __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
854 /* CSC2 - RGB->YUV */
855 __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL);
856 __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0);
857 __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1);
858 __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2);
859 __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3);
860 __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4);
861 __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5);
864 * Input = RGB, Output = RGB
865 * Input & Output both RGB, so bypass both CSCs
869 __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
872 __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
875 /* YCrCb colorspace */
876 /* Not sure when we use this...no YCrCb formats are defined for PxP */
878 __raw_writel(0x84ab01f0, HW_PXP_CSCCOEFF0_ADDR);
879 __raw_writel(0x01230204, HW_PXP_CSCCOEFF1_ADDR);
880 __raw_writel(0x0730079c, HW_PXP_CSCCOEFF2_ADDR);
885 static void pxp_set_s0buf(struct pxps *pxp)
887 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
888 struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
889 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
891 dma_addr_t Y1, U1, V1;
893 u32 pitch = s0_params->stride ? s0_params->stride :
896 Y = s0_params->paddr;
898 if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB565)
900 else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB32)
902 offset = (proc_data->srect.top * s0_params->width +
903 proc_data->srect.left) * bpp;
904 /* clipping or cropping */
906 __raw_writel(Y1, pxp->base + HW_PXP_PS_BUF);
907 if ((s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P) ||
908 (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) ||
909 (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) ||
910 (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P)) {
911 /* Set to 1 if YUV format is 4:2:2 rather than 4:2:0 */
913 if (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P)
916 offset = proc_data->srect.top * s0_params->width / 4 +
917 proc_data->srect.left / 2;
918 U = Y + (s0_params->width * s0_params->height);
920 V = U + ((s0_params->width * s0_params->height) >> s);
922 if (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) {
923 __raw_writel(V1, pxp->base + HW_PXP_PS_UBUF);
924 __raw_writel(U1, pxp->base + HW_PXP_PS_VBUF);
926 __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF);
927 __raw_writel(V1, pxp->base + HW_PXP_PS_VBUF);
929 } else if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV12) ||
930 (s0_params->pixel_fmt == PXP_PIX_FMT_NV21) ||
931 (s0_params->pixel_fmt == PXP_PIX_FMT_NV16) ||
932 (s0_params->pixel_fmt == PXP_PIX_FMT_NV61)) {
934 if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV16) ||
935 (s0_params->pixel_fmt == PXP_PIX_FMT_NV61))
938 offset = (proc_data->srect.top * s0_params->width +
939 proc_data->srect.left) / s;
940 U = Y + (s0_params->width * s0_params->height);
943 __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF);
946 /* TODO: only support RGB565, Y8, Y4, YUV420 */
947 if (s0_params->pixel_fmt == PXP_PIX_FMT_GREY ||
948 s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P ||
949 s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P ||
950 s0_params->pixel_fmt == PXP_PIX_FMT_NV12 ||
951 s0_params->pixel_fmt == PXP_PIX_FMT_NV21 ||
952 s0_params->pixel_fmt == PXP_PIX_FMT_NV16 ||
953 s0_params->pixel_fmt == PXP_PIX_FMT_NV61 ||
954 s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P) {
955 __raw_writel(pitch, pxp->base + HW_PXP_PS_PITCH);
957 else if (s0_params->pixel_fmt == PXP_PIX_FMT_GY04)
958 __raw_writel(pitch >> 1,
959 pxp->base + HW_PXP_PS_PITCH);
960 else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB32)
961 __raw_writel(pitch << 2,
962 pxp->base + HW_PXP_PS_PITCH);
963 else if (s0_params->pixel_fmt == PXP_PIX_FMT_UYVY ||
964 s0_params->pixel_fmt == PXP_PIX_FMT_YUYV ||
965 s0_params->pixel_fmt == PXP_PIX_FMT_VYUY ||
966 s0_params->pixel_fmt == PXP_PIX_FMT_YVYU)
967 __raw_writel(pitch << 1,
968 pxp->base + HW_PXP_PS_PITCH);
969 else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB565)
970 __raw_writel(pitch << 1,
971 pxp->base + HW_PXP_PS_PITCH);
973 __raw_writel(0, pxp->base + HW_PXP_PS_PITCH);
977 * pxp_config() - configure PxP for a processing task
978 * @pxps: PXP context.
979 * @pxp_chan: PXP channel.
980 * @return: 0 on success or negative error code on failure.
982 static int pxp_config(struct pxps *pxp, struct pxp_channel *pxp_chan)
984 struct pxp_config_data *pxp_conf_data = &pxp->pxp_conf_state;
988 /* Configure PxP regs */
990 pxp_set_s0param(pxp);
992 pxp_set_scaling(pxp);
993 ol_nr = pxp_conf_data->layer_nr - 2;
995 i = pxp_conf_data->layer_nr - 2 - ol_nr;
997 pxp_set_olparam(i, pxp);
998 /* only the color key in higher overlay will take effect. */
999 pxp_set_olcolorkey(i, pxp);
1002 pxp_set_s0colorkey(pxp);
1008 pxp_set_outbuf(pxp);
1013 static void pxp_clk_enable(struct pxps *pxp)
1015 mutex_lock(&pxp->clk_mutex);
1017 if (pxp->clk_stat == CLK_STAT_ON) {
1018 mutex_unlock(&pxp->clk_mutex);
1022 clk_prepare_enable(pxp->clk);
1023 pxp->clk_stat = CLK_STAT_ON;
1025 mutex_unlock(&pxp->clk_mutex);
1028 static void pxp_clk_disable(struct pxps *pxp)
1030 unsigned long flags;
1032 mutex_lock(&pxp->clk_mutex);
1034 if (pxp->clk_stat == CLK_STAT_OFF) {
1035 mutex_unlock(&pxp->clk_mutex);
1039 spin_lock_irqsave(&pxp->lock, flags);
1040 if ((pxp->pxp_ongoing == 0) && list_empty(&head)) {
1041 spin_unlock_irqrestore(&pxp->lock, flags);
1042 clk_disable_unprepare(pxp->clk);
1043 pxp->clk_stat = CLK_STAT_OFF;
1045 spin_unlock_irqrestore(&pxp->lock, flags);
1047 mutex_unlock(&pxp->clk_mutex);
1050 static inline void clkoff_callback(struct work_struct *w)
1052 struct pxps *pxp = container_of(w, struct pxps, work);
1054 pxp_clk_disable(pxp);
1057 static void pxp_clkoff_timer(unsigned long arg)
1059 struct pxps *pxp = (struct pxps *)arg;
1061 if ((pxp->pxp_ongoing == 0) && list_empty(&head))
1062 schedule_work(&pxp->work);
1064 mod_timer(&pxp->clk_timer,
1065 jiffies + msecs_to_jiffies(timeout_in_ms));
1068 static struct pxp_tx_desc *pxpdma_first_queued(struct pxp_channel *pxp_chan)
1070 return list_entry(pxp_chan->queue.next, struct pxp_tx_desc, list);
1073 /* called with pxp_chan->lock held */
1074 static void __pxpdma_dostart(struct pxp_channel *pxp_chan)
1076 struct pxp_dma *pxp_dma = to_pxp_dma(pxp_chan->dma_chan.device);
1077 struct pxps *pxp = to_pxp(pxp_dma);
1078 struct pxp_tx_desc *desc;
1079 struct pxp_tx_desc *child;
1083 desc = list_first_entry(&head, struct pxp_tx_desc, list);
1084 memcpy(&pxp->pxp_conf_state.s0_param,
1085 &desc->layer_param.s0_param, sizeof(struct pxp_layer_param));
1086 memcpy(&pxp->pxp_conf_state.proc_data,
1087 &desc->proc_data, sizeof(struct pxp_proc_data));
1089 /* Save PxP configuration */
1090 list_for_each_entry(child, &desc->tx_list, list) {
1091 if (i == 0) { /* Output */
1092 memcpy(&pxp->pxp_conf_state.out_param,
1093 &child->layer_param.out_param,
1094 sizeof(struct pxp_layer_param));
1095 } else { /* Overlay */
1096 memcpy(&pxp->pxp_conf_state.ol_param[i - 1],
1097 &child->layer_param.ol_param,
1098 sizeof(struct pxp_layer_param));
1103 pr_debug("%s:%d S0 w/h %d/%d paddr %08x\n", __func__, __LINE__,
1104 pxp->pxp_conf_state.s0_param.width,
1105 pxp->pxp_conf_state.s0_param.height,
1106 pxp->pxp_conf_state.s0_param.paddr);
1107 pr_debug("%s:%d OUT w/h %d/%d paddr %08x\n", __func__, __LINE__,
1108 pxp->pxp_conf_state.out_param.width,
1109 pxp->pxp_conf_state.out_param.height,
1110 pxp->pxp_conf_state.out_param.paddr);
1113 static void pxpdma_dostart_work(struct pxps *pxp)
1115 struct pxp_channel *pxp_chan = NULL;
1116 unsigned long flags;
1117 struct pxp_tx_desc *desc = NULL;
1119 spin_lock_irqsave(&pxp->lock, flags);
1121 desc = list_entry(head.next, struct pxp_tx_desc, list);
1122 pxp_chan = to_pxp_channel(desc->txd.chan);
1124 __pxpdma_dostart(pxp_chan);
1127 pxp_config(pxp, pxp_chan);
1131 spin_unlock_irqrestore(&pxp->lock, flags);
1134 static void pxpdma_dequeue(struct pxp_channel *pxp_chan, struct pxps *pxp)
1136 unsigned long flags;
1137 struct pxp_tx_desc *desc = NULL;
1140 desc = pxpdma_first_queued(pxp_chan);
1141 spin_lock_irqsave(&pxp->lock, flags);
1142 list_move_tail(&desc->list, &head);
1143 spin_unlock_irqrestore(&pxp->lock, flags);
1144 } while (!list_empty(&pxp_chan->queue));
1147 static dma_cookie_t pxp_tx_submit(struct dma_async_tx_descriptor *tx)
1149 struct pxp_tx_desc *desc = to_tx_desc(tx);
1150 struct pxp_channel *pxp_chan = to_pxp_channel(tx->chan);
1151 dma_cookie_t cookie;
1153 dev_dbg(&pxp_chan->dma_chan.dev->device, "received TX\n");
1155 /* pxp_chan->lock can be taken under ichan->lock, but not v.v. */
1156 spin_lock(&pxp_chan->lock);
1158 cookie = pxp_chan->dma_chan.cookie;
1163 /* from dmaengine.h: "last cookie value returned to client" */
1164 pxp_chan->dma_chan.cookie = cookie;
1165 tx->cookie = cookie;
1167 /* Here we add the tx descriptor to our PxP task queue. */
1168 list_add_tail(&desc->list, &pxp_chan->queue);
1170 spin_unlock(&pxp_chan->lock);
1172 dev_dbg(&pxp_chan->dma_chan.dev->device, "done TX\n");
1178 * pxp_init_channel() - initialize a PXP channel.
1179 * @pxp_dma: PXP DMA context.
1180 * @pchan: pointer to the channel object.
1181 * @return 0 on success or negative error code on failure.
1183 static int pxp_init_channel(struct pxp_dma *pxp_dma,
1184 struct pxp_channel *pxp_chan)
1189 * We are using _virtual_ channel here.
1190 * Each channel contains all parameters of corresponding layers
1191 * for one transaction; each layer is represented as one descriptor
1192 * (i.e., pxp_tx_desc) here.
1195 INIT_LIST_HEAD(&pxp_chan->queue);
1200 static irqreturn_t pxp_irq(int irq, void *dev_id)
1202 struct pxps *pxp = dev_id;
1203 struct pxp_channel *pxp_chan;
1204 struct pxp_tx_desc *desc;
1205 struct pxp_tx_desc *child, *_child;
1206 dma_async_tx_callback callback;
1207 void *callback_param;
1208 unsigned long flags;
1214 __raw_readl(pxp->base + HW_PXP_HIST_CTRL) & BM_PXP_HIST_CTRL_STATUS;
1216 __raw_writel(BM_PXP_STAT_IRQ, pxp->base + HW_PXP_STAT_CLR);
1218 spin_lock_irqsave(&pxp->lock, flags);
1220 if (list_empty(&head)) {
1221 pxp->pxp_ongoing = 0;
1222 spin_unlock_irqrestore(&pxp->lock, flags);
1226 /* Get descriptor and call callback */
1227 desc = list_entry(head.next, struct pxp_tx_desc, list);
1228 pxp_chan = to_pxp_channel(desc->txd.chan);
1230 pxp_chan->completed = desc->txd.cookie;
1232 callback = desc->txd.callback;
1233 callback_param = desc->txd.callback_param;
1235 /* Send histogram status back to caller */
1236 desc->hist_status = hist_status;
1238 if ((desc->txd.flags & DMA_PREP_INTERRUPT) && callback)
1239 callback(callback_param);
1241 pxp_chan->status = PXP_CHANNEL_INITIALIZED;
1243 list_for_each_entry_safe(child, _child, &desc->tx_list, list) {
1244 list_del_init(&child->list);
1245 kmem_cache_free(tx_desc_cache, (void *)child);
1247 list_del_init(&desc->list);
1248 kmem_cache_free(tx_desc_cache, (void *)desc);
1250 complete(&pxp->complete);
1251 pxp->pxp_ongoing = 0;
1252 mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms));
1254 spin_unlock_irqrestore(&pxp->lock, flags);
1259 /* allocate/free dma tx descriptor dynamically*/
1260 static struct pxp_tx_desc *pxpdma_desc_alloc(struct pxp_channel *pxp_chan)
1262 struct pxp_tx_desc *desc = NULL;
1263 struct dma_async_tx_descriptor *txd = NULL;
1265 desc = kmem_cache_alloc(tx_desc_cache, GFP_KERNEL | __GFP_ZERO);
1269 INIT_LIST_HEAD(&desc->list);
1270 INIT_LIST_HEAD(&desc->tx_list);
1272 dma_async_tx_descriptor_init(txd, &pxp_chan->dma_chan);
1273 txd->tx_submit = pxp_tx_submit;
1278 /* Allocate and initialise a transfer descriptor. */
1279 static struct dma_async_tx_descriptor *pxp_prep_slave_sg(struct dma_chan *chan,
1282 unsigned int sg_len,
1284 dma_transfer_direction
1286 unsigned long tx_flags,
1289 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1290 struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
1291 struct pxps *pxp = to_pxp(pxp_dma);
1292 struct pxp_tx_desc *desc = NULL;
1293 struct pxp_tx_desc *first = NULL, *prev = NULL;
1294 struct scatterlist *sg;
1295 dma_addr_t phys_addr;
1298 if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) {
1299 dev_err(chan->device->dev, "Invalid DMA direction %d!\n",
1304 if (unlikely(sg_len < 2))
1307 for_each_sg(sgl, sg, sg_len, i) {
1308 desc = pxpdma_desc_alloc(pxp_chan);
1310 dev_err(chan->device->dev, "no enough memory to allocate tx descriptor\n");
1314 phys_addr = sg_dma_address(sg);
1319 desc->layer_param.s0_param.paddr = phys_addr;
1321 list_add_tail(&desc->list, &first->tx_list);
1326 desc->layer_param.out_param.paddr = phys_addr;
1328 desc->layer_param.ol_param.paddr = phys_addr;
1334 pxp->pxp_conf_state.layer_nr = sg_len;
1335 first->txd.flags = tx_flags;
1336 first->len = sg_len;
1337 pr_debug("%s:%d first %p, first->len %d, flags %08x\n",
1338 __func__, __LINE__, first, first->len, first->txd.flags);
1343 static void pxp_issue_pending(struct dma_chan *chan)
1345 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1346 struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
1347 struct pxps *pxp = to_pxp(pxp_dma);
1349 spin_lock(&pxp_chan->lock);
1351 if (list_empty(&pxp_chan->queue)) {
1352 spin_unlock(&pxp_chan->lock);
1356 pxpdma_dequeue(pxp_chan, pxp);
1357 pxp_chan->status = PXP_CHANNEL_READY;
1359 spin_unlock(&pxp_chan->lock);
1361 pxp_clk_enable(pxp);
1362 wake_up_interruptible(&pxp->thread_waitq);
1365 static void __pxp_terminate_all(struct dma_chan *chan)
1367 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1369 pxp_chan->status = PXP_CHANNEL_INITIALIZED;
1372 static int pxp_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
1375 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1377 /* Only supports DMA_TERMINATE_ALL */
1378 if (cmd != DMA_TERMINATE_ALL)
1381 spin_lock(&pxp_chan->lock);
1382 __pxp_terminate_all(chan);
1383 spin_unlock(&pxp_chan->lock);
1388 static int pxp_alloc_chan_resources(struct dma_chan *chan)
1390 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1391 struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
1394 /* dmaengine.c now guarantees to only offer free channels */
1395 BUG_ON(chan->client_count > 1);
1396 WARN_ON(pxp_chan->status != PXP_CHANNEL_FREE);
1399 pxp_chan->completed = -ENXIO;
1401 pr_debug("%s dma_chan.chan_id %d\n", __func__, chan->chan_id);
1402 ret = pxp_init_channel(pxp_dma, pxp_chan);
1406 pxp_chan->status = PXP_CHANNEL_INITIALIZED;
1408 dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n",
1409 chan->chan_id, pxp_chan->eof_irq);
1417 static void pxp_free_chan_resources(struct dma_chan *chan)
1419 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1421 spin_lock(&pxp_chan->lock);
1423 __pxp_terminate_all(chan);
1425 pxp_chan->status = PXP_CHANNEL_FREE;
1427 spin_unlock(&pxp_chan->lock);
1430 static enum dma_status pxp_tx_status(struct dma_chan *chan,
1431 dma_cookie_t cookie,
1432 struct dma_tx_state *txstate)
1434 struct pxp_channel *pxp_chan = to_pxp_channel(chan);
1436 if (cookie != chan->cookie)
1440 txstate->last = pxp_chan->completed;
1441 txstate->used = chan->cookie;
1442 txstate->residue = 0;
1447 static int pxp_hw_init(struct pxps *pxp)
1449 struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
1450 struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
1453 /* Pull PxP out of reset */
1454 __raw_writel(0, pxp->base + HW_PXP_CTRL);
1456 /* Config defaults */
1458 /* Initialize non-channel-specific PxP parameters */
1459 proc_data->drect.left = proc_data->srect.left = 0;
1460 proc_data->drect.top = proc_data->srect.top = 0;
1461 proc_data->drect.width = proc_data->srect.width = 0;
1462 proc_data->drect.height = proc_data->srect.height = 0;
1463 proc_data->scaling = 0;
1464 proc_data->hflip = 0;
1465 proc_data->vflip = 0;
1466 proc_data->rotate = 0;
1467 proc_data->bgcolor = 0;
1469 /* Initialize S0 channel parameters */
1470 pxp_conf->s0_param.pixel_fmt = pxp_s0_formats[0];
1471 pxp_conf->s0_param.width = 0;
1472 pxp_conf->s0_param.height = 0;
1473 pxp_conf->s0_param.color_key = -1;
1474 pxp_conf->s0_param.color_key_enable = false;
1476 /* Initialize OL channel parameters */
1477 pxp_conf->ol_param[0].combine_enable = false;
1478 pxp_conf->ol_param[0].width = 0;
1479 pxp_conf->ol_param[0].height = 0;
1480 pxp_conf->ol_param[0].pixel_fmt = PXP_PIX_FMT_RGB565;
1481 pxp_conf->ol_param[0].color_key_enable = false;
1482 pxp_conf->ol_param[0].color_key = -1;
1483 pxp_conf->ol_param[0].global_alpha_enable = false;
1484 pxp_conf->ol_param[0].global_alpha = 0;
1485 pxp_conf->ol_param[0].local_alpha_enable = false;
1487 /* Initialize Output channel parameters */
1488 pxp_conf->out_param.width = 0;
1489 pxp_conf->out_param.height = 0;
1490 pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
1492 proc_data->overlay_state = 0;
1494 /* Write default h/w config */
1496 pxp_set_s0param(pxp);
1497 pxp_set_s0crop(pxp);
1499 * simply program the ULC to a higher value than the LRC
1500 * to avoid any AS pixels to show up in the output buffer.
1502 __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_OUT_AS_ULC);
1503 pxp_set_olparam(0, pxp);
1504 pxp_set_olcolorkey(0, pxp);
1506 pxp_set_s0colorkey(pxp);
1511 /* One-time histogram configuration */
1513 BF_PXP_HIST_CTRL_PANEL_MODE(BV_PXP_HIST_CTRL_PANEL_MODE__GRAY16);
1514 __raw_writel(reg_val, pxp->base + HW_PXP_HIST_CTRL);
1516 reg_val = BF_PXP_HIST2_PARAM_VALUE0(0x00) |
1517 BF_PXP_HIST2_PARAM_VALUE1(0x00F);
1518 __raw_writel(reg_val, pxp->base + HW_PXP_HIST2_PARAM);
1520 reg_val = BF_PXP_HIST4_PARAM_VALUE0(0x00) |
1521 BF_PXP_HIST4_PARAM_VALUE1(0x05) |
1522 BF_PXP_HIST4_PARAM_VALUE2(0x0A) | BF_PXP_HIST4_PARAM_VALUE3(0x0F);
1523 __raw_writel(reg_val, pxp->base + HW_PXP_HIST4_PARAM);
1525 reg_val = BF_PXP_HIST8_PARAM0_VALUE0(0x00) |
1526 BF_PXP_HIST8_PARAM0_VALUE1(0x02) |
1527 BF_PXP_HIST8_PARAM0_VALUE2(0x04) | BF_PXP_HIST8_PARAM0_VALUE3(0x06);
1528 __raw_writel(reg_val, pxp->base + HW_PXP_HIST8_PARAM0);
1529 reg_val = BF_PXP_HIST8_PARAM1_VALUE4(0x09) |
1530 BF_PXP_HIST8_PARAM1_VALUE5(0x0B) |
1531 BF_PXP_HIST8_PARAM1_VALUE6(0x0D) | BF_PXP_HIST8_PARAM1_VALUE7(0x0F);
1532 __raw_writel(reg_val, pxp->base + HW_PXP_HIST8_PARAM1);
1534 reg_val = BF_PXP_HIST16_PARAM0_VALUE0(0x00) |
1535 BF_PXP_HIST16_PARAM0_VALUE1(0x01) |
1536 BF_PXP_HIST16_PARAM0_VALUE2(0x02) |
1537 BF_PXP_HIST16_PARAM0_VALUE3(0x03);
1538 __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM0);
1539 reg_val = BF_PXP_HIST16_PARAM1_VALUE4(0x04) |
1540 BF_PXP_HIST16_PARAM1_VALUE5(0x05) |
1541 BF_PXP_HIST16_PARAM1_VALUE6(0x06) |
1542 BF_PXP_HIST16_PARAM1_VALUE7(0x07);
1543 __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM1);
1544 reg_val = BF_PXP_HIST16_PARAM2_VALUE8(0x08) |
1545 BF_PXP_HIST16_PARAM2_VALUE9(0x09) |
1546 BF_PXP_HIST16_PARAM2_VALUE10(0x0A) |
1547 BF_PXP_HIST16_PARAM2_VALUE11(0x0B);
1548 __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM2);
1549 reg_val = BF_PXP_HIST16_PARAM3_VALUE12(0x0C) |
1550 BF_PXP_HIST16_PARAM3_VALUE13(0x0D) |
1551 BF_PXP_HIST16_PARAM3_VALUE14(0x0E) |
1552 BF_PXP_HIST16_PARAM3_VALUE15(0x0F);
1553 __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM3);
1558 static int pxp_dma_init(struct pxps *pxp)
1560 struct pxp_dma *pxp_dma = &pxp->pxp_dma;
1561 struct dma_device *dma = &pxp_dma->dma;
1564 dma_cap_set(DMA_SLAVE, dma->cap_mask);
1565 dma_cap_set(DMA_PRIVATE, dma->cap_mask);
1567 /* Compulsory common fields */
1568 dma->dev = pxp->dev;
1569 dma->device_alloc_chan_resources = pxp_alloc_chan_resources;
1570 dma->device_free_chan_resources = pxp_free_chan_resources;
1571 dma->device_tx_status = pxp_tx_status;
1572 dma->device_issue_pending = pxp_issue_pending;
1574 /* Compulsory for DMA_SLAVE fields */
1575 dma->device_prep_slave_sg = pxp_prep_slave_sg;
1576 dma->device_control = pxp_control;
1578 /* Initialize PxP Channels */
1579 INIT_LIST_HEAD(&dma->channels);
1580 for (i = 0; i < NR_PXP_VIRT_CHANNEL; i++) {
1581 struct pxp_channel *pxp_chan = pxp->channel + i;
1582 struct dma_chan *dma_chan = &pxp_chan->dma_chan;
1584 spin_lock_init(&pxp_chan->lock);
1586 /* Only one EOF IRQ for PxP, shared by all channels */
1587 pxp_chan->eof_irq = pxp->irq;
1588 pxp_chan->status = PXP_CHANNEL_FREE;
1589 pxp_chan->completed = -ENXIO;
1590 snprintf(pxp_chan->eof_name, sizeof(pxp_chan->eof_name),
1593 dma_chan->device = &pxp_dma->dma;
1594 dma_chan->cookie = 1;
1595 dma_chan->chan_id = i;
1596 list_add_tail(&dma_chan->device_node, &dma->channels);
1599 return dma_async_device_register(&pxp_dma->dma);
1602 static ssize_t clk_off_timeout_show(struct device *dev,
1603 struct device_attribute *attr, char *buf)
1605 return sprintf(buf, "%d\n", timeout_in_ms);
1608 static ssize_t clk_off_timeout_store(struct device *dev,
1609 struct device_attribute *attr,
1610 const char *buf, size_t count)
1613 if (sscanf(buf, "%d", &val) > 0) {
1614 timeout_in_ms = val;
1620 static DEVICE_ATTR(clk_off_timeout, 0644, clk_off_timeout_show,
1621 clk_off_timeout_store);
1623 static ssize_t block_size_show(struct device *dev,
1624 struct device_attribute *attr,
1627 return sprintf(buf, "%d\n", block_size);
1630 static ssize_t block_size_store(struct device *dev,
1631 struct device_attribute *attr,
1632 const char *buf, size_t count)
1636 block_size = simple_strtoul(buf, last, 0);
1642 static DEVICE_ATTR(block_size, S_IWUSR | S_IRUGO,
1643 block_size_show, block_size_store);
1645 static const struct of_device_id imx_pxpdma_dt_ids[] = {
1646 { .compatible = "fsl,imx6dl-pxp-dma", },
1649 MODULE_DEVICE_TABLE(of, imx_pxpdma_dt_ids);
1651 static int has_pending_task(struct pxps *pxp, struct pxp_channel *task)
1654 unsigned long flags;
1656 spin_lock_irqsave(&pxp->lock, flags);
1657 found = !list_empty(&head);
1658 spin_unlock_irqrestore(&pxp->lock, flags);
1663 static int pxp_dispatch_thread(void *argv)
1665 struct pxps *pxp = (struct pxps *)argv;
1666 struct pxp_channel *pending = NULL;
1667 unsigned long flags;
1669 while (!kthread_should_stop()) {
1671 ret = wait_event_interruptible(pxp->thread_waitq,
1672 has_pending_task(pxp, pending));
1673 if (signal_pending(current))
1676 spin_lock_irqsave(&pxp->lock, flags);
1677 pxp->pxp_ongoing = 1;
1678 spin_unlock_irqrestore(&pxp->lock, flags);
1679 init_completion(&pxp->complete);
1680 pxpdma_dostart_work(pxp);
1681 ret = wait_for_completion_timeout(&pxp->complete, 2 * HZ);
1683 printk(KERN_EMERG "%s: task is timeout\n\n", __func__);
1691 static int pxp_probe(struct platform_device *pdev)
1694 struct resource *res;
1698 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1699 irq = platform_get_irq(pdev, 0);
1700 if (!res || irq < 0) {
1705 pxp = devm_kzalloc(&pdev->dev, sizeof(*pxp), GFP_KERNEL);
1707 dev_err(&pdev->dev, "failed to allocate control object\n");
1712 pxp->dev = &pdev->dev;
1714 platform_set_drvdata(pdev, pxp);
1717 pxp->pxp_ongoing = 0;
1720 spin_lock_init(&pxp->lock);
1721 mutex_init(&pxp->clk_mutex);
1723 pxp->base = devm_request_and_ioremap(&pdev->dev, res);
1724 if (pxp->base == NULL) {
1725 dev_err(&pdev->dev, "Couldn't ioremap regs\n");
1732 pxp->clk = devm_clk_get(&pdev->dev, "pxp-axi");
1733 clk_prepare_enable(pxp->clk);
1735 err = pxp_hw_init(pxp);
1736 clk_disable_unprepare(pxp->clk);
1738 dev_err(&pdev->dev, "failed to initialize hardware\n");
1742 err = devm_request_irq(&pdev->dev, pxp->irq, pxp_irq, 0,
1743 "pxp-dmaengine", pxp);
1746 /* Initialize DMA engine */
1747 err = pxp_dma_init(pxp);
1751 if (device_create_file(&pdev->dev, &dev_attr_clk_off_timeout)) {
1753 "Unable to create file from clk_off_timeout\n");
1757 device_create_file(&pdev->dev, &dev_attr_block_size);
1760 INIT_WORK(&pxp->work, clkoff_callback);
1761 init_timer(&pxp->clk_timer);
1762 pxp->clk_timer.function = pxp_clkoff_timer;
1763 pxp->clk_timer.data = (unsigned long)pxp;
1765 /* allocate a kernel thread to dispatch pxp conf */
1766 pxp->dispatch = kthread_run(pxp_dispatch_thread, pxp, "pxp_dispatch");
1767 if (IS_ERR(pxp->dispatch)) {
1768 err = PTR_ERR(pxp->dispatch);
1771 init_waitqueue_head(&pxp->thread_waitq);
1772 tx_desc_cache = kmem_cache_create("tx_desc", sizeof(struct pxp_tx_desc),
1773 0, SLAB_HWCACHE_ALIGN, NULL);
1774 if (!tx_desc_cache) {
1779 register_pxp_device();
1783 dev_err(&pdev->dev, "Exiting (unsuccessfully) pxp_probe()\n");
1787 static int pxp_remove(struct platform_device *pdev)
1789 struct pxps *pxp = platform_get_drvdata(pdev);
1791 unregister_pxp_device();
1792 kmem_cache_destroy(tx_desc_cache);
1793 kthread_stop(pxp->dispatch);
1794 cancel_work_sync(&pxp->work);
1795 del_timer_sync(&pxp->clk_timer);
1796 clk_disable_unprepare(pxp->clk);
1797 device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout);
1798 device_remove_file(&pdev->dev, &dev_attr_block_size);
1799 dma_async_device_unregister(&(pxp->pxp_dma.dma));
1805 static int pxp_suspend(struct platform_device *pdev, pm_message_t state)
1807 struct pxps *pxp = platform_get_drvdata(pdev);
1809 pxp_clk_enable(pxp);
1810 while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE)
1813 __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL);
1814 pxp_clk_disable(pxp);
1819 static int pxp_resume(struct platform_device *pdev)
1821 struct pxps *pxp = platform_get_drvdata(pdev);
1823 pxp_clk_enable(pxp);
1824 /* Pull PxP out of reset */
1825 __raw_writel(0, pxp->base + HW_PXP_CTRL);
1826 pxp_clk_disable(pxp);
1831 #define pxp_suspend NULL
1832 #define pxp_resume NULL
1835 static struct platform_driver pxp_driver = {
1838 .of_match_table = of_match_ptr(imx_pxpdma_dt_ids),
1841 .remove = pxp_remove,
1842 .suspend = pxp_suspend,
1843 .resume = pxp_resume,
1846 module_platform_driver(pxp_driver);
1849 MODULE_DESCRIPTION("i.MX PxP driver");
1850 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1851 MODULE_LICENSE("GPL");