xref: /openbmc/linux/drivers/gpu/drm/kmb/kmb_crtc.c (revision bc50cf64)
17f7b96a8SAnitha Chrisanthus // SPDX-License-Identifier: GPL-2.0-only
27f7b96a8SAnitha Chrisanthus /*
37f7b96a8SAnitha Chrisanthus  * Copyright © 2018-2020 Intel Corporation
47f7b96a8SAnitha Chrisanthus  */
57f7b96a8SAnitha Chrisanthus 
67f7b96a8SAnitha Chrisanthus #include <linux/clk.h>
77f7b96a8SAnitha Chrisanthus 
87f7b96a8SAnitha Chrisanthus #include <drm/drm_atomic.h>
97f7b96a8SAnitha Chrisanthus #include <drm/drm_atomic_helper.h>
107f7b96a8SAnitha Chrisanthus #include <drm/drm_crtc.h>
117f7b96a8SAnitha Chrisanthus #include <drm/drm_print.h>
127f7b96a8SAnitha Chrisanthus #include <drm/drm_vblank.h>
137f7b96a8SAnitha Chrisanthus #include <drm/drm_modeset_helper_vtables.h>
147f7b96a8SAnitha Chrisanthus 
157f7b96a8SAnitha Chrisanthus #include "kmb_drv.h"
167f7b96a8SAnitha Chrisanthus #include "kmb_dsi.h"
177f7b96a8SAnitha Chrisanthus #include "kmb_plane.h"
187f7b96a8SAnitha Chrisanthus #include "kmb_regs.h"
197f7b96a8SAnitha Chrisanthus 
207f7b96a8SAnitha Chrisanthus struct kmb_crtc_timing {
217f7b96a8SAnitha Chrisanthus 	u32 vfront_porch;
227f7b96a8SAnitha Chrisanthus 	u32 vback_porch;
237f7b96a8SAnitha Chrisanthus 	u32 vsync_len;
247f7b96a8SAnitha Chrisanthus 	u32 hfront_porch;
257f7b96a8SAnitha Chrisanthus 	u32 hback_porch;
267f7b96a8SAnitha Chrisanthus 	u32 hsync_len;
277f7b96a8SAnitha Chrisanthus };
287f7b96a8SAnitha Chrisanthus 
kmb_crtc_enable_vblank(struct drm_crtc * crtc)297f7b96a8SAnitha Chrisanthus static int kmb_crtc_enable_vblank(struct drm_crtc *crtc)
307f7b96a8SAnitha Chrisanthus {
317f7b96a8SAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
327f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(dev);
337f7b96a8SAnitha Chrisanthus 
347f7b96a8SAnitha Chrisanthus 	/* Clear interrupt */
357f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_INT_CLEAR, LCD_INT_VERT_COMP);
367f7b96a8SAnitha Chrisanthus 	/* Set which interval to generate vertical interrupt */
377f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_VSTATUS_COMPARE,
387f7b96a8SAnitha Chrisanthus 		      LCD_VSTATUS_COMPARE_VSYNC);
397f7b96a8SAnitha Chrisanthus 	/* Enable vertical interrupt */
407f7b96a8SAnitha Chrisanthus 	kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE,
417f7b96a8SAnitha Chrisanthus 			    LCD_INT_VERT_COMP);
427f7b96a8SAnitha Chrisanthus 	return 0;
437f7b96a8SAnitha Chrisanthus }
447f7b96a8SAnitha Chrisanthus 
kmb_crtc_disable_vblank(struct drm_crtc * crtc)457f7b96a8SAnitha Chrisanthus static void kmb_crtc_disable_vblank(struct drm_crtc *crtc)
467f7b96a8SAnitha Chrisanthus {
477f7b96a8SAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
487f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(dev);
497f7b96a8SAnitha Chrisanthus 
507f7b96a8SAnitha Chrisanthus 	/* Clear interrupt */
517f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_INT_CLEAR, LCD_INT_VERT_COMP);
527f7b96a8SAnitha Chrisanthus 	/* Disable vertical interrupt */
537f7b96a8SAnitha Chrisanthus 	kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE,
547f7b96a8SAnitha Chrisanthus 			    LCD_INT_VERT_COMP);
557f7b96a8SAnitha Chrisanthus }
567f7b96a8SAnitha Chrisanthus 
577f7b96a8SAnitha Chrisanthus static const struct drm_crtc_funcs kmb_crtc_funcs = {
587f7b96a8SAnitha Chrisanthus 	.destroy = drm_crtc_cleanup,
597f7b96a8SAnitha Chrisanthus 	.set_config = drm_atomic_helper_set_config,
607f7b96a8SAnitha Chrisanthus 	.page_flip = drm_atomic_helper_page_flip,
617f7b96a8SAnitha Chrisanthus 	.reset = drm_atomic_helper_crtc_reset,
627f7b96a8SAnitha Chrisanthus 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
637f7b96a8SAnitha Chrisanthus 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
647f7b96a8SAnitha Chrisanthus 	.enable_vblank = kmb_crtc_enable_vblank,
657f7b96a8SAnitha Chrisanthus 	.disable_vblank = kmb_crtc_disable_vblank,
667f7b96a8SAnitha Chrisanthus };
677f7b96a8SAnitha Chrisanthus 
kmb_crtc_set_mode(struct drm_crtc * crtc,struct drm_atomic_state * old_state)68*74056092SAnitha Chrisanthus static void kmb_crtc_set_mode(struct drm_crtc *crtc,
69*74056092SAnitha Chrisanthus 			      struct drm_atomic_state *old_state)
707f7b96a8SAnitha Chrisanthus {
717f7b96a8SAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
727f7b96a8SAnitha Chrisanthus 	struct drm_display_mode *m = &crtc->state->adjusted_mode;
737f7b96a8SAnitha Chrisanthus 	struct kmb_crtc_timing vm;
747f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(dev);
757f7b96a8SAnitha Chrisanthus 	unsigned int val = 0;
767f7b96a8SAnitha Chrisanthus 
777f7b96a8SAnitha Chrisanthus 	/* Initialize mipi */
78*74056092SAnitha Chrisanthus 	kmb_dsi_mode_set(kmb->kmb_dsi, m, kmb->sys_clk_mhz, old_state);
797f7b96a8SAnitha Chrisanthus 	drm_info(dev,
8005481f07SColin Ian King 		 "vfp= %d vbp= %d vsync_len=%d hfp=%d hbp=%d hsync_len=%d\n",
817f7b96a8SAnitha Chrisanthus 		 m->crtc_vsync_start - m->crtc_vdisplay,
827f7b96a8SAnitha Chrisanthus 		 m->crtc_vtotal - m->crtc_vsync_end,
837f7b96a8SAnitha Chrisanthus 		 m->crtc_vsync_end - m->crtc_vsync_start,
847f7b96a8SAnitha Chrisanthus 		 m->crtc_hsync_start - m->crtc_hdisplay,
857f7b96a8SAnitha Chrisanthus 		 m->crtc_htotal - m->crtc_hsync_end,
867f7b96a8SAnitha Chrisanthus 		 m->crtc_hsync_end - m->crtc_hsync_start);
877f7b96a8SAnitha Chrisanthus 	val = kmb_read_lcd(kmb, LCD_INT_ENABLE);
887f7b96a8SAnitha Chrisanthus 	kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE, val);
897f7b96a8SAnitha Chrisanthus 	kmb_set_bitmask_lcd(kmb, LCD_INT_CLEAR, ~0x0);
907f7b96a8SAnitha Chrisanthus 	vm.vfront_porch = 2;
917f7b96a8SAnitha Chrisanthus 	vm.vback_porch = 2;
927f7b96a8SAnitha Chrisanthus 	vm.vsync_len = 8;
937f7b96a8SAnitha Chrisanthus 	vm.hfront_porch = 0;
947f7b96a8SAnitha Chrisanthus 	vm.hback_porch = 0;
957f7b96a8SAnitha Chrisanthus 	vm.hsync_len = 28;
967f7b96a8SAnitha Chrisanthus 
9705481f07SColin Ian King 	drm_dbg(dev, "%s : %dactive height= %d vbp=%d vfp=%d vsync-w=%d h-active=%d h-bp=%d h-fp=%d hsync-l=%d",
987f7b96a8SAnitha Chrisanthus 		__func__, __LINE__,
997f7b96a8SAnitha Chrisanthus 			m->crtc_vdisplay, vm.vback_porch, vm.vfront_porch,
1007f7b96a8SAnitha Chrisanthus 			vm.vsync_len, m->crtc_hdisplay, vm.hback_porch,
1017f7b96a8SAnitha Chrisanthus 			vm.hfront_porch, vm.hsync_len);
1027f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_V_ACTIVEHEIGHT,
1037f7b96a8SAnitha Chrisanthus 		      m->crtc_vdisplay - 1);
1047f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_V_BACKPORCH, vm.vback_porch);
1057f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_V_FRONTPORCH, vm.vfront_porch);
1067f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_VSYNC_WIDTH, vm.vsync_len - 1);
1077f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_H_ACTIVEWIDTH,
1087f7b96a8SAnitha Chrisanthus 		      m->crtc_hdisplay - 1);
1097f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_H_BACKPORCH, vm.hback_porch);
1107f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_H_FRONTPORCH, vm.hfront_porch);
1117f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_HSYNC_WIDTH, vm.hsync_len - 1);
1127f7b96a8SAnitha Chrisanthus 	/* This is hardcoded as 0 in the Myriadx code */
1137f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_VSYNC_START, 0);
1147f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_VSYNC_END, 0);
1157f7b96a8SAnitha Chrisanthus 	/* Back ground color */
1167f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_BG_COLOUR_LS, 0x4);
1177f7b96a8SAnitha Chrisanthus 	if (m->flags == DRM_MODE_FLAG_INTERLACE) {
1187f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb,
1197f7b96a8SAnitha Chrisanthus 			      LCD_VSYNC_WIDTH_EVEN, vm.vsync_len - 1);
1207f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb,
1217f7b96a8SAnitha Chrisanthus 			      LCD_V_BACKPORCH_EVEN, vm.vback_porch);
1227f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb,
1237f7b96a8SAnitha Chrisanthus 			      LCD_V_FRONTPORCH_EVEN, vm.vfront_porch);
1247f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb, LCD_V_ACTIVEHEIGHT_EVEN,
1257f7b96a8SAnitha Chrisanthus 			      m->crtc_vdisplay - 1);
1267f7b96a8SAnitha Chrisanthus 		/* This is hardcoded as 10 in the Myriadx code */
1277f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb, LCD_VSYNC_START_EVEN, 10);
1287f7b96a8SAnitha Chrisanthus 		kmb_write_lcd(kmb, LCD_VSYNC_END_EVEN, 10);
1297f7b96a8SAnitha Chrisanthus 	}
1307f7b96a8SAnitha Chrisanthus 	kmb_write_lcd(kmb, LCD_TIMING_GEN_TRIG, 1);
1317f7b96a8SAnitha Chrisanthus 	kmb_set_bitmask_lcd(kmb, LCD_CONTROL, LCD_CTRL_ENABLE);
1327f7b96a8SAnitha Chrisanthus 	kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE, val);
1337f7b96a8SAnitha Chrisanthus }
1347f7b96a8SAnitha Chrisanthus 
kmb_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)1357f7b96a8SAnitha Chrisanthus static void kmb_crtc_atomic_enable(struct drm_crtc *crtc,
1367f7b96a8SAnitha Chrisanthus 				   struct drm_atomic_state *state)
1377f7b96a8SAnitha Chrisanthus {
1387f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);
1397f7b96a8SAnitha Chrisanthus 
1407f7b96a8SAnitha Chrisanthus 	clk_prepare_enable(kmb->kmb_clk.clk_lcd);
141*74056092SAnitha Chrisanthus 	kmb_crtc_set_mode(crtc, state);
1427f7b96a8SAnitha Chrisanthus 	drm_crtc_vblank_on(crtc);
1437f7b96a8SAnitha Chrisanthus }
1447f7b96a8SAnitha Chrisanthus 
kmb_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)1457f7b96a8SAnitha Chrisanthus static void kmb_crtc_atomic_disable(struct drm_crtc *crtc,
1467f7b96a8SAnitha Chrisanthus 				    struct drm_atomic_state *state)
1477f7b96a8SAnitha Chrisanthus {
1487f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = crtc_to_kmb_priv(crtc);
1497f7b96a8SAnitha Chrisanthus 	struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
1507f7b96a8SAnitha Chrisanthus 
1517f7b96a8SAnitha Chrisanthus 	/* due to hw limitations, planes need to be off when crtc is off */
1527f7b96a8SAnitha Chrisanthus 	drm_atomic_helper_disable_planes_on_crtc(old_state, false);
1537f7b96a8SAnitha Chrisanthus 
1547f7b96a8SAnitha Chrisanthus 	drm_crtc_vblank_off(crtc);
1557f7b96a8SAnitha Chrisanthus 	clk_disable_unprepare(kmb->kmb_clk.clk_lcd);
1567f7b96a8SAnitha Chrisanthus }
1577f7b96a8SAnitha Chrisanthus 
kmb_crtc_atomic_begin(struct drm_crtc * crtc,struct drm_atomic_state * state)1587f7b96a8SAnitha Chrisanthus static void kmb_crtc_atomic_begin(struct drm_crtc *crtc,
1597f7b96a8SAnitha Chrisanthus 				  struct drm_atomic_state *state)
1607f7b96a8SAnitha Chrisanthus {
1617f7b96a8SAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
1627f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(dev);
1637f7b96a8SAnitha Chrisanthus 
1647f7b96a8SAnitha Chrisanthus 	kmb_clr_bitmask_lcd(kmb, LCD_INT_ENABLE,
1657f7b96a8SAnitha Chrisanthus 			    LCD_INT_VERT_COMP);
1667f7b96a8SAnitha Chrisanthus }
1677f7b96a8SAnitha Chrisanthus 
kmb_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)1687f7b96a8SAnitha Chrisanthus static void kmb_crtc_atomic_flush(struct drm_crtc *crtc,
1697f7b96a8SAnitha Chrisanthus 				  struct drm_atomic_state *state)
1707f7b96a8SAnitha Chrisanthus {
1717f7b96a8SAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
1727f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(dev);
1737f7b96a8SAnitha Chrisanthus 
1747f7b96a8SAnitha Chrisanthus 	kmb_set_bitmask_lcd(kmb, LCD_INT_ENABLE,
1757f7b96a8SAnitha Chrisanthus 			    LCD_INT_VERT_COMP);
1767f7b96a8SAnitha Chrisanthus 
1777f7b96a8SAnitha Chrisanthus 	spin_lock_irq(&crtc->dev->event_lock);
1787f7b96a8SAnitha Chrisanthus 	if (crtc->state->event) {
1797f7b96a8SAnitha Chrisanthus 		if (drm_crtc_vblank_get(crtc) == 0)
1807f7b96a8SAnitha Chrisanthus 			drm_crtc_arm_vblank_event(crtc, crtc->state->event);
1817f7b96a8SAnitha Chrisanthus 		else
1827f7b96a8SAnitha Chrisanthus 			drm_crtc_send_vblank_event(crtc, crtc->state->event);
1837f7b96a8SAnitha Chrisanthus 	}
1847f7b96a8SAnitha Chrisanthus 	crtc->state->event = NULL;
1857f7b96a8SAnitha Chrisanthus 	spin_unlock_irq(&crtc->dev->event_lock);
1867f7b96a8SAnitha Chrisanthus }
1877f7b96a8SAnitha Chrisanthus 
188a79f40ccSAnitha Chrisanthus static enum drm_mode_status
kmb_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode)189a79f40ccSAnitha Chrisanthus 		kmb_crtc_mode_valid(struct drm_crtc *crtc,
190a79f40ccSAnitha Chrisanthus 				    const struct drm_display_mode *mode)
191a79f40ccSAnitha Chrisanthus {
192a79f40ccSAnitha Chrisanthus 	int refresh;
193a79f40ccSAnitha Chrisanthus 	struct drm_device *dev = crtc->dev;
194a79f40ccSAnitha Chrisanthus 	int vfp = mode->vsync_start - mode->vdisplay;
195a79f40ccSAnitha Chrisanthus 
196a79f40ccSAnitha Chrisanthus 	if (mode->vdisplay < KMB_CRTC_MAX_HEIGHT) {
197a79f40ccSAnitha Chrisanthus 		drm_dbg(dev, "height = %d less than %d",
198a79f40ccSAnitha Chrisanthus 			mode->vdisplay, KMB_CRTC_MAX_HEIGHT);
199a79f40ccSAnitha Chrisanthus 		return MODE_BAD_VVALUE;
200a79f40ccSAnitha Chrisanthus 	}
201a79f40ccSAnitha Chrisanthus 	if (mode->hdisplay < KMB_CRTC_MAX_WIDTH) {
202a79f40ccSAnitha Chrisanthus 		drm_dbg(dev, "width = %d less than %d",
203a79f40ccSAnitha Chrisanthus 			mode->hdisplay, KMB_CRTC_MAX_WIDTH);
204a79f40ccSAnitha Chrisanthus 		return MODE_BAD_HVALUE;
205a79f40ccSAnitha Chrisanthus 	}
206a79f40ccSAnitha Chrisanthus 	refresh = drm_mode_vrefresh(mode);
207a79f40ccSAnitha Chrisanthus 	if (refresh < KMB_MIN_VREFRESH || refresh > KMB_MAX_VREFRESH) {
208a79f40ccSAnitha Chrisanthus 		drm_dbg(dev, "refresh = %d less than %d or greater than %d",
209a79f40ccSAnitha Chrisanthus 			refresh, KMB_MIN_VREFRESH, KMB_MAX_VREFRESH);
210a79f40ccSAnitha Chrisanthus 		return MODE_BAD;
211a79f40ccSAnitha Chrisanthus 	}
212a79f40ccSAnitha Chrisanthus 
213a79f40ccSAnitha Chrisanthus 	if (vfp < KMB_CRTC_MIN_VFP) {
214a79f40ccSAnitha Chrisanthus 		drm_dbg(dev, "vfp = %d less than %d", vfp, KMB_CRTC_MIN_VFP);
215a79f40ccSAnitha Chrisanthus 		return MODE_BAD;
216a79f40ccSAnitha Chrisanthus 	}
217a79f40ccSAnitha Chrisanthus 
218a79f40ccSAnitha Chrisanthus 	return MODE_OK;
219a79f40ccSAnitha Chrisanthus }
220a79f40ccSAnitha Chrisanthus 
2217f7b96a8SAnitha Chrisanthus static const struct drm_crtc_helper_funcs kmb_crtc_helper_funcs = {
2227f7b96a8SAnitha Chrisanthus 	.atomic_begin = kmb_crtc_atomic_begin,
2237f7b96a8SAnitha Chrisanthus 	.atomic_enable = kmb_crtc_atomic_enable,
2247f7b96a8SAnitha Chrisanthus 	.atomic_disable = kmb_crtc_atomic_disable,
2257f7b96a8SAnitha Chrisanthus 	.atomic_flush = kmb_crtc_atomic_flush,
226a79f40ccSAnitha Chrisanthus 	.mode_valid = kmb_crtc_mode_valid,
2277f7b96a8SAnitha Chrisanthus };
2287f7b96a8SAnitha Chrisanthus 
kmb_setup_crtc(struct drm_device * drm)2297f7b96a8SAnitha Chrisanthus int kmb_setup_crtc(struct drm_device *drm)
2307f7b96a8SAnitha Chrisanthus {
2317f7b96a8SAnitha Chrisanthus 	struct kmb_drm_private *kmb = to_kmb(drm);
2327f7b96a8SAnitha Chrisanthus 	struct kmb_plane *primary;
2337f7b96a8SAnitha Chrisanthus 	int ret;
2347f7b96a8SAnitha Chrisanthus 
2357f7b96a8SAnitha Chrisanthus 	primary = kmb_plane_init(drm);
2367f7b96a8SAnitha Chrisanthus 	if (IS_ERR(primary))
2377f7b96a8SAnitha Chrisanthus 		return PTR_ERR(primary);
2387f7b96a8SAnitha Chrisanthus 
2397f7b96a8SAnitha Chrisanthus 	ret = drm_crtc_init_with_planes(drm, &kmb->crtc, &primary->base_plane,
2407f7b96a8SAnitha Chrisanthus 					NULL, &kmb_crtc_funcs, NULL);
2417f7b96a8SAnitha Chrisanthus 	if (ret) {
2427f7b96a8SAnitha Chrisanthus 		kmb_plane_destroy(&primary->base_plane);
2437f7b96a8SAnitha Chrisanthus 		return ret;
2447f7b96a8SAnitha Chrisanthus 	}
2457f7b96a8SAnitha Chrisanthus 
2467f7b96a8SAnitha Chrisanthus 	drm_crtc_helper_add(&kmb->crtc, &kmb_crtc_helper_funcs);
2477f7b96a8SAnitha Chrisanthus 	return 0;
2487f7b96a8SAnitha Chrisanthus }
249