@@ -760,19 +760,62 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
760760{
761761}
762762
763+ #define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
764+ #define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
765+
766+ static int vc4_hdmi_encoder_atomic_check (struct drm_encoder * encoder ,
767+ struct drm_crtc_state * crtc_state ,
768+ struct drm_connector_state * conn_state )
769+ {
770+ struct drm_display_mode * mode = & crtc_state -> adjusted_mode ;
771+ struct vc4_hdmi * vc4_hdmi = encoder_to_vc4_hdmi (encoder );
772+ unsigned long long pixel_rate = mode -> clock * 1000 ;
773+ unsigned long long tmds_rate ;
774+
775+ if (vc4_hdmi -> variant -> unsupported_odd_h_timings &&
776+ ((mode -> hdisplay % 2 ) || (mode -> hsync_start % 2 ) ||
777+ (mode -> hsync_end % 2 ) || (mode -> htotal % 2 )))
778+ return - EINVAL ;
779+
780+ /*
781+ * The 1440p@60 pixel rate is in the same range than the first
782+ * WiFi channel (between 2.4GHz and 2.422GHz with 22MHz
783+ * bandwidth). Slightly lower the frequency to bring it out of
784+ * the WiFi range.
785+ */
786+ tmds_rate = pixel_rate * 10 ;
787+ if (vc4_hdmi -> disable_wifi_frequencies &&
788+ (tmds_rate >= WIFI_2_4GHz_CH1_MIN_FREQ &&
789+ tmds_rate <= WIFI_2_4GHz_CH1_MAX_FREQ )) {
790+ mode -> clock = 238560 ;
791+ pixel_rate = mode -> clock * 1000 ;
792+ }
793+
794+ if (pixel_rate > vc4_hdmi -> variant -> max_pixel_clock )
795+ return - EINVAL ;
796+
797+ return 0 ;
798+ }
799+
763800static enum drm_mode_status
764801vc4_hdmi_encoder_mode_valid (struct drm_encoder * encoder ,
765802 const struct drm_display_mode * mode )
766803{
767804 struct vc4_hdmi * vc4_hdmi = encoder_to_vc4_hdmi (encoder );
768805
806+ if (vc4_hdmi -> variant -> unsupported_odd_h_timings &&
807+ ((mode -> hdisplay % 2 ) || (mode -> hsync_start % 2 ) ||
808+ (mode -> hsync_end % 2 ) || (mode -> htotal % 2 )))
809+ return MODE_H_ILLEGAL ;
810+
769811 if ((mode -> clock * 1000 ) > vc4_hdmi -> variant -> max_pixel_clock )
770812 return MODE_CLOCK_HIGH ;
771813
772814 return MODE_OK ;
773815}
774816
775817static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
818+ .atomic_check = vc4_hdmi_encoder_atomic_check ,
776819 .mode_valid = vc4_hdmi_encoder_mode_valid ,
777820 .disable = vc4_hdmi_encoder_disable ,
778821 .enable = vc4_hdmi_encoder_enable ,
@@ -1694,6 +1737,9 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
16941737 vc4_hdmi -> hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW ;
16951738 }
16961739
1740+ vc4_hdmi -> disable_wifi_frequencies =
1741+ of_property_read_bool (dev -> of_node , "wifi-2.4ghz-coexistence" );
1742+
16971743 pm_runtime_enable (dev );
16981744
16991745 drm_simple_encoder_init (drm , encoder , DRM_MODE_ENCODER_TMDS );
@@ -1817,6 +1863,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
18171863 PHY_LANE_2 ,
18181864 PHY_LANE_CK ,
18191865 },
1866+ .unsupported_odd_h_timings = true,
18201867
18211868 .init_resources = vc5_hdmi_init_resources ,
18221869 .csc_setup = vc5_hdmi_csc_setup ,
@@ -1842,6 +1889,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
18421889 PHY_LANE_CK ,
18431890 PHY_LANE_2 ,
18441891 },
1892+ .unsupported_odd_h_timings = true,
18451893
18461894 .init_resources = vc5_hdmi_init_resources ,
18471895 .csc_setup = vc5_hdmi_csc_setup ,
0 commit comments