Joel Stanley | e50183f | 2017-02-28 12:17:46 +1030 | [diff] [blame] | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | From: Russell Currey <ruscur@russell.cc> |
| 3 | Date: Fri, 17 Feb 2017 14:33:01 +1100 |
| 4 | Subject: [PATCH 04/15] drm/ast: Handle configuration without P2A bridge |
| 5 | |
| 6 | The ast driver configures a window to enable access into BMC |
| 7 | memory space in order to read some configuration registers. |
| 8 | |
| 9 | If this window is disabled, which it can be from the BMC side, |
| 10 | the ast driver can't function. |
| 11 | |
| 12 | Closing this window is a necessity for security if a machine's |
| 13 | host side and BMC side are controlled by different parties; |
| 14 | i.e. a cloud provider offering machines "bare metal". |
| 15 | |
| 16 | A recent patch went in to try to check if that window is open |
| 17 | but it does so by trying to access the registers in question |
| 18 | and testing if the result is 0xffffffff. |
| 19 | |
| 20 | This method will trigger a PCIe error when the window is closed |
| 21 | which on some systems will be fatal (it will trigger an EEH |
| 22 | for example on POWER which will take out the device). |
| 23 | |
| 24 | This patch improves this in two ways: |
| 25 | |
| 26 | - First, if the firmware has put properties in the device-tree |
| 27 | containing the relevant configuration information, we use these. |
| 28 | |
| 29 | - Otherwise, a bit in one of the SCU scratch registers (which |
| 30 | are readable via the VGA register space and writeable by the BMC) |
| 31 | will indicate if the BMC has closed the window. This bit has been |
| 32 | defined by Y.C Chen from Aspeed. |
| 33 | |
| 34 | If the window is closed and the configuration isn't available from |
| 35 | the device-tree, some sane defaults are used. Those defaults are |
| 36 | hopefully sufficient for standard video modes used on a server. |
| 37 | |
| 38 | Signed-off-by: Russell Currey <ruscur@russell.cc> |
| 39 | Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| 40 | -- |
| 41 | |
| 42 | v2. [BenH] |
| 43 | - Reworked on top of Aspeed P2A patch |
| 44 | - Cleanup overall detection via a "config_mode" and log the |
| 45 | selected mode for diagnostics purposes |
| 46 | - Add a property for the SCU straps |
| 47 | |
| 48 | v3. [BenH] |
| 49 | - Moved the config mode detection to a separate functionn |
| 50 | - Add reading of SCU 0x40 D[12] to detect the window is |
| 51 | closed as to not trigger a bus error by just "trying". |
| 52 | (change provided by Y.C. Chen) |
| 53 | v4. [BenH] |
| 54 | - Only devices with the AST2000 PCI ID have a P2A bridge |
| 55 | - Update the P2A presence test to account for VGA only |
| 56 | mode as provided by Y.C. Chen. |
| 57 | v5. [BenH] |
| 58 | - Fixup prefix of OF properties based on Joel Stanley |
| 59 | review comments. |
| 60 | |
| 61 | Signed-off-by: Joel Stanley <joel@jms.id.au> |
| 62 | --- |
| 63 | drivers/gpu/drm/ast/ast_drv.h | 6 +- |
| 64 | drivers/gpu/drm/ast/ast_main.c | 264 +++++++++++++++++++++++++---------------- |
| 65 | drivers/gpu/drm/ast/ast_post.c | 7 +- |
| 66 | 3 files changed, 168 insertions(+), 109 deletions(-) |
| 67 | |
| 68 | diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h |
| 69 | index 7abda94fc2cf..3bedcf7ddd2a 100644 |
| 70 | --- a/drivers/gpu/drm/ast/ast_drv.h |
| 71 | +++ b/drivers/gpu/drm/ast/ast_drv.h |
| 72 | @@ -113,7 +113,11 @@ struct ast_private { |
| 73 | struct ttm_bo_kmap_obj cache_kmap; |
| 74 | int next_cursor; |
| 75 | bool support_wide_screen; |
| 76 | - bool DisableP2A; |
| 77 | + enum { |
| 78 | + ast_use_p2a, |
| 79 | + ast_use_dt, |
| 80 | + ast_use_defaults |
| 81 | + } config_mode; |
| 82 | |
| 83 | enum ast_tx_chip tx_chip_type; |
| 84 | u8 dp501_maxclk; |
| 85 | diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c |
| 86 | index 533e762d036d..fb9976254224 100644 |
| 87 | --- a/drivers/gpu/drm/ast/ast_main.c |
| 88 | +++ b/drivers/gpu/drm/ast/ast_main.c |
| 89 | @@ -62,13 +62,84 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast, |
| 90 | return ret; |
| 91 | } |
| 92 | |
| 93 | +static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) |
| 94 | +{ |
| 95 | + struct device_node *np = dev->pdev->dev.of_node; |
| 96 | + struct ast_private *ast = dev->dev_private; |
| 97 | + uint32_t data, jregd0, jregd1; |
| 98 | + |
| 99 | + /* Defaults */ |
| 100 | + ast->config_mode = ast_use_defaults; |
| 101 | + *scu_rev = 0xffffffff; |
| 102 | + |
| 103 | + /* Check if we have device-tree properties */ |
| 104 | + if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", |
| 105 | + scu_rev)) { |
| 106 | + /* We do, disable P2A access */ |
| 107 | + ast->config_mode = ast_use_dt; |
| 108 | + DRM_INFO("Using device-tree for configuration\n"); |
| 109 | + return; |
| 110 | + } |
| 111 | + |
| 112 | + /* Not all families have a P2A bridge */ |
| 113 | + if (dev->pdev->device != PCI_CHIP_AST2000) |
| 114 | + return; |
| 115 | + |
| 116 | + /* |
| 117 | + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge |
| 118 | + * is disabled. We force using P2A if VGA only mode bit |
| 119 | + * is set D[7] |
| 120 | + */ |
| 121 | + jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); |
| 122 | + jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); |
| 123 | + if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { |
| 124 | + /* Double check it's actually working */ |
| 125 | + data = ast_read32(ast, 0xf004); |
| 126 | + if (data != 0xFFFFFFFF) { |
| 127 | + /* P2A works, grab silicon revision */ |
| 128 | + ast->config_mode = ast_use_p2a; |
| 129 | + |
| 130 | + DRM_INFO("Using P2A bridge for configuration\n"); |
| 131 | + |
| 132 | + /* Read SCU7c (silicon revision register) */ |
| 133 | + ast_write32(ast, 0xf004, 0x1e6e0000); |
| 134 | + ast_write32(ast, 0xf000, 0x1); |
| 135 | + *scu_rev = ast_read32(ast, 0x1207c); |
| 136 | + return; |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + /* We have a P2A bridge but it's disabled */ |
| 141 | + DRM_INFO("P2A bridge disabled, using default configuration\n"); |
| 142 | +} |
| 143 | |
| 144 | static int ast_detect_chip(struct drm_device *dev, bool *need_post) |
| 145 | { |
| 146 | struct ast_private *ast = dev->dev_private; |
| 147 | - uint32_t data, jreg; |
| 148 | + uint32_t jreg, scu_rev; |
| 149 | + |
| 150 | + /* |
| 151 | + * If VGA isn't enabled, we need to enable now or subsequent |
| 152 | + * access to the scratch registers will fail. We also inform |
| 153 | + * our caller that it needs to POST the chip |
| 154 | + * (Assumption: VGA not enabled -> need to POST) |
| 155 | + */ |
| 156 | + if (!ast_is_vga_enabled(dev)) { |
| 157 | + ast_enable_vga(dev); |
| 158 | + DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); |
| 159 | + *need_post = true; |
| 160 | + } else |
| 161 | + *need_post = false; |
| 162 | + |
| 163 | + |
| 164 | + /* Enable extended register access */ |
| 165 | + ast_enable_mmio(dev); |
| 166 | ast_open_key(ast); |
| 167 | |
| 168 | + /* Find out whether P2A works or whether to use device-tree */ |
| 169 | + ast_detect_config_mode(dev, &scu_rev); |
| 170 | + |
| 171 | + /* Identify chipset */ |
| 172 | if (dev->pdev->device == PCI_CHIP_AST1180) { |
| 173 | ast->chip = AST1100; |
| 174 | DRM_INFO("AST 1180 detected\n"); |
| 175 | @@ -80,12 +151,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) |
| 176 | ast->chip = AST2300; |
| 177 | DRM_INFO("AST 2300 detected\n"); |
| 178 | } else if (dev->pdev->revision >= 0x10) { |
| 179 | - uint32_t data; |
| 180 | - ast_write32(ast, 0xf004, 0x1e6e0000); |
| 181 | - ast_write32(ast, 0xf000, 0x1); |
| 182 | - |
| 183 | - data = ast_read32(ast, 0x1207c); |
| 184 | - switch (data & 0x0300) { |
| 185 | + switch (scu_rev & 0x0300) { |
| 186 | case 0x0200: |
| 187 | ast->chip = AST1100; |
| 188 | DRM_INFO("AST 1100 detected\n"); |
| 189 | @@ -110,26 +176,6 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | - /* |
| 194 | - * If VGA isn't enabled, we need to enable now or subsequent |
| 195 | - * access to the scratch registers will fail. We also inform |
| 196 | - * our caller that it needs to POST the chip |
| 197 | - * (Assumption: VGA not enabled -> need to POST) |
| 198 | - */ |
| 199 | - if (!ast_is_vga_enabled(dev)) { |
| 200 | - ast_enable_vga(dev); |
| 201 | - ast_enable_mmio(dev); |
| 202 | - DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); |
| 203 | - *need_post = true; |
| 204 | - } else |
| 205 | - *need_post = false; |
| 206 | - |
| 207 | - /* Check P2A Access */ |
| 208 | - ast->DisableP2A = true; |
| 209 | - data = ast_read32(ast, 0xf004); |
| 210 | - if (data != 0xFFFFFFFF) |
| 211 | - ast->DisableP2A = false; |
| 212 | - |
| 213 | /* Check if we support wide screen */ |
| 214 | switch (ast->chip) { |
| 215 | case AST1180: |
| 216 | @@ -146,17 +192,12 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) |
| 217 | ast->support_wide_screen = true; |
| 218 | else { |
| 219 | ast->support_wide_screen = false; |
| 220 | - if (ast->DisableP2A == false) { |
| 221 | - /* Read SCU7c (silicon revision register) */ |
| 222 | - ast_write32(ast, 0xf004, 0x1e6e0000); |
| 223 | - ast_write32(ast, 0xf000, 0x1); |
| 224 | - data = ast_read32(ast, 0x1207c); |
| 225 | - data &= 0x300; |
| 226 | - if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ |
| 227 | - ast->support_wide_screen = true; |
| 228 | - if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ |
| 229 | - ast->support_wide_screen = true; |
| 230 | - } |
| 231 | + if (ast->chip == AST2300 && |
| 232 | + (scu_rev & 0x300) == 0x0) /* ast1300 */ |
| 233 | + ast->support_wide_screen = true; |
| 234 | + if (ast->chip == AST2400 && |
| 235 | + (scu_rev & 0x300) == 0x100) /* ast1400 */ |
| 236 | + ast->support_wide_screen = true; |
| 237 | } |
| 238 | break; |
| 239 | } |
| 240 | @@ -220,85 +261,102 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) |
| 241 | |
| 242 | static int ast_get_dram_info(struct drm_device *dev) |
| 243 | { |
| 244 | + struct device_node *np = dev->pdev->dev.of_node; |
| 245 | struct ast_private *ast = dev->dev_private; |
| 246 | - uint32_t data, data2; |
| 247 | - uint32_t denum, num, div, ref_pll; |
| 248 | + uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; |
| 249 | + uint32_t denum, num, div, ref_pll, dsel; |
| 250 | |
| 251 | - if (ast->DisableP2A) |
| 252 | - { |
| 253 | + switch (ast->config_mode) { |
| 254 | + case ast_use_dt: |
| 255 | + /* |
| 256 | + * If some properties are missing, use reasonable |
| 257 | + * defaults for AST2400 |
| 258 | + */ |
| 259 | + if (of_property_read_u32(np, "aspeed,mcr-configuration", |
| 260 | + &mcr_cfg)) |
| 261 | + mcr_cfg = 0x00000577; |
| 262 | + if (of_property_read_u32(np, "aspeed,mcr-scu-mpll", |
| 263 | + &mcr_scu_mpll)) |
| 264 | + mcr_scu_mpll = 0x000050C0; |
| 265 | + if (of_property_read_u32(np, "aspeed,mcr-scu-strap", |
| 266 | + &mcr_scu_strap)) |
| 267 | + mcr_scu_strap = 0; |
| 268 | + break; |
| 269 | + case ast_use_p2a: |
| 270 | + ast_write32(ast, 0xf004, 0x1e6e0000); |
| 271 | + ast_write32(ast, 0xf000, 0x1); |
| 272 | + mcr_cfg = ast_read32(ast, 0x10004); |
| 273 | + mcr_scu_mpll = ast_read32(ast, 0x10120); |
| 274 | + mcr_scu_strap = ast_read32(ast, 0x10170); |
| 275 | + break; |
| 276 | + case ast_use_defaults: |
| 277 | + default: |
| 278 | ast->dram_bus_width = 16; |
| 279 | ast->dram_type = AST_DRAM_1Gx16; |
| 280 | ast->mclk = 396; |
| 281 | + return 0; |
| 282 | } |
| 283 | - else |
| 284 | - { |
| 285 | - ast_write32(ast, 0xf004, 0x1e6e0000); |
| 286 | - ast_write32(ast, 0xf000, 0x1); |
| 287 | - data = ast_read32(ast, 0x10004); |
| 288 | - |
| 289 | - if (data & 0x40) |
| 290 | - ast->dram_bus_width = 16; |
| 291 | - else |
| 292 | - ast->dram_bus_width = 32; |
| 293 | |
| 294 | - if (ast->chip == AST2300 || ast->chip == AST2400) { |
| 295 | - switch (data & 0x03) { |
| 296 | - case 0: |
| 297 | - ast->dram_type = AST_DRAM_512Mx16; |
| 298 | - break; |
| 299 | - default: |
| 300 | - case 1: |
| 301 | - ast->dram_type = AST_DRAM_1Gx16; |
| 302 | - break; |
| 303 | - case 2: |
| 304 | - ast->dram_type = AST_DRAM_2Gx16; |
| 305 | - break; |
| 306 | - case 3: |
| 307 | - ast->dram_type = AST_DRAM_4Gx16; |
| 308 | - break; |
| 309 | - } |
| 310 | - } else { |
| 311 | - switch (data & 0x0c) { |
| 312 | - case 0: |
| 313 | - case 4: |
| 314 | - ast->dram_type = AST_DRAM_512Mx16; |
| 315 | - break; |
| 316 | - case 8: |
| 317 | - if (data & 0x40) |
| 318 | - ast->dram_type = AST_DRAM_1Gx16; |
| 319 | - else |
| 320 | - ast->dram_type = AST_DRAM_512Mx32; |
| 321 | - break; |
| 322 | - case 0xc: |
| 323 | - ast->dram_type = AST_DRAM_1Gx32; |
| 324 | - break; |
| 325 | - } |
| 326 | - } |
| 327 | + if (mcr_cfg & 0x40) |
| 328 | + ast->dram_bus_width = 16; |
| 329 | + else |
| 330 | + ast->dram_bus_width = 32; |
| 331 | |
| 332 | - data = ast_read32(ast, 0x10120); |
| 333 | - data2 = ast_read32(ast, 0x10170); |
| 334 | - if (data2 & 0x2000) |
| 335 | - ref_pll = 14318; |
| 336 | - else |
| 337 | - ref_pll = 12000; |
| 338 | - |
| 339 | - denum = data & 0x1f; |
| 340 | - num = (data & 0x3fe0) >> 5; |
| 341 | - data = (data & 0xc000) >> 14; |
| 342 | - switch (data) { |
| 343 | - case 3: |
| 344 | - div = 0x4; |
| 345 | + if (ast->chip == AST2300 || ast->chip == AST2400) { |
| 346 | + switch (mcr_cfg & 0x03) { |
| 347 | + case 0: |
| 348 | + ast->dram_type = AST_DRAM_512Mx16; |
| 349 | break; |
| 350 | - case 2: |
| 351 | + default: |
| 352 | case 1: |
| 353 | - div = 0x2; |
| 354 | + ast->dram_type = AST_DRAM_1Gx16; |
| 355 | break; |
| 356 | - default: |
| 357 | - div = 0x1; |
| 358 | + case 2: |
| 359 | + ast->dram_type = AST_DRAM_2Gx16; |
| 360 | + break; |
| 361 | + case 3: |
| 362 | + ast->dram_type = AST_DRAM_4Gx16; |
| 363 | + break; |
| 364 | + } |
| 365 | + } else { |
| 366 | + switch (mcr_cfg & 0x0c) { |
| 367 | + case 0: |
| 368 | + case 4: |
| 369 | + ast->dram_type = AST_DRAM_512Mx16; |
| 370 | + break; |
| 371 | + case 8: |
| 372 | + if (mcr_cfg & 0x40) |
| 373 | + ast->dram_type = AST_DRAM_1Gx16; |
| 374 | + else |
| 375 | + ast->dram_type = AST_DRAM_512Mx32; |
| 376 | + break; |
| 377 | + case 0xc: |
| 378 | + ast->dram_type = AST_DRAM_1Gx32; |
| 379 | break; |
| 380 | } |
| 381 | - ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); |
| 382 | } |
| 383 | + |
| 384 | + if (mcr_scu_strap & 0x2000) |
| 385 | + ref_pll = 14318; |
| 386 | + else |
| 387 | + ref_pll = 12000; |
| 388 | + |
| 389 | + denum = mcr_scu_mpll & 0x1f; |
| 390 | + num = (mcr_scu_mpll & 0x3fe0) >> 5; |
| 391 | + dsel = (mcr_scu_mpll & 0xc000) >> 14; |
| 392 | + switch (dsel) { |
| 393 | + case 3: |
| 394 | + div = 0x4; |
| 395 | + break; |
| 396 | + case 2: |
| 397 | + case 1: |
| 398 | + div = 0x2; |
| 399 | + break; |
| 400 | + default: |
| 401 | + div = 0x1; |
| 402 | + break; |
| 403 | + } |
| 404 | + ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); |
| 405 | return 0; |
| 406 | } |
| 407 | |
| 408 | diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c |
| 409 | index 6c5391cb90eb..64549cebcc5b 100644 |
| 410 | --- a/drivers/gpu/drm/ast/ast_post.c |
| 411 | +++ b/drivers/gpu/drm/ast/ast_post.c |
| 412 | @@ -379,17 +379,14 @@ void ast_post_gpu(struct drm_device *dev) |
| 413 | ast_open_key(ast); |
| 414 | ast_set_def_ext_reg(dev); |
| 415 | |
| 416 | - if (ast->DisableP2A == false) |
| 417 | - { |
| 418 | + if (ast->config_mode == ast_use_p2a) { |
| 419 | if (ast->chip == AST2300 || ast->chip == AST2400) |
| 420 | ast_init_dram_2300(dev); |
| 421 | else |
| 422 | ast_init_dram_reg(dev); |
| 423 | |
| 424 | ast_init_3rdtx(dev); |
| 425 | - } |
| 426 | - else |
| 427 | - { |
| 428 | + } else { |
| 429 | if (ast->tx_chip_type != AST_TX_NONE) |
| 430 | ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */ |
| 431 | } |
| 432 | -- |
| 433 | 2.11.0 |
| 434 | |