From 85a20d8027f947bb65fc346c8704b8b0cb67cc9d Mon Sep 17 00:00:00 2001 From: Troy Kisky <troy.kisky@boundarydevices.com> Date: Mon, 6 Jul 2015 12:47:36 -0700 Subject: [PATCH] ipu_disp: add YUV modes --- drivers/video/ipu.h | 4 +- drivers/video/ipu_common.c | 9 ++- drivers/video/ipu_disp.c | 130 ++++++++++++++++++++++++++++++------- drivers/video/ipu_regs.h | 14 +++- 4 files changed, 128 insertions(+), 29 deletions(-) diff --git a/drivers/video/ipu.h b/drivers/video/ipu.h index 1e02c7ab6d5..ea4555264b5 100644 --- a/drivers/video/ipu.h +++ b/drivers/video/ipu.h @@ -151,6 +151,8 @@ typedef union { struct { uint32_t di; unsigned char interlaced; + uint32_t in_pixel_fmt; + uint32_t out_pixel_fmt; } mem_dc_sync; struct { uint32_t temp; @@ -257,7 +259,7 @@ bool ipu_clk_enabled(void); void ipu_dmfc_init(int dmfc_type, int first); void ipu_init_dc_mappings(void); void ipu_dmfc_set_wait4eot(int dma_chan, int width); -void ipu_dc_init(int dc_chan, int di, unsigned char interlaced); +void ipu_dc_init(int dc_chan, int di, unsigned char interlaced, uint32_t pixel_fmt); void ipu_dc_uninit(int dc_chan); void ipu_dp_dc_enable(ipu_channel_t channel); int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, diff --git a/drivers/video/ipu_common.c b/drivers/video/ipu_common.c index cbe1984e4f7..5cc7683fcbd 100644 --- a/drivers/video/ipu_common.c +++ b/drivers/video/ipu_common.c @@ -603,7 +603,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) g_dc_di_assignment[1] = params->mem_dc_sync.di; ipu_dc_init(1, params->mem_dc_sync.di, - params->mem_dc_sync.interlaced); + params->mem_dc_sync.interlaced, + params->mem_dc_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dc_sync.di]++; ipu_dc_use_count++; ipu_dmfc_use_count++; @@ -618,7 +619,8 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); ipu_dc_init(5, params->mem_dp_bg_sync.di, - params->mem_dp_bg_sync.interlaced); + params->mem_dp_bg_sync.interlaced, + params->mem_dp_bg_sync.out_pixel_fmt); ipu_di_use_count[params->mem_dp_bg_sync.di]++; ipu_dc_use_count++; ipu_dp_use_count++; @@ -899,7 +901,7 @@ static void ipu_ch_param_init(int ch, case IPU_PIX_FMT_YUYV: ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8); /* pix format */ - ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ + ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ break; case IPU_PIX_FMT_YUV420P2: case IPU_PIX_FMT_YUV420P: @@ -1016,6 +1018,7 @@ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t reg; uint32_t dma_chan; + printf("%s: chan=0x%08x, pixel_fmt=%x\n", __func__, channel, pixel_fmt); dma_chan = channel_2_dma(channel, type); if (!idma_is_valid(dma_chan)) return -EINVAL; diff --git a/drivers/video/ipu_disp.c b/drivers/video/ipu_disp.c index ead8c479358..e154fe45a33 100644 --- a/drivers/video/ipu_disp.c +++ b/drivers/video/ipu_disp.c @@ -239,6 +239,24 @@ static void ipu_di_sync_config(int di, int wave_gen, __raw_writel(reg, DI_STP_REP(di, wave_gen)); } +static void ipu_dc_map_link(int current_map, + int base_map_0, int buf_num_0, + int base_map_1, int buf_num_1, + int base_map_2, int buf_num_2) +{ + int ptr_0 = base_map_0 * 3 + buf_num_0; + int ptr_1 = base_map_1 * 3 + buf_num_1; + int ptr_2 = base_map_2 * 3 + buf_num_2; + int ptr; + u32 reg; + ptr = (ptr_2 << 10) + (ptr_1 << 5) + ptr_0; + + reg = __raw_readl(DC_MAP_CONF_PTR(current_map)); + reg &= ~(0x1F << ((16 * (current_map & 0x1)))); + reg |= ptr << ((16 * (current_map & 0x1))); + __raw_writel(reg, DC_MAP_CONF_PTR(current_map)); +} + static void ipu_dc_map_config(int map, int byte_num, int offset, int mask) { int ptr = map * 3 + byte_num; @@ -284,11 +302,32 @@ static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, static void ipu_dc_link_event(int chan, int event, int addr, int priority) { u32 reg; - - reg = __raw_readl(DC_RL_CH(chan, event)); - reg &= ~(0xFFFF << (16 * (event & 0x1))); - reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); - __raw_writel(reg, DC_RL_CH(chan, event)); + u32 address_shift; + if (event < DC_EVEN_UGDE0) { + reg = __raw_readl(DC_RL_CH(chan, event)); + reg &= ~(0xFFFF << (16 * (event & 0x1))); + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); + __raw_writel(reg, DC_RL_CH(chan, event)); + } else { + reg = __raw_readl(DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + if ((event - DC_EVEN_UGDE0) & 0x1) { + /* DC_ODD_UGDEx */ + reg &= ~(0x2FF << 16); + reg |= (addr << 16); + reg |= priority ? (2 << 24) : 0x0; + } else { + /* DC_EVEN_UGDEx */ + reg &= ~0xFC00FFFF; + if (priority) + chan = (chan >> 1) + + ((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3)); + else + chan = 0x7; + address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8; + reg |= (addr << address_shift) | (priority << 3) | chan; + } + __raw_writel(reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2)); + } } /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; @@ -427,6 +466,7 @@ int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, int partial = 0; uint32_t reg; + printf("%s: chan=0x%08x, infmt %x, outfmt=%x\n", __func__, channel, in_pixel_fmt, out_pixel_fmt); if (channel == MEM_FG_SYNC) { dp = DP_SYNC; partial = 1; @@ -443,6 +483,7 @@ int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, in_fmt = format_to_colorspace(in_pixel_fmt); out_fmt = format_to_colorspace(out_pixel_fmt); + printf("%s: %s to %s\n", __func__, (in_fmt == RGB) ? "rgb" : "yuv", (out_fmt == RGB) ? "rgb" : "yuv"); if (partial) { if (in_fmt == RGB) { if (out_fmt == RGB) @@ -532,26 +573,35 @@ void ipu_dp_uninit(ipu_channel_t channel) ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0); } -void ipu_dc_init(int dc_chan, int di, unsigned char interlaced) +void ipu_dc_init(int dc_chan, int di, unsigned char interlaced, uint32_t pixel_fmt) { u32 reg = 0; + printf("%s: fmt %x, chan=%d, di=%d, interlaced=%d\n", __func__, pixel_fmt, dc_chan, di, interlaced); if ((dc_chan == 1) || (dc_chan == 5)) { if (interlaced) { ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3); ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2); ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1); } else { - if (di) { - ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); - ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); - ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, - 4, 1); - } else { - ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); - ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); - ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, - 7, 1); + int mc1 = di ? 2 : 5; + int mc2 = di ? 8 : 10; + int dc = di ? DC_EVEN_UGDE1 : DC_EVEN_UGDE0; +#define MC_WORD_DI1_NL 2 +#define MC_WORD_DI1_EOL 3 +#define MC_WORD_DI1_NEW_DATA 4 +#define MC_WORD_DI0_NL 5 +#define MC_WORD_DI0_EOL 6 +#define MC_WORD_DI0_NEW_DATA 7 + ipu_dc_link_event(dc_chan, DC_EVT_NL, mc1++, 3); + ipu_dc_link_event(dc_chan, DC_EVT_EOL, mc1++, 2); + ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, mc1, 1); + + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY)) { + printf("%s: link %d %d\n", __func__, dc, mc2); + ipu_dc_link_event(dc_chan, dc++, mc2++, 5); + ipu_dc_link_event(dc_chan, dc, mc2, 5); } } ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); @@ -771,6 +821,28 @@ void ipu_init_dc_mappings(void) ipu_dc_map_config(4, 0, 5, 0xFC); ipu_dc_map_config(4, 1, 13, 0xFC); ipu_dc_map_config(4, 2, 21, 0xFC); + + /* IPU_PIX_FMT_VYUY 16bit width */ + ipu_dc_map_clear(5); + ipu_dc_map_config(5, 0, 7, 0xFF); + ipu_dc_map_config(5, 1, 0, 0x0); + ipu_dc_map_config(5, 2, 15, 0xFF); + ipu_dc_map_clear(6); + ipu_dc_map_config(6, 0, 0, 0x0); + ipu_dc_map_config(6, 1, 7, 0xFF); + ipu_dc_map_config(6, 2, 15, 0xFF); + + /* IPU_PIX_FMT_UYVY 16bit width */ + ipu_dc_map_clear(7); + ipu_dc_map_link(7, 6, 0, 6, 1, 6, 2); + ipu_dc_map_clear(8); + ipu_dc_map_link(8, 5, 0, 5, 1, 5, 2); + + /* IPU_PIX_FMT_YUYV 16bit width */ + ipu_dc_map_clear(9); + ipu_dc_map_link(9, 5, 1, 5, 2, 5, 0); + ipu_dc_map_clear(10); + ipu_dc_map_link(10, 5, 2, 5, 1, 5, 0); } static int ipu_pixfmt_to_map(uint32_t fmt) @@ -787,6 +859,10 @@ static int ipu_pixfmt_to_map(uint32_t fmt) return 3; case IPU_PIX_FMT_LVDS666: return 4; + case IPU_PIX_FMT_UYVY: + return 8; + case IPU_PIX_FMT_YUYV: + return 10; } return -1; @@ -1077,6 +1153,8 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, di_gen |= DI_GEN_POLARITY_5; di_gen |= DI_GEN_POLARITY_8; } else { + int mc1, mc2; + /* Setup internal HSYNC waveform */ ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, @@ -1124,15 +1202,19 @@ int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, __raw_writel(0, DI_STP_REP9(disp)); /* Init template microcode */ - if (disp) { - ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); - ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); - ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); - } else { - ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); - ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); - ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); + mc1 = disp ? 2 : 5; + mc2 = disp ? 8 : 10; + if ((pixel_fmt == IPU_PIX_FMT_YUYV) || + (pixel_fmt == IPU_PIX_FMT_UYVY)) { + printf("%s: map %d %d, %d %d\n", __func__, map-1, mc2, map, mc2+1); + ipu_dc_write_tmpl(mc2++, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5); + ipu_dc_write_tmpl(mc2, WROD(0), 0, map, SYNC_WAVE, 0, 5); + /* configure user events according to DISP NUM */ + __raw_writel((width - 1), DC_UGDE_3(disp)); } + ipu_dc_write_tmpl(mc1++, WROD(0), 0, map, SYNC_WAVE, 8, 5); + ipu_dc_write_tmpl(mc1++, WROD(0), 0, map, SYNC_WAVE, 4, 5); + ipu_dc_write_tmpl(mc1, WROD(0), 0, map, SYNC_WAVE, 0, 5); if (sig.Hsync_pol) di_gen |= DI_GEN_POLARITY_2; diff --git a/drivers/video/ipu_regs.h b/drivers/video/ipu_regs.h index deb44002d75..e688aa0d931 100644 --- a/drivers/video/ipu_regs.h +++ b/drivers/video/ipu_regs.h @@ -73,6 +73,14 @@ extern u32 *ipu_dc_tmpl_reg; #define DC_EVT_NEW_CHAN_R_1 9 #define DC_EVT_NEW_DATA_R_0 10 #define DC_EVT_NEW_DATA_R_1 11 +#define DC_EVEN_UGDE0 12 +#define DC_ODD_UGDE0 13 +#define DC_EVEN_UGDE1 14 +#define DC_ODD_UGDE1 15 +#define DC_EVEN_UGDE2 16 +#define DC_ODD_UGDE2 17 +#define DC_EVEN_UGDE3 18 +#define DC_ODD_UGDE3 19 /* Software reset for ipu */ #define SW_IPU_RST 8 @@ -275,7 +283,7 @@ struct ipu_dc { u32 di1_conf[2]; u32 dc_map_ptr[15]; u32 dc_map_val[12]; - u32 udge[16]; + u32 ugde[16]; u32 lla[2]; u32 r_lla[2]; u32 wr_ch_addr_5_alt; @@ -392,6 +400,10 @@ static inline struct ipu_dc_ch *dc_ch_offset(int ch) #define DC_GEN (&DC_REG->gen) #define DC_DISP_CONF2(disp) (&DC_REG->disp_conf2[disp]) #define DC_STAT (&DC_REG->stat) +#define DC_UGDE_0(evt) (&DC_REG->ugde[0 + (4 * (evt))]) +#define DC_UGDE_1(evt) (&DC_REG->ugde[1 + (4 * (evt))]) +#define DC_UGDE_2(evt) (&DC_REG->ugde[2 + (4 * (evt))]) +#define DC_UGDE_3(evt) (&DC_REG->ugde[3 + (4 * (evt))]) #define DP_SYNC 0 #define DP_ASYNC0 0x60 -- GitLab