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 31 #include "ast_drv.h" 32 #include "ast_post.h" 33 34 /* 35 * POST 36 */ 37 38 static const struct ast_dramstruct ast1100_dram_table_data[] = { 39 { 0x2000, 0x1688a8a8 }, 40 { 0x2020, 0x000041f0 }, 41 AST_DRAMSTRUCT_UDELAY(67u), 42 { 0x0000, 0xfc600309 }, 43 { 0x006C, 0x00909090 }, 44 { 0x0064, 0x00050000 }, 45 AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000585), 46 { 0x0008, 0x0011030f }, 47 { 0x0010, 0x22201724 }, 48 { 0x0018, 0x1e29011a }, 49 { 0x0020, 0x00c82222 }, 50 { 0x0014, 0x01001523 }, 51 { 0x001C, 0x1024010d }, 52 { 0x0024, 0x00cb2522 }, 53 { 0x0038, 0xffffff82 }, 54 { 0x003C, 0x00000000 }, 55 { 0x0040, 0x00000000 }, 56 { 0x0044, 0x00000000 }, 57 { 0x0048, 0x00000000 }, 58 { 0x004C, 0x00000000 }, 59 { 0x0050, 0x00000000 }, 60 { 0x0054, 0x00000000 }, 61 { 0x0058, 0x00000000 }, 62 { 0x005C, 0x00000000 }, 63 { 0x0060, 0x032aa02a }, 64 { 0x0064, 0x002d3000 }, 65 { 0x0068, 0x00000000 }, 66 { 0x0070, 0x00000000 }, 67 { 0x0074, 0x00000000 }, 68 { 0x0078, 0x00000000 }, 69 { 0x007C, 0x00000000 }, 70 { 0x0034, 0x00000001 }, 71 AST_DRAMSTRUCT_UDELAY(67u), 72 { 0x002C, 0x00000732 }, 73 { 0x0030, 0x00000040 }, 74 { 0x0028, 0x00000005 }, 75 { 0x0028, 0x00000007 }, 76 { 0x0028, 0x00000003 }, 77 { 0x0028, 0x00000001 }, 78 { 0x000C, 0x00005a08 }, 79 { 0x002C, 0x00000632 }, 80 { 0x0028, 0x00000001 }, 81 { 0x0030, 0x000003c0 }, 82 { 0x0028, 0x00000003 }, 83 { 0x0030, 0x00000040 }, 84 { 0x0028, 0x00000003 }, 85 { 0x000C, 0x00005a21 }, 86 { 0x0034, 0x00007c03 }, 87 { 0x0120, 0x00004c41 }, 88 AST_DRAMSTRUCT_INVALID, 89 }; 90 91 static const struct ast_dramstruct ast2100_dram_table_data[] = { 92 { 0x2000, 0x1688a8a8 }, 93 { 0x2020, 0x00004120 }, 94 AST_DRAMSTRUCT_UDELAY(67u), 95 { 0x0000, 0xfc600309 }, 96 { 0x006C, 0x00909090 }, 97 { 0x0064, 0x00070000 }, 98 AST_DRAMSTRUCT_INIT(DRAM_TYPE, 0x00000489), 99 { 0x0008, 0x0011030f }, 100 { 0x0010, 0x32302926 }, 101 { 0x0018, 0x274c0122 }, 102 { 0x0020, 0x00ce2222 }, 103 { 0x0014, 0x01001523 }, 104 { 0x001C, 0x1024010d }, 105 { 0x0024, 0x00cb2522 }, 106 { 0x0038, 0xffffff82 }, 107 { 0x003C, 0x00000000 }, 108 { 0x0040, 0x00000000 }, 109 { 0x0044, 0x00000000 }, 110 { 0x0048, 0x00000000 }, 111 { 0x004C, 0x00000000 }, 112 { 0x0050, 0x00000000 }, 113 { 0x0054, 0x00000000 }, 114 { 0x0058, 0x00000000 }, 115 { 0x005C, 0x00000000 }, 116 { 0x0060, 0x0f2aa02a }, 117 { 0x0064, 0x003f3005 }, 118 { 0x0068, 0x02020202 }, 119 { 0x0070, 0x00000000 }, 120 { 0x0074, 0x00000000 }, 121 { 0x0078, 0x00000000 }, 122 { 0x007C, 0x00000000 }, 123 { 0x0034, 0x00000001 }, 124 AST_DRAMSTRUCT_UDELAY(67u), 125 { 0x002C, 0x00000942 }, 126 { 0x0030, 0x00000040 }, 127 { 0x0028, 0x00000005 }, 128 { 0x0028, 0x00000007 }, 129 { 0x0028, 0x00000003 }, 130 { 0x0028, 0x00000001 }, 131 { 0x000C, 0x00005a08 }, 132 { 0x002C, 0x00000842 }, 133 { 0x0028, 0x00000001 }, 134 { 0x0030, 0x000003c0 }, 135 { 0x0028, 0x00000003 }, 136 { 0x0030, 0x00000040 }, 137 { 0x0028, 0x00000003 }, 138 { 0x000C, 0x00005a21 }, 139 { 0x0034, 0x00007c03 }, 140 { 0x0120, 0x00005061 }, 141 AST_DRAMSTRUCT_INVALID, 142 }; 143 144 /* 145 * AST2100/2150 DLL CBR Setting 146 */ 147 #define CBR_SIZE_AST2150 ((16 << 10) - 1) 148 #define CBR_PASSNUM_AST2150 5 149 #define CBR_THRESHOLD_AST2150 10 150 #define CBR_THRESHOLD2_AST2150 10 151 #define TIMEOUT_AST2150 5000000 152 153 #define CBR_PATNUM_AST2150 8 154 155 static const u32 pattern_AST2150[14] = { 156 0xFF00FF00, 157 0xCC33CC33, 158 0xAA55AA55, 159 0xFFFE0001, 160 0x683501FE, 161 0x0F1929B0, 162 0x2D0B4346, 163 0x60767F02, 164 0x6FBE36A6, 165 0x3A253035, 166 0x3019686D, 167 0x41C6167E, 168 0x620152BF, 169 0x20F050E0 170 }; 171 172 static u32 mmctestburst2_ast2150(struct ast_device *ast, u32 datagen) 173 { 174 u32 data, timeout; 175 176 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 177 ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3)); 178 timeout = 0; 179 do { 180 data = ast_mindwm(ast, 0x1e6e0070) & 0x40; 181 if (++timeout > TIMEOUT_AST2150) { 182 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 183 return 0xffffffff; 184 } 185 } while (!data); 186 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 187 ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3)); 188 timeout = 0; 189 do { 190 data = ast_mindwm(ast, 0x1e6e0070) & 0x40; 191 if (++timeout > TIMEOUT_AST2150) { 192 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 193 return 0xffffffff; 194 } 195 } while (!data); 196 data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7; 197 ast_moutdwm(ast, 0x1e6e0070, 0x00000000); 198 return data; 199 } 200 201 static int cbrtest_ast2150(struct ast_device *ast) 202 { 203 int i; 204 205 for (i = 0; i < 8; i++) 206 if (mmctestburst2_ast2150(ast, i)) 207 return 0; 208 return 1; 209 } 210 211 static int cbrscan_ast2150(struct ast_device *ast, int busw) 212 { 213 u32 patcnt, loop; 214 215 for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) { 216 ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]); 217 for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) { 218 if (cbrtest_ast2150(ast)) 219 break; 220 } 221 if (loop == CBR_PASSNUM_AST2150) 222 return 0; 223 } 224 return 1; 225 } 226 227 static void cbrdlli_ast2150(struct ast_device *ast, int busw) 228 { 229 u32 dll_min[4], dll_max[4], dlli, data, passcnt; 230 231 cbr_start: 232 dll_min[0] = 0xff; 233 dll_min[1] = 0xff; 234 dll_min[2] = 0xff; 235 dll_min[3] = 0xff; 236 dll_max[0] = 0x00; 237 dll_max[1] = 0x00; 238 dll_max[2] = 0x00; 239 dll_max[3] = 0x00; 240 passcnt = 0; 241 242 for (dlli = 0; dlli < 100; dlli++) { 243 ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); 244 data = cbrscan_ast2150(ast, busw); 245 if (data != 0) { 246 if (data & 0x1) { 247 if (dll_min[0] > dlli) 248 dll_min[0] = dlli; 249 if (dll_max[0] < dlli) 250 dll_max[0] = dlli; 251 } 252 passcnt++; 253 } else if (passcnt >= CBR_THRESHOLD_AST2150) { 254 goto cbr_start; 255 } 256 } 257 if (dll_max[0] == 0 || (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150) 258 goto cbr_start; 259 260 dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4); 261 ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); 262 } 263 264 static void ast_post_chip_2100(struct ast_device *ast) 265 { 266 u8 j; 267 u32 data, temp, i; 268 const struct ast_dramstruct *dram_reg_info; 269 270 j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); 271 272 if ((j & 0x80) == 0) { /* VGA only */ 273 if (ast->chip == AST2100 || ast->chip == AST2200) 274 dram_reg_info = ast2100_dram_table_data; 275 else 276 dram_reg_info = ast1100_dram_table_data; 277 278 ast_write32(ast, 0xf004, 0x1e6e0000); 279 ast_write32(ast, 0xf000, 0x1); 280 ast_write32(ast, 0x12000, 0x1688A8A8); 281 do { 282 ; 283 } while (ast_read32(ast, 0x12000) != 0x01); 284 285 ast_write32(ast, 0x10000, 0xfc600309); 286 do { 287 ; 288 } while (ast_read32(ast, 0x10000) != 0x01); 289 290 while (!AST_DRAMSTRUCT_IS(dram_reg_info, INVALID)) { 291 if (AST_DRAMSTRUCT_IS(dram_reg_info, UDELAY)) { 292 for (i = 0; i < 15; i++) 293 udelay(dram_reg_info->data); 294 } else if (AST_DRAMSTRUCT_IS(dram_reg_info, DRAM_TYPE)) { 295 data = dram_reg_info->data; 296 if (ast->dram_type == AST_DRAM_1Gx16) 297 data = 0x00000d89; 298 else if (ast->dram_type == AST_DRAM_1Gx32) 299 data = 0x00000c8d; 300 301 temp = ast_read32(ast, 0x12070); 302 temp &= 0xc; 303 temp <<= 2; 304 ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp); 305 } else { 306 ast_write32(ast, 0x10000 + dram_reg_info->index, 307 dram_reg_info->data); 308 } 309 dram_reg_info++; 310 } 311 312 /* AST 2100/2150 DRAM calibration */ 313 data = ast_read32(ast, 0x10120); 314 if (data == 0x5061) { /* 266Mhz */ 315 data = ast_read32(ast, 0x10004); 316 if (data & 0x40) 317 cbrdlli_ast2150(ast, 16); /* 16 bits */ 318 else 319 cbrdlli_ast2150(ast, 32); /* 32 bits */ 320 } 321 322 temp = ast_read32(ast, 0x1200c); 323 ast_write32(ast, 0x1200c, temp & 0xfffffffd); 324 temp = ast_read32(ast, 0x12040); 325 ast_write32(ast, 0x12040, temp | 0x40); 326 } 327 328 /* wait ready */ 329 do { 330 j = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); 331 } while ((j & 0x40) == 0); 332 } 333 334 int ast_2100_post(struct ast_device *ast) 335 { 336 ast_2000_set_def_ext_reg(ast); 337 338 if (ast->config_mode == ast_use_p2a) { 339 ast_post_chip_2100(ast); 340 } else { 341 if (ast->tx_chip == AST_TX_SIL164) { 342 /* Enable DVO */ 343 ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); 344 } 345 } 346 347 return 0; 348 } 349