fimc-lite-reg.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
  3. *
  4. * Copyright (C) 2012 Samsung Electronics Co., Ltd.
  5. * Sylwester Nawrocki <s.nawrocki@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/io.h>
  12. #include <linux/delay.h>
  13. #include <media/s5p_fimc.h>
  14. #include "fimc-lite-reg.h"
  15. #include "fimc-lite.h"
  16. #include "fimc-core.h"
  17. #define FLITE_RESET_TIMEOUT 50 /* in ms */
  18. void flite_hw_reset(struct fimc_lite *dev)
  19. {
  20. unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
  21. u32 cfg;
  22. cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  23. cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
  24. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  25. while (time_is_after_jiffies(end)) {
  26. cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  27. if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
  28. break;
  29. usleep_range(1000, 5000);
  30. }
  31. cfg |= FLITE_REG_CIGCTRL_SWRST;
  32. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  33. }
  34. void flite_hw_clear_pending_irq(struct fimc_lite *dev)
  35. {
  36. u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
  37. cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
  38. writel(cfg, dev->regs + FLITE_REG_CISTATUS);
  39. }
  40. u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
  41. {
  42. u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
  43. return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
  44. }
  45. void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
  46. {
  47. u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
  48. cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
  49. writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
  50. }
  51. void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
  52. {
  53. u32 cfg, intsrc;
  54. /* Select interrupts to be enabled for each output mode */
  55. if (atomic_read(&dev->out_path) == FIMC_IO_DMA) {
  56. intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
  57. FLITE_REG_CIGCTRL_IRQ_LASTEN |
  58. FLITE_REG_CIGCTRL_IRQ_STARTEN;
  59. } else {
  60. /* An output to the FIMC-IS */
  61. intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
  62. FLITE_REG_CIGCTRL_IRQ_LASTEN;
  63. }
  64. cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  65. cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
  66. cfg &= ~intsrc;
  67. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  68. }
  69. void flite_hw_capture_start(struct fimc_lite *dev)
  70. {
  71. u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
  72. cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
  73. writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
  74. }
  75. void flite_hw_capture_stop(struct fimc_lite *dev)
  76. {
  77. u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
  78. cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
  79. writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
  80. }
  81. /*
  82. * Test pattern (color bars) enable/disable. External sensor
  83. * pixel clock must be active for the test pattern to work.
  84. */
  85. void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
  86. {
  87. u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  88. if (on)
  89. cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
  90. else
  91. cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
  92. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  93. }
  94. static const u32 src_pixfmt_map[8][3] = {
  95. { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
  96. FLITE_REG_CIGCTRL_YUV422_1P },
  97. { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
  98. FLITE_REG_CIGCTRL_YUV422_1P },
  99. { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
  100. FLITE_REG_CIGCTRL_YUV422_1P },
  101. { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
  102. FLITE_REG_CIGCTRL_YUV422_1P },
  103. { V4L2_MBUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 },
  104. { V4L2_MBUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 },
  105. { V4L2_MBUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 },
  106. { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
  107. };
  108. /* Set camera input pixel format and resolution */
  109. void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
  110. {
  111. enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
  112. unsigned int i = ARRAY_SIZE(src_pixfmt_map);
  113. u32 cfg;
  114. while (i-- >= 0) {
  115. if (src_pixfmt_map[i][0] == pixelcode)
  116. break;
  117. }
  118. if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
  119. v4l2_err(&dev->vfd,
  120. "Unsupported pixel code, falling back to %#08x\n",
  121. src_pixfmt_map[i][0]);
  122. }
  123. cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  124. cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
  125. cfg |= src_pixfmt_map[i][2];
  126. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  127. cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
  128. cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
  129. FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
  130. cfg |= (f->f_width << 16) | f->f_height;
  131. cfg |= src_pixfmt_map[i][1];
  132. writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
  133. }
  134. /* Set the camera host input window offsets (cropping) */
  135. void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
  136. {
  137. u32 hoff2, voff2;
  138. u32 cfg;
  139. cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
  140. cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
  141. cfg |= (f->rect.left << 16) | f->rect.top;
  142. cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
  143. writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
  144. hoff2 = f->f_width - f->rect.width - f->rect.left;
  145. voff2 = f->f_height - f->rect.height - f->rect.top;
  146. cfg = (hoff2 << 16) | voff2;
  147. writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
  148. }
  149. /* Select camera port (A, B) */
  150. static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
  151. {
  152. u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
  153. if (id == 0)
  154. cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
  155. else
  156. cfg |= FLITE_REG_CIGENERAL_CAM_B;
  157. writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
  158. }
  159. /* Select serial or parallel bus, camera port (A,B) and set signals polarity */
  160. void flite_hw_set_camera_bus(struct fimc_lite *dev,
  161. struct fimc_source_info *si)
  162. {
  163. u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  164. unsigned int flags = si->flags;
  165. if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) {
  166. cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
  167. FLITE_REG_CIGCTRL_INVPOLPCLK |
  168. FLITE_REG_CIGCTRL_INVPOLVSYNC |
  169. FLITE_REG_CIGCTRL_INVPOLHREF);
  170. if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
  171. cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
  172. if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
  173. cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
  174. if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
  175. cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
  176. } else {
  177. cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
  178. }
  179. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  180. flite_hw_set_camera_port(dev, si->mux_id);
  181. }
  182. static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
  183. {
  184. static const u32 pixcode[4][2] = {
  185. { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
  186. { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
  187. { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
  188. { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
  189. };
  190. u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
  191. unsigned int i = ARRAY_SIZE(pixcode);
  192. while (i-- >= 0)
  193. if (pixcode[i][0] == dev->fmt->mbus_code)
  194. break;
  195. cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
  196. writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
  197. }
  198. void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
  199. {
  200. u32 cfg;
  201. /* Maximum output pixel size */
  202. cfg = readl(dev->regs + FLITE_REG_CIOCAN);
  203. cfg &= ~FLITE_REG_CIOCAN_MASK;
  204. cfg = (f->f_height << 16) | f->f_width;
  205. writel(cfg, dev->regs + FLITE_REG_CIOCAN);
  206. /* DMA offsets */
  207. cfg = readl(dev->regs + FLITE_REG_CIOOFF);
  208. cfg &= ~FLITE_REG_CIOOFF_MASK;
  209. cfg |= (f->rect.top << 16) | f->rect.left;
  210. writel(cfg, dev->regs + FLITE_REG_CIOOFF);
  211. }
  212. /* Enable/disable output DMA, set output pixel size and offsets (composition) */
  213. void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
  214. bool enable)
  215. {
  216. u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
  217. if (!enable) {
  218. cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
  219. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  220. return;
  221. }
  222. cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
  223. writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
  224. flite_hw_set_out_order(dev, f);
  225. flite_hw_set_dma_window(dev, f);
  226. }
  227. void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
  228. {
  229. struct {
  230. u32 offset;
  231. const char * const name;
  232. } registers[] = {
  233. { 0x00, "CISRCSIZE" },
  234. { 0x04, "CIGCTRL" },
  235. { 0x08, "CIIMGCPT" },
  236. { 0x0c, "CICPTSEQ" },
  237. { 0x10, "CIWDOFST" },
  238. { 0x14, "CIWDOFST2" },
  239. { 0x18, "CIODMAFMT" },
  240. { 0x20, "CIOCAN" },
  241. { 0x24, "CIOOFF" },
  242. { 0x30, "CIOSA" },
  243. { 0x40, "CISTATUS" },
  244. { 0x44, "CISTATUS2" },
  245. { 0xf0, "CITHOLD" },
  246. { 0xfc, "CIGENERAL" },
  247. };
  248. u32 i;
  249. v4l2_info(&dev->subdev, "--- %s ---\n", label);
  250. for (i = 0; i < ARRAY_SIZE(registers); i++) {
  251. u32 cfg = readl(dev->regs + registers[i].offset);
  252. v4l2_info(&dev->subdev, "%9s: 0x%08x\n",
  253. registers[i].name, cfg);
  254. }
  255. }