Commit 575001e40c9d10e63f2924649098e7c07d3985c7
Committed by
Anatolij Gustschin
1 parent
bf90ecd3c3
Exists in
master
and in
54 other branches
MX51: Add IPU driver for video support
The patch is a porting of the IPU Linux driver developed by Freescale to have framebuffer functionalities in u-boot. The port is based on kernel 2.6.31 commit cc4fe714041805997b601fe8e5dd585d8a99297f, as delivered by Freescale [i.MX BSP]. Most features are dropped from the original driver and only LCD support is the goal of this porting. Signed-off-by: Stefano Babic <sbabic@denx.de>
Showing 5 changed files with 3292 additions and 0 deletions Side-by-side Diff
arch/arm/include/asm/arch-mx5/crm_regs.h
... | ... | @@ -189,5 +189,16 @@ |
189 | 189 | #define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET 0 |
190 | 190 | #define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK 0x7 |
191 | 191 | |
192 | +/* Define the bits in register CCDR */ | |
193 | +#define MXC_CCM_CCDR_IPU_HS_MASK (0x1 << 17) | |
194 | + | |
195 | +/* Define the bits in register CCGRx */ | |
196 | +#define MXC_CCM_CCGR_CG_MASK 0x3 | |
197 | + | |
198 | +#define MXC_CCM_CCGR5_CG5_OFFSET 10 | |
199 | + | |
200 | +/* Define the bits in register CLPCR */ | |
201 | +#define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS (0x1 << 18) | |
202 | + | |
192 | 203 | #endif /* __ARCH_ARM_MACH_MX51_CRM_REGS_H__ */ |
drivers/video/ipu.h
1 | +/* | |
2 | + * Porting to u-boot: | |
3 | + * | |
4 | + * (C) Copyright 2010 | |
5 | + * Stefano Babic, DENX Software Engineering, sbabic@denx.de | |
6 | + * | |
7 | + * Linux IPU driver for MX51: | |
8 | + * | |
9 | + * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. | |
10 | + * | |
11 | + * See file CREDITS for list of people who contributed to this | |
12 | + * project. | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or | |
15 | + * modify it under the terms of the GNU General Public License as | |
16 | + * published by the Free Software Foundation; either version 2 of | |
17 | + * the License, or (at your option) any later version. | |
18 | + * | |
19 | + * This program is distributed in the hope that it will be useful, | |
20 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | + * GNU General Public License for more details. | |
23 | + * | |
24 | + * You should have received a copy of the GNU General Public License | |
25 | + * along with this program; if not, write to the Free Software | |
26 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
27 | + * MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +#ifndef __ASM_ARCH_IPU_H__ | |
31 | +#define __ASM_ARCH_IPU_H__ | |
32 | + | |
33 | +#include <linux/types.h> | |
34 | + | |
35 | +#define IDMA_CHAN_INVALID 0xFF | |
36 | +#define HIGH_RESOLUTION_WIDTH 1024 | |
37 | + | |
38 | +struct clk { | |
39 | + const char *name; | |
40 | + int id; | |
41 | + /* Source clock this clk depends on */ | |
42 | + struct clk *parent; | |
43 | + /* Secondary clock to enable/disable with this clock */ | |
44 | + struct clk *secondary; | |
45 | + /* Current clock rate */ | |
46 | + unsigned long rate; | |
47 | + /* Reference count of clock enable/disable */ | |
48 | + __s8 usecount; | |
49 | + /* Register bit position for clock's enable/disable control. */ | |
50 | + u8 enable_shift; | |
51 | + /* Register address for clock's enable/disable control. */ | |
52 | + void *enable_reg; | |
53 | + u32 flags; | |
54 | + /* | |
55 | + * Function ptr to recalculate the clock's rate based on parent | |
56 | + * clock's rate | |
57 | + */ | |
58 | + void (*recalc) (struct clk *); | |
59 | + /* | |
60 | + * Function ptr to set the clock to a new rate. The rate must match a | |
61 | + * supported rate returned from round_rate. Leave blank if clock is not | |
62 | + * programmable | |
63 | + */ | |
64 | + int (*set_rate) (struct clk *, unsigned long); | |
65 | + /* | |
66 | + * Function ptr to round the requested clock rate to the nearest | |
67 | + * supported rate that is less than or equal to the requested rate. | |
68 | + */ | |
69 | + unsigned long (*round_rate) (struct clk *, unsigned long); | |
70 | + /* | |
71 | + * Function ptr to enable the clock. Leave blank if clock can not | |
72 | + * be gated. | |
73 | + */ | |
74 | + int (*enable) (struct clk *); | |
75 | + /* | |
76 | + * Function ptr to disable the clock. Leave blank if clock can not | |
77 | + * be gated. | |
78 | + */ | |
79 | + void (*disable) (struct clk *); | |
80 | + /* Function ptr to set the parent clock of the clock. */ | |
81 | + int (*set_parent) (struct clk *, struct clk *); | |
82 | +}; | |
83 | + | |
84 | +/* | |
85 | + * Enumeration of Synchronous (Memory-less) panel types | |
86 | + */ | |
87 | +typedef enum { | |
88 | + IPU_PANEL_SHARP_TFT, | |
89 | + IPU_PANEL_TFT, | |
90 | +} ipu_panel_t; | |
91 | + | |
92 | +/* IPU Pixel format definitions */ | |
93 | +#define fourcc(a, b, c, d)\ | |
94 | + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) | |
95 | + | |
96 | +/* | |
97 | + * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are | |
98 | + * the same used by V4L2 API. | |
99 | + */ | |
100 | + | |
101 | +#define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0') | |
102 | +#define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1') | |
103 | +#define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6') | |
104 | +#define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8') | |
105 | + | |
106 | +#define IPU_PIX_FMT_RGB332 fourcc('R', 'G', 'B', '1') /*< 8 RGB-3-3-2 */ | |
107 | +#define IPU_PIX_FMT_RGB555 fourcc('R', 'G', 'B', 'O') /*< 16 RGB-5-5-5 */ | |
108 | +#define IPU_PIX_FMT_RGB565 fourcc('R', 'G', 'B', 'P') /*< 1 6 RGB-5-6-5 */ | |
109 | +#define IPU_PIX_FMT_RGB666 fourcc('R', 'G', 'B', '6') /*< 18 RGB-6-6-6 */ | |
110 | +#define IPU_PIX_FMT_BGR666 fourcc('B', 'G', 'R', '6') /*< 18 BGR-6-6-6 */ | |
111 | +#define IPU_PIX_FMT_BGR24 fourcc('B', 'G', 'R', '3') /*< 24 BGR-8-8-8 */ | |
112 | +#define IPU_PIX_FMT_RGB24 fourcc('R', 'G', 'B', '3') /*< 24 RGB-8-8-8 */ | |
113 | +#define IPU_PIX_FMT_BGR32 fourcc('B', 'G', 'R', '4') /*< 32 BGR-8-8-8-8 */ | |
114 | +#define IPU_PIX_FMT_BGRA32 fourcc('B', 'G', 'R', 'A') /*< 32 BGR-8-8-8-8 */ | |
115 | +#define IPU_PIX_FMT_RGB32 fourcc('R', 'G', 'B', '4') /*< 32 RGB-8-8-8-8 */ | |
116 | +#define IPU_PIX_FMT_RGBA32 fourcc('R', 'G', 'B', 'A') /*< 32 RGB-8-8-8-8 */ | |
117 | +#define IPU_PIX_FMT_ABGR32 fourcc('A', 'B', 'G', 'R') /*< 32 ABGR-8-8-8-8 */ | |
118 | + | |
119 | +/* YUV Interleaved Formats */ | |
120 | +#define IPU_PIX_FMT_YUYV fourcc('Y', 'U', 'Y', 'V') /*< 16 YUV 4:2:2 */ | |
121 | +#define IPU_PIX_FMT_UYVY fourcc('U', 'Y', 'V', 'Y') /*< 16 YUV 4:2:2 */ | |
122 | +#define IPU_PIX_FMT_Y41P fourcc('Y', '4', '1', 'P') /*< 12 YUV 4:1:1 */ | |
123 | +#define IPU_PIX_FMT_YUV444 fourcc('Y', '4', '4', '4') /*< 24 YUV 4:4:4 */ | |
124 | + | |
125 | +/* two planes -- one Y, one Cb + Cr interleaved */ | |
126 | +#define IPU_PIX_FMT_NV12 fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ | |
127 | + | |
128 | +#define IPU_PIX_FMT_GREY fourcc('G', 'R', 'E', 'Y') /*< 8 Greyscale */ | |
129 | +#define IPU_PIX_FMT_YVU410P fourcc('Y', 'V', 'U', '9') /*< 9 YVU 4:1:0 */ | |
130 | +#define IPU_PIX_FMT_YUV410P fourcc('Y', 'U', 'V', '9') /*< 9 YUV 4:1:0 */ | |
131 | +#define IPU_PIX_FMT_YVU420P fourcc('Y', 'V', '1', '2') /*< 12 YVU 4:2:0 */ | |
132 | +#define IPU_PIX_FMT_YUV420P fourcc('I', '4', '2', '0') /*< 12 YUV 4:2:0 */ | |
133 | +#define IPU_PIX_FMT_YUV420P2 fourcc('Y', 'U', '1', '2') /*< 12 YUV 4:2:0 */ | |
134 | +#define IPU_PIX_FMT_YVU422P fourcc('Y', 'V', '1', '6') /*< 16 YVU 4:2:2 */ | |
135 | +#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P') /*< 16 YUV 4:2:2 */ | |
136 | + | |
137 | +/* | |
138 | + * IPU Driver channels definitions. | |
139 | + * Note these are different from IDMA channels | |
140 | + */ | |
141 | +#define IPU_MAX_CH 32 | |
142 | +#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \ | |
143 | + ((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out) | |
144 | +#define _MAKE_ALT_CHAN(ch) (ch | (IPU_MAX_CH << 24)) | |
145 | +#define IPU_CHAN_ID(ch) (ch >> 24) | |
146 | +#define IPU_CHAN_ALT(ch) (ch & 0x02000000) | |
147 | +#define IPU_CHAN_ALPHA_IN_DMA(ch) ((uint32_t) (ch >> 6) & 0x3F) | |
148 | +#define IPU_CHAN_GRAPH_IN_DMA(ch) ((uint32_t) (ch >> 12) & 0x3F) | |
149 | +#define IPU_CHAN_VIDEO_IN_DMA(ch) ((uint32_t) (ch >> 18) & 0x3F) | |
150 | +#define IPU_CHAN_OUT_DMA(ch) ((uint32_t) (ch & 0x3F)) | |
151 | +#define NO_DMA 0x3F | |
152 | +#define ALT 1 | |
153 | + | |
154 | +/* | |
155 | + * Enumeration of IPU logical channels. An IPU logical channel is defined as a | |
156 | + * combination of an input (memory to IPU), output (IPU to memory), and/or | |
157 | + * secondary input IDMA channels and in some cases an Image Converter task. | |
158 | + * Some channels consist of only an input or output. | |
159 | + */ | |
160 | +typedef enum { | |
161 | + CHAN_NONE = -1, | |
162 | + | |
163 | + MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA), | |
164 | + MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA), | |
165 | + MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA), | |
166 | + MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA), | |
167 | + | |
168 | + MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA), | |
169 | + MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA), | |
170 | + MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0), | |
171 | + MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0), | |
172 | + | |
173 | + DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA), | |
174 | + DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA), | |
175 | + | |
176 | +} ipu_channel_t; | |
177 | + | |
178 | +/* | |
179 | + * Enumeration of types of buffers for a logical channel. | |
180 | + */ | |
181 | +typedef enum { | |
182 | + IPU_OUTPUT_BUFFER = 0, /*< Buffer for output from IPU */ | |
183 | + IPU_ALPHA_IN_BUFFER = 1, /*< Buffer for input to IPU */ | |
184 | + IPU_GRAPH_IN_BUFFER = 2, /*< Buffer for input to IPU */ | |
185 | + IPU_VIDEO_IN_BUFFER = 3, /*< Buffer for input to IPU */ | |
186 | + IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER, | |
187 | + IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER, | |
188 | +} ipu_buffer_t; | |
189 | + | |
190 | +#define IPU_PANEL_SERIAL 1 | |
191 | +#define IPU_PANEL_PARALLEL 2 | |
192 | + | |
193 | +struct ipu_channel { | |
194 | + u8 video_in_dma; | |
195 | + u8 alpha_in_dma; | |
196 | + u8 graph_in_dma; | |
197 | + u8 out_dma; | |
198 | +}; | |
199 | + | |
200 | +enum ipu_dmfc_type { | |
201 | + DMFC_NORMAL = 0, | |
202 | + DMFC_HIGH_RESOLUTION_DC, | |
203 | + DMFC_HIGH_RESOLUTION_DP, | |
204 | + DMFC_HIGH_RESOLUTION_ONLY_DP, | |
205 | +}; | |
206 | + | |
207 | + | |
208 | +/* | |
209 | + * Union of initialization parameters for a logical channel. | |
210 | + */ | |
211 | +typedef union { | |
212 | + struct { | |
213 | + uint32_t di; | |
214 | + unsigned char interlaced; | |
215 | + } mem_dc_sync; | |
216 | + struct { | |
217 | + uint32_t temp; | |
218 | + } mem_sdc_fg; | |
219 | + struct { | |
220 | + uint32_t di; | |
221 | + unsigned char interlaced; | |
222 | + uint32_t in_pixel_fmt; | |
223 | + uint32_t out_pixel_fmt; | |
224 | + unsigned char alpha_chan_en; | |
225 | + } mem_dp_bg_sync; | |
226 | + struct { | |
227 | + uint32_t temp; | |
228 | + } mem_sdc_bg; | |
229 | + struct { | |
230 | + uint32_t di; | |
231 | + unsigned char interlaced; | |
232 | + uint32_t in_pixel_fmt; | |
233 | + uint32_t out_pixel_fmt; | |
234 | + unsigned char alpha_chan_en; | |
235 | + } mem_dp_fg_sync; | |
236 | +} ipu_channel_params_t; | |
237 | + | |
238 | +/* | |
239 | + * Bitfield of Display Interface signal polarities. | |
240 | + */ | |
241 | +typedef struct { | |
242 | + unsigned datamask_en:1; | |
243 | + unsigned ext_clk:1; | |
244 | + unsigned interlaced:1; | |
245 | + unsigned odd_field_first:1; | |
246 | + unsigned clksel_en:1; | |
247 | + unsigned clkidle_en:1; | |
248 | + unsigned data_pol:1; /* true = inverted */ | |
249 | + unsigned clk_pol:1; /* true = rising edge */ | |
250 | + unsigned enable_pol:1; | |
251 | + unsigned Hsync_pol:1; /* true = active high */ | |
252 | + unsigned Vsync_pol:1; | |
253 | +} ipu_di_signal_cfg_t; | |
254 | + | |
255 | +typedef enum { | |
256 | + RGB, | |
257 | + YCbCr, | |
258 | + YUV | |
259 | +} ipu_color_space_t; | |
260 | + | |
261 | +/* Common IPU API */ | |
262 | +int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params); | |
263 | +void ipu_uninit_channel(ipu_channel_t channel); | |
264 | + | |
265 | +int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, | |
266 | + uint32_t pixel_fmt, | |
267 | + uint16_t width, uint16_t height, | |
268 | + uint32_t stride, | |
269 | + dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, | |
270 | + uint32_t u_offset, uint32_t v_offset); | |
271 | + | |
272 | +int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, | |
273 | + uint32_t bufNum, dma_addr_t phyaddr); | |
274 | + | |
275 | +int32_t ipu_is_channel_busy(ipu_channel_t channel); | |
276 | +void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, | |
277 | + uint32_t bufNum); | |
278 | +int32_t ipu_enable_channel(ipu_channel_t channel); | |
279 | +int32_t ipu_disable_channel(ipu_channel_t channel); | |
280 | + | |
281 | +int32_t ipu_init_sync_panel(int disp, | |
282 | + uint32_t pixel_clk, | |
283 | + uint16_t width, uint16_t height, | |
284 | + uint32_t pixel_fmt, | |
285 | + uint16_t h_start_width, uint16_t h_sync_width, | |
286 | + uint16_t h_end_width, uint16_t v_start_width, | |
287 | + uint16_t v_sync_width, uint16_t v_end_width, | |
288 | + uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig); | |
289 | + | |
290 | +int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable, | |
291 | + uint8_t alpha); | |
292 | +int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable, | |
293 | + uint32_t colorKey); | |
294 | + | |
295 | +uint32_t bytes_per_pixel(uint32_t fmt); | |
296 | + | |
297 | +void clk_enable(struct clk *clk); | |
298 | +void clk_disable(struct clk *clk); | |
299 | +u32 clk_get_rate(struct clk *clk); | |
300 | +int clk_set_rate(struct clk *clk, unsigned long rate); | |
301 | +long clk_round_rate(struct clk *clk, unsigned long rate); | |
302 | +int clk_set_parent(struct clk *clk, struct clk *parent); | |
303 | +int clk_get_usecount(struct clk *clk); | |
304 | +struct clk *clk_get_parent(struct clk *clk); | |
305 | + | |
306 | +void ipu_dump_registers(void); | |
307 | +int ipu_probe(void); | |
308 | + | |
309 | +void ipu_dmfc_init(int dmfc_type, int first); | |
310 | +void ipu_init_dc_mappings(void); | |
311 | +void ipu_dmfc_set_wait4eot(int dma_chan, int width); | |
312 | +void ipu_dc_init(int dc_chan, int di, unsigned char interlaced); | |
313 | +void ipu_dc_uninit(int dc_chan); | |
314 | +void ipu_dp_dc_enable(ipu_channel_t channel); | |
315 | +int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, | |
316 | + uint32_t out_pixel_fmt); | |
317 | +void ipu_dp_uninit(ipu_channel_t channel); | |
318 | +void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap); | |
319 | +ipu_color_space_t format_to_colorspace(uint32_t fmt); | |
320 | + | |
321 | +#endif |
drivers/video/ipu_common.c
Changes suppressed. Click to show
1 | +/* | |
2 | + * Porting to u-boot: | |
3 | + * | |
4 | + * (C) Copyright 2010 | |
5 | + * Stefano Babic, DENX Software Engineering, sbabic@denx.de | |
6 | + * | |
7 | + * Linux IPU driver for MX51: | |
8 | + * | |
9 | + * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. | |
10 | + * | |
11 | + * See file CREDITS for list of people who contributed to this | |
12 | + * project. | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or | |
15 | + * modify it under the terms of the GNU General Public License as | |
16 | + * published by the Free Software Foundation; either version 2 of | |
17 | + * the License, or (at your option) any later version. | |
18 | + * | |
19 | + * This program is distributed in the hope that it will be useful, | |
20 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | + * GNU General Public License for more details. | |
23 | + * | |
24 | + * You should have received a copy of the GNU General Public License | |
25 | + * along with this program; if not, write to the Free Software | |
26 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
27 | + * MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +/* #define DEBUG */ | |
31 | +#include <common.h> | |
32 | +#include <linux/types.h> | |
33 | +#include <linux/err.h> | |
34 | +#include <asm/io.h> | |
35 | +#include <asm/errno.h> | |
36 | +#include <asm/arch/imx-regs.h> | |
37 | +#include <asm/arch/crm_regs.h> | |
38 | +#include "ipu.h" | |
39 | +#include "ipu_regs.h" | |
40 | + | |
41 | +extern struct mxc_ccm_reg *mxc_ccm; | |
42 | +extern u32 *ipu_cpmem_base; | |
43 | + | |
44 | +struct ipu_ch_param_word { | |
45 | + uint32_t data[5]; | |
46 | + uint32_t res[3]; | |
47 | +}; | |
48 | + | |
49 | +struct ipu_ch_param { | |
50 | + struct ipu_ch_param_word word[2]; | |
51 | +}; | |
52 | + | |
53 | +#define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch)) | |
54 | + | |
55 | +#define _param_word(base, w) \ | |
56 | + (((struct ipu_ch_param *)(base))->word[(w)].data) | |
57 | + | |
58 | +#define ipu_ch_param_set_field(base, w, bit, size, v) { \ | |
59 | + int i = (bit) / 32; \ | |
60 | + int off = (bit) % 32; \ | |
61 | + _param_word(base, w)[i] |= (v) << off; \ | |
62 | + if (((bit) + (size) - 1) / 32 > i) { \ | |
63 | + _param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \ | |
64 | + } \ | |
65 | +} | |
66 | + | |
67 | +#define ipu_ch_param_mod_field(base, w, bit, size, v) { \ | |
68 | + int i = (bit) / 32; \ | |
69 | + int off = (bit) % 32; \ | |
70 | + u32 mask = (1UL << size) - 1; \ | |
71 | + u32 temp = _param_word(base, w)[i]; \ | |
72 | + temp &= ~(mask << off); \ | |
73 | + _param_word(base, w)[i] = temp | (v) << off; \ | |
74 | + if (((bit) + (size) - 1) / 32 > i) { \ | |
75 | + temp = _param_word(base, w)[i + 1]; \ | |
76 | + temp &= ~(mask >> (32 - off)); \ | |
77 | + _param_word(base, w)[i + 1] = \ | |
78 | + temp | ((v) >> (off ? (32 - off) : 0)); \ | |
79 | + } \ | |
80 | +} | |
81 | + | |
82 | +#define ipu_ch_param_read_field(base, w, bit, size) ({ \ | |
83 | + u32 temp2; \ | |
84 | + int i = (bit) / 32; \ | |
85 | + int off = (bit) % 32; \ | |
86 | + u32 mask = (1UL << size) - 1; \ | |
87 | + u32 temp1 = _param_word(base, w)[i]; \ | |
88 | + temp1 = mask & (temp1 >> off); \ | |
89 | + if (((bit)+(size) - 1) / 32 > i) { \ | |
90 | + temp2 = _param_word(base, w)[i + 1]; \ | |
91 | + temp2 &= mask >> (off ? (32 - off) : 0); \ | |
92 | + temp1 |= temp2 << (off ? (32 - off) : 0); \ | |
93 | + } \ | |
94 | + temp1; \ | |
95 | +}) | |
96 | + | |
97 | + | |
98 | +void clk_enable(struct clk *clk) | |
99 | +{ | |
100 | + if (clk) { | |
101 | + if (clk->usecount++ == 0) { | |
102 | + clk->enable(clk); | |
103 | + } | |
104 | + } | |
105 | +} | |
106 | + | |
107 | +void clk_disable(struct clk *clk) | |
108 | +{ | |
109 | + if (clk) { | |
110 | + if (!(--clk->usecount)) { | |
111 | + if (clk->disable) | |
112 | + clk->disable(clk); | |
113 | + } | |
114 | + } | |
115 | +} | |
116 | + | |
117 | +int clk_get_usecount(struct clk *clk) | |
118 | +{ | |
119 | + if (clk == NULL) | |
120 | + return 0; | |
121 | + | |
122 | + return clk->usecount; | |
123 | +} | |
124 | + | |
125 | +u32 clk_get_rate(struct clk *clk) | |
126 | +{ | |
127 | + if (!clk) | |
128 | + return 0; | |
129 | + | |
130 | + return clk->rate; | |
131 | +} | |
132 | + | |
133 | +struct clk *clk_get_parent(struct clk *clk) | |
134 | +{ | |
135 | + if (!clk) | |
136 | + return 0; | |
137 | + | |
138 | + return clk->parent; | |
139 | +} | |
140 | + | |
141 | +int clk_set_rate(struct clk *clk, unsigned long rate) | |
142 | +{ | |
143 | + if (clk && clk->set_rate) | |
144 | + clk->set_rate(clk, rate); | |
145 | + return clk->rate; | |
146 | +} | |
147 | + | |
148 | +long clk_round_rate(struct clk *clk, unsigned long rate) | |
149 | +{ | |
150 | + if (clk == NULL || !clk->round_rate) | |
151 | + return 0; | |
152 | + | |
153 | + return clk->round_rate(clk, rate); | |
154 | +} | |
155 | + | |
156 | +int clk_set_parent(struct clk *clk, struct clk *parent) | |
157 | +{ | |
158 | + clk->parent = parent; | |
159 | + if (clk->set_parent) | |
160 | + return clk->set_parent(clk, parent); | |
161 | + return 0; | |
162 | +} | |
163 | + | |
164 | +static int clk_ipu_enable(struct clk *clk) | |
165 | +{ | |
166 | + u32 reg; | |
167 | + | |
168 | + reg = __raw_readl(clk->enable_reg); | |
169 | + reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift; | |
170 | + __raw_writel(reg, clk->enable_reg); | |
171 | + | |
172 | + /* Handshake with IPU when certain clock rates are changed. */ | |
173 | + reg = __raw_readl(&mxc_ccm->ccdr); | |
174 | + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; | |
175 | + __raw_writel(reg, &mxc_ccm->ccdr); | |
176 | + | |
177 | + /* Handshake with IPU when LPM is entered as its enabled. */ | |
178 | + reg = __raw_readl(&mxc_ccm->clpcr); | |
179 | + reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; | |
180 | + __raw_writel(reg, &mxc_ccm->clpcr); | |
181 | + | |
182 | + return 0; | |
183 | +} | |
184 | + | |
185 | +static void clk_ipu_disable(struct clk *clk) | |
186 | +{ | |
187 | + u32 reg; | |
188 | + | |
189 | + reg = __raw_readl(clk->enable_reg); | |
190 | + reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift); | |
191 | + __raw_writel(reg, clk->enable_reg); | |
192 | + | |
193 | + /* | |
194 | + * No handshake with IPU whe dividers are changed | |
195 | + * as its not enabled. | |
196 | + */ | |
197 | + reg = __raw_readl(&mxc_ccm->ccdr); | |
198 | + reg |= MXC_CCM_CCDR_IPU_HS_MASK; | |
199 | + __raw_writel(reg, &mxc_ccm->ccdr); | |
200 | + | |
201 | + /* No handshake with IPU when LPM is entered as its not enabled. */ | |
202 | + reg = __raw_readl(&mxc_ccm->clpcr); | |
203 | + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; | |
204 | + __raw_writel(reg, &mxc_ccm->clpcr); | |
205 | +} | |
206 | + | |
207 | + | |
208 | +static struct clk ipu_clk = { | |
209 | + .name = "ipu_clk", | |
210 | + .rate = 133000000, | |
211 | + .enable_reg = (u32 *)(MXC_CCM_BASE + | |
212 | + offsetof(struct mxc_ccm_reg, CCGR5)), | |
213 | + .enable_shift = MXC_CCM_CCGR5_CG5_OFFSET, | |
214 | + .enable = clk_ipu_enable, | |
215 | + .disable = clk_ipu_disable, | |
216 | + .usecount = 0, | |
217 | +}; | |
218 | + | |
219 | +/* Globals */ | |
220 | +struct clk *g_ipu_clk; | |
221 | +unsigned char g_ipu_clk_enabled; | |
222 | +struct clk *g_di_clk[2]; | |
223 | +struct clk *g_pixel_clk[2]; | |
224 | +unsigned char g_dc_di_assignment[10]; | |
225 | +uint32_t g_channel_init_mask; | |
226 | +uint32_t g_channel_enable_mask; | |
227 | + | |
228 | +static int ipu_dc_use_count; | |
229 | +static int ipu_dp_use_count; | |
230 | +static int ipu_dmfc_use_count; | |
231 | +static int ipu_di_use_count[2]; | |
232 | + | |
233 | +u32 *ipu_cpmem_base; | |
234 | +u32 *ipu_dc_tmpl_reg; | |
235 | + | |
236 | +/* Static functions */ | |
237 | + | |
238 | +static inline void ipu_ch_param_set_high_priority(uint32_t ch) | |
239 | +{ | |
240 | + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 93, 2, 1); | |
241 | +}; | |
242 | + | |
243 | +static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type) | |
244 | +{ | |
245 | + return ((uint32_t) ch >> (6 * type)) & 0x3F; | |
246 | +}; | |
247 | + | |
248 | +/* Either DP BG or DP FG can be graphic window */ | |
249 | +static inline int ipu_is_dp_graphic_chan(uint32_t dma_chan) | |
250 | +{ | |
251 | + return (dma_chan == 23 || dma_chan == 27); | |
252 | +} | |
253 | + | |
254 | +static inline int ipu_is_dmfc_chan(uint32_t dma_chan) | |
255 | +{ | |
256 | + return ((dma_chan >= 23) && (dma_chan <= 29)); | |
257 | +} | |
258 | + | |
259 | + | |
260 | +static inline void ipu_ch_param_set_buffer(uint32_t ch, int bufNum, | |
261 | + dma_addr_t phyaddr) | |
262 | +{ | |
263 | + ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 29 * bufNum, 29, | |
264 | + phyaddr / 8); | |
265 | +}; | |
266 | + | |
267 | +#define idma_is_valid(ch) (ch != NO_DMA) | |
268 | +#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0) | |
269 | +#define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma)) | |
270 | + | |
271 | +static void ipu_pixel_clk_recalc(struct clk *clk) | |
272 | +{ | |
273 | + u32 div = __raw_readl(DI_BS_CLKGEN0(clk->id)); | |
274 | + if (div == 0) | |
275 | + clk->rate = 0; | |
276 | + else | |
277 | + clk->rate = (clk->parent->rate * 16) / div; | |
278 | +} | |
279 | + | |
280 | +static unsigned long ipu_pixel_clk_round_rate(struct clk *clk, | |
281 | + unsigned long rate) | |
282 | +{ | |
283 | + u32 div, div1; | |
284 | + u32 tmp; | |
285 | + /* | |
286 | + * Calculate divider | |
287 | + * Fractional part is 4 bits, | |
288 | + * so simply multiply by 2^4 to get fractional part. | |
289 | + */ | |
290 | + tmp = (clk->parent->rate * 16); | |
291 | + div = tmp / rate; | |
292 | + | |
293 | + if (div < 0x10) /* Min DI disp clock divider is 1 */ | |
294 | + div = 0x10; | |
295 | + if (div & ~0xFEF) | |
296 | + div &= 0xFF8; | |
297 | + else { | |
298 | + div1 = div & 0xFE0; | |
299 | + if ((tmp/div1 - tmp/div) < rate / 4) | |
300 | + div = div1; | |
301 | + else | |
302 | + div &= 0xFF8; | |
303 | + } | |
304 | + return (clk->parent->rate * 16) / div; | |
305 | +} | |
306 | + | |
307 | +static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate) | |
308 | +{ | |
309 | + u32 div = (clk->parent->rate * 16) / rate; | |
310 | + | |
311 | + __raw_writel(div, DI_BS_CLKGEN0(clk->id)); | |
312 | + | |
313 | + /* Setup pixel clock timing */ | |
314 | + __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id)); | |
315 | + | |
316 | + clk->rate = (clk->parent->rate * 16) / div; | |
317 | + return 0; | |
318 | +} | |
319 | + | |
320 | +static int ipu_pixel_clk_enable(struct clk *clk) | |
321 | +{ | |
322 | + u32 disp_gen = __raw_readl(IPU_DISP_GEN); | |
323 | + disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE; | |
324 | + __raw_writel(disp_gen, IPU_DISP_GEN); | |
325 | + | |
326 | + return 0; | |
327 | +} | |
328 | + | |
329 | +static void ipu_pixel_clk_disable(struct clk *clk) | |
330 | +{ | |
331 | + u32 disp_gen = __raw_readl(IPU_DISP_GEN); | |
332 | + disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE; | |
333 | + __raw_writel(disp_gen, IPU_DISP_GEN); | |
334 | + | |
335 | +} | |
336 | + | |
337 | +static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent) | |
338 | +{ | |
339 | + u32 di_gen = __raw_readl(DI_GENERAL(clk->id)); | |
340 | + | |
341 | + if (parent == g_ipu_clk) | |
342 | + di_gen &= ~DI_GEN_DI_CLK_EXT; | |
343 | + else if (!IS_ERR(g_di_clk[clk->id]) && parent == g_di_clk[clk->id]) | |
344 | + di_gen |= DI_GEN_DI_CLK_EXT; | |
345 | + else | |
346 | + return -EINVAL; | |
347 | + | |
348 | + __raw_writel(di_gen, DI_GENERAL(clk->id)); | |
349 | + ipu_pixel_clk_recalc(clk); | |
350 | + return 0; | |
351 | +} | |
352 | + | |
353 | +static struct clk pixel_clk[] = { | |
354 | + { | |
355 | + .name = "pixel_clk", | |
356 | + .id = 0, | |
357 | + .recalc = ipu_pixel_clk_recalc, | |
358 | + .set_rate = ipu_pixel_clk_set_rate, | |
359 | + .round_rate = ipu_pixel_clk_round_rate, | |
360 | + .set_parent = ipu_pixel_clk_set_parent, | |
361 | + .enable = ipu_pixel_clk_enable, | |
362 | + .disable = ipu_pixel_clk_disable, | |
363 | + .usecount = 0, | |
364 | + }, | |
365 | + { | |
366 | + .name = "pixel_clk", | |
367 | + .id = 1, | |
368 | + .recalc = ipu_pixel_clk_recalc, | |
369 | + .set_rate = ipu_pixel_clk_set_rate, | |
370 | + .round_rate = ipu_pixel_clk_round_rate, | |
371 | + .set_parent = ipu_pixel_clk_set_parent, | |
372 | + .enable = ipu_pixel_clk_enable, | |
373 | + .disable = ipu_pixel_clk_disable, | |
374 | + .usecount = 0, | |
375 | + }, | |
376 | +}; | |
377 | + | |
378 | +/* | |
379 | + * This function resets IPU | |
380 | + */ | |
381 | +void ipu_reset(void) | |
382 | +{ | |
383 | + u32 *reg; | |
384 | + u32 value; | |
385 | + | |
386 | + reg = (u32 *)SRC_BASE_ADDR; | |
387 | + value = __raw_readl(reg); | |
388 | + value = value | SW_IPU_RST; | |
389 | + __raw_writel(value, reg); | |
390 | +} | |
391 | + | |
392 | +/* | |
393 | + * This function is called by the driver framework to initialize the IPU | |
394 | + * hardware. | |
395 | + * | |
396 | + * @param dev The device structure for the IPU passed in by the | |
397 | + * driver framework. | |
398 | + * | |
399 | + * @return Returns 0 on success or negative error code on error | |
400 | + */ | |
401 | +int ipu_probe(void) | |
402 | +{ | |
403 | + unsigned long ipu_base; | |
404 | + u32 temp; | |
405 | + | |
406 | + u32 *reg_hsc_mcd = (u32 *)MIPI_HSC_BASE_ADDR; | |
407 | + u32 *reg_hsc_mxt_conf = (u32 *)(MIPI_HSC_BASE_ADDR + 0x800); | |
408 | + | |
409 | + __raw_writel(0xF00, reg_hsc_mcd); | |
410 | + | |
411 | + /* CSI mode reserved*/ | |
412 | + temp = __raw_readl(reg_hsc_mxt_conf); | |
413 | + __raw_writel(temp | 0x0FF, reg_hsc_mxt_conf); | |
414 | + | |
415 | + temp = __raw_readl(reg_hsc_mxt_conf); | |
416 | + __raw_writel(temp | 0x10000, reg_hsc_mxt_conf); | |
417 | + | |
418 | + ipu_base = IPU_CTRL_BASE_ADDR; | |
419 | + ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE); | |
420 | + ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE); | |
421 | + | |
422 | + g_pixel_clk[0] = &pixel_clk[0]; | |
423 | + g_pixel_clk[1] = &pixel_clk[1]; | |
424 | + | |
425 | + g_ipu_clk = &ipu_clk; | |
426 | + debug("ipu_clk = %u\n", clk_get_rate(g_ipu_clk)); | |
427 | + | |
428 | + ipu_reset(); | |
429 | + | |
430 | + clk_set_parent(g_pixel_clk[0], g_ipu_clk); | |
431 | + clk_set_parent(g_pixel_clk[1], g_ipu_clk); | |
432 | + clk_enable(g_ipu_clk); | |
433 | + | |
434 | + g_di_clk[0] = NULL; | |
435 | + g_di_clk[1] = NULL; | |
436 | + | |
437 | + __raw_writel(0x807FFFFF, IPU_MEM_RST); | |
438 | + while (__raw_readl(IPU_MEM_RST) & 0x80000000) | |
439 | + ; | |
440 | + | |
441 | + ipu_init_dc_mappings(); | |
442 | + | |
443 | + __raw_writel(0, IPU_INT_CTRL(5)); | |
444 | + __raw_writel(0, IPU_INT_CTRL(6)); | |
445 | + __raw_writel(0, IPU_INT_CTRL(9)); | |
446 | + __raw_writel(0, IPU_INT_CTRL(10)); | |
447 | + | |
448 | + /* DMFC Init */ | |
449 | + ipu_dmfc_init(DMFC_NORMAL, 1); | |
450 | + | |
451 | + /* Set sync refresh channels as high priority */ | |
452 | + __raw_writel(0x18800000L, IDMAC_CHA_PRI(0)); | |
453 | + | |
454 | + /* Set MCU_T to divide MCU access window into 2 */ | |
455 | + __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN); | |
456 | + | |
457 | + clk_disable(g_ipu_clk); | |
458 | + | |
459 | + return 0; | |
460 | +} | |
461 | + | |
462 | +void ipu_dump_registers(void) | |
463 | +{ | |
464 | + debug("IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF)); | |
465 | + debug("IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF)); | |
466 | + debug("IDMAC_CHA_EN1 = \t0x%08X\n", | |
467 | + __raw_readl(IDMAC_CHA_EN(0))); | |
468 | + debug("IDMAC_CHA_EN2 = \t0x%08X\n", | |
469 | + __raw_readl(IDMAC_CHA_EN(32))); | |
470 | + debug("IDMAC_CHA_PRI1 = \t0x%08X\n", | |
471 | + __raw_readl(IDMAC_CHA_PRI(0))); | |
472 | + debug("IDMAC_CHA_PRI2 = \t0x%08X\n", | |
473 | + __raw_readl(IDMAC_CHA_PRI(32))); | |
474 | + debug("IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n", | |
475 | + __raw_readl(IPU_CHA_DB_MODE_SEL(0))); | |
476 | + debug("IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n", | |
477 | + __raw_readl(IPU_CHA_DB_MODE_SEL(32))); | |
478 | + debug("DMFC_WR_CHAN = \t0x%08X\n", | |
479 | + __raw_readl(DMFC_WR_CHAN)); | |
480 | + debug("DMFC_WR_CHAN_DEF = \t0x%08X\n", | |
481 | + __raw_readl(DMFC_WR_CHAN_DEF)); | |
482 | + debug("DMFC_DP_CHAN = \t0x%08X\n", | |
483 | + __raw_readl(DMFC_DP_CHAN)); | |
484 | + debug("DMFC_DP_CHAN_DEF = \t0x%08X\n", | |
485 | + __raw_readl(DMFC_DP_CHAN_DEF)); | |
486 | + debug("DMFC_IC_CTRL = \t0x%08X\n", | |
487 | + __raw_readl(DMFC_IC_CTRL)); | |
488 | + debug("IPU_FS_PROC_FLOW1 = \t0x%08X\n", | |
489 | + __raw_readl(IPU_FS_PROC_FLOW1)); | |
490 | + debug("IPU_FS_PROC_FLOW2 = \t0x%08X\n", | |
491 | + __raw_readl(IPU_FS_PROC_FLOW2)); | |
492 | + debug("IPU_FS_PROC_FLOW3 = \t0x%08X\n", | |
493 | + __raw_readl(IPU_FS_PROC_FLOW3)); | |
494 | + debug("IPU_FS_DISP_FLOW1 = \t0x%08X\n", | |
495 | + __raw_readl(IPU_FS_DISP_FLOW1)); | |
496 | +} | |
497 | + | |
498 | +/* | |
499 | + * This function is called to initialize a logical IPU channel. | |
500 | + * | |
501 | + * @param channel Input parameter for the logical channel ID to init. | |
502 | + * | |
503 | + * @param params Input parameter containing union of channel | |
504 | + * initialization parameters. | |
505 | + * | |
506 | + * @return Returns 0 on success or negative error code on fail | |
507 | + */ | |
508 | +int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) | |
509 | +{ | |
510 | + int ret = 0; | |
511 | + uint32_t ipu_conf; | |
512 | + | |
513 | + debug("init channel = %d\n", IPU_CHAN_ID(channel)); | |
514 | + | |
515 | + if (g_ipu_clk_enabled == 0) { | |
516 | + g_ipu_clk_enabled = 1; | |
517 | + clk_enable(g_ipu_clk); | |
518 | + } | |
519 | + | |
520 | + | |
521 | + if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { | |
522 | + printf("Warning: channel already initialized %d\n", | |
523 | + IPU_CHAN_ID(channel)); | |
524 | + } | |
525 | + | |
526 | + ipu_conf = __raw_readl(IPU_CONF); | |
527 | + | |
528 | + switch (channel) { | |
529 | + case MEM_DC_SYNC: | |
530 | + if (params->mem_dc_sync.di > 1) { | |
531 | + ret = -EINVAL; | |
532 | + goto err; | |
533 | + } | |
534 | + | |
535 | + g_dc_di_assignment[1] = params->mem_dc_sync.di; | |
536 | + ipu_dc_init(1, params->mem_dc_sync.di, | |
537 | + params->mem_dc_sync.interlaced); | |
538 | + ipu_di_use_count[params->mem_dc_sync.di]++; | |
539 | + ipu_dc_use_count++; | |
540 | + ipu_dmfc_use_count++; | |
541 | + break; | |
542 | + case MEM_BG_SYNC: | |
543 | + if (params->mem_dp_bg_sync.di > 1) { | |
544 | + ret = -EINVAL; | |
545 | + goto err; | |
546 | + } | |
547 | + | |
548 | + g_dc_di_assignment[5] = params->mem_dp_bg_sync.di; | |
549 | + ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, | |
550 | + params->mem_dp_bg_sync.out_pixel_fmt); | |
551 | + ipu_dc_init(5, params->mem_dp_bg_sync.di, | |
552 | + params->mem_dp_bg_sync.interlaced); | |
553 | + ipu_di_use_count[params->mem_dp_bg_sync.di]++; | |
554 | + ipu_dc_use_count++; | |
555 | + ipu_dp_use_count++; | |
556 | + ipu_dmfc_use_count++; | |
557 | + break; | |
558 | + case MEM_FG_SYNC: | |
559 | + ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt, | |
560 | + params->mem_dp_fg_sync.out_pixel_fmt); | |
561 | + | |
562 | + ipu_dc_use_count++; | |
563 | + ipu_dp_use_count++; | |
564 | + ipu_dmfc_use_count++; | |
565 | + break; | |
566 | + default: | |
567 | + printf("Missing channel initialization\n"); | |
568 | + break; | |
569 | + } | |
570 | + | |
571 | + /* Enable IPU sub module */ | |
572 | + g_channel_init_mask |= 1L << IPU_CHAN_ID(channel); | |
573 | + if (ipu_dc_use_count == 1) | |
574 | + ipu_conf |= IPU_CONF_DC_EN; | |
575 | + if (ipu_dp_use_count == 1) | |
576 | + ipu_conf |= IPU_CONF_DP_EN; | |
577 | + if (ipu_dmfc_use_count == 1) | |
578 | + ipu_conf |= IPU_CONF_DMFC_EN; | |
579 | + if (ipu_di_use_count[0] == 1) { | |
580 | + ipu_conf |= IPU_CONF_DI0_EN; | |
581 | + } | |
582 | + if (ipu_di_use_count[1] == 1) { | |
583 | + ipu_conf |= IPU_CONF_DI1_EN; | |
584 | + } | |
585 | + | |
586 | + __raw_writel(ipu_conf, IPU_CONF); | |
587 | + | |
588 | +err: | |
589 | + return ret; | |
590 | +} | |
591 | + | |
592 | +/* | |
593 | + * This function is called to uninitialize a logical IPU channel. | |
594 | + * | |
595 | + * @param channel Input parameter for the logical channel ID to uninit. | |
596 | + */ | |
597 | +void ipu_uninit_channel(ipu_channel_t channel) | |
598 | +{ | |
599 | + uint32_t reg; | |
600 | + uint32_t in_dma, out_dma = 0; | |
601 | + uint32_t ipu_conf; | |
602 | + | |
603 | + if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) { | |
604 | + debug("Channel already uninitialized %d\n", | |
605 | + IPU_CHAN_ID(channel)); | |
606 | + return; | |
607 | + } | |
608 | + | |
609 | + /* | |
610 | + * Make sure channel is disabled | |
611 | + * Get input and output dma channels | |
612 | + */ | |
613 | + in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); | |
614 | + out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); | |
615 | + | |
616 | + if (idma_is_set(IDMAC_CHA_EN, in_dma) || | |
617 | + idma_is_set(IDMAC_CHA_EN, out_dma)) { | |
618 | + printf( | |
619 | + "Channel %d is not disabled, disable first\n", | |
620 | + IPU_CHAN_ID(channel)); | |
621 | + return; | |
622 | + } | |
623 | + | |
624 | + ipu_conf = __raw_readl(IPU_CONF); | |
625 | + | |
626 | + /* Reset the double buffer */ | |
627 | + reg = __raw_readl(IPU_CHA_DB_MODE_SEL(in_dma)); | |
628 | + __raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma)); | |
629 | + reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma)); | |
630 | + __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma)); | |
631 | + | |
632 | + switch (channel) { | |
633 | + case MEM_DC_SYNC: | |
634 | + ipu_dc_uninit(1); | |
635 | + ipu_di_use_count[g_dc_di_assignment[1]]--; | |
636 | + ipu_dc_use_count--; | |
637 | + ipu_dmfc_use_count--; | |
638 | + break; | |
639 | + case MEM_BG_SYNC: | |
640 | + ipu_dp_uninit(channel); | |
641 | + ipu_dc_uninit(5); | |
642 | + ipu_di_use_count[g_dc_di_assignment[5]]--; | |
643 | + ipu_dc_use_count--; | |
644 | + ipu_dp_use_count--; | |
645 | + ipu_dmfc_use_count--; | |
646 | + break; | |
647 | + case MEM_FG_SYNC: | |
648 | + ipu_dp_uninit(channel); | |
649 | + ipu_dc_use_count--; | |
650 | + ipu_dp_use_count--; | |
651 | + ipu_dmfc_use_count--; | |
652 | + break; | |
653 | + default: | |
654 | + break; | |
655 | + } | |
656 | + | |
657 | + g_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel)); | |
658 | + | |
659 | + if (ipu_dc_use_count == 0) | |
660 | + ipu_conf &= ~IPU_CONF_DC_EN; | |
661 | + if (ipu_dp_use_count == 0) | |
662 | + ipu_conf &= ~IPU_CONF_DP_EN; | |
663 | + if (ipu_dmfc_use_count == 0) | |
664 | + ipu_conf &= ~IPU_CONF_DMFC_EN; | |
665 | + if (ipu_di_use_count[0] == 0) { | |
666 | + ipu_conf &= ~IPU_CONF_DI0_EN; | |
667 | + } | |
668 | + if (ipu_di_use_count[1] == 0) { | |
669 | + ipu_conf &= ~IPU_CONF_DI1_EN; | |
670 | + } | |
671 | + | |
672 | + __raw_writel(ipu_conf, IPU_CONF); | |
673 | + | |
674 | + if (ipu_conf == 0) { | |
675 | + clk_disable(g_ipu_clk); | |
676 | + g_ipu_clk_enabled = 0; | |
677 | + } | |
678 | + | |
679 | +} | |
680 | + | |
681 | +static inline void ipu_ch_param_dump(int ch) | |
682 | +{ | |
683 | +#ifdef DEBUG | |
684 | + struct ipu_ch_param *p = ipu_ch_param_addr(ch); | |
685 | + debug("ch %d word 0 - %08X %08X %08X %08X %08X\n", ch, | |
686 | + p->word[0].data[0], p->word[0].data[1], p->word[0].data[2], | |
687 | + p->word[0].data[3], p->word[0].data[4]); | |
688 | + debug("ch %d word 1 - %08X %08X %08X %08X %08X\n", ch, | |
689 | + p->word[1].data[0], p->word[1].data[1], p->word[1].data[2], | |
690 | + p->word[1].data[3], p->word[1].data[4]); | |
691 | + debug("PFS 0x%x, ", | |
692 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 85, 4)); | |
693 | + debug("BPP 0x%x, ", | |
694 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 107, 3)); | |
695 | + debug("NPB 0x%x\n", | |
696 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 78, 7)); | |
697 | + | |
698 | + debug("FW %d, ", | |
699 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 125, 13)); | |
700 | + debug("FH %d, ", | |
701 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 138, 12)); | |
702 | + debug("Stride %d\n", | |
703 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14)); | |
704 | + | |
705 | + debug("Width0 %d+1, ", | |
706 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 116, 3)); | |
707 | + debug("Width1 %d+1, ", | |
708 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 119, 3)); | |
709 | + debug("Width2 %d+1, ", | |
710 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 122, 3)); | |
711 | + debug("Width3 %d+1, ", | |
712 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 125, 3)); | |
713 | + debug("Offset0 %d, ", | |
714 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 128, 5)); | |
715 | + debug("Offset1 %d, ", | |
716 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 133, 5)); | |
717 | + debug("Offset2 %d, ", | |
718 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 138, 5)); | |
719 | + debug("Offset3 %d\n", | |
720 | + ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 143, 5)); | |
721 | +#endif | |
722 | +} | |
723 | + | |
724 | +static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p, | |
725 | + int red_width, int red_offset, | |
726 | + int green_width, int green_offset, | |
727 | + int blue_width, int blue_offset, | |
728 | + int alpha_width, int alpha_offset) | |
729 | +{ | |
730 | + /* Setup red width and offset */ | |
731 | + ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1); | |
732 | + ipu_ch_param_set_field(p, 1, 128, 5, red_offset); | |
733 | + /* Setup green width and offset */ | |
734 | + ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1); | |
735 | + ipu_ch_param_set_field(p, 1, 133, 5, green_offset); | |
736 | + /* Setup blue width and offset */ | |
737 | + ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1); | |
738 | + ipu_ch_param_set_field(p, 1, 138, 5, blue_offset); | |
739 | + /* Setup alpha width and offset */ | |
740 | + ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1); | |
741 | + ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset); | |
742 | +} | |
743 | + | |
744 | +static void ipu_ch_param_init(int ch, | |
745 | + uint32_t pixel_fmt, uint32_t width, | |
746 | + uint32_t height, uint32_t stride, | |
747 | + uint32_t u, uint32_t v, | |
748 | + uint32_t uv_stride, dma_addr_t addr0, | |
749 | + dma_addr_t addr1) | |
750 | +{ | |
751 | + uint32_t u_offset = 0; | |
752 | + uint32_t v_offset = 0; | |
753 | + struct ipu_ch_param params; | |
754 | + | |
755 | + memset(¶ms, 0, sizeof(params)); | |
756 | + | |
757 | + ipu_ch_param_set_field(¶ms, 0, 125, 13, width - 1); | |
758 | + | |
759 | + if ((ch == 8) || (ch == 9) || (ch == 10)) { | |
760 | + ipu_ch_param_set_field(¶ms, 0, 138, 12, (height / 2) - 1); | |
761 | + ipu_ch_param_set_field(¶ms, 1, 102, 14, (stride * 2) - 1); | |
762 | + } else { | |
763 | + ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1); | |
764 | + ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1); | |
765 | + } | |
766 | + | |
767 | + ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3); | |
768 | + ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3); | |
769 | + | |
770 | + switch (pixel_fmt) { | |
771 | + case IPU_PIX_FMT_GENERIC: | |
772 | + /*Represents 8-bit Generic data */ | |
773 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 5); /* bits/pixel */ | |
774 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ | |
775 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); /* burst size */ | |
776 | + | |
777 | + break; | |
778 | + case IPU_PIX_FMT_GENERIC_32: | |
779 | + /*Represents 32-bit Generic data */ | |
780 | + break; | |
781 | + case IPU_PIX_FMT_RGB565: | |
782 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ | |
783 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
784 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ | |
785 | + | |
786 | + ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16); | |
787 | + break; | |
788 | + case IPU_PIX_FMT_BGR24: | |
789 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ | |
790 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
791 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ | |
792 | + | |
793 | + ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); | |
794 | + break; | |
795 | + case IPU_PIX_FMT_RGB24: | |
796 | + case IPU_PIX_FMT_YUV444: | |
797 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ | |
798 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
799 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ | |
800 | + | |
801 | + ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24); | |
802 | + break; | |
803 | + case IPU_PIX_FMT_BGRA32: | |
804 | + case IPU_PIX_FMT_BGR32: | |
805 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ | |
806 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
807 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ | |
808 | + | |
809 | + ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0); | |
810 | + break; | |
811 | + case IPU_PIX_FMT_RGBA32: | |
812 | + case IPU_PIX_FMT_RGB32: | |
813 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ | |
814 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
815 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ | |
816 | + | |
817 | + ipu_ch_params_set_packing(¶ms, 8, 24, 8, 16, 8, 8, 8, 0); | |
818 | + break; | |
819 | + case IPU_PIX_FMT_ABGR32: | |
820 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ | |
821 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ | |
822 | + | |
823 | + ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); | |
824 | + break; | |
825 | + case IPU_PIX_FMT_UYVY: | |
826 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ | |
827 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */ | |
828 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ | |
829 | + break; | |
830 | + case IPU_PIX_FMT_YUYV: | |
831 | + ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ | |
832 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8); /* pix format */ | |
833 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ | |
834 | + break; | |
835 | + case IPU_PIX_FMT_YUV420P2: | |
836 | + case IPU_PIX_FMT_YUV420P: | |
837 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 2); /* pix format */ | |
838 | + | |
839 | + if (uv_stride < stride / 2) | |
840 | + uv_stride = stride / 2; | |
841 | + | |
842 | + u_offset = stride * height; | |
843 | + v_offset = u_offset + (uv_stride * height / 2); | |
844 | + /* burst size */ | |
845 | + if ((ch == 8) || (ch == 9) || (ch == 10)) { | |
846 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); | |
847 | + uv_stride = uv_stride*2; | |
848 | + } else { | |
849 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); | |
850 | + } | |
851 | + break; | |
852 | + case IPU_PIX_FMT_YVU422P: | |
853 | + /* BPP & pixel format */ | |
854 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ | |
855 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ | |
856 | + | |
857 | + if (uv_stride < stride / 2) | |
858 | + uv_stride = stride / 2; | |
859 | + | |
860 | + v_offset = (v == 0) ? stride * height : v; | |
861 | + u_offset = (u == 0) ? v_offset + v_offset / 2 : u; | |
862 | + break; | |
863 | + case IPU_PIX_FMT_YUV422P: | |
864 | + /* BPP & pixel format */ | |
865 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ | |
866 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ | |
867 | + | |
868 | + if (uv_stride < stride / 2) | |
869 | + uv_stride = stride / 2; | |
870 | + | |
871 | + u_offset = (u == 0) ? stride * height : u; | |
872 | + v_offset = (v == 0) ? u_offset + u_offset / 2 : v; | |
873 | + break; | |
874 | + case IPU_PIX_FMT_NV12: | |
875 | + /* BPP & pixel format */ | |
876 | + ipu_ch_param_set_field(¶ms, 1, 85, 4, 4); /* pix format */ | |
877 | + ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ | |
878 | + uv_stride = stride; | |
879 | + u_offset = (u == 0) ? stride * height : u; | |
880 | + break; | |
881 | + default: | |
882 | + puts("mxc ipu: unimplemented pixel format\n"); | |
883 | + break; | |
884 | + } | |
885 | + | |
886 | + | |
887 | + if (uv_stride) | |
888 | + ipu_ch_param_set_field(¶ms, 1, 128, 14, uv_stride - 1); | |
889 | + | |
890 | + /* Get the uv offset from user when need cropping */ | |
891 | + if (u || v) { | |
892 | + u_offset = u; | |
893 | + v_offset = v; | |
894 | + } | |
895 | + | |
896 | + /* UBO and VBO are 22-bit */ | |
897 | + if (u_offset/8 > 0x3fffff) | |
898 | + puts("The value of U offset exceeds IPU limitation\n"); | |
899 | + if (v_offset/8 > 0x3fffff) | |
900 | + puts("The value of V offset exceeds IPU limitation\n"); | |
901 | + | |
902 | + ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8); | |
903 | + ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8); | |
904 | + | |
905 | + debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch)); | |
906 | + memcpy(ipu_ch_param_addr(ch), ¶ms, sizeof(params)); | |
907 | +}; | |
908 | + | |
909 | +/* | |
910 | + * This function is called to initialize a buffer for logical IPU channel. | |
911 | + * | |
912 | + * @param channel Input parameter for the logical channel ID. | |
913 | + * | |
914 | + * @param type Input parameter which buffer to initialize. | |
915 | + * | |
916 | + * @param pixel_fmt Input parameter for pixel format of buffer. | |
917 | + * Pixel format is a FOURCC ASCII code. | |
918 | + * | |
919 | + * @param width Input parameter for width of buffer in pixels. | |
920 | + * | |
921 | + * @param height Input parameter for height of buffer in pixels. | |
922 | + * | |
923 | + * @param stride Input parameter for stride length of buffer | |
924 | + * in pixels. | |
925 | + * | |
926 | + * @param phyaddr_0 Input parameter buffer 0 physical address. | |
927 | + * | |
928 | + * @param phyaddr_1 Input parameter buffer 1 physical address. | |
929 | + * Setting this to a value other than NULL enables | |
930 | + * double buffering mode. | |
931 | + * | |
932 | + * @param u private u offset for additional cropping, | |
933 | + * zero if not used. | |
934 | + * | |
935 | + * @param v private v offset for additional cropping, | |
936 | + * zero if not used. | |
937 | + * | |
938 | + * @return Returns 0 on success or negative error code on fail | |
939 | + */ | |
940 | +int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, | |
941 | + uint32_t pixel_fmt, | |
942 | + uint16_t width, uint16_t height, | |
943 | + uint32_t stride, | |
944 | + dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, | |
945 | + uint32_t u, uint32_t v) | |
946 | +{ | |
947 | + uint32_t reg; | |
948 | + uint32_t dma_chan; | |
949 | + | |
950 | + dma_chan = channel_2_dma(channel, type); | |
951 | + if (!idma_is_valid(dma_chan)) | |
952 | + return -EINVAL; | |
953 | + | |
954 | + if (stride < width * bytes_per_pixel(pixel_fmt)) | |
955 | + stride = width * bytes_per_pixel(pixel_fmt); | |
956 | + | |
957 | + if (stride % 4) { | |
958 | + printf( | |
959 | + "Stride not 32-bit aligned, stride = %d\n", stride); | |
960 | + return -EINVAL; | |
961 | + } | |
962 | + /* Build parameter memory data for DMA channel */ | |
963 | + ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0, | |
964 | + phyaddr_0, phyaddr_1); | |
965 | + | |
966 | + if (ipu_is_dmfc_chan(dma_chan)) { | |
967 | + ipu_dmfc_set_wait4eot(dma_chan, width); | |
968 | + } | |
969 | + | |
970 | + if (idma_is_set(IDMAC_CHA_PRI, dma_chan)) | |
971 | + ipu_ch_param_set_high_priority(dma_chan); | |
972 | + | |
973 | + ipu_ch_param_dump(dma_chan); | |
974 | + | |
975 | + reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan)); | |
976 | + if (phyaddr_1) | |
977 | + reg |= idma_mask(dma_chan); | |
978 | + else | |
979 | + reg &= ~idma_mask(dma_chan); | |
980 | + __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan)); | |
981 | + | |
982 | + /* Reset to buffer 0 */ | |
983 | + __raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan)); | |
984 | + | |
985 | + return 0; | |
986 | +} | |
987 | + | |
988 | +/* | |
989 | + * This function enables a logical channel. | |
990 | + * | |
991 | + * @param channel Input parameter for the logical channel ID. | |
992 | + * | |
993 | + * @return This function returns 0 on success or negative error code on | |
994 | + * fail. | |
995 | + */ | |
996 | +int32_t ipu_enable_channel(ipu_channel_t channel) | |
997 | +{ | |
998 | + uint32_t reg; | |
999 | + uint32_t in_dma; | |
1000 | + uint32_t out_dma; | |
1001 | + | |
1002 | + if (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) { | |
1003 | + printf("Warning: channel already enabled %d\n", | |
1004 | + IPU_CHAN_ID(channel)); | |
1005 | + } | |
1006 | + | |
1007 | + /* Get input and output dma channels */ | |
1008 | + out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); | |
1009 | + in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); | |
1010 | + | |
1011 | + if (idma_is_valid(in_dma)) { | |
1012 | + reg = __raw_readl(IDMAC_CHA_EN(in_dma)); | |
1013 | + __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); | |
1014 | + } | |
1015 | + if (idma_is_valid(out_dma)) { | |
1016 | + reg = __raw_readl(IDMAC_CHA_EN(out_dma)); | |
1017 | + __raw_writel(reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); | |
1018 | + } | |
1019 | + | |
1020 | + if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) || | |
1021 | + (channel == MEM_FG_SYNC)) | |
1022 | + ipu_dp_dc_enable(channel); | |
1023 | + | |
1024 | + g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel); | |
1025 | + | |
1026 | + return 0; | |
1027 | +} | |
1028 | + | |
1029 | +/* | |
1030 | + * This function clear buffer ready for a logical channel. | |
1031 | + * | |
1032 | + * @param channel Input parameter for the logical channel ID. | |
1033 | + * | |
1034 | + * @param type Input parameter which buffer to clear. | |
1035 | + * | |
1036 | + * @param bufNum Input parameter for which buffer number clear | |
1037 | + * ready state. | |
1038 | + * | |
1039 | + */ | |
1040 | +void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type, | |
1041 | + uint32_t bufNum) | |
1042 | +{ | |
1043 | + uint32_t dma_ch = channel_2_dma(channel, type); | |
1044 | + | |
1045 | + if (!idma_is_valid(dma_ch)) | |
1046 | + return; | |
1047 | + | |
1048 | + __raw_writel(0xF0000000, IPU_GPR); /* write one to clear */ | |
1049 | + if (bufNum == 0) { | |
1050 | + if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) { | |
1051 | + __raw_writel(idma_mask(dma_ch), | |
1052 | + IPU_CHA_BUF0_RDY(dma_ch)); | |
1053 | + } | |
1054 | + } else { | |
1055 | + if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) { | |
1056 | + __raw_writel(idma_mask(dma_ch), | |
1057 | + IPU_CHA_BUF1_RDY(dma_ch)); | |
1058 | + } | |
1059 | + } | |
1060 | + __raw_writel(0x0, IPU_GPR); /* write one to set */ | |
1061 | +} | |
1062 | + | |
1063 | +/* | |
1064 | + * This function disables a logical channel. | |
1065 | + * | |
1066 | + * @param channel Input parameter for the logical channel ID. | |
1067 | + * | |
1068 | + * @param wait_for_stop Flag to set whether to wait for channel end | |
1069 | + * of frame or return immediately. | |
1070 | + * | |
1071 | + * @return This function returns 0 on success or negative error code on | |
1072 | + * fail. | |
1073 | + */ | |
1074 | +int32_t ipu_disable_channel(ipu_channel_t channel) | |
1075 | +{ | |
1076 | + uint32_t reg; | |
1077 | + uint32_t in_dma; | |
1078 | + uint32_t out_dma; | |
1079 | + | |
1080 | + if ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) { | |
1081 | + debug("Channel already disabled %d\n", | |
1082 | + IPU_CHAN_ID(channel)); | |
1083 | + return 0; | |
1084 | + } | |
1085 | + | |
1086 | + /* Get input and output dma channels */ | |
1087 | + out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); | |
1088 | + in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); | |
1089 | + | |
1090 | + if ((idma_is_valid(in_dma) && | |
1091 | + !idma_is_set(IDMAC_CHA_EN, in_dma)) | |
1092 | + && (idma_is_valid(out_dma) && | |
1093 | + !idma_is_set(IDMAC_CHA_EN, out_dma))) | |
1094 | + return -EINVAL; | |
1095 | + | |
1096 | + if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || | |
1097 | + (channel == MEM_DC_SYNC)) { | |
1098 | + ipu_dp_dc_disable(channel, 0); | |
1099 | + } | |
1100 | + | |
1101 | + /* Disable DMA channel(s) */ | |
1102 | + if (idma_is_valid(in_dma)) { | |
1103 | + reg = __raw_readl(IDMAC_CHA_EN(in_dma)); | |
1104 | + __raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); | |
1105 | + __raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma)); | |
1106 | + } | |
1107 | + if (idma_is_valid(out_dma)) { | |
1108 | + reg = __raw_readl(IDMAC_CHA_EN(out_dma)); | |
1109 | + __raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); | |
1110 | + __raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma)); | |
1111 | + } | |
1112 | + | |
1113 | + g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel)); | |
1114 | + | |
1115 | + /* Set channel buffers NOT to be ready */ | |
1116 | + if (idma_is_valid(in_dma)) { | |
1117 | + ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); | |
1118 | + ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1); | |
1119 | + } | |
1120 | + if (idma_is_valid(out_dma)) { | |
1121 | + ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0); | |
1122 | + ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1); | |
1123 | + } | |
1124 | + | |
1125 | + return 0; | |
1126 | +} | |
1127 | + | |
1128 | +uint32_t bytes_per_pixel(uint32_t fmt) | |
1129 | +{ | |
1130 | + switch (fmt) { | |
1131 | + case IPU_PIX_FMT_GENERIC: /*generic data */ | |
1132 | + case IPU_PIX_FMT_RGB332: | |
1133 | + case IPU_PIX_FMT_YUV420P: | |
1134 | + case IPU_PIX_FMT_YUV422P: | |
1135 | + return 1; | |
1136 | + break; | |
1137 | + case IPU_PIX_FMT_RGB565: | |
1138 | + case IPU_PIX_FMT_YUYV: | |
1139 | + case IPU_PIX_FMT_UYVY: | |
1140 | + return 2; | |
1141 | + break; | |
1142 | + case IPU_PIX_FMT_BGR24: | |
1143 | + case IPU_PIX_FMT_RGB24: | |
1144 | + return 3; | |
1145 | + break; | |
1146 | + case IPU_PIX_FMT_GENERIC_32: /*generic data */ | |
1147 | + case IPU_PIX_FMT_BGR32: | |
1148 | + case IPU_PIX_FMT_BGRA32: | |
1149 | + case IPU_PIX_FMT_RGB32: | |
1150 | + case IPU_PIX_FMT_RGBA32: | |
1151 | + case IPU_PIX_FMT_ABGR32: | |
1152 | + return 4; | |
1153 | + break; | |
1154 | + default: | |
1155 | + return 1; | |
1156 | + break; | |
1157 | + } | |
1158 | + return 0; | |
1159 | +} | |
1160 | + | |
1161 | +ipu_color_space_t format_to_colorspace(uint32_t fmt) | |
1162 | +{ | |
1163 | + switch (fmt) { | |
1164 | + case IPU_PIX_FMT_RGB666: | |
1165 | + case IPU_PIX_FMT_RGB565: | |
1166 | + case IPU_PIX_FMT_BGR24: | |
1167 | + case IPU_PIX_FMT_RGB24: | |
1168 | + case IPU_PIX_FMT_BGR32: | |
1169 | + case IPU_PIX_FMT_BGRA32: | |
1170 | + case IPU_PIX_FMT_RGB32: | |
1171 | + case IPU_PIX_FMT_RGBA32: | |
1172 | + case IPU_PIX_FMT_ABGR32: | |
1173 | + case IPU_PIX_FMT_LVDS666: | |
1174 | + case IPU_PIX_FMT_LVDS888: | |
1175 | + return RGB; | |
1176 | + break; | |
1177 | + | |
1178 | + default: | |
1179 | + return YCbCr; | |
1180 | + break; | |
1181 | + } | |
1182 | + return RGB; | |
1183 | +} |
drivers/video/ipu_disp.c
Changes suppressed. Click to show
1 | +/* | |
2 | + * Porting to u-boot: | |
3 | + * | |
4 | + * (C) Copyright 2010 | |
5 | + * Stefano Babic, DENX Software Engineering, sbabic@denx.de | |
6 | + * | |
7 | + * Linux IPU driver for MX51: | |
8 | + * | |
9 | + * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. | |
10 | + * | |
11 | + * See file CREDITS for list of people who contributed to this | |
12 | + * project. | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or | |
15 | + * modify it under the terms of the GNU General Public License as | |
16 | + * published by the Free Software Foundation; either version 2 of | |
17 | + * the License, or (at your option) any later version. | |
18 | + * | |
19 | + * This program is distributed in the hope that it will be useful, | |
20 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | + * GNU General Public License for more details. | |
23 | + * | |
24 | + * You should have received a copy of the GNU General Public License | |
25 | + * along with this program; if not, write to the Free Software | |
26 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
27 | + * MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +/* #define DEBUG */ | |
31 | + | |
32 | +#include <common.h> | |
33 | +#include <linux/types.h> | |
34 | +#include <asm/errno.h> | |
35 | +#include <asm/io.h> | |
36 | +#include <asm/arch/imx-regs.h> | |
37 | +#include <asm/arch/sys_proto.h> | |
38 | +#include "ipu.h" | |
39 | +#include "ipu_regs.h" | |
40 | + | |
41 | +enum csc_type_t { | |
42 | + RGB2YUV = 0, | |
43 | + YUV2RGB, | |
44 | + RGB2RGB, | |
45 | + YUV2YUV, | |
46 | + CSC_NONE, | |
47 | + CSC_NUM | |
48 | +}; | |
49 | + | |
50 | +struct dp_csc_param_t { | |
51 | + int mode; | |
52 | + void *coeff; | |
53 | +}; | |
54 | + | |
55 | +#define SYNC_WAVE 0 | |
56 | + | |
57 | +/* DC display ID assignments */ | |
58 | +#define DC_DISP_ID_SYNC(di) (di) | |
59 | +#define DC_DISP_ID_SERIAL 2 | |
60 | +#define DC_DISP_ID_ASYNC 3 | |
61 | + | |
62 | +int dmfc_type_setup; | |
63 | +static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23; | |
64 | +int g_di1_tvout; | |
65 | + | |
66 | +extern struct clk *g_ipu_clk; | |
67 | +extern struct clk *g_di_clk[2]; | |
68 | +extern struct clk *g_pixel_clk[2]; | |
69 | + | |
70 | +extern unsigned char g_ipu_clk_enabled; | |
71 | +extern unsigned char g_dc_di_assignment[]; | |
72 | + | |
73 | +void ipu_dmfc_init(int dmfc_type, int first) | |
74 | +{ | |
75 | + u32 dmfc_wr_chan, dmfc_dp_chan; | |
76 | + | |
77 | + if (first) { | |
78 | + if (dmfc_type_setup > dmfc_type) | |
79 | + dmfc_type = dmfc_type_setup; | |
80 | + else | |
81 | + dmfc_type_setup = dmfc_type; | |
82 | + | |
83 | + /* disable DMFC-IC channel*/ | |
84 | + __raw_writel(0x2, DMFC_IC_CTRL); | |
85 | + } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) { | |
86 | + printf("DMFC high resolution has set, will not change\n"); | |
87 | + return; | |
88 | + } else | |
89 | + dmfc_type_setup = dmfc_type; | |
90 | + | |
91 | + if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) { | |
92 | + /* 1 - segment 0~3; | |
93 | + * 5B - segement 4, 5; | |
94 | + * 5F - segement 6, 7; | |
95 | + * 1C, 2C and 6B, 6F unused; | |
96 | + */ | |
97 | + debug("IPU DMFC DC HIGH RES: 1(0~3), 5B(4,5), 5F(6,7)\n"); | |
98 | + dmfc_wr_chan = 0x00000088; | |
99 | + dmfc_dp_chan = 0x00009694; | |
100 | + dmfc_size_28 = 256 * 4; | |
101 | + dmfc_size_29 = 0; | |
102 | + dmfc_size_24 = 0; | |
103 | + dmfc_size_27 = 128 * 4; | |
104 | + dmfc_size_23 = 128 * 4; | |
105 | + } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) { | |
106 | + /* 1 - segment 0, 1; | |
107 | + * 5B - segement 2~5; | |
108 | + * 5F - segement 6,7; | |
109 | + * 1C, 2C and 6B, 6F unused; | |
110 | + */ | |
111 | + debug("IPU DMFC DP HIGH RES: 1(0,1), 5B(2~5), 5F(6,7)\n"); | |
112 | + dmfc_wr_chan = 0x00000090; | |
113 | + dmfc_dp_chan = 0x0000968a; | |
114 | + dmfc_size_28 = 128 * 4; | |
115 | + dmfc_size_29 = 0; | |
116 | + dmfc_size_24 = 0; | |
117 | + dmfc_size_27 = 128 * 4; | |
118 | + dmfc_size_23 = 256 * 4; | |
119 | + } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) { | |
120 | + /* 5B - segement 0~3; | |
121 | + * 5F - segement 4~7; | |
122 | + * 1, 1C, 2C and 6B, 6F unused; | |
123 | + */ | |
124 | + debug("IPU DMFC ONLY-DP HIGH RES: 5B(0~3), 5F(4~7)\n"); | |
125 | + dmfc_wr_chan = 0x00000000; | |
126 | + dmfc_dp_chan = 0x00008c88; | |
127 | + dmfc_size_28 = 0; | |
128 | + dmfc_size_29 = 0; | |
129 | + dmfc_size_24 = 0; | |
130 | + dmfc_size_27 = 256 * 4; | |
131 | + dmfc_size_23 = 256 * 4; | |
132 | + } else { | |
133 | + /* 1 - segment 0, 1; | |
134 | + * 5B - segement 4, 5; | |
135 | + * 5F - segement 6, 7; | |
136 | + * 1C, 2C and 6B, 6F unused; | |
137 | + */ | |
138 | + debug("IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n"); | |
139 | + dmfc_wr_chan = 0x00000090; | |
140 | + dmfc_dp_chan = 0x00009694; | |
141 | + dmfc_size_28 = 128 * 4; | |
142 | + dmfc_size_29 = 0; | |
143 | + dmfc_size_24 = 0; | |
144 | + dmfc_size_27 = 128 * 4; | |
145 | + dmfc_size_23 = 128 * 4; | |
146 | + } | |
147 | + __raw_writel(dmfc_wr_chan, DMFC_WR_CHAN); | |
148 | + __raw_writel(0x202020F6, DMFC_WR_CHAN_DEF); | |
149 | + __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN); | |
150 | + /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */ | |
151 | + __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF); | |
152 | +} | |
153 | + | |
154 | +void ipu_dmfc_set_wait4eot(int dma_chan, int width) | |
155 | +{ | |
156 | + u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1); | |
157 | + | |
158 | + if (width >= HIGH_RESOLUTION_WIDTH) { | |
159 | + if (dma_chan == 23) | |
160 | + ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0); | |
161 | + else if (dma_chan == 28) | |
162 | + ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0); | |
163 | + } | |
164 | + | |
165 | + if (dma_chan == 23) { /*5B*/ | |
166 | + if (dmfc_size_23 / width > 3) | |
167 | + dmfc_gen1 |= 1UL << 20; | |
168 | + else | |
169 | + dmfc_gen1 &= ~(1UL << 20); | |
170 | + } else if (dma_chan == 24) { /*6B*/ | |
171 | + if (dmfc_size_24 / width > 1) | |
172 | + dmfc_gen1 |= 1UL << 22; | |
173 | + else | |
174 | + dmfc_gen1 &= ~(1UL << 22); | |
175 | + } else if (dma_chan == 27) { /*5F*/ | |
176 | + if (dmfc_size_27 / width > 2) | |
177 | + dmfc_gen1 |= 1UL << 21; | |
178 | + else | |
179 | + dmfc_gen1 &= ~(1UL << 21); | |
180 | + } else if (dma_chan == 28) { /*1*/ | |
181 | + if (dmfc_size_28 / width > 2) | |
182 | + dmfc_gen1 |= 1UL << 16; | |
183 | + else | |
184 | + dmfc_gen1 &= ~(1UL << 16); | |
185 | + } else if (dma_chan == 29) { /*6F*/ | |
186 | + if (dmfc_size_29 / width > 1) | |
187 | + dmfc_gen1 |= 1UL << 23; | |
188 | + else | |
189 | + dmfc_gen1 &= ~(1UL << 23); | |
190 | + } | |
191 | + | |
192 | + __raw_writel(dmfc_gen1, DMFC_GENERAL1); | |
193 | +} | |
194 | + | |
195 | +static void ipu_di_data_wave_config(int di, | |
196 | + int wave_gen, | |
197 | + int access_size, int component_size) | |
198 | +{ | |
199 | + u32 reg; | |
200 | + reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | | |
201 | + (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); | |
202 | + __raw_writel(reg, DI_DW_GEN(di, wave_gen)); | |
203 | +} | |
204 | + | |
205 | +static void ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set, | |
206 | + int up, int down) | |
207 | +{ | |
208 | + u32 reg; | |
209 | + | |
210 | + reg = __raw_readl(DI_DW_GEN(di, wave_gen)); | |
211 | + reg &= ~(0x3 << (di_pin * 2)); | |
212 | + reg |= set << (di_pin * 2); | |
213 | + __raw_writel(reg, DI_DW_GEN(di, wave_gen)); | |
214 | + | |
215 | + __raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set)); | |
216 | +} | |
217 | + | |
218 | +static void ipu_di_sync_config(int di, int wave_gen, | |
219 | + int run_count, int run_src, | |
220 | + int offset_count, int offset_src, | |
221 | + int repeat_count, int cnt_clr_src, | |
222 | + int cnt_polarity_gen_en, | |
223 | + int cnt_polarity_clr_src, | |
224 | + int cnt_polarity_trigger_src, | |
225 | + int cnt_up, int cnt_down) | |
226 | +{ | |
227 | + u32 reg; | |
228 | + | |
229 | + if ((run_count >= 0x1000) || (offset_count >= 0x1000) || | |
230 | + (repeat_count >= 0x1000) || | |
231 | + (cnt_up >= 0x400) || (cnt_down >= 0x400)) { | |
232 | + printf("DI%d counters out of range.\n", di); | |
233 | + return; | |
234 | + } | |
235 | + | |
236 | + reg = (run_count << 19) | (++run_src << 16) | | |
237 | + (offset_count << 3) | ++offset_src; | |
238 | + __raw_writel(reg, DI_SW_GEN0(di, wave_gen)); | |
239 | + reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) | | |
240 | + (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9); | |
241 | + reg |= (cnt_down << 16) | cnt_up; | |
242 | + if (repeat_count == 0) { | |
243 | + /* Enable auto reload */ | |
244 | + reg |= 0x10000000; | |
245 | + } | |
246 | + __raw_writel(reg, DI_SW_GEN1(di, wave_gen)); | |
247 | + reg = __raw_readl(DI_STP_REP(di, wave_gen)); | |
248 | + reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1))); | |
249 | + reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1)); | |
250 | + __raw_writel(reg, DI_STP_REP(di, wave_gen)); | |
251 | +} | |
252 | + | |
253 | +static void ipu_dc_map_config(int map, int byte_num, int offset, int mask) | |
254 | +{ | |
255 | + int ptr = map * 3 + byte_num; | |
256 | + u32 reg; | |
257 | + | |
258 | + reg = __raw_readl(DC_MAP_CONF_VAL(ptr)); | |
259 | + reg &= ~(0xFFFF << (16 * (ptr & 0x1))); | |
260 | + reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1)); | |
261 | + __raw_writel(reg, DC_MAP_CONF_VAL(ptr)); | |
262 | + | |
263 | + reg = __raw_readl(DC_MAP_CONF_PTR(map)); | |
264 | + reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num))); | |
265 | + reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num)); | |
266 | + __raw_writel(reg, DC_MAP_CONF_PTR(map)); | |
267 | +} | |
268 | + | |
269 | +static void ipu_dc_map_clear(int map) | |
270 | +{ | |
271 | + u32 reg = __raw_readl(DC_MAP_CONF_PTR(map)); | |
272 | + __raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))), | |
273 | + DC_MAP_CONF_PTR(map)); | |
274 | +} | |
275 | + | |
276 | +static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, | |
277 | + int wave, int glue, int sync) | |
278 | +{ | |
279 | + u32 reg; | |
280 | + int stop = 1; | |
281 | + | |
282 | + reg = sync; | |
283 | + reg |= (glue << 4); | |
284 | + reg |= (++wave << 11); | |
285 | + reg |= (++map << 15); | |
286 | + reg |= (operand << 20) & 0xFFF00000; | |
287 | + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); | |
288 | + | |
289 | + reg = (operand >> 12); | |
290 | + reg |= opcode << 4; | |
291 | + reg |= (stop << 9); | |
292 | + __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); | |
293 | +} | |
294 | + | |
295 | +static void ipu_dc_link_event(int chan, int event, int addr, int priority) | |
296 | +{ | |
297 | + u32 reg; | |
298 | + | |
299 | + reg = __raw_readl(DC_RL_CH(chan, event)); | |
300 | + reg &= ~(0xFFFF << (16 * (event & 0x1))); | |
301 | + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); | |
302 | + __raw_writel(reg, DC_RL_CH(chan, event)); | |
303 | +} | |
304 | + | |
305 | +/* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; | |
306 | + * U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.; | |
307 | + * V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.; | |
308 | + */ | |
309 | +static const int rgb2ycbcr_coeff[5][3] = { | |
310 | + {0x4D, 0x96, 0x1D}, | |
311 | + {0x3D5, 0x3AB, 0x80}, | |
312 | + {0x80, 0x395, 0x3EB}, | |
313 | + {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */ | |
314 | + {0x2, 0x2, 0x2}, /* S0, S1, S2 */ | |
315 | +}; | |
316 | + | |
317 | +/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); | |
318 | + * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); | |
319 | + * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); | |
320 | + */ | |
321 | +static const int ycbcr2rgb_coeff[5][3] = { | |
322 | + {0x095, 0x000, 0x0CC}, | |
323 | + {0x095, 0x3CE, 0x398}, | |
324 | + {0x095, 0x0FF, 0x000}, | |
325 | + {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */ | |
326 | + {0x1, 0x1, 0x1}, /*S0,S1,S2 */ | |
327 | +}; | |
328 | + | |
329 | +#define mask_a(a) ((u32)(a) & 0x3FF) | |
330 | +#define mask_b(b) ((u32)(b) & 0x3FFF) | |
331 | + | |
332 | +/* Pls keep S0, S1 and S2 as 0x2 by using this convertion */ | |
333 | +static int rgb_to_yuv(int n, int red, int green, int blue) | |
334 | +{ | |
335 | + int c; | |
336 | + c = red * rgb2ycbcr_coeff[n][0]; | |
337 | + c += green * rgb2ycbcr_coeff[n][1]; | |
338 | + c += blue * rgb2ycbcr_coeff[n][2]; | |
339 | + c /= 16; | |
340 | + c += rgb2ycbcr_coeff[3][n] * 4; | |
341 | + c += 8; | |
342 | + c /= 16; | |
343 | + if (c < 0) | |
344 | + c = 0; | |
345 | + if (c > 255) | |
346 | + c = 255; | |
347 | + return c; | |
348 | +} | |
349 | + | |
350 | +/* | |
351 | + * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE | |
352 | + * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE | |
353 | + */ | |
354 | +static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = { | |
355 | + { | |
356 | + {DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff}, | |
357 | + {0, 0}, | |
358 | + {0, 0}, | |
359 | + {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}, | |
360 | + {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff} | |
361 | + }, | |
362 | + { | |
363 | + {0, 0}, | |
364 | + {DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff}, | |
365 | + {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}, | |
366 | + {0, 0}, | |
367 | + {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff} | |
368 | + }, | |
369 | + { | |
370 | + {0, 0}, | |
371 | + {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, | |
372 | + {0, 0}, | |
373 | + {0, 0}, | |
374 | + {0, 0} | |
375 | + }, | |
376 | + { | |
377 | + {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, | |
378 | + {0, 0}, | |
379 | + {0, 0}, | |
380 | + {0, 0}, | |
381 | + {0, 0} | |
382 | + }, | |
383 | + { | |
384 | + {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, | |
385 | + {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, | |
386 | + {0, 0}, | |
387 | + {0, 0}, | |
388 | + {0, 0} | |
389 | + } | |
390 | +}; | |
391 | + | |
392 | +static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE; | |
393 | +static int color_key_4rgb = 1; | |
394 | + | |
395 | +void ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param, | |
396 | + unsigned char srm_mode_update) | |
397 | +{ | |
398 | + u32 reg; | |
399 | + const int (*coeff)[5][3]; | |
400 | + | |
401 | + if (dp_csc_param.mode >= 0) { | |
402 | + reg = __raw_readl(DP_COM_CONF(dp)); | |
403 | + reg &= ~DP_COM_CONF_CSC_DEF_MASK; | |
404 | + reg |= dp_csc_param.mode; | |
405 | + __raw_writel(reg, DP_COM_CONF(dp)); | |
406 | + } | |
407 | + | |
408 | + coeff = dp_csc_param.coeff; | |
409 | + | |
410 | + if (coeff) { | |
411 | + __raw_writel(mask_a((*coeff)[0][0]) | | |
412 | + (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp)); | |
413 | + __raw_writel(mask_a((*coeff)[0][2]) | | |
414 | + (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp)); | |
415 | + __raw_writel(mask_a((*coeff)[1][1]) | | |
416 | + (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp)); | |
417 | + __raw_writel(mask_a((*coeff)[2][0]) | | |
418 | + (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp)); | |
419 | + __raw_writel(mask_a((*coeff)[2][2]) | | |
420 | + (mask_b((*coeff)[3][0]) << 16) | | |
421 | + ((*coeff)[4][0] << 30), DP_CSC_0(dp)); | |
422 | + __raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) | | |
423 | + (mask_b((*coeff)[3][2]) << 16) | | |
424 | + ((*coeff)[4][2] << 30), DP_CSC_1(dp)); | |
425 | + } | |
426 | + | |
427 | + if (srm_mode_update) { | |
428 | + reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
429 | + __raw_writel(reg, IPU_SRM_PRI2); | |
430 | + } | |
431 | +} | |
432 | + | |
433 | +int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, | |
434 | + uint32_t out_pixel_fmt) | |
435 | +{ | |
436 | + int in_fmt, out_fmt; | |
437 | + int dp; | |
438 | + int partial = 0; | |
439 | + uint32_t reg; | |
440 | + | |
441 | + if (channel == MEM_FG_SYNC) { | |
442 | + dp = DP_SYNC; | |
443 | + partial = 1; | |
444 | + } else if (channel == MEM_BG_SYNC) { | |
445 | + dp = DP_SYNC; | |
446 | + partial = 0; | |
447 | + } else if (channel == MEM_BG_ASYNC0) { | |
448 | + dp = DP_ASYNC0; | |
449 | + partial = 0; | |
450 | + } else { | |
451 | + return -EINVAL; | |
452 | + } | |
453 | + | |
454 | + in_fmt = format_to_colorspace(in_pixel_fmt); | |
455 | + out_fmt = format_to_colorspace(out_pixel_fmt); | |
456 | + | |
457 | + if (partial) { | |
458 | + if (in_fmt == RGB) { | |
459 | + if (out_fmt == RGB) | |
460 | + fg_csc_type = RGB2RGB; | |
461 | + else | |
462 | + fg_csc_type = RGB2YUV; | |
463 | + } else { | |
464 | + if (out_fmt == RGB) | |
465 | + fg_csc_type = YUV2RGB; | |
466 | + else | |
467 | + fg_csc_type = YUV2YUV; | |
468 | + } | |
469 | + } else { | |
470 | + if (in_fmt == RGB) { | |
471 | + if (out_fmt == RGB) | |
472 | + bg_csc_type = RGB2RGB; | |
473 | + else | |
474 | + bg_csc_type = RGB2YUV; | |
475 | + } else { | |
476 | + if (out_fmt == RGB) | |
477 | + bg_csc_type = YUV2RGB; | |
478 | + else | |
479 | + bg_csc_type = YUV2YUV; | |
480 | + } | |
481 | + } | |
482 | + | |
483 | + /* Transform color key from rgb to yuv if CSC is enabled */ | |
484 | + reg = __raw_readl(DP_COM_CONF(dp)); | |
485 | + if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) && | |
486 | + (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || | |
487 | + ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || | |
488 | + ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || | |
489 | + ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) { | |
490 | + int red, green, blue; | |
491 | + int y, u, v; | |
492 | + uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL(dp)) & | |
493 | + 0xFFFFFFL; | |
494 | + | |
495 | + debug("_ipu_dp_init color key 0x%x need change to yuv fmt!\n", | |
496 | + color_key); | |
497 | + | |
498 | + red = (color_key >> 16) & 0xFF; | |
499 | + green = (color_key >> 8) & 0xFF; | |
500 | + blue = color_key & 0xFF; | |
501 | + | |
502 | + y = rgb_to_yuv(0, red, green, blue); | |
503 | + u = rgb_to_yuv(1, red, green, blue); | |
504 | + v = rgb_to_yuv(2, red, green, blue); | |
505 | + color_key = (y << 16) | (u << 8) | v; | |
506 | + | |
507 | + reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp)) & 0xFF000000L; | |
508 | + __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp)); | |
509 | + color_key_4rgb = 0; | |
510 | + | |
511 | + debug("_ipu_dp_init color key change to yuv fmt 0x%x!\n", | |
512 | + color_key); | |
513 | + } | |
514 | + | |
515 | + ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 1); | |
516 | + | |
517 | + return 0; | |
518 | +} | |
519 | + | |
520 | +void ipu_dp_uninit(ipu_channel_t channel) | |
521 | +{ | |
522 | + int dp; | |
523 | + int partial = 0; | |
524 | + | |
525 | + if (channel == MEM_FG_SYNC) { | |
526 | + dp = DP_SYNC; | |
527 | + partial = 1; | |
528 | + } else if (channel == MEM_BG_SYNC) { | |
529 | + dp = DP_SYNC; | |
530 | + partial = 0; | |
531 | + } else if (channel == MEM_BG_ASYNC0) { | |
532 | + dp = DP_ASYNC0; | |
533 | + partial = 0; | |
534 | + } else { | |
535 | + return; | |
536 | + } | |
537 | + | |
538 | + if (partial) | |
539 | + fg_csc_type = CSC_NONE; | |
540 | + else | |
541 | + bg_csc_type = CSC_NONE; | |
542 | + | |
543 | + ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0); | |
544 | +} | |
545 | + | |
546 | +void ipu_dc_init(int dc_chan, int di, unsigned char interlaced) | |
547 | +{ | |
548 | + u32 reg = 0; | |
549 | + | |
550 | + if ((dc_chan == 1) || (dc_chan == 5)) { | |
551 | + if (interlaced) { | |
552 | + ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3); | |
553 | + ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2); | |
554 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1); | |
555 | + } else { | |
556 | + if (di) { | |
557 | + ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); | |
558 | + ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); | |
559 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, | |
560 | + 4, 1); | |
561 | + } else { | |
562 | + ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); | |
563 | + ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); | |
564 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, | |
565 | + 7, 1); | |
566 | + } | |
567 | + } | |
568 | + ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); | |
569 | + ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); | |
570 | + ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); | |
571 | + ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); | |
572 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); | |
573 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); | |
574 | + | |
575 | + reg = 0x2; | |
576 | + reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; | |
577 | + reg |= di << 2; | |
578 | + if (interlaced) | |
579 | + reg |= DC_WR_CH_CONF_FIELD_MODE; | |
580 | + } else if ((dc_chan == 8) || (dc_chan == 9)) { | |
581 | + /* async channels */ | |
582 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1); | |
583 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1); | |
584 | + | |
585 | + reg = 0x3; | |
586 | + reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; | |
587 | + } | |
588 | + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
589 | + | |
590 | + __raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan)); | |
591 | + | |
592 | + __raw_writel(0x00000084, DC_GEN); | |
593 | +} | |
594 | + | |
595 | +void ipu_dc_uninit(int dc_chan) | |
596 | +{ | |
597 | + if ((dc_chan == 1) || (dc_chan == 5)) { | |
598 | + ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0); | |
599 | + ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0); | |
600 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0); | |
601 | + ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); | |
602 | + ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); | |
603 | + ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); | |
604 | + ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); | |
605 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); | |
606 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); | |
607 | + } else if ((dc_chan == 8) || (dc_chan == 9)) { | |
608 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0); | |
609 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0); | |
610 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0); | |
611 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0); | |
612 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0); | |
613 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0); | |
614 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0); | |
615 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0); | |
616 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0); | |
617 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0); | |
618 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0); | |
619 | + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0); | |
620 | + } | |
621 | +} | |
622 | + | |
623 | +int ipu_chan_is_interlaced(ipu_channel_t channel) | |
624 | +{ | |
625 | + if (channel == MEM_DC_SYNC) | |
626 | + return !!(__raw_readl(DC_WR_CH_CONF_1) & | |
627 | + DC_WR_CH_CONF_FIELD_MODE); | |
628 | + else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC)) | |
629 | + return !!(__raw_readl(DC_WR_CH_CONF_5) & | |
630 | + DC_WR_CH_CONF_FIELD_MODE); | |
631 | + return 0; | |
632 | +} | |
633 | + | |
634 | +void ipu_dp_dc_enable(ipu_channel_t channel) | |
635 | +{ | |
636 | + int di; | |
637 | + uint32_t reg; | |
638 | + uint32_t dc_chan; | |
639 | + | |
640 | + if (channel == MEM_FG_SYNC) | |
641 | + dc_chan = 5; | |
642 | + if (channel == MEM_DC_SYNC) | |
643 | + dc_chan = 1; | |
644 | + else if (channel == MEM_BG_SYNC) | |
645 | + dc_chan = 5; | |
646 | + else | |
647 | + return; | |
648 | + | |
649 | + if (channel == MEM_FG_SYNC) { | |
650 | + /* Enable FG channel */ | |
651 | + reg = __raw_readl(DP_COM_CONF(DP_SYNC)); | |
652 | + __raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC)); | |
653 | + | |
654 | + reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
655 | + __raw_writel(reg, IPU_SRM_PRI2); | |
656 | + return; | |
657 | + } | |
658 | + | |
659 | + di = g_dc_di_assignment[dc_chan]; | |
660 | + | |
661 | + /* Make sure other DC sync channel is not assigned same DI */ | |
662 | + reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan)); | |
663 | + if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) { | |
664 | + reg &= ~DC_WR_CH_CONF_PROG_DI_ID; | |
665 | + reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID; | |
666 | + __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); | |
667 | + } | |
668 | + | |
669 | + reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
670 | + reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET; | |
671 | + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
672 | + | |
673 | + clk_enable(g_pixel_clk[di]); | |
674 | +} | |
675 | + | |
676 | +static unsigned char dc_swap; | |
677 | + | |
678 | +void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap) | |
679 | +{ | |
680 | + uint32_t reg; | |
681 | + uint32_t csc; | |
682 | + uint32_t dc_chan = 0; | |
683 | + int timeout = 50; | |
684 | + | |
685 | + dc_swap = swap; | |
686 | + | |
687 | + if (channel == MEM_DC_SYNC) { | |
688 | + dc_chan = 1; | |
689 | + } else if (channel == MEM_BG_SYNC) { | |
690 | + dc_chan = 5; | |
691 | + } else if (channel == MEM_FG_SYNC) { | |
692 | + /* Disable FG channel */ | |
693 | + dc_chan = 5; | |
694 | + | |
695 | + reg = __raw_readl(DP_COM_CONF(DP_SYNC)); | |
696 | + csc = reg & DP_COM_CONF_CSC_DEF_MASK; | |
697 | + if (csc == DP_COM_CONF_CSC_DEF_FG) | |
698 | + reg &= ~DP_COM_CONF_CSC_DEF_MASK; | |
699 | + | |
700 | + reg &= ~DP_COM_CONF_FG_EN; | |
701 | + __raw_writel(reg, DP_COM_CONF(DP_SYNC)); | |
702 | + | |
703 | + reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
704 | + __raw_writel(reg, IPU_SRM_PRI2); | |
705 | + | |
706 | + timeout = 50; | |
707 | + | |
708 | + /* | |
709 | + * Wait for DC triple buffer to empty, | |
710 | + * this check is useful for tv overlay. | |
711 | + */ | |
712 | + if (g_dc_di_assignment[dc_chan] == 0) | |
713 | + while ((__raw_readl(DC_STAT) & 0x00000002) | |
714 | + != 0x00000002) { | |
715 | + udelay(2000); | |
716 | + timeout -= 2; | |
717 | + if (timeout <= 0) | |
718 | + break; | |
719 | + } | |
720 | + else if (g_dc_di_assignment[dc_chan] == 1) | |
721 | + while ((__raw_readl(DC_STAT) & 0x00000020) | |
722 | + != 0x00000020) { | |
723 | + udelay(2000); | |
724 | + timeout -= 2; | |
725 | + if (timeout <= 0) | |
726 | + break; | |
727 | + } | |
728 | + return; | |
729 | + } else { | |
730 | + return; | |
731 | + } | |
732 | + | |
733 | + if (dc_swap) { | |
734 | + /* Swap DC channel 1 and 5 settings, and disable old dc chan */ | |
735 | + reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
736 | + __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); | |
737 | + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; | |
738 | + reg ^= DC_WR_CH_CONF_PROG_DI_ID; | |
739 | + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
740 | + } else { | |
741 | + timeout = 50; | |
742 | + | |
743 | + /* Wait for DC triple buffer to empty */ | |
744 | + if (g_dc_di_assignment[dc_chan] == 0) | |
745 | + while ((__raw_readl(DC_STAT) & 0x00000002) | |
746 | + != 0x00000002) { | |
747 | + udelay(2000); | |
748 | + timeout -= 2; | |
749 | + if (timeout <= 0) | |
750 | + break; | |
751 | + } | |
752 | + else if (g_dc_di_assignment[dc_chan] == 1) | |
753 | + while ((__raw_readl(DC_STAT) & 0x00000020) | |
754 | + != 0x00000020) { | |
755 | + udelay(2000); | |
756 | + timeout -= 2; | |
757 | + if (timeout <= 0) | |
758 | + break; | |
759 | + } | |
760 | + | |
761 | + reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
762 | + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; | |
763 | + __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
764 | + | |
765 | + reg = __raw_readl(IPU_DISP_GEN); | |
766 | + if (g_dc_di_assignment[dc_chan]) | |
767 | + reg &= ~DI1_COUNTER_RELEASE; | |
768 | + else | |
769 | + reg &= ~DI0_COUNTER_RELEASE; | |
770 | + __raw_writel(reg, IPU_DISP_GEN); | |
771 | + | |
772 | + /* Clock is already off because it must be done quickly, but | |
773 | + we need to fix the ref count */ | |
774 | + clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); | |
775 | + } | |
776 | +} | |
777 | + | |
778 | +void ipu_init_dc_mappings(void) | |
779 | +{ | |
780 | + /* IPU_PIX_FMT_RGB24 */ | |
781 | + ipu_dc_map_clear(0); | |
782 | + ipu_dc_map_config(0, 0, 7, 0xFF); | |
783 | + ipu_dc_map_config(0, 1, 15, 0xFF); | |
784 | + ipu_dc_map_config(0, 2, 23, 0xFF); | |
785 | + | |
786 | + /* IPU_PIX_FMT_RGB666 */ | |
787 | + ipu_dc_map_clear(1); | |
788 | + ipu_dc_map_config(1, 0, 5, 0xFC); | |
789 | + ipu_dc_map_config(1, 1, 11, 0xFC); | |
790 | + ipu_dc_map_config(1, 2, 17, 0xFC); | |
791 | + | |
792 | + /* IPU_PIX_FMT_YUV444 */ | |
793 | + ipu_dc_map_clear(2); | |
794 | + ipu_dc_map_config(2, 0, 15, 0xFF); | |
795 | + ipu_dc_map_config(2, 1, 23, 0xFF); | |
796 | + ipu_dc_map_config(2, 2, 7, 0xFF); | |
797 | + | |
798 | + /* IPU_PIX_FMT_RGB565 */ | |
799 | + ipu_dc_map_clear(3); | |
800 | + ipu_dc_map_config(3, 0, 4, 0xF8); | |
801 | + ipu_dc_map_config(3, 1, 10, 0xFC); | |
802 | + ipu_dc_map_config(3, 2, 15, 0xF8); | |
803 | + | |
804 | + /* IPU_PIX_FMT_LVDS666 */ | |
805 | + ipu_dc_map_clear(4); | |
806 | + ipu_dc_map_config(4, 0, 5, 0xFC); | |
807 | + ipu_dc_map_config(4, 1, 13, 0xFC); | |
808 | + ipu_dc_map_config(4, 2, 21, 0xFC); | |
809 | +} | |
810 | + | |
811 | +int ipu_pixfmt_to_map(uint32_t fmt) | |
812 | +{ | |
813 | + switch (fmt) { | |
814 | + case IPU_PIX_FMT_GENERIC: | |
815 | + case IPU_PIX_FMT_RGB24: | |
816 | + return 0; | |
817 | + case IPU_PIX_FMT_RGB666: | |
818 | + return 1; | |
819 | + case IPU_PIX_FMT_YUV444: | |
820 | + return 2; | |
821 | + case IPU_PIX_FMT_RGB565: | |
822 | + return 3; | |
823 | + case IPU_PIX_FMT_LVDS666: | |
824 | + return 4; | |
825 | + } | |
826 | + | |
827 | + return -1; | |
828 | +} | |
829 | + | |
830 | +/* | |
831 | + * This function is called to adapt synchronous LCD panel to IPU restriction. | |
832 | + */ | |
833 | +void adapt_panel_to_ipu_restricitions(uint32_t *pixel_clk, | |
834 | + uint16_t width, uint16_t height, | |
835 | + uint16_t h_start_width, | |
836 | + uint16_t h_end_width, | |
837 | + uint16_t v_start_width, | |
838 | + uint16_t *v_end_width) | |
839 | +{ | |
840 | + if (*v_end_width < 2) { | |
841 | + uint16_t total_width = width + h_start_width + h_end_width; | |
842 | + uint16_t total_height_old = height + v_start_width + | |
843 | + (*v_end_width); | |
844 | + uint16_t total_height_new = height + v_start_width + 2; | |
845 | + *v_end_width = 2; | |
846 | + *pixel_clk = (*pixel_clk) * total_width * total_height_new / | |
847 | + (total_width * total_height_old); | |
848 | + printf("WARNING: adapt panel end blank lines\n"); | |
849 | + } | |
850 | +} | |
851 | + | |
852 | +/* | |
853 | + * This function is called to initialize a synchronous LCD panel. | |
854 | + * | |
855 | + * @param disp The DI the panel is attached to. | |
856 | + * | |
857 | + * @param pixel_clk Desired pixel clock frequency in Hz. | |
858 | + * | |
859 | + * @param pixel_fmt Input parameter for pixel format of buffer. | |
860 | + * Pixel format is a FOURCC ASCII code. | |
861 | + * | |
862 | + * @param width The width of panel in pixels. | |
863 | + * | |
864 | + * @param height The height of panel in pixels. | |
865 | + * | |
866 | + * @param hStartWidth The number of pixel clocks between the HSYNC | |
867 | + * signal pulse and the start of valid data. | |
868 | + * | |
869 | + * @param hSyncWidth The width of the HSYNC signal in units of pixel | |
870 | + * clocks. | |
871 | + * | |
872 | + * @param hEndWidth The number of pixel clocks between the end of | |
873 | + * valid data and the HSYNC signal for next line. | |
874 | + * | |
875 | + * @param vStartWidth The number of lines between the VSYNC | |
876 | + * signal pulse and the start of valid data. | |
877 | + * | |
878 | + * @param vSyncWidth The width of the VSYNC signal in units of lines | |
879 | + * | |
880 | + * @param vEndWidth The number of lines between the end of valid | |
881 | + * data and the VSYNC signal for next frame. | |
882 | + * | |
883 | + * @param sig Bitfield of signal polarities for LCD interface. | |
884 | + * | |
885 | + * @return This function returns 0 on success or negative error code on | |
886 | + * fail. | |
887 | + */ | |
888 | + | |
889 | +int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, | |
890 | + uint16_t width, uint16_t height, | |
891 | + uint32_t pixel_fmt, | |
892 | + uint16_t h_start_width, uint16_t h_sync_width, | |
893 | + uint16_t h_end_width, uint16_t v_start_width, | |
894 | + uint16_t v_sync_width, uint16_t v_end_width, | |
895 | + uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig) | |
896 | +{ | |
897 | + uint32_t reg; | |
898 | + uint32_t di_gen, vsync_cnt; | |
899 | + uint32_t div, rounded_pixel_clk; | |
900 | + uint32_t h_total, v_total; | |
901 | + int map; | |
902 | + struct clk *di_parent; | |
903 | + | |
904 | + debug("panel size = %d x %d\n", width, height); | |
905 | + | |
906 | + if ((v_sync_width == 0) || (h_sync_width == 0)) | |
907 | + return EINVAL; | |
908 | + | |
909 | + adapt_panel_to_ipu_restricitions(&pixel_clk, width, height, | |
910 | + h_start_width, h_end_width, | |
911 | + v_start_width, &v_end_width); | |
912 | + h_total = width + h_sync_width + h_start_width + h_end_width; | |
913 | + v_total = height + v_sync_width + v_start_width + v_end_width; | |
914 | + | |
915 | + /* Init clocking */ | |
916 | + debug("pixel clk = %d\n", pixel_clk); | |
917 | + | |
918 | + if (sig.ext_clk) { | |
919 | + if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/ | |
920 | + /* | |
921 | + * Set the PLL to be an even multiple | |
922 | + * of the pixel clock. | |
923 | + */ | |
924 | + if ((clk_get_usecount(g_pixel_clk[0]) == 0) && | |
925 | + (clk_get_usecount(g_pixel_clk[1]) == 0)) { | |
926 | + di_parent = clk_get_parent(g_di_clk[disp]); | |
927 | + rounded_pixel_clk = | |
928 | + clk_round_rate(g_pixel_clk[disp], | |
929 | + pixel_clk); | |
930 | + div = clk_get_rate(di_parent) / | |
931 | + rounded_pixel_clk; | |
932 | + if (div % 2) | |
933 | + div++; | |
934 | + if (clk_get_rate(di_parent) != div * | |
935 | + rounded_pixel_clk) | |
936 | + clk_set_rate(di_parent, | |
937 | + div * rounded_pixel_clk); | |
938 | + udelay(10000); | |
939 | + clk_set_rate(g_di_clk[disp], | |
940 | + 2 * rounded_pixel_clk); | |
941 | + udelay(10000); | |
942 | + } | |
943 | + } | |
944 | + clk_set_parent(g_pixel_clk[disp], g_di_clk[disp]); | |
945 | + } else { | |
946 | + if (clk_get_usecount(g_pixel_clk[disp]) != 0) | |
947 | + clk_set_parent(g_pixel_clk[disp], g_ipu_clk); | |
948 | + } | |
949 | + rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk); | |
950 | + clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk); | |
951 | + udelay(5000); | |
952 | + /* Get integer portion of divider */ | |
953 | + div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) / | |
954 | + rounded_pixel_clk; | |
955 | + | |
956 | + ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1); | |
957 | + ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); | |
958 | + | |
959 | + map = ipu_pixfmt_to_map(pixel_fmt); | |
960 | + if (map < 0) { | |
961 | + debug("IPU_DISP: No MAP\n"); | |
962 | + return -EINVAL; | |
963 | + } | |
964 | + | |
965 | + di_gen = __raw_readl(DI_GENERAL(disp)); | |
966 | + | |
967 | + if (sig.interlaced) { | |
968 | + /* Setup internal HSYNC waveform */ | |
969 | + ipu_di_sync_config( | |
970 | + disp, /* display */ | |
971 | + 1, /* counter */ | |
972 | + h_total / 2 - 1,/* run count */ | |
973 | + DI_SYNC_CLK, /* run_resolution */ | |
974 | + 0, /* offset */ | |
975 | + DI_SYNC_NONE, /* offset resolution */ | |
976 | + 0, /* repeat count */ | |
977 | + DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
978 | + 0, /* CNT_POLARITY_GEN_EN */ | |
979 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
980 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
981 | + 0, /* COUNT UP */ | |
982 | + 0 /* COUNT DOWN */ | |
983 | + ); | |
984 | + | |
985 | + /* Field 1 VSYNC waveform */ | |
986 | + ipu_di_sync_config( | |
987 | + disp, /* display */ | |
988 | + 2, /* counter */ | |
989 | + h_total - 1, /* run count */ | |
990 | + DI_SYNC_CLK, /* run_resolution */ | |
991 | + 0, /* offset */ | |
992 | + DI_SYNC_NONE, /* offset resolution */ | |
993 | + 0, /* repeat count */ | |
994 | + DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
995 | + 0, /* CNT_POLARITY_GEN_EN */ | |
996 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
997 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
998 | + 0, /* COUNT UP */ | |
999 | + 4 /* COUNT DOWN */ | |
1000 | + ); | |
1001 | + | |
1002 | + /* Setup internal HSYNC waveform */ | |
1003 | + ipu_di_sync_config( | |
1004 | + disp, /* display */ | |
1005 | + 3, /* counter */ | |
1006 | + v_total * 2 - 1,/* run count */ | |
1007 | + DI_SYNC_INT_HSYNC, /* run_resolution */ | |
1008 | + 1, /* offset */ | |
1009 | + DI_SYNC_INT_HSYNC, /* offset resolution */ | |
1010 | + 0, /* repeat count */ | |
1011 | + DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
1012 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1013 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1014 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1015 | + 0, /* COUNT UP */ | |
1016 | + 4 /* COUNT DOWN */ | |
1017 | + ); | |
1018 | + | |
1019 | + /* Active Field ? */ | |
1020 | + ipu_di_sync_config( | |
1021 | + disp, /* display */ | |
1022 | + 4, /* counter */ | |
1023 | + v_total / 2 - 1,/* run count */ | |
1024 | + DI_SYNC_HSYNC, /* run_resolution */ | |
1025 | + v_start_width, /* offset */ | |
1026 | + DI_SYNC_HSYNC, /* offset resolution */ | |
1027 | + 2, /* repeat count */ | |
1028 | + DI_SYNC_VSYNC, /* CNT_CLR_SEL */ | |
1029 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1030 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1031 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1032 | + 0, /* COUNT UP */ | |
1033 | + 0 /* COUNT DOWN */ | |
1034 | + ); | |
1035 | + | |
1036 | + /* Active Line */ | |
1037 | + ipu_di_sync_config( | |
1038 | + disp, /* display */ | |
1039 | + 5, /* counter */ | |
1040 | + 0, /* run count */ | |
1041 | + DI_SYNC_HSYNC, /* run_resolution */ | |
1042 | + 0, /* offset */ | |
1043 | + DI_SYNC_NONE, /* offset resolution */ | |
1044 | + height / 2, /* repeat count */ | |
1045 | + 4, /* CNT_CLR_SEL */ | |
1046 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1047 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1048 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1049 | + 0, /* COUNT UP */ | |
1050 | + 0 /* COUNT DOWN */ | |
1051 | + ); | |
1052 | + | |
1053 | + /* Field 0 VSYNC waveform */ | |
1054 | + ipu_di_sync_config( | |
1055 | + disp, /* display */ | |
1056 | + 6, /* counter */ | |
1057 | + v_total - 1, /* run count */ | |
1058 | + DI_SYNC_HSYNC, /* run_resolution */ | |
1059 | + 0, /* offset */ | |
1060 | + DI_SYNC_NONE, /* offset resolution */ | |
1061 | + 0, /* repeat count */ | |
1062 | + DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
1063 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1064 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1065 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1066 | + 0, /* COUNT UP */ | |
1067 | + 0 /* COUNT DOWN */ | |
1068 | + ); | |
1069 | + | |
1070 | + /* DC VSYNC waveform */ | |
1071 | + vsync_cnt = 7; | |
1072 | + ipu_di_sync_config( | |
1073 | + disp, /* display */ | |
1074 | + 7, /* counter */ | |
1075 | + v_total / 2 - 1,/* run count */ | |
1076 | + DI_SYNC_HSYNC, /* run_resolution */ | |
1077 | + 9, /* offset */ | |
1078 | + DI_SYNC_HSYNC, /* offset resolution */ | |
1079 | + 2, /* repeat count */ | |
1080 | + DI_SYNC_VSYNC, /* CNT_CLR_SEL */ | |
1081 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1082 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1083 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1084 | + 0, /* COUNT UP */ | |
1085 | + 0 /* COUNT DOWN */ | |
1086 | + ); | |
1087 | + | |
1088 | + /* active pixel waveform */ | |
1089 | + ipu_di_sync_config( | |
1090 | + disp, /* display */ | |
1091 | + 8, /* counter */ | |
1092 | + 0, /* run count */ | |
1093 | + DI_SYNC_CLK, /* run_resolution */ | |
1094 | + h_start_width, /* offset */ | |
1095 | + DI_SYNC_CLK, /* offset resolution */ | |
1096 | + width, /* repeat count */ | |
1097 | + 5, /* CNT_CLR_SEL */ | |
1098 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1099 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1100 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1101 | + 0, /* COUNT UP */ | |
1102 | + 0 /* COUNT DOWN */ | |
1103 | + ); | |
1104 | + | |
1105 | + ipu_di_sync_config( | |
1106 | + disp, /* display */ | |
1107 | + 9, /* counter */ | |
1108 | + v_total - 1, /* run count */ | |
1109 | + DI_SYNC_INT_HSYNC,/* run_resolution */ | |
1110 | + v_total / 2, /* offset */ | |
1111 | + DI_SYNC_INT_HSYNC,/* offset resolution */ | |
1112 | + 0, /* repeat count */ | |
1113 | + DI_SYNC_HSYNC, /* CNT_CLR_SEL */ | |
1114 | + 0, /* CNT_POLARITY_GEN_EN */ | |
1115 | + DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1116 | + DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1117 | + 0, /* COUNT UP */ | |
1118 | + 4 /* COUNT DOWN */ | |
1119 | + ); | |
1120 | + | |
1121 | + /* set gentime select and tag sel */ | |
1122 | + reg = __raw_readl(DI_SW_GEN1(disp, 9)); | |
1123 | + reg &= 0x1FFFFFFF; | |
1124 | + reg |= (3 - 1)<<29 | 0x00008000; | |
1125 | + __raw_writel(reg, DI_SW_GEN1(disp, 9)); | |
1126 | + | |
1127 | + __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp)); | |
1128 | + | |
1129 | + /* set y_sel = 1 */ | |
1130 | + di_gen |= 0x10000000; | |
1131 | + di_gen |= DI_GEN_POLARITY_5; | |
1132 | + di_gen |= DI_GEN_POLARITY_8; | |
1133 | + } else { | |
1134 | + /* Setup internal HSYNC waveform */ | |
1135 | + ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK, | |
1136 | + 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, | |
1137 | + 0, DI_SYNC_NONE, | |
1138 | + DI_SYNC_NONE, 0, 0); | |
1139 | + | |
1140 | + /* Setup external (delayed) HSYNC waveform */ | |
1141 | + ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1, | |
1142 | + DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK, | |
1143 | + 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, | |
1144 | + DI_SYNC_CLK, 0, h_sync_width * 2); | |
1145 | + /* Setup VSYNC waveform */ | |
1146 | + vsync_cnt = DI_SYNC_VSYNC; | |
1147 | + ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1, | |
1148 | + DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0, | |
1149 | + DI_SYNC_NONE, 1, DI_SYNC_NONE, | |
1150 | + DI_SYNC_INT_HSYNC, 0, v_sync_width * 2); | |
1151 | + __raw_writel(v_total - 1, DI_SCR_CONF(disp)); | |
1152 | + | |
1153 | + /* Setup active data waveform to sync with DC */ | |
1154 | + ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC, | |
1155 | + v_sync_width + v_start_width, DI_SYNC_HSYNC, | |
1156 | + height, | |
1157 | + DI_SYNC_VSYNC, 0, DI_SYNC_NONE, | |
1158 | + DI_SYNC_NONE, 0, 0); | |
1159 | + ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK, | |
1160 | + h_sync_width + h_start_width, DI_SYNC_CLK, | |
1161 | + width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, | |
1162 | + 0); | |
1163 | + | |
1164 | + /* reset all unused counters */ | |
1165 | + __raw_writel(0, DI_SW_GEN0(disp, 6)); | |
1166 | + __raw_writel(0, DI_SW_GEN1(disp, 6)); | |
1167 | + __raw_writel(0, DI_SW_GEN0(disp, 7)); | |
1168 | + __raw_writel(0, DI_SW_GEN1(disp, 7)); | |
1169 | + __raw_writel(0, DI_SW_GEN0(disp, 8)); | |
1170 | + __raw_writel(0, DI_SW_GEN1(disp, 8)); | |
1171 | + __raw_writel(0, DI_SW_GEN0(disp, 9)); | |
1172 | + __raw_writel(0, DI_SW_GEN1(disp, 9)); | |
1173 | + | |
1174 | + reg = __raw_readl(DI_STP_REP(disp, 6)); | |
1175 | + reg &= 0x0000FFFF; | |
1176 | + __raw_writel(reg, DI_STP_REP(disp, 6)); | |
1177 | + __raw_writel(0, DI_STP_REP(disp, 7)); | |
1178 | + __raw_writel(0, DI_STP_REP(disp, 9)); | |
1179 | + | |
1180 | + /* Init template microcode */ | |
1181 | + if (disp) { | |
1182 | + ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); | |
1183 | + ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); | |
1184 | + ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); | |
1185 | + } else { | |
1186 | + ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); | |
1187 | + ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); | |
1188 | + ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); | |
1189 | + } | |
1190 | + | |
1191 | + if (sig.Hsync_pol) | |
1192 | + di_gen |= DI_GEN_POLARITY_2; | |
1193 | + if (sig.Vsync_pol) | |
1194 | + di_gen |= DI_GEN_POLARITY_3; | |
1195 | + | |
1196 | + if (sig.clk_pol) | |
1197 | + di_gen |= DI_GEN_POL_CLK; | |
1198 | + | |
1199 | + } | |
1200 | + | |
1201 | + __raw_writel(di_gen, DI_GENERAL(disp)); | |
1202 | + | |
1203 | + __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) | | |
1204 | + 0x00000002, DI_SYNC_AS_GEN(disp)); | |
1205 | + | |
1206 | + reg = __raw_readl(DI_POL(disp)); | |
1207 | + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); | |
1208 | + if (sig.enable_pol) | |
1209 | + reg |= DI_POL_DRDY_POLARITY_15; | |
1210 | + if (sig.data_pol) | |
1211 | + reg |= DI_POL_DRDY_DATA_POLARITY; | |
1212 | + __raw_writel(reg, DI_POL(disp)); | |
1213 | + | |
1214 | + __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp))); | |
1215 | + | |
1216 | + return 0; | |
1217 | +} | |
1218 | + | |
1219 | +/* | |
1220 | + * This function sets the foreground and background plane global alpha blending | |
1221 | + * modes. This function also sets the DP graphic plane according to the | |
1222 | + * parameter of IPUv3 DP channel. | |
1223 | + * | |
1224 | + * @param channel IPUv3 DP channel | |
1225 | + * | |
1226 | + * @param enable Boolean to enable or disable global alpha | |
1227 | + * blending. If disabled, local blending is used. | |
1228 | + * | |
1229 | + * @param alpha Global alpha value. | |
1230 | + * | |
1231 | + * @return Returns 0 on success or negative error code on fail | |
1232 | + */ | |
1233 | +int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable, | |
1234 | + uint8_t alpha) | |
1235 | +{ | |
1236 | + uint32_t reg; | |
1237 | + uint32_t flow; | |
1238 | + | |
1239 | + unsigned char bg_chan; | |
1240 | + | |
1241 | + if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) | |
1242 | + flow = DP_SYNC; | |
1243 | + else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) | |
1244 | + flow = DP_ASYNC0; | |
1245 | + else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1) | |
1246 | + flow = DP_ASYNC1; | |
1247 | + else | |
1248 | + return -EINVAL; | |
1249 | + | |
1250 | + if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 || | |
1251 | + channel == MEM_BG_ASYNC1) | |
1252 | + bg_chan = 1; | |
1253 | + else | |
1254 | + bg_chan = 0; | |
1255 | + | |
1256 | + if (!g_ipu_clk_enabled) | |
1257 | + clk_enable(g_ipu_clk); | |
1258 | + | |
1259 | + if (bg_chan) { | |
1260 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1261 | + __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow)); | |
1262 | + } else { | |
1263 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1264 | + __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow)); | |
1265 | + } | |
1266 | + | |
1267 | + if (enable) { | |
1268 | + reg = __raw_readl(DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL; | |
1269 | + __raw_writel(reg | ((uint32_t) alpha << 24), | |
1270 | + DP_GRAPH_WIND_CTRL(flow)); | |
1271 | + | |
1272 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1273 | + __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF(flow)); | |
1274 | + } else { | |
1275 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1276 | + __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(flow)); | |
1277 | + } | |
1278 | + | |
1279 | + reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
1280 | + __raw_writel(reg, IPU_SRM_PRI2); | |
1281 | + | |
1282 | + if (!g_ipu_clk_enabled) | |
1283 | + clk_disable(g_ipu_clk); | |
1284 | + | |
1285 | + return 0; | |
1286 | +} | |
1287 | + | |
1288 | +/* | |
1289 | + * This function sets the transparent color key for SDC graphic plane. | |
1290 | + * | |
1291 | + * @param channel Input parameter for the logical channel ID. | |
1292 | + * | |
1293 | + * @param enable Boolean to enable or disable color key | |
1294 | + * | |
1295 | + * @param colorKey 24-bit RGB color for transparent color key. | |
1296 | + * | |
1297 | + * @return Returns 0 on success or negative error code on fail | |
1298 | + */ | |
1299 | +int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable, | |
1300 | + uint32_t color_key) | |
1301 | +{ | |
1302 | + uint32_t reg, flow; | |
1303 | + int y, u, v; | |
1304 | + int red, green, blue; | |
1305 | + | |
1306 | + if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) | |
1307 | + flow = DP_SYNC; | |
1308 | + else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) | |
1309 | + flow = DP_ASYNC0; | |
1310 | + else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1) | |
1311 | + flow = DP_ASYNC1; | |
1312 | + else | |
1313 | + return -EINVAL; | |
1314 | + | |
1315 | + if (!g_ipu_clk_enabled) | |
1316 | + clk_enable(g_ipu_clk); | |
1317 | + | |
1318 | + color_key_4rgb = 1; | |
1319 | + /* Transform color key from rgb to yuv if CSC is enabled */ | |
1320 | + if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || | |
1321 | + ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || | |
1322 | + ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || | |
1323 | + ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) { | |
1324 | + | |
1325 | + debug("color key 0x%x need change to yuv fmt\n", color_key); | |
1326 | + | |
1327 | + red = (color_key >> 16) & 0xFF; | |
1328 | + green = (color_key >> 8) & 0xFF; | |
1329 | + blue = color_key & 0xFF; | |
1330 | + | |
1331 | + y = rgb_to_yuv(0, red, green, blue); | |
1332 | + u = rgb_to_yuv(1, red, green, blue); | |
1333 | + v = rgb_to_yuv(2, red, green, blue); | |
1334 | + color_key = (y << 16) | (u << 8) | v; | |
1335 | + | |
1336 | + color_key_4rgb = 0; | |
1337 | + | |
1338 | + debug("color key change to yuv fmt 0x%x\n", color_key); | |
1339 | + } | |
1340 | + | |
1341 | + if (enable) { | |
1342 | + reg = __raw_readl(DP_GRAPH_WIND_CTRL(flow)) & 0xFF000000L; | |
1343 | + __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(flow)); | |
1344 | + | |
1345 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1346 | + __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF(flow)); | |
1347 | + } else { | |
1348 | + reg = __raw_readl(DP_COM_CONF(flow)); | |
1349 | + __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(flow)); | |
1350 | + } | |
1351 | + | |
1352 | + reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
1353 | + __raw_writel(reg, IPU_SRM_PRI2); | |
1354 | + | |
1355 | + if (!g_ipu_clk_enabled) | |
1356 | + clk_disable(g_ipu_clk); | |
1357 | + | |
1358 | + return 0; | |
1359 | +} |
drivers/video/ipu_regs.h
1 | +/* | |
2 | + * Porting to u-boot: | |
3 | + * | |
4 | + * (C) Copyright 2010 | |
5 | + * Stefano Babic, DENX Software Engineering, sbabic@denx.de | |
6 | + * | |
7 | + * Linux IPU driver for MX51: | |
8 | + * | |
9 | + * (C) Copyright 2005-2009 Freescale Semiconductor, Inc. | |
10 | + * | |
11 | + * See file CREDITS for list of people who contributed to this | |
12 | + * project. | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or | |
15 | + * modify it under the terms of the GNU General Public License as | |
16 | + * published by the Free Software Foundation; either version 2 of | |
17 | + * the License, or (at your option) any later version. | |
18 | + * | |
19 | + * This program is distributed in the hope that it will be useful, | |
20 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | + * GNU General Public License for more details. | |
23 | + * | |
24 | + * You should have received a copy of the GNU General Public License | |
25 | + * along with this program; if not, write to the Free Software | |
26 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
27 | + * MA 02111-1307 USA | |
28 | + */ | |
29 | + | |
30 | +#ifndef __IPU_REGS_INCLUDED__ | |
31 | +#define __IPU_REGS_INCLUDED__ | |
32 | + | |
33 | +#define IPU_DISP0_BASE 0x00000000 | |
34 | +#define IPU_MCU_T_DEFAULT 8 | |
35 | +#define IPU_DISP1_BASE (IPU_MCU_T_DEFAULT << 25) | |
36 | +#define IPU_CM_REG_BASE 0x1E000000 | |
37 | +#define IPU_STAT_REG_BASE 0x1E000200 | |
38 | +#define IPU_IDMAC_REG_BASE 0x1E008000 | |
39 | +#define IPU_ISP_REG_BASE 0x1E010000 | |
40 | +#define IPU_DP_REG_BASE 0x1E018000 | |
41 | +#define IPU_IC_REG_BASE 0x1E020000 | |
42 | +#define IPU_IRT_REG_BASE 0x1E028000 | |
43 | +#define IPU_CSI0_REG_BASE 0x1E030000 | |
44 | +#define IPU_CSI1_REG_BASE 0x1E038000 | |
45 | +#define IPU_DI0_REG_BASE 0x1E040000 | |
46 | +#define IPU_DI1_REG_BASE 0x1E048000 | |
47 | +#define IPU_SMFC_REG_BASE 0x1E050000 | |
48 | +#define IPU_DC_REG_BASE 0x1E058000 | |
49 | +#define IPU_DMFC_REG_BASE 0x1E060000 | |
50 | +#define IPU_CPMEM_REG_BASE 0x1F000000 | |
51 | +#define IPU_LUT_REG_BASE 0x1F020000 | |
52 | +#define IPU_SRM_REG_BASE 0x1F040000 | |
53 | +#define IPU_TPM_REG_BASE 0x1F060000 | |
54 | +#define IPU_DC_TMPL_REG_BASE 0x1F080000 | |
55 | +#define IPU_ISP_TBPR_REG_BASE 0x1F0C0000 | |
56 | +#define IPU_VDI_REG_BASE 0x1E068000 | |
57 | + | |
58 | + | |
59 | +extern u32 *ipu_dc_tmpl_reg; | |
60 | + | |
61 | +#define DC_EVT_NF 0 | |
62 | +#define DC_EVT_NL 1 | |
63 | +#define DC_EVT_EOF 2 | |
64 | +#define DC_EVT_NFIELD 3 | |
65 | +#define DC_EVT_EOL 4 | |
66 | +#define DC_EVT_EOFIELD 5 | |
67 | +#define DC_EVT_NEW_ADDR 6 | |
68 | +#define DC_EVT_NEW_CHAN 7 | |
69 | +#define DC_EVT_NEW_DATA 8 | |
70 | + | |
71 | +#define DC_EVT_NEW_ADDR_W_0 0 | |
72 | +#define DC_EVT_NEW_ADDR_W_1 1 | |
73 | +#define DC_EVT_NEW_CHAN_W_0 2 | |
74 | +#define DC_EVT_NEW_CHAN_W_1 3 | |
75 | +#define DC_EVT_NEW_DATA_W_0 4 | |
76 | +#define DC_EVT_NEW_DATA_W_1 5 | |
77 | +#define DC_EVT_NEW_ADDR_R_0 6 | |
78 | +#define DC_EVT_NEW_ADDR_R_1 7 | |
79 | +#define DC_EVT_NEW_CHAN_R_0 8 | |
80 | +#define DC_EVT_NEW_CHAN_R_1 9 | |
81 | +#define DC_EVT_NEW_DATA_R_0 10 | |
82 | +#define DC_EVT_NEW_DATA_R_1 11 | |
83 | + | |
84 | +/* Software reset for ipu */ | |
85 | +#define SW_IPU_RST 8 | |
86 | + | |
87 | +enum { | |
88 | + IPU_CONF_DP_EN = 0x00000020, | |
89 | + IPU_CONF_DI0_EN = 0x00000040, | |
90 | + IPU_CONF_DI1_EN = 0x00000080, | |
91 | + IPU_CONF_DMFC_EN = 0x00000400, | |
92 | + IPU_CONF_DC_EN = 0x00000200, | |
93 | + | |
94 | + DI0_COUNTER_RELEASE = 0x01000000, | |
95 | + DI1_COUNTER_RELEASE = 0x02000000, | |
96 | + | |
97 | + DI_DW_GEN_ACCESS_SIZE_OFFSET = 24, | |
98 | + DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16, | |
99 | + | |
100 | + DI_GEN_DI_CLK_EXT = 0x100000, | |
101 | + DI_GEN_POLARITY_1 = 0x00000001, | |
102 | + DI_GEN_POLARITY_2 = 0x00000002, | |
103 | + DI_GEN_POLARITY_3 = 0x00000004, | |
104 | + DI_GEN_POLARITY_4 = 0x00000008, | |
105 | + DI_GEN_POLARITY_5 = 0x00000010, | |
106 | + DI_GEN_POLARITY_6 = 0x00000020, | |
107 | + DI_GEN_POLARITY_7 = 0x00000040, | |
108 | + DI_GEN_POLARITY_8 = 0x00000080, | |
109 | + DI_GEN_POL_CLK = 0x20000, | |
110 | + | |
111 | + DI_POL_DRDY_DATA_POLARITY = 0x00000080, | |
112 | + DI_POL_DRDY_POLARITY_15 = 0x00000010, | |
113 | + DI_VSYNC_SEL_OFFSET = 13, | |
114 | + | |
115 | + DC_WR_CH_CONF_FIELD_MODE = 0x00000200, | |
116 | + DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5, | |
117 | + DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0, | |
118 | + DC_WR_CH_CONF_PROG_DI_ID = 0x00000004, | |
119 | + DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3, | |
120 | + DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018, | |
121 | + | |
122 | + DP_COM_CONF_FG_EN = 0x00000001, | |
123 | + DP_COM_CONF_GWSEL = 0x00000002, | |
124 | + DP_COM_CONF_GWAM = 0x00000004, | |
125 | + DP_COM_CONF_GWCKE = 0x00000008, | |
126 | + DP_COM_CONF_CSC_DEF_MASK = 0x00000300, | |
127 | + DP_COM_CONF_CSC_DEF_OFFSET = 8, | |
128 | + DP_COM_CONF_CSC_DEF_FG = 0x00000300, | |
129 | + DP_COM_CONF_CSC_DEF_BG = 0x00000200, | |
130 | + DP_COM_CONF_CSC_DEF_BOTH = 0x00000100, | |
131 | + DP_COM_CONF_GAMMA_EN = 0x00001000, | |
132 | + DP_COM_CONF_GAMMA_YUV_EN = 0x00002000, | |
133 | +}; | |
134 | + | |
135 | +enum di_pins { | |
136 | + DI_PIN11 = 0, | |
137 | + DI_PIN12 = 1, | |
138 | + DI_PIN13 = 2, | |
139 | + DI_PIN14 = 3, | |
140 | + DI_PIN15 = 4, | |
141 | + DI_PIN16 = 5, | |
142 | + DI_PIN17 = 6, | |
143 | + DI_PIN_CS = 7, | |
144 | + | |
145 | + DI_PIN_SER_CLK = 0, | |
146 | + DI_PIN_SER_RS = 1, | |
147 | +}; | |
148 | + | |
149 | +enum di_sync_wave { | |
150 | + DI_SYNC_NONE = -1, | |
151 | + DI_SYNC_CLK = 0, | |
152 | + DI_SYNC_INT_HSYNC = 1, | |
153 | + DI_SYNC_HSYNC = 2, | |
154 | + DI_SYNC_VSYNC = 3, | |
155 | + DI_SYNC_DE = 5, | |
156 | +}; | |
157 | + | |
158 | +struct ipu_cm { | |
159 | + u32 conf; | |
160 | + u32 sisg_ctrl0; | |
161 | + u32 sisg_ctrl1; | |
162 | + u32 sisg_set[6]; | |
163 | + u32 sisg_clear[6]; | |
164 | + u32 int_ctrl[15]; | |
165 | + u32 sdma_event[10]; | |
166 | + u32 srm_pri1; | |
167 | + u32 srm_pri2; | |
168 | + u32 fs_proc_flow[3]; | |
169 | + u32 fs_disp_flow[2]; | |
170 | + u32 skip; | |
171 | + u32 disp_alt_conf; | |
172 | + u32 disp_gen; | |
173 | + u32 disp_alt[4]; | |
174 | + u32 snoop; | |
175 | + u32 mem_rst; | |
176 | + u32 pm; | |
177 | + u32 gpr; | |
178 | + u32 reserved0[26]; | |
179 | + u32 ch_db_mode_sel[2]; | |
180 | + u32 reserved1[16]; | |
181 | + u32 alt_ch_db_mode_sel[2]; | |
182 | + u32 reserved2[2]; | |
183 | + u32 ch_trb_mode_sel[2]; | |
184 | +}; | |
185 | + | |
186 | +struct ipu_idmac { | |
187 | + u32 conf; | |
188 | + u32 ch_en[2]; | |
189 | + u32 sep_alpha; | |
190 | + u32 alt_sep_alpha; | |
191 | + u32 ch_pri[2]; | |
192 | + u32 wm_en[2]; | |
193 | + u32 lock_en[2]; | |
194 | + u32 sub_addr[5]; | |
195 | + u32 bndm_en[2]; | |
196 | + u32 sc_cord[2]; | |
197 | + u32 reserved[45]; | |
198 | + u32 ch_busy[2]; | |
199 | +}; | |
200 | + | |
201 | +struct ipu_com_async { | |
202 | + u32 com_conf_async; | |
203 | + u32 graph_wind_ctrl_async; | |
204 | + u32 fg_pos_async; | |
205 | + u32 cur_pos_async; | |
206 | + u32 cur_map_async; | |
207 | + u32 gamma_c_async[8]; | |
208 | + u32 gamma_s_async[4]; | |
209 | + u32 dp_csca_async[4]; | |
210 | + u32 dp_csc_async[2]; | |
211 | +}; | |
212 | + | |
213 | +struct ipu_dp { | |
214 | + u32 com_conf_sync; | |
215 | + u32 graph_wind_ctrl_sync; | |
216 | + u32 fg_pos_sync; | |
217 | + u32 cur_pos_sync; | |
218 | + u32 cur_map_sync; | |
219 | + u32 gamma_c_sync[8]; | |
220 | + u32 gamma_s_sync[4]; | |
221 | + u32 csca_sync[4]; | |
222 | + u32 csc_sync[2]; | |
223 | + u32 cur_pos_alt; | |
224 | + struct ipu_com_async async[2]; | |
225 | +}; | |
226 | + | |
227 | +struct ipu_di { | |
228 | + u32 general; | |
229 | + u32 bs_clkgen0; | |
230 | + u32 bs_clkgen1; | |
231 | + u32 sw_gen0[9]; | |
232 | + u32 sw_gen1[9]; | |
233 | + u32 sync_as; | |
234 | + u32 dw_gen[12]; | |
235 | + u32 dw_set[48]; | |
236 | + u32 stp_rep[4]; | |
237 | + u32 stp_rep9; | |
238 | + u32 ser_conf; | |
239 | + u32 ssc; | |
240 | + u32 pol; | |
241 | + u32 aw0; | |
242 | + u32 aw1; | |
243 | + u32 scr_conf; | |
244 | + u32 stat; | |
245 | +}; | |
246 | + | |
247 | +struct ipu_stat { | |
248 | + u32 int_stat[15]; | |
249 | + u32 cur_buf[2]; | |
250 | + u32 alt_cur_buf_0; | |
251 | + u32 alt_cur_buf_1; | |
252 | + u32 srm_stat; | |
253 | + u32 proc_task_stat; | |
254 | + u32 disp_task_stat; | |
255 | + u32 triple_cur_buf[4]; | |
256 | + u32 ch_buf0_rdy[2]; | |
257 | + u32 ch_buf1_rdy[2]; | |
258 | + u32 alt_ch_buf0_rdy[2]; | |
259 | + u32 alt_ch_buf1_rdy[2]; | |
260 | + u32 ch_buf2_rdy[2]; | |
261 | +}; | |
262 | + | |
263 | +struct ipu_dc_ch { | |
264 | + u32 wr_ch_conf; | |
265 | + u32 wr_ch_addr; | |
266 | + u32 rl[5]; | |
267 | +}; | |
268 | + | |
269 | +struct ipu_dc { | |
270 | + struct ipu_dc_ch dc_ch0_1_2[3]; | |
271 | + u32 cmd_ch_conf_3; | |
272 | + u32 cmd_ch_conf_4; | |
273 | + struct ipu_dc_ch dc_ch5_6[2]; | |
274 | + struct ipu_dc_ch dc_ch8; | |
275 | + u32 rl6_ch_8; | |
276 | + struct ipu_dc_ch dc_ch9; | |
277 | + u32 rl6_ch_9; | |
278 | + u32 gen; | |
279 | + u32 disp_conf1[4]; | |
280 | + u32 disp_conf2[4]; | |
281 | + u32 di0_conf[2]; | |
282 | + u32 di1_conf[2]; | |
283 | + u32 dc_map_ptr[15]; | |
284 | + u32 dc_map_val[12]; | |
285 | + u32 udge[16]; | |
286 | + u32 lla[2]; | |
287 | + u32 r_lla[2]; | |
288 | + u32 wr_ch_addr_5_alt; | |
289 | + u32 stat; | |
290 | +}; | |
291 | + | |
292 | +struct ipu_dmfc { | |
293 | + u32 rd_chan; | |
294 | + u32 wr_chan; | |
295 | + u32 wr_chan_def; | |
296 | + u32 dp_chan; | |
297 | + u32 dp_chan_def; | |
298 | + u32 general[2]; | |
299 | + u32 ic_ctrl; | |
300 | + u32 wr_chan_alt; | |
301 | + u32 wr_chan_def_alt; | |
302 | + u32 general1_alt; | |
303 | + u32 stat; | |
304 | +}; | |
305 | + | |
306 | +#define IPU_CM_REG ((struct ipu_cm *)(IPU_CTRL_BASE_ADDR + \ | |
307 | + IPU_CM_REG_BASE)) | |
308 | +#define IPU_CONF (&IPU_CM_REG->conf) | |
309 | +#define IPU_SRM_PRI1 (&IPU_CM_REG->srm_pri1) | |
310 | +#define IPU_SRM_PRI2 (&IPU_CM_REG->srm_pri2) | |
311 | +#define IPU_FS_PROC_FLOW1 (&IPU_CM_REG->fs_proc_flow[0]) | |
312 | +#define IPU_FS_PROC_FLOW2 (&IPU_CM_REG->fs_proc_flow[1]) | |
313 | +#define IPU_FS_PROC_FLOW3 (&IPU_CM_REG->fs_proc_flow[2]) | |
314 | +#define IPU_FS_DISP_FLOW1 (&IPU_CM_REG->fs_disp_flow[0]) | |
315 | +#define IPU_DISP_GEN (&IPU_CM_REG->disp_gen) | |
316 | +#define IPU_MEM_RST (&IPU_CM_REG->mem_rst) | |
317 | +#define IPU_GPR (&IPU_CM_REG->gpr) | |
318 | +#define IPU_CHA_DB_MODE_SEL(ch) (&IPU_CM_REG->ch_db_mode_sel[ch / 32]) | |
319 | + | |
320 | +#define IPU_STAT ((struct ipu_stat *)(IPU_CTRL_BASE_ADDR + \ | |
321 | + IPU_STAT_REG_BASE)) | |
322 | +#define IPU_CHA_CUR_BUF(ch) (&IPU_STAT->cur_buf[ch / 32]) | |
323 | +#define IPU_CHA_BUF0_RDY(ch) (&IPU_STAT->ch_buf0_rdy[ch / 32]) | |
324 | +#define IPU_CHA_BUF1_RDY(ch) (&IPU_STAT->ch_buf1_rdy[ch / 32]) | |
325 | + | |
326 | +#define IPU_INT_CTRL(n) (&IPU_CM_REG->int_ctrl[(n) - 1]) | |
327 | + | |
328 | +#define IDMAC_REG ((struct ipu_idmac *)(IPU_CTRL_BASE_ADDR + \ | |
329 | + IPU_IDMAC_REG_BASE)) | |
330 | +#define IDMAC_CONF (&IDMAC_REG->conf) | |
331 | +#define IDMAC_CHA_EN(ch) (&IDMAC_REG->ch_en[ch / 32]) | |
332 | +#define IDMAC_CHA_PRI(ch) (&IDMAC_REG->ch_pri[ch / 32]) | |
333 | + | |
334 | +#define DI_REG(di) ((struct ipu_di *)(IPU_CTRL_BASE_ADDR + \ | |
335 | + ((di == 1) ? IPU_DI1_REG_BASE : \ | |
336 | + IPU_DI0_REG_BASE))) | |
337 | +#define DI_GENERAL(di) (&DI_REG(di)->general) | |
338 | +#define DI_BS_CLKGEN0(di) (&DI_REG(di)->bs_clkgen0) | |
339 | +#define DI_BS_CLKGEN1(di) (&DI_REG(di)->bs_clkgen1) | |
340 | + | |
341 | +#define DI_SW_GEN0(di, gen) (&DI_REG(di)->sw_gen0[gen - 1]) | |
342 | +#define DI_SW_GEN1(di, gen) (&DI_REG(di)->sw_gen1[gen - 1]) | |
343 | +#define DI_STP_REP(di, gen) (&DI_REG(di)->stp_rep[(gen - 1) / 2]) | |
344 | +#define DI_SYNC_AS_GEN(di) (&DI_REG(di)->sync_as) | |
345 | +#define DI_DW_GEN(di, gen) (&DI_REG(di)->dw_gen[gen]) | |
346 | +#define DI_DW_SET(di, gen, set) (&DI_REG(di)->dw_set[gen + 12 * set]) | |
347 | +#define DI_POL(di) (&DI_REG(di)->pol) | |
348 | +#define DI_SCR_CONF(di) (&DI_REG(di)->scr_conf) | |
349 | + | |
350 | +#define DMFC_REG ((struct ipu_dmfc *)(IPU_CTRL_BASE_ADDR + \ | |
351 | + IPU_DMFC_REG_BASE)) | |
352 | +#define DMFC_WR_CHAN (&DMFC_REG->wr_chan) | |
353 | +#define DMFC_WR_CHAN_DEF (&DMFC_REG->wr_chan_def) | |
354 | +#define DMFC_DP_CHAN (&DMFC_REG->dp_chan) | |
355 | +#define DMFC_DP_CHAN_DEF (&DMFC_REG->dp_chan_def) | |
356 | +#define DMFC_GENERAL1 (&DMFC_REG->general[0]) | |
357 | +#define DMFC_IC_CTRL (&DMFC_REG->ic_ctrl) | |
358 | + | |
359 | + | |
360 | +#define DC_REG ((struct ipu_dc *)(IPU_CTRL_BASE_ADDR + \ | |
361 | + IPU_DC_REG_BASE)) | |
362 | +#define DC_MAP_CONF_PTR(n) (&DC_REG->dc_map_ptr[n / 2]) | |
363 | +#define DC_MAP_CONF_VAL(n) (&DC_REG->dc_map_val[n / 2]) | |
364 | + | |
365 | + | |
366 | +static inline struct ipu_dc_ch *dc_ch_offset(int ch) | |
367 | +{ | |
368 | + switch (ch) { | |
369 | + case 0: | |
370 | + case 1: | |
371 | + case 2: | |
372 | + return &DC_REG->dc_ch0_1_2[ch]; | |
373 | + case 5: | |
374 | + case 6: | |
375 | + return &DC_REG->dc_ch5_6[ch - 5]; | |
376 | + case 8: | |
377 | + return &DC_REG->dc_ch8; | |
378 | + case 9: | |
379 | + return &DC_REG->dc_ch9; | |
380 | + default: | |
381 | + printf("%s: invalid channel %d\n", __func__, ch); | |
382 | + return NULL; | |
383 | + } | |
384 | + | |
385 | +} | |
386 | + | |
387 | +#define DC_RL_CH(ch, evt) (&dc_ch_offset(ch)->rl[evt / 2]) | |
388 | + | |
389 | +#define DC_WR_CH_CONF(ch) (&dc_ch_offset(ch)->wr_ch_conf) | |
390 | +#define DC_WR_CH_ADDR(ch) (&dc_ch_offset(ch)->wr_ch_addr) | |
391 | + | |
392 | +#define DC_WR_CH_CONF_1 DC_WR_CH_CONF(1) | |
393 | +#define DC_WR_CH_CONF_5 DC_WR_CH_CONF(5) | |
394 | + | |
395 | +#define DC_GEN (&DC_REG->gen) | |
396 | +#define DC_DISP_CONF2(disp) (&DC_REG->disp_conf2[disp]) | |
397 | +#define DC_STAT (&DC_REG->stat) | |
398 | + | |
399 | +#define DP_SYNC 0 | |
400 | +#define DP_ASYNC0 0x60 | |
401 | +#define DP_ASYNC1 0xBC | |
402 | + | |
403 | +#define DP_REG ((struct ipu_dp *)(IPU_CTRL_BASE_ADDR + \ | |
404 | + IPU_DP_REG_BASE)) | |
405 | +#define DP_COM_CONF(flow) (&DP_REG->com_conf_sync) | |
406 | +#define DP_GRAPH_WIND_CTRL(flow) (&DP_REG->graph_wind_ctrl_sync) | |
407 | +#define DP_CSC_A_0(flow) (&DP_REG->csca_sync[0]) | |
408 | +#define DP_CSC_A_1(flow) (&DP_REG->csca_sync[1]) | |
409 | +#define DP_CSC_A_2(flow) (&DP_REG->csca_sync[2]) | |
410 | +#define DP_CSC_A_3(flow) (&DP_REG->csca_sync[3]) | |
411 | + | |
412 | +#define DP_CSC_0(flow) (&DP_REG->csc_sync[0]) | |
413 | +#define DP_CSC_1(flow) (&DP_REG->csc_sync[1]) | |
414 | + | |
415 | +/* DC template opcodes */ | |
416 | +#define WROD(lf) (0x18 | (lf << 1)) | |
417 | + | |
418 | +#endif |