Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mixer_reg.c
Go to the documentation of this file.
1 /*
2  * Samsung TV Mixer driver
3  *
4  * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
5  *
6  * Tomasz Stanislawski, <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published
10  * by the Free Software Foundiation. either version 2 of the License,
11  * or (at your option) any later version
12  */
13 
14 #include "mixer.h"
15 #include "regs-mixer.h"
16 #include "regs-vp.h"
17 
18 #include <linux/delay.h>
19 
20 /* Register access subroutines */
21 
22 static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
23 {
24  return readl(mdev->res.vp_regs + reg_id);
25 }
26 
27 static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
28 {
29  writel(val, mdev->res.vp_regs + reg_id);
30 }
31 
32 static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
33  u32 val, u32 mask)
34 {
35  u32 old = vp_read(mdev, reg_id);
36 
37  val = (val & mask) | (old & ~mask);
38  writel(val, mdev->res.vp_regs + reg_id);
39 }
40 
41 static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
42 {
43  return readl(mdev->res.mxr_regs + reg_id);
44 }
45 
46 static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
47 {
48  writel(val, mdev->res.mxr_regs + reg_id);
49 }
50 
51 static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
52  u32 val, u32 mask)
53 {
54  u32 old = mxr_read(mdev, reg_id);
55 
56  val = (val & mask) | (old & ~mask);
57  writel(val, mdev->res.mxr_regs + reg_id);
58 }
59 
60 void mxr_vsync_set_update(struct mxr_device *mdev, int en)
61 {
62  /* block update on vsync */
63  mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
64  MXR_STATUS_SYNC_ENABLE);
65  vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
66 }
67 
68 static void __mxr_reg_vp_reset(struct mxr_device *mdev)
69 {
70  int tries = 100;
71 
72  vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
73  for (tries = 100; tries; --tries) {
74  /* waiting until VP_SRESET_PROCESSING is 0 */
75  if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
76  break;
77  mdelay(10);
78  }
79  WARN(tries == 0, "failed to reset Video Processor\n");
80 }
81 
82 static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
83 
84 void mxr_reg_reset(struct mxr_device *mdev)
85 {
86  unsigned long flags;
87  u32 val; /* value stored to register */
88 
89  spin_lock_irqsave(&mdev->reg_slock, flags);
91 
92  /* set output in RGB888 mode */
93  mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888);
94 
95  /* 16 beat burst in DMA */
96  mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
98 
99  /* setting default layer priority: layer1 > video > layer0
100  * because typical usage scenario would be
101  * layer0 - framebuffer
102  * video - video overlay
103  * layer1 - OSD
104  */
105  val = MXR_LAYER_CFG_GRP0_VAL(1);
106  val |= MXR_LAYER_CFG_VP_VAL(2);
107  val |= MXR_LAYER_CFG_GRP1_VAL(3);
108  mxr_write(mdev, MXR_LAYER_CFG, val);
109 
110  /* use dark gray background color */
111  mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
112  mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
113  mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
114 
115  /* setting graphical layers */
116 
117  val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
118  val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
119  val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
120 
121  /* the same configuration for both layers */
122  mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
123  mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
124 
125  /* configuration of Video Processor Registers */
126  __mxr_reg_vp_reset(mdev);
127  mxr_reg_vp_default_filter(mdev);
128 
129  /* enable all interrupts */
130  mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
131 
133  spin_unlock_irqrestore(&mdev->reg_slock, flags);
134 }
135 
136 void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
137  const struct mxr_format *fmt, const struct mxr_geometry *geo)
138 {
139  u32 val;
140  unsigned long flags;
141 
142  spin_lock_irqsave(&mdev->reg_slock, flags);
144 
145  /* setup format */
146  mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
148 
149  /* setup geometry */
150  mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
151  val = MXR_GRP_WH_WIDTH(geo->src.width);
152  val |= MXR_GRP_WH_HEIGHT(geo->src.height);
153  val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
154  val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
155  mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
156 
157  /* setup offsets in source image */
158  val = MXR_GRP_SXY_SX(geo->src.x_offset);
159  val |= MXR_GRP_SXY_SY(geo->src.y_offset);
160  mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
161 
162  /* setup offsets in display image */
163  val = MXR_GRP_DXY_DX(geo->dst.x_offset);
164  val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
165  mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
166 
168  spin_unlock_irqrestore(&mdev->reg_slock, flags);
169 }
170 
171 void mxr_reg_vp_format(struct mxr_device *mdev,
172  const struct mxr_format *fmt, const struct mxr_geometry *geo)
173 {
174  unsigned long flags;
175 
176  spin_lock_irqsave(&mdev->reg_slock, flags);
178 
179  vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
180 
181  /* setting size of input image */
182  vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
183  VP_IMG_VSIZE(geo->src.full_height));
184  /* chroma height has to reduced by 2 to avoid chroma distorions */
185  vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
186  VP_IMG_VSIZE(geo->src.full_height / 2));
187 
188  vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
189  vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
190  vp_write(mdev, VP_SRC_H_POSITION,
191  VP_SRC_H_POSITION_VAL(geo->src.x_offset));
192  vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
193 
194  vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
195  vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
196  if (geo->dst.field == V4L2_FIELD_INTERLACED) {
197  vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
198  vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
199  } else {
200  vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
201  vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
202  }
203 
204  vp_write(mdev, VP_H_RATIO, geo->x_ratio);
205  vp_write(mdev, VP_V_RATIO, geo->y_ratio);
206 
207  vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
208 
210  spin_unlock_irqrestore(&mdev->reg_slock, flags);
211 
212 }
213 
215 {
216  u32 val = addr ? ~0 : 0;
217  unsigned long flags;
218 
219  spin_lock_irqsave(&mdev->reg_slock, flags);
221 
222  if (idx == 0)
223  mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
224  else
225  mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
226  mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
227 
229  spin_unlock_irqrestore(&mdev->reg_slock, flags);
230 }
231 
232 void mxr_reg_vp_buffer(struct mxr_device *mdev,
233  dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
234 {
235  u32 val = luma_addr[0] ? ~0 : 0;
236  unsigned long flags;
237 
238  spin_lock_irqsave(&mdev->reg_slock, flags);
240 
241  mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
242  vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
243  /* TODO: fix tiled mode */
244  vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
245  vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
246  vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
247  vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
248 
250  spin_unlock_irqrestore(&mdev->reg_slock, flags);
251 }
252 
253 static void mxr_irq_layer_handle(struct mxr_layer *layer)
254 {
255  struct list_head *head = &layer->enq_list;
256  struct mxr_buffer *done;
257 
258  /* skip non-existing layer */
259  if (layer == NULL)
260  return;
261 
262  spin_lock(&layer->enq_slock);
263  if (layer->state == MXR_LAYER_IDLE)
264  goto done;
265 
266  done = layer->shadow_buf;
267  layer->shadow_buf = layer->update_buf;
268 
269  if (list_empty(head)) {
270  if (layer->state != MXR_LAYER_STREAMING)
271  layer->update_buf = NULL;
272  } else {
273  struct mxr_buffer *next;
274  next = list_first_entry(head, struct mxr_buffer, list);
275  list_del(&next->list);
276  layer->update_buf = next;
277  }
278 
279  layer->ops.buffer_set(layer, layer->update_buf);
280 
281  if (done && done != layer->shadow_buf)
283 
284 done:
285  spin_unlock(&layer->enq_slock);
286 }
287 
289 {
290  struct mxr_device *mdev = dev_data;
291  u32 i, val;
292 
293  spin_lock(&mdev->reg_slock);
294  val = mxr_read(mdev, MXR_INT_STATUS);
295 
296  /* wake up process waiting for VSYNC */
297  if (val & MXR_INT_STATUS_VSYNC) {
299  /* toggle TOP field event if working in interlaced mode */
300  if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE)
302  wake_up(&mdev->event_queue);
303  /* vsync interrupt use different bit for read and clear */
304  val &= ~MXR_INT_STATUS_VSYNC;
305  val |= MXR_INT_CLEAR_VSYNC;
306  }
307 
308  /* clear interrupts */
309  mxr_write(mdev, MXR_INT_STATUS, val);
310 
311  spin_unlock(&mdev->reg_slock);
312  /* leave on non-vsync event */
313  if (~val & MXR_INT_CLEAR_VSYNC)
314  return IRQ_HANDLED;
315  /* skip layer update on bottom field */
316  if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags))
317  return IRQ_HANDLED;
318  for (i = 0; i < MXR_MAX_LAYERS; ++i)
319  mxr_irq_layer_handle(mdev->layer[i]);
320  return IRQ_HANDLED;
321 }
322 
323 void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
324 {
325  u32 val;
326 
327  val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
328  mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
329 }
330 
331 void mxr_reg_streamon(struct mxr_device *mdev)
332 {
333  unsigned long flags;
334 
335  spin_lock_irqsave(&mdev->reg_slock, flags);
336  /* single write -> no need to block vsync update */
337 
338  /* start MIXER */
339  mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
341 
342  spin_unlock_irqrestore(&mdev->reg_slock, flags);
343 }
344 
345 void mxr_reg_streamoff(struct mxr_device *mdev)
346 {
347  unsigned long flags;
348 
349  spin_lock_irqsave(&mdev->reg_slock, flags);
350  /* single write -> no need to block vsync update */
351 
352  /* stop MIXER */
353  mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
354 
355  spin_unlock_irqrestore(&mdev->reg_slock, flags);
356 }
357 
359 {
360  int ret;
361 
363  /* TODO: consider adding interruptible */
364  ret = wait_event_timeout(mdev->event_queue,
366  msecs_to_jiffies(1000));
367  if (ret > 0)
368  return 0;
369  if (ret < 0)
370  return ret;
371  mxr_warn(mdev, "no vsync detected - timeout\n");
372  return -ETIME;
373 }
374 
376  struct v4l2_mbus_framefmt *fmt)
377 {
378  u32 val = 0;
379  unsigned long flags;
380 
381  spin_lock_irqsave(&mdev->reg_slock, flags);
383 
384  /* selecting colorspace accepted by output */
385  if (fmt->colorspace == V4L2_COLORSPACE_JPEG)
386  val |= MXR_CFG_OUT_YUV444;
387  else
388  val |= MXR_CFG_OUT_RGB888;
389 
390  /* choosing between interlace and progressive mode */
391  if (fmt->field == V4L2_FIELD_INTERLACED)
392  val |= MXR_CFG_SCAN_INTERLACE;
393  else
395 
396  /* choosing between porper HD and SD mode */
397  if (fmt->height == 480)
399  else if (fmt->height == 576)
401  else if (fmt->height == 720)
403  else if (fmt->height == 1080)
405  else
406  WARN(1, "unrecognized mbus height %u!\n", fmt->height);
407 
408  mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK |
410 
411  val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
412  vp_write_mask(mdev, VP_MODE, val,
414 
416  spin_unlock_irqrestore(&mdev->reg_slock, flags);
417 }
418 
419 void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
420 {
421  /* no extra actions need to be done */
422 }
423 
424 void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
425 {
426  /* no extra actions need to be done */
427 }
428 
429 static const u8 filter_y_horiz_tap8[] = {
430  0, -1, -1, -1, -1, -1, -1, -1,
431  -1, -1, -1, -1, -1, 0, 0, 0,
432  0, 2, 4, 5, 6, 6, 6, 6,
433  6, 5, 5, 4, 3, 2, 1, 1,
434  0, -6, -12, -16, -18, -20, -21, -20,
435  -20, -18, -16, -13, -10, -8, -5, -2,
436  127, 126, 125, 121, 114, 107, 99, 89,
437  79, 68, 57, 46, 35, 25, 16, 8,
438 };
439 
440 static const u8 filter_y_vert_tap4[] = {
441  0, -3, -6, -8, -8, -8, -8, -7,
442  -6, -5, -4, -3, -2, -1, -1, 0,
443  127, 126, 124, 118, 111, 102, 92, 81,
444  70, 59, 48, 37, 27, 19, 11, 5,
445  0, 5, 11, 19, 27, 37, 48, 59,
446  70, 81, 92, 102, 111, 118, 124, 126,
447  0, 0, -1, -1, -2, -3, -4, -5,
448  -6, -7, -8, -8, -8, -8, -6, -3,
449 };
450 
451 static const u8 filter_cr_horiz_tap4[] = {
452  0, -3, -6, -8, -8, -8, -8, -7,
453  -6, -5, -4, -3, -2, -1, -1, 0,
454  127, 126, 124, 118, 111, 102, 92, 81,
455  70, 59, 48, 37, 27, 19, 11, 5,
456 };
457 
458 static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
459  int reg_id, const u8 *data, unsigned int size)
460 {
461  /* assure 4-byte align */
462  BUG_ON(size & 3);
463  for (; size; size -= 4, reg_id += 4, data += 4) {
464  u32 val = (data[0] << 24) | (data[1] << 16) |
465  (data[2] << 8) | data[3];
466  vp_write(mdev, reg_id, val);
467  }
468 }
469 
470 static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
471 {
472  mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
473  filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
474  mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
475  filter_y_vert_tap4, sizeof filter_y_vert_tap4);
476  mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
477  filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
478 }
479 
480 static void mxr_reg_mxr_dump(struct mxr_device *mdev)
481 {
482 #define DUMPREG(reg_id) \
483 do { \
484  mxr_dbg(mdev, #reg_id " = %08x\n", \
485  (u32)readl(mdev->res.mxr_regs + reg_id)); \
486 } while (0)
487 
489  DUMPREG(MXR_CFG);
492 
495 
502 
509 #undef DUMPREG
510 }
511 
512 static void mxr_reg_vp_dump(struct mxr_device *mdev)
513 {
514 #define DUMPREG(reg_id) \
515 do { \
516  mxr_dbg(mdev, #reg_id " = %08x\n", \
517  (u32) readl(mdev->res.vp_regs + reg_id)); \
518 } while (0)
519 
520 
525  DUMPREG(VP_MODE);
544 
545 #undef DUMPREG
546 }
547 
548 void mxr_reg_dump(struct mxr_device *mdev)
549 {
550  mxr_reg_mxr_dump(mdev);
551  mxr_reg_vp_dump(mdev);
552 }
553