diff options
author | Dave Airlie <airlied@redhat.com> | 2014-09-10 05:43:29 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-09-10 05:43:29 -0400 |
commit | fdcaa1dbb7c6ed419b10fb8cdb5001ab0a00538f (patch) | |
tree | b1e27087862402b573bb90567e27e4a739b82310 | |
parent | bb6d822ec546603bca01f7ba17c52f0f4f80e329 (diff) | |
parent | 3feb049f378da6aa1209e05ef5c656a1f26a9183 (diff) |
Merge tag 'ipu-3.18' of git://git.pengutronix.de/git/pza/linux into drm-next
IPUv3 preparations for capture support
* tag 'ipu-3.18' of git://git.pengutronix.de/git/pza/linux: (26 commits)
gpu: ipu-v3: Add ipu_dump()
gpu: ipu-cpmem: Add ipu_cpmem_dump()
gpu: ipu-v3: Add more planar formats support
gpu: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
gpu: ipu-cpmem: Add ipu_cpmem_set_rotation()
gpu: ipu-cpmem: Add ipu_cpmem_set_axi_id()
gpu: ipu-cpmem: Add ipu_cpmem_set_block_mode()
gpu: ipu-v3: Add ipu_idmac_lock_enable()
gpu: ipu-v3: Add ipu_idmac_enable_watermark()
gpu: ipu-v3: Add ipu_stride_to_bytes()
gpu: ipu-v3: Add __ipu_idmac_reset_current_buffer()
gpu: ipu-v3: Add ipu_idmac_clear_buffer()
gpu: ipu-v3: Add ipu_idmac_buffer_is_ready()
gpu: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
gpu: ipu-v3: Add helper function checking if pixfmt is planar
gpu: ipu-v3: Add rotation mode conversion utilities
gpu: ipu-v3: Add ipu_mbus_code_to_colorspace()
gpu: ipu-v3: smfc: Add ipu_smfc_set_watermark()
gpu: ipu-v3: smfc: Convert to per-channel
gpu: ipu-v3: smfc: Move enable/disable to ipu-smfc.c
...
-rw-r--r-- | drivers/gpu/ipu-v3/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 916 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 764 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-csi.c | 741 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-ic.c | 778 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prv.h | 44 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-smfc.c | 156 | ||||
-rw-r--r-- | drivers/staging/imx-drm/ipuv3-plane.c | 16 | ||||
-rw-r--r-- | include/video/imx-ipu-v3.h | 326 |
9 files changed, 3072 insertions, 672 deletions
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 1887972b4ac2..107ec236a4a6 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o | 1 | obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o |
2 | 2 | ||
3 | imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-smfc.o | 3 | imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \ |
4 | ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-smfc.o | ||
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 04e7b2eafbdd..df65d2bca522 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c | |||
@@ -44,17 +44,6 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset) | |||
44 | writel(value, ipu->cm_reg + offset); | 44 | writel(value, ipu->cm_reg + offset); |
45 | } | 45 | } |
46 | 46 | ||
47 | static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) | ||
48 | { | ||
49 | return readl(ipu->idmac_reg + offset); | ||
50 | } | ||
51 | |||
52 | static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, | ||
53 | unsigned offset) | ||
54 | { | ||
55 | writel(value, ipu->idmac_reg + offset); | ||
56 | } | ||
57 | |||
58 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu) | 47 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu) |
59 | { | 48 | { |
60 | u32 val; | 49 | u32 val; |
@@ -65,457 +54,184 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu) | |||
65 | } | 54 | } |
66 | EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); | 55 | EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); |
67 | 56 | ||
68 | struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) | 57 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) |
69 | { | ||
70 | struct ipu_soc *ipu = channel->ipu; | ||
71 | |||
72 | return ipu->cpmem_base + channel->num; | ||
73 | } | ||
74 | EXPORT_SYMBOL_GPL(ipu_get_cpmem); | ||
75 | |||
76 | void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel) | ||
77 | { | ||
78 | struct ipu_soc *ipu = channel->ipu; | ||
79 | struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel); | ||
80 | u32 val; | ||
81 | |||
82 | if (ipu->ipu_type == IPUV3EX) | ||
83 | ipu_ch_param_write_field(p, IPU_FIELD_ID, 1); | ||
84 | |||
85 | val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num)); | ||
86 | val |= 1 << (channel->num % 32); | ||
87 | ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num)); | ||
88 | }; | ||
89 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); | ||
90 | |||
91 | void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v) | ||
92 | { | ||
93 | u32 bit = (wbs >> 8) % 160; | ||
94 | u32 size = wbs & 0xff; | ||
95 | u32 word = (wbs >> 8) / 160; | ||
96 | u32 i = bit / 32; | ||
97 | u32 ofs = bit % 32; | ||
98 | u32 mask = (1 << size) - 1; | ||
99 | u32 val; | ||
100 | |||
101 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
102 | |||
103 | val = readl(&base->word[word].data[i]); | ||
104 | val &= ~(mask << ofs); | ||
105 | val |= v << ofs; | ||
106 | writel(val, &base->word[word].data[i]); | ||
107 | |||
108 | if ((bit + size - 1) / 32 > i) { | ||
109 | val = readl(&base->word[word].data[i + 1]); | ||
110 | val &= ~(mask >> (ofs ? (32 - ofs) : 0)); | ||
111 | val |= v >> (ofs ? (32 - ofs) : 0); | ||
112 | writel(val, &base->word[word].data[i + 1]); | ||
113 | } | ||
114 | } | ||
115 | EXPORT_SYMBOL_GPL(ipu_ch_param_write_field); | ||
116 | |||
117 | u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) | ||
118 | { | ||
119 | u32 bit = (wbs >> 8) % 160; | ||
120 | u32 size = wbs & 0xff; | ||
121 | u32 word = (wbs >> 8) / 160; | ||
122 | u32 i = bit / 32; | ||
123 | u32 ofs = bit % 32; | ||
124 | u32 mask = (1 << size) - 1; | ||
125 | u32 val = 0; | ||
126 | |||
127 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
128 | |||
129 | val = (readl(&base->word[word].data[i]) >> ofs) & mask; | ||
130 | |||
131 | if ((bit + size - 1) / 32 > i) { | ||
132 | u32 tmp; | ||
133 | tmp = readl(&base->word[word].data[i + 1]); | ||
134 | tmp &= mask >> (ofs ? (32 - ofs) : 0); | ||
135 | val |= tmp << (ofs ? (32 - ofs) : 0); | ||
136 | } | ||
137 | |||
138 | return val; | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); | ||
141 | |||
142 | int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p, | ||
143 | const struct ipu_rgb *rgb) | ||
144 | { | ||
145 | int bpp = 0, npb = 0, ro, go, bo, to; | ||
146 | |||
147 | ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; | ||
148 | go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; | ||
149 | bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; | ||
150 | to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; | ||
151 | |||
152 | ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1); | ||
153 | ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro); | ||
154 | ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1); | ||
155 | ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go); | ||
156 | ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1); | ||
157 | ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo); | ||
158 | |||
159 | if (rgb->transp.length) { | ||
160 | ipu_ch_param_write_field(p, IPU_FIELD_WID3, | ||
161 | rgb->transp.length - 1); | ||
162 | ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to); | ||
163 | } else { | ||
164 | ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7); | ||
165 | ipu_ch_param_write_field(p, IPU_FIELD_OFS3, | ||
166 | rgb->bits_per_pixel); | ||
167 | } | ||
168 | |||
169 | switch (rgb->bits_per_pixel) { | ||
170 | case 32: | ||
171 | bpp = 0; | ||
172 | npb = 15; | ||
173 | break; | ||
174 | case 24: | ||
175 | bpp = 1; | ||
176 | npb = 19; | ||
177 | break; | ||
178 | case 16: | ||
179 | bpp = 3; | ||
180 | npb = 31; | ||
181 | break; | ||
182 | case 8: | ||
183 | bpp = 5; | ||
184 | npb = 63; | ||
185 | break; | ||
186 | default: | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); | ||
190 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); | ||
191 | ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */ | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); | ||
196 | |||
197 | int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, | ||
198 | int width) | ||
199 | { | 58 | { |
200 | int bpp = 0, npb = 0; | 59 | switch (drm_fourcc) { |
201 | 60 | case DRM_FORMAT_RGB565: | |
202 | switch (width) { | 61 | case DRM_FORMAT_BGR565: |
203 | case 32: | 62 | case DRM_FORMAT_RGB888: |
204 | bpp = 0; | 63 | case DRM_FORMAT_BGR888: |
205 | npb = 15; | 64 | case DRM_FORMAT_XRGB8888: |
206 | break; | 65 | case DRM_FORMAT_XBGR8888: |
207 | case 24: | 66 | case DRM_FORMAT_RGBX8888: |
208 | bpp = 1; | 67 | case DRM_FORMAT_BGRX8888: |
209 | npb = 19; | 68 | case DRM_FORMAT_ARGB8888: |
210 | break; | 69 | case DRM_FORMAT_ABGR8888: |
211 | case 16: | 70 | case DRM_FORMAT_RGBA8888: |
212 | bpp = 3; | 71 | case DRM_FORMAT_BGRA8888: |
213 | npb = 31; | 72 | return IPUV3_COLORSPACE_RGB; |
214 | break; | 73 | case DRM_FORMAT_YUYV: |
215 | case 8: | 74 | case DRM_FORMAT_UYVY: |
216 | bpp = 5; | 75 | case DRM_FORMAT_YUV420: |
217 | npb = 63; | 76 | case DRM_FORMAT_YVU420: |
218 | break; | 77 | case DRM_FORMAT_YUV422: |
78 | case DRM_FORMAT_YVU422: | ||
79 | case DRM_FORMAT_NV12: | ||
80 | case DRM_FORMAT_NV21: | ||
81 | case DRM_FORMAT_NV16: | ||
82 | case DRM_FORMAT_NV61: | ||
83 | return IPUV3_COLORSPACE_YUV; | ||
219 | default: | 84 | default: |
220 | return -EINVAL; | 85 | return IPUV3_COLORSPACE_UNKNOWN; |
221 | } | 86 | } |
222 | |||
223 | ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); | ||
224 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); | ||
225 | ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */ | ||
226 | |||
227 | return 0; | ||
228 | } | 87 | } |
229 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); | 88 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); |
230 | 89 | ||
231 | void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, | 90 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) |
232 | u32 pixel_format) | ||
233 | { | 91 | { |
234 | switch (pixel_format) { | 92 | switch (pixelformat) { |
93 | case V4L2_PIX_FMT_YUV420: | ||
94 | case V4L2_PIX_FMT_YVU420: | ||
95 | case V4L2_PIX_FMT_YUV422P: | ||
235 | case V4L2_PIX_FMT_UYVY: | 96 | case V4L2_PIX_FMT_UYVY: |
236 | ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
237 | ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA); /* pix format */ | ||
238 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ | ||
239 | break; | ||
240 | case V4L2_PIX_FMT_YUYV: | 97 | case V4L2_PIX_FMT_YUYV: |
241 | ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ | 98 | case V4L2_PIX_FMT_NV12: |
242 | ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */ | 99 | case V4L2_PIX_FMT_NV21: |
243 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ | 100 | case V4L2_PIX_FMT_NV16: |
244 | break; | 101 | case V4L2_PIX_FMT_NV61: |
102 | return IPUV3_COLORSPACE_YUV; | ||
103 | case V4L2_PIX_FMT_RGB32: | ||
104 | case V4L2_PIX_FMT_BGR32: | ||
105 | case V4L2_PIX_FMT_RGB24: | ||
106 | case V4L2_PIX_FMT_BGR24: | ||
107 | case V4L2_PIX_FMT_RGB565: | ||
108 | return IPUV3_COLORSPACE_RGB; | ||
109 | default: | ||
110 | return IPUV3_COLORSPACE_UNKNOWN; | ||
245 | } | 111 | } |
246 | } | 112 | } |
247 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); | 113 | EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); |
248 | 114 | ||
249 | void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, | 115 | bool ipu_pixelformat_is_planar(u32 pixelformat) |
250 | u32 pixel_format, int stride, int u_offset, int v_offset) | ||
251 | { | 116 | { |
252 | switch (pixel_format) { | 117 | switch (pixelformat) { |
253 | case V4L2_PIX_FMT_YUV420: | 118 | case V4L2_PIX_FMT_YUV420: |
254 | ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
255 | ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8); | ||
256 | ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8); | ||
257 | break; | ||
258 | case V4L2_PIX_FMT_YVU420: | 119 | case V4L2_PIX_FMT_YVU420: |
259 | ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); | 120 | case V4L2_PIX_FMT_YUV422P: |
260 | ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8); | 121 | case V4L2_PIX_FMT_NV12: |
261 | ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8); | 122 | case V4L2_PIX_FMT_NV21: |
262 | break; | 123 | case V4L2_PIX_FMT_NV16: |
124 | case V4L2_PIX_FMT_NV61: | ||
125 | return true; | ||
263 | } | 126 | } |
264 | } | ||
265 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); | ||
266 | |||
267 | void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, | ||
268 | int stride, int height) | ||
269 | { | ||
270 | int u_offset, v_offset; | ||
271 | int uv_stride = 0; | ||
272 | 127 | ||
273 | switch (pixel_format) { | 128 | return false; |
274 | case V4L2_PIX_FMT_YUV420: | ||
275 | case V4L2_PIX_FMT_YVU420: | ||
276 | uv_stride = stride / 2; | ||
277 | u_offset = stride * height; | ||
278 | v_offset = u_offset + (uv_stride * height / 2); | ||
279 | ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride, | ||
280 | u_offset, v_offset); | ||
281 | break; | ||
282 | } | ||
283 | } | 129 | } |
284 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); | 130 | EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar); |
285 | |||
286 | static const struct ipu_rgb def_rgb_32 = { | ||
287 | .red = { .offset = 16, .length = 8, }, | ||
288 | .green = { .offset = 8, .length = 8, }, | ||
289 | .blue = { .offset = 0, .length = 8, }, | ||
290 | .transp = { .offset = 24, .length = 8, }, | ||
291 | .bits_per_pixel = 32, | ||
292 | }; | ||
293 | |||
294 | static const struct ipu_rgb def_bgr_32 = { | ||
295 | .red = { .offset = 0, .length = 8, }, | ||
296 | .green = { .offset = 8, .length = 8, }, | ||
297 | .blue = { .offset = 16, .length = 8, }, | ||
298 | .transp = { .offset = 24, .length = 8, }, | ||
299 | .bits_per_pixel = 32, | ||
300 | }; | ||
301 | |||
302 | static const struct ipu_rgb def_rgb_24 = { | ||
303 | .red = { .offset = 16, .length = 8, }, | ||
304 | .green = { .offset = 8, .length = 8, }, | ||
305 | .blue = { .offset = 0, .length = 8, }, | ||
306 | .transp = { .offset = 0, .length = 0, }, | ||
307 | .bits_per_pixel = 24, | ||
308 | }; | ||
309 | |||
310 | static const struct ipu_rgb def_bgr_24 = { | ||
311 | .red = { .offset = 0, .length = 8, }, | ||
312 | .green = { .offset = 8, .length = 8, }, | ||
313 | .blue = { .offset = 16, .length = 8, }, | ||
314 | .transp = { .offset = 0, .length = 0, }, | ||
315 | .bits_per_pixel = 24, | ||
316 | }; | ||
317 | |||
318 | static const struct ipu_rgb def_rgb_16 = { | ||
319 | .red = { .offset = 11, .length = 5, }, | ||
320 | .green = { .offset = 5, .length = 6, }, | ||
321 | .blue = { .offset = 0, .length = 5, }, | ||
322 | .transp = { .offset = 0, .length = 0, }, | ||
323 | .bits_per_pixel = 16, | ||
324 | }; | ||
325 | 131 | ||
326 | static const struct ipu_rgb def_bgr_16 = { | 132 | enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code) |
327 | .red = { .offset = 0, .length = 5, }, | ||
328 | .green = { .offset = 5, .length = 6, }, | ||
329 | .blue = { .offset = 11, .length = 5, }, | ||
330 | .transp = { .offset = 0, .length = 0, }, | ||
331 | .bits_per_pixel = 16, | ||
332 | }; | ||
333 | |||
334 | #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) | ||
335 | #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
336 | (pix->width * (y) / 4) + (x) / 2) | ||
337 | #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
338 | (pix->width * pix->height / 4) + \ | ||
339 | (pix->width * (y) / 4) + (x) / 2) | ||
340 | |||
341 | int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc) | ||
342 | { | 133 | { |
343 | switch (drm_fourcc) { | 134 | switch (mbus_code & 0xf000) { |
344 | case DRM_FORMAT_YUV420: | 135 | case 0x1000: |
345 | case DRM_FORMAT_YVU420: | 136 | return IPUV3_COLORSPACE_RGB; |
346 | /* pix format */ | 137 | case 0x2000: |
347 | ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); | 138 | return IPUV3_COLORSPACE_YUV; |
348 | /* burst size */ | ||
349 | ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63); | ||
350 | break; | ||
351 | case DRM_FORMAT_UYVY: | ||
352 | /* bits/pixel */ | ||
353 | ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); | ||
354 | /* pix format */ | ||
355 | ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA); | ||
356 | /* burst size */ | ||
357 | ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); | ||
358 | break; | ||
359 | case DRM_FORMAT_YUYV: | ||
360 | /* bits/pixel */ | ||
361 | ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); | ||
362 | /* pix format */ | ||
363 | ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8); | ||
364 | /* burst size */ | ||
365 | ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); | ||
366 | break; | ||
367 | case DRM_FORMAT_ABGR8888: | ||
368 | case DRM_FORMAT_XBGR8888: | ||
369 | ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); | ||
370 | break; | ||
371 | case DRM_FORMAT_ARGB8888: | ||
372 | case DRM_FORMAT_XRGB8888: | ||
373 | ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); | ||
374 | break; | ||
375 | case DRM_FORMAT_BGR888: | ||
376 | ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); | ||
377 | break; | ||
378 | case DRM_FORMAT_RGB888: | ||
379 | ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24); | ||
380 | break; | ||
381 | case DRM_FORMAT_RGB565: | ||
382 | ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); | ||
383 | break; | ||
384 | case DRM_FORMAT_BGR565: | ||
385 | ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16); | ||
386 | break; | ||
387 | default: | 139 | default: |
388 | return -EINVAL; | 140 | return IPUV3_COLORSPACE_UNKNOWN; |
389 | } | 141 | } |
390 | |||
391 | return 0; | ||
392 | } | 142 | } |
393 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | 143 | EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace); |
394 | 144 | ||
395 | /* | 145 | int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat) |
396 | * The V4L2 spec defines packed RGB formats in memory byte order, which from | ||
397 | * point of view of the IPU corresponds to little-endian words with the first | ||
398 | * component in the least significant bits. | ||
399 | * The DRM pixel formats and IPU internal representation are ordered the other | ||
400 | * way around, with the first named component ordered at the most significant | ||
401 | * bits. Further, V4L2 formats are not well defined: | ||
402 | * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html | ||
403 | * We choose the interpretation which matches GStreamer behavior. | ||
404 | */ | ||
405 | static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) | ||
406 | { | 146 | { |
407 | switch (pixelformat) { | 147 | switch (pixelformat) { |
408 | case V4L2_PIX_FMT_RGB565: | 148 | case V4L2_PIX_FMT_YUV420: |
149 | case V4L2_PIX_FMT_YVU420: | ||
150 | case V4L2_PIX_FMT_YUV422P: | ||
151 | case V4L2_PIX_FMT_NV12: | ||
152 | case V4L2_PIX_FMT_NV21: | ||
153 | case V4L2_PIX_FMT_NV16: | ||
154 | case V4L2_PIX_FMT_NV61: | ||
409 | /* | 155 | /* |
410 | * Here we choose the 'corrected' interpretation of RGBP, a | 156 | * for the planar YUV formats, the stride passed to |
411 | * little-endian 16-bit word with the red component at the most | 157 | * cpmem must be the stride in bytes of the Y plane. |
412 | * significant bits: | 158 | * And all the planar YUV formats have an 8-bit |
413 | * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B | 159 | * Y component. |
414 | */ | 160 | */ |
415 | return DRM_FORMAT_RGB565; | 161 | return (8 * pixel_stride) >> 3; |
162 | case V4L2_PIX_FMT_RGB565: | ||
163 | case V4L2_PIX_FMT_YUYV: | ||
164 | case V4L2_PIX_FMT_UYVY: | ||
165 | return (16 * pixel_stride) >> 3; | ||
416 | case V4L2_PIX_FMT_BGR24: | 166 | case V4L2_PIX_FMT_BGR24: |
417 | /* B G R <=> [24:0] R:G:B */ | ||
418 | return DRM_FORMAT_RGB888; | ||
419 | case V4L2_PIX_FMT_RGB24: | 167 | case V4L2_PIX_FMT_RGB24: |
420 | /* R G B <=> [24:0] B:G:R */ | 168 | return (24 * pixel_stride) >> 3; |
421 | return DRM_FORMAT_BGR888; | ||
422 | case V4L2_PIX_FMT_BGR32: | 169 | case V4L2_PIX_FMT_BGR32: |
423 | /* B G R A <=> [32:0] A:B:G:R */ | ||
424 | return DRM_FORMAT_XRGB8888; | ||
425 | case V4L2_PIX_FMT_RGB32: | 170 | case V4L2_PIX_FMT_RGB32: |
426 | /* R G B A <=> [32:0] A:B:G:R */ | 171 | return (32 * pixel_stride) >> 3; |
427 | return DRM_FORMAT_XBGR8888; | 172 | default: |
428 | case V4L2_PIX_FMT_UYVY: | 173 | break; |
429 | return DRM_FORMAT_UYVY; | ||
430 | case V4L2_PIX_FMT_YUYV: | ||
431 | return DRM_FORMAT_YUYV; | ||
432 | case V4L2_PIX_FMT_YUV420: | ||
433 | return DRM_FORMAT_YUV420; | ||
434 | case V4L2_PIX_FMT_YVU420: | ||
435 | return DRM_FORMAT_YVU420; | ||
436 | } | 174 | } |
437 | 175 | ||
438 | return -EINVAL; | 176 | return -EINVAL; |
439 | } | 177 | } |
178 | EXPORT_SYMBOL_GPL(ipu_stride_to_bytes); | ||
440 | 179 | ||
441 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) | 180 | int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, |
181 | bool hflip, bool vflip) | ||
442 | { | 182 | { |
443 | switch (drm_fourcc) { | 183 | u32 r90, vf, hf; |
444 | case DRM_FORMAT_RGB565: | 184 | |
445 | case DRM_FORMAT_BGR565: | 185 | switch (degrees) { |
446 | case DRM_FORMAT_RGB888: | 186 | case 0: |
447 | case DRM_FORMAT_BGR888: | 187 | vf = hf = r90 = 0; |
448 | case DRM_FORMAT_XRGB8888: | 188 | break; |
449 | case DRM_FORMAT_XBGR8888: | 189 | case 90: |
450 | case DRM_FORMAT_RGBX8888: | 190 | vf = hf = 0; |
451 | case DRM_FORMAT_BGRX8888: | 191 | r90 = 1; |
452 | case DRM_FORMAT_ARGB8888: | 192 | break; |
453 | case DRM_FORMAT_ABGR8888: | 193 | case 180: |
454 | case DRM_FORMAT_RGBA8888: | 194 | vf = hf = 1; |
455 | case DRM_FORMAT_BGRA8888: | 195 | r90 = 0; |
456 | return IPUV3_COLORSPACE_RGB; | 196 | break; |
457 | case DRM_FORMAT_YUYV: | 197 | case 270: |
458 | case DRM_FORMAT_UYVY: | 198 | vf = hf = r90 = 1; |
459 | case DRM_FORMAT_YUV420: | 199 | break; |
460 | case DRM_FORMAT_YVU420: | ||
461 | return IPUV3_COLORSPACE_YUV; | ||
462 | default: | 200 | default: |
463 | return IPUV3_COLORSPACE_UNKNOWN; | 201 | return -EINVAL; |
464 | } | 202 | } |
465 | } | ||
466 | EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); | ||
467 | 203 | ||
468 | int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, | 204 | hf ^= (u32)hflip; |
469 | struct ipu_image *image) | 205 | vf ^= (u32)vflip; |
470 | { | ||
471 | struct v4l2_pix_format *pix = &image->pix; | ||
472 | int y_offset, u_offset, v_offset; | ||
473 | 206 | ||
474 | pr_debug("%s: resolution: %dx%d stride: %d\n", | 207 | *mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf); |
475 | __func__, pix->width, pix->height, | 208 | return 0; |
476 | pix->bytesperline); | 209 | } |
210 | EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode); | ||
477 | 211 | ||
478 | ipu_cpmem_set_resolution(cpmem, image->rect.width, | 212 | int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, |
479 | image->rect.height); | 213 | bool hflip, bool vflip) |
480 | ipu_cpmem_set_stride(cpmem, pix->bytesperline); | 214 | { |
215 | u32 r90, vf, hf; | ||
481 | 216 | ||
482 | ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); | 217 | r90 = ((u32)mode >> 2) & 0x1; |
218 | hf = ((u32)mode >> 1) & 0x1; | ||
219 | vf = ((u32)mode >> 0) & 0x1; | ||
220 | hf ^= (u32)hflip; | ||
221 | vf ^= (u32)vflip; | ||
483 | 222 | ||
484 | switch (pix->pixelformat) { | 223 | switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) { |
485 | case V4L2_PIX_FMT_YUV420: | 224 | case IPU_ROTATE_NONE: |
486 | case V4L2_PIX_FMT_YVU420: | 225 | *degrees = 0; |
487 | y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
488 | u_offset = U_OFFSET(pix, image->rect.left, | ||
489 | image->rect.top) - y_offset; | ||
490 | v_offset = V_OFFSET(pix, image->rect.left, | ||
491 | image->rect.top) - y_offset; | ||
492 | |||
493 | ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat, | ||
494 | pix->bytesperline, u_offset, v_offset); | ||
495 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset); | ||
496 | break; | 226 | break; |
497 | case V4L2_PIX_FMT_UYVY: | 227 | case IPU_ROTATE_90_RIGHT: |
498 | case V4L2_PIX_FMT_YUYV: | 228 | *degrees = 90; |
499 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
500 | image->rect.left * 2 + | ||
501 | image->rect.top * image->pix.bytesperline); | ||
502 | break; | 229 | break; |
503 | case V4L2_PIX_FMT_RGB32: | 230 | case IPU_ROTATE_180: |
504 | case V4L2_PIX_FMT_BGR32: | 231 | *degrees = 180; |
505 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
506 | image->rect.left * 4 + | ||
507 | image->rect.top * image->pix.bytesperline); | ||
508 | break; | 232 | break; |
509 | case V4L2_PIX_FMT_RGB565: | 233 | case IPU_ROTATE_90_LEFT: |
510 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | 234 | *degrees = 270; |
511 | image->rect.left * 2 + | ||
512 | image->rect.top * image->pix.bytesperline); | ||
513 | break; | ||
514 | case V4L2_PIX_FMT_RGB24: | ||
515 | case V4L2_PIX_FMT_BGR24: | ||
516 | ipu_cpmem_set_buffer(cpmem, 0, image->phys + | ||
517 | image->rect.left * 3 + | ||
518 | image->rect.top * image->pix.bytesperline); | ||
519 | break; | 235 | break; |
520 | default: | 236 | default: |
521 | return -EINVAL; | 237 | return -EINVAL; |
@@ -523,27 +239,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, | |||
523 | 239 | ||
524 | return 0; | 240 | return 0; |
525 | } | 241 | } |
526 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | 242 | EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees); |
527 | |||
528 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) | ||
529 | { | ||
530 | switch (pixelformat) { | ||
531 | case V4L2_PIX_FMT_YUV420: | ||
532 | case V4L2_PIX_FMT_YVU420: | ||
533 | case V4L2_PIX_FMT_UYVY: | ||
534 | case V4L2_PIX_FMT_YUYV: | ||
535 | return IPUV3_COLORSPACE_YUV; | ||
536 | case V4L2_PIX_FMT_RGB32: | ||
537 | case V4L2_PIX_FMT_BGR32: | ||
538 | case V4L2_PIX_FMT_RGB24: | ||
539 | case V4L2_PIX_FMT_BGR24: | ||
540 | case V4L2_PIX_FMT_RGB565: | ||
541 | return IPUV3_COLORSPACE_RGB; | ||
542 | default: | ||
543 | return IPUV3_COLORSPACE_UNKNOWN; | ||
544 | } | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); | ||
547 | 243 | ||
548 | struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) | 244 | struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) |
549 | { | 245 | { |
@@ -587,7 +283,26 @@ void ipu_idmac_put(struct ipuv3_channel *channel) | |||
587 | } | 283 | } |
588 | EXPORT_SYMBOL_GPL(ipu_idmac_put); | 284 | EXPORT_SYMBOL_GPL(ipu_idmac_put); |
589 | 285 | ||
590 | #define idma_mask(ch) (1 << (ch & 0x1f)) | 286 | #define idma_mask(ch) (1 << ((ch) & 0x1f)) |
287 | |||
288 | /* | ||
289 | * This is an undocumented feature, a write one to a channel bit in | ||
290 | * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's | ||
291 | * internal current buffer pointer so that transfers start from buffer | ||
292 | * 0 on the next channel enable (that's the theory anyway, the imx6 TRM | ||
293 | * only says these are read-only registers). This operation is required | ||
294 | * for channel linking to work correctly, for instance video capture | ||
295 | * pipelines that carry out image rotations will fail after the first | ||
296 | * streaming unless this function is called for each channel before | ||
297 | * re-enabling the channels. | ||
298 | */ | ||
299 | static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel) | ||
300 | { | ||
301 | struct ipu_soc *ipu = channel->ipu; | ||
302 | unsigned int chno = channel->num; | ||
303 | |||
304 | ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno)); | ||
305 | } | ||
591 | 306 | ||
592 | void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, | 307 | void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, |
593 | bool doublebuffer) | 308 | bool doublebuffer) |
@@ -605,10 +320,81 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, | |||
605 | reg &= ~idma_mask(channel->num); | 320 | reg &= ~idma_mask(channel->num); |
606 | ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num)); | 321 | ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num)); |
607 | 322 | ||
323 | __ipu_idmac_reset_current_buffer(channel); | ||
324 | |||
608 | spin_unlock_irqrestore(&ipu->lock, flags); | 325 | spin_unlock_irqrestore(&ipu->lock, flags); |
609 | } | 326 | } |
610 | EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); | 327 | EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); |
611 | 328 | ||
329 | static const struct { | ||
330 | int chnum; | ||
331 | u32 reg; | ||
332 | int shift; | ||
333 | } idmac_lock_en_info[] = { | ||
334 | { .chnum = 5, .reg = IDMAC_CH_LOCK_EN_1, .shift = 0, }, | ||
335 | { .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift = 2, }, | ||
336 | { .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift = 4, }, | ||
337 | { .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift = 6, }, | ||
338 | { .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift = 8, }, | ||
339 | { .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, }, | ||
340 | { .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, }, | ||
341 | { .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, }, | ||
342 | { .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, }, | ||
343 | { .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, }, | ||
344 | { .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, }, | ||
345 | { .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift = 0, }, | ||
346 | { .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift = 2, }, | ||
347 | { .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift = 4, }, | ||
348 | { .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift = 6, }, | ||
349 | { .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift = 8, }, | ||
350 | { .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, }, | ||
351 | }; | ||
352 | |||
353 | int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts) | ||
354 | { | ||
355 | struct ipu_soc *ipu = channel->ipu; | ||
356 | unsigned long flags; | ||
357 | u32 bursts, regval; | ||
358 | int i; | ||
359 | |||
360 | switch (num_bursts) { | ||
361 | case 0: | ||
362 | case 1: | ||
363 | bursts = 0x00; /* locking disabled */ | ||
364 | break; | ||
365 | case 2: | ||
366 | bursts = 0x01; | ||
367 | break; | ||
368 | case 4: | ||
369 | bursts = 0x02; | ||
370 | break; | ||
371 | case 8: | ||
372 | bursts = 0x03; | ||
373 | break; | ||
374 | default: | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
378 | for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) { | ||
379 | if (channel->num == idmac_lock_en_info[i].chnum) | ||
380 | break; | ||
381 | } | ||
382 | if (i >= ARRAY_SIZE(idmac_lock_en_info)) | ||
383 | return -EINVAL; | ||
384 | |||
385 | spin_lock_irqsave(&ipu->lock, flags); | ||
386 | |||
387 | regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg); | ||
388 | regval &= ~(0x03 << idmac_lock_en_info[i].shift); | ||
389 | regval |= (bursts << idmac_lock_en_info[i].shift); | ||
390 | ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg); | ||
391 | |||
392 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable); | ||
397 | |||
612 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask) | 398 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask) |
613 | { | 399 | { |
614 | unsigned long lock_flags; | 400 | unsigned long lock_flags; |
@@ -661,30 +447,6 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask) | |||
661 | } | 447 | } |
662 | EXPORT_SYMBOL_GPL(ipu_module_disable); | 448 | EXPORT_SYMBOL_GPL(ipu_module_disable); |
663 | 449 | ||
664 | int ipu_csi_enable(struct ipu_soc *ipu, int csi) | ||
665 | { | ||
666 | return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN); | ||
667 | } | ||
668 | EXPORT_SYMBOL_GPL(ipu_csi_enable); | ||
669 | |||
670 | int ipu_csi_disable(struct ipu_soc *ipu, int csi) | ||
671 | { | ||
672 | return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN); | ||
673 | } | ||
674 | EXPORT_SYMBOL_GPL(ipu_csi_disable); | ||
675 | |||
676 | int ipu_smfc_enable(struct ipu_soc *ipu) | ||
677 | { | ||
678 | return ipu_module_enable(ipu, IPU_CONF_SMFC_EN); | ||
679 | } | ||
680 | EXPORT_SYMBOL_GPL(ipu_smfc_enable); | ||
681 | |||
682 | int ipu_smfc_disable(struct ipu_soc *ipu) | ||
683 | { | ||
684 | return ipu_module_disable(ipu, IPU_CONF_SMFC_EN); | ||
685 | } | ||
686 | EXPORT_SYMBOL_GPL(ipu_smfc_disable); | ||
687 | |||
688 | int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) | 450 | int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) |
689 | { | 451 | { |
690 | struct ipu_soc *ipu = channel->ipu; | 452 | struct ipu_soc *ipu = channel->ipu; |
@@ -694,6 +456,30 @@ int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel) | |||
694 | } | 456 | } |
695 | EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer); | 457 | EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer); |
696 | 458 | ||
459 | bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num) | ||
460 | { | ||
461 | struct ipu_soc *ipu = channel->ipu; | ||
462 | unsigned long flags; | ||
463 | u32 reg = 0; | ||
464 | |||
465 | spin_lock_irqsave(&ipu->lock, flags); | ||
466 | switch (buf_num) { | ||
467 | case 0: | ||
468 | reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)); | ||
469 | break; | ||
470 | case 1: | ||
471 | reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)); | ||
472 | break; | ||
473 | case 2: | ||
474 | reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num)); | ||
475 | break; | ||
476 | } | ||
477 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
478 | |||
479 | return ((reg & idma_mask(channel->num)) != 0); | ||
480 | } | ||
481 | EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready); | ||
482 | |||
697 | void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) | 483 | void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) |
698 | { | 484 | { |
699 | struct ipu_soc *ipu = channel->ipu; | 485 | struct ipu_soc *ipu = channel->ipu; |
@@ -712,6 +498,34 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) | |||
712 | } | 498 | } |
713 | EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); | 499 | EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); |
714 | 500 | ||
501 | void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num) | ||
502 | { | ||
503 | struct ipu_soc *ipu = channel->ipu; | ||
504 | unsigned int chno = channel->num; | ||
505 | unsigned long flags; | ||
506 | |||
507 | spin_lock_irqsave(&ipu->lock, flags); | ||
508 | |||
509 | ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */ | ||
510 | switch (buf_num) { | ||
511 | case 0: | ||
512 | ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno)); | ||
513 | break; | ||
514 | case 1: | ||
515 | ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno)); | ||
516 | break; | ||
517 | case 2: | ||
518 | ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno)); | ||
519 | break; | ||
520 | default: | ||
521 | break; | ||
522 | } | ||
523 | ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */ | ||
524 | |||
525 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
526 | } | ||
527 | EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer); | ||
528 | |||
715 | int ipu_idmac_enable_channel(struct ipuv3_channel *channel) | 529 | int ipu_idmac_enable_channel(struct ipuv3_channel *channel) |
716 | { | 530 | { |
717 | struct ipu_soc *ipu = channel->ipu; | 531 | struct ipu_soc *ipu = channel->ipu; |
@@ -782,6 +596,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel) | |||
782 | val &= ~idma_mask(channel->num); | 596 | val &= ~idma_mask(channel->num); |
783 | ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); | 597 | ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); |
784 | 598 | ||
599 | __ipu_idmac_reset_current_buffer(channel); | ||
600 | |||
785 | /* Set channel buffers NOT to be ready */ | 601 | /* Set channel buffers NOT to be ready */ |
786 | ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */ | 602 | ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */ |
787 | 603 | ||
@@ -810,6 +626,31 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel) | |||
810 | } | 626 | } |
811 | EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); | 627 | EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); |
812 | 628 | ||
629 | /* | ||
630 | * The imx6 rev. D TRM says that enabling the WM feature will increase | ||
631 | * a channel's priority. Refer to Table 36-8 Calculated priority value. | ||
632 | * The sub-module that is the sink or source for the channel must enable | ||
633 | * watermark signal for this to take effect (SMFC_WM for instance). | ||
634 | */ | ||
635 | void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable) | ||
636 | { | ||
637 | struct ipu_soc *ipu = channel->ipu; | ||
638 | unsigned long flags; | ||
639 | u32 val; | ||
640 | |||
641 | spin_lock_irqsave(&ipu->lock, flags); | ||
642 | |||
643 | val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num)); | ||
644 | if (enable) | ||
645 | val |= 1 << (channel->num % 32); | ||
646 | else | ||
647 | val &= ~(1 << (channel->num % 32)); | ||
648 | ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num)); | ||
649 | |||
650 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
651 | } | ||
652 | EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark); | ||
653 | |||
813 | static int ipu_memory_reset(struct ipu_soc *ipu) | 654 | static int ipu_memory_reset(struct ipu_soc *ipu) |
814 | { | 655 | { |
815 | unsigned long timeout; | 656 | unsigned long timeout; |
@@ -826,12 +667,66 @@ static int ipu_memory_reset(struct ipu_soc *ipu) | |||
826 | return 0; | 667 | return 0; |
827 | } | 668 | } |
828 | 669 | ||
670 | /* | ||
671 | * Set the source mux for the given CSI. Selects either parallel or | ||
672 | * MIPI CSI2 sources. | ||
673 | */ | ||
674 | void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2) | ||
675 | { | ||
676 | unsigned long flags; | ||
677 | u32 val, mask; | ||
678 | |||
679 | mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE : | ||
680 | IPU_CONF_CSI0_DATA_SOURCE; | ||
681 | |||
682 | spin_lock_irqsave(&ipu->lock, flags); | ||
683 | |||
684 | val = ipu_cm_read(ipu, IPU_CONF); | ||
685 | if (mipi_csi2) | ||
686 | val |= mask; | ||
687 | else | ||
688 | val &= ~mask; | ||
689 | ipu_cm_write(ipu, val, IPU_CONF); | ||
690 | |||
691 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
692 | } | ||
693 | EXPORT_SYMBOL_GPL(ipu_set_csi_src_mux); | ||
694 | |||
695 | /* | ||
696 | * Set the source mux for the IC. Selects either CSI[01] or the VDI. | ||
697 | */ | ||
698 | void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi) | ||
699 | { | ||
700 | unsigned long flags; | ||
701 | u32 val; | ||
702 | |||
703 | spin_lock_irqsave(&ipu->lock, flags); | ||
704 | |||
705 | val = ipu_cm_read(ipu, IPU_CONF); | ||
706 | if (vdi) { | ||
707 | val |= IPU_CONF_IC_INPUT; | ||
708 | } else { | ||
709 | val &= ~IPU_CONF_IC_INPUT; | ||
710 | if (csi_id == 1) | ||
711 | val |= IPU_CONF_CSI_SEL; | ||
712 | else | ||
713 | val &= ~IPU_CONF_CSI_SEL; | ||
714 | } | ||
715 | ipu_cm_write(ipu, val, IPU_CONF); | ||
716 | |||
717 | spin_unlock_irqrestore(&ipu->lock, flags); | ||
718 | } | ||
719 | EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux); | ||
720 | |||
829 | struct ipu_devtype { | 721 | struct ipu_devtype { |
830 | const char *name; | 722 | const char *name; |
831 | unsigned long cm_ofs; | 723 | unsigned long cm_ofs; |
832 | unsigned long cpmem_ofs; | 724 | unsigned long cpmem_ofs; |
833 | unsigned long srm_ofs; | 725 | unsigned long srm_ofs; |
834 | unsigned long tpm_ofs; | 726 | unsigned long tpm_ofs; |
727 | unsigned long csi0_ofs; | ||
728 | unsigned long csi1_ofs; | ||
729 | unsigned long ic_ofs; | ||
835 | unsigned long disp0_ofs; | 730 | unsigned long disp0_ofs; |
836 | unsigned long disp1_ofs; | 731 | unsigned long disp1_ofs; |
837 | unsigned long dc_tmpl_ofs; | 732 | unsigned long dc_tmpl_ofs; |
@@ -845,6 +740,9 @@ static struct ipu_devtype ipu_type_imx51 = { | |||
845 | .cpmem_ofs = 0x1f000000, | 740 | .cpmem_ofs = 0x1f000000, |
846 | .srm_ofs = 0x1f040000, | 741 | .srm_ofs = 0x1f040000, |
847 | .tpm_ofs = 0x1f060000, | 742 | .tpm_ofs = 0x1f060000, |
743 | .csi0_ofs = 0x1f030000, | ||
744 | .csi1_ofs = 0x1f038000, | ||
745 | .ic_ofs = 0x1f020000, | ||
848 | .disp0_ofs = 0x1e040000, | 746 | .disp0_ofs = 0x1e040000, |
849 | .disp1_ofs = 0x1e048000, | 747 | .disp1_ofs = 0x1e048000, |
850 | .dc_tmpl_ofs = 0x1f080000, | 748 | .dc_tmpl_ofs = 0x1f080000, |
@@ -858,6 +756,9 @@ static struct ipu_devtype ipu_type_imx53 = { | |||
858 | .cpmem_ofs = 0x07000000, | 756 | .cpmem_ofs = 0x07000000, |
859 | .srm_ofs = 0x07040000, | 757 | .srm_ofs = 0x07040000, |
860 | .tpm_ofs = 0x07060000, | 758 | .tpm_ofs = 0x07060000, |
759 | .csi0_ofs = 0x07030000, | ||
760 | .csi1_ofs = 0x07038000, | ||
761 | .ic_ofs = 0x07020000, | ||
861 | .disp0_ofs = 0x06040000, | 762 | .disp0_ofs = 0x06040000, |
862 | .disp1_ofs = 0x06048000, | 763 | .disp1_ofs = 0x06048000, |
863 | .dc_tmpl_ofs = 0x07080000, | 764 | .dc_tmpl_ofs = 0x07080000, |
@@ -871,6 +772,9 @@ static struct ipu_devtype ipu_type_imx6q = { | |||
871 | .cpmem_ofs = 0x00300000, | 772 | .cpmem_ofs = 0x00300000, |
872 | .srm_ofs = 0x00340000, | 773 | .srm_ofs = 0x00340000, |
873 | .tpm_ofs = 0x00360000, | 774 | .tpm_ofs = 0x00360000, |
775 | .csi0_ofs = 0x00230000, | ||
776 | .csi1_ofs = 0x00238000, | ||
777 | .ic_ofs = 0x00220000, | ||
874 | .disp0_ofs = 0x00240000, | 778 | .disp0_ofs = 0x00240000, |
875 | .disp1_ofs = 0x00248000, | 779 | .disp1_ofs = 0x00248000, |
876 | .dc_tmpl_ofs = 0x00380000, | 780 | .dc_tmpl_ofs = 0x00380000, |
@@ -895,8 +799,36 @@ static int ipu_submodules_init(struct ipu_soc *ipu, | |||
895 | struct device *dev = &pdev->dev; | 799 | struct device *dev = &pdev->dev; |
896 | const struct ipu_devtype *devtype = ipu->devtype; | 800 | const struct ipu_devtype *devtype = ipu->devtype; |
897 | 801 | ||
802 | ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs); | ||
803 | if (ret) { | ||
804 | unit = "cpmem"; | ||
805 | goto err_cpmem; | ||
806 | } | ||
807 | |||
808 | ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs, | ||
809 | IPU_CONF_CSI0_EN, ipu_clk); | ||
810 | if (ret) { | ||
811 | unit = "csi0"; | ||
812 | goto err_csi_0; | ||
813 | } | ||
814 | |||
815 | ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs, | ||
816 | IPU_CONF_CSI1_EN, ipu_clk); | ||
817 | if (ret) { | ||
818 | unit = "csi1"; | ||
819 | goto err_csi_1; | ||
820 | } | ||
821 | |||
822 | ret = ipu_ic_init(ipu, dev, | ||
823 | ipu_base + devtype->ic_ofs, | ||
824 | ipu_base + devtype->tpm_ofs); | ||
825 | if (ret) { | ||
826 | unit = "ic"; | ||
827 | goto err_ic; | ||
828 | } | ||
829 | |||
898 | ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, | 830 | ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, |
899 | IPU_CONF_DI0_EN, ipu_clk); | 831 | IPU_CONF_DI0_EN, ipu_clk); |
900 | if (ret) { | 832 | if (ret) { |
901 | unit = "di0"; | 833 | unit = "di0"; |
902 | goto err_di_0; | 834 | goto err_di_0; |
@@ -949,6 +881,14 @@ err_dc: | |||
949 | err_di_1: | 881 | err_di_1: |
950 | ipu_di_exit(ipu, 0); | 882 | ipu_di_exit(ipu, 0); |
951 | err_di_0: | 883 | err_di_0: |
884 | ipu_ic_exit(ipu); | ||
885 | err_ic: | ||
886 | ipu_csi_exit(ipu, 1); | ||
887 | err_csi_1: | ||
888 | ipu_csi_exit(ipu, 0); | ||
889 | err_csi_0: | ||
890 | ipu_cpmem_exit(ipu); | ||
891 | err_cpmem: | ||
952 | dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); | 892 | dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); |
953 | return ret; | 893 | return ret; |
954 | } | 894 | } |
@@ -1025,6 +965,10 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) | |||
1025 | ipu_dc_exit(ipu); | 965 | ipu_dc_exit(ipu); |
1026 | ipu_di_exit(ipu, 1); | 966 | ipu_di_exit(ipu, 1); |
1027 | ipu_di_exit(ipu, 0); | 967 | ipu_di_exit(ipu, 0); |
968 | ipu_ic_exit(ipu); | ||
969 | ipu_csi_exit(ipu, 1); | ||
970 | ipu_csi_exit(ipu, 0); | ||
971 | ipu_cpmem_exit(ipu); | ||
1028 | } | 972 | } |
1029 | 973 | ||
1030 | static int platform_remove_devices_fn(struct device *dev, void *unused) | 974 | static int platform_remove_devices_fn(struct device *dev, void *unused) |
@@ -1201,6 +1145,44 @@ static void ipu_irq_exit(struct ipu_soc *ipu) | |||
1201 | irq_domain_remove(ipu->domain); | 1145 | irq_domain_remove(ipu->domain); |
1202 | } | 1146 | } |
1203 | 1147 | ||
1148 | void ipu_dump(struct ipu_soc *ipu) | ||
1149 | { | ||
1150 | int i; | ||
1151 | |||
1152 | dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n", | ||
1153 | ipu_cm_read(ipu, IPU_CONF)); | ||
1154 | dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n", | ||
1155 | ipu_idmac_read(ipu, IDMAC_CONF)); | ||
1156 | dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n", | ||
1157 | ipu_idmac_read(ipu, IDMAC_CHA_EN(0))); | ||
1158 | dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n", | ||
1159 | ipu_idmac_read(ipu, IDMAC_CHA_EN(32))); | ||
1160 | dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n", | ||
1161 | ipu_idmac_read(ipu, IDMAC_CHA_PRI(0))); | ||
1162 | dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n", | ||
1163 | ipu_idmac_read(ipu, IDMAC_CHA_PRI(32))); | ||
1164 | dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n", | ||
1165 | ipu_idmac_read(ipu, IDMAC_BAND_EN(0))); | ||
1166 | dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n", | ||
1167 | ipu_idmac_read(ipu, IDMAC_BAND_EN(32))); | ||
1168 | dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n", | ||
1169 | ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0))); | ||
1170 | dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n", | ||
1171 | ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32))); | ||
1172 | dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n", | ||
1173 | ipu_cm_read(ipu, IPU_FS_PROC_FLOW1)); | ||
1174 | dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n", | ||
1175 | ipu_cm_read(ipu, IPU_FS_PROC_FLOW2)); | ||
1176 | dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n", | ||
1177 | ipu_cm_read(ipu, IPU_FS_PROC_FLOW3)); | ||
1178 | dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n", | ||
1179 | ipu_cm_read(ipu, IPU_FS_DISP_FLOW1)); | ||
1180 | for (i = 0; i < 15; i++) | ||
1181 | dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i, | ||
1182 | ipu_cm_read(ipu, IPU_INT_CTRL(i))); | ||
1183 | } | ||
1184 | EXPORT_SYMBOL_GPL(ipu_dump); | ||
1185 | |||
1204 | static int ipu_probe(struct platform_device *pdev) | 1186 | static int ipu_probe(struct platform_device *pdev) |
1205 | { | 1187 | { |
1206 | const struct of_device_id *of_id = | 1188 | const struct of_device_id *of_id = |
@@ -1243,6 +1225,12 @@ static int ipu_probe(struct platform_device *pdev) | |||
1243 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); | 1225 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); |
1244 | dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n", | 1226 | dev_dbg(&pdev->dev, "cpmem: 0x%08lx\n", |
1245 | ipu_base + devtype->cpmem_ofs); | 1227 | ipu_base + devtype->cpmem_ofs); |
1228 | dev_dbg(&pdev->dev, "csi0: 0x%08lx\n", | ||
1229 | ipu_base + devtype->csi0_ofs); | ||
1230 | dev_dbg(&pdev->dev, "csi1: 0x%08lx\n", | ||
1231 | ipu_base + devtype->csi1_ofs); | ||
1232 | dev_dbg(&pdev->dev, "ic: 0x%08lx\n", | ||
1233 | ipu_base + devtype->ic_ofs); | ||
1246 | dev_dbg(&pdev->dev, "disp0: 0x%08lx\n", | 1234 | dev_dbg(&pdev->dev, "disp0: 0x%08lx\n", |
1247 | ipu_base + devtype->disp0_ofs); | 1235 | ipu_base + devtype->disp0_ofs); |
1248 | dev_dbg(&pdev->dev, "disp1: 0x%08lx\n", | 1236 | dev_dbg(&pdev->dev, "disp1: 0x%08lx\n", |
@@ -1265,10 +1253,8 @@ static int ipu_probe(struct platform_device *pdev) | |||
1265 | ipu->idmac_reg = devm_ioremap(&pdev->dev, | 1253 | ipu->idmac_reg = devm_ioremap(&pdev->dev, |
1266 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, | 1254 | ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, |
1267 | PAGE_SIZE); | 1255 | PAGE_SIZE); |
1268 | ipu->cpmem_base = devm_ioremap(&pdev->dev, | ||
1269 | ipu_base + devtype->cpmem_ofs, PAGE_SIZE); | ||
1270 | 1256 | ||
1271 | if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) | 1257 | if (!ipu->cm_reg || !ipu->idmac_reg) |
1272 | return -ENOMEM; | 1258 | return -ENOMEM; |
1273 | 1259 | ||
1274 | ipu->clk = devm_clk_get(&pdev->dev, "bus"); | 1260 | ipu->clk = devm_clk_get(&pdev->dev, "bus"); |
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c new file mode 100644 index 000000000000..3bf05bc4ab67 --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c | |||
@@ -0,0 +1,764 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Mentor Graphics Inc. | ||
3 | * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/bitrev.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <drm/drm_fourcc.h> | ||
16 | #include "ipu-prv.h" | ||
17 | |||
18 | struct ipu_cpmem_word { | ||
19 | u32 data[5]; | ||
20 | u32 res[3]; | ||
21 | }; | ||
22 | |||
23 | struct ipu_ch_param { | ||
24 | struct ipu_cpmem_word word[2]; | ||
25 | }; | ||
26 | |||
27 | struct ipu_cpmem { | ||
28 | struct ipu_ch_param __iomem *base; | ||
29 | u32 module; | ||
30 | spinlock_t lock; | ||
31 | int use_count; | ||
32 | struct ipu_soc *ipu; | ||
33 | }; | ||
34 | |||
35 | #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) | ||
36 | |||
37 | #define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) | ||
38 | #define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) | ||
39 | #define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) | ||
40 | #define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) | ||
41 | #define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) | ||
42 | #define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) | ||
43 | #define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) | ||
44 | |||
45 | #define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) | ||
46 | #define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) | ||
47 | #define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) | ||
48 | #define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) | ||
49 | #define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) | ||
50 | #define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) | ||
51 | #define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) | ||
52 | #define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) | ||
53 | #define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) | ||
54 | #define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) | ||
55 | #define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) | ||
56 | #define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) | ||
57 | #define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) | ||
58 | #define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) | ||
59 | #define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) | ||
60 | #define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) | ||
61 | #define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) | ||
62 | #define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) | ||
63 | #define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) | ||
64 | #define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) | ||
65 | #define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) | ||
66 | #define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) | ||
67 | #define IPU_FIELD_ROT_HF_VF IPU_CPMEM_WORD(0, 119, 3) | ||
68 | #define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) | ||
69 | #define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) | ||
70 | #define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) | ||
71 | #define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) | ||
72 | #define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) | ||
73 | #define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) | ||
74 | #define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) | ||
75 | #define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) | ||
76 | #define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) | ||
77 | #define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) | ||
78 | #define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) | ||
79 | #define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) | ||
80 | #define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) | ||
81 | #define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) | ||
82 | #define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) | ||
83 | #define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) | ||
84 | #define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) | ||
85 | #define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) | ||
86 | #define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) | ||
87 | #define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) | ||
88 | #define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) | ||
89 | #define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) | ||
90 | #define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) | ||
91 | #define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) | ||
92 | #define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) | ||
93 | #define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) | ||
94 | #define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) | ||
95 | #define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) | ||
96 | |||
97 | static inline struct ipu_ch_param __iomem * | ||
98 | ipu_get_cpmem(struct ipuv3_channel *ch) | ||
99 | { | ||
100 | struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv; | ||
101 | |||
102 | return cpmem->base + ch->num; | ||
103 | } | ||
104 | |||
105 | static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v) | ||
106 | { | ||
107 | struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); | ||
108 | u32 bit = (wbs >> 8) % 160; | ||
109 | u32 size = wbs & 0xff; | ||
110 | u32 word = (wbs >> 8) / 160; | ||
111 | u32 i = bit / 32; | ||
112 | u32 ofs = bit % 32; | ||
113 | u32 mask = (1 << size) - 1; | ||
114 | u32 val; | ||
115 | |||
116 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
117 | |||
118 | val = readl(&base->word[word].data[i]); | ||
119 | val &= ~(mask << ofs); | ||
120 | val |= v << ofs; | ||
121 | writel(val, &base->word[word].data[i]); | ||
122 | |||
123 | if ((bit + size - 1) / 32 > i) { | ||
124 | val = readl(&base->word[word].data[i + 1]); | ||
125 | val &= ~(mask >> (ofs ? (32 - ofs) : 0)); | ||
126 | val |= v >> (ofs ? (32 - ofs) : 0); | ||
127 | writel(val, &base->word[word].data[i + 1]); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs) | ||
132 | { | ||
133 | struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); | ||
134 | u32 bit = (wbs >> 8) % 160; | ||
135 | u32 size = wbs & 0xff; | ||
136 | u32 word = (wbs >> 8) / 160; | ||
137 | u32 i = bit / 32; | ||
138 | u32 ofs = bit % 32; | ||
139 | u32 mask = (1 << size) - 1; | ||
140 | u32 val = 0; | ||
141 | |||
142 | pr_debug("%s %d %d %d\n", __func__, word, bit , size); | ||
143 | |||
144 | val = (readl(&base->word[word].data[i]) >> ofs) & mask; | ||
145 | |||
146 | if ((bit + size - 1) / 32 > i) { | ||
147 | u32 tmp; | ||
148 | |||
149 | tmp = readl(&base->word[word].data[i + 1]); | ||
150 | tmp &= mask >> (ofs ? (32 - ofs) : 0); | ||
151 | val |= tmp << (ofs ? (32 - ofs) : 0); | ||
152 | } | ||
153 | |||
154 | return val; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * The V4L2 spec defines packed RGB formats in memory byte order, which from | ||
159 | * point of view of the IPU corresponds to little-endian words with the first | ||
160 | * component in the least significant bits. | ||
161 | * The DRM pixel formats and IPU internal representation are ordered the other | ||
162 | * way around, with the first named component ordered at the most significant | ||
163 | * bits. Further, V4L2 formats are not well defined: | ||
164 | * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html | ||
165 | * We choose the interpretation which matches GStreamer behavior. | ||
166 | */ | ||
167 | static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) | ||
168 | { | ||
169 | switch (pixelformat) { | ||
170 | case V4L2_PIX_FMT_RGB565: | ||
171 | /* | ||
172 | * Here we choose the 'corrected' interpretation of RGBP, a | ||
173 | * little-endian 16-bit word with the red component at the most | ||
174 | * significant bits: | ||
175 | * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B | ||
176 | */ | ||
177 | return DRM_FORMAT_RGB565; | ||
178 | case V4L2_PIX_FMT_BGR24: | ||
179 | /* B G R <=> [24:0] R:G:B */ | ||
180 | return DRM_FORMAT_RGB888; | ||
181 | case V4L2_PIX_FMT_RGB24: | ||
182 | /* R G B <=> [24:0] B:G:R */ | ||
183 | return DRM_FORMAT_BGR888; | ||
184 | case V4L2_PIX_FMT_BGR32: | ||
185 | /* B G R A <=> [32:0] A:B:G:R */ | ||
186 | return DRM_FORMAT_XRGB8888; | ||
187 | case V4L2_PIX_FMT_RGB32: | ||
188 | /* R G B A <=> [32:0] A:B:G:R */ | ||
189 | return DRM_FORMAT_XBGR8888; | ||
190 | case V4L2_PIX_FMT_UYVY: | ||
191 | return DRM_FORMAT_UYVY; | ||
192 | case V4L2_PIX_FMT_YUYV: | ||
193 | return DRM_FORMAT_YUYV; | ||
194 | case V4L2_PIX_FMT_YUV420: | ||
195 | return DRM_FORMAT_YUV420; | ||
196 | case V4L2_PIX_FMT_YUV422P: | ||
197 | return DRM_FORMAT_YUV422; | ||
198 | case V4L2_PIX_FMT_YVU420: | ||
199 | return DRM_FORMAT_YVU420; | ||
200 | case V4L2_PIX_FMT_NV12: | ||
201 | return DRM_FORMAT_NV12; | ||
202 | case V4L2_PIX_FMT_NV16: | ||
203 | return DRM_FORMAT_NV16; | ||
204 | } | ||
205 | |||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | void ipu_cpmem_zero(struct ipuv3_channel *ch) | ||
210 | { | ||
211 | struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); | ||
212 | void __iomem *base = p; | ||
213 | int i; | ||
214 | |||
215 | for (i = 0; i < sizeof(*p) / sizeof(u32); i++) | ||
216 | writel(0, base + i * sizeof(u32)); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(ipu_cpmem_zero); | ||
219 | |||
220 | void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres) | ||
221 | { | ||
222 | ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1); | ||
223 | ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1); | ||
224 | } | ||
225 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution); | ||
226 | |||
227 | void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride) | ||
228 | { | ||
229 | ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1); | ||
230 | } | ||
231 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride); | ||
232 | |||
233 | void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch) | ||
234 | { | ||
235 | struct ipu_soc *ipu = ch->ipu; | ||
236 | u32 val; | ||
237 | |||
238 | if (ipu->ipu_type == IPUV3EX) | ||
239 | ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1); | ||
240 | |||
241 | val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num)); | ||
242 | val |= 1 << (ch->num % 32); | ||
243 | ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num)); | ||
244 | }; | ||
245 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); | ||
246 | |||
247 | void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) | ||
248 | { | ||
249 | if (bufnum) | ||
250 | ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); | ||
251 | else | ||
252 | ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3); | ||
253 | } | ||
254 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer); | ||
255 | |||
256 | void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) | ||
257 | { | ||
258 | ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); | ||
259 | ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8); | ||
260 | ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1); | ||
261 | }; | ||
262 | EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); | ||
263 | |||
264 | void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id) | ||
265 | { | ||
266 | id &= 0x3; | ||
267 | ipu_ch_param_write_field(ch, IPU_FIELD_ID, id); | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id); | ||
270 | |||
271 | void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize) | ||
272 | { | ||
273 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1); | ||
274 | }; | ||
275 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize); | ||
276 | |||
277 | void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch) | ||
278 | { | ||
279 | ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1); | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode); | ||
282 | |||
283 | void ipu_cpmem_set_rotation(struct ipuv3_channel *ch, | ||
284 | enum ipu_rotate_mode rot) | ||
285 | { | ||
286 | u32 temp_rot = bitrev8(rot) >> 5; | ||
287 | |||
288 | ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot); | ||
289 | } | ||
290 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation); | ||
291 | |||
292 | int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch, | ||
293 | const struct ipu_rgb *rgb) | ||
294 | { | ||
295 | int bpp = 0, npb = 0, ro, go, bo, to; | ||
296 | |||
297 | ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; | ||
298 | go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; | ||
299 | bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; | ||
300 | to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; | ||
301 | |||
302 | ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1); | ||
303 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro); | ||
304 | ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1); | ||
305 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go); | ||
306 | ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1); | ||
307 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo); | ||
308 | |||
309 | if (rgb->transp.length) { | ||
310 | ipu_ch_param_write_field(ch, IPU_FIELD_WID3, | ||
311 | rgb->transp.length - 1); | ||
312 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to); | ||
313 | } else { | ||
314 | ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7); | ||
315 | ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, | ||
316 | rgb->bits_per_pixel); | ||
317 | } | ||
318 | |||
319 | switch (rgb->bits_per_pixel) { | ||
320 | case 32: | ||
321 | bpp = 0; | ||
322 | npb = 15; | ||
323 | break; | ||
324 | case 24: | ||
325 | bpp = 1; | ||
326 | npb = 19; | ||
327 | break; | ||
328 | case 16: | ||
329 | bpp = 3; | ||
330 | npb = 31; | ||
331 | break; | ||
332 | case 8: | ||
333 | bpp = 5; | ||
334 | npb = 63; | ||
335 | break; | ||
336 | default: | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); | ||
340 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); | ||
341 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */ | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); | ||
346 | |||
347 | int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width) | ||
348 | { | ||
349 | int bpp = 0, npb = 0; | ||
350 | |||
351 | switch (width) { | ||
352 | case 32: | ||
353 | bpp = 0; | ||
354 | npb = 15; | ||
355 | break; | ||
356 | case 24: | ||
357 | bpp = 1; | ||
358 | npb = 19; | ||
359 | break; | ||
360 | case 16: | ||
361 | bpp = 3; | ||
362 | npb = 31; | ||
363 | break; | ||
364 | case 8: | ||
365 | bpp = 5; | ||
366 | npb = 63; | ||
367 | break; | ||
368 | default: | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); | ||
373 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); | ||
374 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */ | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); | ||
379 | |||
380 | void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format) | ||
381 | { | ||
382 | switch (pixel_format) { | ||
383 | case V4L2_PIX_FMT_UYVY: | ||
384 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
385 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */ | ||
386 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ | ||
387 | break; | ||
388 | case V4L2_PIX_FMT_YUYV: | ||
389 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ | ||
390 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */ | ||
391 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ | ||
392 | break; | ||
393 | } | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); | ||
396 | |||
397 | void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, | ||
398 | u32 pixel_format, int stride, | ||
399 | int u_offset, int v_offset) | ||
400 | { | ||
401 | switch (pixel_format) { | ||
402 | case V4L2_PIX_FMT_YUV420: | ||
403 | case V4L2_PIX_FMT_YUV422P: | ||
404 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
405 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); | ||
406 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); | ||
407 | break; | ||
408 | case V4L2_PIX_FMT_YVU420: | ||
409 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); | ||
410 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); | ||
411 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); | ||
412 | break; | ||
413 | case V4L2_PIX_FMT_NV12: | ||
414 | case V4L2_PIX_FMT_NV16: | ||
415 | ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1); | ||
416 | ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); | ||
417 | ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); | ||
418 | break; | ||
419 | } | ||
420 | } | ||
421 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); | ||
422 | |||
423 | void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, | ||
424 | u32 pixel_format, int stride, int height) | ||
425 | { | ||
426 | int u_offset, v_offset; | ||
427 | int uv_stride = 0; | ||
428 | |||
429 | switch (pixel_format) { | ||
430 | case V4L2_PIX_FMT_YUV420: | ||
431 | case V4L2_PIX_FMT_YVU420: | ||
432 | uv_stride = stride / 2; | ||
433 | u_offset = stride * height; | ||
434 | v_offset = u_offset + (uv_stride * height / 2); | ||
435 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
436 | u_offset, v_offset); | ||
437 | break; | ||
438 | case V4L2_PIX_FMT_YUV422P: | ||
439 | uv_stride = stride / 2; | ||
440 | u_offset = stride * height; | ||
441 | v_offset = u_offset + (uv_stride * height); | ||
442 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
443 | u_offset, v_offset); | ||
444 | break; | ||
445 | case V4L2_PIX_FMT_NV12: | ||
446 | case V4L2_PIX_FMT_NV16: | ||
447 | u_offset = stride * height; | ||
448 | ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, | ||
449 | u_offset, 0); | ||
450 | break; | ||
451 | } | ||
452 | } | ||
453 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); | ||
454 | |||
455 | static const struct ipu_rgb def_rgb_32 = { | ||
456 | .red = { .offset = 16, .length = 8, }, | ||
457 | .green = { .offset = 8, .length = 8, }, | ||
458 | .blue = { .offset = 0, .length = 8, }, | ||
459 | .transp = { .offset = 24, .length = 8, }, | ||
460 | .bits_per_pixel = 32, | ||
461 | }; | ||
462 | |||
463 | static const struct ipu_rgb def_bgr_32 = { | ||
464 | .red = { .offset = 0, .length = 8, }, | ||
465 | .green = { .offset = 8, .length = 8, }, | ||
466 | .blue = { .offset = 16, .length = 8, }, | ||
467 | .transp = { .offset = 24, .length = 8, }, | ||
468 | .bits_per_pixel = 32, | ||
469 | }; | ||
470 | |||
471 | static const struct ipu_rgb def_rgb_24 = { | ||
472 | .red = { .offset = 16, .length = 8, }, | ||
473 | .green = { .offset = 8, .length = 8, }, | ||
474 | .blue = { .offset = 0, .length = 8, }, | ||
475 | .transp = { .offset = 0, .length = 0, }, | ||
476 | .bits_per_pixel = 24, | ||
477 | }; | ||
478 | |||
479 | static const struct ipu_rgb def_bgr_24 = { | ||
480 | .red = { .offset = 0, .length = 8, }, | ||
481 | .green = { .offset = 8, .length = 8, }, | ||
482 | .blue = { .offset = 16, .length = 8, }, | ||
483 | .transp = { .offset = 0, .length = 0, }, | ||
484 | .bits_per_pixel = 24, | ||
485 | }; | ||
486 | |||
487 | static const struct ipu_rgb def_rgb_16 = { | ||
488 | .red = { .offset = 11, .length = 5, }, | ||
489 | .green = { .offset = 5, .length = 6, }, | ||
490 | .blue = { .offset = 0, .length = 5, }, | ||
491 | .transp = { .offset = 0, .length = 0, }, | ||
492 | .bits_per_pixel = 16, | ||
493 | }; | ||
494 | |||
495 | static const struct ipu_rgb def_bgr_16 = { | ||
496 | .red = { .offset = 0, .length = 5, }, | ||
497 | .green = { .offset = 5, .length = 6, }, | ||
498 | .blue = { .offset = 11, .length = 5, }, | ||
499 | .transp = { .offset = 0, .length = 0, }, | ||
500 | .bits_per_pixel = 16, | ||
501 | }; | ||
502 | |||
503 | #define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) | ||
504 | #define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
505 | (pix->width * (y) / 4) + (x) / 2) | ||
506 | #define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
507 | (pix->width * pix->height / 4) + \ | ||
508 | (pix->width * (y) / 4) + (x) / 2) | ||
509 | #define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
510 | (pix->width * (y) / 2) + (x) / 2) | ||
511 | #define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
512 | (pix->width * pix->height / 2) + \ | ||
513 | (pix->width * (y) / 2) + (x) / 2) | ||
514 | #define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
515 | (pix->width * (y) / 2) + (x)) | ||
516 | #define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ | ||
517 | (pix->width * y) + (x)) | ||
518 | |||
519 | int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) | ||
520 | { | ||
521 | switch (drm_fourcc) { | ||
522 | case DRM_FORMAT_YUV420: | ||
523 | case DRM_FORMAT_YVU420: | ||
524 | /* pix format */ | ||
525 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2); | ||
526 | /* burst size */ | ||
527 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
528 | break; | ||
529 | case DRM_FORMAT_YUV422: | ||
530 | case DRM_FORMAT_YVU422: | ||
531 | /* pix format */ | ||
532 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1); | ||
533 | /* burst size */ | ||
534 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
535 | break; | ||
536 | case DRM_FORMAT_NV12: | ||
537 | /* pix format */ | ||
538 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4); | ||
539 | /* burst size */ | ||
540 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
541 | break; | ||
542 | case DRM_FORMAT_NV16: | ||
543 | /* pix format */ | ||
544 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3); | ||
545 | /* burst size */ | ||
546 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
547 | break; | ||
548 | case DRM_FORMAT_UYVY: | ||
549 | /* bits/pixel */ | ||
550 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); | ||
551 | /* pix format */ | ||
552 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA); | ||
553 | /* burst size */ | ||
554 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
555 | break; | ||
556 | case DRM_FORMAT_YUYV: | ||
557 | /* bits/pixel */ | ||
558 | ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); | ||
559 | /* pix format */ | ||
560 | ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8); | ||
561 | /* burst size */ | ||
562 | ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); | ||
563 | break; | ||
564 | case DRM_FORMAT_ABGR8888: | ||
565 | case DRM_FORMAT_XBGR8888: | ||
566 | ipu_cpmem_set_format_rgb(ch, &def_bgr_32); | ||
567 | break; | ||
568 | case DRM_FORMAT_ARGB8888: | ||
569 | case DRM_FORMAT_XRGB8888: | ||
570 | ipu_cpmem_set_format_rgb(ch, &def_rgb_32); | ||
571 | break; | ||
572 | case DRM_FORMAT_BGR888: | ||
573 | ipu_cpmem_set_format_rgb(ch, &def_bgr_24); | ||
574 | break; | ||
575 | case DRM_FORMAT_RGB888: | ||
576 | ipu_cpmem_set_format_rgb(ch, &def_rgb_24); | ||
577 | break; | ||
578 | case DRM_FORMAT_RGB565: | ||
579 | ipu_cpmem_set_format_rgb(ch, &def_rgb_16); | ||
580 | break; | ||
581 | case DRM_FORMAT_BGR565: | ||
582 | ipu_cpmem_set_format_rgb(ch, &def_bgr_16); | ||
583 | break; | ||
584 | default: | ||
585 | return -EINVAL; | ||
586 | } | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); | ||
591 | |||
592 | int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) | ||
593 | { | ||
594 | struct v4l2_pix_format *pix = &image->pix; | ||
595 | int offset, u_offset, v_offset; | ||
596 | |||
597 | pr_debug("%s: resolution: %dx%d stride: %d\n", | ||
598 | __func__, pix->width, pix->height, | ||
599 | pix->bytesperline); | ||
600 | |||
601 | ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height); | ||
602 | ipu_cpmem_set_stride(ch, pix->bytesperline); | ||
603 | |||
604 | ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); | ||
605 | |||
606 | switch (pix->pixelformat) { | ||
607 | case V4L2_PIX_FMT_YUV420: | ||
608 | case V4L2_PIX_FMT_YVU420: | ||
609 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
610 | u_offset = U_OFFSET(pix, image->rect.left, | ||
611 | image->rect.top) - offset; | ||
612 | v_offset = V_OFFSET(pix, image->rect.left, | ||
613 | image->rect.top) - offset; | ||
614 | |||
615 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
616 | pix->bytesperline, | ||
617 | u_offset, v_offset); | ||
618 | break; | ||
619 | case V4L2_PIX_FMT_YUV422P: | ||
620 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
621 | u_offset = U2_OFFSET(pix, image->rect.left, | ||
622 | image->rect.top) - offset; | ||
623 | v_offset = V2_OFFSET(pix, image->rect.left, | ||
624 | image->rect.top) - offset; | ||
625 | |||
626 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
627 | pix->bytesperline, | ||
628 | u_offset, v_offset); | ||
629 | break; | ||
630 | case V4L2_PIX_FMT_NV12: | ||
631 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
632 | u_offset = UV_OFFSET(pix, image->rect.left, | ||
633 | image->rect.top) - offset; | ||
634 | v_offset = 0; | ||
635 | |||
636 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
637 | pix->bytesperline, | ||
638 | u_offset, v_offset); | ||
639 | break; | ||
640 | case V4L2_PIX_FMT_NV16: | ||
641 | offset = Y_OFFSET(pix, image->rect.left, image->rect.top); | ||
642 | u_offset = UV2_OFFSET(pix, image->rect.left, | ||
643 | image->rect.top) - offset; | ||
644 | v_offset = 0; | ||
645 | |||
646 | ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, | ||
647 | pix->bytesperline, | ||
648 | u_offset, v_offset); | ||
649 | break; | ||
650 | case V4L2_PIX_FMT_UYVY: | ||
651 | case V4L2_PIX_FMT_YUYV: | ||
652 | case V4L2_PIX_FMT_RGB565: | ||
653 | offset = image->rect.left * 2 + | ||
654 | image->rect.top * pix->bytesperline; | ||
655 | break; | ||
656 | case V4L2_PIX_FMT_RGB32: | ||
657 | case V4L2_PIX_FMT_BGR32: | ||
658 | offset = image->rect.left * 4 + | ||
659 | image->rect.top * pix->bytesperline; | ||
660 | break; | ||
661 | case V4L2_PIX_FMT_RGB24: | ||
662 | case V4L2_PIX_FMT_BGR24: | ||
663 | offset = image->rect.left * 3 + | ||
664 | image->rect.top * pix->bytesperline; | ||
665 | break; | ||
666 | default: | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | |||
670 | ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset); | ||
671 | ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset); | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); | ||
676 | |||
677 | void ipu_cpmem_dump(struct ipuv3_channel *ch) | ||
678 | { | ||
679 | struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); | ||
680 | struct ipu_soc *ipu = ch->ipu; | ||
681 | int chno = ch->num; | ||
682 | |||
683 | dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno, | ||
684 | readl(&p->word[0].data[0]), | ||
685 | readl(&p->word[0].data[1]), | ||
686 | readl(&p->word[0].data[2]), | ||
687 | readl(&p->word[0].data[3]), | ||
688 | readl(&p->word[0].data[4])); | ||
689 | dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno, | ||
690 | readl(&p->word[1].data[0]), | ||
691 | readl(&p->word[1].data[1]), | ||
692 | readl(&p->word[1].data[2]), | ||
693 | readl(&p->word[1].data[3]), | ||
694 | readl(&p->word[1].data[4])); | ||
695 | dev_dbg(ipu->dev, "PFS 0x%x, ", | ||
696 | ipu_ch_param_read_field(ch, IPU_FIELD_PFS)); | ||
697 | dev_dbg(ipu->dev, "BPP 0x%x, ", | ||
698 | ipu_ch_param_read_field(ch, IPU_FIELD_BPP)); | ||
699 | dev_dbg(ipu->dev, "NPB 0x%x\n", | ||
700 | ipu_ch_param_read_field(ch, IPU_FIELD_NPB)); | ||
701 | |||
702 | dev_dbg(ipu->dev, "FW %d, ", | ||
703 | ipu_ch_param_read_field(ch, IPU_FIELD_FW)); | ||
704 | dev_dbg(ipu->dev, "FH %d, ", | ||
705 | ipu_ch_param_read_field(ch, IPU_FIELD_FH)); | ||
706 | dev_dbg(ipu->dev, "EBA0 0x%x\n", | ||
707 | ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3); | ||
708 | dev_dbg(ipu->dev, "EBA1 0x%x\n", | ||
709 | ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3); | ||
710 | dev_dbg(ipu->dev, "Stride %d\n", | ||
711 | ipu_ch_param_read_field(ch, IPU_FIELD_SL)); | ||
712 | dev_dbg(ipu->dev, "scan_order %d\n", | ||
713 | ipu_ch_param_read_field(ch, IPU_FIELD_SO)); | ||
714 | dev_dbg(ipu->dev, "uv_stride %d\n", | ||
715 | ipu_ch_param_read_field(ch, IPU_FIELD_SLUV)); | ||
716 | dev_dbg(ipu->dev, "u_offset 0x%x\n", | ||
717 | ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3); | ||
718 | dev_dbg(ipu->dev, "v_offset 0x%x\n", | ||
719 | ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3); | ||
720 | |||
721 | dev_dbg(ipu->dev, "Width0 %d+1, ", | ||
722 | ipu_ch_param_read_field(ch, IPU_FIELD_WID0)); | ||
723 | dev_dbg(ipu->dev, "Width1 %d+1, ", | ||
724 | ipu_ch_param_read_field(ch, IPU_FIELD_WID1)); | ||
725 | dev_dbg(ipu->dev, "Width2 %d+1, ", | ||
726 | ipu_ch_param_read_field(ch, IPU_FIELD_WID2)); | ||
727 | dev_dbg(ipu->dev, "Width3 %d+1, ", | ||
728 | ipu_ch_param_read_field(ch, IPU_FIELD_WID3)); | ||
729 | dev_dbg(ipu->dev, "Offset0 %d, ", | ||
730 | ipu_ch_param_read_field(ch, IPU_FIELD_OFS0)); | ||
731 | dev_dbg(ipu->dev, "Offset1 %d, ", | ||
732 | ipu_ch_param_read_field(ch, IPU_FIELD_OFS1)); | ||
733 | dev_dbg(ipu->dev, "Offset2 %d, ", | ||
734 | ipu_ch_param_read_field(ch, IPU_FIELD_OFS2)); | ||
735 | dev_dbg(ipu->dev, "Offset3 %d\n", | ||
736 | ipu_ch_param_read_field(ch, IPU_FIELD_OFS3)); | ||
737 | } | ||
738 | EXPORT_SYMBOL_GPL(ipu_cpmem_dump); | ||
739 | |||
740 | int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) | ||
741 | { | ||
742 | struct ipu_cpmem *cpmem; | ||
743 | |||
744 | cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL); | ||
745 | if (!cpmem) | ||
746 | return -ENOMEM; | ||
747 | |||
748 | ipu->cpmem_priv = cpmem; | ||
749 | |||
750 | spin_lock_init(&cpmem->lock); | ||
751 | cpmem->base = devm_ioremap(dev, base, SZ_128K); | ||
752 | if (!cpmem->base) | ||
753 | return -ENOMEM; | ||
754 | |||
755 | dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n", | ||
756 | base, cpmem->base); | ||
757 | cpmem->ipu = ipu; | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | void ipu_cpmem_exit(struct ipu_soc *ipu) | ||
763 | { | ||
764 | } | ||
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c new file mode 100644 index 000000000000..d6f56471bd2a --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-csi.c | |||
@@ -0,0 +1,741 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012-2014 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/export.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | #include <uapi/linux/v4l2-mediabus.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/clk-provider.h> | ||
27 | #include <linux/clkdev.h> | ||
28 | |||
29 | #include "ipu-prv.h" | ||
30 | |||
31 | struct ipu_csi { | ||
32 | void __iomem *base; | ||
33 | int id; | ||
34 | u32 module; | ||
35 | struct clk *clk_ipu; /* IPU bus clock */ | ||
36 | spinlock_t lock; | ||
37 | bool inuse; | ||
38 | struct ipu_soc *ipu; | ||
39 | }; | ||
40 | |||
41 | /* CSI Register Offsets */ | ||
42 | #define CSI_SENS_CONF 0x0000 | ||
43 | #define CSI_SENS_FRM_SIZE 0x0004 | ||
44 | #define CSI_ACT_FRM_SIZE 0x0008 | ||
45 | #define CSI_OUT_FRM_CTRL 0x000c | ||
46 | #define CSI_TST_CTRL 0x0010 | ||
47 | #define CSI_CCIR_CODE_1 0x0014 | ||
48 | #define CSI_CCIR_CODE_2 0x0018 | ||
49 | #define CSI_CCIR_CODE_3 0x001c | ||
50 | #define CSI_MIPI_DI 0x0020 | ||
51 | #define CSI_SKIP 0x0024 | ||
52 | #define CSI_CPD_CTRL 0x0028 | ||
53 | #define CSI_CPD_RC(n) (0x002c + ((n)*4)) | ||
54 | #define CSI_CPD_RS(n) (0x004c + ((n)*4)) | ||
55 | #define CSI_CPD_GRC(n) (0x005c + ((n)*4)) | ||
56 | #define CSI_CPD_GRS(n) (0x007c + ((n)*4)) | ||
57 | #define CSI_CPD_GBC(n) (0x008c + ((n)*4)) | ||
58 | #define CSI_CPD_GBS(n) (0x00Ac + ((n)*4)) | ||
59 | #define CSI_CPD_BC(n) (0x00Bc + ((n)*4)) | ||
60 | #define CSI_CPD_BS(n) (0x00Dc + ((n)*4)) | ||
61 | #define CSI_CPD_OFFSET1 0x00ec | ||
62 | #define CSI_CPD_OFFSET2 0x00f0 | ||
63 | |||
64 | /* CSI Register Fields */ | ||
65 | #define CSI_SENS_CONF_DATA_FMT_SHIFT 8 | ||
66 | #define CSI_SENS_CONF_DATA_FMT_MASK 0x00000700 | ||
67 | #define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 0L | ||
68 | #define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L | ||
69 | #define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L | ||
70 | #define CSI_SENS_CONF_DATA_FMT_BAYER 3L | ||
71 | #define CSI_SENS_CONF_DATA_FMT_RGB565 4L | ||
72 | #define CSI_SENS_CONF_DATA_FMT_RGB555 5L | ||
73 | #define CSI_SENS_CONF_DATA_FMT_RGB444 6L | ||
74 | #define CSI_SENS_CONF_DATA_FMT_JPEG 7L | ||
75 | |||
76 | #define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 | ||
77 | #define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 | ||
78 | #define CSI_SENS_CONF_DATA_POL_SHIFT 2 | ||
79 | #define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 | ||
80 | #define CSI_SENS_CONF_SENS_PRTCL_MASK 0x00000070 | ||
81 | #define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 | ||
82 | #define CSI_SENS_CONF_PACK_TIGHT_SHIFT 7 | ||
83 | #define CSI_SENS_CONF_DATA_WIDTH_SHIFT 11 | ||
84 | #define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 | ||
85 | #define CSI_SENS_CONF_DIVRATIO_SHIFT 16 | ||
86 | |||
87 | #define CSI_SENS_CONF_DIVRATIO_MASK 0x00ff0000 | ||
88 | #define CSI_SENS_CONF_DATA_DEST_SHIFT 24 | ||
89 | #define CSI_SENS_CONF_DATA_DEST_MASK 0x07000000 | ||
90 | #define CSI_SENS_CONF_JPEG8_EN_SHIFT 27 | ||
91 | #define CSI_SENS_CONF_JPEG_EN_SHIFT 28 | ||
92 | #define CSI_SENS_CONF_FORCE_EOF_SHIFT 29 | ||
93 | #define CSI_SENS_CONF_DATA_EN_POL_SHIFT 31 | ||
94 | |||
95 | #define CSI_DATA_DEST_IC 2 | ||
96 | #define CSI_DATA_DEST_IDMAC 4 | ||
97 | |||
98 | #define CSI_CCIR_ERR_DET_EN 0x01000000 | ||
99 | #define CSI_HORI_DOWNSIZE_EN 0x80000000 | ||
100 | #define CSI_VERT_DOWNSIZE_EN 0x40000000 | ||
101 | #define CSI_TEST_GEN_MODE_EN 0x01000000 | ||
102 | |||
103 | #define CSI_HSC_MASK 0x1fff0000 | ||
104 | #define CSI_HSC_SHIFT 16 | ||
105 | #define CSI_VSC_MASK 0x00000fff | ||
106 | #define CSI_VSC_SHIFT 0 | ||
107 | |||
108 | #define CSI_TEST_GEN_R_MASK 0x000000ff | ||
109 | #define CSI_TEST_GEN_R_SHIFT 0 | ||
110 | #define CSI_TEST_GEN_G_MASK 0x0000ff00 | ||
111 | #define CSI_TEST_GEN_G_SHIFT 8 | ||
112 | #define CSI_TEST_GEN_B_MASK 0x00ff0000 | ||
113 | #define CSI_TEST_GEN_B_SHIFT 16 | ||
114 | |||
115 | #define CSI_MAX_RATIO_SKIP_SMFC_MASK 0x00000007 | ||
116 | #define CSI_MAX_RATIO_SKIP_SMFC_SHIFT 0 | ||
117 | #define CSI_SKIP_SMFC_MASK 0x000000f8 | ||
118 | #define CSI_SKIP_SMFC_SHIFT 3 | ||
119 | #define CSI_ID_2_SKIP_MASK 0x00000300 | ||
120 | #define CSI_ID_2_SKIP_SHIFT 8 | ||
121 | |||
122 | #define CSI_COLOR_FIRST_ROW_MASK 0x00000002 | ||
123 | #define CSI_COLOR_FIRST_COMP_MASK 0x00000001 | ||
124 | |||
125 | /* MIPI CSI-2 data types */ | ||
126 | #define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */ | ||
127 | #define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */ | ||
128 | #define MIPI_DT_YUV422 0x1e /* UYVY... */ | ||
129 | #define MIPI_DT_RGB444 0x20 | ||
130 | #define MIPI_DT_RGB555 0x21 | ||
131 | #define MIPI_DT_RGB565 0x22 | ||
132 | #define MIPI_DT_RGB666 0x23 | ||
133 | #define MIPI_DT_RGB888 0x24 | ||
134 | #define MIPI_DT_RAW6 0x28 | ||
135 | #define MIPI_DT_RAW7 0x29 | ||
136 | #define MIPI_DT_RAW8 0x2a | ||
137 | #define MIPI_DT_RAW10 0x2b | ||
138 | #define MIPI_DT_RAW12 0x2c | ||
139 | #define MIPI_DT_RAW14 0x2d | ||
140 | |||
141 | /* | ||
142 | * Bitfield of CSI bus signal polarities and modes. | ||
143 | */ | ||
144 | struct ipu_csi_bus_config { | ||
145 | unsigned data_width:4; | ||
146 | unsigned clk_mode:3; | ||
147 | unsigned ext_vsync:1; | ||
148 | unsigned vsync_pol:1; | ||
149 | unsigned hsync_pol:1; | ||
150 | unsigned pixclk_pol:1; | ||
151 | unsigned data_pol:1; | ||
152 | unsigned sens_clksrc:1; | ||
153 | unsigned pack_tight:1; | ||
154 | unsigned force_eof:1; | ||
155 | unsigned data_en_pol:1; | ||
156 | |||
157 | unsigned data_fmt; | ||
158 | unsigned mipi_dt; | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * Enumeration of CSI data bus widths. | ||
163 | */ | ||
164 | enum ipu_csi_data_width { | ||
165 | IPU_CSI_DATA_WIDTH_4 = 0, | ||
166 | IPU_CSI_DATA_WIDTH_8 = 1, | ||
167 | IPU_CSI_DATA_WIDTH_10 = 3, | ||
168 | IPU_CSI_DATA_WIDTH_12 = 5, | ||
169 | IPU_CSI_DATA_WIDTH_16 = 9, | ||
170 | }; | ||
171 | |||
172 | /* | ||
173 | * Enumeration of CSI clock modes. | ||
174 | */ | ||
175 | enum ipu_csi_clk_mode { | ||
176 | IPU_CSI_CLK_MODE_GATED_CLK, | ||
177 | IPU_CSI_CLK_MODE_NONGATED_CLK, | ||
178 | IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE, | ||
179 | IPU_CSI_CLK_MODE_CCIR656_INTERLACED, | ||
180 | IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR, | ||
181 | IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR, | ||
182 | IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR, | ||
183 | IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR, | ||
184 | }; | ||
185 | |||
186 | static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset) | ||
187 | { | ||
188 | return readl(csi->base + offset); | ||
189 | } | ||
190 | |||
191 | static inline void ipu_csi_write(struct ipu_csi *csi, u32 value, | ||
192 | unsigned offset) | ||
193 | { | ||
194 | writel(value, csi->base + offset); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Set mclk division ratio for generating test mode mclk. Only used | ||
199 | * for test generator. | ||
200 | */ | ||
201 | static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk, | ||
202 | u32 ipu_clk) | ||
203 | { | ||
204 | u32 temp; | ||
205 | u32 div_ratio; | ||
206 | |||
207 | div_ratio = (ipu_clk / pixel_clk) - 1; | ||
208 | |||
209 | if (div_ratio > 0xFF || div_ratio < 0) { | ||
210 | dev_err(csi->ipu->dev, | ||
211 | "value of pixel_clk extends normal range\n"); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | |||
215 | temp = ipu_csi_read(csi, CSI_SENS_CONF); | ||
216 | temp &= ~CSI_SENS_CONF_DIVRATIO_MASK; | ||
217 | ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT), | ||
218 | CSI_SENS_CONF); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Find the CSI data format and data width for the given V4L2 media | ||
225 | * bus pixel format code. | ||
226 | */ | ||
227 | static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) | ||
228 | { | ||
229 | switch (mbus_code) { | ||
230 | case V4L2_MBUS_FMT_BGR565_2X8_BE: | ||
231 | case V4L2_MBUS_FMT_BGR565_2X8_LE: | ||
232 | case V4L2_MBUS_FMT_RGB565_2X8_BE: | ||
233 | case V4L2_MBUS_FMT_RGB565_2X8_LE: | ||
234 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; | ||
235 | cfg->mipi_dt = MIPI_DT_RGB565; | ||
236 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
237 | break; | ||
238 | case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE: | ||
239 | case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE: | ||
240 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444; | ||
241 | cfg->mipi_dt = MIPI_DT_RGB444; | ||
242 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
243 | break; | ||
244 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE: | ||
245 | case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: | ||
246 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555; | ||
247 | cfg->mipi_dt = MIPI_DT_RGB555; | ||
248 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
249 | break; | ||
250 | case V4L2_MBUS_FMT_UYVY8_2X8: | ||
251 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; | ||
252 | cfg->mipi_dt = MIPI_DT_YUV422; | ||
253 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
254 | break; | ||
255 | case V4L2_MBUS_FMT_YUYV8_2X8: | ||
256 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; | ||
257 | cfg->mipi_dt = MIPI_DT_YUV422; | ||
258 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
259 | break; | ||
260 | case V4L2_MBUS_FMT_UYVY8_1X16: | ||
261 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; | ||
262 | cfg->mipi_dt = MIPI_DT_YUV422; | ||
263 | cfg->data_width = IPU_CSI_DATA_WIDTH_16; | ||
264 | break; | ||
265 | case V4L2_MBUS_FMT_YUYV8_1X16: | ||
266 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; | ||
267 | cfg->mipi_dt = MIPI_DT_YUV422; | ||
268 | cfg->data_width = IPU_CSI_DATA_WIDTH_16; | ||
269 | break; | ||
270 | case V4L2_MBUS_FMT_SBGGR8_1X8: | ||
271 | case V4L2_MBUS_FMT_SGBRG8_1X8: | ||
272 | case V4L2_MBUS_FMT_SGRBG8_1X8: | ||
273 | case V4L2_MBUS_FMT_SRGGB8_1X8: | ||
274 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; | ||
275 | cfg->mipi_dt = MIPI_DT_RAW8; | ||
276 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
277 | break; | ||
278 | case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: | ||
279 | case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: | ||
280 | case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: | ||
281 | case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: | ||
282 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: | ||
283 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: | ||
284 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: | ||
285 | case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: | ||
286 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; | ||
287 | cfg->mipi_dt = MIPI_DT_RAW10; | ||
288 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
289 | break; | ||
290 | case V4L2_MBUS_FMT_SBGGR10_1X10: | ||
291 | case V4L2_MBUS_FMT_SGBRG10_1X10: | ||
292 | case V4L2_MBUS_FMT_SGRBG10_1X10: | ||
293 | case V4L2_MBUS_FMT_SRGGB10_1X10: | ||
294 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; | ||
295 | cfg->mipi_dt = MIPI_DT_RAW10; | ||
296 | cfg->data_width = IPU_CSI_DATA_WIDTH_10; | ||
297 | break; | ||
298 | case V4L2_MBUS_FMT_SBGGR12_1X12: | ||
299 | case V4L2_MBUS_FMT_SGBRG12_1X12: | ||
300 | case V4L2_MBUS_FMT_SGRBG12_1X12: | ||
301 | case V4L2_MBUS_FMT_SRGGB12_1X12: | ||
302 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; | ||
303 | cfg->mipi_dt = MIPI_DT_RAW12; | ||
304 | cfg->data_width = IPU_CSI_DATA_WIDTH_12; | ||
305 | break; | ||
306 | case V4L2_MBUS_FMT_JPEG_1X8: | ||
307 | /* TODO */ | ||
308 | cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG; | ||
309 | cfg->mipi_dt = MIPI_DT_RAW8; | ||
310 | cfg->data_width = IPU_CSI_DATA_WIDTH_8; | ||
311 | break; | ||
312 | default: | ||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Fill a CSI bus config struct from mbus_config and mbus_framefmt. | ||
321 | */ | ||
322 | static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, | ||
323 | struct v4l2_mbus_config *mbus_cfg, | ||
324 | struct v4l2_mbus_framefmt *mbus_fmt) | ||
325 | { | ||
326 | memset(csicfg, 0, sizeof(*csicfg)); | ||
327 | |||
328 | mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); | ||
329 | |||
330 | switch (mbus_cfg->type) { | ||
331 | case V4L2_MBUS_PARALLEL: | ||
332 | csicfg->ext_vsync = 1; | ||
333 | csicfg->vsync_pol = (mbus_cfg->flags & | ||
334 | V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0; | ||
335 | csicfg->hsync_pol = (mbus_cfg->flags & | ||
336 | V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0; | ||
337 | csicfg->pixclk_pol = (mbus_cfg->flags & | ||
338 | V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0; | ||
339 | csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; | ||
340 | break; | ||
341 | case V4L2_MBUS_BT656: | ||
342 | csicfg->ext_vsync = 0; | ||
343 | if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field)) | ||
344 | csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; | ||
345 | else | ||
346 | csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; | ||
347 | break; | ||
348 | case V4L2_MBUS_CSI2: | ||
349 | /* | ||
350 | * MIPI CSI-2 requires non gated clock mode, all other | ||
351 | * parameters are not applicable for MIPI CSI-2 bus. | ||
352 | */ | ||
353 | csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK; | ||
354 | break; | ||
355 | default: | ||
356 | /* will never get here, keep compiler quiet */ | ||
357 | break; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | int ipu_csi_init_interface(struct ipu_csi *csi, | ||
362 | struct v4l2_mbus_config *mbus_cfg, | ||
363 | struct v4l2_mbus_framefmt *mbus_fmt) | ||
364 | { | ||
365 | struct ipu_csi_bus_config cfg; | ||
366 | unsigned long flags; | ||
367 | u32 data = 0; | ||
368 | |||
369 | fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); | ||
370 | |||
371 | /* Set the CSI_SENS_CONF register remaining fields */ | ||
372 | data |= cfg.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT | | ||
373 | cfg.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT | | ||
374 | cfg.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT | | ||
375 | cfg.vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT | | ||
376 | cfg.hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT | | ||
377 | cfg.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT | | ||
378 | cfg.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT | | ||
379 | cfg.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT | | ||
380 | cfg.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT | | ||
381 | cfg.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT | | ||
382 | cfg.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT; | ||
383 | |||
384 | spin_lock_irqsave(&csi->lock, flags); | ||
385 | |||
386 | ipu_csi_write(csi, data, CSI_SENS_CONF); | ||
387 | |||
388 | /* Setup sensor frame size */ | ||
389 | ipu_csi_write(csi, | ||
390 | (mbus_fmt->width - 1) | ((mbus_fmt->height - 1) << 16), | ||
391 | CSI_SENS_FRM_SIZE); | ||
392 | |||
393 | /* Set CCIR registers */ | ||
394 | |||
395 | switch (cfg.clk_mode) { | ||
396 | case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: | ||
397 | ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1); | ||
398 | ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); | ||
399 | break; | ||
400 | case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: | ||
401 | if (mbus_fmt->width == 720 && mbus_fmt->height == 576) { | ||
402 | /* | ||
403 | * PAL case | ||
404 | * | ||
405 | * Field0BlankEnd = 0x6, Field0BlankStart = 0x2, | ||
406 | * Field0ActiveEnd = 0x4, Field0ActiveStart = 0 | ||
407 | * Field1BlankEnd = 0x7, Field1BlankStart = 0x3, | ||
408 | * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1 | ||
409 | */ | ||
410 | ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN, | ||
411 | CSI_CCIR_CODE_1); | ||
412 | ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2); | ||
413 | ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); | ||
414 | |||
415 | } else if (mbus_fmt->width == 720 && mbus_fmt->height == 480) { | ||
416 | /* | ||
417 | * NTSC case | ||
418 | * | ||
419 | * Field0BlankEnd = 0x7, Field0BlankStart = 0x3, | ||
420 | * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1 | ||
421 | * Field1BlankEnd = 0x6, Field1BlankStart = 0x2, | ||
422 | * Field1ActiveEnd = 0x4, Field1ActiveStart = 0 | ||
423 | */ | ||
424 | ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN, | ||
425 | CSI_CCIR_CODE_1); | ||
426 | ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2); | ||
427 | ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); | ||
428 | } else { | ||
429 | dev_err(csi->ipu->dev, | ||
430 | "Unsupported CCIR656 interlaced video mode\n"); | ||
431 | spin_unlock_irqrestore(&csi->lock, flags); | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | break; | ||
435 | case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: | ||
436 | case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: | ||
437 | case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: | ||
438 | case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: | ||
439 | ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN, | ||
440 | CSI_CCIR_CODE_1); | ||
441 | ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); | ||
442 | break; | ||
443 | case IPU_CSI_CLK_MODE_GATED_CLK: | ||
444 | case IPU_CSI_CLK_MODE_NONGATED_CLK: | ||
445 | ipu_csi_write(csi, 0, CSI_CCIR_CODE_1); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n", | ||
450 | ipu_csi_read(csi, CSI_SENS_CONF)); | ||
451 | dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n", | ||
452 | ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); | ||
453 | |||
454 | spin_unlock_irqrestore(&csi->lock, flags); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | EXPORT_SYMBOL_GPL(ipu_csi_init_interface); | ||
459 | |||
460 | bool ipu_csi_is_interlaced(struct ipu_csi *csi) | ||
461 | { | ||
462 | unsigned long flags; | ||
463 | u32 sensor_protocol; | ||
464 | |||
465 | spin_lock_irqsave(&csi->lock, flags); | ||
466 | sensor_protocol = | ||
467 | (ipu_csi_read(csi, CSI_SENS_CONF) & | ||
468 | CSI_SENS_CONF_SENS_PRTCL_MASK) >> | ||
469 | CSI_SENS_CONF_SENS_PRTCL_SHIFT; | ||
470 | spin_unlock_irqrestore(&csi->lock, flags); | ||
471 | |||
472 | switch (sensor_protocol) { | ||
473 | case IPU_CSI_CLK_MODE_GATED_CLK: | ||
474 | case IPU_CSI_CLK_MODE_NONGATED_CLK: | ||
475 | case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: | ||
476 | case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: | ||
477 | case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: | ||
478 | return false; | ||
479 | case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: | ||
480 | case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: | ||
481 | case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: | ||
482 | return true; | ||
483 | default: | ||
484 | dev_err(csi->ipu->dev, | ||
485 | "CSI %d sensor protocol unsupported\n", csi->id); | ||
486 | return false; | ||
487 | } | ||
488 | } | ||
489 | EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced); | ||
490 | |||
491 | void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w) | ||
492 | { | ||
493 | unsigned long flags; | ||
494 | u32 reg; | ||
495 | |||
496 | spin_lock_irqsave(&csi->lock, flags); | ||
497 | |||
498 | reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE); | ||
499 | w->width = (reg & 0xFFFF) + 1; | ||
500 | w->height = (reg >> 16 & 0xFFFF) + 1; | ||
501 | |||
502 | reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); | ||
503 | w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT; | ||
504 | w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT; | ||
505 | |||
506 | spin_unlock_irqrestore(&csi->lock, flags); | ||
507 | } | ||
508 | EXPORT_SYMBOL_GPL(ipu_csi_get_window); | ||
509 | |||
510 | void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w) | ||
511 | { | ||
512 | unsigned long flags; | ||
513 | u32 reg; | ||
514 | |||
515 | spin_lock_irqsave(&csi->lock, flags); | ||
516 | |||
517 | ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16), | ||
518 | CSI_ACT_FRM_SIZE); | ||
519 | |||
520 | reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); | ||
521 | reg &= ~(CSI_HSC_MASK | CSI_VSC_MASK); | ||
522 | reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT)); | ||
523 | ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL); | ||
524 | |||
525 | spin_unlock_irqrestore(&csi->lock, flags); | ||
526 | } | ||
527 | EXPORT_SYMBOL_GPL(ipu_csi_set_window); | ||
528 | |||
529 | void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, | ||
530 | u32 r_value, u32 g_value, u32 b_value, | ||
531 | u32 pix_clk) | ||
532 | { | ||
533 | unsigned long flags; | ||
534 | u32 ipu_clk = clk_get_rate(csi->clk_ipu); | ||
535 | u32 temp; | ||
536 | |||
537 | spin_lock_irqsave(&csi->lock, flags); | ||
538 | |||
539 | temp = ipu_csi_read(csi, CSI_TST_CTRL); | ||
540 | |||
541 | if (active == false) { | ||
542 | temp &= ~CSI_TEST_GEN_MODE_EN; | ||
543 | ipu_csi_write(csi, temp, CSI_TST_CTRL); | ||
544 | } else { | ||
545 | /* Set sensb_mclk div_ratio */ | ||
546 | ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk); | ||
547 | |||
548 | temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK | | ||
549 | CSI_TEST_GEN_B_MASK); | ||
550 | temp |= CSI_TEST_GEN_MODE_EN; | ||
551 | temp |= (r_value << CSI_TEST_GEN_R_SHIFT) | | ||
552 | (g_value << CSI_TEST_GEN_G_SHIFT) | | ||
553 | (b_value << CSI_TEST_GEN_B_SHIFT); | ||
554 | ipu_csi_write(csi, temp, CSI_TST_CTRL); | ||
555 | } | ||
556 | |||
557 | spin_unlock_irqrestore(&csi->lock, flags); | ||
558 | } | ||
559 | EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator); | ||
560 | |||
561 | int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, | ||
562 | struct v4l2_mbus_framefmt *mbus_fmt) | ||
563 | { | ||
564 | struct ipu_csi_bus_config cfg; | ||
565 | unsigned long flags; | ||
566 | u32 temp; | ||
567 | |||
568 | if (vc > 3) | ||
569 | return -EINVAL; | ||
570 | |||
571 | mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); | ||
572 | |||
573 | spin_lock_irqsave(&csi->lock, flags); | ||
574 | |||
575 | temp = ipu_csi_read(csi, CSI_MIPI_DI); | ||
576 | temp &= ~(0xff << (vc * 8)); | ||
577 | temp |= (cfg.mipi_dt << (vc * 8)); | ||
578 | ipu_csi_write(csi, temp, CSI_MIPI_DI); | ||
579 | |||
580 | spin_unlock_irqrestore(&csi->lock, flags); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype); | ||
585 | |||
586 | int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip, | ||
587 | u32 max_ratio, u32 id) | ||
588 | { | ||
589 | unsigned long flags; | ||
590 | u32 temp; | ||
591 | |||
592 | if (max_ratio > 5 || id > 3) | ||
593 | return -EINVAL; | ||
594 | |||
595 | spin_lock_irqsave(&csi->lock, flags); | ||
596 | |||
597 | temp = ipu_csi_read(csi, CSI_SKIP); | ||
598 | temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK | | ||
599 | CSI_SKIP_SMFC_MASK); | ||
600 | temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) | | ||
601 | (id << CSI_ID_2_SKIP_SHIFT) | | ||
602 | (skip << CSI_SKIP_SMFC_SHIFT); | ||
603 | ipu_csi_write(csi, temp, CSI_SKIP); | ||
604 | |||
605 | spin_unlock_irqrestore(&csi->lock, flags); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc); | ||
610 | |||
611 | int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest) | ||
612 | { | ||
613 | unsigned long flags; | ||
614 | u32 csi_sens_conf, dest; | ||
615 | |||
616 | if (csi_dest == IPU_CSI_DEST_IDMAC) | ||
617 | dest = CSI_DATA_DEST_IDMAC; | ||
618 | else | ||
619 | dest = CSI_DATA_DEST_IC; /* IC or VDIC */ | ||
620 | |||
621 | spin_lock_irqsave(&csi->lock, flags); | ||
622 | |||
623 | csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF); | ||
624 | csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK; | ||
625 | csi_sens_conf |= (dest << CSI_SENS_CONF_DATA_DEST_SHIFT); | ||
626 | ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF); | ||
627 | |||
628 | spin_unlock_irqrestore(&csi->lock, flags); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | EXPORT_SYMBOL_GPL(ipu_csi_set_dest); | ||
633 | |||
634 | int ipu_csi_enable(struct ipu_csi *csi) | ||
635 | { | ||
636 | ipu_module_enable(csi->ipu, csi->module); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | EXPORT_SYMBOL_GPL(ipu_csi_enable); | ||
641 | |||
642 | int ipu_csi_disable(struct ipu_csi *csi) | ||
643 | { | ||
644 | ipu_module_disable(csi->ipu, csi->module); | ||
645 | |||
646 | return 0; | ||
647 | } | ||
648 | EXPORT_SYMBOL_GPL(ipu_csi_disable); | ||
649 | |||
650 | struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id) | ||
651 | { | ||
652 | unsigned long flags; | ||
653 | struct ipu_csi *csi, *ret; | ||
654 | |||
655 | if (id > 1) | ||
656 | return ERR_PTR(-EINVAL); | ||
657 | |||
658 | csi = ipu->csi_priv[id]; | ||
659 | ret = csi; | ||
660 | |||
661 | spin_lock_irqsave(&csi->lock, flags); | ||
662 | |||
663 | if (csi->inuse) { | ||
664 | ret = ERR_PTR(-EBUSY); | ||
665 | goto unlock; | ||
666 | } | ||
667 | |||
668 | csi->inuse = true; | ||
669 | unlock: | ||
670 | spin_unlock_irqrestore(&csi->lock, flags); | ||
671 | return ret; | ||
672 | } | ||
673 | EXPORT_SYMBOL_GPL(ipu_csi_get); | ||
674 | |||
675 | void ipu_csi_put(struct ipu_csi *csi) | ||
676 | { | ||
677 | unsigned long flags; | ||
678 | |||
679 | spin_lock_irqsave(&csi->lock, flags); | ||
680 | csi->inuse = false; | ||
681 | spin_unlock_irqrestore(&csi->lock, flags); | ||
682 | } | ||
683 | EXPORT_SYMBOL_GPL(ipu_csi_put); | ||
684 | |||
685 | int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id, | ||
686 | unsigned long base, u32 module, struct clk *clk_ipu) | ||
687 | { | ||
688 | struct ipu_csi *csi; | ||
689 | |||
690 | if (id > 1) | ||
691 | return -ENODEV; | ||
692 | |||
693 | csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL); | ||
694 | if (!csi) | ||
695 | return -ENOMEM; | ||
696 | |||
697 | ipu->csi_priv[id] = csi; | ||
698 | |||
699 | spin_lock_init(&csi->lock); | ||
700 | csi->module = module; | ||
701 | csi->id = id; | ||
702 | csi->clk_ipu = clk_ipu; | ||
703 | csi->base = devm_ioremap(dev, base, PAGE_SIZE); | ||
704 | if (!csi->base) | ||
705 | return -ENOMEM; | ||
706 | |||
707 | dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n", | ||
708 | id, base, csi->base); | ||
709 | csi->ipu = ipu; | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | void ipu_csi_exit(struct ipu_soc *ipu, int id) | ||
715 | { | ||
716 | } | ||
717 | |||
718 | void ipu_csi_dump(struct ipu_csi *csi) | ||
719 | { | ||
720 | dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n", | ||
721 | ipu_csi_read(csi, CSI_SENS_CONF)); | ||
722 | dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n", | ||
723 | ipu_csi_read(csi, CSI_SENS_FRM_SIZE)); | ||
724 | dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n", | ||
725 | ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); | ||
726 | dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n", | ||
727 | ipu_csi_read(csi, CSI_OUT_FRM_CTRL)); | ||
728 | dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n", | ||
729 | ipu_csi_read(csi, CSI_TST_CTRL)); | ||
730 | dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n", | ||
731 | ipu_csi_read(csi, CSI_CCIR_CODE_1)); | ||
732 | dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n", | ||
733 | ipu_csi_read(csi, CSI_CCIR_CODE_2)); | ||
734 | dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n", | ||
735 | ipu_csi_read(csi, CSI_CCIR_CODE_3)); | ||
736 | dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n", | ||
737 | ipu_csi_read(csi, CSI_MIPI_DI)); | ||
738 | dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n", | ||
739 | ipu_csi_read(csi, CSI_SKIP)); | ||
740 | } | ||
741 | EXPORT_SYMBOL_GPL(ipu_csi_dump); | ||
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c new file mode 100644 index 000000000000..ad75588e1629 --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-ic.c | |||
@@ -0,0 +1,778 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012-2014 Mentor Graphics Inc. | ||
3 | * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/bitrev.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/err.h> | ||
20 | #include "ipu-prv.h" | ||
21 | |||
22 | /* IC Register Offsets */ | ||
23 | #define IC_CONF 0x0000 | ||
24 | #define IC_PRP_ENC_RSC 0x0004 | ||
25 | #define IC_PRP_VF_RSC 0x0008 | ||
26 | #define IC_PP_RSC 0x000C | ||
27 | #define IC_CMBP_1 0x0010 | ||
28 | #define IC_CMBP_2 0x0014 | ||
29 | #define IC_IDMAC_1 0x0018 | ||
30 | #define IC_IDMAC_2 0x001C | ||
31 | #define IC_IDMAC_3 0x0020 | ||
32 | #define IC_IDMAC_4 0x0024 | ||
33 | |||
34 | /* IC Register Fields */ | ||
35 | #define IC_CONF_PRPENC_EN (1 << 0) | ||
36 | #define IC_CONF_PRPENC_CSC1 (1 << 1) | ||
37 | #define IC_CONF_PRPENC_ROT_EN (1 << 2) | ||
38 | #define IC_CONF_PRPVF_EN (1 << 8) | ||
39 | #define IC_CONF_PRPVF_CSC1 (1 << 9) | ||
40 | #define IC_CONF_PRPVF_CSC2 (1 << 10) | ||
41 | #define IC_CONF_PRPVF_CMB (1 << 11) | ||
42 | #define IC_CONF_PRPVF_ROT_EN (1 << 12) | ||
43 | #define IC_CONF_PP_EN (1 << 16) | ||
44 | #define IC_CONF_PP_CSC1 (1 << 17) | ||
45 | #define IC_CONF_PP_CSC2 (1 << 18) | ||
46 | #define IC_CONF_PP_CMB (1 << 19) | ||
47 | #define IC_CONF_PP_ROT_EN (1 << 20) | ||
48 | #define IC_CONF_IC_GLB_LOC_A (1 << 28) | ||
49 | #define IC_CONF_KEY_COLOR_EN (1 << 29) | ||
50 | #define IC_CONF_RWS_EN (1 << 30) | ||
51 | #define IC_CONF_CSI_MEM_WR_EN (1 << 31) | ||
52 | |||
53 | #define IC_IDMAC_1_CB0_BURST_16 (1 << 0) | ||
54 | #define IC_IDMAC_1_CB1_BURST_16 (1 << 1) | ||
55 | #define IC_IDMAC_1_CB2_BURST_16 (1 << 2) | ||
56 | #define IC_IDMAC_1_CB3_BURST_16 (1 << 3) | ||
57 | #define IC_IDMAC_1_CB4_BURST_16 (1 << 4) | ||
58 | #define IC_IDMAC_1_CB5_BURST_16 (1 << 5) | ||
59 | #define IC_IDMAC_1_CB6_BURST_16 (1 << 6) | ||
60 | #define IC_IDMAC_1_CB7_BURST_16 (1 << 7) | ||
61 | #define IC_IDMAC_1_PRPENC_ROT_MASK (0x7 << 11) | ||
62 | #define IC_IDMAC_1_PRPENC_ROT_OFFSET 11 | ||
63 | #define IC_IDMAC_1_PRPVF_ROT_MASK (0x7 << 14) | ||
64 | #define IC_IDMAC_1_PRPVF_ROT_OFFSET 14 | ||
65 | #define IC_IDMAC_1_PP_ROT_MASK (0x7 << 17) | ||
66 | #define IC_IDMAC_1_PP_ROT_OFFSET 17 | ||
67 | #define IC_IDMAC_1_PP_FLIP_RS (1 << 22) | ||
68 | #define IC_IDMAC_1_PRPVF_FLIP_RS (1 << 21) | ||
69 | #define IC_IDMAC_1_PRPENC_FLIP_RS (1 << 20) | ||
70 | |||
71 | #define IC_IDMAC_2_PRPENC_HEIGHT_MASK (0x3ff << 0) | ||
72 | #define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0 | ||
73 | #define IC_IDMAC_2_PRPVF_HEIGHT_MASK (0x3ff << 10) | ||
74 | #define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET 10 | ||
75 | #define IC_IDMAC_2_PP_HEIGHT_MASK (0x3ff << 20) | ||
76 | #define IC_IDMAC_2_PP_HEIGHT_OFFSET 20 | ||
77 | |||
78 | #define IC_IDMAC_3_PRPENC_WIDTH_MASK (0x3ff << 0) | ||
79 | #define IC_IDMAC_3_PRPENC_WIDTH_OFFSET 0 | ||
80 | #define IC_IDMAC_3_PRPVF_WIDTH_MASK (0x3ff << 10) | ||
81 | #define IC_IDMAC_3_PRPVF_WIDTH_OFFSET 10 | ||
82 | #define IC_IDMAC_3_PP_WIDTH_MASK (0x3ff << 20) | ||
83 | #define IC_IDMAC_3_PP_WIDTH_OFFSET 20 | ||
84 | |||
85 | struct ic_task_regoffs { | ||
86 | u32 rsc; | ||
87 | u32 tpmem_csc[2]; | ||
88 | }; | ||
89 | |||
90 | struct ic_task_bitfields { | ||
91 | u32 ic_conf_en; | ||
92 | u32 ic_conf_rot_en; | ||
93 | u32 ic_conf_cmb_en; | ||
94 | u32 ic_conf_csc1_en; | ||
95 | u32 ic_conf_csc2_en; | ||
96 | u32 ic_cmb_galpha_bit; | ||
97 | }; | ||
98 | |||
99 | static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = { | ||
100 | [IC_TASK_ENCODER] = { | ||
101 | .rsc = IC_PRP_ENC_RSC, | ||
102 | .tpmem_csc = {0x2008, 0}, | ||
103 | }, | ||
104 | [IC_TASK_VIEWFINDER] = { | ||
105 | .rsc = IC_PRP_VF_RSC, | ||
106 | .tpmem_csc = {0x4028, 0x4040}, | ||
107 | }, | ||
108 | [IC_TASK_POST_PROCESSOR] = { | ||
109 | .rsc = IC_PP_RSC, | ||
110 | .tpmem_csc = {0x6060, 0x6078}, | ||
111 | }, | ||
112 | }; | ||
113 | |||
114 | static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = { | ||
115 | [IC_TASK_ENCODER] = { | ||
116 | .ic_conf_en = IC_CONF_PRPENC_EN, | ||
117 | .ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN, | ||
118 | .ic_conf_cmb_en = 0, /* NA */ | ||
119 | .ic_conf_csc1_en = IC_CONF_PRPENC_CSC1, | ||
120 | .ic_conf_csc2_en = 0, /* NA */ | ||
121 | .ic_cmb_galpha_bit = 0, /* NA */ | ||
122 | }, | ||
123 | [IC_TASK_VIEWFINDER] = { | ||
124 | .ic_conf_en = IC_CONF_PRPVF_EN, | ||
125 | .ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN, | ||
126 | .ic_conf_cmb_en = IC_CONF_PRPVF_CMB, | ||
127 | .ic_conf_csc1_en = IC_CONF_PRPVF_CSC1, | ||
128 | .ic_conf_csc2_en = IC_CONF_PRPVF_CSC2, | ||
129 | .ic_cmb_galpha_bit = 0, | ||
130 | }, | ||
131 | [IC_TASK_POST_PROCESSOR] = { | ||
132 | .ic_conf_en = IC_CONF_PP_EN, | ||
133 | .ic_conf_rot_en = IC_CONF_PP_ROT_EN, | ||
134 | .ic_conf_cmb_en = IC_CONF_PP_CMB, | ||
135 | .ic_conf_csc1_en = IC_CONF_PP_CSC1, | ||
136 | .ic_conf_csc2_en = IC_CONF_PP_CSC2, | ||
137 | .ic_cmb_galpha_bit = 8, | ||
138 | }, | ||
139 | }; | ||
140 | |||
141 | struct ipu_ic_priv; | ||
142 | |||
143 | struct ipu_ic { | ||
144 | enum ipu_ic_task task; | ||
145 | const struct ic_task_regoffs *reg; | ||
146 | const struct ic_task_bitfields *bit; | ||
147 | |||
148 | enum ipu_color_space in_cs, g_in_cs; | ||
149 | enum ipu_color_space out_cs; | ||
150 | bool graphics; | ||
151 | bool rotation; | ||
152 | bool in_use; | ||
153 | |||
154 | struct ipu_ic_priv *priv; | ||
155 | }; | ||
156 | |||
157 | struct ipu_ic_priv { | ||
158 | void __iomem *base; | ||
159 | void __iomem *tpmem_base; | ||
160 | spinlock_t lock; | ||
161 | struct ipu_soc *ipu; | ||
162 | int use_count; | ||
163 | struct ipu_ic task[IC_NUM_TASKS]; | ||
164 | }; | ||
165 | |||
166 | static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset) | ||
167 | { | ||
168 | return readl(ic->priv->base + offset); | ||
169 | } | ||
170 | |||
171 | static inline void ipu_ic_write(struct ipu_ic *ic, u32 value, unsigned offset) | ||
172 | { | ||
173 | writel(value, ic->priv->base + offset); | ||
174 | } | ||
175 | |||
176 | struct ic_csc_params { | ||
177 | s16 coeff[3][3]; /* signed 9-bit integer coefficients */ | ||
178 | s16 offset[3]; /* signed 11+2-bit fixed point offset */ | ||
179 | u8 scale:2; /* scale coefficients * 2^(scale-1) */ | ||
180 | bool sat:1; /* saturate to (16, 235(Y) / 240(U, V)) */ | ||
181 | }; | ||
182 | |||
183 | /* | ||
184 | * Y = R * .299 + G * .587 + B * .114; | ||
185 | * U = R * -.169 + G * -.332 + B * .500 + 128.; | ||
186 | * V = R * .500 + G * -.419 + B * -.0813 + 128.; | ||
187 | */ | ||
188 | static const struct ic_csc_params ic_csc_rgb2ycbcr = { | ||
189 | .coeff = { | ||
190 | { 77, 150, 29 }, | ||
191 | { 469, 427, 128 }, | ||
192 | { 128, 405, 491 }, | ||
193 | }, | ||
194 | .offset = { 0, 512, 512 }, | ||
195 | .scale = 1, | ||
196 | }; | ||
197 | |||
198 | /* transparent RGB->RGB matrix for graphics combining */ | ||
199 | static const struct ic_csc_params ic_csc_rgb2rgb = { | ||
200 | .coeff = { | ||
201 | { 128, 0, 0 }, | ||
202 | { 0, 128, 0 }, | ||
203 | { 0, 0, 128 }, | ||
204 | }, | ||
205 | .scale = 2, | ||
206 | }; | ||
207 | |||
208 | /* | ||
209 | * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); | ||
210 | * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); | ||
211 | * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); | ||
212 | */ | ||
213 | static const struct ic_csc_params ic_csc_ycbcr2rgb = { | ||
214 | .coeff = { | ||
215 | { 149, 0, 204 }, | ||
216 | { 149, 462, 408 }, | ||
217 | { 149, 255, 0 }, | ||
218 | }, | ||
219 | .offset = { -446, 266, -554 }, | ||
220 | .scale = 2, | ||
221 | }; | ||
222 | |||
223 | static int init_csc(struct ipu_ic *ic, | ||
224 | enum ipu_color_space inf, | ||
225 | enum ipu_color_space outf, | ||
226 | int csc_index) | ||
227 | { | ||
228 | struct ipu_ic_priv *priv = ic->priv; | ||
229 | const struct ic_csc_params *params; | ||
230 | u32 __iomem *base; | ||
231 | const u16 (*c)[3]; | ||
232 | const u16 *a; | ||
233 | u32 param; | ||
234 | |||
235 | base = (u32 __iomem *) | ||
236 | (priv->tpmem_base + ic->reg->tpmem_csc[csc_index]); | ||
237 | |||
238 | if (inf == IPUV3_COLORSPACE_YUV && outf == IPUV3_COLORSPACE_RGB) | ||
239 | params = &ic_csc_ycbcr2rgb; | ||
240 | else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_YUV) | ||
241 | params = &ic_csc_rgb2ycbcr; | ||
242 | else if (inf == IPUV3_COLORSPACE_RGB && outf == IPUV3_COLORSPACE_RGB) | ||
243 | params = &ic_csc_rgb2rgb; | ||
244 | else { | ||
245 | dev_err(priv->ipu->dev, "Unsupported color space conversion\n"); | ||
246 | return -EINVAL; | ||
247 | } | ||
248 | |||
249 | /* Cast to unsigned */ | ||
250 | c = (const u16 (*)[3])params->coeff; | ||
251 | a = (const u16 *)params->offset; | ||
252 | |||
253 | param = ((a[0] & 0x1f) << 27) | ((c[0][0] & 0x1ff) << 18) | | ||
254 | ((c[1][1] & 0x1ff) << 9) | (c[2][2] & 0x1ff); | ||
255 | writel(param, base++); | ||
256 | |||
257 | param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) | | ||
258 | (params->sat << 9); | ||
259 | writel(param, base++); | ||
260 | |||
261 | param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) | | ||
262 | ((c[1][0] & 0x1ff) << 9) | (c[2][0] & 0x1ff); | ||
263 | writel(param, base++); | ||
264 | |||
265 | param = ((a[1] & 0x1fe0) >> 5); | ||
266 | writel(param, base++); | ||
267 | |||
268 | param = ((a[2] & 0x1f) << 27) | ((c[0][2] & 0x1ff) << 18) | | ||
269 | ((c[1][2] & 0x1ff) << 9) | (c[2][1] & 0x1ff); | ||
270 | writel(param, base++); | ||
271 | |||
272 | param = ((a[2] & 0x1fe0) >> 5); | ||
273 | writel(param, base++); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int calc_resize_coeffs(struct ipu_ic *ic, | ||
279 | u32 in_size, u32 out_size, | ||
280 | u32 *resize_coeff, | ||
281 | u32 *downsize_coeff) | ||
282 | { | ||
283 | struct ipu_ic_priv *priv = ic->priv; | ||
284 | struct ipu_soc *ipu = priv->ipu; | ||
285 | u32 temp_size, temp_downsize; | ||
286 | |||
287 | /* | ||
288 | * Input size cannot be more than 4096, and output size cannot | ||
289 | * be more than 1024 | ||
290 | */ | ||
291 | if (in_size > 4096) { | ||
292 | dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n"); | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | if (out_size > 1024) { | ||
296 | dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n"); | ||
297 | return -EINVAL; | ||
298 | } | ||
299 | |||
300 | /* Cannot downsize more than 8:1 */ | ||
301 | if ((out_size << 3) < in_size) { | ||
302 | dev_err(ipu->dev, "Unsupported downsize\n"); | ||
303 | return -EINVAL; | ||
304 | } | ||
305 | |||
306 | /* Compute downsizing coefficient */ | ||
307 | temp_downsize = 0; | ||
308 | temp_size = in_size; | ||
309 | while (((temp_size > 1024) || (temp_size >= out_size * 2)) && | ||
310 | (temp_downsize < 2)) { | ||
311 | temp_size >>= 1; | ||
312 | temp_downsize++; | ||
313 | } | ||
314 | *downsize_coeff = temp_downsize; | ||
315 | |||
316 | /* | ||
317 | * compute resizing coefficient using the following equation: | ||
318 | * resize_coeff = M * (SI - 1) / (SO - 1) | ||
319 | * where M = 2^13, SI = input size, SO = output size | ||
320 | */ | ||
321 | *resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1); | ||
322 | if (*resize_coeff >= 16384L) { | ||
323 | dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n"); | ||
324 | *resize_coeff = 0x3FFF; | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | void ipu_ic_task_enable(struct ipu_ic *ic) | ||
331 | { | ||
332 | struct ipu_ic_priv *priv = ic->priv; | ||
333 | unsigned long flags; | ||
334 | u32 ic_conf; | ||
335 | |||
336 | spin_lock_irqsave(&priv->lock, flags); | ||
337 | |||
338 | ic_conf = ipu_ic_read(ic, IC_CONF); | ||
339 | |||
340 | ic_conf |= ic->bit->ic_conf_en; | ||
341 | |||
342 | if (ic->rotation) | ||
343 | ic_conf |= ic->bit->ic_conf_rot_en; | ||
344 | |||
345 | if (ic->in_cs != ic->out_cs) | ||
346 | ic_conf |= ic->bit->ic_conf_csc1_en; | ||
347 | |||
348 | if (ic->graphics) { | ||
349 | ic_conf |= ic->bit->ic_conf_cmb_en; | ||
350 | ic_conf |= ic->bit->ic_conf_csc1_en; | ||
351 | |||
352 | if (ic->g_in_cs != ic->out_cs) | ||
353 | ic_conf |= ic->bit->ic_conf_csc2_en; | ||
354 | } | ||
355 | |||
356 | ipu_ic_write(ic, ic_conf, IC_CONF); | ||
357 | |||
358 | spin_unlock_irqrestore(&priv->lock, flags); | ||
359 | } | ||
360 | EXPORT_SYMBOL_GPL(ipu_ic_task_enable); | ||
361 | |||
362 | void ipu_ic_task_disable(struct ipu_ic *ic) | ||
363 | { | ||
364 | struct ipu_ic_priv *priv = ic->priv; | ||
365 | unsigned long flags; | ||
366 | u32 ic_conf; | ||
367 | |||
368 | spin_lock_irqsave(&priv->lock, flags); | ||
369 | |||
370 | ic_conf = ipu_ic_read(ic, IC_CONF); | ||
371 | |||
372 | ic_conf &= ~(ic->bit->ic_conf_en | | ||
373 | ic->bit->ic_conf_csc1_en | | ||
374 | ic->bit->ic_conf_rot_en); | ||
375 | if (ic->bit->ic_conf_csc2_en) | ||
376 | ic_conf &= ~ic->bit->ic_conf_csc2_en; | ||
377 | if (ic->bit->ic_conf_cmb_en) | ||
378 | ic_conf &= ~ic->bit->ic_conf_cmb_en; | ||
379 | |||
380 | ipu_ic_write(ic, ic_conf, IC_CONF); | ||
381 | |||
382 | ic->rotation = ic->graphics = false; | ||
383 | |||
384 | spin_unlock_irqrestore(&priv->lock, flags); | ||
385 | } | ||
386 | EXPORT_SYMBOL_GPL(ipu_ic_task_disable); | ||
387 | |||
388 | int ipu_ic_task_graphics_init(struct ipu_ic *ic, | ||
389 | enum ipu_color_space in_g_cs, | ||
390 | bool galpha_en, u32 galpha, | ||
391 | bool colorkey_en, u32 colorkey) | ||
392 | { | ||
393 | struct ipu_ic_priv *priv = ic->priv; | ||
394 | unsigned long flags; | ||
395 | u32 reg, ic_conf; | ||
396 | int ret = 0; | ||
397 | |||
398 | if (ic->task == IC_TASK_ENCODER) | ||
399 | return -EINVAL; | ||
400 | |||
401 | spin_lock_irqsave(&priv->lock, flags); | ||
402 | |||
403 | ic_conf = ipu_ic_read(ic, IC_CONF); | ||
404 | |||
405 | if (!(ic_conf & ic->bit->ic_conf_csc1_en)) { | ||
406 | /* need transparent CSC1 conversion */ | ||
407 | ret = init_csc(ic, IPUV3_COLORSPACE_RGB, | ||
408 | IPUV3_COLORSPACE_RGB, 0); | ||
409 | if (ret) | ||
410 | goto unlock; | ||
411 | } | ||
412 | |||
413 | ic->g_in_cs = in_g_cs; | ||
414 | |||
415 | if (ic->g_in_cs != ic->out_cs) { | ||
416 | ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1); | ||
417 | if (ret) | ||
418 | goto unlock; | ||
419 | } | ||
420 | |||
421 | if (galpha_en) { | ||
422 | ic_conf |= IC_CONF_IC_GLB_LOC_A; | ||
423 | reg = ipu_ic_read(ic, IC_CMBP_1); | ||
424 | reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit); | ||
425 | reg |= (galpha << ic->bit->ic_cmb_galpha_bit); | ||
426 | ipu_ic_write(ic, reg, IC_CMBP_1); | ||
427 | } else | ||
428 | ic_conf &= ~IC_CONF_IC_GLB_LOC_A; | ||
429 | |||
430 | if (colorkey_en) { | ||
431 | ic_conf |= IC_CONF_KEY_COLOR_EN; | ||
432 | ipu_ic_write(ic, colorkey, IC_CMBP_2); | ||
433 | } else | ||
434 | ic_conf &= ~IC_CONF_KEY_COLOR_EN; | ||
435 | |||
436 | ipu_ic_write(ic, ic_conf, IC_CONF); | ||
437 | |||
438 | ic->graphics = true; | ||
439 | unlock: | ||
440 | spin_unlock_irqrestore(&priv->lock, flags); | ||
441 | return ret; | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); | ||
444 | |||
445 | int ipu_ic_task_init(struct ipu_ic *ic, | ||
446 | int in_width, int in_height, | ||
447 | int out_width, int out_height, | ||
448 | enum ipu_color_space in_cs, | ||
449 | enum ipu_color_space out_cs) | ||
450 | { | ||
451 | struct ipu_ic_priv *priv = ic->priv; | ||
452 | u32 reg, downsize_coeff, resize_coeff; | ||
453 | unsigned long flags; | ||
454 | int ret = 0; | ||
455 | |||
456 | /* Setup vertical resizing */ | ||
457 | ret = calc_resize_coeffs(ic, in_height, out_height, | ||
458 | &resize_coeff, &downsize_coeff); | ||
459 | if (ret) | ||
460 | return ret; | ||
461 | |||
462 | reg = (downsize_coeff << 30) | (resize_coeff << 16); | ||
463 | |||
464 | /* Setup horizontal resizing */ | ||
465 | ret = calc_resize_coeffs(ic, in_width, out_width, | ||
466 | &resize_coeff, &downsize_coeff); | ||
467 | if (ret) | ||
468 | return ret; | ||
469 | |||
470 | reg |= (downsize_coeff << 14) | resize_coeff; | ||
471 | |||
472 | spin_lock_irqsave(&priv->lock, flags); | ||
473 | |||
474 | ipu_ic_write(ic, reg, ic->reg->rsc); | ||
475 | |||
476 | /* Setup color space conversion */ | ||
477 | ic->in_cs = in_cs; | ||
478 | ic->out_cs = out_cs; | ||
479 | |||
480 | if (ic->in_cs != ic->out_cs) { | ||
481 | ret = init_csc(ic, ic->in_cs, ic->out_cs, 0); | ||
482 | if (ret) | ||
483 | goto unlock; | ||
484 | } | ||
485 | |||
486 | unlock: | ||
487 | spin_unlock_irqrestore(&priv->lock, flags); | ||
488 | return ret; | ||
489 | } | ||
490 | EXPORT_SYMBOL_GPL(ipu_ic_task_init); | ||
491 | |||
492 | int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel, | ||
493 | u32 width, u32 height, int burst_size, | ||
494 | enum ipu_rotate_mode rot) | ||
495 | { | ||
496 | struct ipu_ic_priv *priv = ic->priv; | ||
497 | struct ipu_soc *ipu = priv->ipu; | ||
498 | u32 ic_idmac_1, ic_idmac_2, ic_idmac_3; | ||
499 | u32 temp_rot = bitrev8(rot) >> 5; | ||
500 | bool need_hor_flip = false; | ||
501 | unsigned long flags; | ||
502 | int ret = 0; | ||
503 | |||
504 | if ((burst_size != 8) && (burst_size != 16)) { | ||
505 | dev_err(ipu->dev, "Illegal burst length for IC\n"); | ||
506 | return -EINVAL; | ||
507 | } | ||
508 | |||
509 | width--; | ||
510 | height--; | ||
511 | |||
512 | if (temp_rot & 0x2) /* Need horizontal flip */ | ||
513 | need_hor_flip = true; | ||
514 | |||
515 | spin_lock_irqsave(&priv->lock, flags); | ||
516 | |||
517 | ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1); | ||
518 | ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2); | ||
519 | ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3); | ||
520 | |||
521 | switch (channel->num) { | ||
522 | case IPUV3_CHANNEL_IC_PP_MEM: | ||
523 | if (burst_size == 16) | ||
524 | ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16; | ||
525 | else | ||
526 | ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16; | ||
527 | |||
528 | if (need_hor_flip) | ||
529 | ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS; | ||
530 | else | ||
531 | ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS; | ||
532 | |||
533 | ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK; | ||
534 | ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET; | ||
535 | |||
536 | ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK; | ||
537 | ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET; | ||
538 | break; | ||
539 | case IPUV3_CHANNEL_MEM_IC_PP: | ||
540 | if (burst_size == 16) | ||
541 | ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16; | ||
542 | else | ||
543 | ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16; | ||
544 | break; | ||
545 | case IPUV3_CHANNEL_MEM_ROT_PP: | ||
546 | ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK; | ||
547 | ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET; | ||
548 | break; | ||
549 | case IPUV3_CHANNEL_MEM_IC_PRP_VF: | ||
550 | if (burst_size == 16) | ||
551 | ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16; | ||
552 | else | ||
553 | ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16; | ||
554 | break; | ||
555 | case IPUV3_CHANNEL_IC_PRP_ENC_MEM: | ||
556 | if (burst_size == 16) | ||
557 | ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16; | ||
558 | else | ||
559 | ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16; | ||
560 | |||
561 | if (need_hor_flip) | ||
562 | ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS; | ||
563 | else | ||
564 | ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS; | ||
565 | |||
566 | ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK; | ||
567 | ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET; | ||
568 | |||
569 | ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK; | ||
570 | ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET; | ||
571 | break; | ||
572 | case IPUV3_CHANNEL_MEM_ROT_ENC: | ||
573 | ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK; | ||
574 | ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET; | ||
575 | break; | ||
576 | case IPUV3_CHANNEL_IC_PRP_VF_MEM: | ||
577 | if (burst_size == 16) | ||
578 | ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16; | ||
579 | else | ||
580 | ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16; | ||
581 | |||
582 | if (need_hor_flip) | ||
583 | ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS; | ||
584 | else | ||
585 | ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS; | ||
586 | |||
587 | ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK; | ||
588 | ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET; | ||
589 | |||
590 | ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK; | ||
591 | ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET; | ||
592 | break; | ||
593 | case IPUV3_CHANNEL_MEM_ROT_VF: | ||
594 | ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK; | ||
595 | ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET; | ||
596 | break; | ||
597 | case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: | ||
598 | if (burst_size == 16) | ||
599 | ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16; | ||
600 | else | ||
601 | ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16; | ||
602 | break; | ||
603 | case IPUV3_CHANNEL_G_MEM_IC_PP: | ||
604 | if (burst_size == 16) | ||
605 | ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16; | ||
606 | else | ||
607 | ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16; | ||
608 | break; | ||
609 | case IPUV3_CHANNEL_VDI_MEM_IC_VF: | ||
610 | if (burst_size == 16) | ||
611 | ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16; | ||
612 | else | ||
613 | ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16; | ||
614 | break; | ||
615 | default: | ||
616 | goto unlock; | ||
617 | } | ||
618 | |||
619 | ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1); | ||
620 | ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2); | ||
621 | ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3); | ||
622 | |||
623 | if (rot >= IPU_ROTATE_90_RIGHT) | ||
624 | ic->rotation = true; | ||
625 | |||
626 | unlock: | ||
627 | spin_unlock_irqrestore(&priv->lock, flags); | ||
628 | return ret; | ||
629 | } | ||
630 | EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init); | ||
631 | |||
632 | int ipu_ic_enable(struct ipu_ic *ic) | ||
633 | { | ||
634 | struct ipu_ic_priv *priv = ic->priv; | ||
635 | unsigned long flags; | ||
636 | u32 module = IPU_CONF_IC_EN; | ||
637 | |||
638 | spin_lock_irqsave(&priv->lock, flags); | ||
639 | |||
640 | if (ic->rotation) | ||
641 | module |= IPU_CONF_ROT_EN; | ||
642 | |||
643 | if (!priv->use_count) | ||
644 | ipu_module_enable(priv->ipu, module); | ||
645 | |||
646 | priv->use_count++; | ||
647 | |||
648 | spin_unlock_irqrestore(&priv->lock, flags); | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | EXPORT_SYMBOL_GPL(ipu_ic_enable); | ||
653 | |||
654 | int ipu_ic_disable(struct ipu_ic *ic) | ||
655 | { | ||
656 | struct ipu_ic_priv *priv = ic->priv; | ||
657 | unsigned long flags; | ||
658 | u32 module = IPU_CONF_IC_EN | IPU_CONF_ROT_EN; | ||
659 | |||
660 | spin_lock_irqsave(&priv->lock, flags); | ||
661 | |||
662 | priv->use_count--; | ||
663 | |||
664 | if (!priv->use_count) | ||
665 | ipu_module_disable(priv->ipu, module); | ||
666 | |||
667 | if (priv->use_count < 0) | ||
668 | priv->use_count = 0; | ||
669 | |||
670 | spin_unlock_irqrestore(&priv->lock, flags); | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | EXPORT_SYMBOL_GPL(ipu_ic_disable); | ||
675 | |||
676 | struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task) | ||
677 | { | ||
678 | struct ipu_ic_priv *priv = ipu->ic_priv; | ||
679 | unsigned long flags; | ||
680 | struct ipu_ic *ic, *ret; | ||
681 | |||
682 | if (task >= IC_NUM_TASKS) | ||
683 | return ERR_PTR(-EINVAL); | ||
684 | |||
685 | ic = &priv->task[task]; | ||
686 | |||
687 | spin_lock_irqsave(&priv->lock, flags); | ||
688 | |||
689 | if (ic->in_use) { | ||
690 | ret = ERR_PTR(-EBUSY); | ||
691 | goto unlock; | ||
692 | } | ||
693 | |||
694 | ic->in_use = true; | ||
695 | ret = ic; | ||
696 | |||
697 | unlock: | ||
698 | spin_unlock_irqrestore(&priv->lock, flags); | ||
699 | return ret; | ||
700 | } | ||
701 | EXPORT_SYMBOL_GPL(ipu_ic_get); | ||
702 | |||
703 | void ipu_ic_put(struct ipu_ic *ic) | ||
704 | { | ||
705 | struct ipu_ic_priv *priv = ic->priv; | ||
706 | unsigned long flags; | ||
707 | |||
708 | spin_lock_irqsave(&priv->lock, flags); | ||
709 | ic->in_use = false; | ||
710 | spin_unlock_irqrestore(&priv->lock, flags); | ||
711 | } | ||
712 | EXPORT_SYMBOL_GPL(ipu_ic_put); | ||
713 | |||
714 | int ipu_ic_init(struct ipu_soc *ipu, struct device *dev, | ||
715 | unsigned long base, unsigned long tpmem_base) | ||
716 | { | ||
717 | struct ipu_ic_priv *priv; | ||
718 | int i; | ||
719 | |||
720 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
721 | if (!priv) | ||
722 | return -ENOMEM; | ||
723 | |||
724 | ipu->ic_priv = priv; | ||
725 | |||
726 | spin_lock_init(&priv->lock); | ||
727 | priv->base = devm_ioremap(dev, base, PAGE_SIZE); | ||
728 | if (!priv->base) | ||
729 | return -ENOMEM; | ||
730 | priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K); | ||
731 | if (!priv->tpmem_base) | ||
732 | return -ENOMEM; | ||
733 | |||
734 | dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base); | ||
735 | |||
736 | priv->ipu = ipu; | ||
737 | |||
738 | for (i = 0; i < IC_NUM_TASKS; i++) { | ||
739 | priv->task[i].task = i; | ||
740 | priv->task[i].priv = priv; | ||
741 | priv->task[i].reg = &ic_task_reg[i]; | ||
742 | priv->task[i].bit = &ic_task_bit[i]; | ||
743 | } | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | void ipu_ic_exit(struct ipu_soc *ipu) | ||
749 | { | ||
750 | } | ||
751 | |||
752 | void ipu_ic_dump(struct ipu_ic *ic) | ||
753 | { | ||
754 | struct ipu_ic_priv *priv = ic->priv; | ||
755 | struct ipu_soc *ipu = priv->ipu; | ||
756 | |||
757 | dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n", | ||
758 | ipu_ic_read(ic, IC_CONF)); | ||
759 | dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n", | ||
760 | ipu_ic_read(ic, IC_PRP_ENC_RSC)); | ||
761 | dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n", | ||
762 | ipu_ic_read(ic, IC_PRP_VF_RSC)); | ||
763 | dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n", | ||
764 | ipu_ic_read(ic, IC_PP_RSC)); | ||
765 | dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n", | ||
766 | ipu_ic_read(ic, IC_CMBP_1)); | ||
767 | dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n", | ||
768 | ipu_ic_read(ic, IC_CMBP_2)); | ||
769 | dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n", | ||
770 | ipu_ic_read(ic, IC_IDMAC_1)); | ||
771 | dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n", | ||
772 | ipu_ic_read(ic, IC_IDMAC_2)); | ||
773 | dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n", | ||
774 | ipu_ic_read(ic, IC_IDMAC_3)); | ||
775 | dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n", | ||
776 | ipu_ic_read(ic, IC_IDMAC_4)); | ||
777 | } | ||
778 | EXPORT_SYMBOL_GPL(ipu_ic_dump); | ||
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index c93f50ec04f7..bfb1e8a4483f 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h | |||
@@ -24,23 +24,6 @@ struct ipu_soc; | |||
24 | 24 | ||
25 | #include <video/imx-ipu-v3.h> | 25 | #include <video/imx-ipu-v3.h> |
26 | 26 | ||
27 | #define IPUV3_CHANNEL_CSI0 0 | ||
28 | #define IPUV3_CHANNEL_CSI1 1 | ||
29 | #define IPUV3_CHANNEL_CSI2 2 | ||
30 | #define IPUV3_CHANNEL_CSI3 3 | ||
31 | #define IPUV3_CHANNEL_MEM_BG_SYNC 23 | ||
32 | #define IPUV3_CHANNEL_MEM_FG_SYNC 27 | ||
33 | #define IPUV3_CHANNEL_MEM_DC_SYNC 28 | ||
34 | #define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31 | ||
35 | #define IPUV3_CHANNEL_MEM_DC_ASYNC 41 | ||
36 | #define IPUV3_CHANNEL_ROT_ENC_MEM 45 | ||
37 | #define IPUV3_CHANNEL_ROT_VF_MEM 46 | ||
38 | #define IPUV3_CHANNEL_ROT_PP_MEM 47 | ||
39 | #define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48 | ||
40 | #define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49 | ||
41 | #define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50 | ||
42 | #define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51 | ||
43 | |||
44 | #define IPU_MCU_T_DEFAULT 8 | 27 | #define IPU_MCU_T_DEFAULT 8 |
45 | #define IPU_CM_IDMAC_REG_OFS 0x00008000 | 28 | #define IPU_CM_IDMAC_REG_OFS 0x00008000 |
46 | #define IPU_CM_IC_REG_OFS 0x00020000 | 29 | #define IPU_CM_IC_REG_OFS 0x00020000 |
@@ -85,6 +68,7 @@ struct ipu_soc; | |||
85 | #define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254) | 68 | #define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254) |
86 | #define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32)) | 69 | #define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32)) |
87 | #define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32)) | 70 | #define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32)) |
71 | #define IPU_CHA_BUF2_RDY(ch) IPU_CM_REG(0x0288 + 4 * ((ch) / 32)) | ||
88 | #define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32)) | 72 | #define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32)) |
89 | #define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32)) | 73 | #define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32)) |
90 | 74 | ||
@@ -148,9 +132,12 @@ struct ipuv3_channel { | |||
148 | struct ipu_soc *ipu; | 132 | struct ipu_soc *ipu; |
149 | }; | 133 | }; |
150 | 134 | ||
135 | struct ipu_cpmem; | ||
136 | struct ipu_csi; | ||
151 | struct ipu_dc_priv; | 137 | struct ipu_dc_priv; |
152 | struct ipu_dmfc_priv; | 138 | struct ipu_dmfc_priv; |
153 | struct ipu_di; | 139 | struct ipu_di; |
140 | struct ipu_ic_priv; | ||
154 | struct ipu_smfc_priv; | 141 | struct ipu_smfc_priv; |
155 | 142 | ||
156 | struct ipu_devtype; | 143 | struct ipu_devtype; |
@@ -164,7 +151,6 @@ struct ipu_soc { | |||
164 | 151 | ||
165 | void __iomem *cm_reg; | 152 | void __iomem *cm_reg; |
166 | void __iomem *idmac_reg; | 153 | void __iomem *idmac_reg; |
167 | struct ipu_ch_param __iomem *cpmem_base; | ||
168 | 154 | ||
169 | int usecount; | 155 | int usecount; |
170 | 156 | ||
@@ -176,13 +162,27 @@ struct ipu_soc { | |||
176 | int irq_err; | 162 | int irq_err; |
177 | struct irq_domain *domain; | 163 | struct irq_domain *domain; |
178 | 164 | ||
165 | struct ipu_cpmem *cpmem_priv; | ||
179 | struct ipu_dc_priv *dc_priv; | 166 | struct ipu_dc_priv *dc_priv; |
180 | struct ipu_dp_priv *dp_priv; | 167 | struct ipu_dp_priv *dp_priv; |
181 | struct ipu_dmfc_priv *dmfc_priv; | 168 | struct ipu_dmfc_priv *dmfc_priv; |
182 | struct ipu_di *di_priv[2]; | 169 | struct ipu_di *di_priv[2]; |
170 | struct ipu_csi *csi_priv[2]; | ||
171 | struct ipu_ic_priv *ic_priv; | ||
183 | struct ipu_smfc_priv *smfc_priv; | 172 | struct ipu_smfc_priv *smfc_priv; |
184 | }; | 173 | }; |
185 | 174 | ||
175 | static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) | ||
176 | { | ||
177 | return readl(ipu->idmac_reg + offset); | ||
178 | } | ||
179 | |||
180 | static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, | ||
181 | unsigned offset) | ||
182 | { | ||
183 | writel(value, ipu->idmac_reg + offset); | ||
184 | } | ||
185 | |||
186 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu); | 186 | void ipu_srm_dp_sync_update(struct ipu_soc *ipu); |
187 | 187 | ||
188 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask); | 188 | int ipu_module_enable(struct ipu_soc *ipu, u32 mask); |
@@ -191,6 +191,14 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask); | |||
191 | bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); | 191 | bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno); |
192 | int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); | 192 | int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms); |
193 | 193 | ||
194 | int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id, | ||
195 | unsigned long base, u32 module, struct clk *clk_ipu); | ||
196 | void ipu_csi_exit(struct ipu_soc *ipu, int id); | ||
197 | |||
198 | int ipu_ic_init(struct ipu_soc *ipu, struct device *dev, | ||
199 | unsigned long base, unsigned long tpmem_base); | ||
200 | void ipu_ic_exit(struct ipu_soc *ipu); | ||
201 | |||
194 | int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, | 202 | int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, |
195 | unsigned long base, u32 module, struct clk *ipu_clk); | 203 | unsigned long base, u32 module, struct clk *ipu_clk); |
196 | void ipu_di_exit(struct ipu_soc *ipu, int id); | 204 | void ipu_di_exit(struct ipu_soc *ipu, int id); |
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/ipu-v3/ipu-smfc.c index e4f85ad286fc..6ca9b43ce25a 100644 --- a/drivers/gpu/ipu-v3/ipu-smfc.c +++ b/drivers/gpu/ipu-v3/ipu-smfc.c | |||
@@ -21,9 +21,18 @@ | |||
21 | 21 | ||
22 | #include "ipu-prv.h" | 22 | #include "ipu-prv.h" |
23 | 23 | ||
24 | struct ipu_smfc { | ||
25 | struct ipu_smfc_priv *priv; | ||
26 | int chno; | ||
27 | bool inuse; | ||
28 | }; | ||
29 | |||
24 | struct ipu_smfc_priv { | 30 | struct ipu_smfc_priv { |
25 | void __iomem *base; | 31 | void __iomem *base; |
26 | spinlock_t lock; | 32 | spinlock_t lock; |
33 | struct ipu_soc *ipu; | ||
34 | struct ipu_smfc channel[4]; | ||
35 | int use_count; | ||
27 | }; | 36 | }; |
28 | 37 | ||
29 | /*SMFC Registers */ | 38 | /*SMFC Registers */ |
@@ -31,63 +40,166 @@ struct ipu_smfc_priv { | |||
31 | #define SMFC_WMC 0x0004 | 40 | #define SMFC_WMC 0x0004 |
32 | #define SMFC_BS 0x0008 | 41 | #define SMFC_BS 0x0008 |
33 | 42 | ||
34 | int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize) | 43 | int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize) |
35 | { | 44 | { |
36 | struct ipu_smfc_priv *smfc = ipu->smfc_priv; | 45 | struct ipu_smfc_priv *priv = smfc->priv; |
37 | unsigned long flags; | 46 | unsigned long flags; |
38 | u32 val, shift; | 47 | u32 val, shift; |
39 | 48 | ||
40 | spin_lock_irqsave(&smfc->lock, flags); | 49 | spin_lock_irqsave(&priv->lock, flags); |
41 | 50 | ||
42 | shift = channel * 4; | 51 | shift = smfc->chno * 4; |
43 | val = readl(smfc->base + SMFC_BS); | 52 | val = readl(priv->base + SMFC_BS); |
44 | val &= ~(0xf << shift); | 53 | val &= ~(0xf << shift); |
45 | val |= burstsize << shift; | 54 | val |= burstsize << shift; |
46 | writel(val, smfc->base + SMFC_BS); | 55 | writel(val, priv->base + SMFC_BS); |
47 | 56 | ||
48 | spin_unlock_irqrestore(&smfc->lock, flags); | 57 | spin_unlock_irqrestore(&priv->lock, flags); |
49 | 58 | ||
50 | return 0; | 59 | return 0; |
51 | } | 60 | } |
52 | EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize); | 61 | EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize); |
53 | 62 | ||
54 | int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id) | 63 | int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id) |
55 | { | 64 | { |
56 | struct ipu_smfc_priv *smfc = ipu->smfc_priv; | 65 | struct ipu_smfc_priv *priv = smfc->priv; |
57 | unsigned long flags; | 66 | unsigned long flags; |
58 | u32 val, shift; | 67 | u32 val, shift; |
59 | 68 | ||
60 | spin_lock_irqsave(&smfc->lock, flags); | 69 | spin_lock_irqsave(&priv->lock, flags); |
61 | 70 | ||
62 | shift = channel * 3; | 71 | shift = smfc->chno * 3; |
63 | val = readl(smfc->base + SMFC_MAP); | 72 | val = readl(priv->base + SMFC_MAP); |
64 | val &= ~(0x7 << shift); | 73 | val &= ~(0x7 << shift); |
65 | val |= ((csi_id << 2) | mipi_id) << shift; | 74 | val |= ((csi_id << 2) | mipi_id) << shift; |
66 | writel(val, smfc->base + SMFC_MAP); | 75 | writel(val, priv->base + SMFC_MAP); |
67 | 76 | ||
68 | spin_unlock_irqrestore(&smfc->lock, flags); | 77 | spin_unlock_irqrestore(&priv->lock, flags); |
69 | 78 | ||
70 | return 0; | 79 | return 0; |
71 | } | 80 | } |
72 | EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); | 81 | EXPORT_SYMBOL_GPL(ipu_smfc_map_channel); |
73 | 82 | ||
83 | int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level) | ||
84 | { | ||
85 | struct ipu_smfc_priv *priv = smfc->priv; | ||
86 | unsigned long flags; | ||
87 | u32 val, shift; | ||
88 | |||
89 | spin_lock_irqsave(&priv->lock, flags); | ||
90 | |||
91 | shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0); | ||
92 | val = readl(priv->base + SMFC_WMC); | ||
93 | val &= ~(0x3f << shift); | ||
94 | val |= ((clr_level << 3) | set_level) << shift; | ||
95 | writel(val, priv->base + SMFC_WMC); | ||
96 | |||
97 | spin_unlock_irqrestore(&priv->lock, flags); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark); | ||
102 | |||
103 | int ipu_smfc_enable(struct ipu_smfc *smfc) | ||
104 | { | ||
105 | struct ipu_smfc_priv *priv = smfc->priv; | ||
106 | unsigned long flags; | ||
107 | |||
108 | spin_lock_irqsave(&priv->lock, flags); | ||
109 | |||
110 | if (!priv->use_count) | ||
111 | ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN); | ||
112 | |||
113 | priv->use_count++; | ||
114 | |||
115 | spin_unlock_irqrestore(&priv->lock, flags); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | EXPORT_SYMBOL_GPL(ipu_smfc_enable); | ||
120 | |||
121 | int ipu_smfc_disable(struct ipu_smfc *smfc) | ||
122 | { | ||
123 | struct ipu_smfc_priv *priv = smfc->priv; | ||
124 | unsigned long flags; | ||
125 | |||
126 | spin_lock_irqsave(&priv->lock, flags); | ||
127 | |||
128 | priv->use_count--; | ||
129 | |||
130 | if (!priv->use_count) | ||
131 | ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN); | ||
132 | |||
133 | if (priv->use_count < 0) | ||
134 | priv->use_count = 0; | ||
135 | |||
136 | spin_unlock_irqrestore(&priv->lock, flags); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(ipu_smfc_disable); | ||
141 | |||
142 | struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno) | ||
143 | { | ||
144 | struct ipu_smfc_priv *priv = ipu->smfc_priv; | ||
145 | struct ipu_smfc *smfc, *ret; | ||
146 | unsigned long flags; | ||
147 | |||
148 | if (chno >= 4) | ||
149 | return ERR_PTR(-EINVAL); | ||
150 | |||
151 | smfc = &priv->channel[chno]; | ||
152 | ret = smfc; | ||
153 | |||
154 | spin_lock_irqsave(&priv->lock, flags); | ||
155 | |||
156 | if (smfc->inuse) { | ||
157 | ret = ERR_PTR(-EBUSY); | ||
158 | goto unlock; | ||
159 | } | ||
160 | |||
161 | smfc->inuse = true; | ||
162 | unlock: | ||
163 | spin_unlock_irqrestore(&priv->lock, flags); | ||
164 | return ret; | ||
165 | } | ||
166 | EXPORT_SYMBOL_GPL(ipu_smfc_get); | ||
167 | |||
168 | void ipu_smfc_put(struct ipu_smfc *smfc) | ||
169 | { | ||
170 | struct ipu_smfc_priv *priv = smfc->priv; | ||
171 | unsigned long flags; | ||
172 | |||
173 | spin_lock_irqsave(&priv->lock, flags); | ||
174 | smfc->inuse = false; | ||
175 | spin_unlock_irqrestore(&priv->lock, flags); | ||
176 | } | ||
177 | EXPORT_SYMBOL_GPL(ipu_smfc_put); | ||
178 | |||
74 | int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, | 179 | int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, |
75 | unsigned long base) | 180 | unsigned long base) |
76 | { | 181 | { |
77 | struct ipu_smfc_priv *smfc; | 182 | struct ipu_smfc_priv *priv; |
183 | int i; | ||
78 | 184 | ||
79 | smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL); | 185 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
80 | if (!smfc) | 186 | if (!priv) |
81 | return -ENOMEM; | 187 | return -ENOMEM; |
82 | 188 | ||
83 | ipu->smfc_priv = smfc; | 189 | ipu->smfc_priv = priv; |
84 | spin_lock_init(&smfc->lock); | 190 | spin_lock_init(&priv->lock); |
191 | priv->ipu = ipu; | ||
85 | 192 | ||
86 | smfc->base = devm_ioremap(dev, base, PAGE_SIZE); | 193 | priv->base = devm_ioremap(dev, base, PAGE_SIZE); |
87 | if (!smfc->base) | 194 | if (!priv->base) |
88 | return -ENOMEM; | 195 | return -ENOMEM; |
89 | 196 | ||
90 | pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, smfc->base); | 197 | for (i = 0; i < 4; i++) { |
198 | priv->channel[i].priv = priv; | ||
199 | priv->channel[i].chno = i; | ||
200 | } | ||
201 | |||
202 | pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base); | ||
91 | 203 | ||
92 | return 0; | 204 | return 0; |
93 | } | 205 | } |
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c index 6f393a11f44d..6ffe1bbbcf16 100644 --- a/drivers/staging/imx-drm/ipuv3-plane.c +++ b/drivers/staging/imx-drm/ipuv3-plane.c | |||
@@ -62,7 +62,6 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref) | |||
62 | int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | 62 | int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, |
63 | int x, int y) | 63 | int x, int y) |
64 | { | 64 | { |
65 | struct ipu_ch_param __iomem *cpmem; | ||
66 | struct drm_gem_cma_object *cma_obj; | 65 | struct drm_gem_cma_object *cma_obj; |
67 | unsigned long eba; | 66 | unsigned long eba; |
68 | 67 | ||
@@ -75,13 +74,12 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, | |||
75 | dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", | 74 | dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", |
76 | &cma_obj->paddr, x, y); | 75 | &cma_obj->paddr, x, y); |
77 | 76 | ||
78 | cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); | 77 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); |
79 | ipu_cpmem_set_stride(cpmem, fb->pitches[0]); | ||
80 | 78 | ||
81 | eba = cma_obj->paddr + fb->offsets[0] + | 79 | eba = cma_obj->paddr + fb->offsets[0] + |
82 | fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; | 80 | fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x; |
83 | ipu_cpmem_set_buffer(cpmem, 0, eba); | 81 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); |
84 | ipu_cpmem_set_buffer(cpmem, 1, eba); | 82 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); |
85 | 83 | ||
86 | /* cache offsets for subsequent pageflips */ | 84 | /* cache offsets for subsequent pageflips */ |
87 | ipu_plane->x = x; | 85 | ipu_plane->x = x; |
@@ -97,7 +95,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, | |||
97 | uint32_t src_x, uint32_t src_y, | 95 | uint32_t src_x, uint32_t src_y, |
98 | uint32_t src_w, uint32_t src_h) | 96 | uint32_t src_w, uint32_t src_h) |
99 | { | 97 | { |
100 | struct ipu_ch_param __iomem *cpmem; | ||
101 | struct device *dev = ipu_plane->base.dev->dev; | 98 | struct device *dev = ipu_plane->base.dev->dev; |
102 | int ret; | 99 | int ret; |
103 | 100 | ||
@@ -175,10 +172,9 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc, | |||
175 | return ret; | 172 | return ret; |
176 | } | 173 | } |
177 | 174 | ||
178 | cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); | 175 | ipu_cpmem_zero(ipu_plane->ipu_ch); |
179 | ipu_ch_param_zero(cpmem); | 176 | ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h); |
180 | ipu_cpmem_set_resolution(cpmem, src_w, src_h); | 177 | ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format); |
181 | ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format); | ||
182 | if (ret < 0) { | 178 | if (ret < 0) { |
183 | dev_err(dev, "unsupported pixel format 0x%08x\n", | 179 | dev_err(dev, "unsupported pixel format 0x%08x\n", |
184 | fb->pixel_format); | 180 | fb->pixel_format); |
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h index 3e43e22cdff9..c74bf4a0520e 100644 --- a/include/video/imx-ipu-v3.h +++ b/include/video/imx-ipu-v3.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/videodev2.h> | 16 | #include <linux/videodev2.h> |
17 | #include <linux/bitmap.h> | 17 | #include <linux/bitmap.h> |
18 | #include <linux/fb.h> | 18 | #include <linux/fb.h> |
19 | #include <media/v4l2-mediabus.h> | ||
19 | 20 | ||
20 | struct ipu_soc; | 21 | struct ipu_soc; |
21 | 22 | ||
@@ -61,6 +62,29 @@ struct ipu_di_signal_cfg { | |||
61 | u8 vsync_pin; | 62 | u8 vsync_pin; |
62 | }; | 63 | }; |
63 | 64 | ||
65 | /* | ||
66 | * Enumeration of CSI destinations | ||
67 | */ | ||
68 | enum ipu_csi_dest { | ||
69 | IPU_CSI_DEST_IDMAC, /* to memory via SMFC */ | ||
70 | IPU_CSI_DEST_IC, /* to Image Converter */ | ||
71 | IPU_CSI_DEST_VDIC, /* to VDIC */ | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * Enumeration of IPU rotation modes | ||
76 | */ | ||
77 | enum ipu_rotate_mode { | ||
78 | IPU_ROTATE_NONE = 0, | ||
79 | IPU_ROTATE_VERT_FLIP, | ||
80 | IPU_ROTATE_HORIZ_FLIP, | ||
81 | IPU_ROTATE_180, | ||
82 | IPU_ROTATE_90_RIGHT, | ||
83 | IPU_ROTATE_90_RIGHT_VFLIP, | ||
84 | IPU_ROTATE_90_RIGHT_HFLIP, | ||
85 | IPU_ROTATE_90_LEFT, | ||
86 | }; | ||
87 | |||
64 | enum ipu_color_space { | 88 | enum ipu_color_space { |
65 | IPUV3_COLORSPACE_RGB, | 89 | IPUV3_COLORSPACE_RGB, |
66 | IPUV3_COLORSPACE_YUV, | 90 | IPUV3_COLORSPACE_YUV, |
@@ -76,6 +100,36 @@ enum ipu_channel_irq { | |||
76 | IPU_IRQ_EOS = 192, | 100 | IPU_IRQ_EOS = 192, |
77 | }; | 101 | }; |
78 | 102 | ||
103 | /* | ||
104 | * Enumeration of IDMAC channels | ||
105 | */ | ||
106 | #define IPUV3_CHANNEL_CSI0 0 | ||
107 | #define IPUV3_CHANNEL_CSI1 1 | ||
108 | #define IPUV3_CHANNEL_CSI2 2 | ||
109 | #define IPUV3_CHANNEL_CSI3 3 | ||
110 | #define IPUV3_CHANNEL_VDI_MEM_IC_VF 5 | ||
111 | #define IPUV3_CHANNEL_MEM_IC_PP 11 | ||
112 | #define IPUV3_CHANNEL_MEM_IC_PRP_VF 12 | ||
113 | #define IPUV3_CHANNEL_G_MEM_IC_PRP_VF 14 | ||
114 | #define IPUV3_CHANNEL_G_MEM_IC_PP 15 | ||
115 | #define IPUV3_CHANNEL_IC_PRP_ENC_MEM 20 | ||
116 | #define IPUV3_CHANNEL_IC_PRP_VF_MEM 21 | ||
117 | #define IPUV3_CHANNEL_IC_PP_MEM 22 | ||
118 | #define IPUV3_CHANNEL_MEM_BG_SYNC 23 | ||
119 | #define IPUV3_CHANNEL_MEM_BG_ASYNC 24 | ||
120 | #define IPUV3_CHANNEL_MEM_FG_SYNC 27 | ||
121 | #define IPUV3_CHANNEL_MEM_DC_SYNC 28 | ||
122 | #define IPUV3_CHANNEL_MEM_FG_ASYNC 29 | ||
123 | #define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31 | ||
124 | #define IPUV3_CHANNEL_MEM_DC_ASYNC 41 | ||
125 | #define IPUV3_CHANNEL_MEM_ROT_ENC 45 | ||
126 | #define IPUV3_CHANNEL_MEM_ROT_VF 46 | ||
127 | #define IPUV3_CHANNEL_MEM_ROT_PP 47 | ||
128 | #define IPUV3_CHANNEL_ROT_ENC_MEM 48 | ||
129 | #define IPUV3_CHANNEL_ROT_VF_MEM 49 | ||
130 | #define IPUV3_CHANNEL_ROT_PP_MEM 50 | ||
131 | #define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51 | ||
132 | |||
79 | int ipu_map_irq(struct ipu_soc *ipu, int irq); | 133 | int ipu_map_irq(struct ipu_soc *ipu, int irq); |
80 | int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, | 134 | int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, |
81 | enum ipu_channel_irq irq); | 135 | enum ipu_channel_irq irq); |
@@ -93,6 +147,13 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, | |||
93 | #define IPU_IRQ_VSYNC_PRE_1 (448 + 15) | 147 | #define IPU_IRQ_VSYNC_PRE_1 (448 + 15) |
94 | 148 | ||
95 | /* | 149 | /* |
150 | * IPU Common functions | ||
151 | */ | ||
152 | void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2); | ||
153 | void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi); | ||
154 | void ipu_dump(struct ipu_soc *ipu); | ||
155 | |||
156 | /* | ||
96 | * IPU Image DMA Controller (idmac) functions | 157 | * IPU Image DMA Controller (idmac) functions |
97 | */ | 158 | */ |
98 | struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel); | 159 | struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel); |
@@ -100,12 +161,58 @@ void ipu_idmac_put(struct ipuv3_channel *); | |||
100 | 161 | ||
101 | int ipu_idmac_enable_channel(struct ipuv3_channel *channel); | 162 | int ipu_idmac_enable_channel(struct ipuv3_channel *channel); |
102 | int ipu_idmac_disable_channel(struct ipuv3_channel *channel); | 163 | int ipu_idmac_disable_channel(struct ipuv3_channel *channel); |
164 | void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable); | ||
165 | int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts); | ||
103 | int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms); | 166 | int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms); |
104 | 167 | ||
105 | void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, | 168 | void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, |
106 | bool doublebuffer); | 169 | bool doublebuffer); |
107 | int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel); | 170 | int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel); |
171 | bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num); | ||
108 | void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num); | 172 | void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num); |
173 | void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num); | ||
174 | |||
175 | /* | ||
176 | * IPU Channel Parameter Memory (cpmem) functions | ||
177 | */ | ||
178 | struct ipu_rgb { | ||
179 | struct fb_bitfield red; | ||
180 | struct fb_bitfield green; | ||
181 | struct fb_bitfield blue; | ||
182 | struct fb_bitfield transp; | ||
183 | int bits_per_pixel; | ||
184 | }; | ||
185 | |||
186 | struct ipu_image { | ||
187 | struct v4l2_pix_format pix; | ||
188 | struct v4l2_rect rect; | ||
189 | dma_addr_t phys0; | ||
190 | dma_addr_t phys1; | ||
191 | }; | ||
192 | |||
193 | void ipu_cpmem_zero(struct ipuv3_channel *ch); | ||
194 | void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres); | ||
195 | void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride); | ||
196 | void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch); | ||
197 | void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf); | ||
198 | void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride); | ||
199 | void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id); | ||
200 | void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize); | ||
201 | void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch); | ||
202 | void ipu_cpmem_set_rotation(struct ipuv3_channel *ch, | ||
203 | enum ipu_rotate_mode rot); | ||
204 | int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch, | ||
205 | const struct ipu_rgb *rgb); | ||
206 | int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width); | ||
207 | void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format); | ||
208 | void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, | ||
209 | u32 pixel_format, int stride, | ||
210 | int u_offset, int v_offset); | ||
211 | void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, | ||
212 | u32 pixel_format, int stride, int height); | ||
213 | int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc); | ||
214 | int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image); | ||
215 | void ipu_cpmem_dump(struct ipuv3_channel *ch); | ||
109 | 216 | ||
110 | /* | 217 | /* |
111 | * IPU Display Controller (dc) functions | 218 | * IPU Display Controller (dc) functions |
@@ -169,171 +276,78 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, | |||
169 | /* | 276 | /* |
170 | * IPU CMOS Sensor Interface (csi) functions | 277 | * IPU CMOS Sensor Interface (csi) functions |
171 | */ | 278 | */ |
172 | int ipu_csi_enable(struct ipu_soc *ipu, int csi); | 279 | struct ipu_csi; |
173 | int ipu_csi_disable(struct ipu_soc *ipu, int csi); | 280 | int ipu_csi_init_interface(struct ipu_csi *csi, |
281 | struct v4l2_mbus_config *mbus_cfg, | ||
282 | struct v4l2_mbus_framefmt *mbus_fmt); | ||
283 | bool ipu_csi_is_interlaced(struct ipu_csi *csi); | ||
284 | void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w); | ||
285 | void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w); | ||
286 | void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, | ||
287 | u32 r_value, u32 g_value, u32 b_value, | ||
288 | u32 pix_clk); | ||
289 | int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, | ||
290 | struct v4l2_mbus_framefmt *mbus_fmt); | ||
291 | int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip, | ||
292 | u32 max_ratio, u32 id); | ||
293 | int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest); | ||
294 | int ipu_csi_enable(struct ipu_csi *csi); | ||
295 | int ipu_csi_disable(struct ipu_csi *csi); | ||
296 | struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id); | ||
297 | void ipu_csi_put(struct ipu_csi *csi); | ||
298 | void ipu_csi_dump(struct ipu_csi *csi); | ||
174 | 299 | ||
175 | /* | 300 | /* |
176 | * IPU Sensor Multiple FIFO Controller (SMFC) functions | 301 | * IPU Image Converter (ic) functions |
177 | */ | 302 | */ |
178 | int ipu_smfc_enable(struct ipu_soc *ipu); | 303 | enum ipu_ic_task { |
179 | int ipu_smfc_disable(struct ipu_soc *ipu); | 304 | IC_TASK_ENCODER, |
180 | int ipu_smfc_map_channel(struct ipu_soc *ipu, int channel, int csi_id, int mipi_id); | 305 | IC_TASK_VIEWFINDER, |
181 | int ipu_smfc_set_burstsize(struct ipu_soc *ipu, int channel, int burstsize); | 306 | IC_TASK_POST_PROCESSOR, |
182 | 307 | IC_NUM_TASKS, | |
183 | #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) | ||
184 | |||
185 | #define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) | ||
186 | #define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) | ||
187 | #define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) | ||
188 | #define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) | ||
189 | #define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) | ||
190 | #define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) | ||
191 | #define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) | ||
192 | |||
193 | #define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) | ||
194 | #define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) | ||
195 | #define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) | ||
196 | #define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) | ||
197 | #define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) | ||
198 | #define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) | ||
199 | #define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) | ||
200 | #define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) | ||
201 | #define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) | ||
202 | #define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) | ||
203 | #define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) | ||
204 | #define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) | ||
205 | #define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) | ||
206 | #define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) | ||
207 | #define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) | ||
208 | #define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) | ||
209 | #define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) | ||
210 | #define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) | ||
211 | #define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) | ||
212 | #define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) | ||
213 | #define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) | ||
214 | #define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) | ||
215 | #define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) | ||
216 | #define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) | ||
217 | #define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) | ||
218 | #define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) | ||
219 | #define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) | ||
220 | #define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) | ||
221 | #define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) | ||
222 | #define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) | ||
223 | #define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) | ||
224 | #define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) | ||
225 | #define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) | ||
226 | #define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) | ||
227 | #define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) | ||
228 | #define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) | ||
229 | #define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) | ||
230 | #define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) | ||
231 | #define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) | ||
232 | #define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) | ||
233 | #define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) | ||
234 | #define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) | ||
235 | #define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) | ||
236 | #define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) | ||
237 | #define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) | ||
238 | #define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) | ||
239 | #define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) | ||
240 | #define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) | ||
241 | #define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) | ||
242 | #define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) | ||
243 | |||
244 | struct ipu_cpmem_word { | ||
245 | u32 data[5]; | ||
246 | u32 res[3]; | ||
247 | }; | ||
248 | |||
249 | struct ipu_ch_param { | ||
250 | struct ipu_cpmem_word word[2]; | ||
251 | }; | ||
252 | |||
253 | void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v); | ||
254 | u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs); | ||
255 | struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel); | ||
256 | void ipu_ch_param_dump(struct ipu_ch_param __iomem *p); | ||
257 | |||
258 | static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p) | ||
259 | { | ||
260 | int i; | ||
261 | void __iomem *base = p; | ||
262 | |||
263 | for (i = 0; i < sizeof(*p) / sizeof(u32); i++) | ||
264 | writel(0, base + i * sizeof(u32)); | ||
265 | } | ||
266 | |||
267 | static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p, | ||
268 | int bufnum, dma_addr_t buf) | ||
269 | { | ||
270 | if (bufnum) | ||
271 | ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3); | ||
272 | else | ||
273 | ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3); | ||
274 | } | ||
275 | |||
276 | static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p, | ||
277 | int xres, int yres) | ||
278 | { | ||
279 | ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1); | ||
280 | ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1); | ||
281 | } | ||
282 | |||
283 | static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p, | ||
284 | int stride) | ||
285 | { | ||
286 | ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1); | ||
287 | } | ||
288 | |||
289 | void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel); | ||
290 | |||
291 | struct ipu_rgb { | ||
292 | struct fb_bitfield red; | ||
293 | struct fb_bitfield green; | ||
294 | struct fb_bitfield blue; | ||
295 | struct fb_bitfield transp; | ||
296 | int bits_per_pixel; | ||
297 | }; | ||
298 | |||
299 | struct ipu_image { | ||
300 | struct v4l2_pix_format pix; | ||
301 | struct v4l2_rect rect; | ||
302 | dma_addr_t phys; | ||
303 | }; | 308 | }; |
304 | 309 | ||
305 | int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, | 310 | struct ipu_ic; |
306 | int width); | 311 | int ipu_ic_task_init(struct ipu_ic *ic, |
307 | 312 | int in_width, int in_height, | |
308 | int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *, | 313 | int out_width, int out_height, |
309 | const struct ipu_rgb *rgb); | 314 | enum ipu_color_space in_cs, |
310 | 315 | enum ipu_color_space out_cs); | |
311 | static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p, | 316 | int ipu_ic_task_graphics_init(struct ipu_ic *ic, |
312 | int stride) | 317 | enum ipu_color_space in_g_cs, |
313 | { | 318 | bool galpha_en, u32 galpha, |
314 | ipu_ch_param_write_field(p, IPU_FIELD_SO, 1); | 319 | bool colorkey_en, u32 colorkey); |
315 | ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8); | 320 | void ipu_ic_task_enable(struct ipu_ic *ic); |
316 | ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1); | 321 | void ipu_ic_task_disable(struct ipu_ic *ic); |
317 | }; | 322 | int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel, |
323 | u32 width, u32 height, int burst_size, | ||
324 | enum ipu_rotate_mode rot); | ||
325 | int ipu_ic_enable(struct ipu_ic *ic); | ||
326 | int ipu_ic_disable(struct ipu_ic *ic); | ||
327 | struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task); | ||
328 | void ipu_ic_put(struct ipu_ic *ic); | ||
329 | void ipu_ic_dump(struct ipu_ic *ic); | ||
318 | 330 | ||
319 | void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, | 331 | /* |
320 | int stride, int height); | 332 | * IPU Sensor Multiple FIFO Controller (SMFC) functions |
321 | void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, | 333 | */ |
322 | u32 pixel_format); | 334 | struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno); |
323 | void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, | 335 | void ipu_smfc_put(struct ipu_smfc *smfc); |
324 | u32 pixel_format, int stride, int u_offset, int v_offset); | 336 | int ipu_smfc_enable(struct ipu_smfc *smfc); |
325 | int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat); | 337 | int ipu_smfc_disable(struct ipu_smfc *smfc); |
326 | int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, | 338 | int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id); |
327 | struct ipu_image *image); | 339 | int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize); |
340 | int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level); | ||
328 | 341 | ||
329 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); | 342 | enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc); |
330 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); | 343 | enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); |
331 | 344 | enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code); | |
332 | static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p, | 345 | int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat); |
333 | int burstsize) | 346 | bool ipu_pixelformat_is_planar(u32 pixelformat); |
334 | { | 347 | int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, |
335 | ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1); | 348 | bool hflip, bool vflip); |
336 | }; | 349 | int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, |
350 | bool hflip, bool vflip); | ||
337 | 351 | ||
338 | struct ipu_client_platformdata { | 352 | struct ipu_client_platformdata { |
339 | int csi; | 353 | int csi; |