linux/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2020 Rockchip Electronics Co., Ltd.
 * Author: Andy Yan <[email protected]>
 */
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/media-bus-format.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/swab.h>

#include <drm/drm.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_blend.h>
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_flip_work.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>

#include <uapi/linux/videodev2.h>
#include <dt-bindings/soc/rockchip,vop2.h>

#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
#include "rockchip_drm_vop2.h"
#include "rockchip_rgb.h"

/*
 * VOP2 architecture
 *
 +----------+   +-------------+                                                        +-----------+
 |  Cluster |   | Sel 1 from 6|                                                        | 1 from 3  |
 |  window0 |   |    Layer0   |                                                        |    RGB    |
 +----------+   +-------------+              +---------------+    +-------------+      +-----------+
 +----------+   +-------------+              |N from 6 layers|    |             |
 |  Cluster |   | Sel 1 from 6|              |   Overlay0    +--->| Video Port0 |      +-----------+
 |  window1 |   |    Layer1   |              |               |    |             |      | 1 from 3  |
 +----------+   +-------------+              +---------------+    +-------------+      |   LVDS    |
 +----------+   +-------------+                                                        +-----------+
 |  Esmart  |   | Sel 1 from 6|
 |  window0 |   |   Layer2    |              +---------------+    +-------------+      +-----------+
 +----------+   +-------------+              |N from 6 Layers|    |             | +--> | 1 from 3  |
 +----------+   +-------------+   -------->  |   Overlay1    +--->| Video Port1 |      |   MIPI    |
 |  Esmart  |   | Sel 1 from 6|   -------->  |               |    |             |      +-----------+
 |  Window1 |   |   Layer3    |              +---------------+    +-------------+
 +----------+   +-------------+                                                        +-----------+
 +----------+   +-------------+                                                        | 1 from 3  |
 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |   HDMI    |
 |  Window0 |   |    Layer4   |              |N from 6 Layers|    |             |      +-----------+
 +----------+   +-------------+              |   Overlay2    +--->| Video Port2 |
 +----------+   +-------------+              |               |    |             |      +-----------+
 |  Smart   |   | Sel 1 from 6|              +---------------+    +-------------+      |  1 from 3 |
 |  Window1 |   |    Layer5   |                                                        |    eDP    |
 +----------+   +-------------+                                                        +-----------+
 *
 */

enum vop2_data_format {};

enum vop2_afbc_format {};

vop2_alpha_ctrl;

struct vop2_alpha {};

struct vop2_alpha_config {};

struct vop2_win {};

struct vop2_video_port {};

struct vop2 {};

#define vop2_output_if_is_hdmi(x)

#define vop2_output_if_is_dp(x)

#define vop2_output_if_is_edp(x)

#define vop2_output_if_is_mipi(x)

#define vop2_output_if_is_lvds(x)

#define vop2_output_if_is_dpi(x)

static const struct regmap_config vop2_regmap_config;

static struct vop2_video_port *to_vop2_video_port(struct drm_crtc *crtc)
{}

static struct vop2_win *to_vop2_win(struct drm_plane *p)
{}

static void vop2_lock(struct vop2 *vop2)
{}

static void vop2_unlock(struct vop2 *vop2)
{}

static void vop2_writel(struct vop2 *vop2, u32 offset, u32 v)
{}

static void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v)
{}

static u32 vop2_readl(struct vop2 *vop2, u32 offset)
{}

static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v)
{}

static bool vop2_cluster_window(const struct vop2_win *win)
{}

/*
 * Note:
 * The write mask function is documented but missing on rk3566/8, writes
 * to these bits have no effect. For newer soc(rk3588 and following) the
 * write mask is needed for register writes.
 *
 * GLB_CFG_DONE_EN has no write mask bit.
 *
 */
static void vop2_cfg_done(struct vop2_video_port *vp)
{}

static void vop2_win_disable(struct vop2_win *win)
{}

static u32 vop2_get_bpp(const struct drm_format_info *format)
{}

static enum vop2_data_format vop2_convert_format(u32 format)
{}

static enum vop2_afbc_format vop2_convert_afbc_format(u32 format)
{}

static bool vop2_win_rb_swap(u32 format)
{}

static bool vop2_afbc_uv_swap(u32 format)
{}

static bool vop2_win_uv_swap(u32 format)
{}

static bool vop2_win_dither_up(u32 format)
{}

static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
{}

static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
{}

static bool is_yuv_output(u32 bus_format)
{}

static bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
{}

static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format,
					u64 modifier)
{}

/*
 * 0: Full mode, 16 lines for one tail
 * 1: half block mode, 8 lines one tail
 */
static bool vop2_half_block_enable(struct drm_plane_state *pstate)
{}

static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate,
				      bool afbc_half_block_en)
{}

/*
 * A Cluster window has 2048 x 16 line buffer, which can
 * works at 2048 x 16(Full) or 4096 x 8 (Half) mode.
 * for Cluster_lb_mode register:
 * 0: half mode, for plane input width range 2048 ~ 4096
 * 1: half mode, for cluster work at 2 * 2048 plane mode
 * 2: half mode, for rotate_90/270 mode
 *
 */
static int vop2_get_cluster_lb_mode(struct vop2_win *win,
				    struct drm_plane_state *pstate)
{}

static u16 vop2_scale_factor(u32 src, u32 dst)
{}

static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win,
			     u32 src_w, u32 src_h, u32 dst_w,
			     u32 dst_h, u32 pixel_format)
{}

static int vop2_convert_csc_mode(int csc_mode)
{}

/*
 * colorspace path:
 *      Input        Win csc                     Output
 * 1. YUV(2020)  --> Y2R->2020To709->R2Y   --> YUV_OUTPUT(601/709)
 *    RGB        --> R2Y                  __/
 *
 * 2. YUV(2020)  --> bypasss               --> YUV_OUTPUT(2020)
 *    RGB        --> 709To2020->R2Y       __/
 *
 * 3. YUV(2020)  --> Y2R->2020To709        --> RGB_OUTPUT(709)
 *    RGB        --> R2Y                  __/
 *
 * 4. YUV(601/709)-> Y2R->709To2020->R2Y   --> YUV_OUTPUT(2020)
 *    RGB        --> 709To2020->R2Y       __/
 *
 * 5. YUV(601/709)-> bypass                --> YUV_OUTPUT(709)
 *    RGB        --> R2Y                  __/
 *
 * 6. YUV(601/709)-> bypass                --> YUV_OUTPUT(601)
 *    RGB        --> R2Y(601)             __/
 *
 * 7. YUV        --> Y2R(709)              --> RGB_OUTPUT(709)
 *    RGB        --> bypass               __/
 *
 * 8. RGB        --> 709To2020->R2Y        --> YUV_OUTPUT(2020)
 *
 * 9. RGB        --> R2Y(709)              --> YUV_OUTPUT(709)
 *
 * 10. RGB       --> R2Y(601)              --> YUV_OUTPUT(601)
 *
 * 11. RGB       --> bypass                --> RGB_OUTPUT(709)
 */

static void vop2_setup_csc_mode(struct vop2_video_port *vp,
				struct vop2_win *win,
				struct drm_plane_state *pstate)
{}

static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)
{}

static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq)
{}

static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
{}

static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2)
{}

static void vop2_enable(struct vop2 *vop2)
{}

static void vop2_disable(struct vop2 *vop2)
{}

static void vop2_crtc_atomic_disable(struct drm_crtc *crtc,
				     struct drm_atomic_state *state)
{}

static int vop2_plane_atomic_check(struct drm_plane *plane,
				   struct drm_atomic_state *astate)
{}

static void vop2_plane_atomic_disable(struct drm_plane *plane,
				      struct drm_atomic_state *state)
{}

/*
 * The color key is 10 bit, so all format should
 * convert to 10 bit here.
 */
static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key)
{}

static void vop2_plane_atomic_update(struct drm_plane *plane,
				     struct drm_atomic_state *state)
{}

static const struct drm_plane_helper_funcs vop2_plane_helper_funcs =;

static const struct drm_plane_funcs vop2_plane_funcs =;

static int vop2_crtc_enable_vblank(struct drm_crtc *crtc)
{}

static void vop2_crtc_disable_vblank(struct drm_crtc *crtc)
{}

static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc,
				 const struct drm_display_mode *mode,
				 struct drm_display_mode *adj_mode)
{}

static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
{}

static void vop2_post_config(struct drm_crtc *crtc)
{}

static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
{}

/*
 * calc the dclk on rk3588
 * the available div of dclk is 1, 2, 4
 */
static unsigned long rk3588_calc_dclk(unsigned long child_clk, unsigned long max_dclk)
{}

