// SPDX-License-Identifier: GPL-2.0+ #include #include #include #include #include #include #include #include "rockchip_drm_drv.h" #include "rockchip_drm_vop.h" #define XRES_DEF 1920 #define YRES_DEF 1080 struct vconn_device { struct rockchip_vconn *vconn; struct drm_encoder encoder; struct drm_connector connector; struct list_head list; int encoder_type; int output_type; int output_mode; int bus_format; int if_id; int vp_id_mask; bool connected; }; struct rockchip_vconn { struct device *dev; struct drm_device *drm_dev; struct platform_device *pdev; struct list_head list_head; }; #define to_vconn_device(x) container_of(x, struct vconn_device, x) static const struct drm_display_mode edid_cea_modes_1[] = { /* 1 - 640x480@60Hz 4:3 */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 2 - 720x480@60Hz 4:3 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 3 - 720x480@60Hz 16:9 */ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 4 - 1280x720@60Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 5 - 1920x1080i@60Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 6 - 720(1440)x480i@60Hz 4:3 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 7 - 720(1440)x480i@60Hz 16:9 */ { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739, 801, 858, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 16 - 1920x1080@60Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 17 - 720x576@50Hz 4:3 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 18 - 720x576@50Hz 16:9 */ { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 19 - 1280x720@50Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 20 - 1920x1080i@50Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 21 - 720(1440)x576i@50Hz 4:3 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, }, /* 22 - 720(1440)x576i@50Hz 16:9 */ { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732, 795, 864, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 31 - 1920x1080@50Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 34 - 1920x1080@30Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 39 - 1920x1080i@50Hz 16:9 */ { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 62 - 1280x720@30Hz 16:9 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 63 - 1920x1080@120Hz 16:9 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 67 - 1280x720@30Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 68 - 1280x720@50Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 69 - 1280x720@60Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 70 - 1280x720@100Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 71 - 1280x720@120Hz 64:27 */ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 74 - 1920x1080@30Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 75 - 1920x1080@50Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 76 - 1920x1080@60Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 77 - 1920x1080@100Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 78 - 1920x1080@120Hz 64:27 */ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 95 - 3840x2160@30Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 96 - 3840x2160@50Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 97 - 3840x2160@60Hz 16:9 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, }, /* 100 - 4096x2160@30Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184, 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, /* 101 - 4096x2160@50Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064, 5152, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, /* 102 - 4096x2160@60Hz 256:135 */ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184, 4272, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, }, /* 105 - 3840x2160@30Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 106 - 3840x2160@50Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896, 4984, 5280, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, /* 107 - 3840x2160@60Hz 64:27 */ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016, 4104, 4400, 0, 2160, 2168, 2178, 2250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC), .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, }, }; static int vconn_drm_add_modes_noedid(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_display_mode *mode; int i, count, num_modes = 0; count = ARRAY_SIZE(edid_cea_modes_1); for (i = 0; i < count; i++) { const struct drm_display_mode *ptr = &edid_cea_modes_1[i]; mode = drm_mode_duplicate(dev, ptr); if (mode) { drm_mode_probed_add(connector, mode); num_modes++; } } return num_modes; } static void rockchip_virtual_encoder_enable(struct drm_encoder *encoder) { struct vconn_device *vconn_dev = to_vconn_device(encoder); struct rockchip_vconn *vconn = vconn_dev->vconn; dev_info(vconn->dev, "encoder enable for output%d\n", ffs(vconn_dev->if_id) - 1); } static void rockchip_virtual_encoder_disable(struct drm_encoder *encoder) { struct vconn_device *vconn_dev = to_vconn_device(encoder); struct rockchip_vconn *vconn = vconn_dev->vconn; struct drm_crtc *crtc = encoder->crtc; struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); vcstate->output_if &= ~vconn_dev->if_id; dev_info(vconn->dev, "encoder disable for output%d\n", ffs(vconn_dev->if_id) - 1); } static int rockchip_virtual_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { return 0; } static void rockchip_virtual_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adj) { struct drm_crtc *crtc = encoder->crtc; struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); struct vconn_device *vconn_dev = to_vconn_device(encoder); struct rockchip_vconn *vconn = vconn_dev->vconn; vcstate->output_if |= vconn_dev->if_id; vcstate->output_mode = vconn_dev->output_mode; vcstate->output_type = vconn_dev->output_type; vcstate->bus_format = vconn_dev->bus_format; dev_info(vconn->dev, "mode set for output%d\n", ffs(vconn_dev->if_id) - 1); } static const struct drm_encoder_helper_funcs rockchip_virtual_encoder_helper_funcs = { .enable = rockchip_virtual_encoder_enable, .disable = rockchip_virtual_encoder_disable, .atomic_check = rockchip_virtual_encoder_atomic_check, .mode_set = rockchip_virtual_encoder_mode_set, }; static enum drm_connector_status rockchip_virtual_connector_detect(struct drm_connector *connector, bool force) { struct vconn_device *vconn_dev = to_vconn_device(connector); if (vconn_dev->output_type == DRM_MODE_CONNECTOR_VIRTUAL) return vconn_dev->connected ? connector_status_connected : connector_status_disconnected; return connector_status_connected; } static void rockchip_virtual_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); drm_connector_cleanup(connector); } static const struct drm_connector_funcs rockchip_virtual_connector_funcs = { .detect = rockchip_virtual_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = rockchip_virtual_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int vvop_conn_get_modes(struct drm_connector *connector) { int count; count = vconn_drm_add_modes_noedid(connector); drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF); return count; } static const struct drm_connector_helper_funcs rockchip_virtual_connector_helper_funcs = { .get_modes = vvop_conn_get_modes, }; static int rockchip_virtual_connector_register(struct rockchip_vconn *vconn) { struct vconn_device *vconn_dev, *n; struct drm_encoder *encoder; struct drm_connector *connector; int ret; list_for_each_entry_safe(vconn_dev, n, &vconn->list_head, list) { encoder = &vconn_dev->encoder; connector = &vconn_dev->connector; encoder->possible_crtcs = vconn_dev->vp_id_mask; drm_encoder_helper_add(encoder, &rockchip_virtual_encoder_helper_funcs); ret = drm_simple_encoder_init(vconn->drm_dev, encoder, vconn_dev->encoder_type); if (ret < 0) { dev_err(vconn->dev, "failed to register encoder for output%d", ffs(vconn_dev->if_id) - 1); return ret; } drm_connector_helper_add(connector, &rockchip_virtual_connector_helper_funcs); ret = drm_connector_init(vconn->drm_dev, connector, &rockchip_virtual_connector_funcs, vconn_dev->output_type); if (ret) { dev_err(vconn->dev, "Failed to initialize connector for output%d\n", ffs(vconn_dev->if_id) - 1); return ret; } drm_connector_attach_encoder(connector, encoder); } return 0; } static int rockchip_vconn_parse_vp_id(struct rockchip_vconn *vconn, const char *name) { struct device_node *np = vconn->dev->of_node; char propname[16]; int ret; u32 id; if (strlen(name) > 6) { dev_err(vconn->dev, "invalid connector name %s\n", name); return -EINVAL; } snprintf(propname, sizeof(propname), "%s-enable", name); if (of_property_read_bool(np, propname)) { snprintf(propname, sizeof(propname), "%s-vp-id", name); ret = of_property_read_u32(np, propname, &id); if (ret < 0) { dev_err(vconn->dev, "no specific vp-id for %s\n", name); return ret; } return id; } return -ENODEV; } static int rockchip_vconn_get_encoder_type(int conn_type) { if (conn_type == DRM_MODE_CONNECTOR_DSI) return DRM_MODE_ENCODER_DSI; else if (conn_type == DRM_MODE_CONNECTOR_DPI) return DRM_MODE_ENCODER_DPI; else if (conn_type == DRM_MODE_CONNECTOR_VIRTUAL) return DRM_MODE_ENCODER_VIRTUAL; else return DRM_MODE_ENCODER_TMDS; } static int rockchip_vconn_device_create(struct rockchip_vconn *vconn, const char *name, int conn_type, int output_mode, int bus_format, int if_id) { struct vconn_device *vconn_dev; int id; id = rockchip_vconn_parse_vp_id(vconn, name); if (id >= 0) { vconn_dev = devm_kzalloc(vconn->dev, sizeof(*vconn_dev), GFP_KERNEL); if (!vconn_dev) return -ENOMEM; vconn_dev->vconn = vconn; vconn_dev->encoder_type = rockchip_vconn_get_encoder_type(conn_type); vconn_dev->output_type = conn_type; vconn_dev->output_mode = output_mode; vconn_dev->bus_format = bus_format; vconn_dev->if_id = if_id; vconn_dev->vp_id_mask = BIT(id); list_add_tail(&vconn_dev->list, &vconn->list_head); } return 0; } static int rockchip_virtual_connectors_create(struct rockchip_vconn *vconn) { struct device_node *np = vconn->dev->of_node; struct vconn_device *vconn_dev; char propname[64]; u32 count; int i; int ret; ret = of_property_read_u32(np, "virtual-connector-count", &count); if (ret) return ret; for (i = 0; i < count; i++) { vconn_dev = devm_kzalloc(vconn->dev, sizeof(*vconn_dev), GFP_KERNEL); if (!vconn_dev) return -ENOMEM; snprintf(propname, sizeof(propname), "virtual%d-disconnected", i); vconn_dev->connected = !of_property_read_bool(np, propname); vconn_dev->vconn = vconn; vconn_dev->encoder_type = DRM_MODE_ENCODER_VIRTUAL; vconn_dev->output_type = DRM_MODE_CONNECTOR_VIRTUAL; vconn_dev->output_mode = ROCKCHIP_OUT_MODE_AAAA; vconn_dev->bus_format = MEDIA_BUS_FMT_FIXED; vconn_dev->if_id = 0; vconn_dev->vp_id_mask = 0; list_add_tail(&vconn_dev->list, &vconn->list_head); } return 0; } static int rockchip_virtual_connector_bind(struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct rockchip_vconn *vconn; if (!pdev->dev.of_node) return -ENODEV; vconn = devm_kzalloc(&pdev->dev, sizeof(*vconn), GFP_KERNEL); if (!vconn) return -ENOMEM; vconn->dev = dev; vconn->drm_dev = drm; INIT_LIST_HEAD(&vconn->list_head); rockchip_vconn_device_create(vconn, "hdmi0", DRM_MODE_CONNECTOR_HDMIA, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_HDMI0); rockchip_vconn_device_create(vconn, "hdmi1", DRM_MODE_CONNECTOR_HDMIA, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_HDMI1); rockchip_vconn_device_create(vconn, "dp0", DRM_MODE_CONNECTOR_DisplayPort, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_DP0); rockchip_vconn_device_create(vconn, "dp1", DRM_MODE_CONNECTOR_DisplayPort, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_DP1); rockchip_vconn_device_create(vconn, "edp0", DRM_MODE_CONNECTOR_eDP, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_eDP0); rockchip_vconn_device_create(vconn, "edp0", DRM_MODE_CONNECTOR_eDP, ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_eDP1); rockchip_vconn_device_create(vconn, "mipi0", DRM_MODE_CONNECTOR_DSI, ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_MIPI0); rockchip_vconn_device_create(vconn, "mipi1", DRM_MODE_CONNECTOR_DSI, ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_MIPI1); rockchip_vconn_device_create(vconn, "rgb", DRM_MODE_CONNECTOR_DPI, ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24, VOP_OUTPUT_IF_RGB); rockchip_virtual_connectors_create(vconn); platform_set_drvdata(pdev, vconn); rockchip_virtual_connector_register(vconn); return 0; } static void rockchip_virtual_connector_unbind(struct device *dev, struct device *master, void *data) { } static const struct component_ops rockchip_virtual_connector_ops = { .bind = rockchip_virtual_connector_bind, .unbind = rockchip_virtual_connector_unbind, }; static int rockchip_virtual_connector_probe(struct platform_device *pdev) { return component_add(&pdev->dev, &rockchip_virtual_connector_ops); } static void rockchip_virtual_connector_shutdown(struct platform_device *pdev) { } static int rockchip_virtual_connector_remove(struct platform_device *pdev) { component_del(&pdev->dev, &rockchip_virtual_connector_ops); return 0; } static const struct of_device_id rockchip_virtual_connector_dt_ids[] = { { .compatible = "rockchip,virtual-connector", }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_virtual_connector_dt_ids); struct platform_driver vconn_platform_driver = { .probe = rockchip_virtual_connector_probe, .remove = rockchip_virtual_connector_remove, .shutdown = rockchip_virtual_connector_shutdown, .driver = { .name = "drm-virtual-connector", .of_match_table = rockchip_virtual_connector_dt_ids, }, };