[5/8] drm/loongson: Using vbios for the LS7A2000 output initialization
Commit Message
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
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
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
@@ -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);
}