blob: a940fc1ef8c28badc13edc2fe0dee37f30c7b842 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include "meson_vpu_pipeline.h"
#include "meson_vpu_reg.h"
#include "meson_vpu_util.h"
#include "osd.h"
#include "osd_log.h"
/* osd_mafbc_irq_clear& irq_mask */
#define OSD_MAFBC_SURFACES_COMPLETED BIT(0)
#define OSD_MAFBC_CONFI_SWAPPED BIT(1)
#define OSD_MAFBC_DECODE_ERROR BIT(2)
#define OSD_MAFBC_DETILING_ERROR BIT(3)
#define OSD_MAFBC_AXI_ERROR BIT(4)
#define OSD_MAFBC_SECURE_ID_ERROR BIT(5)
/* osd_mafbc_command */
#define OSD_MAFBC_DIRECT_SWAP
#define OSD_MAFBC_PENDING_SWAP
/* osd_mafbc_surface_cfg */
#define OSD_MAFBC_S0_ENABLE BIT(0)
#define OSD_MAFBC_S1_ENABLE BIT(1)
#define OSD_MAFBC_S2_ENABLE BIT(2)
#define OSD_MAFBC_S3_ENABLE BIT(3)
#define OSD_MAFBC_DECODE_ENABLE BIT(16)
/* osd_mafbc_axi_cfg */
#define OSD_MAFBC_AXI_QOS(val) FIELD_PREP(GENMASK(3, 0), val)
#define OSD_MAFBC_AXI_CACHE(val) FIELD_PREP(GENMASK(7, 4), val)
/* osd_mafbc_format_specifier */
#define OSD_MAFBC_PIXEL_FORMAT(val) FIELD_PREP(GENMASK(3, 0), val)
#define OSD_MAFBC_YUV_TRANSFORM BIT(8)
#define OSD_MAFBC_BLOCK_SPLIT BIT(9)
#define OSD_MAFBC_SUPER_BLOCK_ASPECT(val) \
FIELD_PREP(GENMASK(17, 16), val)
#define OSD_MAFBC_TILED_HEADER_EN BIT(18)
#define OSD_MAFBC_PAYLOAD_LIMIT_EN BIT(19)
/* osd_mafbc_prefetch_cfg */
#define OSD_MAFBC_PREFETCH_READ_DIR_X BIT(0)
#define OSD_MAFBC_PREFETCH_READ_DIR_Y BIT(1)
static int afbc_pix_format(u32 fmt_mode)
{
u32 pix_format = RGBA8888;
switch (fmt_mode) {
case COLOR_INDEX_YUV_422:
pix_format = YUV422_8B;
break;
case COLOR_INDEX_16_565:
pix_format = RGB565;
break;
case COLOR_INDEX_16_1555_A:
pix_format = RGBA5551;
break;
case COLOR_INDEX_16_4444_R:
case COLOR_INDEX_16_4444_A:
pix_format = RGBA4444;
break;
case COLOR_INDEX_32_BGRX:
case COLOR_INDEX_32_XBGR:
case COLOR_INDEX_32_RGBX:
case COLOR_INDEX_32_XRGB:
case COLOR_INDEX_32_BGRA:
case COLOR_INDEX_32_ABGR:
case COLOR_INDEX_32_RGBA:
case COLOR_INDEX_32_ARGB:
pix_format = RGBA8888;
break;
case COLOR_INDEX_24_888_B:
case COLOR_INDEX_24_RGB:
pix_format = RGB888;
break;
case COLOR_INDEX_RGBA_1010102:
pix_format = RGBA1010102;
break;
default:
osd_log_err("unsupport fmt:%x\n", fmt_mode);
break;
}
return pix_format;
}
static u32 line_stride_calc_afbc(u32 fmt_mode, u32 hsize,
u32 stride_align_32bytes)
{
u32 line_stride = 0;
switch (fmt_mode) {
case R8:
line_stride = ((hsize << 3) + 127) >> 7;
break;
case YUV422_8B:
case RGB565:
case RGBA5551:
case RGBA4444:
line_stride = ((hsize << 4) + 127) >> 7;
break;
case RGBA8888:
case RGB888:
case YUV422_10B:
case RGBA1010102:
line_stride = ((hsize << 5) + 127) >> 7;
break;
}
/* need wr ddr is 32bytes aligned */
if (stride_align_32bytes)
line_stride = ((line_stride + 1) >> 1) << 1;
else
line_stride = line_stride;
return line_stride;
}
static void osd_afbc_enable(u32 osd_index, bool flag)
{
if (flag) {
VSYNCOSD_WR_MPEG_REG_BITS(VPU_MAFBC_SURFACE_CFG,
1, osd_index, 1);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_IRQ_MASK, 0xf);
} else {
VSYNCOSD_WR_MPEG_REG_BITS(VPU_MAFBC_SURFACE_CFG,
0, osd_index, 1);
}
}
static int afbc_check_state(struct meson_vpu_block *vblk,
struct meson_vpu_block_state *state,
struct meson_vpu_pipeline_state *mvps)
{
struct meson_vpu_afbc *afbc = to_afbc_block(vblk);
//vpu_block_check_input(vblk, state, mvps);
if (state->checked)
return 0;
state->checked = true;
DRM_DEBUG("%s check_state called.\n", afbc->base.name);
return 0;
}
static void osd1_afbc_set_state(struct meson_vpu_block *vblk,
struct meson_vpu_block_state *state)
{
u32 pixel_format, line_stride, output_stride;
u32 plane_index, osd_index;
u64 header_addr, out_addr;
u32 aligned_32, afbc_color_reorder;
struct meson_vpu_afbc *afbc;
struct meson_vpu_afbc_state *afbc_state;
struct meson_vpu_osd_layer_info *plane_info;
struct meson_vpu_pipeline *pipeline;
struct meson_vpu_pipeline_state *pipeline_state;
afbc = to_afbc_block(vblk);
afbc_state = to_afbc_state(state);
pipeline = vblk->pipeline;
osd_index = vblk->index;
pipeline_state = priv_to_pipeline_state(pipeline->obj.state);
plane_index = pipeline_state->ratio_plane_index[osd_index];
plane_info = &pipeline_state->plane_info[plane_index];
if (!plane_info->afbc_en)
return;
osd_afbc_enable(0, 1);
aligned_32 = 1;
afbc_color_reorder = 0x1234;
pixel_format = afbc_pix_format(plane_info->pixel_format);
header_addr = plane_info->phy_addr;
line_stride = line_stride_calc_afbc(pixel_format,
plane_info->src_w, aligned_32);
output_stride = plane_info->byte_stride;
header_addr = plane_info->phy_addr;
out_addr = ((u64)(vblk->index + 1)) << 24;
/* set osd path misc ctrl */
VSYNCOSD_WR_MPEG_REG_BITS(OSD_PATH_MISC_CTRL, 0x1, (osd_index + 4), 1);
/* set linear addr */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_CTRL_STAT, 0x1, 2, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_CTRL_STAT2, 1, 1, 1);
/* set read from mali */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 0x1, 30, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 0, 15, 1);
/* set line_stride */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK2_CFG_W4, line_stride, 0, 12);
/* set frame addr */
VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK1_CFG_W4, out_addr & 0xffffffff);
/* set afbc color reorder and mali src*/
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_MALI_UNPACK_CTRL,
afbc_color_reorder, 0, 16);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_MALI_UNPACK_CTRL, 0x1, 31, 1);
/* set header addr */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0,
header_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0,
(header_addr >> 32) & 0xffffffff);
/* set format specifier */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_FORMAT_SPECIFIER_S0,
plane_info->afbc_inter_format |
(pixel_format & 0x0f));
/* set pic size */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_WIDTH_S0, plane_info->src_w);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_HEIGHT_S0, plane_info->src_h);
/* set buf stride */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_STRIDE_S0, output_stride);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0,
out_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0,
(out_addr >> 32) & 0xffffffff);
/* set bounding box */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_START_S0,
plane_info->src_x);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_END_S0,
(plane_info->src_x + plane_info->src_w - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_START_S0,
plane_info->src_y);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_END_S0,
(plane_info->src_y + plane_info->src_h - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_COMMAND, 1);
DRM_DEBUG("%s set_state called.\n", afbc->base.name);
}
static void osd2_afbc_set_state(struct meson_vpu_block *vblk,
struct meson_vpu_block_state *state)
{
u32 pixel_format, line_stride, output_stride;
u32 plane_index, osd_index;
u64 header_addr, out_addr;
u32 aligned_32, afbc_color_reorder;
struct meson_vpu_afbc *afbc;
struct meson_vpu_afbc_state *afbc_state;
struct meson_vpu_osd_layer_info *plane_info;
struct meson_vpu_pipeline *pipeline;
struct meson_vpu_pipeline_state *pipeline_state;
afbc = to_afbc_block(vblk);
afbc_state = to_afbc_state(state);
pipeline = vblk->pipeline;
osd_index = vblk->index;
pipeline_state = priv_to_pipeline_state(pipeline->obj.state);
plane_index = pipeline_state->ratio_plane_index[osd_index];
plane_info = &pipeline_state->plane_info[plane_index];
if (!plane_info->afbc_en)
return;
osd_afbc_enable(1, 1);
aligned_32 = 1;
afbc_color_reorder = 0x1234;
pixel_format = afbc_pix_format(plane_info->pixel_format);
header_addr = plane_info->phy_addr;
line_stride = line_stride_calc_afbc(pixel_format,
plane_info->src_w, aligned_32);
output_stride = plane_info->byte_stride;
header_addr = plane_info->phy_addr;
out_addr = ((u64)(vblk->index + 1)) << 24;
/* set osd path misc ctrl */
VSYNCOSD_WR_MPEG_REG_BITS(OSD_PATH_MISC_CTRL, 0x1, (osd_index + 4), 1);
/* set linear addr */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_CTRL_STAT, 0x1, 2, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_CTRL_STAT2, 1, 1, 1);
/* set read from mali */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 0x1, 30, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 0, 15, 1);
/* set line_stride */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK2_CFG_W4, line_stride, 0, 12);
/* set frame addr */
VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK1_CFG_W4, out_addr & 0xffffffff);
/* set afbc color reorder and mali src*/
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_MALI_UNPACK_CTRL,
afbc_color_reorder, 0, 16);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_MALI_UNPACK_CTRL, 0x1, 31, 1);
/* set header addr */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1,
header_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1,
(header_addr >> 32) & 0xffffffff);
/* set format specifier */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_FORMAT_SPECIFIER_S1,
plane_info->afbc_inter_format |
(pixel_format & 0x0f));
/* set pic size */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_WIDTH_S1, plane_info->src_w);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_HEIGHT_S1, plane_info->src_h);
/* set buf stride */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_STRIDE_S1, output_stride);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1,
out_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1,
(out_addr >> 32) & 0xffffffff);
/* set bounding box */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_START_S1,
plane_info->src_x);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_END_S1,
(plane_info->src_x + plane_info->src_w - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_START_S1,
plane_info->src_y);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_END_S1,
(plane_info->src_y + plane_info->src_h - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_COMMAND, 1);
DRM_DEBUG("%s set_state called.\n", afbc->base.name);
}
static void osd3_afbc_set_state(struct meson_vpu_block *vblk,
struct meson_vpu_block_state *state)
{
u32 pixel_format, line_stride, output_stride;
u32 plane_index, osd_index;
u64 header_addr, out_addr;
u32 aligned_32, afbc_color_reorder;
struct meson_vpu_afbc *afbc;
struct meson_vpu_afbc_state *afbc_state;
struct meson_vpu_osd_layer_info *plane_info;
struct meson_vpu_pipeline *pipeline;
struct meson_vpu_pipeline_state *pipeline_state;
afbc = to_afbc_block(vblk);
afbc_state = to_afbc_state(state);
pipeline = vblk->pipeline;
osd_index = vblk->index;
pipeline_state = priv_to_pipeline_state(pipeline->obj.state);
plane_index = pipeline_state->ratio_plane_index[osd_index];
plane_info = &pipeline_state->plane_info[plane_index];
if (!plane_info->afbc_en)
return;
osd_afbc_enable(2, 1);
aligned_32 = 1;
afbc_color_reorder = 0x1234;
pixel_format = afbc_pix_format(plane_info->pixel_format);
header_addr = plane_info->phy_addr;
line_stride = line_stride_calc_afbc(pixel_format,
plane_info->src_w, aligned_32);
output_stride = plane_info->byte_stride;
header_addr = plane_info->phy_addr;
out_addr = ((u64)(vblk->index + 1)) << 24;
/* set osd path misc ctrl */
VSYNCOSD_WR_MPEG_REG_BITS(OSD_PATH_MISC_CTRL, 0x1, (osd_index + 4), 1);
/* set linear addr */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_CTRL_STAT, 0x1, 2, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_CTRL_STAT2, 1, 1, 1);
/* set read from mali */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_BLK0_CFG_W0, 0x1, 30, 1);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_BLK0_CFG_W0, 0, 15, 1);
/* set line_stride */
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_BLK2_CFG_W4, line_stride, 0, 12);
/* set frame addr */
VSYNCOSD_WR_MPEG_REG(VIU_OSD3_BLK1_CFG_W4, out_addr & 0xffffffff);
/* set afbc color reorder and mali src*/
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_MALI_UNPACK_CTRL,
afbc_color_reorder, 0, 16);
VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD3_MALI_UNPACK_CTRL, 0x1, 31, 1);
/* set header addr */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2,
header_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2,
(header_addr >> 32) & 0xffffffff);
/* set format specifier */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_FORMAT_SPECIFIER_S2,
plane_info->afbc_inter_format |
(pixel_format & 0x0f));
/* set pic size */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_WIDTH_S2, plane_info->src_w);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BUFFER_HEIGHT_S2, plane_info->src_h);
/* set buf stride */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_STRIDE_S2, output_stride);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2,
out_addr & 0xffffffff);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2,
(out_addr >> 32) & 0xffffffff);
/* set bounding box */
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_START_S2,
plane_info->src_x);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_X_END_S2,
(plane_info->src_x + plane_info->src_w - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_START_S2,
plane_info->src_y);
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_BOUNDING_BOX_Y_END_S2,
(plane_info->src_y + plane_info->src_h - 1));
VSYNCOSD_WR_MPEG_REG(VPU_MAFBC_COMMAND, 1);
DRM_DEBUG("%s set_state called.\n", afbc->base.name);
}
static void afbc_set_state(struct meson_vpu_block *vblk,
struct meson_vpu_block_state *state)
{
switch (vblk->index) {
case 0:
osd1_afbc_set_state(vblk, state);
break;
case 1:
osd2_afbc_set_state(vblk, state);
break;
case 2:
osd3_afbc_set_state(vblk, state);
break;
default:
break;
}
}
static void afbc_hw_enable(struct meson_vpu_block *vblk)
{
struct meson_vpu_afbc *afbc = to_afbc_block(vblk);
u32 osd_index = vblk->index;
osd_afbc_enable(osd_index, 1);
DRM_DEBUG("%s enable called.\n", afbc->base.name);
}
static void afbc_hw_disable(struct meson_vpu_block *vblk)
{
struct meson_vpu_afbc *afbc = to_afbc_block(vblk);
u32 osd_index = vblk->index;
osd_afbc_enable(osd_index, 0);
DRM_DEBUG("%s disable called.\n", afbc->base.name);
}
static void afbc_hw_init(struct meson_vpu_block *vblk)
{
struct meson_vpu_afbc *afbc = to_afbc_block(vblk);
vpu_vmod_mem_pd_switch(VPU_MAIL_AFBCD,
VPU_MEM_POWER_ON);
/* disable osd1 afbc */
osd_afbc_enable(0, 0);
osd_afbc_enable(1, 0);
osd_afbc_enable(2, 0);
DRM_DEBUG("%s hw_init called.\n", afbc->base.name);
}
struct meson_vpu_block_ops afbc_ops = {
.check_state = afbc_check_state,
.update_state = afbc_set_state,
.enable = afbc_hw_enable,
.disable = afbc_hw_disable,
.init = afbc_hw_init,
};