Linux Audio

Check our new training course

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