File Index
Files and directories
Sign in
FILE

ast_mode.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/ast/ast_mode.c C
   1/*
   2 * Copyright 2012 Red Hat Inc.
   3 * Parts based on xf86-video-ast
   4 * Copyright (c) 2005 ASPEED Technology Inc.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a
   7 * copy of this software and associated documentation files (the
   8 * "Software"), to deal in the Software without restriction, including
   9 * without limitation the rights to use, copy, modify, merge, publish,
  10 * distribute, sub license, and/or sell copies of the Software, and to
  11 * permit persons to whom the Software is furnished to do so, subject to
  12 * the following conditions:
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * The above copyright notice and this permission notice (including the
  23 * next paragraph) shall be included in all copies or substantial portions
  24 * of the Software.
  25 *
  26 */
  27/*
  28 * Authors: Dave Airlie <airlied@redhat.com>
  29 */
  30
  31#include <linux/delay.h>
  32#include <linux/pci.h>
  33
  34#include <drm/drm_atomic.h>
  35#include <drm/drm_atomic_helper.h>
  36#include <drm/drm_color_mgmt.h>
  37#include <drm/drm_crtc.h>
  38#include <drm/drm_damage_helper.h>
  39#include <drm/drm_format_helper.h>
  40#include <drm/drm_fourcc.h>
  41#include <drm/drm_gem_atomic_helper.h>
  42#include <drm/drm_gem_framebuffer_helper.h>
  43#include <drm/drm_gem_shmem_helper.h>
  44#include <drm/drm_managed.h>
  45#include <drm/drm_panic.h>
  46#include <drm/drm_print.h>
  47#include <drm/drm_probe_helper.h>
  48
  49#include "ast_drv.h"
  50#include "ast_tables.h"
  51#include "ast_vbios.h"
  52
  53#define AST_LUT_SIZE 256
  54
  55#define AST_PRIMARY_PLANE_MAX_OFFSET	(BIT(16) - 1)
  56
  57static unsigned long ast_fb_vram_offset(void)
  58{
  59	return 0; // with shmem, the primary plane is always at offset 0
  60}
  61
  62static unsigned long ast_fb_vram_size(struct ast_device *ast)
  63{
  64	struct drm_device *dev = &ast->base;
  65	unsigned long offset = ast_fb_vram_offset(); // starts at offset
  66	long cursor_offset = ast_cursor_vram_offset(ast); // ends at cursor offset
  67
  68	if (cursor_offset < 0)
  69		cursor_offset = ast->vram_size; // no cursor; it's all ours
  70	if (drm_WARN_ON_ONCE(dev, offset > cursor_offset))
  71		return 0; // cannot legally happen; signal error
  72	return cursor_offset - offset;
  73}
  74
  75static void ast_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
  76			      u16 red, u16 green, u16 blue)
  77{
  78	struct drm_device *dev = crtc->dev;
  79	struct ast_device *ast = to_ast_device(dev);
  80	u8 i8 = index & 0xff;
  81	u8 r8 = red >> 8;
  82	u8 g8 = green >> 8;
  83	u8 b8 = blue >> 8;
  84
  85	if (drm_WARN_ON_ONCE(dev, index != i8))
  86		return; /* driver bug */
  87
  88	ast_io_write8(ast, AST_IO_VGADWR, i8);
  89	ast_io_read8(ast, AST_IO_VGASRI);
  90	ast_io_write8(ast, AST_IO_VGAPDR, r8);
  91	ast_io_read8(ast, AST_IO_VGASRI);
  92	ast_io_write8(ast, AST_IO_VGAPDR, g8);
  93	ast_io_read8(ast, AST_IO_VGASRI);
  94	ast_io_write8(ast, AST_IO_VGAPDR, b8);
  95	ast_io_read8(ast, AST_IO_VGASRI);
  96}
  97
  98static void ast_crtc_fill_gamma(struct ast_device *ast,
  99				const struct drm_format_info *format)
 100{
 101	struct drm_crtc *crtc = &ast->crtc;
 102
 103	switch (format->format) {
 104	case DRM_FORMAT_C8:
 105		/* gamma table is used as color palette */
 106		drm_crtc_fill_palette_8(crtc, ast_set_gamma_lut);
 107		break;
 108	case DRM_FORMAT_RGB565:
 109		/* also uses 8-bit gamma ramp on low-color modes */
 110		fallthrough;
 111	case DRM_FORMAT_XRGB8888:
 112		drm_crtc_fill_gamma_888(crtc, ast_set_gamma_lut);
 113		break;
 114	default:
 115		drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
 116			      &format->format);
 117		break;
 118	}
 119}
 120
 121static void ast_crtc_load_gamma(struct ast_device *ast,
 122				const struct drm_format_info *format,
 123				struct drm_color_lut *lut)
 124{
 125	struct drm_crtc *crtc = &ast->crtc;
 126
 127	switch (format->format) {
 128	case DRM_FORMAT_C8:
 129		/* gamma table is used as color palette */
 130		drm_crtc_load_palette_8(crtc, lut, ast_set_gamma_lut);
 131		break;
 132	case DRM_FORMAT_RGB565:
 133		/* also uses 8-bit gamma ramp on low-color modes */
 134		fallthrough;
 135	case DRM_FORMAT_XRGB8888:
 136		drm_crtc_load_gamma_888(crtc, lut, ast_set_gamma_lut);
 137		break;
 138	default:
 139		drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n",
 140			      &format->format);
 141		break;
 142	}
 143}
 144
 145static void ast_set_vbios_color_reg(struct ast_device *ast,
 146				    const struct drm_format_info *format,
 147				    const struct ast_vbios_enhtable *vmode)
 148{
 149	u32 color_index;
 150
 151	switch (format->cpp[0]) {
 152	case 1:
 153		color_index = VGAModeIndex - 1;
 154		break;
 155	case 2:
 156		color_index = HiCModeIndex;
 157		break;
 158	case 3:
 159	case 4:
 160		color_index = TrueCModeIndex;
 161		break;
 162	default:
 163		return;
 164	}
 165
 166	ast_set_index_reg(ast, AST_IO_VGACRI, 0x8c, (u8)((color_index & 0x0f) << 4));
 167
 168	ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
 169
 170	if (vmode->flags & NewModeInfo) {
 171		ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
 172		ast_set_index_reg(ast, AST_IO_VGACRI, 0x92, format->cpp[0] * 8);
 173	}
 174}
 175
 176static void ast_set_vbios_mode_reg(struct ast_device *ast,
 177				   const struct drm_display_mode *adjusted_mode,
 178				   const struct ast_vbios_enhtable *vmode)
 179{
 180	u32 refresh_rate_index, mode_id;
 181
 182	refresh_rate_index = vmode->refresh_rate_index;
 183	mode_id = vmode->mode_id;
 184
 185	ast_set_index_reg(ast, AST_IO_VGACRI, 0x8d, refresh_rate_index & 0xff);
 186	ast_set_index_reg(ast, AST_IO_VGACRI, 0x8e, mode_id & 0xff);
 187
 188	ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0x00);
 189
 190	if (vmode->flags & NewModeInfo) {
 191		ast_set_index_reg(ast, AST_IO_VGACRI, 0x91, 0xa8);
 192		ast_set_index_reg(ast, AST_IO_VGACRI, 0x93, adjusted_mode->clock / 1000);
 193		ast_set_index_reg(ast, AST_IO_VGACRI, 0x94, adjusted_mode->crtc_hdisplay);
 194		ast_set_index_reg(ast, AST_IO_VGACRI, 0x95, adjusted_mode->crtc_hdisplay >> 8);
 195		ast_set_index_reg(ast, AST_IO_VGACRI, 0x96, adjusted_mode->crtc_vdisplay);
 196		ast_set_index_reg(ast, AST_IO_VGACRI, 0x97, adjusted_mode->crtc_vdisplay >> 8);
 197	}
 198}
 199
 200static void ast_set_std_reg(struct ast_device *ast,
 201			    struct drm_display_mode *mode,
 202			    const struct ast_vbios_stdtable *stdtable)
 203{
 204	u32 i;
 205	u8 jreg;
 206
 207	jreg = stdtable->misc;
 208	ast_io_write8(ast, AST_IO_VGAMR_W, jreg);
 209
 210	/* Set SEQ; except Screen Disable field */
 211	ast_set_index_reg(ast, AST_IO_VGASRI, 0x00, 0x03);
 212	ast_set_index_reg_mask(ast, AST_IO_VGASRI, 0x01, 0x20, stdtable->seq[0]);
 213	for (i = 1; i < 4; i++) {
 214		jreg = stdtable->seq[i];
 215		ast_set_index_reg(ast, AST_IO_VGASRI, (i + 1), jreg);
 216	}
 217
 218	/* Set CRTC; except base address and offset */
 219	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
 220	for (i = 0; i < 12; i++)
 221		ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
 222	for (i = 14; i < 19; i++)
 223		ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
 224	for (i = 20; i < 25; i++)
 225		ast_set_index_reg(ast, AST_IO_VGACRI, i, stdtable->crtc[i]);
 226
 227	/* set AR */
 228	jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
 229	for (i = 0; i < 20; i++) {
 230		jreg = stdtable->ar[i];
 231		ast_io_write8(ast, AST_IO_VGAARI_W, (u8)i);
 232		ast_io_write8(ast, AST_IO_VGAARI_W, jreg);
 233	}
 234	ast_io_write8(ast, AST_IO_VGAARI_W, 0x14);
 235	ast_io_write8(ast, AST_IO_VGAARI_W, 0x00);
 236
 237	jreg = ast_io_read8(ast, AST_IO_VGAIR1_R);
 238	ast_io_write8(ast, AST_IO_VGAARI_W, 0x20);
 239
 240	/* Set GR */
 241	for (i = 0; i < 9; i++)
 242		ast_set_index_reg(ast, AST_IO_VGAGRI, i, stdtable->gr[i]);
 243}
 244
 245static void ast_set_crtc_reg(struct ast_device *ast, struct drm_display_mode *mode,
 246			     const struct ast_vbios_enhtable *vmode)
 247{
 248	u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
 249	u16 temp;
 250	unsigned char crtc_hsync_precatch = 0;
 251
 252	if (ast->quirks->crtc_hsync_precatch_needed && (vmode->flags & AST2500PreCatchCRT))
 253		crtc_hsync_precatch = 40;
 254
 255	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x00);
 256
 257	temp = (mode->crtc_htotal >> 3) - 5;
 258	if (temp & 0x100)
 259		jregAC |= 0x01; /* HT D[8] */
 260	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x00, 0x00, temp);
 261
 262	temp = (mode->crtc_hdisplay >> 3) - 1;
 263	if (temp & 0x100)
 264		jregAC |= 0x04; /* HDE D[8] */
 265	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x01, 0x00, temp);
 266
 267	temp = (mode->crtc_hblank_start >> 3) - 1;
 268	if (temp & 0x100)
 269		jregAC |= 0x10; /* HBS D[8] */
 270	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x02, 0x00, temp);
 271
 272	temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
 273	if (temp & 0x20)
 274		jreg05 |= 0x80;  /* HBE D[5] */
 275	if (temp & 0x40)
 276		jregAD |= 0x01;  /* HBE D[5] */
 277	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x03, 0xE0, (temp & 0x1f));
 278
 279	temp = ((mode->crtc_hsync_start - crtc_hsync_precatch) >> 3) - 1;
 280	if (temp & 0x100)
 281		jregAC |= 0x40; /* HRS D[5] */
 282	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x04, 0x00, temp);
 283
 284	temp = (((mode->crtc_hsync_end - crtc_hsync_precatch) >> 3) - 1) & 0x3f;
 285	if (temp & 0x20)
 286		jregAD |= 0x04; /* HRE D[5] */
 287	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
 288
 289	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAC, 0x00, jregAC);
 290	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAD, 0x00, jregAD);
 291
 292	if (ast->quirks->crtc_hsync_add4_needed && mode->crtc_vdisplay == 1080)
 293		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x02);
 294	else
 295		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xFC, 0xFD, 0x00);
 296
 297	/* vert timings */
 298	temp = (mode->crtc_vtotal) - 2;
 299	if (temp & 0x100)
 300		jreg07 |= 0x01;
 301	if (temp & 0x200)
 302		jreg07 |= 0x20;
 303	if (temp & 0x400)
 304		jregAE |= 0x01;
 305	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x06, 0x00, temp);
 306
 307	temp = (mode->crtc_vsync_start) - 1;
 308	if (temp & 0x100)
 309		jreg07 |= 0x04;
 310	if (temp & 0x200)
 311		jreg07 |= 0x80;
 312	if (temp & 0x400)
 313		jregAE |= 0x08;
 314	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x10, 0x00, temp);
 315
 316	temp = (mode->crtc_vsync_end - 1) & 0x3f;
 317	if (temp & 0x10)
 318		jregAE |= 0x20;
 319	if (temp & 0x20)
 320		jregAE |= 0x40;
 321	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x70, temp & 0xf);
 322
 323	temp = mode->crtc_vdisplay - 1;
 324	if (temp & 0x100)
 325		jreg07 |= 0x02;
 326	if (temp & 0x200)
 327		jreg07 |= 0x40;
 328	if (temp & 0x400)
 329		jregAE |= 0x02;
 330	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x12, 0x00, temp);
 331
 332	temp = mode->crtc_vblank_start - 1;
 333	if (temp & 0x100)
 334		jreg07 |= 0x08;
 335	if (temp & 0x200)
 336		jreg09 |= 0x20;
 337	if (temp & 0x400)
 338		jregAE |= 0x04;
 339	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x15, 0x00, temp);
 340
 341	temp = mode->crtc_vblank_end - 1;
 342	if (temp & 0x100)
 343		jregAE |= 0x10;
 344	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x16, 0x00, temp);
 345
 346	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x07, 0x00, jreg07);
 347	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x09, 0xdf, jreg09);
 348	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xAE, 0x00, (jregAE | 0x80));
 349
 350	if (crtc_hsync_precatch)
 351		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x80);
 352	else
 353		ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0x3f, 0x00);
 354
 355	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x11, 0x7f, 0x80);
 356}
 357
 358static void ast_set_offset_reg(struct ast_device *ast,
 359			       struct drm_framebuffer *fb)
 360{
 361	u16 offset;
 362
 363	offset = fb->pitches[0] >> 3;
 364	ast_set_index_reg(ast, AST_IO_VGACRI, 0x13, (offset & 0xff));
 365	ast_set_index_reg(ast, AST_IO_VGACRI, 0xb0, (offset >> 8) & 0x3f);
 366}
 367
 368static void ast_set_dclk_reg(struct ast_device *ast,
 369			     struct drm_display_mode *mode,
 370			     const struct ast_vbios_enhtable *vmode)
 371{
 372	const struct ast_vbios_dclk_info *clk_info = &ast->dclk_table[vmode->dclk_index];
 373
 374	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc0, 0x00, clk_info->param1);
 375	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xc1, 0x00, clk_info->param2);
 376	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xbb, 0x0f,
 377			       (clk_info->param3 & 0xc0) |
 378			       ((clk_info->param3 & 0x3) << 4));
 379}
 380
 381static void ast_set_color_reg(struct ast_device *ast,
 382			      const struct drm_format_info *format)
 383{
 384	u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
 385
 386	switch (format->cpp[0] * 8) {
 387	case 8:
 388		jregA0 = 0x70;
 389		jregA3 = 0x01;
 390		jregA8 = 0x00;
 391		break;
 392	case 15:
 393	case 16:
 394		jregA0 = 0x70;
 395		jregA3 = 0x04;
 396		jregA8 = 0x02;
 397		break;
 398	case 32:
 399		jregA0 = 0x70;
 400		jregA3 = 0x08;
 401		jregA8 = 0x02;
 402		break;
 403	}
 404
 405	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa0, 0x8f, jregA0);
 406	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xf0, jregA3);
 407	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa8, 0xfd, jregA8);
 408}
 409
 410static void ast_set_crtthd_reg(struct ast_device *ast)
 411{
 412	u8 vgacra6 = ast->quirks->crtc_mem_req_threshold_low;
 413	u8 vgacra7 = ast->quirks->crtc_mem_req_threshold_high;
 414
 415	ast_set_index_reg(ast, AST_IO_VGACRI, 0xa7, vgacra7);
 416	ast_set_index_reg(ast, AST_IO_VGACRI, 0xa6, vgacra6);
 417}
 418
 419static void ast_set_sync_reg(struct ast_device *ast,
 420			     struct drm_display_mode *mode,
 421			     const struct ast_vbios_enhtable *vmode)
 422{
 423	u8 jreg;
 424
 425	jreg  = ast_io_read8(ast, AST_IO_VGAMR_R);
 426	jreg &= ~0xC0;
 427	if (vmode->flags & NVSync)
 428		jreg |= 0x80;
 429	if (vmode->flags & NHSync)
 430		jreg |= 0x40;
 431	ast_io_write8(ast, AST_IO_VGAMR_W, jreg);
 432}
 433
 434static void ast_set_start_address_crt1(struct ast_device *ast,
 435				       unsigned int offset)
 436{
 437	u32 addr;
 438
 439	addr = offset >> 2;
 440	ast_set_index_reg(ast, AST_IO_VGACRI, 0x0d, (u8)(addr & 0xff));
 441	ast_set_index_reg(ast, AST_IO_VGACRI, 0x0c, (u8)((addr >> 8) & 0xff));
 442	ast_set_index_reg(ast, AST_IO_VGACRI, 0xaf, (u8)((addr >> 16) & 0xff));
 443
 444}
 445
 446static void ast_wait_for_vretrace(struct ast_device *ast)
 447{
 448	unsigned long timeout = jiffies + HZ;
 449	u8 vgair1;
 450
 451	do {
 452		vgair1 = ast_io_read8(ast, AST_IO_VGAIR1_R);
 453	} while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout));
 454}
 455
 456/*
 457 * Planes
 458 */
 459
 460int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane,
 461		   u64 offset, unsigned long size,
 462		   uint32_t possible_crtcs,
 463		   const struct drm_plane_funcs *funcs,
 464		   const uint32_t *formats, unsigned int format_count,
 465		   const uint64_t *format_modifiers,
 466		   enum drm_plane_type type)
 467{
 468	struct drm_plane *plane = &ast_plane->base;
 469
 470	ast_plane->offset = offset;
 471	ast_plane->size = size;
 472
 473	return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
 474					formats, format_count, format_modifiers,
 475					type, NULL);
 476}
 477
 478void __iomem *ast_plane_vaddr(struct ast_plane *ast_plane)
 479{
 480	struct ast_device *ast = to_ast_device(ast_plane->base.dev);
 481
 482	return ast->vram + ast_plane->offset;
 483}
 484
 485/*
 486 * Primary plane
 487 */
 488
 489static const uint32_t ast_primary_plane_formats[] = {
 490	DRM_FORMAT_XRGB8888,
 491	DRM_FORMAT_RGB565,
 492	DRM_FORMAT_C8,
 493};
 494
 495static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane,
 496						 struct drm_atomic_state *state)
 497{
 498	struct drm_device *dev = plane->dev;
 499	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
 500	struct drm_crtc_state *new_crtc_state = NULL;
 501	struct ast_crtc_state *new_ast_crtc_state;
 502	int ret;
 503
 504	if (new_plane_state->crtc)
 505		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc);
 506
 507	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
 508						  DRM_PLANE_NO_SCALING,
 509						  DRM_PLANE_NO_SCALING,
 510						  false, true);
 511	if (ret) {
 512		return ret;
 513	} else if (!new_plane_state->visible) {
 514		if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */
 515			return -EINVAL;
 516		else
 517			return 0;
 518	}
 519
 520	new_ast_crtc_state = to_ast_crtc_state(new_crtc_state);
 521
 522	new_ast_crtc_state->format = new_plane_state->fb->format;
 523
 524	return 0;
 525}
 526
 527static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src,
 528			      struct drm_framebuffer *fb,
 529			      const struct drm_rect *clip,
 530			      struct drm_format_conv_state *fmtcnv_state)
 531{
 532	struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane_vaddr(ast_plane));
 533
 534	iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
 535
 536#if defined(__BIG_ENDIAN)
 537	drm_fb_swab(&dst, fb->pitches, src, fb, clip, !src[0].is_iomem, fmtcnv_state);
 538#else
 539	drm_fb_memcpy(&dst, fb->pitches, src, fb, clip);
 540#endif
 541}
 542
 543static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane,
 544						   struct drm_atomic_state *state)
 545{
 546	struct drm_device *dev = plane->dev;
 547	struct ast_device *ast = to_ast_device(dev);
 548	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
 549	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
 550	struct drm_framebuffer *fb = plane_state->fb;
 551	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 552	struct drm_framebuffer *old_fb = old_plane_state->fb;
 553	struct ast_plane *ast_plane = to_ast_plane(plane);
 554	struct drm_crtc *crtc = plane_state->crtc;
 555	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 556	struct drm_rect damage;
 557	struct drm_atomic_helper_damage_iter iter;
 558
 559	if (!old_fb || (fb->format != old_fb->format) || crtc_state->mode_changed) {
 560		struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
 561
 562		ast_set_color_reg(ast, fb->format);
 563		ast_set_vbios_color_reg(ast, fb->format, ast_crtc_state->vmode);
 564	}
 565
 566	/* if the buffer comes from another device */
 567	if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) {
 568		drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
 569		drm_atomic_for_each_plane_damage(&iter, &damage) {
 570			ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage,
 571					  &shadow_plane_state->fmtcnv_state);
 572		}
 573
 574		drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
 575	}
 576
 577	/*
 578	 * Some BMCs stop scanning out the video signal after the driver
 579	 * reprogrammed the offset. This stalls display output for several
 580	 * seconds and makes the display unusable. Therefore only update
 581	 * the offset if it changes.
 582	 */
 583	if (!old_fb || old_fb->pitches[0] != fb->pitches[0])
 584		ast_set_offset_reg(ast, fb);
 585}
 586
 587static void ast_primary_plane_helper_atomic_enable(struct drm_plane *plane,
 588						   struct drm_atomic_state *state)
 589{
 590	struct ast_device *ast = to_ast_device(plane->dev);
 591	struct ast_plane *ast_plane = to_ast_plane(plane);
 592
 593	/*
 594	 * Some BMCs stop scanning out the video signal after the driver
 595	 * reprogrammed the scanout address. This stalls display
 596	 * output for several seconds and makes the display unusable.
 597	 * Therefore only reprogram the address after enabling the plane.
 598	 */
 599	ast_set_start_address_crt1(ast, (u32)ast_plane->offset);
 600}
 601
 602static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,
 603						    struct drm_atomic_state *state)
 604{
 605	/*
 606	 * Keep this empty function to avoid calling
 607	 * atomic_update when disabling the plane.
 608	 */
 609}
 610
 611static int ast_primary_plane_helper_get_scanout_buffer(struct drm_plane *plane,
 612						       struct drm_scanout_buffer *sb)
 613{
 614	struct ast_plane *ast_plane = to_ast_plane(plane);
 615
 616	if (plane->state && plane->state->fb) {
 617		sb->format = plane->state->fb->format;
 618		sb->width = plane->state->fb->width;
 619		sb->height = plane->state->fb->height;
 620		sb->pitch[0] = plane->state->fb->pitches[0];
 621		iosys_map_set_vaddr_iomem(&sb->map[0], ast_plane_vaddr(ast_plane));
 622		return 0;
 623	}
 624	return -ENODEV;
 625}
 626
 627static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = {
 628	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
 629	.atomic_check = ast_primary_plane_helper_atomic_check,
 630	.atomic_update = ast_primary_plane_helper_atomic_update,
 631	.atomic_enable = ast_primary_plane_helper_atomic_enable,
 632	.atomic_disable = ast_primary_plane_helper_atomic_disable,
 633	.get_scanout_buffer = ast_primary_plane_helper_get_scanout_buffer,
 634};
 635
 636static const struct drm_plane_funcs ast_primary_plane_funcs = {
 637	.update_plane = drm_atomic_helper_update_plane,
 638	.disable_plane = drm_atomic_helper_disable_plane,
 639	.destroy = drm_plane_cleanup,
 640	DRM_GEM_SHADOW_PLANE_FUNCS,
 641};
 642
 643static int ast_primary_plane_init(struct ast_device *ast)
 644{
 645	struct drm_device *dev = &ast->base;
 646	struct ast_plane *ast_primary_plane = &ast->primary_plane;
 647	struct drm_plane *primary_plane = &ast_primary_plane->base;
 648	u64 offset = ast_fb_vram_offset();
 649	unsigned long size = ast_fb_vram_size(ast);
 650	int ret;
 651
 652	ret = ast_plane_init(dev, ast_primary_plane, offset, size,
 653			     0x01, &ast_primary_plane_funcs,
 654			     ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats),
 655			     NULL, DRM_PLANE_TYPE_PRIMARY);
 656	if (ret) {
 657		drm_err(dev, "ast_plane_init() failed: %d\n", ret);
 658		return ret;
 659	}
 660	drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs);
 661	drm_plane_enable_fb_damage_clips(primary_plane);
 662
 663	return 0;
 664}
 665
 666/*
 667 * CRTC
 668 */
 669
 670static enum drm_mode_status
 671ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
 672{
 673	struct ast_device *ast = to_ast_device(crtc->dev);
 674	const struct ast_vbios_enhtable *vmode;
 675
 676	vmode = ast_vbios_find_mode(ast, mode);
 677	if (!vmode)
 678		return MODE_NOMODE;
 679
 680	return MODE_OK;
 681}
 682
 683static void ast_crtc_helper_mode_set_nofb(struct drm_crtc *crtc)
 684{
 685	struct drm_device *dev = crtc->dev;
 686	struct ast_device *ast = to_ast_device(dev);
 687	struct drm_crtc_state *crtc_state = crtc->state;
 688	struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
 689	const struct ast_vbios_stdtable *std_table = ast_crtc_state->std_table;
 690	const struct ast_vbios_enhtable *vmode = ast_crtc_state->vmode;
 691	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
 692
 693	/*
 694	 * Ensure that no scanout takes place before reprogramming mode
 695	 * and format registers.
 696	 *
 697	 * TODO: Get vblank interrupts working and remove this line.
 698	 */
 699	ast_wait_for_vretrace(ast);
 700
 701	ast_set_vbios_mode_reg(ast, adjusted_mode, vmode);
 702	ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06);
 703	ast_set_std_reg(ast, adjusted_mode, std_table);
 704	ast_set_crtc_reg(ast, adjusted_mode, vmode);
 705	ast_set_dclk_reg(ast, adjusted_mode, vmode);
 706	ast_set_crtthd_reg(ast);
 707	ast_set_sync_reg(ast, adjusted_mode, vmode);
 708}
 709
 710static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,
 711					struct drm_atomic_state *state)
 712{
 713	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 714	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
 715	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 716	struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
 717	struct drm_device *dev = crtc->dev;
 718	struct ast_device *ast = to_ast_device(dev);
 719	struct ast_crtc_state *ast_state;
 720	const struct drm_format_info *format;
 721	const struct ast_vbios_enhtable *vmode;
 722	unsigned int hborder = 0;
 723	unsigned int vborder = 0;
 724	int ret;
 725
 726	if (!crtc_state->enable)
 727		return 0;
 728
 729	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
 730	if (ret)
 731		return ret;
 732
 733	ast_state = to_ast_crtc_state(crtc_state);
 734
 735	format = ast_state->format;
 736	if (drm_WARN_ON_ONCE(dev, !format))
 737		return -EINVAL; /* BUG: We didn't set format in primary check(). */
 738
 739	/*
 740	 * The gamma LUT has to be reloaded after changing the primary
 741	 * plane's color format.
 742	 */
 743	if (old_ast_crtc_state->format != format)
 744		crtc_state->color_mgmt_changed = true;
 745
 746	if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
 747		if (crtc_state->gamma_lut->length !=
 748		    AST_LUT_SIZE * sizeof(struct drm_color_lut)) {
 749			drm_err(dev, "Wrong size for gamma_lut %zu\n",
 750				crtc_state->gamma_lut->length);
 751			return -EINVAL;
 752		}
 753	}
 754
 755	/*
 756	 * Set register tables.
 757	 *
 758	 * TODO: These tables mix all kinds of fields and should
 759	 *       probably be resolved into various helper functions.
 760	 */
 761	switch (format->format) {
 762	case DRM_FORMAT_C8:
 763		ast_state->std_table = &vbios_stdtable[VGAModeIndex];
 764		break;
 765	case DRM_FORMAT_RGB565:
 766		ast_state->std_table = &vbios_stdtable[HiCModeIndex];
 767		break;
 768	case DRM_FORMAT_RGB888:
 769	case DRM_FORMAT_XRGB8888:
 770		ast_state->std_table = &vbios_stdtable[TrueCModeIndex];
 771		break;
 772	default:
 773		return -EINVAL;
 774	}
 775
 776	/*
 777	 * Find the VBIOS mode and adjust the DRM display mode accordingly
 778	 * if a full modeset is required. Otherwise keep the existing values.
 779	 */
 780	if (drm_atomic_crtc_needs_modeset(crtc_state)) {
 781		vmode = ast_vbios_find_mode(ast, &crtc_state->mode);
 782		if (!vmode)
 783			return -EINVAL;
 784		ast_state->vmode = vmode;
 785
 786		if (vmode->flags & HBorder)
 787			hborder = 8;
 788		if (vmode->flags & VBorder)
 789			vborder = 8;
 790
 791		adjusted_mode->crtc_hdisplay = vmode->hde;
 792		adjusted_mode->crtc_hblank_start = vmode->hde + hborder;
 793		adjusted_mode->crtc_hblank_end = vmode->ht - hborder;
 794		adjusted_mode->crtc_hsync_start = vmode->hde + hborder + vmode->hfp;
 795		adjusted_mode->crtc_hsync_end = vmode->hde + hborder + vmode->hfp + vmode->hsync;
 796		adjusted_mode->crtc_htotal = vmode->ht;
 797
 798		adjusted_mode->crtc_vdisplay = vmode->vde;
 799		adjusted_mode->crtc_vblank_start = vmode->vde + vborder;
 800		adjusted_mode->crtc_vblank_end = vmode->vt - vborder;
 801		adjusted_mode->crtc_vsync_start = vmode->vde + vborder + vmode->vfp;
 802		adjusted_mode->crtc_vsync_end = vmode->vde + vborder + vmode->vfp + vmode->vsync;
 803		adjusted_mode->crtc_vtotal = vmode->vt;
 804	}
 805
 806	return 0;
 807}
 808
 809static void
 810ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 811			     struct drm_atomic_state *state)
 812{
 813	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
 814									  crtc);
 815	struct drm_device *dev = crtc->dev;
 816	struct ast_device *ast = to_ast_device(dev);
 817	struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
 818
 819	/*
 820	 * The gamma LUT has to be reloaded after changing the primary
 821	 * plane's color format.
 822	 */
 823	if (crtc_state->enable && crtc_state->color_mgmt_changed) {
 824		if (crtc_state->gamma_lut)
 825			ast_crtc_load_gamma(ast,
 826					    ast_crtc_state->format,
 827					    crtc_state->gamma_lut->data);
 828		else
 829			ast_crtc_fill_gamma(ast, ast_crtc_state->format);
 830	}
 831}
 832
 833static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)
 834{
 835	struct ast_device *ast = to_ast_device(crtc->dev);
 836	u8 vgacr17 = 0x00;
 837	u8 vgacrb6 = 0xff;
 838
 839	vgacr17 |= AST_IO_VGACR17_SYNC_ENABLE;
 840	vgacrb6 &= ~(AST_IO_VGACRB6_VSYNC_OFF | AST_IO_VGACRB6_HSYNC_OFF);
 841
 842	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x17, 0x7f, vgacr17);
 843	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xfc, vgacrb6);
 844}
 845
 846static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)
 847{
 848	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 849	struct ast_device *ast = to_ast_device(crtc->dev);
 850	u8 vgacr17 = 0xff;
 851
 852	vgacr17 &= ~AST_IO_VGACR17_SYNC_ENABLE;
 853	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x17, 0x7f, vgacr17);
 854
 855	/*
 856	 * HW cursors require the underlying primary plane and CRTC to
 857	 * display a valid mode and image. This is not the case during
 858	 * full modeset operations. So we temporarily disable any active
 859	 * plane, including the HW cursor. Each plane's atomic_update()
 860	 * helper will re-enable it if necessary.
 861	 *
 862	 * We only do this during *full* modesets. It does not affect
 863	 * simple pageflips on the planes.
 864	 */
 865	drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
 866}
 867
 868static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
 869	.mode_valid = ast_crtc_helper_mode_valid,
 870	.mode_set_nofb = ast_crtc_helper_mode_set_nofb,
 871	.atomic_check = ast_crtc_helper_atomic_check,
 872	.atomic_flush = ast_crtc_helper_atomic_flush,
 873	.atomic_enable = ast_crtc_helper_atomic_enable,
 874	.atomic_disable = ast_crtc_helper_atomic_disable,
 875};
 876
 877static void ast_crtc_reset(struct drm_crtc *crtc)
 878{
 879	struct ast_crtc_state *ast_state =
 880		kzalloc(sizeof(*ast_state), GFP_KERNEL);
 881
 882	if (crtc->state)
 883		crtc->funcs->atomic_destroy_state(crtc, crtc->state);
 884
 885	if (ast_state)
 886		__drm_atomic_helper_crtc_reset(crtc, &ast_state->base);
 887	else
 888		__drm_atomic_helper_crtc_reset(crtc, NULL);
 889}
 890
 891static struct drm_crtc_state *
 892ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
 893{
 894	struct ast_crtc_state *new_ast_state, *ast_state;
 895	struct drm_device *dev = crtc->dev;
 896
 897	if (drm_WARN_ON(dev, !crtc->state))
 898		return NULL;
 899
 900	new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL);
 901	if (!new_ast_state)
 902		return NULL;
 903	__drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base);
 904
 905	ast_state = to_ast_crtc_state(crtc->state);
 906
 907	new_ast_state->format = ast_state->format;
 908	new_ast_state->std_table = ast_state->std_table;
 909	new_ast_state->vmode = ast_state->vmode;
 910
 911	return &new_ast_state->base;
 912}
 913
 914static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc,
 915					  struct drm_crtc_state *state)
 916{
 917	struct ast_crtc_state *ast_state = to_ast_crtc_state(state);
 918
 919	__drm_atomic_helper_crtc_destroy_state(&ast_state->base);
 920	kfree(ast_state);
 921}
 922
 923static const struct drm_crtc_funcs ast_crtc_funcs = {
 924	.reset = ast_crtc_reset,
 925	.destroy = drm_crtc_cleanup,
 926	.set_config = drm_atomic_helper_set_config,
 927	.page_flip = drm_atomic_helper_page_flip,
 928	.atomic_duplicate_state = ast_crtc_atomic_duplicate_state,
 929	.atomic_destroy_state = ast_crtc_atomic_destroy_state,
 930};
 931
 932static int ast_crtc_init(struct ast_device *ast)
 933{
 934	struct drm_device *dev = &ast->base;
 935	struct drm_crtc *crtc = &ast->crtc;
 936	int ret;
 937
 938	ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base,
 939					&ast->cursor_plane.base.base, &ast_crtc_funcs,
 940					NULL);
 941	if (ret)
 942		return ret;
 943
 944	drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE);
 945	drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE);
 946
 947	drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);
 948
 949	return 0;
 950}
 951
 952/*
 953 * Mode config
 954 */
 955
 956static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
 957{
 958	struct ast_device *ast = to_ast_device(state->dev);
 959
 960	/*
 961	 * Concurrent operations could possibly trigger a call to
 962	 * drm_connector_helper_funcs.get_modes by reading the display
 963	 * modes. Protect access to registers by acquiring the modeset
 964	 * lock.
 965	 */
 966	mutex_lock(&ast->modeset_lock);
 967	drm_atomic_helper_commit_tail(state);
 968	mutex_unlock(&ast->modeset_lock);
 969}
 970
 971static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = {
 972	.atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail,
 973};
 974
 975static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev,
 976						       const struct drm_display_mode *mode)
 977{
 978	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB8888);
 979	struct ast_device *ast = to_ast_device(dev);
 980	unsigned long max_fb_size = ast_fb_vram_size(ast);
 981	u64 pitch;
 982
 983	if (drm_WARN_ON_ONCE(dev, !info))
 984		return MODE_ERROR; /* driver bug */
 985
 986	pitch = drm_format_info_min_pitch(info, 0, mode->hdisplay);
 987	if (!pitch)
 988		return MODE_BAD_WIDTH;
 989	if (pitch > AST_PRIMARY_PLANE_MAX_OFFSET)
 990		return MODE_BAD_WIDTH; /* maximum programmable pitch */
 991	if (pitch > max_fb_size / mode->vdisplay)
 992		return MODE_MEM;
 993
 994	return MODE_OK;
 995}
 996
 997static const struct drm_mode_config_funcs ast_mode_config_funcs = {
 998	.fb_create = drm_gem_fb_create_with_dirty,
 999	.mode_valid = ast_mode_config_mode_valid,
1000	.atomic_check = drm_atomic_helper_check,
1001	.atomic_commit = drm_atomic_helper_commit,
1002};
1003
1004int ast_mode_config_init(struct ast_device *ast)
1005{
1006	struct drm_device *dev = &ast->base;
1007	int ret;
1008
1009	ret = drmm_mutex_init(dev, &ast->modeset_lock);
1010	if (ret)
1011		return ret;
1012
1013	ret = drmm_mode_config_init(dev);
1014	if (ret)
1015		return ret;
1016
1017	dev->mode_config.funcs = &ast_mode_config_funcs;
1018	dev->mode_config.min_width = 0;
1019	dev->mode_config.min_height = 0;
1020	dev->mode_config.preferred_depth = 24;
1021
1022	if (ast->support_fullhd) {
1023		dev->mode_config.max_width = 1920;
1024		dev->mode_config.max_height = 2048;
1025	} else {
1026		dev->mode_config.max_width = 1600;
1027		dev->mode_config.max_height = 1200;
1028	}
1029
1030	dev->mode_config.helper_private = &ast_mode_config_helper_funcs;
1031
1032	ret = ast_primary_plane_init(ast);
1033	if (ret)
1034		return ret;
1035
1036	ret = ast_cursor_plane_init(ast);
1037	if (ret)
1038		return ret;
1039
1040	ret = ast_crtc_init(ast);
1041	if (ret)
1042		return ret;
1043
1044	switch (ast->tx_chip) {
1045	case AST_TX_NONE:
1046		ret = ast_vga_output_init(ast);
1047		break;
1048	case AST_TX_SIL164:
1049		ret = ast_sil164_output_init(ast);
1050		break;
1051	case AST_TX_DP501:
1052		ret = ast_dp501_output_init(ast);
1053		break;
1054	case AST_TX_ASTDP:
1055		ret = ast_astdp_output_init(ast);
1056		break;
1057	}
1058	if (ret)
1059		return ret;
1060
1061	drm_mode_config_reset(dev);
1062	drmm_kms_helper_poll_init(dev);
1063
1064	return 0;
1065}
~/ Read-only file preview.