From 9d63a6b46dd79de611dad8aaeba9bdf071370ee2 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Mon, 7 Sep 2020 09:32:37 +0200 Subject: drivers/aspeed/common: Support disabled P2A bridge This ports Linux commit 71f677a91046599ece96ebab21df956ce909c456 "Handle configuration without P2A bridge". Quote: The ast driver configures a window to enable access into BMC memory space in order to read some configuration registers. If this window is disabled, which it can be from the BMC side, the ast driver can't function. Closing this window is a necessity for security if a machine's host side and BMC side are controlled by different parties; i.e. a cloud provider offering machines "bare metal". P2A stands for primary to AHB. Tested on Prodrive Hermes, which uses an AST2500. The machine still boots, has a high resolution framebuffer working in EDK2, and its boot time has been reduced by 2.5 seconds as it no longer runs into a timeout due to disabled P2A bridge. Change-Id: I3293dc35ae89c010154e02eff904ec3a68c96683 Signed-off-by: Patrick Rudolph Reviewed-on: https://review.coreboot.org/c/coreboot/+/45137 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons Reviewed-by: Paul Menzel --- src/drivers/aspeed/common/ast_drv.h | 5 + src/drivers/aspeed/common/ast_main.c | 193 +++++++++++++++++++++++------------ src/drivers/aspeed/common/ast_post.c | 22 ++-- 3 files changed, 149 insertions(+), 71 deletions(-) (limited to 'src/drivers/aspeed/common') diff --git a/src/drivers/aspeed/common/ast_drv.h b/src/drivers/aspeed/common/ast_drv.h index e275108602..206a7ad83c 100644 --- a/src/drivers/aspeed/common/ast_drv.h +++ b/src/drivers/aspeed/common/ast_drv.h @@ -64,6 +64,11 @@ struct ast_private { int next_cursor; bool support_wide_screen; + enum { + ast_use_p2a, + ast_use_dt, + ast_use_defaults + } config_mode; enum ast_tx_chip tx_chip_type; u8 dp501_maxclk; diff --git a/src/drivers/aspeed/common/ast_main.c b/src/drivers/aspeed/common/ast_main.c index 8ed1eaa803..89194ad0be 100644 --- a/src/drivers/aspeed/common/ast_main.c +++ b/src/drivers/aspeed/common/ast_main.c @@ -37,17 +37,79 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast, return ret; } +static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) +{ + struct ast_private *ast = dev->dev_private; + uint32_t data, jregd0, jregd1; + + /* Defaults */ + ast->config_mode = ast_use_defaults; + *scu_rev = 0xffffffff; + + /* Not all families have a P2A bridge */ + if (dev->pdev->device != PCI_CHIP_AST2000) + return; + + /* + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge + * is disabled. We force using P2A if VGA only mode bit + * is set D[7] + */ + jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); + jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); + if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { + /* Double check it's actually working */ + data = ast_read32(ast, 0xf004); + if (data != 0xFFFFFFFF) { + /* P2A works, grab silicon revision */ + ast->config_mode = ast_use_p2a; + + DRM_INFO("Using P2A bridge for configuration\n"); + + /* Read SCU7c (silicon revision register) */ + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + *scu_rev = ast_read32(ast, 0x1207c); + return; + } + } + + /* We have a P2A bridge but it's disabled */ + DRM_INFO("P2A bridge disabled, using default configuration\n"); +} static int ast_detect_chip(struct drm_device *dev, bool *need_post) { struct ast_private *ast = dev->dev_private; - uint32_t data, jreg; + uint32_t jreg, scu_rev; + + /* + * If VGA isn't enabled, we need to enable now or subsequent + * access to the scratch registers will fail. We also inform + * our caller that it needs to POST the chip + * (Assumption: VGA not enabled -> need to POST) + */ + if (!ast_is_vga_enabled(dev)) { + ast_enable_vga(dev); + DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); + *need_post = true; + } else + *need_post = false; + + + /* Enable extended register access */ + ast_enable_mmio(dev); ast_open_key(ast); + /* Find out whether P2A works or whether to use device-tree */ + ast_detect_config_mode(dev, &scu_rev); + + /* Identify chipset */ if (dev->pdev->device == PCI_CHIP_AST1180) { ast->chip = AST1100; DRM_INFO("AST 1180 detected\n"); } else { + uint32_t data; pci_read_config_dword(ast->dev->pdev, 0x08, &data); uint8_t revision = data & 0xff; if (revision >= 0x40) { @@ -60,11 +122,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->chip = AST2300; DRM_INFO("AST 2300 detected\n"); } else if (revision >= 0x10) { - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - - data = ast_read32(ast, 0x1207c); - switch (data & 0x0300) { + switch (scu_rev & 0x0300) { case 0x0200: ast->chip = AST1100; DRM_INFO("AST 1100 detected\n"); @@ -89,20 +147,6 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) } } - /* - * If VGA isn't enabled, we need to enable now or subsequent - * access to the scratch registers will fail. We also inform - * our caller that it needs to POST the chip - * (Assumption: VGA not enabled -> need to POST) - */ - if (!ast_is_vga_enabled(dev)) { - ast_enable_vga(dev); - ast_enable_mmio(dev); - DRM_INFO("VGA not enabled on entry, requesting chip POST\n"); - *need_post = true; - } else - *need_post = false; - /* Check if we support wide screen */ switch (ast->chip) { case AST1180: @@ -119,16 +163,14 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->support_wide_screen = true; else { ast->support_wide_screen = false; - /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - data = ast_read32(ast, 0x1207c); - data &= 0x300; - if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ + if (ast->chip == AST2300 && + (scu_rev & 0x300) == 0x0) /* ast1300 */ ast->support_wide_screen = true; - if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ + if (ast->chip == AST2400 && + (scu_rev & 0x300) == 0x100) /* ast1400 */ ast->support_wide_screen = true; - if (ast->chip == AST2500 && data == 0x100) /* ast2510 */ + if (ast->chip == AST2500 && + scu_rev == 0x100) /* ast2510 */ ast->support_wide_screen = true; } break; @@ -194,34 +236,44 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) static int ast_get_dram_info(struct drm_device *dev) { struct ast_private *ast = dev->dev_private; - uint8_t i; - uint32_t data, data2; - uint32_t denum, num, div, ref_pll; - - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - - - ast_write32(ast, 0x10000, 0xfc600309); + uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; + uint32_t denum, num, div, ref_pll, dsel; - /* Wait up to 2.5 seconds for device initialization / register unlock */ - for (i = 0; i < 250; i++) { - if (ast_read32(ast, 0x10000) == 0x01) - break; - mdelay(10); + switch (ast->config_mode) { + case ast_use_dt: + /* + * If some properties are missing, use reasonable + * defaults for AST2400 + */ + mcr_cfg = 0x00000577; + mcr_scu_mpll = 0x000050C0; + mcr_scu_strap = 0; + break; + case ast_use_p2a: + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + mcr_cfg = ast_read32(ast, 0x10004); + mcr_scu_mpll = ast_read32(ast, 0x10120); + mcr_scu_strap = ast_read32(ast, 0x10170); + break; + case ast_use_defaults: + default: + ast->dram_bus_width = 16; + ast->dram_type = AST_DRAM_1Gx16; + if (ast->chip == AST2500) + ast->mclk = 800; + else + ast->mclk = 396; + return 0; } - if (ast_read32(ast, 0x10000) != 0x01) - dev_err(dev->pdev, "Unable to unlock SDRAM control registers\n"); - data = ast_read32(ast, 0x10004); - - if (data & 0x40) + if (mcr_cfg & 0x40) ast->dram_bus_width = 16; else ast->dram_bus_width = 32; if (ast->chip == AST2500) { - switch (data & 0x03) { + switch (mcr_cfg & 0x03) { case 0: ast->dram_type = AST_DRAM_1Gx16; break; @@ -237,7 +289,7 @@ static int ast_get_dram_info(struct drm_device *dev) break; } } else if (ast->chip == AST2300 || ast->chip == AST2400) { - switch (data & 0x03) { + switch (mcr_cfg & 0x03) { case 0: ast->dram_type = AST_DRAM_512Mx16; break; @@ -253,13 +305,13 @@ static int ast_get_dram_info(struct drm_device *dev) break; } } else { - switch (data & 0x0c) { + switch (mcr_cfg & 0x0c) { case 0: case 4: ast->dram_type = AST_DRAM_512Mx16; break; case 8: - if (data & 0x40) + if (mcr_cfg & 0x40) ast->dram_type = AST_DRAM_1Gx16; else ast->dram_type = AST_DRAM_512Mx32; @@ -270,17 +322,15 @@ static int ast_get_dram_info(struct drm_device *dev) } } - data = ast_read32(ast, 0x10120); - data2 = ast_read32(ast, 0x10170); - if (data2 & 0x2000) + if (mcr_scu_strap & 0x2000) ref_pll = 14318; else ref_pll = 12000; - denum = data & 0x1f; - num = (data & 0x3fe0) >> 5; - data = (data & 0xc000) >> 14; - switch (data) { + denum = mcr_scu_mpll & 0x1f; + num = (mcr_scu_mpll & 0x3fe0) >> 5; + dsel = (mcr_scu_mpll & 0xc000) >> 14; + switch (dsel) { case 3: div = 0x4; break; @@ -312,6 +362,19 @@ static u32 ast_get_vram_info(struct drm_device *dev) case 3: vram_size = AST_VIDMEM_SIZE_64M; break; } + jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xff); + switch (jreg & 0x03) { + case 1: + vram_size -= 0x100000; + break; + case 2: + vram_size -= 0x200000; + break; + case 3: + vram_size -= 0x400000; + break; + } + return vram_size; } @@ -375,15 +438,19 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) ast_detect_chip(dev, &need_post); + if (need_post) + ast_post_gpu(dev); + if (ast->chip != AST1180) { - ast_get_dram_info(dev); + ret = ast_get_dram_info(dev); + if (ret) + goto out_free; ast->vram_size = ast_get_vram_info(dev); - DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size); + DRM_INFO("dram MCLK=%u Mhz type=%d bus_width=%d size=%08x\n", + ast->mclk, ast->dram_type, + ast->dram_bus_width, ast->vram_size); } - if (need_post) - ast_post_gpu(dev); - return 0; out_free: kfree(ast); diff --git a/src/drivers/aspeed/common/ast_post.c b/src/drivers/aspeed/common/ast_post.c index b3b7d6196c..c909182834 100644 --- a/src/drivers/aspeed/common/ast_post.c +++ b/src/drivers/aspeed/common/ast_post.c @@ -370,14 +370,20 @@ void ast_post_gpu(struct drm_device *dev) ast_enable_mmio(dev); ast_set_def_ext_reg(dev); - if (ast->chip == AST2500) - ast_post_chip_2500(dev); - else if (ast->chip == AST2300 || ast->chip == AST2400) - ast_post_chip_2300(dev); - else - ast_init_dram_reg(dev); - - ast_init_3rdtx(dev); + if (ast->config_mode == ast_use_p2a) { + if (ast->chip == AST2500) + ast_post_chip_2500(dev); + else if (ast->chip == AST2300 || ast->chip == AST2400) + ast_post_chip_2300(dev); + else + ast_init_dram_reg(dev); + + ast_init_3rdtx(dev); + } else { + if (ast->tx_chip_type != AST_TX_NONE) + /* Enable DVO */ + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); + } } /* AST 2300 DRAM settings */ -- cgit v1.2.3