[5/8] drm/loongson: Using vbios for the LS7A2000 output initialization

Message ID 20231029194607.379459-6-suijingfeng@loongson.cn
State New
Headers
Series drm/loongson: Submit a mini VBIOS support and a display bridge driver |

Commit Message

Sui Jingfeng Oct. 29, 2023, 7:46 p.m. UTC
  For LS7A2000, the built-in VGA encoder is transparent. Connect another
external transmitter with this internal VGA encoder is not sane, thus is
not allowed. Because there are two internal encoders hardware resource on
the first display pipe, call loongson_vbios_query_encoder_info() to know
what exatly the output configutaion is. Either VGA or HDMI display output
interface, but not both. And formal products should not export three
display connector interfaces. As the hardware has two-way I2Cs and two
CRTCs. So with this observation, we can untangle more.

If there a need to extend(transform) the output interface type, then the
internal HDMI phy MUST be enabled and initialized. External transmitters
must take the HDMI signal as input, this is the only choices. Such as
lt6711(HDMI to eDP), lt8619(HDMI to LVDS) etc.

Before apply this patch, ls7a2000_output_init() is simplified function
which assumed that there is no external display bridge attached. This
naive abstraction no longer suit the needs in the long run. Hence, switch
to call the newly implemented lsdc_output_init() function, which allow us
model the external encoder as a drm display bridge. The driver of this drm
display bridge should reside in the same kernel module with drm/loongson.
We will attach it by ourself, and rely on the VBIOS tell us which display
pipe has what display bridge connected.

Signed-off-by: Sui Jingfeng <suijingfeng@loongson.cn>
---
 drivers/gpu/drm/loongson/lsdc_output_7a2000.c | 154 ++++++++++++++----
 1 file changed, 124 insertions(+), 30 deletions(-)
  

Comments

