[PATCH 1/9] drm/ast: Handle configuration without P2A bridge
Benjamin Herrenschmidt
benh at kernel.crashing.org
Fri Feb 17 07:43:00 UTC 2017
On Fri, 2017-02-17 at 16:32 +1100, Benjamin Herrenschmidt wrote:
Make this
From: Russell Currey <ruscur at russell.cc>
Git ate it when I amended (citool bug) and I forgot to fix it up.
> 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".
>
> A recent patch went in to try to check if that window is open
> but it does so by trying to access the registers in question
> and testing if the result is 0xffffffff.
>
> This method will trigger a PCIe error when the window is closed
> which on some systems will be fatal (it will trigger an EEH
> for example on POWER which will take out the device).
>
> This patch improves this in two ways:
>
> - First, if the firmware has put properties in the device-tree
> containing the relevant configuration information, we use these.
>
> - Otherwise, a bit in one of the SCU scratch registers (which
> are readable via the VGA register space and writeable by the BMC)
> will indicate if the BMC has closed the window. This bit has been
> defined by Y.C Chen from Aspeed.
>
> If the window is closed and the configuration isn't available from
> the device-tree, some sane defaults are used. Those defaults are
> hopefully sufficient for standard video modes used on a server.
>
> Signed-off-by: Russell Currey <ruscur at russell.cc>
> Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> --
>
> v2. [BenH]
> - Reworked on top of Aspeed P2A patch
> - Cleanup overall detection via a "config_mode" and log the
> selected mode for diagnostics purposes
> - Add a property for the SCU straps
>
> v3. [BenH]
> - Moved the config mode detection to a separate functionn
> - Add reading of SCU 0x40 D[12] to detect the window is
> closed as to not trigger a bus error by just "trying".
> (change provided by Y.C. Chen)
> ---
> drivers/gpu/drm/ast/ast_drv.h | 6 +-
> drivers/gpu/drm/ast/ast_main.c | 223 +++++++++++++++++++++++++----
> ------------
> drivers/gpu/drm/ast/ast_post.c | 7 +-
> 3 files changed, 141 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/gpu/drm/ast/ast_drv.h
> b/drivers/gpu/drm/ast/ast_drv.h
> index 7abda94..3bedcf7 100644
> --- a/drivers/gpu/drm/ast/ast_drv.h
> +++ b/drivers/gpu/drm/ast/ast_drv.h
> @@ -113,7 +113,11 @@ struct ast_private {
> struct ttm_bo_kmap_obj cache_kmap;
> int next_cursor;
> bool support_wide_screen;
> - bool DisableP2A;
> + 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/drivers/gpu/drm/ast/ast_main.c
> b/drivers/gpu/drm/ast/ast_main.c
> index 533e762..823c68f 100644
> --- a/drivers/gpu/drm/ast/ast_main.c
> +++ b/drivers/gpu/drm/ast/ast_main.c
> @@ -62,13 +62,58 @@ 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 device_node *np = dev->pdev->dev.of_node;
> + struct ast_private *ast = dev->dev_private;
> + uint32_t data, jreg;
> +
> + /* Check if we have device-tree properties */
> + if (np && !of_property_read_u32(np, "ast,scu-revision-id",
> scu_rev)) {
> + /* We do, disable P2A access */
> + ast->config_mode = ast_use_dt;
> + DRM_INFO("Using device-tree for configuration\n");
> + return;
> + }
> +
> + /*
> + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge
> + * is disabled
> + */
> + jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1,
> 0xff);
> + if (!(jreg & 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;
> + }
> + }
> +
> + DRM_INFO("P2A bridge disabled, using default
> configuration\n");
> + ast->config_mode = ast_use_defaults;
> + *scu_rev = 0xffffffff;
> +}
>
> 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;
> +
> 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");
> @@ -80,12 +125,7 @@ static int ast_detect_chip(struct drm_device
> *dev, bool *need_post)
> ast->chip = AST2300;
> DRM_INFO("AST 2300 detected\n");
> } else if (dev->pdev->revision >= 0x10) {
> - uint32_t data;
> - 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");
> @@ -124,12 +164,6 @@ static int ast_detect_chip(struct drm_device
> *dev, bool *need_post)
> } else
> *need_post = false;
>
> - /* Check P2A Access */
> - ast->DisableP2A = true;
> - data = ast_read32(ast, 0xf004);
> - if (data != 0xFFFFFFFF)
> - ast->DisableP2A = false;
> -
> /* Check if we support wide screen */
> switch (ast->chip) {
> case AST1180:
> @@ -146,17 +180,12 @@ static int ast_detect_chip(struct drm_device
> *dev, bool *need_post)
> ast->support_wide_screen = true;
> else {
> ast->support_wide_screen = false;
> - if (ast->DisableP2A == 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 */
> - ast->support_wide_screen =
> true;
> - if (ast->chip == AST2400 && data ==
> 0x100) /* ast1400 */
> - ast->support_wide_screen =
> true;
> - }
> + if (ast->chip == AST2300 &&
> + (scu_rev & 0x300) == 0x0) /* ast1300 */
> + ast->support_wide_screen = true;
> + if (ast->chip == AST2400 &&
> + (scu_rev & 0x300) == 0x100) /* ast1400
> */
> + ast->support_wide_screen = true;
> }
> break;
> }
> @@ -220,85 +249,101 @@ static int ast_detect_chip(struct drm_device
> *dev, bool *need_post)
>
> static int ast_get_dram_info(struct drm_device *dev)
> {
> + struct device_node *np = dev->pdev->dev.of_node;
> struct ast_private *ast = dev->dev_private;
> - uint32_t data, data2;
> - uint32_t denum, num, div, ref_pll;
> + uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap;
> + uint32_t denum, num, div, ref_pll, dsel;
>
> - if (ast->DisableP2A)
> - {
> + switch (ast->config_mode) {
> + case ast_use_dt:
> + /*
> + * If some properties are missing, use reasonable
> + * defaults for AST2400
> + */
> + if (of_property_read_u32(np, "ast,mcr-
> configuration", &mcr_cfg))
> + mcr_cfg = 0x00000577;
> + if (of_property_read_u32(np, "ast,ast,mcr-scu-mpll",
> + &mcr_scu_mpll))
> + mcr_scu_mpll = 0x000050C0;
> + if (of_property_read_u32(np, "ast,ast,mcr-scu-
> strap",
> + &mcr_scu_strap))
> + 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;
> ast->mclk = 396;
> + return 0;
> }
> - else
> - {
> - ast_write32(ast, 0xf004, 0x1e6e0000);
> - ast_write32(ast, 0xf000, 0x1);
> - data = ast_read32(ast, 0x10004);
> -
> - if (data & 0x40)
> - ast->dram_bus_width = 16;
> - else
> - ast->dram_bus_width = 32;
>
> - if (ast->chip == AST2300 || ast->chip == AST2400) {
> - switch (data & 0x03) {
> - case 0:
> - ast->dram_type = AST_DRAM_512Mx16;
> - break;
> - default:
> - case 1:
> - ast->dram_type = AST_DRAM_1Gx16;
> - break;
> - case 2:
> - ast->dram_type = AST_DRAM_2Gx16;
> - break;
> - case 3:
> - ast->dram_type = AST_DRAM_4Gx16;
> - break;
> - }
> - } else {
> - switch (data & 0x0c) {
> - case 0:
> - case 4:
> - ast->dram_type = AST_DRAM_512Mx16;
> - break;
> - case 8:
> - if (data & 0x40)
> - ast->dram_type =
> AST_DRAM_1Gx16;
> - else
> - ast->dram_type =
> AST_DRAM_512Mx32;
> - break;
> - case 0xc:
> - ast->dram_type = AST_DRAM_1Gx32;
> - break;
> - }
> - }
> + if (mcr_cfg & 0x40)
> + ast->dram_bus_width = 16;
> + else
> + ast->dram_bus_width = 32;
>
> - data = ast_read32(ast, 0x10120);
> - data2 = ast_read32(ast, 0x10170);
> - if (data2 & 0x2000)
> - ref_pll = 14318;
> - else
> - ref_pll = 12000;
> -
> - denum = data & 0x1f;
> - num = (data & 0x3fe0) >> 5;
> - data = (data & 0xc000) >> 14;
> - switch (data) {
> - case 3:
> - div = 0x4;
> + if (ast->chip == AST2300 || ast->chip == AST2400) {
> + switch (mcr_cfg & 0x03) {
> + case 0:
> + ast->dram_type = AST_DRAM_512Mx16;
> break;
> - case 2:
> + default:
> case 1:
> - div = 0x2;
> + ast->dram_type = AST_DRAM_1Gx16;
> break;
> - default:
> - div = 0x1;
> + case 2:
> + ast->dram_type = AST_DRAM_2Gx16;
> + break;
> + case 3:
> + ast->dram_type = AST_DRAM_4Gx16;
> break;
> }
> - ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div
> * 1000);
> + } else {
> + switch (mcr_cfg & 0x0c) {
> + case 0:
> + case 4:
> + ast->dram_type = AST_DRAM_512Mx16;
> + break;
> + case 8:
> + if (mcr_cfg & 0x40)
> + ast->dram_type = AST_DRAM_1Gx16;
> + else
> + ast->dram_type = AST_DRAM_512Mx32;
> + break;
> + case 0xc:
> + ast->dram_type = AST_DRAM_1Gx32;
> + break;
> + }
> + }
> +
> + if (mcr_scu_strap & 0x2000)
> + ref_pll = 14318;
> + else
> + ref_pll = 12000;
> +
> + denum = mcr_scu_mpll & 0x1f;
> + num = (mcr_scu_mpll & 0x3fe0) >> 5;
> + dsel = (mcr_scu_mpll & 0xc000) >> 14;
> + switch (dsel) {
> + case 3:
> + div = 0x4;
> + break;
> + case 2:
> + case 1:
> + div = 0x2;
> + break;
> + default:
> + div = 0x1;
> + break;
> }
> + ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div *
> 1000);
> return 0;
> }
>
> diff --git a/drivers/gpu/drm/ast/ast_post.c
> b/drivers/gpu/drm/ast/ast_post.c
> index 5331ee1..7197635 100644
> --- a/drivers/gpu/drm/ast/ast_post.c
> +++ b/drivers/gpu/drm/ast/ast_post.c
> @@ -379,17 +379,14 @@ void ast_post_gpu(struct drm_device *dev)
> ast_open_key(ast);
> ast_set_def_ext_reg(dev);
>
> - if (ast->DisableP2A == false)
> - {
> + if (ast->config_mode == ast_use_p2a) {
> if (ast->chip == AST2300 || ast->chip == AST2400)
> ast_init_dram_2300(dev);
> else
> ast_init_dram_reg(dev);
>
> ast_init_3rdtx(dev);
> - }
> - else
> - {
> + } else {
> if (ast->tx_chip_type != AST_TX_NONE)
> ast_set_index_reg_mask(ast,
> AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */
> }
More information about the dri-devel
mailing list