| /* |
| * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved. |
| */ |
| |
| /* |
| * The code contained herein is licensed under the GNU General Public |
| * License. You may obtain a copy of the GNU General Public License |
| * Version 2 or later at the following locations: |
| * |
| * http://www.opensource.org/licenses/gpl-license.html |
| * http://www.gnu.org/copyleft/gpl.html |
| */ |
| #ifndef __INCLUDE_IPU_PARAM_MEM_H__ |
| #define __INCLUDE_IPU_PARAM_MEM_H__ |
| |
| #include <linux/bitrev.h> |
| #include <linux/types.h> |
| |
| #include "ipu_prv.h" |
| |
| extern u32 *ipu_cpmem_base; |
| |
| struct ipu_ch_param_word { |
| uint32_t data[5]; |
| uint32_t res[3]; |
| }; |
| |
| struct ipu_ch_param { |
| struct ipu_ch_param_word word[2]; |
| }; |
| |
| #define ipu_ch_param_addr(ipu, ch) \ |
| (((struct ipu_ch_param *)(ipu)->cpmem_base) + (ch)) |
| |
| #define _param_word(base, w) \ |
| (((struct ipu_ch_param *)(base))->word[(w)].data) |
| |
| #define ipu_ch_param_set_field(base, w, bit, size, v) { \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| _param_word((base), (w))[i] |= (v) << off; \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| _param_word((base), (w))[i + 1] |= \ |
| (v) >> (off ? (32 - off) : 0); \ |
| } \ |
| } |
| |
| #define ipu_ch_param_set_field_io(base, w, bit, size, v) { \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| unsigned reg_offset; \ |
| u32 temp; \ |
| reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \ |
| reg_offset += i; \ |
| temp = readl((u32 *)(base) + reg_offset); \ |
| temp |= (v) << off; \ |
| writel(temp, (u32 *)(base) + reg_offset); \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| reg_offset++; \ |
| temp = readl((u32 *)(base) + reg_offset); \ |
| temp |= (v) >> (off ? (32 - off) : 0); \ |
| writel(temp, (u32 *)(base) + reg_offset); \ |
| } \ |
| } |
| |
| #define ipu_ch_param_mod_field(base, w, bit, size, v) { \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| u32 mask = (1UL << (size)) - 1; \ |
| u32 temp = _param_word((base), (w))[i]; \ |
| temp &= ~(mask << off); \ |
| _param_word((base), (w))[i] = temp | (v) << off; \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| temp = _param_word((base), (w))[i + 1]; \ |
| temp &= ~(mask >> (32 - off)); \ |
| _param_word((base), (w))[i + 1] = \ |
| temp | ((v) >> (off ? (32 - off) : 0)); \ |
| } \ |
| } |
| |
| #define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| u32 mask = (1UL << (size)) - 1; \ |
| unsigned reg_offset; \ |
| u32 temp; \ |
| reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \ |
| reg_offset += i; \ |
| temp = readl((u32 *)(base) + reg_offset); \ |
| temp &= ~(mask << off); \ |
| temp |= (v) << off; \ |
| writel(temp, (u32 *)(base) + reg_offset); \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| reg_offset++; \ |
| temp = readl((u32 *)(base) + reg_offset); \ |
| temp &= ~(mask >> (32 - off)); \ |
| temp |= ((v) >> (off ? (32 - off) : 0)); \ |
| writel(temp, (u32 *)(base) + reg_offset); \ |
| } \ |
| } |
| |
| #define ipu_ch_param_read_field(base, w, bit, size) ({ \ |
| u32 temp2; \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| u32 mask = (1UL << (size)) - 1; \ |
| u32 temp1 = _param_word((base), (w))[i]; \ |
| temp1 = mask & (temp1 >> off); \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| temp2 = _param_word((base), (w))[i + 1]; \ |
| temp2 &= mask >> (off ? (32 - off) : 0); \ |
| temp1 |= temp2 << (off ? (32 - off) : 0); \ |
| } \ |
| temp1; \ |
| }) |
| |
| #define ipu_ch_param_read_field_io(base, w, bit, size) ({ \ |
| u32 temp1, temp2; \ |
| int i = (bit) / 32; \ |
| int off = (bit) % 32; \ |
| u32 mask = (1UL << (size)) - 1; \ |
| unsigned reg_offset; \ |
| reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \ |
| reg_offset += i; \ |
| temp1 = readl((u32 *)(base) + reg_offset); \ |
| temp1 = mask & (temp1 >> off); \ |
| if (((bit)+(size)-1)/32 > i) { \ |
| reg_offset++; \ |
| temp2 = readl((u32 *)(base) + reg_offset); \ |
| temp2 &= mask >> (off ? (32 - off) : 0); \ |
| temp1 |= temp2 << (off ? (32 - off) : 0); \ |
| } \ |
| temp1; \ |
| }) |
| |
| static inline int __ipu_ch_get_third_buf_cpmem_num(int ch) |
| { |
| switch (ch) { |
| case 8: |
| return 64; |
| case 9: |
| return 65; |
| case 10: |
| return 66; |
| case 13: |
| return 67; |
| case 21: |
| return 68; |
| case 23: |
| return 69; |
| case 27: |
| return 70; |
| case 28: |
| return 71; |
| default: |
| return -EINVAL; |
| } |
| return 0; |
| } |
| |
| static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p, |
| int red_width, int red_offset, |
| int green_width, int green_offset, |
| int blue_width, int blue_offset, |
| int alpha_width, int alpha_offset) |
| { |
| /* Setup red width and offset */ |
| ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1); |
| ipu_ch_param_set_field(p, 1, 128, 5, red_offset); |
| /* Setup green width and offset */ |
| ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1); |
| ipu_ch_param_set_field(p, 1, 133, 5, green_offset); |
| /* Setup blue width and offset */ |
| ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1); |
| ipu_ch_param_set_field(p, 1, 138, 5, blue_offset); |
| /* Setup alpha width and offset */ |
| ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1); |
| ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset); |
| } |
| |
| static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch) |
| { |
| struct ipu_ch_param *p = ipu_ch_param_addr(ipu, ch); |
| dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch, |
| p->word[0].data[0], p->word[0].data[1], p->word[0].data[2], |
| p->word[0].data[3], p->word[0].data[4]); |
| dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch, |
| p->word[1].data[0], p->word[1].data[1], p->word[1].data[2], |
| p->word[1].data[3], p->word[1].data[4]); |
| dev_dbg(ipu->dev, "PFS 0x%x, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4)); |
| dev_dbg(ipu->dev, "BPP 0x%x, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3)); |
| dev_dbg(ipu->dev, "NPB 0x%x\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7)); |
| |
| dev_dbg(ipu->dev, "FW %d, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13)); |
| dev_dbg(ipu->dev, "FH %d, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12)); |
| dev_dbg(ipu->dev, "EBA0 0x%x\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3); |
| dev_dbg(ipu->dev, "EBA1 0x%x\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3); |
| dev_dbg(ipu->dev, "Stride %d\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14)); |
| dev_dbg(ipu->dev, "scan_order %d\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1)); |
| dev_dbg(ipu->dev, "uv_stride %d\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14)); |
| dev_dbg(ipu->dev, "u_offset 0x%x\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3); |
| dev_dbg(ipu->dev, "v_offset 0x%x\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3); |
| |
| dev_dbg(ipu->dev, "Width0 %d+1, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3)); |
| dev_dbg(ipu->dev, "Width1 %d+1, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3)); |
| dev_dbg(ipu->dev, "Width2 %d+1, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3)); |
| dev_dbg(ipu->dev, "Width3 %d+1, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3)); |
| dev_dbg(ipu->dev, "Offset0 %d, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5)); |
| dev_dbg(ipu->dev, "Offset1 %d, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5)); |
| dev_dbg(ipu->dev, "Offset2 %d, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5)); |
| dev_dbg(ipu->dev, "Offset3 %d\n", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5)); |
| } |
| |
| static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params) |
| { |
| int i, w; |
| void *addr = ipu_ch_param_addr(ipu, ch); |
| |
| /* 2 words, 5 valid data */ |
| for (w = 0; w < 2; w++) { |
| for (i = 0; i < 5; i++) { |
| writel(params->word[w].data[i], addr); |
| addr += 4; |
| } |
| addr += 12; |
| } |
| } |
| |
| static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch, |
| uint32_t pixel_fmt, uint32_t width, |
| uint32_t height, uint32_t stride, |
| uint32_t u, uint32_t v, |
| uint32_t uv_stride, dma_addr_t addr0, |
| dma_addr_t addr1, dma_addr_t addr2) |
| { |
| uint32_t u_offset = 0; |
| uint32_t v_offset = 0; |
| uint32_t bs = 0; |
| int32_t sub_ch = 0; |
| struct ipu_ch_param params; |
| |
| memset(¶ms, 0, sizeof(params)); |
| |
| ipu_ch_param_set_field(¶ms, 0, 125, 13, width - 1); |
| |
| if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) { |
| ipu_ch_param_set_field(¶ms, 0, 138, 12, (height / 2) - 1); |
| ipu_ch_param_set_field(¶ms, 1, 102, 14, (stride * 2) - 1); |
| } else { |
| /* note: for vdoa+vdi- ch8/9/10, always use band mode */ |
| ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1); |
| ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1); |
| } |
| |
| /* EBA is 8-byte aligned */ |
| ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3); |
| ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3); |
| if (addr0%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's EBA0 is not 8-byte aligned\n", ch); |
| if (addr1%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's EBA1 is not 8-byte aligned\n", ch); |
| |
| switch (pixel_fmt) { |
| case IPU_PIX_FMT_GENERIC: |
| /*Represents 8-bit Generic data */ |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 5); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); /* burst size */ |
| |
| break; |
| case IPU_PIX_FMT_GENERIC_16: |
| /* Represents 16-bit generic data */ |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| break; |
| case IPU_PIX_FMT_GENERIC_32: |
| /*Represents 32-bit Generic data */ |
| break; |
| case IPU_PIX_FMT_RGB565: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16); |
| break; |
| case IPU_PIX_FMT_BGRA4444: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 4, 4, 4, 8, 4, 12, 4, 0); |
| break; |
| case IPU_PIX_FMT_BGRA5551: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 5, 1, 5, 6, 5, 11, 1, 0); |
| break; |
| case IPU_PIX_FMT_BGR24: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); |
| break; |
| case IPU_PIX_FMT_RGB24: |
| case IPU_PIX_FMT_YUV444: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24); |
| break; |
| case IPU_PIX_FMT_VYU444: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 8, 8, 0, 8, 16, 8, 24); |
| break; |
| case IPU_PIX_FMT_AYUV: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0); |
| break; |
| case IPU_PIX_FMT_BGRA32: |
| case IPU_PIX_FMT_BGR32: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0); |
| break; |
| case IPU_PIX_FMT_RGBA32: |
| case IPU_PIX_FMT_RGB32: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 24, 8, 16, 8, 8, 8, 0); |
| break; |
| case IPU_PIX_FMT_ABGR32: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| |
| _ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24); |
| break; |
| case IPU_PIX_FMT_UYVY: |
| ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */ |
| if ((ch == 8) || (ch == 9) || (ch == 10)) { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| } else { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| } |
| break; |
| 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 */ |
| if ((ch == 8) || (ch == 9) || (ch == 10)) { |
| if (ipu->vdoa_en) { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); |
| } else { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); |
| } |
| } else { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| } |
| break; |
| case IPU_PIX_FMT_YUV420P2: |
| case IPU_PIX_FMT_YUV420P: |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 2); /* pix format */ |
| |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| u_offset = stride * height; |
| v_offset = u_offset + (uv_stride * height / 2); |
| if ((ch == 8) || (ch == 9) || (ch == 10)) { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| uv_stride = uv_stride*2; |
| } else { |
| if (_ipu_is_smfc_chan(ch) && |
| ipu->smfc_idmac_12bit_3planar_bs_fixup) |
| bs = 15; |
| else |
| bs = 31; |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, bs); /* burst size */ |
| } |
| break; |
| case IPU_PIX_FMT_YVU420P: |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 2); /* pix format */ |
| |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| v_offset = stride * height; |
| u_offset = v_offset + (uv_stride * height / 2); |
| if ((ch == 8) || (ch == 9) || (ch == 10)) { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */ |
| uv_stride = uv_stride*2; |
| } else { |
| if (_ipu_is_smfc_chan(ch) && |
| ipu->smfc_idmac_12bit_3planar_bs_fixup) |
| bs = 15; |
| else |
| bs = 31; |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, bs); /* burst size */ |
| } |
| break; |
| case IPU_PIX_FMT_YVU422P: |
| /* BPP & pixel format */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| v_offset = (v == 0) ? stride * height : v; |
| u_offset = (u == 0) ? v_offset + v_offset / 2 : u; |
| break; |
| case IPU_PIX_FMT_YUV422P: |
| /* BPP & pixel format */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| u_offset = (u == 0) ? stride * height : u; |
| v_offset = (v == 0) ? u_offset + u_offset / 2 : v; |
| break; |
| case IPU_PIX_FMT_YUV444P: |
| /* BPP & pixel format */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 0); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| uv_stride = stride; |
| u_offset = (u == 0) ? stride * height : u; |
| v_offset = (v == 0) ? u_offset * 2 : v; |
| break; |
| case IPU_PIX_FMT_NV16: |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| uv_stride = stride; |
| u_offset = (u == 0) ? stride * height : u; |
| break; |
| case IPU_PIX_FMT_NV12: |
| /* BPP & pixel format */ |
| ipu_ch_param_set_field(¶ms, 1, 85, 4, 4); /* pix format */ |
| uv_stride = stride; |
| u_offset = (u == 0) ? stride * height : u; |
| if ((ch == 8) || (ch == 9) || (ch == 10)) { |
| if (ipu->vdoa_en) { |
| /* one field buffer, memory width 64bits */ |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); |
| } else { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); |
| /* top/bottom field in one buffer*/ |
| uv_stride = uv_stride*2; |
| } |
| } else { |
| ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */ |
| } |
| break; |
| default: |
| dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n"); |
| break; |
| } |
| /*set burst size to 16*/ |
| |
| |
| if (uv_stride) |
| ipu_ch_param_set_field(¶ms, 1, 128, 14, uv_stride - 1); |
| |
| /* Get the uv offset from user when need cropping */ |
| if (u || v) { |
| u_offset = u; |
| v_offset = v; |
| } |
| |
| /* UBO and VBO are 22-bit and 8-byte aligned */ |
| if (u_offset/8 > 0x3fffff) |
| dev_warn(ipu->dev, |
| "IDMAC%d's U offset exceeds IPU limitation\n", ch); |
| if (v_offset/8 > 0x3fffff) |
| dev_warn(ipu->dev, |
| "IDMAC%d's V offset exceeds IPU limitation\n", ch); |
| if (u_offset%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's U offset is not 8-byte aligned\n", ch); |
| if (v_offset%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's V offset is not 8-byte aligned\n", ch); |
| |
| ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8); |
| ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8); |
| |
| dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch)); |
| fill_cpmem(ipu, ch, ¶ms); |
| if (addr2) { |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| |
| ipu_ch_param_set_field(¶ms, 1, 0, 29, addr2 >> 3); |
| ipu_ch_param_set_field(¶ms, 1, 29, 29, 0); |
| if (addr2%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's sub-CPMEM entry%d EBA0 is not " |
| "8-byte aligned\n", ch, sub_ch); |
| |
| dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch, |
| ipu_ch_param_addr(ipu, sub_ch)); |
| fill_cpmem(ipu, sub_ch, ¶ms); |
| } |
| }; |
| |
| static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu, |
| uint32_t ch, |
| uint16_t burst_pixels) |
| { |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7, |
| burst_pixels - 1); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7, |
| burst_pixels - 1); |
| }; |
| |
| static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch) |
| { |
| return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1; |
| }; |
| |
| static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch) |
| { |
| return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3); |
| }; |
| |
| static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch, |
| int bufNum, dma_addr_t phyaddr) |
| { |
| if (bufNum == 2) { |
| ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (ch <= 0) |
| return; |
| bufNum = 0; |
| } |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29, |
| phyaddr / 8); |
| }; |
| |
| static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch, |
| ipu_rotate_mode_t rot) |
| { |
| u32 temp_rot = bitrev8(rot) >> 5; |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot); |
| }; |
| |
| static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch) |
| { |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1); |
| }; |
| |
| static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu, |
| uint32_t ch, |
| bool option) |
| { |
| int32_t sub_ch = 0; |
| |
| if (option) { |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1); |
| } else { |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0); |
| } |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| |
| if (option) { |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1); |
| } else { |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0); |
| } |
| }; |
| |
| static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch) |
| { |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1); |
| }; |
| |
| static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch) |
| { |
| int alp_mem_idx; |
| int32_t sub_ch = 0; |
| |
| switch (ch) { |
| case 14: /* PRP graphic */ |
| alp_mem_idx = 0; |
| break; |
| case 15: /* PP graphic */ |
| alp_mem_idx = 1; |
| break; |
| case 23: /* DP BG SYNC graphic */ |
| alp_mem_idx = 4; |
| break; |
| case 27: /* DP FG SYNC graphic */ |
| alp_mem_idx = 2; |
| break; |
| default: |
| dev_err(ipu->dev, "unsupported correlative channel of local " |
| "alpha channel\n"); |
| return; |
| } |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx); |
| }; |
| |
| static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch) |
| { |
| u32 stride; |
| int32_t sub_ch = 0; |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1); |
| if (sub_ch > 0) |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1); |
| stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1; |
| /* ILO is 20-bit and 8-byte aligned */ |
| if (stride/8 > 0xfffff) |
| dev_warn(ipu->dev, |
| "IDMAC%d's ILO exceeds IPU limitation\n", ch); |
| if (stride%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's ILO is not 8-byte aligned\n", ch); |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8); |
| if (sub_ch > 0) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20, |
| stride / 8); |
| stride *= 2; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1); |
| if (sub_ch > 0) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14, |
| stride - 1); |
| }; |
| |
| static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id) |
| { |
| int32_t sub_ch = 0; |
| |
| id %= 4; |
| |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id); |
| }; |
| |
| static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch) |
| { |
| return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2); |
| } |
| |
| static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt, |
| uint32_t width, |
| uint32_t height, |
| uint32_t stride, |
| uint32_t u, |
| uint32_t v, |
| uint32_t uv_stride, |
| uint32_t vertical_offset, |
| uint32_t horizontal_offset, |
| uint32_t *u_offset, |
| uint32_t *v_offset) |
| { |
| uint32_t u_fix = 0; |
| uint32_t v_fix = 0; |
| |
| switch (pixel_fmt) { |
| case IPU_PIX_FMT_GENERIC: |
| case IPU_PIX_FMT_GENERIC_16: |
| case IPU_PIX_FMT_GENERIC_32: |
| case IPU_PIX_FMT_RGB565: |
| case IPU_PIX_FMT_BGR24: |
| case IPU_PIX_FMT_RGB24: |
| case IPU_PIX_FMT_YUV444: |
| case IPU_PIX_FMT_BGRA32: |
| case IPU_PIX_FMT_BGR32: |
| case IPU_PIX_FMT_RGBA32: |
| case IPU_PIX_FMT_RGB32: |
| case IPU_PIX_FMT_ABGR32: |
| case IPU_PIX_FMT_UYVY: |
| case IPU_PIX_FMT_YUYV: |
| case IPU_PIX_FMT_GPU32_SB_ST: |
| case IPU_PIX_FMT_GPU32_SB_SRT: |
| case IPU_PIX_FMT_GPU32_ST: |
| case IPU_PIX_FMT_GPU32_SRT: |
| case IPU_PIX_FMT_GPU16_SB_ST: |
| case IPU_PIX_FMT_GPU16_SB_SRT: |
| case IPU_PIX_FMT_GPU16_ST: |
| case IPU_PIX_FMT_GPU16_SRT: |
| *u_offset = 0; |
| *v_offset = 0; |
| break; |
| case IPU_PIX_FMT_YUV420P2: |
| case IPU_PIX_FMT_YUV420P: |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| *u_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset / 2) + |
| horizontal_offset / 2; |
| *v_offset = *u_offset + (uv_stride * height / 2); |
| u_fix = u ? (u + (uv_stride * vertical_offset / 2) + |
| (horizontal_offset / 2) - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *u_offset; |
| v_fix = v ? (v + (uv_stride * vertical_offset / 2) + |
| (horizontal_offset / 2) - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *v_offset; |
| break; |
| case IPU_PIX_FMT_YVU420P: |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| *v_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset / 2) + |
| horizontal_offset / 2; |
| *u_offset = *v_offset + (uv_stride * height / 2); |
| u_fix = u ? (u + (uv_stride * vertical_offset / 2) + |
| (horizontal_offset / 2) - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *u_offset; |
| v_fix = v ? (v + (uv_stride * vertical_offset / 2) + |
| (horizontal_offset / 2) - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *v_offset; |
| break; |
| case IPU_PIX_FMT_YVU422P: |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| *v_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset) + |
| horizontal_offset / 2; |
| *u_offset = *v_offset + uv_stride * height; |
| u_fix = u ? (u + (uv_stride * vertical_offset) + |
| horizontal_offset / 2 - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *u_offset; |
| v_fix = v ? (v + (uv_stride * vertical_offset) + |
| horizontal_offset / 2 - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *v_offset; |
| break; |
| case IPU_PIX_FMT_YUV422P: |
| if (uv_stride < stride / 2) |
| uv_stride = stride / 2; |
| |
| *u_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset) + |
| horizontal_offset / 2; |
| *v_offset = *u_offset + uv_stride * height; |
| u_fix = u ? (u + (uv_stride * vertical_offset) + |
| horizontal_offset / 2 - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *u_offset; |
| v_fix = v ? (v + (uv_stride * vertical_offset) + |
| horizontal_offset / 2 - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *v_offset; |
| break; |
| case IPU_PIX_FMT_YUV444P: |
| uv_stride = stride; |
| *u_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset) + |
| horizontal_offset; |
| *v_offset = *u_offset + uv_stride * height; |
| u_fix = u ? (u + (uv_stride * vertical_offset) + |
| horizontal_offset - |
| (stride * vertical_offset) - |
| (horizontal_offset)) : |
| *u_offset; |
| v_fix = v ? (v + (uv_stride * vertical_offset) + |
| horizontal_offset - |
| (stride * vertical_offset) - |
| (horizontal_offset)) : |
| *v_offset; |
| break; |
| case IPU_PIX_FMT_NV12: |
| case IPU_PIX_FMT_NV16: |
| case PRE_PIX_FMT_NV21: |
| case PRE_PIX_FMT_NV61: |
| uv_stride = stride; |
| *u_offset = stride * (height - vertical_offset - 1) + |
| (stride - horizontal_offset) + |
| (uv_stride * vertical_offset / 2) + |
| horizontal_offset; |
| *v_offset = 0; |
| u_fix = u ? (u + (uv_stride * vertical_offset / 2) + |
| horizontal_offset - |
| (stride * vertical_offset) - (horizontal_offset)) : |
| *u_offset; |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| if (u_fix > *u_offset) |
| *u_offset = u_fix; |
| |
| if (v_fix > *v_offset) |
| *v_offset = v_fix; |
| |
| return 0; |
| } |
| |
| /* IDMAC U/V offset changing support */ |
| /* U and V input is not affected, */ |
| /* the update is done by new calculation according to */ |
| /* vertical_offset and horizontal_offset */ |
| static inline void _ipu_ch_offset_update(struct ipu_soc *ipu, |
| int ch, |
| uint32_t pixel_fmt, |
| uint32_t width, |
| uint32_t height, |
| uint32_t stride, |
| uint32_t u, |
| uint32_t v, |
| uint32_t uv_stride, |
| uint32_t vertical_offset, |
| uint32_t horizontal_offset) |
| { |
| uint32_t u_offset = 0; |
| uint32_t v_offset = 0; |
| uint32_t old_offset = 0; |
| int32_t sub_ch = 0; |
| int ret; |
| |
| ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride, |
| u, v, uv_stride, |
| vertical_offset, horizontal_offset, |
| &u_offset, &v_offset); |
| if (ret) { |
| dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n"); |
| return; |
| } |
| |
| /* UBO and VBO are 22-bit and 8-byte aligned */ |
| if (u_offset/8 > 0x3fffff) |
| dev_warn(ipu->dev, |
| "IDMAC%d's U offset exceeds IPU limitation\n", ch); |
| if (v_offset/8 > 0x3fffff) |
| dev_warn(ipu->dev, |
| "IDMAC%d's V offset exceeds IPU limitation\n", ch); |
| if (u_offset%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's U offset is not 8-byte aligned\n", ch); |
| if (v_offset%8) |
| dev_warn(ipu->dev, |
| "IDMAC%d's V offset is not 8-byte aligned\n", ch); |
| |
| old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22); |
| if (old_offset != u_offset / 8) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8); |
| old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22); |
| if (old_offset != v_offset / 8) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22); |
| if (old_offset != u_offset / 8) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8); |
| old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22); |
| if (old_offset != v_offset / 8) |
| ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8); |
| }; |
| |
| static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width) |
| { |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1); |
| |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1); |
| }; |
| |
| static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu, |
| uint32_t ch, uint32_t band_height) |
| { |
| int32_t sub_ch = 0; |
| |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), |
| 0, 114, 3, band_height - 1); |
| sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch); |
| if (sub_ch <= 0) |
| return; |
| ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), |
| 0, 114, 3, band_height - 1); |
| |
| dev_dbg(ipu->dev, "BNDM 0x%x, ", |
| ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3)); |
| } |
| |
| /* |
| * The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane |
| * whose alpha component is at the most significant 8 bits. The bug only |
| * impacts on cases in which the relevant separate alpha channel is enabled. |
| * |
| * Return true on bad alpha component position, otherwise, return false. |
| */ |
| static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt) |
| { |
| switch (pixel_fmt) { |
| case IPU_PIX_FMT_BGRA32: |
| case IPU_PIX_FMT_BGR32: |
| case IPU_PIX_FMT_RGBA32: |
| case IPU_PIX_FMT_RGB32: |
| return true; |
| } |
| |
| return false; |
| } |
| #endif |