[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <PSAPR06MB48059863BEAA36A481BD903F8CCA9@PSAPR06MB4805.apcprd06.prod.outlook.com>
Date: Fri, 13 May 2022 10:39:13 +0000
From: Kuo-Hsiang Chou <kuohsiang_chou@...eedtech.com>
To: Thomas Zimmermann <tzimmermann@...e.de>,
"dri-devel@...ts.freedesktop.org" <dri-devel@...ts.freedesktop.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
CC: Hungju Huang <hungju_huang@...eedtech.com>,
"airlied@...ux.ie" <airlied@...ux.ie>,
Tommy Huang <tommy_huang@...eedtech.com>,
"airlied@...hat.com" <airlied@...hat.com>,
Arc Sung <arc_sung@...eedtech.com>,
Luke Chen <luke_chen@...eedtech.com>
Subject: RE: [PATCH v4] drm/ast: Create the driver for ASPEED proprietory
Display-Port
Hi Thomas,
-----Original Message-----
From: Thomas Zimmermann [mailto:tzimmermann@...e.de]
Sent: Friday, May 13, 2022 6:21 PM
To: Kuo-Hsiang Chou <kuohsiang_chou@...eedtech.com>; dri-devel@...ts.freedesktop.org; linux-kernel@...r.kernel.org
Subject: Re: [PATCH v4] drm/ast: Create the driver for ASPEED proprietory Display-Port
Hi
Am 13.05.22 um 11:07 schrieb Kuo-Hsiang Chou:
>
>
> -----Original Message-----
> From: Thomas Zimmermann [mailto:tzimmermann@...e.de]
> Sent: Tuesday, May 10, 2022 6:56 PM
> To: Kuo-Hsiang Chou <kuohsiang_chou@...eedtech.com>;
> dri-devel@...ts.freedesktop.org; linux-kernel@...r.kernel.org
> Subject: Re: [PATCH v4] drm/ast: Create the driver for ASPEED
> proprietory Display-Port
>
> Hi
>
> Am 04.05.22 um 10:49 schrieb Kuo-Hsiang Chou:
>> Hi Thomas,
>>
>> Thanks for your efforts to review this patch.
>>
>> Now, I observe a change that after DP unplugged and then the system
>> is unable to get EDID from D-sub connecting.
>>
>> The reason seems that TXs are merged into union structure in
>> /drivers/gpu/drm/ast/ast_drv.h
>> (a59b026419f33040d7d28b8e3b1cea681b9ce7a7
>> <https://cgit.freedesktop.org/drm/drm-misc/commit/?id=a59b026419f3304
>> 0
>> d7d28b8e3b1cea681b9ce7a7>)
>
> I have posted a patch that enables multiple parallel outputs. See
>
>
> <https://lore.kernel.org/dri-devel/20220510105010.20712-1-tzimmermann@
> suse.de/T/#u>
>
> If you have the time, I'd appreciate if you could test it.
>
> Hi Thomas,
> First, thanks for your efforts on this patch of " enables multiple parallel outputs ".
> But it doesn't work. There is still NO EDID got from D-sub after DP unplugged.
>
> Base on your patch, I am trying to find out the solution also.
> Final, thanks for your help again!
Let's try to find a solution. I might be able to come up with something if I have enough information.
How are these outputs connected to each each other?
1. DP and D-sub both connected: it is correct to get EDID and monitor type is correctly shown on display setting. Resolution is up to 1920*1200.
2. DP unplugged and only D-sub connected: Unknown Display is shown on display setting. Only 800*600 and 1024*768 are available for Resolution.
They are both served by the same CRTC. Can they be used at the same time?
No, 2 different monitors are connected at same time.
One is connected by D-sub and another is connected by DP connecting.
Are they mutually exclusive?
Yes, If DP and D-sub are all connecting, DP's EDID is first priority for Display setting.
When DP unplugged, EDID got from D-sub are used for Display setting.
Now, I try to add the codes of ast_vga_connector_helper_get_modes() into ast_astdp_connector_helper_get_modes().
The result is failed.
Anyway, I will continue to try and test the feature next Monday.
Thanks for your great help!
Regards,
Kuo-Hsiang Chou
Best regards
Thomas
>
> Regards,
> Kuo-Hsiang Chou
>
> Best regards
> Thomas
>
>>
>> Another, do you need the ast2600 EVB to ease verification on "drm/ast" ?
>>
>> Regards,
>>
>> Kuo-Hsiang Chou
>>
>> -----Original Message-----
>> From: Thomas Zimmermann [mailto:tzimmermann@...e.de]
>> Sent: Wednesday, May 04, 2022 3:28 PM
>> To: Kuo-Hsiang Chou <kuohsiang_chou@...eedtech.com>;
>> dri-devel@...ts.freedesktop.org; linux-kernel@...r.kernel.org
>> Subject: Re: [PATCH v4] drm/ast: Create the driver for ASPEED
>> proprietory Display-Port
>>
>> Hi
>>
>> Am 28.04.22 um 09:56 schrieb KuoHsiang Chou:
>>
>>> V1:
>>
>>> 1. The MCU FW controling ASPEED DP is loaded by BMC boot loader.
>>
>>> 2. Driver starts after CR[3:1] == 111b that indicates Tx is ASTDP,
>>
>>> and CRD1[5] has been asserted by BMVC boot loader.
>>
>>> 3. EDID is prioritized by DP monitor.
>>
>>> 4. DP's EDID has high priority to decide resolution supporting.
>>
>>>
>>
>>> V2:
>>
>>> Modules description:
>>
>>> 1. ASTDP (ASPEED DisplayPort) is controlled by dedicated
>>
>>> AST-MCU (ASPEED propriatary MCU).
>>
>>> 2. MCU is looping in charged of HPD, Read EDID, Link Training with
>>
>>> DP sink.
>>
>>> 3. ASTDP and AST-MUC reside in BMC (Baseboard Management controller)
>>
>>> addressing-space.
>>
>>> 4. ASPEED DRM driver requests MCU to get HPD and EDID by
>>> CR-scratched
>>
>>> register.
>>
>>>
>>
>>> Booting sequence:
>>
>>> 1. Check if TX is ASTDP //
>>> ast_dp_launch()
>>
>>> 2. Check if DP-MCU FW has loaded
>>> // ast_dp_launch()
>>
>>> 3. Read EDID //
>>> ast_dp_read_edid()
>>
>>> 4. Resolution switch //
>>> ast_dp_SetOutput()
>>
>>>
>>
>>> V3:
>>
>>> 1. Remove unneeded semicolon.
>>
>>> 2. Apply to git://anongit.freedesktop.org/drm/drm, instead of
>>
>>> git://anongit.freedesktop.org/drm/drm-misc
>>
>>> 3. Resolve auto build test WARNINGs on V1 patch.
>>
>>>
>>
>>> V4:
>>
>>> 1. Sync code-base with kernel 5.17_rc6 2. Remove the define of
>>
>>> DPControlPower, because DP chips need to be
>>
>>> powered on to be used.
>>
>>> 3. Remove the switches of PHY and Display from EDID procedure.
>>
>>> 4. Revise increaing delay to fixed delay, because this version
>>> kernel
>>
>>> doesn't detect minitor consistenntly.
>>
>>> 5. Create clean-up code used for reset of power state on errors with
>>
>>> -EIO manner.
>>
>>> 6. Revise the DP detection by TX type and its DP-FW status during
>>
>>> booting and resume.
>>
>>> 7. Correct the CamelCase Style.
>>
>>> 8. Use register reading while needing, and remove to hold full
>>
>>> register.
>>
>>> 9. Instead of 'u8', revise to 'bool' on swwitch of PHY and video.
>>
>>> 10.Correct typo
>>
>>> 11.Remove the duplicated copy of TX definition.
>>
>>> 12.Use EDID_LENGTH as the constant of 128.
>>
>>>
>>
>>> Signed-off-by: KuoHsiang Chou <kuohsiang_chou@...eedtech.com
>>> <mailto:kuohsiang_chou@...eedtech.com>>
>>
>> Reviewed-by: Thomas Zimmermann <tzimmermann@...e.de
>> <mailto:tzimmermann@...e.de>>
>>
>> I've meanwhile added your patch to drm-misc-next. It should show up
>> in one of the next kernel releases. Thanks a lot.
>>
>> Best regards
>>
>> Thomas
>>
>>> ---
>>
>>> drivers/gpu/drm/ast/Makefile | 2 +-
>>
>>> drivers/gpu/drm/ast/ast_dp.c | 282
>>> +++++++++++++++++++++++++++++++++
>>
>>> drivers/gpu/drm/ast/ast_drv.h | 115 ++++++++++++++
>>
>>> drivers/gpu/drm/ast/ast_main.c | 5 +-
>>
>>> drivers/gpu/drm/ast/ast_mode.c | 124 ++++++++++++++-
>>
>>> drivers/gpu/drm/ast/ast_post.c | 4 +-
>>
>>> 6 files changed, 524 insertions(+), 8 deletions(-)
>>
>>> create mode 100644 drivers/gpu/drm/ast/ast_dp.c
>>
>>>
>>
>>> diff --git a/drivers/gpu/drm/ast/Makefile
>>
>>> b/drivers/gpu/drm/ast/Makefile index 21f71160b..5a53ce51f 100644
>>
>>> --- a/drivers/gpu/drm/ast/Makefile
>>
>>> +++ b/drivers/gpu/drm/ast/Makefile
>>
>>> @@ -3,6 +3,6 @@
>>
>>> # Makefile for the drm device driver. This driver provides
>>> support for the
>>
>>> # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>>
>>>
>>
>>> -ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o
>>
>>> ast_post.o ast_dp501.o
>>
>>> +ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o
>>
>>> +ast_post.o ast_dp501.o ast_dp.o
>>
>>>
>>
>>> obj-$(CONFIG_DRM_AST) := ast.o
>>
>>> diff --git a/drivers/gpu/drm/ast/ast_dp.c
>>
>>> b/drivers/gpu/drm/ast/ast_dp.c new file mode 100644 index
>>
>>> 000000000..4551bc8a3
>>
>>> --- /dev/null
>>
>>> +++ b/drivers/gpu/drm/ast/ast_dp.c
>>
>>> @@ -0,0 +1,282 @@
>>
>>> +// SPDX-License-Identifier: GPL-2.0
>>
>>> +// Copyright (c) 2021, ASPEED Technology Inc.
>>
>>> +// Authors: KuoHsiang Chou <kuohsiang_chou@...eedtech.com
>>> +<mailto:kuohsiang_chou@...eedtech.com>>
>>
>>> +
>>
>>> +#include <linux/firmware.h>
>>
>>> +#include <linux/delay.h>
>>
>>> +#include <drm/drm_print.h>
>>
>>> +#include "ast_drv.h"
>>
>>> +
>>
>>> +int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) {
>>
>>> + struct ast_private *ast = to_ast_private(dev);
>>
>>> + u8 i = 0, j = 0;
>>
>>> +
>>
>>> + /*
>>
>>> + * CRD1[b5]: DP MCU FW is executing
>>
>>> + * CRDC[b0]: DP link success
>>
>>> + * CRDF[b0]: DP HPD
>>
>>> + * CRE5[b0]: Host reading EDID process is done
>>
>>> + */
>>
>>> + if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1,
>>> +ASTDP_MCU_FW_EXECUTING) &&
>>
>>> + ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC,
>>> +ASTDP_LINK_SUCCESS) &&
>>
>>> + ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF,
>>> +ASTDP_HPD) &&
>>
>>> + ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
>>
>>> +
>>> +ASTDP_HOST_EDID_READ_DONE_MASK))) {
>>
>>> + goto err_astdp_edid_not_ready;
>>
>>> + }
>>
>>> +
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8)
>>> +~ASTDP_HOST_EDID_READ_DONE_MASK,
>>
>>> + 0x00);
>>
>>> +
>>
>>> + for (i = 0; i < 32; i++) {
>>
>>> + /*
>>
>>> + * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid
>>> +range: 0~64
>>
>>> + */
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4,
>>
>>> + (u8)
>>> +~ASTDP_EDID_READ_POINTER_MASK, (u8) i);
>>
>>> + j = 0;
>>
>>> +
>>
>>> + /*
>>
>>> + * CRD7[b0]: valid flag for EDID
>>
>>> + * CRD6[b0]: mirror read pointer for EDID
>>
>>> + */
>>
>>> + while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
>>> +0xD7,
>>
>>> + ASTDP_EDID_VALID_FLAG_MASK) != 0x01) ||
>>
>>> + (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
>>> +0xD6,
>>
>>> +
>>> +ASTDP_EDID_READ_POINTER_MASK) != i)) {
>>
>>> + /*
>>
>>> + * Delay are getting longer with each retry.
>>
>>> + * 1. The Delays are often 2 loops when users request "Display Settings"
>>
>>> + * of right-click of mouse.
>>
>>> + * 2. The Delays are often longer a lot when system resume from S3/S4.
>>
>>> + */
>>
>>> + mdelay(j+1);
>>
>>> +
>>
>>> + if (!(ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xD1,
>>
>>> +
>>> +ASTDP_MCU_FW_EXECUTING) &&
>>
>>> + ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xDC,
>>
>>> +
>>> +ASTDP_LINK_SUCCESS) &&
>>
>>> + ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))) {
>>
>>> + goto err_astdp_jump_out_loop_of_edid;
>>
>>> + }
>>
>>> +
>>
>>> + j++;
>>
>>> + if (j > 200)
>>
>>> + goto err_astdp_jump_out_loop_of_edid;
>>
>>> + }
>>
>>> +
>>
>>> + *(ediddata) = ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT,
>>
>>> + 0xD8,
>>> +ASTDP_EDID_READ_DATA_MASK);
>>
>>> + *(ediddata + 1) = ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xD9,
>>
>>> +
>>> +ASTDP_EDID_READ_DATA_MASK);
>>
>>> + *(ediddata + 2) = ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xDA,
>>
>>> +
>>> +ASTDP_EDID_READ_DATA_MASK);
>>
>>> + *(ediddata + 3) = ast_get_index_reg_mask(ast,
>>> +AST_IO_CRTC_PORT, 0xDB,
>>
>>> +
>>> +ASTDP_EDID_READ_DATA_MASK);
>>
>>> +
>>
>>> + if (i == 31) {
>>
>>> + /*
>>
>>> + * For 128-bytes EDID_1.3,
>>
>>> + * 1. Add the value of Bytes-126 to Bytes-127.
>>
>>> + * The Bytes-127 is Checksum. Sum of
>>> +all 128bytes should
>>
>>> + * equal 0 (mod 256).
>>
>>> + * 2. Modify Bytes-126 to be 0.
>>
>>> + * The Bytes-126 indicates the Number
>>> +of extensions to
>>
>>> + * follow. 0 represents noextensions.
>>
>>> + */
>>
>>> + *(ediddata + 3) = *(ediddata + 3) + *(ediddata +
>>> +2);
>>
>>> + *(ediddata + 2) = 0;
>>
>>> + }
>>
>>> +
>>
>>> + ediddata += 4;
>>
>>> + }
>>
>>> +
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8)
>>> +~ASTDP_HOST_EDID_READ_DONE_MASK,
>>
>>> +
>>> +ASTDP_HOST_EDID_READ_DONE);
>>
>>> +
>>
>>> + return 0;
>>
>>> +
>>
>>> +err_astdp_jump_out_loop_of_edid:
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
>>
>>> + (u8)
>>> +~ASTDP_HOST_EDID_READ_DONE_MASK,
>>
>>> +
>>> +ASTDP_HOST_EDID_READ_DONE);
>>
>>> + return (~(j+256) + 1);
>>
>>> +
>>
>>> +err_astdp_edid_not_ready:
>>
>>> + if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1,
>>> +ASTDP_MCU_FW_EXECUTING)))
>>
>>> + return (~0xD1 + 1);
>>
>>> + if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC,
>>> +ASTDP_LINK_SUCCESS)))
>>
>>> + return (~0xDC + 1);
>>
>>> + if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF,
>>> +ASTDP_HPD)))
>>
>>> + return (~0xDF + 1);
>>
>>> + if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
>>> +ASTDP_HOST_EDID_READ_DONE_MASK)))
>>
>>> + return (~0xE5 + 1);
>>
>>> +
>>
>>> + return 0;
>>
>>> +}
>>
>>> +
>>
>>> +/*
>>
>>> + * Launch Aspeed DP
>>
>>> + */
>>
>>> +void ast_dp_launch(struct drm_device *dev, u8 bPower) {
>>
>>> + u32 i = 0, j = 0, WaitCount = 1;
>>
>>> + u8 bDPTX = 0;
>>
>>> + u8 bDPExecute = 1;
>>
>>> +
>>
>>> + struct ast_private *ast = to_ast_private(dev);
>>
>>> + // S3 come back, need more time to wait BMC ready.
>>
>>> + if (bPower)
>>
>>> + WaitCount = 300;
>>
>>> +
>>
>>> +
>>
>>> + // Wait total count by different condition.
>>
>>> + for (j = 0; j < WaitCount; j++) {
>>
>>> + bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
>>> +0xD1,
>>
>>> +TX_TYPE_MASK);
>>
>>> +
>>
>>> + if (bDPTX)
>>
>>> + break;
>>
>>> +
>>
>>> + msleep(100);
>>
>>> + }
>>
>>> +
>>
>>> + // 0xE : ASTDP with DPMCU FW handling
>>
>>> + if (bDPTX == ASTDP_DPMCU_TX) {
>>
>>> + // Wait one second then timeout.
>>
>>> + i = 0;
>>
>>> +
>>
>>> + while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
>>> +0xD1, COPROCESSOR_LAUNCH) !=
>>
>>> + COPROCESSOR_LAUNCH) {
>>
>>> + i++;
>>
>>> + // wait 100 ms
>>
>>> + msleep(100);
>>
>>> +
>>
>>> + if (i >= 10) {
>>
>>> + // DP would not be ready.
>>
>>> + bDPExecute = 0;
>>
>>> + break;
>>
>>> + }
>>
>>> + }
>>
>>> +
>>
>>> + if (bDPExecute)
>>
>>> + ast->tx_chip_type = AST_TX_ASTDP;
>>
>>> +
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
>>
>>> + (u8)
>>> +~ASTDP_HOST_EDID_READ_DONE_MASK,
>>
>>> +
>>> +ASTDP_HOST_EDID_READ_DONE);
>>
>>> + } else
>>
>>> + ast->tx_chip_type = AST_TX_NONE;
>>
>>> +}
>>
>>> +
>>
>>> +
>>
>>> +
>>
>>> +void ast_dp_power_on_off(struct drm_device *dev, bool on) {
>>
>>> + struct ast_private *ast = to_ast_private(dev);
>>
>>> + // Read and Turn off DP PHY sleep
>>
>>> + u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3,
>>
>>> +AST_DP_VIDEO_ENABLE);
>>
>>> +
>>
>>> + // Turn on DP PHY sleep
>>
>>> + if (!on)
>>
>>> + bE3 |= AST_DP_PHY_SLEEP;
>>
>>> +
>>
>>> + // DP Power on/off
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8)
>>
>>> +~AST_DP_PHY_SLEEP, bE3); }
>>
>>> +
>>
>>> +
>>
>>> +
>>
>>> +void ast_dp_set_on_off(struct drm_device *dev, bool on) {
>>
>>> + struct ast_private *ast = to_ast_private(dev);
>>
>>> + u8 video_on_off = on;
>>
>>> +
>>
>>> + // Video On/Off
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8)
>>
>>> +~AST_DP_VIDEO_ENABLE, on);
>>
>>> +
>>
>>> + // If DP plug in and link successful then check video on / off
>>> +status
>>
>>> + if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC,
>>> +ASTDP_LINK_SUCCESS) &&
>>
>>> + ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF,
>>> +ASTDP_HPD)) {
>>
>>> + video_on_off <<= 4;
>>
>>> + while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
>>> +0xDF,
>>
>>> +
>>> +ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) {
>>
>>> + // wait 1 ms
>>
>>> + mdelay(1);
>>
>>> + }
>>
>>> + }
>>
>>> +}
>>
>>> +
>>
>>> +void ast_dp_set_mode(struct drm_crtc *crtc, struct
>>
>>> +ast_vbios_mode_info *vbios_mode) {
>>
>>> + struct ast_private *ast = to_ast_private(crtc->dev);
>>
>>> +
>>
>>> + u32 ulRefreshRateIndex;
>>
>>> + u8 ModeIdx;
>>
>>> +
>>
>>> + ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index -
>>> +1;
>>
>>> +
>>
>>> + switch (crtc->mode.crtc_hdisplay) {
>>
>>> + case 320:
>>
>>> + ModeIdx = ASTDP_320x240_60;
>>
>>> + break;
>>
>>> + case 400:
>>
>>> + ModeIdx = ASTDP_400x300_60;
>>
>>> + break;
>>
>>> + case 512:
>>
>>> + ModeIdx = ASTDP_512x384_60;
>>
>>> + break;
>>
>>> + case 640:
>>
>>> + ModeIdx = (ASTDP_640x480_60 + (u8) ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 800:
>>
>>> + ModeIdx = (ASTDP_800x600_56 + (u8) ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 1024:
>>
>>> + ModeIdx = (ASTDP_1024x768_60 + (u8) ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 1152:
>>
>>> + ModeIdx = ASTDP_1152x864_75;
>>
>>> + break;
>>
>>> + case 1280:
>>
>>> + if (crtc->mode.crtc_vdisplay == 800)
>>
>>> + ModeIdx = (ASTDP_1280x800_60_RB - (u8)
>>> +ulRefreshRateIndex);
>>
>>> + else // 1024
>>
>>> + ModeIdx = (ASTDP_1280x1024_60 + (u8)
>>> +ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 1360:
>>
>>> + case 1366:
>>
>>> + ModeIdx = ASTDP_1366x768_60;
>>
>>> + break;
>>
>>> + case 1440:
>>
>>> + ModeIdx = (ASTDP_1440x900_60_RB - (u8)
>>> +ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 1600:
>>
>>> + if (crtc->mode.crtc_vdisplay == 900)
>>
>>> + ModeIdx = (ASTDP_1600x900_60_RB - (u8)
>>> +ulRefreshRateIndex);
>>
>>> + else //1200
>>
>>> + ModeIdx = ASTDP_1600x1200_60;
>>
>>> + break;
>>
>>> + case 1680:
>>
>>> + ModeIdx = (ASTDP_1680x1050_60_RB - (u8)
>>> +ulRefreshRateIndex);
>>
>>> + break;
>>
>>> + case 1920:
>>
>>> + if (crtc->mode.crtc_vdisplay == 1080)
>>
>>> + ModeIdx = ASTDP_1920x1080_60;
>>
>>> + else //1200
>>
>>> + ModeIdx = ASTDP_1920x1200_60;
>>
>>> + break;
>>
>>> + default:
>>
>>> + return;
>>
>>> + }
>>
>>> +
>>
>>> + /*
>>
>>> + * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
>>
>>> + * CRE1[7:0]: MISC1 (default: 0x00)
>>
>>> + * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50)
>>
>>> + */
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, (u8)
>>> +~ASTDP_CLEAR_MASK,
>>
>>> + ASTDP_MISC0_24bpp);
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, (u8)
>>> +~ASTDP_CLEAR_MASK, ASTDP_MISC1);
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, (u8)
>>
>>> +~ASTDP_CLEAR_MASK, ModeIdx); }
>>
>>> diff --git a/drivers/gpu/drm/ast/ast_drv.h
>>
>>> b/drivers/gpu/drm/ast/ast_drv.h index a19315b2f..ff1ae314b 100644
>>
>>> --- a/drivers/gpu/drm/ast/ast_drv.h
>>
>>> +++ b/drivers/gpu/drm/ast/ast_drv.h
>>
>>> @@ -70,6 +70,7 @@ enum ast_tx_chip {
>>
>>> AST_TX_NONE,
>>
>>> AST_TX_SIL164,
>>
>>> AST_TX_DP501,
>>
>>> + AST_TX_ASTDP,
>>
>>> };
>>
>>>
>>
>>> #define AST_DRAM_512Mx16 0
>>
>>> @@ -184,6 +185,10 @@ struct ast_private {
>>
>>> struct drm_encoder encoder;
>>
>>> struct drm_connector connector;
>>
>>> } dp501;
>>
>>> + struct {
>>
>>> + struct drm_encoder encoder;
>>
>>> + struct drm_connector connector;
>>
>>> + } astdp;
>>
>>> } output;
>>
>>>
>>
>>> bool support_wide_screen;
>>
>>> @@ -357,10 +362,113 @@ int ast_mode_config_init(struct ast_private
>>> *ast);
>>
>>> #define AST_DP501_EDID_DATA 0xf020
>>
>>>
>>
>>> /* Define for Soc scratched reg */
>>
>>> +#define COPROCESSOR_LAUNCH BIT(5)
>>
>>> +
>>
>>> +/*
>>
>>> + * Display Transmitter Type:
>>
>>> + */
>>
>>> +#define TX_TYPE_MASK GENMASK(3, 1)
>>
>>> +#define NO_TX (0 << 1)
>>
>>> +#define ITE66121_VBIOS_TX (1 << 1)
>>
>>> +#define SI164_VBIOS_TX (2 << 1)
>>
>>> +#define CH7003_VBIOS_TX (3 << 1)
>>
>>> +#define DP501_VBIOS_TX (4 << 1)
>>
>>> +#define ANX9807_VBIOS_TX (5 << 1)
>>
>>> +#define TX_FW_EMBEDDED_FW_TX (6 << 1)
>>
>>> +#define ASTDP_DPMCU_TX (7 << 1)
>>
>>> +
>>
>>> #define AST_VRAM_INIT_STATUS_MASK GENMASK(7, 6)
>>
>>> //#define AST_VRAM_INIT_BY_BMC BIT(7)
>>
>>> //#define AST_VRAM_INIT_READY BIT(6)
>>
>>>
>>
>>> +/* Define for Soc scratched reg used on ASTDP */
>>
>>> +#define AST_DP_PHY_SLEEP BIT(4)
>>
>>> +#define AST_DP_VIDEO_ENABLE BIT(0)
>>
>>> +
>>
>>> +#define AST_DP_POWER_ON true
>>
>>> +#define AST_DP_POWER_OFF false
>>
>>> +
>>
>>> +/*
>>
>>> + * CRD1[b5]: DP MCU FW is executing
>>
>>> + * CRDC[b0]: DP link success
>>
>>> + * CRDF[b0]: DP HPD
>>
>>> + * CRE5[b0]: Host reading EDID process is done */
>>
>>> +#define ASTDP_MCU_FW_EXECUTING BIT(5)
>>
>>> +#define ASTDP_LINK_SUCCESS BIT(0)
>>
>>> +#define ASTDP_HPD BIT(0)
>>
>>> +#define ASTDP_HOST_EDID_READ_DONE BIT(0)
>>
>>> +#define ASTDP_HOST_EDID_READ_DONE_MASK GENMASK(0, 0)
>>
>>> +
>>
>>> +/*
>>
>>> + * CRB8[b1]: Enable VSYNC off
>>
>>> + * CRB8[b0]: Enable HSYNC off
>>
>>> + */
>>
>>> +#define AST_DPMS_VSYNC_OFF BIT(1)
>>
>>> +#define AST_DPMS_HSYNC_OFF BIT(0)
>>
>>> +
>>
>>> +/*
>>
>>> + * CRDF[b4]: Mirror of AST_DP_VIDEO_ENABLE
>>
>>> + * Precondition: A. ~AST_DP_PHY_SLEEP &&
>>
>>> + * B. DP_HPD &&
>>
>>> + * C. DP_LINK_SUCCESS
>>
>>> + */
>>
>>> +#define ASTDP_MIRROR_VIDEO_ENABLE BIT(4)
>>
>>> +
>>
>>> +#define ASTDP_EDID_READ_POINTER_MASK GENMASK(7, 0)
>>
>>> +#define ASTDP_EDID_VALID_FLAG_MASK GENMASK(0, 0)
>>
>>> +#define ASTDP_EDID_READ_DATA_MASK GENMASK(7, 0)
>>
>>> +
>>
>>> +/*
>>
>>> + * ASTDP setmode registers:
>>
>>> + * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
>>
>>> + * CRE1[7:0]: MISC1 (default: 0x00)
>>
>>> + * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50) */
>>
>>> +#define ASTDP_MISC0_24bpp BIT(5)
>>
>>> +#define ASTDP_MISC1 0
>>
>>> +#define ASTDP_CLEAR_MASK GENMASK(7, 0)
>>
>>> +
>>
>>> +/*
>>
>>> + * ASTDP resoultion table:
>>
>>> + * EX: ASTDP_A_B_C:
>>
>>> + * A: Resolution
>>
>>> + * B: Refresh Rate
>>
>>> + * C: Misc information, such as CVT, Reduce Blanked
>>
>>> + */
>>
>>> +#define ASTDP_640x480_60 0x00
>>
>>> +#define ASTDP_640x480_72 0x01
>>
>>> +#define ASTDP_640x480_75 0x02
>>
>>> +#define ASTDP_640x480_85 0x03
>>
>>> +#define ASTDP_800x600_56 0x04
>>
>>> +#define ASTDP_800x600_60 0x05
>>
>>> +#define ASTDP_800x600_72 0x06
>>
>>> +#define ASTDP_800x600_75 0x07
>>
>>> +#define ASTDP_800x600_85 0x08
>>
>>> +#define ASTDP_1024x768_60 0x09
>>
>>> +#define ASTDP_1024x768_70 0x0A
>>
>>> +#define ASTDP_1024x768_75 0x0B
>>
>>> +#define ASTDP_1024x768_85 0x0C
>>
>>> +#define ASTDP_1280x1024_60 0x0D
>>
>>> +#define ASTDP_1280x1024_75 0x0E
>>
>>> +#define ASTDP_1280x1024_85 0x0F
>>
>>> +#define ASTDP_1600x1200_60 0x10
>>
>>> +#define ASTDP_320x240_60 0x11
>>
>>> +#define ASTDP_400x300_60 0x12
>>
>>> +#define ASTDP_512x384_60 0x13
>>
>>> +#define ASTDP_1920x1200_60 0x14
>>
>>> +#define ASTDP_1920x1080_60 0x15
>>
>>> +#define ASTDP_1280x800_60 0x16
>>
>>> +#define ASTDP_1280x800_60_RB 0x17
>>
>>> +#define ASTDP_1440x900_60 0x18
>>
>>> +#define ASTDP_1440x900_60_RB 0x19
>>
>>> +#define ASTDP_1680x1050_60 0x1A
>>
>>> +#define ASTDP_1680x1050_60_RB 0x1B
>>
>>> +#define ASTDP_1600x900_60 0x1C
>>
>>> +#define ASTDP_1600x900_60_RB 0x1D
>>
>>> +#define ASTDP_1366x768_60 0x1E
>>
>>> +#define ASTDP_1152x864_75 0x1F
>>
>>> +
>>
>>> int ast_mm_init(struct ast_private *ast);
>>
>>>
>>
>>> /* ast post */
>>
>>> @@ -381,4 +489,11 @@ void ast_init_3rdtx(struct drm_device *dev);
>>
>>> /* ast_i2c.c */
>>
>>> struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
>>
>>>
>>
>>> +/* aspeed DP */
>>
>>> +int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); void
>>
>>> +ast_dp_launch(struct drm_device *dev, u8 bPower); void
>>
>>> +ast_dp_power_on_off(struct drm_device *dev, bool no); void
>>
>>> +ast_dp_set_on_off(struct drm_device *dev, bool no); void
>>
>>> +ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info
>>
>>> +*vbios_mode);
>>
>>> +
>>
>>> #endif
>>
>>> diff --git a/drivers/gpu/drm/ast/ast_main.c
>>
>>> b/drivers/gpu/drm/ast/ast_main.c index 22e9e2d3c..1113ee1cb 100644
>>
>>> --- a/drivers/gpu/drm/ast/ast_main.c
>>
>>> +++ b/drivers/gpu/drm/ast/ast_main.c
>>
>>> @@ -232,7 +232,7 @@ static int ast_detect_chip(struct drm_device
>>> *dev, bool *need_post)
>>
>>> ast->tx_chip_type = AST_TX_SIL164;
>>
>>> }
>>
>>>
>>
>>> - if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
>>
>>> + if ((ast->chip == AST2300) || (ast->chip == AST2400) ||
>>> +(ast->chip
>>
>>> +== AST2500)) {
>>
>>> /*
>>
>>> * On AST2300 and 2400, look the configuration
>>> set by the SoC in
>>
>>> * the SOC scratch register #1 bits 11:8
>>> (interestingly marked @@
>>
>>> -256,7 +256,8 @@ static int ast_detect_chip(struct drm_device *dev,
>>> bool *need_post)
>>
>>> case 0x0c:
>>
>>> ast->tx_chip_type = AST_TX_DP501;
>>
>>> }
>>
>>> - }
>>
>>> + } else if (ast->chip == AST2600)
>>
>>> + ast_dp_launch(&ast->base, 0);
>>
>>>
>>
>>> /* Print stuff for diagnostic purposes */
>>
>>> switch(ast->tx_chip_type) {
>>
>>> diff --git a/drivers/gpu/drm/ast/ast_mode.c
>>
>>> b/drivers/gpu/drm/ast/ast_mode.c index 45b56b39a..4728825b7 100644
>>
>>> --- a/drivers/gpu/drm/ast/ast_mode.c
>>
>>> +++ b/drivers/gpu/drm/ast/ast_mode.c
>>
>>> @@ -988,21 +988,41 @@ static int ast_cursor_plane_init(struct
>>> ast_private *ast)
>>
>>> static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
>>
>>> {
>>
>>> struct ast_private *ast = to_ast_private(crtc->dev);
>>
>>> + u8 ch = AST_DPMS_VSYNC_OFF | AST_DPMS_HSYNC_OFF;
>>
>>>
>>
>>> /* TODO: Maybe control display signal generation with
>>
>>> * Sync Enable (bit CR17.7).
>>
>>> */
>>
>>> switch (mode) {
>>
>>> case DRM_MODE_DPMS_ON:
>>
>>> - case DRM_MODE_DPMS_STANDBY:
>>
>>> - case DRM_MODE_DPMS_SUSPEND:
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01,
>>> +0xdf, 0);
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6,
>>> +0xfc, 0);
>>
>>> if (ast->tx_chip_type == AST_TX_DP501)
>>
>>> ast_set_dp501_video_output(crtc->dev,
>>> 1);
>>
>>> +
>>
>>> + if (ast->tx_chip_type == AST_TX_ASTDP) {
>>
>>> + ast_dp_power_on_off(crtc->dev, AST_DP_POWER_ON);
>>
>>> + ast_wait_for_vretrace(ast);
>>
>>> + ast_dp_set_on_off(crtc->dev, 1);
>>
>>> + }
>>
>>> +
>>
>>> + ast_crtc_load_lut(ast, crtc);
>>
>>> break;
>>
>>> + case DRM_MODE_DPMS_STANDBY:
>>
>>> + case DRM_MODE_DPMS_SUSPEND:
>>
>>> case DRM_MODE_DPMS_OFF:
>>
>>> + ch = mode;
>>
>>> if (ast->tx_chip_type == AST_TX_DP501)
>>
>>> ast_set_dp501_video_output(crtc->dev,
>>> 0);
>>
>>> break;
>>
>>> +
>>
>>> + if (ast->tx_chip_type == AST_TX_ASTDP) {
>>
>>> + ast_dp_set_on_off(crtc->dev, 0);
>>
>>> + ast_dp_power_on_off(crtc->dev,
>>> +AST_DP_POWER_OFF);
>>
>>> + }
>>
>>> +
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01,
>>> +0xdf, 0x20);
>>
>>> + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6,
>>> +0xfc, ch);
>>
>>> }
>>
>>> }
>>
>>>
>>
>>> @@ -1027,7 +1047,7 @@ ast_crtc_helper_mode_valid(struct drm_crtc
>>
>>> *crtc, const struct drm_display_mode
>>
>>>
>>
>>> if ((ast->chip == AST2100) || (ast->chip ==
>>> AST2200) ||
>>
>>> (ast->chip == AST2300) || (ast->chip ==
>>> AST2400) ||
>>
>>> - (ast->chip == AST2500)) {
>>
>>> + (ast->chip == AST2500) || (ast->chip == AST2600)) {
>>
>>> if ((mode->hdisplay == 1920) &&
>>> (mode->vdisplay == 1080))
>>
>>> return MODE_OK;
>>
>>>
>>
>>> @@ -1110,6 +1130,7 @@ ast_crtc_helper_atomic_flush(struct drm_crtc
>>> *crtc,
>>
>>> struct ast_private *ast = to_ast_private(crtc->dev);
>>
>>> struct ast_crtc_state *ast_crtc_state =
>>> to_ast_crtc_state(crtc_state);
>>
>>> struct ast_crtc_state *old_ast_crtc_state =
>>
>>> to_ast_crtc_state(old_crtc_state);
>>
>>> + struct ast_vbios_mode_info *vbios_mode_info =
>>
>>> +&ast_crtc_state->vbios_mode_info;
>>
>>>
>>
>>> /*
>>
>>> * The gamma LUT has to be reloaded after changing the
>>> primary @@
>>
>>> -1117,6 +1138,10 @@ ast_crtc_helper_atomic_flush(struct drm_crtc
>>> *crtc,
>>
>>> */
>>
>>> if (old_ast_crtc_state->format !=
>>> ast_crtc_state->format)
>>
>>> ast_crtc_load_lut(ast, crtc);
>>
>>> +
>>
>>> + //Set Aspeed Display-Port
>>
>>> + if (ast->tx_chip_type == AST_TX_ASTDP)
>>
>>> + ast_dp_set_mode(crtc, vbios_mode_info);
>>
>>> }
>>
>>>
>>
>>> static void
>>
>>> @@ -1527,6 +1552,93 @@ static int ast_dp501_output_init(struct
>>> ast_private *ast)
>>
>>> return 0;
>>
>>> }
>>
>>>
>>
>>> +/*
>>
>>> + * ASPEED Display-Port Connector
>>
>>> + */
>>
>>> +
>>
>>> +static int ast_astdp_connector_helper_get_modes(struct
>>> +drm_connector
>>
>>> +*connector) {
>>
>>> + void *edid;
>>
>>> +
>>
>>> + int succ;
>>
>>> + int count;
>>
>>> +
>>
>>> + edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
>>
>>> + if (!edid)
>>
>>> + goto err_drm_connector_update_edid_property;
>>
>>> +
>>
>>> + succ = ast_astdp_read_edid(connector->dev, edid);
>>
>>> + if (succ < 0)
>>
>>> + goto err_kfree;
>>
>>> +
>>
>>> + drm_connector_update_edid_property(connector, edid);
>>
>>> + count = drm_add_edid_modes(connector, edid);
>>
>>> + kfree(edid);
>>
>>> +
>>
>>> + return count;
>>
>>> +
>>
>>> +err_kfree:
>>
>>> + kfree(edid);
>>
>>> +err_drm_connector_update_edid_property:
>>
>>> + drm_connector_update_edid_property(connector, NULL);
>>
>>> + return 0;
>>
>>> +}
>>
>>> +
>>
>>> +static const struct drm_connector_helper_funcs
>>> +ast_astdp_connector_helper_funcs = {
>>
>>> + .get_modes = ast_astdp_connector_helper_get_modes,
>>
>>> +};
>>
>>> +
>>
>>> +static const struct drm_connector_funcs ast_astdp_connector_funcs =
>>> +{
>>
>>> + .reset = drm_atomic_helper_connector_reset,
>>
>>> + .fill_modes = drm_helper_probe_single_connector_modes,
>>
>>> + .destroy = drm_connector_cleanup,
>>
>>> + .atomic_duplicate_state =
>>> +drm_atomic_helper_connector_duplicate_state,
>>
>>> + .atomic_destroy_state =
>>> +drm_atomic_helper_connector_destroy_state,
>>
>>> +};
>>
>>> +
>>
>>> +static int ast_astdp_connector_init(struct drm_device *dev, struct
>>
>>> +drm_connector *connector) {
>>
>>> + int ret;
>>
>>> +
>>
>>> + ret = drm_connector_init(dev, connector,
>>> +&ast_astdp_connector_funcs,
>>
>>> + DRM_MODE_CONNECTOR_DisplayPort);
>>
>>> + if (ret)
>>
>>> + return ret;
>>
>>> +
>>
>>> + drm_connector_helper_add(connector,
>>
>>> +&ast_astdp_connector_helper_funcs);
>>
>>> +
>>
>>> + connector->interlace_allowed = 0;
>>
>>> + connector->doublescan_allowed = 0;
>>
>>> +
>>
>>> + connector->polled = DRM_CONNECTOR_POLL_CONNECT;
>>
>>> +
>>
>>> + return 0;
>>
>>> +}
>>
>>> +
>>
>>> +static int ast_astdp_output_init(struct ast_private *ast) {
>>
>>> + struct drm_device *dev = &ast->base;
>>
>>> + struct drm_crtc *crtc = &ast->crtc;
>>
>>> + struct drm_encoder *encoder = &ast->output.astdp.encoder;
>>
>>> + struct drm_connector *connector = &ast->output.astdp.connector;
>>
>>> + int ret;
>>
>>> +
>>
>>> + ret = drm_simple_encoder_init(dev, encoder,
>>> +DRM_MODE_ENCODER_TMDS);
>>
>>> + if (ret)
>>
>>> + return ret;
>>
>>> + encoder->possible_crtcs = drm_crtc_mask(crtc);
>>
>>> +
>>
>>> + ret = ast_astdp_connector_init(dev, connector);
>>
>>> + if (ret)
>>
>>> + return ret;
>>
>>> +
>>
>>> + ret = drm_connector_attach_encoder(connector, encoder);
>>
>>> + if (ret)
>>
>>> + return ret;
>>
>>> +
>>
>>> + return 0;
>>
>>> +}
>>
>>> +
>>
>>> /*
>>
>>> * Mode config
>>
>>> */
>>
>>> @@ -1563,7 +1675,8 @@ int ast_mode_config_init(struct ast_private
>>> *ast)
>>
>>> ast->chip == AST2200 ||
>>
>>> ast->chip == AST2300 ||
>>
>>> ast->chip == AST2400 ||
>>
>>> - ast->chip == AST2500) {
>>
>>> + ast->chip == AST2500 ||
>>
>>> + ast->chip == AST2600) {
>>
>>> dev->mode_config.max_width = 1920;
>>
>>> dev->mode_config.max_height = 2048;
>>
>>> } else {
>>
>>> @@ -1594,6 +1707,9 @@ int ast_mode_config_init(struct ast_private
>>> *ast)
>>
>>> case AST_TX_DP501:
>>
>>> ret = ast_dp501_output_init(ast);
>>
>>> break;
>>
>>> + case AST_TX_ASTDP:
>>
>>> + ret = ast_astdp_output_init(ast);
>>
>>> + break;
>>
>>> }
>>
>>> if (ret)
>>
>>> return ret;
>>
>>> diff --git a/drivers/gpu/drm/ast/ast_post.c
>>
>>> b/drivers/gpu/drm/ast/ast_post.c index b5d92f652..0aa9cf0fb 100644
>>
>>> --- a/drivers/gpu/drm/ast/ast_post.c
>>
>>> +++ b/drivers/gpu/drm/ast/ast_post.c
>>
>>> @@ -379,7 +379,9 @@ void ast_post_gpu(struct drm_device *dev)
>>
>>> ast_enable_mmio(dev);
>>
>>> ast_set_def_ext_reg(dev);
>>
>>>
>>
>>> - if (ast->config_mode == ast_use_p2a) {
>>
>>> + if (ast->chip == AST2600) {
>>
>>> + ast_dp_launch(dev, 1);
>>
>>> + } else if (ast->config_mode == ast_use_p2a) {
>>
>>> if (ast->chip == AST2500)
>>
>>> ast_post_chip_2500(dev);
>>
>>> else if (ast->chip == AST2300 || ast->chip ==
>>> AST2400)
>>
>>>
>>
>>> base-commit: c54b39a565227538c52ead2349eb17d54aadd6f7
>>
>>> --
>>
>>> 2.27.0
>>
>>>
>>
>> --
>>
>> Thomas Zimmermann
>>
>> Graphics Driver Developer
>>
>> SUSE Software Solutions Germany GmbH
>>
>> Maxfeldstr. 5, 90409 Nürnberg, Germany
>>
>> (HRB 36809, AG Nürnberg)
>>
>> Geschäftsführer: Ivo Totev
>>
>
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany (HRB 36809, AG Nürnberg)
> Geschäftsführer: Ivo Totev
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev
Powered by blists - more mailing lists