kernel test robot Oct. 30, 2023, 2:28 a.m. UTC | #1
Hi Sui,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master v6.6-rc7 next-20231027]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sui-Jingfeng/drm-loongson-Introduce-a-minimal-support-for-Loongson-VBIOS/20231030-034730
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20231029194607.379459-6-suijingfeng%40loongson.cn
patch subject: [PATCH 5/8] drm/loongson: Using vbios for the LS7A2000 output initialization
config: loongarch-randconfig-002-20231030 (https://download.01.org/0day-ci/archive/20231030/202310301026.haj8ZOHJ-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231030/202310301026.haj8ZOHJ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202310301026.haj8ZOHJ-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/gpu/drm/loongson/lsdc_output_7a2000.c:568:1: warning: no previous prototype for 'ls7a2000_query_output_configuration' [-Wmissing-prototypes]
     568 | ls7a2000_query_output_configuration(struct drm_device *ddev, unsigned int pipe)
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/loongson/lsdc_output_7a2000.c:498:46: warning: 'ls7a2000_encoder_helper_funcs' defined but not used [-Wunused-const-variable=]
     498 | static const struct drm_encoder_helper_funcs ls7a2000_encoder_helper_funcs = {
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/loongson/lsdc_output_7a2000.c:272:39: warning: 'ls7a2000_encoder_funcs' defined but not used [-Wunused-const-variable=]
     272 | static const struct drm_encoder_funcs ls7a2000_encoder_funcs[2] = {
         |                                       ^~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/loongson/lsdc_output_7a2000.c:201:41: warning: 'ls7a2000_hdmi_connector_funcs' defined but not used [-Wunused-const-variable=]
     201 | static const struct drm_connector_funcs ls7a2000_hdmi_connector_funcs[2] = {
         |                                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpu/drm/loongson/lsdc_output_7a2000.c:77:48: warning: 'ls7a2000_connector_helpers' defined but not used [-Wunused-const-variable=]
      77 | static const struct drm_connector_helper_funcs ls7a2000_connector_helpers = {
         |                                                ^~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/ls7a2000_query_output_configuration +568 drivers/gpu/drm/loongson/lsdc_output_7a2000.c

   559	
   560	/*
   561	 * For LS7A2000, the built-in VGA encoder is transparent. If there are
   562	 * external encoder exist, then the internal HDMI encoder MUST be enabled
   563	 * and initialized. As the internal HDMI encoder is always connected, so
   564	 * only the transmitters which take HDMI signal (such as HDMI to eDP, HDMI
   565	 * to LVDS, etc) are usable with.
   566	 */
   567	const struct lsdc_output_desc *
 > 568	ls7a2000_query_output_configuration(struct drm_device *ddev, unsigned int pipe)
   569	{
   570		enum loongson_vbios_encoder_name encoder_name = 0;
   571		bool ret;
   572	
   573		ret = loongson_vbios_query_encoder_info(ddev, pipe, NULL,
   574							&encoder_name, NULL);
   575		if (!ret)
   576			goto bailout;
   577	
   578		if (pipe == 0) {
   579			switch (encoder_name) {
   580			case ENCODER_CHIP_INTERNAL_HDMI:
   581				return &ls7a2000_hdmi_pipe0;
   582	
   583			/*
   584			 * For LS7A2000, the built-in VGA encoder is transparent.
   585			 */
   586			case ENCODER_CHIP_INTERNAL_VGA:
   587				return &ls7a2000_vga_pipe0;
   588	
   589			/*
   590			 * External display bridge exists, the internal HDMI encoder
   591			 * MUST be enabled and initialized. Please add a drm bridge
   592			 * driver, and attach to this encoder.
   593			 */
   594			default:
   595				return &ls7a2000_hdmi_pipe0;
   596			}
   597		}
   598	
   599		if (pipe == 1) {
   600			switch (encoder_name) {
   601			case ENCODER_CHIP_INTERNAL_HDMI:
   602				return &ls7a2000_hdmi_pipe1;
   603	
   604			/*
   605			 * External display bridge exists, the internal HDMI encoder
   606			 * MUST be enabled and initialized. Please add a drm bridge
   607			 * driver, and attach it to this encoder.
   608			 */
   609			default:
   610				return &ls7a2000_hdmi_pipe1;
   611			}
   612		}
   613	
   614	bailout:
   615		if (pipe == 0)
   616			return &ls7a2000_vga_pipe0;
   617	
   618		if (pipe == 1)
   619			return &ls7a2000_hdmi_pipe1;
   620	
   621		return NULL;
   622	}
   623
  
kernel test robot Nov. 6, 2023, 5:46 p.m. UTC | #2
Hi Sui,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master v6.6 next-20231106]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sui-Jingfeng/drm-loongson-Introduce-a-minimal-support-for-Loongson-VBIOS/20231030-034730
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20231029194607.379459-6-suijingfeng%40loongson.cn
patch subject: [PATCH 5/8] drm/loongson: Using vbios for the LS7A2000 output initialization
config: x86_64-randconfig-122-20231102 (https://download.01.org/0day-ci/archive/20231107/202311070048.L62vVvHE-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231107/202311070048.L62vVvHE-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311070048.L62vVvHE-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/loongson/lsdc_output_7a2000.c:567:31: sparse: sparse: symbol 'ls7a2000_query_output_configuration' was not declared. Should it be static?

vim +/ls7a2000_query_output_configuration +567 drivers/gpu/drm/loongson/lsdc_output_7a2000.c

   559	
   560	/*
   561	 * For LS7A2000, the built-in VGA encoder is transparent. If there are
   562	 * external encoder exist, then the internal HDMI encoder MUST be enabled
   563	 * and initialized. As the internal HDMI encoder is always connected, so
   564	 * only the transmitters which take HDMI signal (such as HDMI to eDP, HDMI
   565	 * to LVDS, etc) are usable with.
   566	 */
 > 567	const struct lsdc_output_desc *
   568	ls7a2000_query_output_configuration(struct drm_device *ddev, unsigned int pipe)
   569	{
   570		enum loongson_vbios_encoder_name encoder_name = 0;
   571		bool ret;
   572	
   573		ret = loongson_vbios_query_encoder_info(ddev, pipe, NULL,
   574							&encoder_name, NULL);
   575		if (!ret)
   576			goto bailout;
   577	
   578		if (pipe == 0) {
   579			switch (encoder_name) {
   580			case ENCODER_CHIP_INTERNAL_HDMI:
   581				return &ls7a2000_hdmi_pipe0;
   582	
   583			/*
   584			 * For LS7A2000, the built-in VGA encoder is transparent.
   585			 */
   586			case ENCODER_CHIP_INTERNAL_VGA:
   587				return &ls7a2000_vga_pipe0;
   588	
   589			/*
   590			 * External display bridge exists, the internal HDMI encoder
   591			 * MUST be enabled and initialized. Please add a drm bridge
   592			 * driver, and attach to this encoder.
   593			 */
   594			default:
   595				return &ls7a2000_hdmi_pipe0;
   596			}
   597		}
   598	
   599		if (pipe == 1) {
   600			switch (encoder_name) {
   601			case ENCODER_CHIP_INTERNAL_HDMI:
   602				return &ls7a2000_hdmi_pipe1;
   603	
   604			/*
   605			 * External display bridge exists, the internal HDMI encoder
   606			 * MUST be enabled and initialized. Please add a drm bridge
   607			 * driver, and attach it to this encoder.
   608			 */
   609			default:
   610				return &ls7a2000_hdmi_pipe1;
   611			}
   612		}
   613	
   614	bailout:
   615		if (pipe == 0)
   616			return &ls7a2000_vga_pipe0;
   617	
   618		if (pipe == 1)
   619			return &ls7a2000_hdmi_pipe1;
   620	
   621		return NULL;
   622	}
   623
  

Patch

diff --git a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
index ce3dabec887e..bf558b61802b 100644
--- a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
+++ b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
@@ -501,6 +501,126 @@  static const struct drm_encoder_helper_funcs ls7a2000_encoder_helper_funcs = {
 	.atomic_mode_set = ls7a2000_hdmi_atomic_mode_set,
 };
 
+/* The built-in tranparent VGA encoder is only available on display pipe 0 */
+static void ls7a2000_pipe0_vga_encoder_reset(struct drm_encoder *encoder)
+{
+	struct lsdc_device *ldev = to_lsdc(encoder->dev);
+	u32 val = PHY_CLOCK_POL | PHY_CLOCK_EN | PHY_DATA_EN;
+
+	lsdc_wreg32(ldev, LSDC_CRTC0_DVO_CONF_REG, val);
+
+	/*
+	 * The firmware set LSDC_HDMIx_CTRL_REG blindly to use hardware I2C,
+	 * which is may not works because of hardware bug. We using built-in
+	 * GPIO emulated I2C instead of the hardware I2C here.
+	 */
+	lsdc_ureg32_clr(ldev, LSDC_HDMI0_INTF_CTRL_REG, HW_I2C_EN);
+
+	mdelay(20);
+}
+
+static const struct drm_encoder_funcs ls7a2000_pipe0_vga_encoder_funcs = {
+	.reset = ls7a2000_pipe0_vga_encoder_reset,
+	.destroy = drm_encoder_cleanup,
+};
+
+static const struct lsdc_output_desc ls7a2000_vga_pipe0 = {
+	.pipe = 0,
+	.encoder_type = DRM_MODE_ENCODER_DAC,
+	.connector_type = DRM_MODE_CONNECTOR_VGA,
+	.encoder_funcs = &ls7a2000_pipe0_vga_encoder_funcs,
+	.encoder_helper_funcs = &lsdc_pipe0_hdmi_encoder_helper_funcs,
+	.connector_funcs = &lsdc_connector_funcs,
+	.connector_helper_funcs = &lsdc_connector_helper_funcs,
+	.name = "VGA-0",
+};
+
+static const struct lsdc_output_desc ls7a2000_hdmi_pipe0 = {
+	.pipe = 0,
+	.encoder_type = DRM_MODE_ENCODER_TMDS,
+	.connector_type = DRM_MODE_CONNECTOR_HDMIA,
+	.encoder_funcs = &lsdc_pipe0_hdmi_encoder_funcs,
+	.encoder_helper_funcs = &lsdc_pipe0_hdmi_encoder_helper_funcs,
+	.connector_funcs = &lsdc_pipe0_hdmi_connector_funcs,
+	.connector_helper_funcs = &lsdc_connector_helper_funcs,
+	.name = "HDMI-0",
+};
+
+static const struct lsdc_output_desc ls7a2000_hdmi_pipe1 = {
+	.pipe = 1,
+	.encoder_type = DRM_MODE_ENCODER_TMDS,
+	.connector_type = DRM_MODE_CONNECTOR_HDMIA,
+	.encoder_funcs = &lsdc_pipe1_hdmi_encoder_funcs,
+	.encoder_helper_funcs = &lsdc_pipe1_hdmi_encoder_helper_funcs,
+	.connector_funcs = &lsdc_pipe1_hdmi_connector_funcs,
+	.connector_helper_funcs = &lsdc_connector_helper_funcs,
+	.name = "HDMI-1",
+};
+
+/*
+ * For LS7A2000, the built-in VGA encoder is transparent. If there are
+ * external encoder exist, then the internal HDMI encoder MUST be enabled
+ * and initialized. As the internal HDMI encoder is always connected, so
+ * only the transmitters which take HDMI signal (such as HDMI to eDP, HDMI
+ * to LVDS, etc) are usable with.
+ */
+const struct lsdc_output_desc *
+ls7a2000_query_output_configuration(struct drm_device *ddev, unsigned int pipe)
+{
+	enum loongson_vbios_encoder_name encoder_name = 0;
+	bool ret;
+
+	ret = loongson_vbios_query_encoder_info(ddev, pipe, NULL,
+						&encoder_name, NULL);
+	if (!ret)
+		goto bailout;
+
+	if (pipe == 0) {
+		switch (encoder_name) {
+		case ENCODER_CHIP_INTERNAL_HDMI:
+			return &ls7a2000_hdmi_pipe0;
+
+		/*
+		 * For LS7A2000, the built-in VGA encoder is transparent.
+		 */
+		case ENCODER_CHIP_INTERNAL_VGA:
+			return &ls7a2000_vga_pipe0;
+
+		/*
+		 * External display bridge exists, the internal HDMI encoder
+		 * MUST be enabled and initialized. Please add a drm bridge
+		 * driver, and attach to this encoder.
+		 */
+		default:
+			return &ls7a2000_hdmi_pipe0;
+		}
+	}
+
+	if (pipe == 1) {
+		switch (encoder_name) {
+		case ENCODER_CHIP_INTERNAL_HDMI:
+			return &ls7a2000_hdmi_pipe1;
+
+		/*
+		 * External display bridge exists, the internal HDMI encoder
+		 * MUST be enabled and initialized. Please add a drm bridge
+		 * driver, and attach it to this encoder.
+		 */
+		default:
+			return &ls7a2000_hdmi_pipe1;
+		}
+	}
+
+bailout:
+	if (pipe == 0)
+		return &ls7a2000_vga_pipe0;
+
+	if (pipe == 1)
+		return &ls7a2000_hdmi_pipe1;
+
+	return NULL;
+}
+
 /*
  * For LS7A2000:
  *
@@ -517,36 +637,10 @@  int ls7a2000_output_init(struct drm_device *ddev,
 			 unsigned int pipe)
 {
 	struct lsdc_output *output = &dispipe->output;
-	struct drm_encoder *encoder = &output->encoder;
-	struct drm_connector *connector = &output->connector;
-	int ret;
-
-	ret = drm_encoder_init(ddev, encoder, &ls7a2000_encoder_funcs[pipe],
-			       DRM_MODE_ENCODER_TMDS, "encoder-%u", pipe);
-	if (ret)
-		return ret;
-
-	encoder->possible_crtcs = BIT(pipe);
-
-	drm_encoder_helper_add(encoder, &ls7a2000_encoder_helper_funcs);
-
-	ret = drm_connector_init_with_ddc(ddev, connector,
-					  &ls7a2000_hdmi_connector_funcs[pipe],
-					  DRM_MODE_CONNECTOR_HDMIA, ddc);
-	if (ret)
-		return ret;
 
-	drm_info(ddev, "display pipe-%u has HDMI %s\n", pipe, pipe ? "" : "and/or VGA");
+	output->descp = ls7a2000_query_output_configuration(ddev, pipe);
+	if (!output->descp)
+		return -EINVAL;
 
-	drm_connector_helper_add(connector, &ls7a2000_connector_helpers);
-
-	drm_connector_attach_encoder(connector, encoder);
-
-	connector->polled = DRM_CONNECTOR_POLL_CONNECT |
-			    DRM_CONNECTOR_POLL_DISCONNECT;
-
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-
-	return 0;
+	return lsdc_output_init(ddev, dispipe, ddc, pipe);
 }