Commit 575001e40c9d10e63f2924649098e7c07d3985c7

Authored by Stefano Babic
Committed by Anatolij Gustschin
1 parent bf90ecd3c3

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__ */
  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(&params, 0, sizeof(params));
  756 +
  757 + ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
  758 +
  759 + if ((ch == 8) || (ch == 9) || (ch == 10)) {
  760 + ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
  761 + ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
  762 + } else {
  763 + ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
  764 + ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
  765 + }
  766 +
  767 + ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
  768 + ipu_ch_param_set_field(&params, 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(&params, 0, 107, 3, 5); /* bits/pixel */
  774 + ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
  775 + ipu_ch_param_set_field(&params, 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(&params, 0, 107, 3, 3); /* bits/pixel */
  783 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  784 + ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
  785 +
  786 + ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
  787 + break;
  788 + case IPU_PIX_FMT_BGR24:
  789 + ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
  790 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  791 + ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
  792 +
  793 + ipu_ch_params_set_packing(&params, 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(&params, 0, 107, 3, 1); /* bits/pixel */
  798 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  799 + ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
  800 +
  801 + ipu_ch_params_set_packing(&params, 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(&params, 0, 107, 3, 0); /* bits/pixel */
  806 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  807 + ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
  808 +
  809 + ipu_ch_params_set_packing(&params, 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(&params, 0, 107, 3, 0); /* bits/pixel */
  814 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  815 + ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
  816 +
  817 + ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
  818 + break;
  819 + case IPU_PIX_FMT_ABGR32:
  820 + ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
  821 + ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
  822 +
  823 + ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
  824 + break;
  825 + case IPU_PIX_FMT_UYVY:
  826 + ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
  827 + ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
  828 + ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
  829 + break;
  830 + case IPU_PIX_FMT_YUYV:
  831 + ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
  832 + ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
  833 + ipu_ch_param_set_field(&params, 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(&params, 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(&params, 1, 78, 7, 15);
  847 + uv_stride = uv_stride*2;
  848 + } else {
  849 + ipu_ch_param_set_field(&params, 1, 78, 7, 31);
  850 + }
  851 + break;
  852 + case IPU_PIX_FMT_YVU422P:
  853 + /* BPP & pixel format */
  854 + ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
  855 + ipu_ch_param_set_field(&params, 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(&params, 1, 85, 4, 1); /* pix format */
  866 + ipu_ch_param_set_field(&params, 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(&params, 1, 85, 4, 4); /* pix format */
  877 + ipu_ch_param_set_field(&params, 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(&params, 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(&params, 0, 46, 22, u_offset / 8);
  903 + ipu_ch_param_set_field(&params, 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), &params, 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