1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2012 Red Hat Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19 * USE OR OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * The above copyright notice and this permission notice (including the 22 * next paragraph) shall be included in all copies or substantial portions 23 * of the Software. 24 */ 25 /* 26 * Authors: Dave Airlie <airlied@redhat.com> 27 */ 28 29 #include <linux/delay.h> 30 #include <linux/pci.h> 31 32 #include <drm/drm_drv.h> 33 34 #include "ast_drv.h" 35 #include "ast_post.h" 36 37 /* 38 * DRAM type 39 */ 40 41 static enum ast_dram_layout ast_2100_get_dram_layout_p2a(struct ast_device *ast) 42 { 43 u32 mcr_cfg; 44 enum ast_dram_layout dram_layout; 45 46 ast_write32(ast, 0xf004, 0x1e6e0000); 47 ast_write32(ast, 0xf000, 0x1); 48 mcr_cfg = ast_read32(ast, 0x10004); 49 50 switch (mcr_cfg & 0x0c) { 51 case 0: 52 case 4: 53 default: 54 dram_layout = AST_DRAM_512Mx16; 55 break; 56 case 8: 57 if (mcr_cfg & 0x40) 58 dram_layout = AST_DRAM_1Gx16; 59 else 60 dram_layout = AST_DRAM_512Mx32; 61 break; 62 case 0xc: 63 dram_layout = AST_DRAM_1Gx32; 64 break; 65 } 66 67 return dram_layout; 68 } 69 70 /* 71 * POST 72 */ 73 74 static const struct ast_dramstruct ast1100_dram_table_data[] = { 75 { 0x2000, 0x1688a8a8 }, 76 { 0x2020, 0x000041f0 }, 77 AST_DRAMSTRUCT_UDELAY(67u), 78 { 0x0000, 0xfc600309 }, 79 { 0x006C, 0x00909090 }, 80 { 0x0064, 0x00050000 }, 81 AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585), 82 { 0x0008, 0x0011030f }, 83 { 0x0010, 0x22201724 }, 84 { 0x0018, 0x1e29011a }, 85 { 0x0020, 0x00c82222 }, 86 { 0x0014, 0x01001523 }, 87 { 0x001C, 0x1024010d }, 88 { 0x0024, 0x00cb2522 }, 89 { 0x0038, 0xffffff82 }, 90 { 0x003C, 0x00000000 }, 91 { 0x0040, 0x00000000 }, 92 { 0x0044, 0x00000000 }, 93 { 0x0048, 0x00000000 }, 94 { 0x004C, 0x00000000 }, 95 { 0x0050, 0x00000000 }, 96 { 0x0054, 0x00000000 }, 97 { 0x0058, 0x00000000 }, 98 { 0x005C, 0x00000000 }, 99 { 0x0060, 0x032aa02a }, 100 { 0x0064, 0x002d3000 }, 101 { 0x0068, 0x00000000 }, 102 { 0x0070, 0x00000000 }, 103 { 0x0074, 0x00000000 }, 104 { 0x0078, 0x00000000 }, 105 { 0x007C, 0x00000000 }, 106 { 0x0034, 0x00000001 }, 107 AST_DRAMSTRUCT_UDELAY(67u), 108 { 0x002C, 0x00000732 }, 109 { 0x0030, 0x00000040 }, 110 { 0x0028, 0x00000005 }, 111 { 0x0028, 0x00000007 }, 112 { 0x0028, 0x00000003 }, 113 { 0x0028, 0x00000001 }, 114 { 0x000C, 0x00005a08 }, 115 { 0x002C, 0x00000632 }, 116 { 0x0028, 0x00000001 }, 117 { 0x0030, 0x000003c0 }, 118 { 0x0028, 0x00000003 }, 119 { 0x0030, 0x00000040 }, 120 { 0x0028, 0x00000003 }, 121 { 0x000C, 0x00005a21 }, 122 { 0x0034, 0x00007c03 }, 123 { 0x0120, 0x00004c41 }, 124 AST_DRAMSTRUCT_INVALID, 125 }; 126 127 static const struct ast_dramstruct ast2100_dram_table_data[] = { 128 { 0x2000, 0x1688a8a8 }, 129 { 0x2020, 0x00004120 }, 130 AST_DRAMSTRUCT_UDELAY(67u), 131 { 0x0000, 0xfc600309 }, 132 { 0x006C, 0x00909090 }, 133 { 0x0064, 0x00070000 }, 134 AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489), 135 { 0x0008, 0x0011030f }, 136 { 0x0010, 0x32302926 }, 137 { 0x0018, 0x274c0122 }, 138 { 0x0020, 0x00ce2222 }, 139 { 0x0014, 0x01001523 }, 140 { 0x001C, 0x1024010d }, 141 { 0x0024, 0x00cb2522 }, 142 { 0x0038, 0xffffff82 }, 143 { 0x003C, 0x00000000 }, 144 { 0x0040, 0x00000000 }, 145 { 0x0044, 0x00000000 }, 146 { 0x0048, 0x00000000 }, 147 { 0x004C, 0x00000000 }, 148 { 0x0050, 0x00000000 }, 149 { 0x0054, 0x00000000 }, 150 { 0x0058, 0x00000000 }, 151 { 0x005C, 0x00000000 }, 152 { 0x0060, 0x0f2aa02a }, 153 { 0x0064, 0x003f3005 }, 154 { 0x0068, 0x02020202 }, 155 { 0x0070, 0x00000000 }, 156 { 0x0074, 0x00000000 }, 157 { 0x0078, 0x00000000 }, 158 { 0x007C, 0x00000000 }, 159 { 0x0034, 0x00000001 }, 160 AST_DRAMSTRUCT_UDELAY(67u), 161 { 0x002C, 0x00000942 }, 162 { 0x0030, 0x00000040 }, 163 { 0x0028, 0x00000005 }, 164 { 0x0028, 0x00000007 }, 165 { 0x0028, 0x00000003 }, 166 { 0x0028, 0x00000001 }, 167 { 0x000C, 0x00005a08 }, 168 { 0x002C, 0x00000842 }, 169 { 0x0028, 0x00000001 }, 170 { 0x0030, 0x000003c0 }, 171 { 0x0028, 0x00000003 }, 172 { 0x0030, 0x00000040 }, 173 { 0x0028, 0x00000003 }, 174 { 0x000C, 0x00005a21 }, 175 { 0x0034, 0x00007c03 }, 176 { 0x0120, 0x00005061 }, 177 AST_DRAMSTRUCT_INVALID, 178 }; 179 180 /* 181 * AST2100/2150 DLL CBR Setting 182 */ 183 #define CBR_SIZE_AST2150 ((16 << 10) - 1) 184 #define CBR_PASSNUM_AST2150 5 185 #define CBR_THRESHOLD_AST2150 10 186 #define CBR_THRESHOLD2_AST2150 10 187 #define TIMEOUT_AST2150 5000000 188 189 #define CBR_PATNUM_AST2150 8 190 191 static const u32 pattern_AST2150[14] = { 192 0xFF00FF00, 193 0xCC33CC33, 194 0xAA55AA55, 195 0xFFFE0001, 196 0x683501FE, 197 0x0F1929B0, 198 0x2D0B4346, 199 0x60767F02, 200 0x6FBE36A6, 201 0x3A253035, 202 0x3019686D, 203 0x41C6167E, 204 0x620152BF, 205 0x20F050E0 206 }; 207 208 static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen) 209 { 210 u32 data, timeout; 211 212 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 213 ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3)); 214 timeout = 0; 215 do { 216 data = ast_mindwm(ast, 0x1e6e0070) & 0x40; 217 if (++timeout > TIMEOUT_AST2150) { 218 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 219 return 0xffffffff; 220 } 221 } while (!data); 222 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 223 ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3)); 224 timeout = 0; 225 do { 226 data = ast_mindwm(ast, 0x1e6e0070) & 0x40; 227 if (++timeout > TIMEOUT_AST2150) { 228 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 229 return 0xffffffff; 230 } 231 } while (!data); 232 data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7; 233 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 234 return data; 235 } 236 237 static int cbrtest_ast2150(struct ast_device *ast) 238 { 239 int i; 240 241 for (i = 0; i < 8; i++) 242 if (mmctestburst2_ast2150(ast, i)) 243 return 0; 244 return 1; 245 } 246 247 static int cbrscan_ast2150(struct ast_device *ast, int busw) 248 { 249 u32 patcnt, loop; 250 251 for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) { 252 ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]); 253 for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) { 254 if (cbrtest_ast2150(ast)) 255 break; 256 } 257 if (loop == CBR_PASSNUM_AST2150) 258 return 0; 259 } 260 return 1; 261 } 262 263 static void cbrdlli_ast2150(struct ast_device *ast, int busw) 264 { 265 u32 dll_min[4], dll_max[4], dlli, data, passcnt; 266 267 cbr_start: 268 dll_min[0] = 0xff; 269 dll_min[1] = 0xff; 270 dll_min[2] = 0xff; 271 dll_min[3] = 0xff; 272 dll_max[0] = 0x00; 273 dll_max[1] = 0x00; 274 dll_max[2] = 0x00; 275 dll_max[3] = 0x00; 276 passcnt = 0; 277 278 for (dlli = 0; dlli < 100; dlli++) { 279 ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); 280 data = cbrscan_ast2150(ast, busw); 281 if (data != 0) { 282 if (data & 0x1) { 283 if (dll_min[0] > dlli) 284 dll_min[0] = dlli; 285 if (dll_max[0] < dlli) 286 dll_max[0] = dlli; 287 } 288 passcnt++; 289 } else if (passcnt >= CBR_THRESHOLD_AST2150) { 290 goto cbr_start; 291 } 292 } 293 if (dll_max[0] == 0 || (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150) 294 goto cbr_start; 295 296 dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4); 297 ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); 298 } 299 300 static void ast_post_chip_2100(struct ast_device *ast) 301 { 302 u8 j; 303 u32 data, temp, i; 304 const struct ast_dramstruct *dram_reg_info; 305 enum ast_dram_layout dram_layout = ast_2100_get_dram_layout_p2a(ast); 306 307 j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); 308 309 if ((j & 0x80) == 0) { /* VGA only */ 310 if (ast->chip == AST2100 || ast->chip == AST2200) 311 dram_reg_info = ast2100_dram_table_data; 312 else 313 dram_reg_info = ast1100_dram_table_data; 314 315 ast_write32(ast, 0xf004, 0x1e6e0000); 316 ast_write32(ast, 0xf000, 0x1); 317 ast_write32(ast, 0x12000, 0x1688A8A8); 318 do { 319 ; 320 } while (ast_read32(ast, 0x12000) != 0x01); 321 322 ast_write32(ast, 0x10000, 0xfc600309); 323 do { 324 ; 325 } while (ast_read32(ast, 0x10000) != 0x01); 326 327 while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) { 328 if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) { 329 for (i = 0; i < 15; i++) 330 udelay(dram_reg_info->data); 331 } else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) { 332 switch (dram_layout) { 333 case AST_DRAM_1Gx16: 334 data = 0x00000d89; 335 break; 336 case AST_DRAM_1Gx32: 337 data = 0x00000c8d; 338 break; 339 default: 340 data = dram_reg_info->data; 341 break; 342 } 343 344 temp = ast_read32(ast, 0x12070); 345 temp &= 0xc; 346 temp <<= 2; 347 ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp); 348 } else { 349 ast_write32(ast, 0x10000 + dram_reg_info->index, 350 dram_reg_info->data); 351 } 352 dram_reg_info++; 353 } 354 355 /* AST 2100/2150 DRAM calibration */ 356 data = ast_read32(ast, 0x10120); 357 if (data == 0x5061) { /* 266Mhz */ 358 data = ast_read32(ast, 0x10004); 359 if (data & 0x40) 360 cbrdlli_ast2150(ast, 16); /* 16 bits */ 361 else 362 cbrdlli_ast2150(ast, 32); /* 32 bits */ 363 } 364 365 temp = ast_read32(ast, 0x1200c); 366 ast_write32(ast, 0x1200c, temp & 0xfffffffd); 367 temp = ast_read32(ast, 0x12040); 368 ast_write32(ast, 0x12040, temp | 0x40); 369 } 370 371 /* wait ready */ 372 do { 373 j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); 374 } while ((j & 0x40) == 0); 375 } 376 377 int ast_2100_post(struct ast_device *ast) 378 { 379 ast_2000_set_def_ext_reg(ast); 380 381 if (ast->config_mode == ast_use_p2a) { 382 ast_post_chip_2100(ast); 383 } else { 384 if (ast->tx_chip == AST_TX_SIL164) { 385 /* Enable DVO */ 386 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); 387 } 388 } 389 390 return 0; 391 } 392 393 /* 394 * Widescreen detection 395 */ 396 397 /* Try to detect WSXGA+ on Gen2+ */ 398 bool __ast_2100_detect_wsxga_p(struct ast_device *ast) 399 { 400 u8 vgacrd0 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd0); 401 402 if (!(vgacrd0 & AST_IO_VGACRD0_VRAM_INIT_BY_BMC)) 403 return true; 404 if (vgacrd0 & AST_IO_VGACRD0_IKVM_WIDESCREEN) 405 return true; 406 407 return false; 408 } 409 410 /* Try to detect WUXGA on Gen2+ */ 411 bool __ast_2100_detect_wuxga(struct ast_device *ast) 412 { 413 u8 vgacrd1; 414 415 if (ast->support_fullhd) { 416 vgacrd1 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd1); 417 if (!(vgacrd1 & AST_IO_VGACRD1_SUPPORTS_WUXGA)) 418 return true; 419 } 420 421 return false; 422 } 423 424 static void ast_2100_detect_widescreen(struct ast_device *ast) 425 { 426 if (__ast_2100_detect_wsxga_p(ast)) { 427 ast->support_wsxga_p = true; 428 if (ast->chip == AST2100) 429 ast->support_fullhd = true; 430 } 431 if (__ast_2100_detect_wuxga(ast)) 432 ast->support_wuxga = true; 433 } 434 435 static const struct ast_device_quirks ast_2100_device_quirks = { 436 .crtc_mem_req_threshold_low = 47, 437 .crtc_mem_req_threshold_high = 63, 438 }; 439 440 struct drm_device *ast_2100_device_create(struct pci_dev *pdev, 441 const struct drm_driver *drv, 442 enum ast_chip chip, 443 enum ast_config_mode config_mode, 444 void __iomem *regs, 445 void __iomem *ioregs, 446 bool need_post) 447 { 448 struct drm_device *dev; 449 struct ast_device *ast; 450 int ret; 451 452 ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base); 453 if (IS_ERR(ast)) 454 return ERR_CAST(ast); 455 dev = &ast->base; 456 457 ast_device_init(ast, chip, config_mode, regs, ioregs, &ast_2100_device_quirks); 458 459 ast->dclk_table = ast_2000_dclk_table; 460 461 ast_2000_detect_tx_chip(ast, need_post); 462 463 if (need_post) { 464 ret = ast_post_gpu(ast); 465 if (ret) 466 return ERR_PTR(ret); 467 } 468 469 ret = ast_mm_init(ast); 470 if (ret) 471 return ERR_PTR(ret); 472 473 ast_2100_detect_widescreen(ast); 474 475 ret = ast_mode_config_init(ast); 476 if (ret) 477 return ERR_PTR(ret); 478 479 return dev; 480 } 481