@@ -79,9 +79,15 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
7979 int div , ret ;
8080 bool is_xlcdc = crtc -> dc -> desc -> is_xlcdc ;
8181
82- ret = clk_prepare_enable (crtc -> dc -> hlcdc -> sys_clk );
83- if (ret )
84- return ;
82+ if (crtc -> dc -> hlcdc -> lvds_pll_clk ) {
83+ ret = clk_prepare_enable (crtc -> dc -> hlcdc -> lvds_pll_clk );
84+ if (ret )
85+ return ;
86+ } else {
87+ ret = clk_prepare_enable (crtc -> dc -> hlcdc -> sys_clk );
88+ if (ret )
89+ return ;
90+ }
8591
8692 vm .vfront_porch = adj -> crtc_vsync_start - adj -> crtc_vdisplay ;
8793 vm .vback_porch = adj -> crtc_vtotal - adj -> crtc_vsync_end ;
@@ -103,39 +109,44 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
103109 (adj -> crtc_hdisplay - 1 ) |
104110 ((adj -> crtc_vdisplay - 1 ) << 16 ));
105111
106- prate = clk_get_rate (crtc -> dc -> hlcdc -> sys_clk );
107- mode_rate = adj -> crtc_clock * 1000 ;
108- if (!crtc -> dc -> desc -> fixed_clksrc ) {
109- prate *= 2 ;
110- cfg |= ATMEL_HLCDC_CLKSEL ;
111- mask |= ATMEL_HLCDC_CLKSEL ;
112- }
112+ if (crtc -> dc -> hlcdc -> lvds_pll_clk ) {
113+ cfg |= ATMEL_XLCDC_CLKBYP ;
114+ mask |= ATMEL_XLCDC_CLKBYP ;
115+ } else {
116+ prate = clk_get_rate (crtc -> dc -> hlcdc -> sys_clk );
117+ mode_rate = adj -> crtc_clock * 1000 ;
118+ if (!crtc -> dc -> desc -> fixed_clksrc ) {
119+ prate *= 2 ;
120+ cfg |= ATMEL_HLCDC_CLKSEL ;
121+ mask |= ATMEL_HLCDC_CLKSEL ;
122+ }
113123
114- div = DIV_ROUND_UP (prate , mode_rate );
115- if (div < 2 ) {
116- div = 2 ;
117- } else if (ATMEL_HLCDC_CLKDIV (div ) & ~ATMEL_HLCDC_CLKDIV_MASK ) {
118- /* The divider ended up too big, try a lower base rate. */
119- cfg &= ~ATMEL_HLCDC_CLKSEL ;
120- prate /= 2 ;
121124 div = DIV_ROUND_UP (prate , mode_rate );
122- if (ATMEL_HLCDC_CLKDIV (div ) & ~ATMEL_HLCDC_CLKDIV_MASK )
123- div = ATMEL_HLCDC_CLKDIV_MASK ;
124- } else {
125- int div_low = prate / mode_rate ;
125+ if (div < 2 ) {
126+ div = 2 ;
127+ } else if (ATMEL_HLCDC_CLKDIV (div ) & ~ATMEL_HLCDC_CLKDIV_MASK ) {
128+ /* The divider ended up too big, try a lower base rate. */
129+ cfg &= ~ATMEL_HLCDC_CLKSEL ;
130+ prate /= 2 ;
131+ div = DIV_ROUND_UP (prate , mode_rate );
132+ if (ATMEL_HLCDC_CLKDIV (div ) & ~ATMEL_HLCDC_CLKDIV_MASK )
133+ div = ATMEL_HLCDC_CLKDIV_MASK ;
134+ } else {
135+ int div_low = prate / mode_rate ;
126136
127- if (div_low >= 2 &&
128- (10 * (prate / div_low - mode_rate ) <
129- (mode_rate - prate / div )))
130137 /*
131- * At least 10 times better when using a higher
138+ * Its better to use a higher Pixel clock
132139 * frequency than requested, instead of a lower.
133140 * So, go with that.
134141 */
135- div = div_low ;
136- }
137142
138- cfg |= ATMEL_HLCDC_CLKDIV (div );
143+ if (div_low >= 2 &&
144+ ((prate / div_low >= mode_rate ) &&
145+ (prate / div < mode_rate )))
146+ div = div_low ;
147+ }
148+ cfg |= ATMEL_HLCDC_CLKDIV (div );
149+ }
139150
140151 regmap_update_bits (regmap , ATMEL_HLCDC_CFG (0 ), mask , cfg );
141152
@@ -160,7 +171,10 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
160171 ATMEL_XLCDC_DPI : ATMEL_HLCDC_MODE_MASK ),
161172 cfg );
162173
163- clk_disable_unprepare (crtc -> dc -> hlcdc -> sys_clk );
174+ if (crtc -> dc -> hlcdc -> lvds_pll_clk )
175+ clk_disable_unprepare (crtc -> dc -> hlcdc -> lvds_pll_clk );
176+ else
177+ clk_disable_unprepare (crtc -> dc -> hlcdc -> sys_clk );
164178}
165179
166180static enum drm_mode_status
@@ -213,7 +227,11 @@ static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
213227 (status & ATMEL_HLCDC_PIXEL_CLK ))
214228 cpu_relax ();
215229
216- clk_disable_unprepare (crtc -> dc -> hlcdc -> sys_clk );
230+ if (crtc -> dc -> hlcdc -> lvds_pll_clk )
231+ clk_disable_unprepare (crtc -> dc -> hlcdc -> lvds_pll_clk );
232+ else
233+ clk_disable_unprepare (crtc -> dc -> hlcdc -> sys_clk );
234+
217235 pinctrl_pm_select_sleep_state (dev -> dev );
218236
219237 pm_runtime_allow (dev -> dev );
@@ -226,15 +244,37 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
226244{
227245 struct drm_device * dev = c -> dev ;
228246 struct atmel_hlcdc_crtc * crtc = drm_crtc_to_atmel_hlcdc_crtc (c );
247+ struct drm_display_mode * adj = & c -> state -> adjusted_mode ;
229248 struct regmap * regmap = crtc -> dc -> hlcdc -> regmap ;
230249 unsigned int status ;
250+ int ret ;
231251
232252 pm_runtime_get_sync (dev -> dev );
233253
234254 pm_runtime_forbid (dev -> dev );
235255
236256 pinctrl_pm_select_default_state (dev -> dev );
237- clk_prepare_enable (crtc -> dc -> hlcdc -> sys_clk );
257+
258+ if (crtc -> dc -> hlcdc -> lvds_pll_clk ) {
259+ /* If the LVDS interface is used, fetch the pixel clock
260+ * from the panel and set the clock rate.
261+ * Here LVDS PLL clock is 7 times the pixel clock.
262+ */
263+ ret = clk_set_rate (crtc -> dc -> hlcdc -> lvds_pll_clk ,
264+ (adj -> clock * 7 * 1000 ));
265+ if (ret ) {
266+ dev_err (c -> dev -> dev , "failed to set clk rate for lvds pll: %d\n" , ret );
267+ return ;
268+ }
269+
270+ ret = clk_prepare_enable (crtc -> dc -> hlcdc -> lvds_pll_clk );
271+ if (ret )
272+ return ;
273+ } else {
274+ ret = clk_prepare_enable (crtc -> dc -> hlcdc -> sys_clk );
275+ if (ret )
276+ return ;
277+ }
238278
239279 regmap_write (regmap , ATMEL_HLCDC_EN , ATMEL_HLCDC_PIXEL_CLK );
240280 while (!regmap_read (regmap , ATMEL_HLCDC_SR , & status ) &&
@@ -295,7 +335,8 @@ static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
295335 if (!encoder )
296336 encoder = connector -> encoder ;
297337
298- if (encoder -> encoder_type == DRM_MODE_ENCODER_DSI ) {
338+ switch (encoder -> encoder_type ) {
339+ case DRM_MODE_ENCODER_DSI :
299340 /*
300341 * atmel-hlcdc to support DSI formats with DSI video pipeline
301342 * when DRM_MODE_ENCODER_DSI type is set by
@@ -338,7 +379,35 @@ static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
338379 break ;
339380 }
340381 }
341- } else {
382+ break ;
383+ case DRM_MODE_ENCODER_LVDS :
384+ switch (atmel_hlcdc_encoder_get_bus_fmt (encoder )) {
385+ case 0 :
386+ break ;
387+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG :
388+ case MEDIA_BUS_FMT_RGB666_1X18 :
389+ return ATMEL_HLCDC_RGB666_OUTPUT ;
390+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG :
391+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA :
392+ default :
393+ return ATMEL_HLCDC_RGB888_OUTPUT ;
394+ }
395+
396+ for (j = 0 ; j < info -> num_bus_formats ; j ++ ) {
397+ switch (info -> bus_formats [j ]) {
398+ case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG :
399+ case MEDIA_BUS_FMT_RGB666_1X18 :
400+ supported_fmts |= ATMEL_HLCDC_RGB666_OUTPUT ;
401+ break ;
402+ case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG :
403+ case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA :
404+ default :
405+ supported_fmts |= ATMEL_HLCDC_RGB888_OUTPUT ;
406+ break ;
407+ }
408+ }
409+ break ;
410+ default :
342411 switch (atmel_hlcdc_encoder_get_bus_fmt (encoder )) {
343412 case 0 :
344413 break ;
@@ -372,6 +441,7 @@ static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
372441 break ;
373442 }
374443 }
444+ break ;
375445 }
376446 return supported_fmts ;
377447}
0 commit comments