ipu-vdi.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (C) 2012-2016 Mentor Graphics Inc.
  3. * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <linux/io.h>
  16. #include "ipu-prv.h"
  17. struct ipu_vdi {
  18. void __iomem *base;
  19. u32 module;
  20. spinlock_t lock;
  21. int use_count;
  22. struct ipu_soc *ipu;
  23. };
  24. /* VDI Register Offsets */
  25. #define VDI_FSIZE 0x0000
  26. #define VDI_C 0x0004
  27. /* VDI Register Fields */
  28. #define VDI_C_CH_420 (0 << 1)
  29. #define VDI_C_CH_422 (1 << 1)
  30. #define VDI_C_MOT_SEL_MASK (0x3 << 2)
  31. #define VDI_C_MOT_SEL_FULL (2 << 2)
  32. #define VDI_C_MOT_SEL_LOW (1 << 2)
  33. #define VDI_C_MOT_SEL_MED (0 << 2)
  34. #define VDI_C_BURST_SIZE1_4 (3 << 4)
  35. #define VDI_C_BURST_SIZE2_4 (3 << 8)
  36. #define VDI_C_BURST_SIZE3_4 (3 << 12)
  37. #define VDI_C_BURST_SIZE_MASK 0xF
  38. #define VDI_C_BURST_SIZE1_OFFSET 4
  39. #define VDI_C_BURST_SIZE2_OFFSET 8
  40. #define VDI_C_BURST_SIZE3_OFFSET 12
  41. #define VDI_C_VWM1_SET_1 (0 << 16)
  42. #define VDI_C_VWM1_SET_2 (1 << 16)
  43. #define VDI_C_VWM1_CLR_2 (1 << 19)
  44. #define VDI_C_VWM3_SET_1 (0 << 22)
  45. #define VDI_C_VWM3_SET_2 (1 << 22)
  46. #define VDI_C_VWM3_CLR_2 (1 << 25)
  47. #define VDI_C_TOP_FIELD_MAN_1 (1 << 30)
  48. #define VDI_C_TOP_FIELD_AUTO_1 (1 << 31)
  49. static inline u32 ipu_vdi_read(struct ipu_vdi *vdi, unsigned int offset)
  50. {
  51. return readl(vdi->base + offset);
  52. }
  53. static inline void ipu_vdi_write(struct ipu_vdi *vdi, u32 value,
  54. unsigned int offset)
  55. {
  56. writel(value, vdi->base + offset);
  57. }
  58. void ipu_vdi_set_field_order(struct ipu_vdi *vdi, v4l2_std_id std, u32 field)
  59. {
  60. bool top_field_0 = false;
  61. unsigned long flags;
  62. u32 reg;
  63. switch (field) {
  64. case V4L2_FIELD_INTERLACED_TB:
  65. case V4L2_FIELD_SEQ_TB:
  66. case V4L2_FIELD_TOP:
  67. top_field_0 = true;
  68. break;
  69. case V4L2_FIELD_INTERLACED_BT:
  70. case V4L2_FIELD_SEQ_BT:
  71. case V4L2_FIELD_BOTTOM:
  72. top_field_0 = false;
  73. break;
  74. default:
  75. top_field_0 = (std & V4L2_STD_525_60) ? true : false;
  76. break;
  77. }
  78. spin_lock_irqsave(&vdi->lock, flags);
  79. reg = ipu_vdi_read(vdi, VDI_C);
  80. if (top_field_0)
  81. reg &= ~VDI_C_TOP_FIELD_MAN_1;
  82. else
  83. reg |= VDI_C_TOP_FIELD_MAN_1;
  84. ipu_vdi_write(vdi, reg, VDI_C);
  85. spin_unlock_irqrestore(&vdi->lock, flags);
  86. }
  87. EXPORT_SYMBOL_GPL(ipu_vdi_set_field_order);
  88. void ipu_vdi_set_motion(struct ipu_vdi *vdi, enum ipu_motion_sel motion_sel)
  89. {
  90. unsigned long flags;
  91. u32 reg;
  92. spin_lock_irqsave(&vdi->lock, flags);
  93. reg = ipu_vdi_read(vdi, VDI_C);
  94. reg &= ~VDI_C_MOT_SEL_MASK;
  95. switch (motion_sel) {
  96. case MED_MOTION:
  97. reg |= VDI_C_MOT_SEL_MED;
  98. break;
  99. case HIGH_MOTION:
  100. reg |= VDI_C_MOT_SEL_FULL;
  101. break;
  102. default:
  103. reg |= VDI_C_MOT_SEL_LOW;
  104. break;
  105. }
  106. ipu_vdi_write(vdi, reg, VDI_C);
  107. spin_unlock_irqrestore(&vdi->lock, flags);
  108. }
  109. EXPORT_SYMBOL_GPL(ipu_vdi_set_motion);
  110. void ipu_vdi_setup(struct ipu_vdi *vdi, u32 code, int xres, int yres)
  111. {
  112. unsigned long flags;
  113. u32 pixel_fmt, reg;
  114. spin_lock_irqsave(&vdi->lock, flags);
  115. reg = ((yres - 1) << 16) | (xres - 1);
  116. ipu_vdi_write(vdi, reg, VDI_FSIZE);
  117. /*
  118. * Full motion, only vertical filter is used.
  119. * Burst size is 4 accesses
  120. */
  121. if (code == MEDIA_BUS_FMT_UYVY8_2X8 ||
  122. code == MEDIA_BUS_FMT_UYVY8_1X16 ||
  123. code == MEDIA_BUS_FMT_YUYV8_2X8 ||
  124. code == MEDIA_BUS_FMT_YUYV8_1X16)
  125. pixel_fmt = VDI_C_CH_422;
  126. else
  127. pixel_fmt = VDI_C_CH_420;
  128. reg = ipu_vdi_read(vdi, VDI_C);
  129. reg |= pixel_fmt;
  130. reg |= VDI_C_BURST_SIZE2_4;
  131. reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_CLR_2;
  132. reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_CLR_2;
  133. ipu_vdi_write(vdi, reg, VDI_C);
  134. spin_unlock_irqrestore(&vdi->lock, flags);
  135. }
  136. EXPORT_SYMBOL_GPL(ipu_vdi_setup);
  137. void ipu_vdi_unsetup(struct ipu_vdi *vdi)
  138. {
  139. unsigned long flags;
  140. spin_lock_irqsave(&vdi->lock, flags);
  141. ipu_vdi_write(vdi, 0, VDI_FSIZE);
  142. ipu_vdi_write(vdi, 0, VDI_C);
  143. spin_unlock_irqrestore(&vdi->lock, flags);
  144. }
  145. EXPORT_SYMBOL_GPL(ipu_vdi_unsetup);
  146. int ipu_vdi_enable(struct ipu_vdi *vdi)
  147. {
  148. unsigned long flags;
  149. spin_lock_irqsave(&vdi->lock, flags);
  150. if (!vdi->use_count)
  151. ipu_module_enable(vdi->ipu, vdi->module);
  152. vdi->use_count++;
  153. spin_unlock_irqrestore(&vdi->lock, flags);
  154. return 0;
  155. }
  156. EXPORT_SYMBOL_GPL(ipu_vdi_enable);
  157. int ipu_vdi_disable(struct ipu_vdi *vdi)
  158. {
  159. unsigned long flags;
  160. spin_lock_irqsave(&vdi->lock, flags);
  161. if (vdi->use_count) {
  162. if (!--vdi->use_count)
  163. ipu_module_disable(vdi->ipu, vdi->module);
  164. }
  165. spin_unlock_irqrestore(&vdi->lock, flags);
  166. return 0;
  167. }
  168. EXPORT_SYMBOL_GPL(ipu_vdi_disable);
  169. struct ipu_vdi *ipu_vdi_get(struct ipu_soc *ipu)
  170. {
  171. return ipu->vdi_priv;
  172. }
  173. EXPORT_SYMBOL_GPL(ipu_vdi_get);
  174. void ipu_vdi_put(struct ipu_vdi *vdi)
  175. {
  176. }
  177. EXPORT_SYMBOL_GPL(ipu_vdi_put);
  178. int ipu_vdi_init(struct ipu_soc *ipu, struct device *dev,
  179. unsigned long base, u32 module)
  180. {
  181. struct ipu_vdi *vdi;
  182. vdi = devm_kzalloc(dev, sizeof(*vdi), GFP_KERNEL);
  183. if (!vdi)
  184. return -ENOMEM;
  185. ipu->vdi_priv = vdi;
  186. spin_lock_init(&vdi->lock);
  187. vdi->module = module;
  188. vdi->base = devm_ioremap(dev, base, PAGE_SIZE);
  189. if (!vdi->base)
  190. return -ENOMEM;
  191. dev_dbg(dev, "VDI base: 0x%08lx remapped to %p\n", base, vdi->base);
  192. vdi->ipu = ipu;
  193. return 0;
  194. }
  195. void ipu_vdi_exit(struct ipu_soc *ipu)
  196. {
  197. }