1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2023 Loongson Technology Corporation Limited 4 */ 5 6 #include <drm/drm_atomic_helper.h> 7 #include <drm/drm_edid.h> 8 #include <drm/drm_probe_helper.h> 9 10 #include "lsdc_drv.h" 11 #include "lsdc_output.h" 12 13 /* 14 * The display controller in the LS7A1000 exports two DVO interfaces, thus 15 * external encoder is required, except connected to the DPI panel directly. 16 * 17 * ___________________ _________ 18 * | -------| | | 19 * | CRTC0 --> | DVO0 ----> Encoder0 ---> Connector0 ---> | Display | 20 * | _ _ -------| ^ ^ |_________| 21 * | | | | | +------+ | | | 22 * | |_| |_| | i2c6 | <--------+-------------+ 23 * | +------+ | 24 * | | 25 * | DC in LS7A1000 | 26 * | | 27 * | _ _ +------+ | 28 * | | | | | | i2c7 | <--------+-------------+ 29 * | |_| |_| +------+ | | | _________ 30 * | -------| | | | | 31 * | CRTC1 --> | DVO1 ----> Encoder1 ---> Connector1 ---> | Panel | 32 * | -------| |_________| 33 * |___________________| 34 * 35 * Currently, we assume the external encoders connected to the DVO are 36 * transparent. Loongson's DVO interface can directly drive RGB888 panels. 37 * 38 * TODO: Add support for non-transparent encoders 39 */ 40 41 static int ls7a1000_dpi_connector_get_modes(struct drm_connector *conn) 42 { 43 unsigned int num = 0; 44 struct edid *edid; 45 46 if (conn->ddc) { 47 edid = drm_get_edid(conn, conn->ddc); 48 if (edid) { 49 drm_connector_update_edid_property(conn, edid); 50 num = drm_add_edid_modes(conn, edid); 51 kfree(edid); 52 } 53 54 return num; 55 } 56 57 num = drm_add_modes_noedid(conn, 1920, 1200); 58 59 drm_set_preferred_mode(conn, 1024, 768); 60 61 return num; 62 } 63 64 static struct drm_encoder * 65 ls7a1000_dpi_connector_get_best_encoder(struct drm_connector *connector, 66 struct drm_atomic_state *state) 67 { 68 struct lsdc_output *output = connector_to_lsdc_output(connector); 69 70 return &output->encoder; 71 } 72 73 static const struct drm_connector_helper_funcs 74 ls7a1000_dpi_connector_helpers = { 75 .atomic_best_encoder = ls7a1000_dpi_connector_get_best_encoder, 76 .get_modes = ls7a1000_dpi_connector_get_modes, 77 }; 78 79 static enum drm_connector_status 80 ls7a1000_dpi_connector_detect(struct drm_connector *connector, bool force) 81 { 82 struct i2c_adapter *ddc = connector->ddc; 83 84 if (ddc) { 85 if (drm_probe_ddc(ddc)) 86 return connector_status_connected; 87 88 return connector_status_disconnected; 89 } 90 91 return connector_status_unknown; 92 } 93 94 static const struct drm_connector_funcs ls7a1000_dpi_connector_funcs = { 95 .detect = ls7a1000_dpi_connector_detect, 96 .fill_modes = drm_helper_probe_single_connector_modes, 97 .destroy = drm_connector_cleanup, 98 .reset = drm_atomic_helper_connector_reset, 99 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 100 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state 101 }; 102 103 static void ls7a1000_pipe0_encoder_reset(struct drm_encoder *encoder) 104 { 105 struct drm_device *ddev = encoder->dev; 106 struct lsdc_device *ldev = to_lsdc(ddev); 107 108 /* 109 * We need this for S3 support, screen will not lightup if don't set 110 * this register correctly. 111 */ 112 lsdc_wreg32(ldev, LSDC_CRTC0_DVO_CONF_REG, 113 PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN); 114 } 115 116 static void ls7a1000_pipe1_encoder_reset(struct drm_encoder *encoder) 117 { 118 struct drm_device *ddev = encoder->dev; 119 struct lsdc_device *ldev = to_lsdc(ddev); 120 121 /* 122 * We need this for S3 support, screen will not lightup if don't set 123 * this register correctly. 124 */ 125 126 /* DVO */ 127 lsdc_wreg32(ldev, LSDC_CRTC1_DVO_CONF_REG, 128 BIT(31) | PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN); 129 } 130 131 static const struct drm_encoder_funcs ls7a1000_encoder_funcs[2] = { 132 { 133 .reset = ls7a1000_pipe0_encoder_reset, 134 .destroy = drm_encoder_cleanup, 135 }, 136 { 137 .reset = ls7a1000_pipe1_encoder_reset, 138 .destroy = drm_encoder_cleanup, 139 }, 140 }; 141 142 int ls7a1000_output_init(struct drm_device *ddev, 143 struct lsdc_display_pipe *dispipe, 144 struct i2c_adapter *ddc, 145 unsigned int index) 146 { 147 struct lsdc_output *output = &dispipe->output; 148 struct drm_encoder *encoder = &output->encoder; 149 struct drm_connector *connector = &output->connector; 150 int ret; 151 152 ret = drm_encoder_init(ddev, encoder, &ls7a1000_encoder_funcs[index], 153 DRM_MODE_ENCODER_TMDS, "encoder-%u", index); 154 if (ret) 155 return ret; 156 157 encoder->possible_crtcs = BIT(index); 158 159 ret = drm_connector_init_with_ddc(ddev, connector, 160 &ls7a1000_dpi_connector_funcs, 161 DRM_MODE_CONNECTOR_DPI, ddc); 162 if (ret) 163 return ret; 164 165 drm_info(ddev, "display pipe-%u has a DVO\n", index); 166 167 drm_connector_helper_add(connector, &ls7a1000_dpi_connector_helpers); 168 169 drm_connector_attach_encoder(connector, encoder); 170 171 connector->polled = DRM_CONNECTOR_POLL_CONNECT | 172 DRM_CONNECTOR_POLL_DISCONNECT; 173 174 connector->interlace_allowed = 0; 175 connector->doublescan_allowed = 0; 176 177 return 0; 178 } 179