/*
 * 4 pixclk/cycle on rk3588
 * RGB/eDP/HDMI: if_pixclk >= dclk_core
 * DP: dp_pixclk = dclk_out <= dclk_core
 * DSI: mipi_pixclk <= dclk_out <= dclk_core
 */
static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id,
					 int *dclk_core_div, int *dclk_out_div,
					 int *if_pixclk_div, int *if_dclk_div)
{}

/*
 * MIPI port mux on rk3588:
 * 0: Video Port2
 * 1: Video Port3
 * 3: Video Port 1(MIPI1 only)
 */
static u32 rk3588_get_mipi_port_mux(int vp_id)
{}

static u32 rk3588_get_hdmi_pol(u32 flags)
{}

static unsigned long rk3588_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
{}

static unsigned long vop2_set_intf_mux(struct vop2_video_port *vp, int ep_id, u32 polflags)
{}

static int us_to_vertical_line(struct drm_display_mode *mode, int us)
{}

static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
				    struct drm_atomic_state *state)
{}

static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
				  struct drm_atomic_state *state)
{}

static bool is_opaque(u16 alpha)
{}

static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
			     struct vop2_alpha *alpha)
{}

static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
{}

static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_win *main_win)
{}

static void vop2_setup_alpha(struct vop2_video_port *vp)
{}

static void vop2_setup_layer_mixer(struct vop2_video_port *vp)
{}

static void vop2_setup_dly_for_windows(struct vop2 *vop2)
{}

static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
				   struct drm_atomic_state *state)
{}

static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
				   struct drm_atomic_state *state)
{}

static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs =;

static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc)
{}

static void vop2_crtc_destroy_state(struct drm_crtc *crtc,
				    struct drm_crtc_state *state)
{}

static void vop2_crtc_reset(struct drm_crtc *crtc)
{}

static const struct drm_crtc_funcs vop2_crtc_funcs =;

static irqreturn_t vop2_isr(int irq, void *data)
{}

static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win,
			   unsigned long possible_crtcs)
{}

static struct vop2_video_port *find_vp_without_primary(struct vop2 *vop2)
{}

static int vop2_create_crtcs(struct vop2 *vop2)
{}

static void vop2_destroy_crtcs(struct vop2 *vop2)
{}

static int vop2_find_rgb_encoder(struct vop2 *vop2)
{}

static struct reg_field vop2_cluster_regs[VOP2_WIN_MAX_REG] =;

static int vop2_cluster_init(struct vop2_win *win)
{
	struct vop2 *vop2 = win->vop2;
	struct reg_field *cluster_regs;
	int ret, i;

	cluster_regs = kmemdup(vop2_cluster_regs, sizeof(vop2_cluster_regs),
			       GFP_KERNEL);
	if (!cluster_regs)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(vop2_cluster_regs); i++)
		if (cluster_regs[i].reg != 0xffffffff)
			cluster_regs[i].reg += win->offset;

	ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
					   cluster_regs,
					   ARRAY_SIZE(vop2_cluster_regs));

	kfree(cluster_regs);

	return ret;
};

static struct reg_field vop2_esmart_regs[VOP2_WIN_MAX_REG] =;

static int vop2_esmart_init(struct vop2_win *win)
{
	struct vop2 *vop2 = win->vop2;
	struct reg_field *esmart_regs;
	int ret, i;

	esmart_regs = kmemdup(vop2_esmart_regs, sizeof(vop2_esmart_regs),
			      GFP_KERNEL);
	if (!esmart_regs)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(vop2_esmart_regs); i++)
		if (esmart_regs[i].reg != 0xffffffff)
			esmart_regs[i].reg += win->offset;

	ret = devm_regmap_field_bulk_alloc(vop2->dev, vop2->map, win->reg,
					   esmart_regs,
					   ARRAY_SIZE(vop2_esmart_regs));

	kfree(esmart_regs);

	return ret;
};

static int vop2_win_init(struct vop2 *vop2)
{}

/*
 * The window registers are only updated when config done is written.
 * Until that they read back the old value. As we read-modify-write
 * these registers mark them as non-volatile. This makes sure we read
 * the new values from the regmap register cache.
 */
static const struct regmap_range vop2_nonvolatile_range[] =;

static const struct regmap_access_table vop2_volatile_table =;

static const struct regmap_config vop2_regmap_config =;

static int vop2_bind(struct device *dev, struct device *master, void *data)
{}

static void vop2_unbind(struct device *dev, struct device *master, void *data)
{}

const struct component_ops vop2_component_ops =;
EXPORT_SYMBOL_GPL();