mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
drm/rockchip: vop2: Add writeback support
VOP2 has a writeback with max 1920 x 1080 output. Writeback work as a connector in drm system. Change-Id: I670ca8de5155f1102454c618c62dd0c51fa45202 Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
This commit is contained in:
@@ -601,6 +601,20 @@ struct vop2_video_port_regs {
|
||||
struct vop_reg bcsh_en;
|
||||
};
|
||||
|
||||
struct vop2_wb_regs {
|
||||
struct vop_reg enable;
|
||||
struct vop_reg format;
|
||||
struct vop_reg dither_en;
|
||||
struct vop_reg r2y_en;
|
||||
struct vop_reg yrgb_mst;
|
||||
struct vop_reg uv_mst;
|
||||
struct vop_reg vp_id;
|
||||
struct vop_reg fifo_throd;
|
||||
struct vop_reg scale_x_factor;
|
||||
struct vop_reg scale_x_en;
|
||||
struct vop_reg scale_y_en;
|
||||
};
|
||||
|
||||
struct vop_win_data {
|
||||
uint32_t base;
|
||||
enum drm_plane_type type;
|
||||
@@ -644,6 +658,13 @@ struct vop2_win_data {
|
||||
const uint8_t dly[VOP2_DLY_MODE_MAX];
|
||||
};
|
||||
|
||||
struct vop2_wb_data {
|
||||
uint32_t nformats;
|
||||
const uint32_t *formats;
|
||||
struct vop_rect max_output;
|
||||
const struct vop2_wb_regs *regs;
|
||||
};
|
||||
|
||||
struct vop2_video_port_data {
|
||||
char id;
|
||||
uint32_t feature;
|
||||
@@ -712,6 +733,7 @@ struct vop_data {
|
||||
|
||||
struct vop2_ctrl {
|
||||
struct vop_reg cfg_done_en;
|
||||
struct vop_reg wb_cfg_done;
|
||||
struct vop_reg auto_gating_en;
|
||||
struct vop_reg ovl_cfg_done_port;
|
||||
struct vop_reg ovl_port_mux_cfg_done_imd;
|
||||
@@ -804,6 +826,7 @@ struct vop2_data {
|
||||
const struct vop2_ctrl *ctrl;
|
||||
const struct vop2_win_data *win;
|
||||
const struct vop2_video_port_data *vp;
|
||||
const struct vop2_wb_data *wb;
|
||||
const struct vop2_layer_data *layer;
|
||||
const struct vop_csc_table *csc_table;
|
||||
const struct vop_hdr_table *hdr_table;
|
||||
@@ -834,6 +857,9 @@ struct vop2_data {
|
||||
#define DMA_FINISH_INTR BIT(14)
|
||||
#define FS_FIELD_INTR BIT(15)
|
||||
#define FE_INTR BIT(16)
|
||||
#define WB_UV_FIFO_FULL_INTR BIT(17)
|
||||
#define WB_YRGB_FIFO_FULL_INTR BIT(18)
|
||||
#define WB_COMPLETE_INTR BIT(19)
|
||||
|
||||
#define INTR_MASK (DSP_HOLD_VALID_INTR | FS_INTR | \
|
||||
LINE_FLAG_INTR | BUS_ERROR_INTR | \
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_flip_work.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_writeback.h>
|
||||
#ifdef CONFIG_DRM_ANALOGIX_DP
|
||||
#include <drm/bridge/analogix_dp.h>
|
||||
#endif
|
||||
@@ -124,6 +125,7 @@
|
||||
#define to_vop2_video_port(c) container_of(c, struct vop2_video_port, crtc)
|
||||
#define to_vop2_win(x) container_of(x, struct vop2_win, base)
|
||||
#define to_vop2_plane_state(x) container_of(x, struct vop2_plane_state, base)
|
||||
#define to_wb_state(x) container_of(x, struct vop2_wb_connector_state, base)
|
||||
|
||||
#define ROCKCHIP_AFBC_MOD DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
|
||||
|
||||
@@ -322,6 +324,31 @@ struct vop2_layer {
|
||||
const struct vop2_layer_regs *regs;
|
||||
};
|
||||
|
||||
struct vop2_wb {
|
||||
uint8_t vp_id;
|
||||
struct drm_writeback_connector conn;
|
||||
const struct vop2_wb_regs *regs;
|
||||
};
|
||||
|
||||
enum vop2_wb_format {
|
||||
VOP2_WB_ARGB8888,
|
||||
VOP2_WB_RGB888,
|
||||
VOP2_WB_RGB565,
|
||||
VOP2_WB_YUV420SP = 4,
|
||||
VOP2_WB_INVALID = -1,
|
||||
};
|
||||
|
||||
struct vop2_wb_connector_state {
|
||||
struct drm_connector_state base;
|
||||
dma_addr_t yrgb_addr;
|
||||
dma_addr_t uv_addr;
|
||||
enum vop2_wb_format format;
|
||||
uint16_t scale_x_factor;
|
||||
uint8_t scale_x_en;
|
||||
uint8_t scale_y_en;
|
||||
uint8_t vp_id;
|
||||
};
|
||||
|
||||
struct vop2_video_port {
|
||||
struct drm_crtc crtc;
|
||||
struct vop2 *vop2;
|
||||
@@ -355,6 +382,17 @@ struct vop2_video_port {
|
||||
*/
|
||||
bool sdr2hdr_en;
|
||||
|
||||
/**
|
||||
* @wb_en: write back enabled on this port;
|
||||
*/
|
||||
bool wb_en;
|
||||
|
||||
/**
|
||||
* @fs_vsync_cnt: frame start vysnc counter,
|
||||
* used to get the write back complete event;
|
||||
*/
|
||||
uint32_t fs_vsync_cnt;
|
||||
|
||||
/**
|
||||
* @bg_ovl_dly: The timing delay from background layer
|
||||
* to overlay module.
|
||||
@@ -386,6 +424,7 @@ struct vop2 {
|
||||
struct device *dev;
|
||||
struct drm_device *drm_dev;
|
||||
struct vop2_video_port vps[ROCKCHIP_MAX_CRTC];
|
||||
struct vop2_wb wb;
|
||||
struct dentry *debugfs;
|
||||
struct drm_info_list *debugfs_files;
|
||||
struct drm_property *soc_id_prop;
|
||||
@@ -680,6 +719,13 @@ static inline void vop2_cfg_done(struct drm_crtc *crtc)
|
||||
VOP_MODULE_SET(vop2, vp, cfg_done, 1);
|
||||
}
|
||||
|
||||
static inline void vop2_wb_cfg_done(struct vop2 *vop2)
|
||||
{
|
||||
uint32_t val = RK3568_VOP2_WB_CFG_DONE | (RK3568_VOP2_WB_CFG_DONE << 16);
|
||||
|
||||
vop2_writel(vop2, 0, val);
|
||||
}
|
||||
|
||||
static void vop2_win_disable(struct vop2_win *win)
|
||||
{
|
||||
struct vop2 *vop2 = win->vop2;
|
||||
@@ -765,6 +811,23 @@ static enum vop2_afbc_format vop2_convert_afbc_format(uint32_t format)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static enum vop2_wb_format vop2_convert_wb_format(uint32_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
return VOP2_WB_ARGB8888;
|
||||
case DRM_FORMAT_RGB888:
|
||||
return VOP2_WB_RGB888;
|
||||
case DRM_FORMAT_RGB565:
|
||||
return VOP2_WB_RGB565;
|
||||
case DRM_FORMAT_NV12:
|
||||
return VOP2_WB_YUV420SP;
|
||||
default:
|
||||
DRM_ERROR("unsupported wb format[%08x]\n", format);
|
||||
return VOP2_WB_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static bool vop2_win_rb_swap(uint32_t format)
|
||||
{
|
||||
switch (format) {
|
||||
@@ -1452,6 +1515,264 @@ static void vop2_core_clks_disable(struct vop2 *vop2)
|
||||
clk_disable(vop2->hclk);
|
||||
}
|
||||
|
||||
static void vop2_wb_connector_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct vop2_wb_connector_state *wb_state;
|
||||
|
||||
if (connector->state) {
|
||||
__drm_atomic_helper_connector_destroy_state(connector->state);
|
||||
kfree(connector->state);
|
||||
connector->state = NULL;
|
||||
}
|
||||
|
||||
wb_state = kzalloc(sizeof(*wb_state), GFP_KERNEL);
|
||||
if (wb_state)
|
||||
__drm_atomic_helper_connector_reset(connector, &wb_state->base);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
vop2_wb_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static void vop2_wb_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static struct drm_connector_state *
|
||||
vop2_wb_connector_duplicate_state(struct drm_connector *connector)
|
||||
{
|
||||
struct vop2_wb_connector_state *wb_state;
|
||||
|
||||
if (WARN_ON(!connector->state))
|
||||
return NULL;
|
||||
|
||||
wb_state = kzalloc(sizeof(*wb_state), GFP_KERNEL);
|
||||
if (!wb_state)
|
||||
return NULL;
|
||||
|
||||
__drm_atomic_helper_connector_duplicate_state(connector, &wb_state->base);
|
||||
|
||||
return &wb_state->base;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs vop2_wb_connector_funcs = {
|
||||
.reset = vop2_wb_connector_reset,
|
||||
.detect = vop2_wb_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = vop2_wb_connector_destroy,
|
||||
.atomic_duplicate_state = vop2_wb_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static int vop2_wb_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
mode = drm_mode_create(connector->dev);
|
||||
if (!mode)
|
||||
break;
|
||||
|
||||
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
|
||||
mode->clock = 148500 >> i;
|
||||
mode->hdisplay = 1920 >> i;
|
||||
mode->hsync_start = 1930 >> i;
|
||||
mode->hsync_end = 1940 >> i;
|
||||
mode->htotal = 1990 >> i;
|
||||
mode->vdisplay = 1080 >> i;
|
||||
mode->vsync_start = 1090 >> i;
|
||||
mode->vsync_end = 1100 >> i;
|
||||
mode->vtotal = 1110 >> i;
|
||||
mode->flags = 0;
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
vop2_wb_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
|
||||
struct drm_writeback_connector *wb_conn;
|
||||
struct vop2_wb *wb;
|
||||
struct vop2 *vop2;
|
||||
int w, h;
|
||||
|
||||
wb_conn = container_of(connector, struct drm_writeback_connector, base);
|
||||
wb = container_of(wb_conn, struct vop2_wb, conn);
|
||||
vop2 = container_of(wb, struct vop2, wb);
|
||||
w = mode->hdisplay;
|
||||
h = mode->vdisplay;
|
||||
|
||||
|
||||
if (w > vop2->data->wb->max_output.width)
|
||||
return MODE_BAD_HVALUE;
|
||||
|
||||
if (h > vop2->data->wb->max_output.height)
|
||||
return MODE_BAD_VVALUE;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static int vop2_wb_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
struct drm_crtc_state *cstate,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct vop2_wb_connector_state *wb_state = to_wb_state(conn_state);
|
||||
struct drm_crtc *crtc = cstate->crtc;
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
|
||||
return 0;
|
||||
|
||||
fb = conn_state->writeback_job->fb;
|
||||
DRM_DEV_DEBUG(vp->vop2->dev, "%d x % d\n", fb->width, fb->height);
|
||||
if ((fb->width > cstate->mode.hdisplay) ||
|
||||
((fb->height != cstate->mode.vdisplay) &&
|
||||
(fb->height != (cstate->mode.vdisplay >> 1)))) {
|
||||
DRM_DEBUG_KMS("Invalid framebuffer size %ux%u, Only support x scale down and 1/2 y scale down\n",
|
||||
fb->width, fb->height);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wb_state->scale_x_factor = vop2_scale_factor(SCALE_DOWN, VOP2_SCALE_DOWN_BIL,
|
||||
cstate->mode.hdisplay, fb->width);
|
||||
wb_state->scale_x_en = (fb->width < cstate->mode.hdisplay) ? 1 : 0;
|
||||
wb_state->scale_y_en = (fb->height < cstate->mode.vdisplay) ? 1 : 0;
|
||||
|
||||
wb_state->format = vop2_convert_wb_format(fb->format->format);
|
||||
if (wb_state->format < 0) {
|
||||
struct drm_format_name_buf format_name;
|
||||
|
||||
DRM_DEBUG_KMS("Invalid pixel format %s\n",
|
||||
drm_get_format_name(fb->format->format,
|
||||
&format_name));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wb_state->vp_id = vp->id;
|
||||
wb_state->yrgb_addr = rockchip_fb_get_dma_addr(fb, 0);
|
||||
if (fb->format->is_yuv) {
|
||||
wb_state->uv_addr = rockchip_fb_get_dma_addr(fb, 1);
|
||||
wb_state->uv_addr += fb->offsets[1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs vop2_wb_encoder_helper_funcs = {
|
||||
.atomic_check = vop2_wb_encoder_atomic_check,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs vop2_wb_connector_helper_funcs = {
|
||||
.get_modes = vop2_wb_connector_get_modes,
|
||||
.mode_valid = vop2_wb_connector_mode_valid,
|
||||
};
|
||||
|
||||
|
||||
static int vop2_wb_connector_init(struct vop2 *vop2)
|
||||
{
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
int ret;
|
||||
|
||||
vop2->wb.regs = vop2_data->wb->regs;
|
||||
vop2->wb.conn.encoder.possible_crtcs = (1 << vop2_data->nr_vps) - 1;
|
||||
drm_connector_helper_add(&vop2->wb.conn.base, &vop2_wb_connector_helper_funcs);
|
||||
|
||||
ret = drm_writeback_connector_init(vop2->drm_dev, &vop2->wb.conn,
|
||||
&vop2_wb_connector_funcs,
|
||||
&vop2_wb_encoder_helper_funcs,
|
||||
vop2_data->wb->formats,
|
||||
vop2_data->wb->nformats);
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(vop2->dev, "writeback connector init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vop2_wb_irqs_enable(struct vop2 *vop2)
|
||||
{
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
const struct vop_intr *intr = &vop2_data->axi_intr[0];
|
||||
uint32_t irqs = WB_UV_FIFO_FULL_INTR | WB_YRGB_FIFO_FULL_INTR;
|
||||
|
||||
VOP_INTR_SET_TYPE(vop2, intr, clear, irqs, 1);
|
||||
VOP_INTR_SET_TYPE(vop2, intr, enable, irqs, 1);
|
||||
}
|
||||
|
||||
static uint32_t vop2_read_and_clear_wb_irqs(struct vop2 *vop2)
|
||||
{
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
const struct vop_intr *intr = &vop2_data->axi_intr[0];
|
||||
uint32_t irqs = WB_UV_FIFO_FULL_INTR | WB_YRGB_FIFO_FULL_INTR;
|
||||
uint32_t val;
|
||||
|
||||
val = VOP_INTR_GET_TYPE(vop2, intr, status, irqs);
|
||||
if (val)
|
||||
VOP_INTR_SET_TYPE(vop2, intr, clear, val, 1);
|
||||
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void vop2_wb_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
struct vop2 *vop2 = vp->vop2;
|
||||
struct vop2_wb *wb = &vop2->wb;
|
||||
struct drm_writeback_connector *wb_conn = &wb->conn;
|
||||
struct drm_connector_state *conn_state = wb_conn->base.state;
|
||||
struct vop2_wb_connector_state *wb_state;
|
||||
uint32_t fifo_throd;
|
||||
uint8_t r2y;
|
||||
|
||||
if (!conn_state)
|
||||
return;
|
||||
wb_state = to_wb_state(conn_state);
|
||||
|
||||
if (wb_state->vp_id != vp->id)
|
||||
return;
|
||||
|
||||
if (conn_state->writeback_job && conn_state->writeback_job->fb) {
|
||||
struct drm_framebuffer *fb = conn_state->writeback_job->fb;
|
||||
|
||||
DRM_DEV_DEBUG(vop2->dev, "Enable wb %ux%u fmt: %u pitches: %d\n",
|
||||
fb->width, fb->height, wb_state->format, fb->pitches[0]);
|
||||
|
||||
drm_writeback_queue_job(wb_conn, conn_state->writeback_job);
|
||||
conn_state->writeback_job = NULL;
|
||||
|
||||
fifo_throd = fb->pitches[0] >> 4;
|
||||
r2y = is_yuv_support(fb->format->format) && (!is_yuv_output(vcstate->bus_format));
|
||||
|
||||
/*
|
||||
* the vp_id register config done immediately
|
||||
*/
|
||||
VOP_MODULE_SET(vop2, wb, vp_id, wb_state->vp_id);
|
||||
VOP_MODULE_SET(vop2, wb, format, wb_state->format);
|
||||
VOP_MODULE_SET(vop2, wb, yrgb_mst, wb_state->yrgb_addr);
|
||||
VOP_MODULE_SET(vop2, wb, uv_mst, wb_state->uv_addr);
|
||||
VOP_MODULE_SET(vop2, wb, fifo_throd, fifo_throd);
|
||||
VOP_MODULE_SET(vop2, wb, scale_x_factor, wb_state->scale_x_factor);
|
||||
VOP_MODULE_SET(vop2, wb, scale_x_en, wb_state->scale_x_en);
|
||||
VOP_MODULE_SET(vop2, wb, scale_y_en, wb_state->scale_y_en);
|
||||
VOP_MODULE_SET(vop2, wb, r2y_en, r2y);
|
||||
VOP_MODULE_SET(vop2, wb, enable, 1);
|
||||
vop2_wb_irqs_enable(vop2);
|
||||
vp->wb_en = true;
|
||||
vp->fs_vsync_cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void vop2_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
struct vop2_video_port *vp = to_vop2_video_port(crtc);
|
||||
@@ -3917,6 +4238,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state
|
||||
|
||||
spin_lock_irqsave(&vop2->irq_lock, flags);
|
||||
|
||||
vop2_wb_commit(crtc);
|
||||
vop2_cfg_done(crtc);
|
||||
|
||||
spin_unlock_irqrestore(&vop2->irq_lock, flags);
|
||||
@@ -4234,9 +4556,11 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
const struct vop2_data *vop2_data = vop2->data;
|
||||
size_t vp_max = min_t(size_t, vop2_data->nr_vps, ROCKCHIP_MAX_CRTC);
|
||||
size_t axi_max = min_t(size_t, vop2_data->nr_axi_intr, VOP2_SYS_AXI_BUS_NUM);
|
||||
struct vop2_wb *wb = &vop2->wb;
|
||||
uint32_t vp_irqs[ROCKCHIP_MAX_CRTC];
|
||||
uint32_t axi_irqs[VOP2_SYS_AXI_BUS_NUM];
|
||||
uint32_t active_irqs;
|
||||
uint32_t wb_irqs;
|
||||
unsigned long flags;
|
||||
int ret = IRQ_NONE;
|
||||
int i;
|
||||
@@ -4271,6 +4595,7 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
vp_irqs[i] = vop2_read_and_clear_active_vp_irqs(vop2, i);
|
||||
for (i = 0; i < axi_max; i++)
|
||||
axi_irqs[i] = vop2_read_and_clear_axi_irqs(vop2, i);
|
||||
wb_irqs = vop2_read_and_clear_wb_irqs(vop2);
|
||||
spin_unlock_irqrestore(&vop2->irq_lock, flags);
|
||||
|
||||
for (i = 0; i < vp_max; i++) {
|
||||
@@ -4293,6 +4618,28 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
drm_crtc_handle_vblank(crtc);
|
||||
vop2_handle_vblank(vop2, crtc);
|
||||
active_irqs &= ~FS_FIELD_INTR;
|
||||
|
||||
if (vp->wb_en) {
|
||||
vp->fs_vsync_cnt++;
|
||||
/*
|
||||
* First frame start, the start of the write back
|
||||
* we should stop when write back complete.
|
||||
*/
|
||||
if (vp->fs_vsync_cnt == 1) {
|
||||
VOP_MODULE_SET(vop2, wb, enable, 0);
|
||||
vop2_wb_cfg_done(vop2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Second frame start, write back complete now.
|
||||
*/
|
||||
if (vp->fs_vsync_cnt == 2) {
|
||||
drm_writeback_signal_completion(&vop2->wb.conn, 0);
|
||||
vp->wb_en = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -4303,6 +4650,12 @@ static irqreturn_t vop2_isr(int irq, void *data)
|
||||
DRM_ERROR("Unknown video_port%d IRQs: %02x\n", i, active_irqs);
|
||||
}
|
||||
|
||||
if (wb_irqs) {
|
||||
active_irqs = wb_irqs;
|
||||
ERROR_HANDLER(WB_UV_FIFO_FULL);
|
||||
ERROR_HANDLER(WB_YRGB_FIFO_FULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < axi_max; i++) {
|
||||
active_irqs = axi_irqs[i];
|
||||
|
||||
@@ -4842,7 +5195,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
|
||||
ret = vop2_gamma_init(vop2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vop2_wb_connector_init(vop2);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -53,6 +53,13 @@ static const uint32_t formats_win_lite[] = {
|
||||
DRM_FORMAT_BGR565,
|
||||
};
|
||||
|
||||
static const u32 formats_wb[] = {
|
||||
DRM_FORMAT_RGB888,
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_NV12,
|
||||
};
|
||||
|
||||
static const u32 sdr2hdr_bt1886eotf_yn_for_hlg_hdr[65] = {
|
||||
0,
|
||||
1, 7, 17, 35,
|
||||
@@ -287,6 +294,11 @@ static const struct vop_hdr_table rk3568_vop_hdr_table = {
|
||||
static const int rk3568_vop_axi_intrs[] = {
|
||||
0,
|
||||
BUS_ERROR_INTR,
|
||||
0,
|
||||
WB_UV_FIFO_FULL_INTR,
|
||||
WB_YRGB_FIFO_FULL_INTR,
|
||||
WB_COMPLETE_INTR,
|
||||
|
||||
};
|
||||
|
||||
static const struct vop_intr rk3568_vop_axi_intr[] = {
|
||||
@@ -347,6 +359,27 @@ static const struct vop_intr rk3568_vp2_intr = {
|
||||
.clear = VOP_REG_MASK(RK3568_VP2_INT_CLR, 0xffff, 0),
|
||||
};
|
||||
|
||||
static const struct vop2_wb_regs rk3568_vop_wb_regs = {
|
||||
.enable = VOP_REG(RK3568_WB_CTRL, 0x1, 0),
|
||||
.format = VOP_REG(RK3568_WB_CTRL, 0x7, 1),
|
||||
.dither_en = VOP_REG(RK3568_WB_CTRL, 0x1, 4),
|
||||
.r2y_en = VOP_REG(RK3568_WB_CTRL, 0x1, 5),
|
||||
.scale_x_en = VOP_REG(RK3568_WB_CTRL, 0x1, 7),
|
||||
.scale_y_en = VOP_REG(RK3568_WB_CTRL, 0x1, 8),
|
||||
.scale_x_factor = VOP_REG(RK3568_WB_XSCAL_FACTOR, 0x3fff, 16),
|
||||
.yrgb_mst = VOP_REG(RK3568_WB_YRGB_MST, 0xffffffff, 0),
|
||||
.uv_mst = VOP_REG(RK3568_WB_CBR_MST, 0xffffffff, 0),
|
||||
.vp_id = VOP_REG(RK3568_LUT_PORT_SEL, 0x3, 8),
|
||||
.fifo_throd = VOP_REG(RK3568_WB_XSCAL_FACTOR, 0x3ff, 0),
|
||||
};
|
||||
|
||||
static const struct vop2_wb_data rk3568_vop_wb_data = {
|
||||
.formats = formats_wb,
|
||||
.nformats = ARRAY_SIZE(formats_wb),
|
||||
.max_output = { 1920, 1080 },
|
||||
.regs = &rk3568_vop_wb_regs,
|
||||
};
|
||||
|
||||
static const struct vop2_video_port_regs rk3568_vop_vp0_regs = {
|
||||
.cfg_done = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 0),
|
||||
.overlay_mode = VOP_REG(RK3568_OVL_CTRL, 0x1, 0),
|
||||
@@ -1059,6 +1092,7 @@ static const struct vop_grf_ctrl rk3568_grf_ctrl = {
|
||||
|
||||
static const struct vop2_ctrl rk3568_vop_ctrl = {
|
||||
.cfg_done_en = VOP_REG(RK3568_REG_CFG_DONE, 0x1, 15),
|
||||
.wb_cfg_done = VOP_REG_MASK(RK3568_REG_CFG_DONE, 0x1, 14),
|
||||
.auto_gating_en = VOP_REG(RK3568_SYS_AUTO_GATING_CTRL, 0x1, 31),
|
||||
.ovl_cfg_done_port = VOP_REG(RK3568_OVL_CTRL, 0x3, 30),
|
||||
.ovl_port_mux_cfg_done_imd = VOP_REG(RK3568_OVL_CTRL, 0x1, 28),
|
||||
@@ -1127,6 +1161,7 @@ static const struct vop2_data rk3568_vop = {
|
||||
.axi_intr = rk3568_vop_axi_intr,
|
||||
.nr_axi_intr = ARRAY_SIZE(rk3568_vop_axi_intr),
|
||||
.vp = rk3568_vop_video_ports,
|
||||
.wb = &rk3568_vop_wb_data,
|
||||
.layer = rk3568_vop_layers,
|
||||
.nr_layers = ARRAY_SIZE(rk3568_vop_layers),
|
||||
.win = rk3568_vop_win_data,
|
||||
|
||||
@@ -1050,11 +1050,16 @@
|
||||
#define RK3568_GRF_VO_CON1 0x0364
|
||||
/* System registers definition */
|
||||
#define RK3568_REG_CFG_DONE 0x000
|
||||
#define RK3568_VOP2_WB_CFG_DONE BIT(14)
|
||||
#define RK3568_VERSION_INFO 0x004
|
||||
#define RK3568_SYS_AUTO_GATING_CTRL 0x008
|
||||
#define RK3568_DSP_IF_EN 0x028
|
||||
#define RK3568_DSP_IF_CTRL 0x02c
|
||||
#define RK3568_DSP_IF_POL 0x030
|
||||
#define RK3568_WB_CTRL 0x40
|
||||
#define RK3568_WB_XSCAL_FACTOR 0x44
|
||||
#define RK3568_WB_YRGB_MST 0x48
|
||||
#define RK3568_WB_CBR_MST 0x4C
|
||||
#define RK3568_LUT_PORT_SEL 0x058
|
||||
#define RK3568_VP0_LINE_FLAG 0x70
|
||||
#define RK3568_VP1_LINE_FLAG 0x74
|
||||
|
||||
Reference in New Issue
Block a user