File Index
Files and directories
Sign in
FILE

lsdc_crtc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/loongson/lsdc_crtc.c C
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2023 Loongson Technology Corporation Limited
   4 */
   5
   6#include <linux/debugfs.h>
   7#include <linux/delay.h>
   8
   9#include <drm/drm_atomic.h>
  10#include <drm/drm_atomic_helper.h>
  11#include <drm/drm_debugfs.h>
  12#include <drm/drm_print.h>
  13#include <drm/drm_vblank.h>
  14
  15#include "lsdc_drv.h"
  16
  17/*
  18 * After the CRTC soft reset, the vblank counter would be reset to zero.
  19 * But the address and other settings in the CRTC register remain the same
  20 * as before.
  21 */
  22
  23static void lsdc_crtc0_soft_reset(struct lsdc_crtc *lcrtc)
  24{
  25	struct lsdc_device *ldev = lcrtc->ldev;
  26	u32 val;
  27
  28	val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
  29
  30	val &= CFG_VALID_BITS_MASK;
  31
  32	/* Soft reset bit, active low */
  33	val &= ~CFG_RESET_N;
  34
  35	val &= ~CFG_PIX_FMT_MASK;
  36
  37	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
  38
  39	udelay(1);
  40
  41	val |= CFG_RESET_N | LSDC_PF_XRGB8888 | CFG_OUTPUT_ENABLE;
  42
  43	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
  44
  45	/* Wait about a vblank time */
  46	mdelay(20);
  47}
  48
  49static void lsdc_crtc1_soft_reset(struct lsdc_crtc *lcrtc)
  50{
  51	struct lsdc_device *ldev = lcrtc->ldev;
  52	u32 val;
  53
  54	val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
  55
  56	val &= CFG_VALID_BITS_MASK;
  57
  58	/* Soft reset bit, active low */
  59	val &= ~CFG_RESET_N;
  60
  61	val &= ~CFG_PIX_FMT_MASK;
  62
  63	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
  64
  65	udelay(1);
  66
  67	val |= CFG_RESET_N | LSDC_PF_XRGB8888 | CFG_OUTPUT_ENABLE;
  68
  69	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
  70
  71	/* Wait about a vblank time */
  72	msleep(20);
  73}
  74
  75static void lsdc_crtc0_enable(struct lsdc_crtc *lcrtc)
  76{
  77	struct lsdc_device *ldev = lcrtc->ldev;
  78	u32 val;
  79
  80	val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
  81
  82	/*
  83	 * This may happen in extremely rare cases, but a soft reset can
  84	 * bring it back to normal. We add a warning here, hoping to catch
  85	 * something if it happens.
  86	 */
  87	if (val & CRTC_ANCHORED) {
  88		drm_warn(&ldev->base, "%s stall\n", lcrtc->base.name);
  89		return lsdc_crtc0_soft_reset(lcrtc);
  90	}
  91
  92	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val | CFG_OUTPUT_ENABLE);
  93}
  94
  95static void lsdc_crtc0_disable(struct lsdc_crtc *lcrtc)
  96{
  97	struct lsdc_device *ldev = lcrtc->ldev;
  98
  99	lsdc_ureg32_clr(ldev, LSDC_CRTC0_CFG_REG, CFG_OUTPUT_ENABLE);
 100
 101	udelay(9);
 102}
 103
 104static void lsdc_crtc1_enable(struct lsdc_crtc *lcrtc)
 105{
 106	struct lsdc_device *ldev = lcrtc->ldev;
 107	u32 val;
 108
 109	/*
 110	 * This may happen in extremely rare cases, but a soft reset can
 111	 * bring it back to normal. We add a warning here, hoping to catch
 112	 * something if it happens.
 113	 */
 114	val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
 115	if (val & CRTC_ANCHORED) {
 116		drm_warn(&ldev->base, "%s stall\n", lcrtc->base.name);
 117		return lsdc_crtc1_soft_reset(lcrtc);
 118	}
 119
 120	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val | CFG_OUTPUT_ENABLE);
 121}
 122
 123static void lsdc_crtc1_disable(struct lsdc_crtc *lcrtc)
 124{
 125	struct lsdc_device *ldev = lcrtc->ldev;
 126
 127	lsdc_ureg32_clr(ldev, LSDC_CRTC1_CFG_REG, CFG_OUTPUT_ENABLE);
 128
 129	udelay(9);
 130}
 131
 132/* All Loongson display controllers have hardware scanout position recoders */
 133
 134static void lsdc_crtc0_scan_pos(struct lsdc_crtc *lcrtc, int *hpos, int *vpos)
 135{
 136	struct lsdc_device *ldev = lcrtc->ldev;
 137	u32 val;
 138
 139	val = lsdc_rreg32(ldev, LSDC_CRTC0_SCAN_POS_REG);
 140
 141	*hpos = val >> 16;
 142	*vpos = val & 0xffff;
 143}
 144
 145static void lsdc_crtc1_scan_pos(struct lsdc_crtc *lcrtc, int *hpos, int *vpos)
 146{
 147	struct lsdc_device *ldev = lcrtc->ldev;
 148	u32 val;
 149
 150	val = lsdc_rreg32(ldev, LSDC_CRTC1_SCAN_POS_REG);
 151
 152	*hpos = val >> 16;
 153	*vpos = val & 0xffff;
 154}
 155
 156static void lsdc_crtc0_enable_vblank(struct lsdc_crtc *lcrtc)
 157{
 158	struct lsdc_device *ldev = lcrtc->ldev;
 159
 160	lsdc_ureg32_set(ldev, LSDC_INT_REG, INT_CRTC0_VSYNC_EN);
 161}
 162
 163static void lsdc_crtc0_disable_vblank(struct lsdc_crtc *lcrtc)
 164{
 165	struct lsdc_device *ldev = lcrtc->ldev;
 166
 167	lsdc_ureg32_clr(ldev, LSDC_INT_REG, INT_CRTC0_VSYNC_EN);
 168}
 169
 170static void lsdc_crtc1_enable_vblank(struct lsdc_crtc *lcrtc)
 171{
 172	struct lsdc_device *ldev = lcrtc->ldev;
 173
 174	lsdc_ureg32_set(ldev, LSDC_INT_REG, INT_CRTC1_VSYNC_EN);
 175}
 176
 177static void lsdc_crtc1_disable_vblank(struct lsdc_crtc *lcrtc)
 178{
 179	struct lsdc_device *ldev = lcrtc->ldev;
 180
 181	lsdc_ureg32_clr(ldev, LSDC_INT_REG, INT_CRTC1_VSYNC_EN);
 182}
 183
 184static void lsdc_crtc0_flip(struct lsdc_crtc *lcrtc)
 185{
 186	struct lsdc_device *ldev = lcrtc->ldev;
 187
 188	lsdc_ureg32_set(ldev, LSDC_CRTC0_CFG_REG, CFG_PAGE_FLIP);
 189}
 190
 191static void lsdc_crtc1_flip(struct lsdc_crtc *lcrtc)
 192{
 193	struct lsdc_device *ldev = lcrtc->ldev;
 194
 195	lsdc_ureg32_set(ldev, LSDC_CRTC1_CFG_REG, CFG_PAGE_FLIP);
 196}
 197
 198/*
 199 * CRTC0 clone from CRTC1 or CRTC1 clone from CRTC0 using hardware logic
 200 * This may be useful for custom cloning (TWIN) applications. Saving the
 201 * bandwidth compared with the clone (mirroring) display mode provided by
 202 * drm core.
 203 */
 204
 205static void lsdc_crtc0_clone(struct lsdc_crtc *lcrtc)
 206{
 207	struct lsdc_device *ldev = lcrtc->ldev;
 208
 209	lsdc_ureg32_set(ldev, LSDC_CRTC0_CFG_REG, CFG_HW_CLONE);
 210}
 211
 212static void lsdc_crtc1_clone(struct lsdc_crtc *lcrtc)
 213{
 214	struct lsdc_device *ldev = lcrtc->ldev;
 215
 216	lsdc_ureg32_set(ldev, LSDC_CRTC1_CFG_REG, CFG_HW_CLONE);
 217}
 218
 219static void lsdc_crtc0_set_mode(struct lsdc_crtc *lcrtc,
 220				const struct drm_display_mode *mode)
 221{
 222	struct lsdc_device *ldev = lcrtc->ldev;
 223
 224	lsdc_wreg32(ldev, LSDC_CRTC0_HDISPLAY_REG,
 225		    (mode->crtc_htotal << 16) | mode->crtc_hdisplay);
 226
 227	lsdc_wreg32(ldev, LSDC_CRTC0_VDISPLAY_REG,
 228		    (mode->crtc_vtotal << 16) | mode->crtc_vdisplay);
 229
 230	lsdc_wreg32(ldev, LSDC_CRTC0_HSYNC_REG,
 231		    (mode->crtc_hsync_end << 16) | mode->crtc_hsync_start | HSYNC_EN);
 232
 233	lsdc_wreg32(ldev, LSDC_CRTC0_VSYNC_REG,
 234		    (mode->crtc_vsync_end << 16) | mode->crtc_vsync_start | VSYNC_EN);
 235}
 236
 237static void lsdc_crtc1_set_mode(struct lsdc_crtc *lcrtc,
 238				const struct drm_display_mode *mode)
 239{
 240	struct lsdc_device *ldev = lcrtc->ldev;
 241
 242	lsdc_wreg32(ldev, LSDC_CRTC1_HDISPLAY_REG,
 243		    (mode->crtc_htotal << 16) | mode->crtc_hdisplay);
 244
 245	lsdc_wreg32(ldev, LSDC_CRTC1_VDISPLAY_REG,
 246		    (mode->crtc_vtotal << 16) | mode->crtc_vdisplay);
 247
 248	lsdc_wreg32(ldev, LSDC_CRTC1_HSYNC_REG,
 249		    (mode->crtc_hsync_end << 16) | mode->crtc_hsync_start | HSYNC_EN);
 250
 251	lsdc_wreg32(ldev, LSDC_CRTC1_VSYNC_REG,
 252		    (mode->crtc_vsync_end << 16) | mode->crtc_vsync_start | VSYNC_EN);
 253}
 254
 255/*
 256 * This is required for S3 support.
 257 * After resuming from suspend, LSDC_CRTCx_CFG_REG (x = 0 or 1) is filled
 258 * with garbage value, which causes the CRTC hang there.
 259 *
 260 * This function provides minimal settings for the affected registers.
 261 * This overrides the firmware's settings on startup, making the CRTC work
 262 * on our own, similar to the functional of GPU POST (Power On Self Test).
 263 * Only touch CRTC hardware-related parts.
 264 */
 265
 266static void lsdc_crtc0_reset(struct lsdc_crtc *lcrtc)
 267{
 268	struct lsdc_device *ldev = lcrtc->ldev;
 269
 270	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, CFG_RESET_N | LSDC_PF_XRGB8888);
 271}
 272
 273static void lsdc_crtc1_reset(struct lsdc_crtc *lcrtc)
 274{
 275	struct lsdc_device *ldev = lcrtc->ldev;
 276
 277	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, CFG_RESET_N | LSDC_PF_XRGB8888);
 278}
 279
 280static const struct lsdc_crtc_hw_ops ls7a1000_crtc_hw_ops[2] = {
 281	{
 282		.enable = lsdc_crtc0_enable,
 283		.disable = lsdc_crtc0_disable,
 284		.enable_vblank = lsdc_crtc0_enable_vblank,
 285		.disable_vblank = lsdc_crtc0_disable_vblank,
 286		.flip = lsdc_crtc0_flip,
 287		.clone = lsdc_crtc0_clone,
 288		.set_mode = lsdc_crtc0_set_mode,
 289		.get_scan_pos = lsdc_crtc0_scan_pos,
 290		.soft_reset = lsdc_crtc0_soft_reset,
 291		.reset = lsdc_crtc0_reset,
 292	},
 293	{
 294		.enable = lsdc_crtc1_enable,
 295		.disable = lsdc_crtc1_disable,
 296		.enable_vblank = lsdc_crtc1_enable_vblank,
 297		.disable_vblank = lsdc_crtc1_disable_vblank,
 298		.flip = lsdc_crtc1_flip,
 299		.clone = lsdc_crtc1_clone,
 300		.set_mode = lsdc_crtc1_set_mode,
 301		.get_scan_pos = lsdc_crtc1_scan_pos,
 302		.soft_reset = lsdc_crtc1_soft_reset,
 303		.reset = lsdc_crtc1_reset,
 304	},
 305};
 306
 307/*
 308 * The 32-bit hardware vblank counter has been available since LS7A2000
 309 * and LS2K2000. The counter increases even though the CRTC is disabled,
 310 * it will be reset only if the CRTC is being soft reset.
 311 * Those registers are also readable for ls7a1000, but its value does not
 312 * change.
 313 */
 314
 315static u32 lsdc_crtc0_get_vblank_count(struct lsdc_crtc *lcrtc)
 316{
 317	struct lsdc_device *ldev = lcrtc->ldev;
 318
 319	return lsdc_rreg32(ldev, LSDC_CRTC0_VSYNC_COUNTER_REG);
 320}
 321
 322static u32 lsdc_crtc1_get_vblank_count(struct lsdc_crtc *lcrtc)
 323{
 324	struct lsdc_device *ldev = lcrtc->ldev;
 325
 326	return lsdc_rreg32(ldev, LSDC_CRTC1_VSYNC_COUNTER_REG);
 327}
 328
 329/*
 330 * The DMA step bit fields are available since LS7A2000/LS2K2000, for
 331 * supporting odd resolutions. But a large DMA step save the bandwidth.
 332 * The larger, the better. Behavior of writing those bits on LS7A1000
 333 * or LS2K1000 is underfined.
 334 */
 335
 336static void lsdc_crtc0_set_dma_step(struct lsdc_crtc *lcrtc,
 337				    enum lsdc_dma_steps dma_step)
 338{
 339	struct lsdc_device *ldev = lcrtc->ldev;
 340	u32 val = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
 341
 342	val &= ~CFG_DMA_STEP_MASK;
 343	val |= dma_step << CFG_DMA_STEP_SHIFT;
 344
 345	lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, val);
 346}
 347
 348static void lsdc_crtc1_set_dma_step(struct lsdc_crtc *lcrtc,
 349				    enum lsdc_dma_steps dma_step)
 350{
 351	struct lsdc_device *ldev = lcrtc->ldev;
 352	u32 val = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
 353
 354	val &= ~CFG_DMA_STEP_MASK;
 355	val |= dma_step << CFG_DMA_STEP_SHIFT;
 356
 357	lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, val);
 358}
 359
 360static const struct lsdc_crtc_hw_ops ls7a2000_crtc_hw_ops[2] = {
 361	{
 362		.enable = lsdc_crtc0_enable,
 363		.disable = lsdc_crtc0_disable,
 364		.enable_vblank = lsdc_crtc0_enable_vblank,
 365		.disable_vblank = lsdc_crtc0_disable_vblank,
 366		.flip = lsdc_crtc0_flip,
 367		.clone = lsdc_crtc0_clone,
 368		.set_mode = lsdc_crtc0_set_mode,
 369		.soft_reset = lsdc_crtc0_soft_reset,
 370		.get_scan_pos = lsdc_crtc0_scan_pos,
 371		.set_dma_step = lsdc_crtc0_set_dma_step,
 372		.get_vblank_counter = lsdc_crtc0_get_vblank_count,
 373		.reset = lsdc_crtc0_reset,
 374	},
 375	{
 376		.enable = lsdc_crtc1_enable,
 377		.disable = lsdc_crtc1_disable,
 378		.enable_vblank = lsdc_crtc1_enable_vblank,
 379		.disable_vblank = lsdc_crtc1_disable_vblank,
 380		.flip = lsdc_crtc1_flip,
 381		.clone = lsdc_crtc1_clone,
 382		.set_mode = lsdc_crtc1_set_mode,
 383		.get_scan_pos = lsdc_crtc1_scan_pos,
 384		.soft_reset = lsdc_crtc1_soft_reset,
 385		.set_dma_step = lsdc_crtc1_set_dma_step,
 386		.get_vblank_counter = lsdc_crtc1_get_vblank_count,
 387		.reset = lsdc_crtc1_reset,
 388	},
 389};
 390
 391static void lsdc_crtc_reset(struct drm_crtc *crtc)
 392{
 393	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 394	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
 395	struct lsdc_crtc_state *priv_crtc_state;
 396
 397	if (crtc->state)
 398		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
 399
 400	priv_crtc_state = kzalloc(sizeof(*priv_crtc_state), GFP_KERNEL);
 401
 402	if (!priv_crtc_state)
 403		__drm_atomic_helper_crtc_reset(crtc, NULL);
 404	else
 405		__drm_atomic_helper_crtc_reset(crtc, &priv_crtc_state->base);
 406
 407	/* Reset the CRTC hardware, this is required for S3 support */
 408	ops->reset(lcrtc);
 409}
 410
 411static void lsdc_crtc_atomic_destroy_state(struct drm_crtc *crtc,
 412					   struct drm_crtc_state *state)
 413{
 414	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
 415
 416	__drm_atomic_helper_crtc_destroy_state(&priv_state->base);
 417
 418	kfree(priv_state);
 419}
 420
 421static struct drm_crtc_state *
 422lsdc_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 423{
 424	struct lsdc_crtc_state *new_priv_state;
 425	struct lsdc_crtc_state *old_priv_state;
 426
 427	new_priv_state = kzalloc(sizeof(*new_priv_state), GFP_KERNEL);
 428	if (!new_priv_state)
 429		return NULL;
 430
 431	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_priv_state->base);
 432
 433	old_priv_state = to_lsdc_crtc_state(crtc->state);
 434
 435	memcpy(&new_priv_state->pparms, &old_priv_state->pparms,
 436	       sizeof(new_priv_state->pparms));
 437
 438	return &new_priv_state->base;
 439}
 440
 441static u32 lsdc_crtc_get_vblank_counter(struct drm_crtc *crtc)
 442{
 443	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 444
 445	/* 32-bit hardware vblank counter */
 446	return lcrtc->hw_ops->get_vblank_counter(lcrtc);
 447}
 448
 449static int lsdc_crtc_enable_vblank(struct drm_crtc *crtc)
 450{
 451	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 452
 453	if (!lcrtc->has_vblank)
 454		return -EINVAL;
 455
 456	lcrtc->hw_ops->enable_vblank(lcrtc);
 457
 458	return 0;
 459}
 460
 461static void lsdc_crtc_disable_vblank(struct drm_crtc *crtc)
 462{
 463	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 464
 465	if (!lcrtc->has_vblank)
 466		return;
 467
 468	lcrtc->hw_ops->disable_vblank(lcrtc);
 469}
 470
 471/*
 472 * CRTC related debugfs
 473 * Primary planes and cursor planes belong to the CRTC as well.
 474 * For the sake of convenience, plane-related registers are also add here.
 475 */
 476
 477#define REG_DEF(reg) { \
 478	.name = __stringify_1(LSDC_##reg##_REG), \
 479	.offset = LSDC_##reg##_REG, \
 480}
 481
 482static const struct lsdc_reg32 lsdc_crtc_regs_array[2][21] = {
 483	[0] = {
 484		REG_DEF(CRTC0_CFG),
 485		REG_DEF(CRTC0_FB_ORIGIN),
 486		REG_DEF(CRTC0_DVO_CONF),
 487		REG_DEF(CRTC0_HDISPLAY),
 488		REG_DEF(CRTC0_HSYNC),
 489		REG_DEF(CRTC0_VDISPLAY),
 490		REG_DEF(CRTC0_VSYNC),
 491		REG_DEF(CRTC0_GAMMA_INDEX),
 492		REG_DEF(CRTC0_GAMMA_DATA),
 493		REG_DEF(CRTC0_SYNC_DEVIATION),
 494		REG_DEF(CRTC0_VSYNC_COUNTER),
 495		REG_DEF(CRTC0_SCAN_POS),
 496		REG_DEF(CRTC0_STRIDE),
 497		REG_DEF(CRTC0_FB1_ADDR_HI),
 498		REG_DEF(CRTC0_FB1_ADDR_LO),
 499		REG_DEF(CRTC0_FB0_ADDR_HI),
 500		REG_DEF(CRTC0_FB0_ADDR_LO),
 501		REG_DEF(CURSOR0_CFG),
 502		REG_DEF(CURSOR0_POSITION),
 503		REG_DEF(CURSOR0_BG_COLOR),
 504		REG_DEF(CURSOR0_FG_COLOR),
 505	},
 506	[1] = {
 507		REG_DEF(CRTC1_CFG),
 508		REG_DEF(CRTC1_FB_ORIGIN),
 509		REG_DEF(CRTC1_DVO_CONF),
 510		REG_DEF(CRTC1_HDISPLAY),
 511		REG_DEF(CRTC1_HSYNC),
 512		REG_DEF(CRTC1_VDISPLAY),
 513		REG_DEF(CRTC1_VSYNC),
 514		REG_DEF(CRTC1_GAMMA_INDEX),
 515		REG_DEF(CRTC1_GAMMA_DATA),
 516		REG_DEF(CRTC1_SYNC_DEVIATION),
 517		REG_DEF(CRTC1_VSYNC_COUNTER),
 518		REG_DEF(CRTC1_SCAN_POS),
 519		REG_DEF(CRTC1_STRIDE),
 520		REG_DEF(CRTC1_FB1_ADDR_HI),
 521		REG_DEF(CRTC1_FB1_ADDR_LO),
 522		REG_DEF(CRTC1_FB0_ADDR_HI),
 523		REG_DEF(CRTC1_FB0_ADDR_LO),
 524		REG_DEF(CURSOR1_CFG),
 525		REG_DEF(CURSOR1_POSITION),
 526		REG_DEF(CURSOR1_BG_COLOR),
 527		REG_DEF(CURSOR1_FG_COLOR),
 528	},
 529};
 530
 531static int lsdc_crtc_show_regs(struct seq_file *m, void *arg)
 532{
 533	struct drm_info_node *node = (struct drm_info_node *)m->private;
 534	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
 535	struct lsdc_device *ldev = lcrtc->ldev;
 536	unsigned int i;
 537
 538	for (i = 0; i < lcrtc->nreg; i++) {
 539		const struct lsdc_reg32 *preg = &lcrtc->preg[i];
 540		u32 offset = preg->offset;
 541
 542		seq_printf(m, "%s (0x%04x): 0x%08x\n",
 543			   preg->name, offset, lsdc_rreg32(ldev, offset));
 544	}
 545
 546	return 0;
 547}
 548
 549static int lsdc_crtc_show_scan_position(struct seq_file *m, void *arg)
 550{
 551	struct drm_info_node *node = (struct drm_info_node *)m->private;
 552	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
 553	int x, y;
 554
 555	lcrtc->hw_ops->get_scan_pos(lcrtc, &x, &y);
 556	seq_printf(m, "Scanout position: x: %08u, y: %08u\n", x, y);
 557
 558	return 0;
 559}
 560
 561static int lsdc_crtc_show_vblank_counter(struct seq_file *m, void *arg)
 562{
 563	struct drm_info_node *node = (struct drm_info_node *)m->private;
 564	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
 565
 566	if (lcrtc->hw_ops->get_vblank_counter)
 567		seq_printf(m, "%s vblank counter: %08u\n\n", lcrtc->base.name,
 568			   lcrtc->hw_ops->get_vblank_counter(lcrtc));
 569
 570	return 0;
 571}
 572
 573static int lsdc_pixpll_show_clock(struct seq_file *m, void *arg)
 574{
 575	struct drm_info_node *node = (struct drm_info_node *)m->private;
 576	struct lsdc_crtc *lcrtc = (struct lsdc_crtc *)node->info_ent->data;
 577	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
 578	const struct lsdc_pixpll_funcs *funcs = pixpll->funcs;
 579	struct drm_crtc *crtc = &lcrtc->base;
 580	struct drm_display_mode *mode = &crtc->state->mode;
 581	struct drm_printer printer = drm_seq_file_printer(m);
 582	unsigned int out_khz;
 583
 584	out_khz = funcs->get_rate(pixpll);
 585
 586	seq_printf(m, "%s: %dx%d@%d\n", crtc->name,
 587		   mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode));
 588
 589	seq_printf(m, "Pixel clock required: %d kHz\n", mode->clock);
 590	seq_printf(m, "Actual frequency output: %u kHz\n", out_khz);
 591	seq_printf(m, "Diff: %d kHz\n", out_khz - mode->clock);
 592
 593	funcs->print(pixpll, &printer);
 594
 595	return 0;
 596}
 597
 598static struct drm_info_list lsdc_crtc_debugfs_list[2][4] = {
 599	[0] = {
 600		{ "regs", lsdc_crtc_show_regs, 0, NULL },
 601		{ "pixclk", lsdc_pixpll_show_clock, 0, NULL },
 602		{ "scanpos", lsdc_crtc_show_scan_position, 0, NULL },
 603		{ "vblanks", lsdc_crtc_show_vblank_counter, 0, NULL },
 604	},
 605	[1] = {
 606		{ "regs", lsdc_crtc_show_regs, 0, NULL },
 607		{ "pixclk", lsdc_pixpll_show_clock, 0, NULL },
 608		{ "scanpos", lsdc_crtc_show_scan_position, 0, NULL },
 609		{ "vblanks", lsdc_crtc_show_vblank_counter, 0, NULL },
 610	},
 611};
 612
 613/* operate manually */
 614
 615static int lsdc_crtc_man_op_show(struct seq_file *m, void *data)
 616{
 617	seq_puts(m, "soft_reset: soft reset this CRTC\n");
 618	seq_puts(m, "enable: enable this CRTC\n");
 619	seq_puts(m, "disable: disable this CRTC\n");
 620	seq_puts(m, "flip: trigger the page flip\n");
 621	seq_puts(m, "clone: clone the another crtc with hardware logic\n");
 622
 623	return 0;
 624}
 625
 626static int lsdc_crtc_man_op_open(struct inode *inode, struct file *file)
 627{
 628	struct drm_crtc *crtc = inode->i_private;
 629
 630	return single_open(file, lsdc_crtc_man_op_show, crtc);
 631}
 632
 633static ssize_t lsdc_crtc_man_op_write(struct file *file,
 634				      const char __user *ubuf,
 635				      size_t len,
 636				      loff_t *offp)
 637{
 638	struct seq_file *m = file->private_data;
 639	struct lsdc_crtc *lcrtc = m->private;
 640	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
 641	char buf[16];
 642
 643	if (len > sizeof(buf) - 1)
 644		return -EINVAL;
 645
 646	if (copy_from_user(buf, ubuf, len))
 647		return -EFAULT;
 648
 649	buf[len] = '\0';
 650
 651	if (sysfs_streq(buf, "soft_reset"))
 652		ops->soft_reset(lcrtc);
 653	else if (sysfs_streq(buf, "enable"))
 654		ops->enable(lcrtc);
 655	else if (sysfs_streq(buf, "disable"))
 656		ops->disable(lcrtc);
 657	else if (sysfs_streq(buf, "flip"))
 658		ops->flip(lcrtc);
 659	else if (sysfs_streq(buf, "clone"))
 660		ops->clone(lcrtc);
 661
 662	return len;
 663}
 664
 665static const struct file_operations lsdc_crtc_man_op_fops = {
 666	.owner = THIS_MODULE,
 667	.open = lsdc_crtc_man_op_open,
 668	.read = seq_read,
 669	.llseek = seq_lseek,
 670	.release = single_release,
 671	.write = lsdc_crtc_man_op_write,
 672};
 673
 674static int lsdc_crtc_late_register(struct drm_crtc *crtc)
 675{
 676	struct lsdc_display_pipe *dispipe = crtc_to_display_pipe(crtc);
 677	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 678	struct drm_minor *minor = crtc->dev->primary;
 679	unsigned int index = dispipe->index;
 680	unsigned int i;
 681
 682	lcrtc->preg = lsdc_crtc_regs_array[index];
 683	lcrtc->nreg = ARRAY_SIZE(lsdc_crtc_regs_array[index]);
 684	lcrtc->p_info_list = lsdc_crtc_debugfs_list[index];
 685	lcrtc->n_info_list = ARRAY_SIZE(lsdc_crtc_debugfs_list[index]);
 686
 687	for (i = 0; i < lcrtc->n_info_list; ++i)
 688		lcrtc->p_info_list[i].data = lcrtc;
 689
 690	drm_debugfs_create_files(lcrtc->p_info_list, lcrtc->n_info_list,
 691				 crtc->debugfs_entry, minor);
 692
 693	/* Manual operations supported */
 694	debugfs_create_file("ops", 0644, crtc->debugfs_entry, lcrtc,
 695			    &lsdc_crtc_man_op_fops);
 696
 697	return 0;
 698}
 699
 700static void lsdc_crtc_atomic_print_state(struct drm_printer *p,
 701					 const struct drm_crtc_state *state)
 702{
 703	const struct lsdc_crtc_state *priv_state;
 704	const struct lsdc_pixpll_parms *pparms;
 705
 706	priv_state = container_of_const(state, struct lsdc_crtc_state, base);
 707	pparms = &priv_state->pparms;
 708
 709	drm_printf(p, "\tInput clock divider = %u\n", pparms->div_ref);
 710	drm_printf(p, "\tMedium clock multiplier = %u\n", pparms->loopc);
 711	drm_printf(p, "\tOutput clock divider = %u\n", pparms->div_out);
 712}
 713
 714static const struct drm_crtc_funcs ls7a1000_crtc_funcs = {
 715	.reset = lsdc_crtc_reset,
 716	.destroy = drm_crtc_cleanup,
 717	.set_config = drm_atomic_helper_set_config,
 718	.page_flip = drm_atomic_helper_page_flip,
 719	.atomic_duplicate_state = lsdc_crtc_atomic_duplicate_state,
 720	.atomic_destroy_state = lsdc_crtc_atomic_destroy_state,
 721	.late_register = lsdc_crtc_late_register,
 722	.enable_vblank = lsdc_crtc_enable_vblank,
 723	.disable_vblank = lsdc_crtc_disable_vblank,
 724	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
 725	.atomic_print_state = lsdc_crtc_atomic_print_state,
 726};
 727
 728static const struct drm_crtc_funcs ls7a2000_crtc_funcs = {
 729	.reset = lsdc_crtc_reset,
 730	.destroy = drm_crtc_cleanup,
 731	.set_config = drm_atomic_helper_set_config,
 732	.page_flip = drm_atomic_helper_page_flip,
 733	.atomic_duplicate_state = lsdc_crtc_atomic_duplicate_state,
 734	.atomic_destroy_state = lsdc_crtc_atomic_destroy_state,
 735	.late_register = lsdc_crtc_late_register,
 736	.get_vblank_counter = lsdc_crtc_get_vblank_counter,
 737	.enable_vblank = lsdc_crtc_enable_vblank,
 738	.disable_vblank = lsdc_crtc_disable_vblank,
 739	.get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
 740	.atomic_print_state = lsdc_crtc_atomic_print_state,
 741};
 742
 743static enum drm_mode_status
 744lsdc_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
 745{
 746	struct drm_device *ddev = crtc->dev;
 747	struct lsdc_device *ldev = to_lsdc(ddev);
 748	const struct lsdc_desc *descp = ldev->descp;
 749	unsigned int pitch;
 750
 751	if (mode->hdisplay > descp->max_width)
 752		return MODE_BAD_HVALUE;
 753
 754	if (mode->vdisplay > descp->max_height)
 755		return MODE_BAD_VVALUE;
 756
 757	if (mode->clock > descp->max_pixel_clk) {
 758		drm_dbg_kms(ddev, "mode %dx%d, pixel clock=%d is too high\n",
 759			    mode->hdisplay, mode->vdisplay, mode->clock);
 760		return MODE_CLOCK_HIGH;
 761	}
 762
 763	/* 4 for DRM_FORMAT_XRGB8888 */
 764	pitch = mode->hdisplay * 4;
 765
 766	if (pitch % descp->pitch_align) {
 767		drm_dbg_kms(ddev, "align to %u bytes is required: %u\n",
 768			    descp->pitch_align, pitch);
 769		return MODE_BAD_WIDTH;
 770	}
 771
 772	return MODE_OK;
 773}
 774
 775static int lsdc_pixpll_atomic_check(struct drm_crtc *crtc,
 776				    struct drm_crtc_state *state)
 777{
 778	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 779	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
 780	const struct lsdc_pixpll_funcs *pfuncs = pixpll->funcs;
 781	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
 782	unsigned int clock = state->mode.clock;
 783	int ret;
 784
 785	ret = pfuncs->compute(pixpll, clock, &priv_state->pparms);
 786	if (ret) {
 787		drm_warn(crtc->dev, "Failed to find PLL params for %ukHz\n",
 788			 clock);
 789		return -EINVAL;
 790	}
 791
 792	return 0;
 793}
 794
 795static int lsdc_crtc_helper_atomic_check(struct drm_crtc *crtc,
 796					 struct drm_atomic_state *state)
 797{
 798	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 799
 800	if (!crtc_state->enable)
 801		return 0;
 802
 803	return lsdc_pixpll_atomic_check(crtc, crtc_state);
 804}
 805
 806static void lsdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
 807{
 808	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 809	const struct lsdc_crtc_hw_ops *crtc_hw_ops = lcrtc->hw_ops;
 810	struct lsdc_pixpll *pixpll = &lcrtc->pixpll;
 811	const struct lsdc_pixpll_funcs *pixpll_funcs = pixpll->funcs;
 812	struct drm_crtc_state *state = crtc->state;
 813	struct drm_display_mode *mode = &state->mode;
 814	struct lsdc_crtc_state *priv_state = to_lsdc_crtc_state(state);
 815
 816	pixpll_funcs->update(pixpll, &priv_state->pparms);
 817
 818	if (crtc_hw_ops->set_dma_step) {
 819		unsigned int width_in_bytes = mode->hdisplay * 4;
 820		enum lsdc_dma_steps dma_step;
 821
 822		/*
 823		 * Using DMA step as large as possible, for improving
 824		 * hardware DMA efficiency.
 825		 */
 826		if (width_in_bytes % 256 == 0)
 827			dma_step = LSDC_DMA_STEP_256_BYTES;
 828		else if (width_in_bytes % 128 == 0)
 829			dma_step = LSDC_DMA_STEP_128_BYTES;
 830		else if (width_in_bytes % 64 == 0)
 831			dma_step = LSDC_DMA_STEP_64_BYTES;
 832		else  /* width_in_bytes % 32 == 0 */
 833			dma_step = LSDC_DMA_STEP_32_BYTES;
 834
 835		crtc_hw_ops->set_dma_step(lcrtc, dma_step);
 836	}
 837
 838	crtc_hw_ops->set_mode(lcrtc, mode);
 839}
 840
 841static void lsdc_crtc_send_vblank(struct drm_crtc *crtc)
 842{
 843	struct drm_device *ddev = crtc->dev;
 844	unsigned long flags;
 845
 846	if (!crtc->state || !crtc->state->event)
 847		return;
 848
 849	drm_dbg(ddev, "Send vblank manually\n");
 850
 851	spin_lock_irqsave(&ddev->event_lock, flags);
 852	drm_crtc_send_vblank_event(crtc, crtc->state->event);
 853	crtc->state->event = NULL;
 854	spin_unlock_irqrestore(&ddev->event_lock, flags);
 855}
 856
 857static void lsdc_crtc_atomic_enable(struct drm_crtc *crtc,
 858				    struct drm_atomic_state *state)
 859{
 860	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 861
 862	if (lcrtc->has_vblank)
 863		drm_crtc_vblank_on(crtc);
 864
 865	lcrtc->hw_ops->enable(lcrtc);
 866}
 867
 868static void lsdc_crtc_atomic_disable(struct drm_crtc *crtc,
 869				     struct drm_atomic_state *state)
 870{
 871	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 872
 873	if (lcrtc->has_vblank)
 874		drm_crtc_vblank_off(crtc);
 875
 876	lcrtc->hw_ops->disable(lcrtc);
 877
 878	/*
 879	 * Make sure we issue a vblank event after disabling the CRTC if
 880	 * someone was waiting it.
 881	 */
 882	lsdc_crtc_send_vblank(crtc);
 883}
 884
 885static void lsdc_crtc_atomic_flush(struct drm_crtc *crtc,
 886				   struct drm_atomic_state *state)
 887{
 888	spin_lock_irq(&crtc->dev->event_lock);
 889	if (crtc->state->event) {
 890		if (drm_crtc_vblank_get(crtc) == 0)
 891			drm_crtc_arm_vblank_event(crtc, crtc->state->event);
 892		else
 893			drm_crtc_send_vblank_event(crtc, crtc->state->event);
 894		crtc->state->event = NULL;
 895	}
 896	spin_unlock_irq(&crtc->dev->event_lock);
 897}
 898
 899static bool lsdc_crtc_get_scanout_position(struct drm_crtc *crtc,
 900					   bool in_vblank_irq,
 901					   int *vpos,
 902					   int *hpos,
 903					   ktime_t *stime,
 904					   ktime_t *etime,
 905					   const struct drm_display_mode *mode)
 906{
 907	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 908	const struct lsdc_crtc_hw_ops *ops = lcrtc->hw_ops;
 909	int vsw, vbp, vactive_start, vactive_end, vfp_end;
 910	int x, y;
 911
 912	vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
 913	vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
 914
 915	vactive_start = vsw + vbp + 1;
 916	vactive_end = vactive_start + mode->crtc_vdisplay;
 917
 918	/* last scan line before VSYNC */
 919	vfp_end = mode->crtc_vtotal;
 920
 921	if (stime)
 922		*stime = ktime_get();
 923
 924	ops->get_scan_pos(lcrtc, &x, &y);
 925
 926	if (y > vactive_end)
 927		y = y - vfp_end - vactive_start;
 928	else
 929		y -= vactive_start;
 930
 931	*vpos = y;
 932	*hpos = 0;
 933
 934	if (etime)
 935		*etime = ktime_get();
 936
 937	return true;
 938}
 939
 940static const struct drm_crtc_helper_funcs lsdc_crtc_helper_funcs = {
 941	.mode_valid = lsdc_crtc_mode_valid,
 942	.mode_set_nofb = lsdc_crtc_mode_set_nofb,
 943	.atomic_enable = lsdc_crtc_atomic_enable,
 944	.atomic_disable = lsdc_crtc_atomic_disable,
 945	.atomic_check = lsdc_crtc_helper_atomic_check,
 946	.atomic_flush = lsdc_crtc_atomic_flush,
 947	.get_scanout_position = lsdc_crtc_get_scanout_position,
 948};
 949
 950int ls7a1000_crtc_init(struct drm_device *ddev,
 951		       struct drm_crtc *crtc,
 952		       struct drm_plane *primary,
 953		       struct drm_plane *cursor,
 954		       unsigned int index,
 955		       bool has_vblank)
 956{
 957	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 958	int ret;
 959
 960	ret = lsdc_pixpll_init(&lcrtc->pixpll, ddev, index);
 961	if (ret) {
 962		drm_err(ddev, "pixel pll init failed: %d\n", ret);
 963		return ret;
 964	}
 965
 966	lcrtc->ldev = to_lsdc(ddev);
 967	lcrtc->has_vblank = has_vblank;
 968	lcrtc->hw_ops = &ls7a1000_crtc_hw_ops[index];
 969
 970	ret = drm_crtc_init_with_planes(ddev, crtc, primary, cursor,
 971					&ls7a1000_crtc_funcs,
 972					"LS-CRTC-%d", index);
 973	if (ret) {
 974		drm_err(ddev, "crtc init with planes failed: %d\n", ret);
 975		return ret;
 976	}
 977
 978	drm_crtc_helper_add(crtc, &lsdc_crtc_helper_funcs);
 979
 980	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
 981	if (ret)
 982		return ret;
 983
 984	drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
 985
 986	return 0;
 987}
 988
 989int ls7a2000_crtc_init(struct drm_device *ddev,
 990		       struct drm_crtc *crtc,
 991		       struct drm_plane *primary,
 992		       struct drm_plane *cursor,
 993		       unsigned int index,
 994		       bool has_vblank)
 995{
 996	struct lsdc_crtc *lcrtc = to_lsdc_crtc(crtc);
 997	int ret;
 998
 999	ret = lsdc_pixpll_init(&lcrtc->pixpll, ddev, index);
1000	if (ret) {
1001		drm_err(ddev, "crtc init with pll failed: %d\n", ret);
1002		return ret;
1003	}
1004
1005	lcrtc->ldev = to_lsdc(ddev);
1006	lcrtc->has_vblank = has_vblank;
1007	lcrtc->hw_ops = &ls7a2000_crtc_hw_ops[index];
1008
1009	ret = drm_crtc_init_with_planes(ddev, crtc, primary, cursor,
1010					&ls7a2000_crtc_funcs,
1011					"LS-CRTC-%u", index);
1012	if (ret) {
1013		drm_err(ddev, "crtc init with planes failed: %d\n", ret);
1014		return ret;
1015	}
1016
1017	drm_crtc_helper_add(crtc, &lsdc_crtc_helper_funcs);
1018
1019	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
1020	if (ret)
1021		return ret;
1022
1023	drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
1024
1025	return 0;
1026}
~/ Read-only file preview.