// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Amlogic Headers */ #include #include #include #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT #include #endif #include #include #ifdef CONFIG_AMLOGIC_DRM_USE_ION #include "meson_fb.h" #endif #include "meson_vpu.h" #include "meson_plane.h" #include "meson_crtc.h" #include "meson_vpu_pipeline.h" #include "vpu-hw/meson_vpu_postblend.h" #define AM_VOUT_NULL_MODE "null" int meson_vpu_is_compatible(struct meson_vpu_pipeline *pipeline, enum vpu_compatible family) { struct meson_drm *priv; if (!pipeline || !pipeline->priv) { DRM_ERROR("pipeline or priv is NULL!\n"); return 0; } priv = pipeline->priv; return priv->compat == family; } void meson_vout_notify_mode_change(int idx, enum vmode_e mode, enum meson_vout_event event) { /*pre_process event*/ if (event == EVENT_MODE_SET_START) { switch (idx) { case 1: vout_set_uevent(VOUT_EVENT_MODE_CHANGE, 1); vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &mode); break; case 2: #ifdef CONFIG_AMLOGIC_VOUT2_SERVE vout2_set_uevent(VOUT_EVENT_MODE_CHANGE, 1); vout2_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &mode); #endif break; case 3: #ifdef CONFIG_AMLOGIC_VOUT3_SERVE vout3_set_uevent(VOUT_EVENT_MODE_CHANGE, 1); vout3_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &mode); #endif break; default: DRM_ERROR("unknown vout %d\n", idx); break; }; } else if (event == EVENT_MODE_SET_FINISH) { switch (idx) { case 1: vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); vout_set_uevent(VOUT_EVENT_MODE_CHANGE, 0); break; case 2: #ifdef CONFIG_AMLOGIC_VOUT2_SERVE vout2_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); vout2_set_uevent(VOUT_EVENT_MODE_CHANGE, 0); #endif break; case 3: #ifdef CONFIG_AMLOGIC_VOUT3_SERVE vout3_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &mode); vout3_set_uevent(VOUT_EVENT_MODE_CHANGE, 0); #endif break; default: DRM_ERROR("unknown vout %d\n", idx); break; }; } } /*debug only, set mode to vout_server, so display/mode can be still used.*/ void meson_vout_update_mode_name(int idx, char *modename, char *ctx) { DRM_INFO("%s: %s update vout %d name %s.\n", __func__, ctx, idx, modename); if (idx == 1) set_vout_mode_name(modename); #ifdef CONFIG_AMLOGIC_VOUT2_SERVE else if (idx == 2) set_vout2_mode_name(modename); #endif #ifdef CONFIG_AMLOGIC_VOUT3_SERVE else if (idx == 3) set_vout3_mode_name(modename); #endif else DRM_ERROR("unsupported vout idx %d.\n", idx); } static void meson_drm_handle_vpp_crc(struct am_meson_crtc *amcrtc) { u32 crc; struct drm_crtc *crtc = &amcrtc->base; struct meson_vpu_pipeline *ppl = amcrtc->pipeline; struct rdma_reg_ops *reg_ops = ppl->subs[0]->reg_ops; if (amcrtc->vpp_crc_enable && cpu_after_eq(MESON_CPU_MAJOR_ID_SM1)) { crc = reg_ops->rdma_read_reg(VPP_RO_CRCSUM); drm_crtc_add_crc_entry(crtc, true, drm_crtc_accurate_vblank_count(crtc), &crc); } } static void meson_drm_signal_present_fence(struct am_meson_crtc *amcrtc) { struct am_meson_crtc_present_fence *pre_fence = &amcrtc->present_fence; if (pre_fence->fence) { DRM_DEBUG("fd=%d, fence=%px\n", pre_fence->fd, pre_fence->fence); dma_fence_signal(pre_fence->fence); dma_fence_put(pre_fence->fence); pre_fence->fence = NULL; } } void am_meson_crtc_handle_vsync(struct am_meson_crtc *amcrtc) { unsigned long flags; struct drm_crtc *crtc; crtc = &amcrtc->base; drm_crtc_handle_vblank(crtc); spin_lock_irqsave(&crtc->dev->event_lock, flags); if (amcrtc->event) { drm_crtc_send_vblank_event(crtc, amcrtc->event); amcrtc->event = NULL; } spin_unlock_irqrestore(&crtc->dev->event_lock, flags); meson_drm_signal_present_fence(amcrtc); meson_drm_handle_vpp_crc(amcrtc); } static irqreturn_t am_meson_vpu_irq(int irq, void *arg) { struct am_meson_crtc *amcrtc = arg; struct meson_drm *priv = amcrtc->priv; if (!priv->irq_enabled) return IRQ_NONE; MESON_DRM_STATE("irq crtc%d coming\n", amcrtc->crtc_index); am_meson_crtc_handle_vsync(amcrtc); amcrtc->priv->pan_async_commit_ran = false; return IRQ_HANDLED; } /*vpu mem power on/off*/ void meson_vpu_power_config(enum vpu_mod_e mode, bool en) { #ifdef CONFIG_AMLOGIC_VPU struct vpu_dev_s *vpu_dev; vpu_dev = vpu_dev_register(mode, "meson_drm"); if (en) vpu_dev_mem_power_on(vpu_dev); else vpu_dev_mem_power_down(vpu_dev); #endif } static void am_meson_vpu_power_config(bool en) { meson_vpu_power_config(VPU_MAIL_AFBCD, en); meson_vpu_power_config(VPU_VIU_OSD2, en); meson_vpu_power_config(VPU_VIU_OSD_SCALE, en); meson_vpu_power_config(VPU_VD2_OSD2_SCALE, en); meson_vpu_power_config(VPU_VIU_OSD3, en); meson_vpu_power_config(VPU_OSD_BLD34, en); meson_vpu_power_config(VPU_VIU_OSD2, en); meson_vpu_power_config(VPU_VIU2_OSD1, en); meson_vpu_power_config(VPU_VIU2_OSD1, en); meson_vpu_power_config(VPU_VIU2_OSD_ROT, en); } #ifndef CONFIG_AMLOGIC_ZAPPER_CUT static void g12b_pipeline_pre_init(struct meson_vpu_pipeline *pipeline, struct device *dev) { struct clk *vpu_clkc; vpu_clkc = devm_clk_get(dev, "vpu_clkc"); if (IS_ERR_OR_NULL(vpu_clkc)) { DRM_ERROR("cannot get vpu_clkc\n"); vpu_clkc = NULL; } else { int vpu_clkc_rate; /* use default clock rate in dts */ clk_prepare_enable(vpu_clkc); vpu_clkc_rate = clk_get_rate(vpu_clkc); DRM_INFO("vpu clkc clock is %d MHZ\n", vpu_clkc_rate / 1000000); } } #endif static void vpu_pipeline_pre_init(struct meson_vpu_pipeline *pipeline, struct device *dev) { struct meson_drm *private = pipeline->priv; struct meson_vpu_data *vpu_data = private->vpu_data; int i; for (i = 0; i < pipeline->num_postblend; i++) pipeline->subs[i]->reg_ops = &vpu_data->crtc_func.reg_ops[i]; if (vpu_data->crtc_func.pre_init) vpu_data->crtc_func.pre_init(pipeline, dev); } static void meson_init_policy_mask(struct meson_drm *private) { const enum meson_policy_id *policy; if (private->vpu_data->policy) { policy = private->vpu_data->policy; for (; *policy != MAX_POLICY_ID; policy++) private->of_conf.drm_policy_mask |= BIT(*policy); } } static void osd_vpu_power_on(void) { #ifdef CONFIG_AMLOGIC_VPU struct vpu_dev_s *osd1_vpu_dev; struct vpu_dev_s *osd2_vpu_dev; struct vpu_dev_s *osd_scale_vpu_dev; osd1_vpu_dev = vpu_dev_register(VPU_VIU_OSD1, "OSD1"); vpu_dev_mem_power_on(osd1_vpu_dev); osd2_vpu_dev = vpu_dev_register(VPU_VIU_OSD2, "OSD2"); vpu_dev_mem_power_on(osd2_vpu_dev); osd_scale_vpu_dev = vpu_dev_register(VPU_VIU_OSD_SCALE, "OSD_SCALE"); vpu_dev_mem_power_on(osd_scale_vpu_dev); if (1) { struct vpu_dev_s *osd2_scale_vpu_dev; struct vpu_dev_s *osd3_vpu_dev; struct vpu_dev_s *blend34_vpu_dev; osd2_scale_vpu_dev = vpu_dev_register(VPU_VD2_OSD2_SCALE, "OSD2_SCALE"); vpu_dev_mem_power_on(osd2_scale_vpu_dev); osd3_vpu_dev = vpu_dev_register(VPU_VIU_OSD3, "OSD3"); vpu_dev_mem_power_on(osd3_vpu_dev); blend34_vpu_dev = vpu_dev_register(VPU_OSD_BLD34, "BLEND34_SCALE"); vpu_dev_mem_power_on(blend34_vpu_dev); } if (1) { struct vpu_dev_s *mali_afbc_vpu_dev; mali_afbc_vpu_dev = vpu_dev_register(VPU_MAIL_AFBCD, "MALI_AFBC"); vpu_dev_mem_power_on(mali_afbc_vpu_dev); } #endif } static int am_meson_vpu_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct meson_drm_bound_data *bound_data = data; struct drm_device *drm_dev = bound_data->drm; struct meson_drm *private = drm_dev->dev_private; struct meson_vpu_pipeline *pipeline = private->pipeline; struct am_meson_crtc *amcrtc; struct meson_vpu_data *vpu_data; int i, ret, irq; DRM_DEBUG("in[%d]\n", __LINE__); vpu_data = (struct meson_vpu_data *)of_device_get_match_data(dev); if (!vpu_data) return -EFAULT; private->vpu_data = vpu_data; pipeline->ops = private->vpu_data->pipe_ops; private->compat = vpu_data->compat; vpu_topology_populate(pipeline); meson_vpu_block_state_init(private, private->pipeline); meson_of_init(dev, drm_dev, private); meson_init_policy_mask(private); ret = am_meson_plane_create(private); if (ret) { dev_err(dev, "am_meson_plane_create FAILED [%d]\n", ret); return ret; } /*subpipeline/postblend/crtc have same index.*/ for (i = 0; i < pipeline->num_postblend; i++) { if (pipeline->subs[i]->index == -1) break; amcrtc = meson_crtc_bind(private, pipeline->subs[i]->index); if (!amcrtc) { dev_err(dev, "create crtc %d failed\n", i); break; } irq = platform_get_irq(pdev, i); if (irq < 0) { dev_err(dev, "cannot find irq for crtc %d\n", i); return irq; } amcrtc->irq = (unsigned int)irq; ret = devm_request_irq(dev, amcrtc->irq, am_meson_vpu_irq, IRQF_SHARED, dev_name(dev), amcrtc); if (ret) return ret; } vpu_pipeline_pre_init(pipeline, dev); vpu_pipeline_init(pipeline); /* HW config for different VPUs */ if (vpu_data && vpu_data->crtc_func.init_default_reg) vpu_data->crtc_func.init_default_reg(); if (0) am_meson_vpu_power_config(1); else osd_vpu_power_on(); DRM_DEBUG("out[%d]\n", __LINE__); return 0; } static void am_meson_vpu_unbind(struct device *dev, struct device *master, void *data) { struct meson_drm_bound_data *bound_data = data; struct drm_device *drm_dev = bound_data->drm; struct meson_drm *private = drm_dev->dev_private; #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT amvecm_drm_gamma_disable(0); am_meson_ctm_disable(); #endif am_meson_vpu_power_config(0); vpu_pipeline_fini(private->pipeline); } static const struct component_ops am_meson_vpu_component_ops = { .bind = am_meson_vpu_bind, .unbind = am_meson_vpu_unbind, }; #ifndef CONFIG_AMLOGIC_ZAPPER_CUT static const enum meson_policy_id s5_policy[] = { HDR_BEFORE_BLEND, MAX_POLICY_ID, }; static const enum meson_policy_id s7d_policy[] = { HDR_BEFORE_BLEND, MAX_POLICY_ID, }; #endif struct meson_rdma_done_detect drm_rdma_cnt[MESON_MAX_CRTC] = { {VIU_OSD2_TCOLOR_AG1, 0}, {VIU_OSD2_TCOLOR_AG2, 0}, {VIU_OSD2_TCOLOR_AG3, 0}, }; struct meson_rdma_done_detect c5_drm_rdma_cnt[MESON_MAX_CRTC] = { {VOUT_OSD1_TCOLOR_AG1, 0}, {VOUT_OSD1_TCOLOR_AG2, 0}, {VOUT_OSD1_TCOLOR_AG3, 0}, }; #ifndef CONFIG_AMLOGIC_ZAPPER_CUT_C1A static const struct meson_vpu_data vpu_g12a_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &osd_ops, .afbc_ops = &afbc_ops, .scaler_ops = &scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats, .video_formats = &video_formats, .drm_rdma_cnt = drm_rdma_cnt, }; #endif #ifndef CONFIG_AMLOGIC_ZAPPER_CUT static const struct meson_vpu_data vpu_g12b_data = { .crtc_func = { .reg_ops = g12b_reg_ops, .pre_init = g12b_pipeline_pre_init, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &g12b_osd_ops, .afbc_ops = &afbc_ops, .scaler_ops = &scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &g12b_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t7_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t7_osd_ops, .afbc_ops = &t7_afbc_ops, .scaler_ops = &scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &t7_hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t7_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats, .video_formats = &video_formats, .enc_method = 1, .max_osdblend_width = 3840, .max_osdblend_height = 2160, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t3_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t7_osd_ops, .afbc_ops = &t3_afbc_ops, .scaler_ops = &t3_scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t3_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats, .video_formats = &video_formats, .enc_method = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t5w_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t7_osd_ops, .afbc_ops = &t3_afbc_ops, .scaler_ops = &t3_scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t5w_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats, .video_formats = &video_formats, .enc_method = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t5m_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t7_osd_ops, .afbc_ops = &t3_afbc_ops, .scaler_ops = &t3_scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t3_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_t5m, .video_formats = &video_formats, .enc_method = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_s5_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &s5_vpu_pipeline_ops, .osd_ops = &s5_osd_ops, .afbc_ops = &s5_afbc_ops, .scaler_ops = &s5_scaler_ops, .osdblend_ops = &s5_osdblend_ops, .hdr_ops = &s5_hdr_ops, .dv_ops = &db_ops, .postblend_ops = &s5_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .slice2ppc_ops = &slice2ppc_ops, .osd_formats = &osd_formats, .video_formats = &video_formats, .cached_regs = s5_reg_table_cached, .enc_method = 1, .slice_mode = 1, .max_osdblend_width = 3840, .max_osdblend_height = 2160, .policy = s5_policy, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t3x_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &s5_vpu_pipeline_ops, .osd_ops = &t3x_osd_ops, .afbc_ops = &t3x_afbc_ops, .scaler_ops = &s5_scaler_ops, .osdblend_ops = &t3x_osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t3x_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .slice2ppc_ops = &slice2ppc_ops, .osd_formats = &osd_formats_t3x, .video_formats = &video_formats, .cached_regs = s5_reg_table_cached, .enc_method = 1, .slice_mode = 1, .max_osdblend_width = 3840, .max_osdblend_height = 2160, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_txhd2_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &txhd2_osd_ops, .afbc_ops = &afbc_ops, .scaler_ops = &scaler_ops, .osdblend_ops = &txhd2_osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &txhd2_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats, .video_formats = &video_formats, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_s7_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &s7_osd_ops, .afbc_ops = &s7_afbc_ops, .scaler_ops = &s7_scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &s7_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_s1a, .video_formats = &video_formats, .cached_regs = s7_reg_table_cached, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_s7d_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &s7d_osd_ops, .gfcd_ops = &gfcd_ops, .afbc_ops = &s7d_afbc_ops, .scaler_ops = &s7_scaler_ops, .osdblend_ops = &s7d_osdblend_ops, .hdr_ops = &s7d_hdr_ops, .dv_ops = &db_ops, .postblend_ops = &postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_s7d, .video_formats = &video_formats, .policy = s7d_policy, .has_gfcd = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_s6_data = { .crtc_func = { .reg_ops = common_reg_ops, .pre_init = g12b_pipeline_pre_init, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &s6_osd_ops, .gfcd_ops = &gfcd_ops, .afbc_ops = &s6_afbc_ops, .scaler_ops = &s6_scaler_ops, .osdblend_ops = &s7d_osdblend_ops, .hdr_ops = &s7d_hdr_ops, .dv_ops = &db_ops, .postblend_ops = &s6_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_s7d, .video_formats = &video_formats, .policy = s7d_policy, .has_gfcd = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t6d_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t6d_osd_ops, .afbc_ops = &t3_afbc_ops, .scaler_ops = &t6d_scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t6d_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_t6d, .video_formats = &video_formats, .enc_method = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_t6w_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &t6d_osd_ops, .afbc_ops = &t3_afbc_ops, .scaler_ops = &t6d_scaler_ops, .osdblend_ops = &t6w_osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &t6d_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_t6d, .video_formats = &video_formats, .enc_method = 1, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct meson_vpu_data vpu_c5_data = { .crtc_func = { .reg_ops = c5_reg_ops, }, .pipe_ops = &t7_vpu_pipeline_ops, .osd_ops = &c5_osd_ops, .scaler_ops = &c5_scaler_ops, .postblend_ops = &c5_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_t6d, .video_formats = &video_formats, .drm_rdma_cnt = c5_drm_rdma_cnt, .enc_method = ENC_METHOD_NULL, .compat = VPU_COMPATIBLE_C5, }; static const struct meson_vpu_data vpu_a9_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &a9_osd_ops, .gfcd_ops = &a9_gfcd_ops, .scaler_ops = &a9_scaler_ops, .osdblend_ops = &a9_osdblend_ops, .hdr_ops = &a9_hdr_ops, .dv_ops = &db_ops, .postblend_ops = &a9_postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_t6d, .video_formats = &video_formats, .drm_rdma_cnt = drm_rdma_cnt, .policy = s7d_policy, .has_gfcd = 1, .enc_method = 2, }; #endif static const struct meson_vpu_data vpu_s1a_data = { .crtc_func = { .reg_ops = common_reg_ops, }, .pipe_ops = &g12a_vpu_pipeline_ops, .osd_ops = &s1a_osd_ops, .afbc_ops = &afbc_ops, .scaler_ops = &scaler_ops, .osdblend_ops = &osdblend_ops, .hdr_ops = &hdr_ops, .dv_ops = &db_ops, .postblend_ops = &postblend_ops, #ifdef CONFIG_AMLOGIC_VIDEO_DISPLAY .video_ops = &video_ops, #endif .osd_formats = &osd_formats_s1a, .video_formats = &video_formats, .drm_rdma_cnt = drm_rdma_cnt, }; static const struct of_device_id am_meson_vpu_driver_dt_match[] = { #ifndef CONFIG_AMLOGIC_REMOVE_OLD { .compatible = "amlogic, meson-gxbb-vpu",}, { .compatible = "amlogic, meson-gxl-vpu",}, { .compatible = "amlogic, meson-gxm-vpu",}, { .compatible = "amlogic, meson-txl-vpu",}, { .compatible = "amlogic, meson-txlx-vpu",}, { .compatible = "amlogic, meson-axg-vpu",}, {.compatible = "amlogic, meson-tl1-vpu",}, #endif #ifndef CONFIG_AMLOGIC_ZAPPER_CUT { .compatible = "amlogic, meson-g12a-vpu", .data = &vpu_g12a_data,}, { .compatible = "amlogic, meson-g12b-vpu", .data = &vpu_g12b_data,}, {.compatible = "amlogic, meson-sm1-vpu", .data = &vpu_g12b_data,}, {.compatible = "amlogic, meson-tm2-vpu", .data = &vpu_g12a_data,}, {.compatible = "amlogic, meson-t5-vpu", .data = &vpu_g12a_data,}, {.compatible = "amlogic, meson-sc2-vpu", .data = &vpu_g12a_data,}, #endif #ifndef CONFIG_AMLOGIC_ZAPPER_CUT_C1A {.compatible = "amlogic, meson-s4-vpu", .data = &vpu_g12a_data,}, #endif #ifndef CONFIG_AMLOGIC_ZAPPER_CUT {.compatible = "amlogic, meson-t7-vpu", .data = &vpu_t7_data,}, {.compatible = "amlogic, meson-t5w-vpu", .data = &vpu_t5w_data,}, {.compatible = "amlogic, meson-t3-vpu", .data = &vpu_t3_data,}, {.compatible = "amlogic, meson-s5-vpu", .data = &vpu_s5_data,}, {.compatible = "amlogic, meson-t3x-vpu", .data = &vpu_t3x_data,}, {.compatible = "amlogic, meson-txhd2-vpu", .data = &vpu_txhd2_data,}, {.compatible = "amlogic, meson-t5m-vpu", .data = &vpu_t5m_data,}, {.compatible = "amlogic, meson-s7-vpu", .data = &vpu_s7_data,}, {.compatible = "amlogic, meson-s7d-vpu", .data = &vpu_s7d_data,}, {.compatible = "amlogic, meson-s6-vpu", .data = &vpu_s6_data,}, {.compatible = "amlogic, meson-t6d-vpu", .data = &vpu_t6d_data,}, {.compatible = "amlogic, meson-t6w-vpu", .data = &vpu_t6w_data,}, {.compatible = "amlogic, meson-t6x-vpu", .data = &vpu_t6w_data,}, {.compatible = "amlogic, meson-a9-vpu", .data = &vpu_a9_data,}, {.compatible = "amlogic, meson-c5-vpu", .data = &vpu_c5_data,}, #endif {.compatible = "amlogic, meson-s1a-vpu", .data = &vpu_s1a_data,}, {} }; MODULE_DEVICE_TABLE(of, am_meson_vpu_driver_dt_match); static int am_meson_vpu_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; DRM_DEBUG("in[%d]\n", __LINE__); if (!dev->of_node) { dev_err(dev, "can't find vpu devices\n"); return -ENODEV; } DRM_DEBUG("out[%d]\n", __LINE__); return component_add(dev, &am_meson_vpu_component_ops); } static void am_meson_vpu_remove(struct platform_device *pdev) { component_del(&pdev->dev, &am_meson_vpu_component_ops); } static struct platform_driver am_meson_vpu_platform_driver = { .probe = am_meson_vpu_probe, .remove = am_meson_vpu_remove, .driver = { .name = "meson-vpu", .owner = THIS_MODULE, .of_match_table = of_match_ptr(am_meson_vpu_driver_dt_match), }, }; int __init am_meson_vpu_init(void) { return platform_driver_register(&am_meson_vpu_platform_driver); } void __exit am_meson_vpu_exit(void) { platform_driver_unregister(&am_meson_vpu_platform_driver); } #ifndef MODULE module_init(am_meson_vpu_init); module_exit(am_meson_vpu_exit); #endif MODULE_AUTHOR("MultiMedia Amlogic "); MODULE_DESCRIPTION("Amlogic Meson Drm VPU driver"); MODULE_LICENSE("GPL");