From patchwork Tue Jul 18 14:43:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 9848625 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0BF8B602A7 for ; Tue, 18 Jul 2017 14:43:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F091C237F1 for ; Tue, 18 Jul 2017 14:43:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E582826785; Tue, 18 Jul 2017 14:43:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 665C6237F1 for ; Tue, 18 Jul 2017 14:43:42 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 361F56E36E; Tue, 18 Jul 2017 14:43:28 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3F7AD6E365 for ; Tue, 18 Jul 2017 14:43:26 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id AEC92ADEF; Tue, 18 Jul 2017 14:43:23 +0000 (UTC) From: Takashi Iwai To: dri-devel@lists.freedesktop.org Subject: [PATCH 07/14] drm/mgag200: Add support for MATROX PCI device IDs 0x520 and 0x521 Date: Tue, 18 Jul 2017 16:43:13 +0200 Message-Id: <20170718144320.8354-8-tiwai@suse.de> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20170718144320.8354-1-tiwai@suse.de> References: <20170718144320.8354-1-tiwai@suse.de> Cc: Egbert Eich , Dave Airlie , Mathieu Larouche , Daniel Vetter X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Egbert Eich Add two more models G200_PCI and G200 for PCI device IDs 0x520 and 0x521, respectively. They need to retrieve the reference clock and pclk min/max values from BIOS, and set up the PLLs accordingly. Signed-off-by: Egbert Eich Signed-off-by: Takashi Iwai --- drivers/gpu/drm/mgag200/mgag200_drv.c | 2 + drivers/gpu/drm/mgag200/mgag200_drv.h | 7 ++ drivers/gpu/drm/mgag200/mgag200_main.c | 113 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 81 +++++++++++++++++++++++ 4 files changed, 203 insertions(+) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 9ac007880328..03258e9fc6c0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -29,6 +29,8 @@ module_param_named(modeset, mgag200_modeset, int, 0400); static struct drm_driver driver; static const struct pci_device_id pciidlist[] = { + { PCI_VENDOR_ID_MATROX, 0x520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_PCI }, + { PCI_VENDOR_ID_MATROX, 0x521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200 }, { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A }, { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B }, { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV }, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 2ba4060e3363..1ba559c93b8f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -175,6 +175,8 @@ struct mga_mc { }; enum mga_type { + G200_PCI, + G200, G200_SE_A, G200_SE_B, G200_WB, @@ -219,6 +221,11 @@ struct mga_device { /* SE model number stored in reg 0x1e24 */ u32 unique_rev_id; + struct { + long ref_clk; + long pclk_min; + long pclk_max; + } bios; }; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index cf3a602f453f..87c5469d06a7 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -155,6 +155,116 @@ static int mga_vram_init(struct mga_device *mdev) return 0; } +#define MGA_BIOS_OFFSET 0x7ffc + +static void mgag200_interpret_bios(struct mga_device *mdev, + unsigned char __iomem *bios, + size_t size) +{ + static const unsigned int expected_length[6] = { + 0, 64, 64, 64, 128, 128 + }; + unsigned char __iomem *pins; + unsigned int pins_len, version; + int offset; + int tmp; + + if (size < MGA_BIOS_OFFSET + 1) + return; + + if (bios[45] != 'M' || bios[46] != 'A' || bios[47] != 'T' || + bios[48] != 'R' || bios[49] != 'O' || bios[50] != 'X') + return; + + offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET]; + + if (offset + 5 > size) + return; + + pins = bios + offset; + if (pins[0] == 0x2e && pins[1] == 0x41) { + version = pins[5]; + pins_len = pins[2]; + } else { + version = 1; + pins_len = pins[0] + (pins[1] << 8); + } + + if (version < 1 || version > 5) { + DRM_WARN("Unknown BIOS PInS version: %d\n", version); + return; + } + if (pins_len != expected_length[version]) { + DRM_WARN("Unexpected BIOS PInS size: %d expeced: %d\n", + pins_len, expected_length[version]); + return; + } + + if (offset + pins_len > size) + return; + + DRM_DEBUG_KMS("MATROX BIOS PInS version %d size: %d found\n", + version, pins_len); + + switch (version) { + case 1: + tmp = pins[24] + (pins[25] << 8); + if (tmp) + mdev->bios.pclk_max = tmp * 10; + break; + case 2: + if (pins[41] != 0xff) + mdev->bios.pclk_max = (pins[41] + 100) * 1000; + break; + case 3: + if (pins[36] != 0xff) + mdev->bios.pclk_max = (pins[36] + 100) * 1000; + if (pins[52] & 0x20) + mdev->bios.ref_clk = 14318; + break; + case 4: + if (pins[39] != 0xff) + mdev->bios.pclk_max = pins[39] * 4 * 1000; + if (pins[92] & 0x01) + mdev->bios.ref_clk = 14318; + break; + case 5: + tmp = pins[4] ? 8000 : 6000; + if (pins[123] != 0xff) + mdev->bios.pclk_min = pins[123] * tmp; + if (pins[38] != 0xff) + mdev->bios.pclk_max = pins[38] * tmp; + if (pins[110] & 0x01) + mdev->bios.ref_clk = 14318; + break; + default: + break; + } +} + +static void mgag200_probe_bios(struct mga_device *mdev) +{ + unsigned char __iomem *bios; + size_t size; + + mdev->bios.pclk_min = 50000; + mdev->bios.pclk_max = 230000; + mdev->bios.ref_clk = 27050; + + bios = pci_map_rom(mdev->dev->pdev, &size); + if (!bios) + return; + + if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa) + mgag200_interpret_bios(mdev, bios, size); + + pci_unmap_rom(mdev->dev->pdev, bios); + + DRM_DEBUG_KMS("pclk_min: %ld pclk_max: %ld ref_clk: %ld\n", + mdev->bios.pclk_min, mdev->bios.pclk_max, + mdev->bios.ref_clk); +} + static int mgag200_device_init(struct drm_device *dev, uint32_t flags) { @@ -187,6 +297,9 @@ static int mgag200_device_init(struct drm_device *dev, if (IS_G200_SE(mdev)) mdev->unique_rev_id = RREG32(0x1e24); + if (mdev->type == G200_PCI || mdev->type == G200) + mgag200_probe_bios(mdev); + ret = mga_vram_init(mdev); if (ret) return ret; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index afec8f190ee3..ba7ee93b57a9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -92,6 +92,72 @@ static inline void mga_wait_busy(struct mga_device *mdev) } while ((status & 0x01) && time_before(jiffies, timeout)); } +static int mga_set_plls(struct mga_device *mdev, long clock) +{ + const int post_div_max = 7; + const int in_div_min = 1; + const int in_div_max = 6; + const int feed_div_min = 7; + const int feed_div_max = 127; + u8 testm, testn; + u8 n = 0, m = 0, p, s; + long f_vco; + long computed; + long delta, tmp_delta; + long ref_clk = mdev->bios.ref_clk; + long p_clk_min = mdev->bios.pclk_min; + long p_clk_max = mdev->bios.pclk_max; + + if (clock > p_clk_max) { + DRM_WARN("Pixel Clock %ld too high\n", clock); + return 1; + } + + if (clock < p_clk_min >> 3) + clock = p_clk_min >> 3; + + f_vco = clock; + for (p = 0; + p <= post_div_max && f_vco < p_clk_min; + p = (p << 1) + 1, f_vco <<= 1) + ; + + delta = clock; + + for (testm = in_div_min; testm <= in_div_max; testm++) { + for (testn = feed_div_min; testn <= feed_div_max; testn++) { + computed = ref_clk * (testn + 1) / (testm + 1); + if (computed < f_vco) + tmp_delta = f_vco - computed; + else + tmp_delta = computed - f_vco; + if (tmp_delta < delta) { + delta = tmp_delta; + m = testm; + n = testn; + } + } + } + f_vco = ref_clk * (n + 1) / (m + 1); + if (f_vco < 100000) + s = 0; + else if (f_vco < 140000) + s = 1; + else if (f_vco < 180000) + s = 2; + else + s = 3; + + DRM_DEBUG_KMS("clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", + clock, f_vco, m, n, p, s); + + WREG_DAC(MGA1064_PIX_PLLC_M, m); + WREG_DAC(MGA1064_PIX_PLLC_N, n); + WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); + + return 0; +} + #define P_ARRAY_SIZE 9 static int mga_g200se_set_plls(struct mga_device *mdev, long clock) @@ -698,6 +764,10 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) static int mga_crtc_set_plls(struct mga_device *mdev, long clock) { switch(mdev->type) { + case G200: + case G200_PCI: + return mga_set_plls(mdev, clock); + break; case G200_SE_A: case G200_SE_B: return mga_g200se_set_plls(mdev, clock); @@ -944,6 +1014,17 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, bppshift = mdev->bpp_shifts[fb->format->cpp[0] - 1]; switch (mdev->type) { + case G200: + case G200_PCI: + dacvalue[MGA1064_SYS_PLL_M] = 0x04; + dacvalue[MGA1064_SYS_PLL_N] = 0x2D; + dacvalue[MGA1064_SYS_PLL_P] = 0x19; + if (mdev->has_sdram) + option = 0x40499121; + else + option = 0x4049cd21; + option2 = 0x00008000; + break; case G200_SE_A: case G200_SE_B: dacvalue[MGA1064_VREF_CTL] = 0x03;