!252 [devel-6.6] drm/loongson: add loongson-bmc drm driver support.

Merge pull request !252 from Ming Wang/linux-6.6/devel
This commit is contained in:
chinaljp030 2024-11-04 08:39:25 +00:00 committed by Gitee
commit 41643eeac5
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
16 changed files with 6707 additions and 1 deletions

View File

@ -1471,7 +1471,7 @@ CONFIG_DRM_AMDGPU_USERPTR=y
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_VKMS=m
CONFIG_DRM_UDL=m
CONFIG_DRM_AST=y
CONFIG_DRM_AST_LOONGSON=y
CONFIG_DRM_MGAG200=m
CONFIG_DRM_QXL=m
CONFIG_DRM_VIRTIO_GPU=m

View File

@ -15,3 +15,4 @@ config DRM_LOONGSON
If "M" is selected, the module will be called loongson.
If in doubt, say "N".
source "drivers/gpu/drm/loongson/ast/Kconfig"

View File

@ -20,3 +20,4 @@ loongson-y += loongson_device.o \
loongson_module.o
obj-$(CONFIG_DRM_LOONGSON) += loongson.o
obj-$(CONFIG_DRM_AST_LOONGSON) += ast/

View File

@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_AST_LOONGSON
tristate "AST server chips for Loongson Platform"
depends on DRM && PCI && MMU && LOONGARCH
select DRM_KMS_HELPER
select DRM_VRAM_HELPER
select DRM_TTM
select DRM_TTM_HELPER
help
Say yes for experimental AST GPU driver. Do not enable
this driver without having a working -modesetting,
and a version of AST that knows to fail if KMS
is bound to the driver. These GPUs are commonly found
in server chipsets.

View File

@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# 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_dp.o
obj-$(CONFIG_DRM_AST_LOONGSON) := ast.o

View File

@ -0,0 +1,299 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2021, ASPEED Technology Inc.
// Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.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,
ASTDP_AND_CLEAR_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_types |= BIT(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);
}
}
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,
ASTDP_AND_CLEAR_MASK, ASTDP_MISC0_24bpp);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1,
ASTDP_AND_CLEAR_MASK, ASTDP_MISC1);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2,
ASTDP_AND_CLEAR_MASK, ModeIdx);
}

View File

@ -0,0 +1,429 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include "ast_drv.h"
MODULE_FIRMWARE("ast_dp501_fw.bin");
static void ast_release_firmware(void *data)
{
struct ast_private *ast = data;
release_firmware(ast->dp501_fw);
ast->dp501_fw = NULL;
}
static int ast_load_dp501_microcode(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
int ret;
ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev);
if (ret)
return ret;
return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast);
}
static void send_ack(struct ast_private *ast)
{
u8 sendack;
sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
sendack |= 0x80;
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
}
static void send_nack(struct ast_private *ast)
{
u8 sendack;
sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
sendack &= ~0x80;
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
}
static bool wait_ack(struct ast_private *ast)
{
u8 waitack;
u32 retry = 0;
do {
waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2,
0xff);
waitack &= 0x80;
udelay(100);
} while ((!waitack) && (retry++ < 1000));
if (retry < 1000)
return true;
else
return false;
}
static bool wait_nack(struct ast_private *ast)
{
u8 waitack;
u32 retry = 0;
do {
waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2,
0xff);
waitack &= 0x80;
udelay(100);
} while ((waitack) && (retry++ < 1000));
if (retry < 1000)
return true;
else
return false;
}
static void set_cmd_trigger(struct ast_private *ast)
{
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
}
static void clear_cmd_trigger(struct ast_private *ast)
{
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
}
static bool ast_write_cmd(struct drm_device *dev, u8 data)
{
struct ast_private *ast = to_ast_private(dev);
int retry = 0;
if (wait_nack(ast)) {
send_nack(ast);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
send_ack(ast);
set_cmd_trigger(ast);
do {
if (wait_ack(ast)) {
clear_cmd_trigger(ast);
send_nack(ast);
return true;
}
} while (retry++ < 100);
}
clear_cmd_trigger(ast);
send_nack(ast);
return false;
}
static bool ast_write_data(struct drm_device *dev, u8 data)
{
struct ast_private *ast = to_ast_private(dev);
if (wait_nack(ast)) {
send_nack(ast);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
send_ack(ast);
if (wait_ack(ast)) {
send_nack(ast);
return true;
}
}
send_nack(ast);
return false;
}
void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
{
ast_write_cmd(dev, 0x40);
ast_write_data(dev, mode);
/*
* msleep < 20ms can sleep for up to 20ms;
* see Documentation/timers/timers-howto.rst
*/
msleep(20);
}
static u32 get_fw_base(struct ast_private *ast)
{
return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
}
bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
{
struct ast_private *ast = to_ast_private(dev);
u32 i, data;
u32 boot_address;
if (ast->config_mode != ast_use_p2a)
return false;
data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
if (data) {
boot_address = get_fw_base(ast);
for (i = 0; i < size; i += 4)
*(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
return true;
}
return false;
}
static bool ast_launch_m68k(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
u32 i, data, len = 0;
u32 boot_address;
u8 *fw_addr = NULL;
u8 jreg;
if (ast->config_mode != ast_use_p2a)
return false;
data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
if (!data) {
if (ast->dp501_fw_addr) {
fw_addr = ast->dp501_fw_addr;
len = 32 * 1024;
} else {
if (!ast->dp501_fw && ast_load_dp501_microcode(dev) < 0)
return false;
fw_addr = (u8 *)ast->dp501_fw->data;
len = ast->dp501_fw->size;
}
/* Get BootAddress */
ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
data = ast_mindwm(ast, 0x1e6e0004);
switch (data & 0x03) {
case 0:
boot_address = 0x44000000;
break;
default:
case 1:
boot_address = 0x48000000;
break;
case 2:
boot_address = 0x50000000;
break;
case 3:
boot_address = 0x60000000;
break;
}
boot_address -= 0x200000; /* -2MB */
/* copy image to buffer */
for (i = 0; i < len; i += 4) {
data = *(u32 *)(fw_addr + i);
ast_moutdwm(ast, boot_address + i, data);
}
/* Init SCU */
ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
/* Launch FW */
ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
ast_moutdwm(ast, 0x1e6e2100, 1);
/* Update Scratch */
data = ast_mindwm(ast, 0x1e6e2040) &
0xfffff1ff; /* D[11:9] = 100b: UEFI handling */
data |= 0x800;
ast_moutdwm(ast, 0x1e6e2040, data);
jreg = ast_get_index_reg_mask(
ast, AST_IO_CRTC_PORT, 0x99,
0xfc); /* D[1:0]: Reserved Video Buffer */
jreg |= 0x02;
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
}
return true;
}
bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
{
struct ast_private *ast = to_ast_private(dev);
u32 i, boot_address, offset, data;
u32 *pEDIDidx;
if (ast->config_mode == ast_use_p2a) {
boot_address = get_fw_base(ast);
/* validate FW version */
offset = AST_DP501_GBL_VERSION;
data = ast_mindwm(ast, boot_address + offset);
if ((data & AST_DP501_FW_VERSION_MASK) !=
AST_DP501_FW_VERSION_1)
return false;
/* validate PnP Monitor */
offset = AST_DP501_PNPMONITOR;
data = ast_mindwm(ast, boot_address + offset);
if (!(data & AST_DP501_PNP_CONNECTED))
return false;
/* Read EDID */
offset = AST_DP501_EDID_DATA;
for (i = 0; i < 128; i += 4) {
data = ast_mindwm(ast, boot_address + offset + i);
pEDIDidx = (u32 *)(ediddata + i);
*pEDIDidx = data;
}
} else {
if (!ast->dp501_fw_buf)
return false;
/* dummy read */
offset = 0x0000;
data = readl(ast->dp501_fw_buf + offset);
/* validate FW version */
offset = AST_DP501_GBL_VERSION;
data = readl(ast->dp501_fw_buf + offset);
if ((data & AST_DP501_FW_VERSION_MASK) !=
AST_DP501_FW_VERSION_1)
return false;
/* validate PnP Monitor */
offset = AST_DP501_PNPMONITOR;
data = readl(ast->dp501_fw_buf + offset);
if (!(data & AST_DP501_PNP_CONNECTED))
return false;
/* Read EDID */
offset = AST_DP501_EDID_DATA;
for (i = 0; i < 128; i += 4) {
data = readl(ast->dp501_fw_buf + offset + i);
pEDIDidx = (u32 *)(ediddata + i);
*pEDIDidx = data;
}
}
return true;
}
static bool ast_init_dvo(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
u8 jreg;
u32 data;
ast_write32(ast, 0xf004, 0x1e6e0000);
ast_write32(ast, 0xf000, 0x1);
ast_write32(ast, 0x12000, 0x1688a8a8);
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
if (!(jreg & 0x80)) {
/* Init SCU DVO Settings */
data = ast_read32(ast, 0x12008);
/* delay phase */
data &= 0xfffff8ff;
data |= 0x00000500;
ast_write32(ast, 0x12008, data);
if (ast->chip == AST2300) {
data = ast_read32(ast, 0x12084);
/* multi-pins for DVO single-edge */
data |= 0xfffe0000;
ast_write32(ast, 0x12084, data);
data = ast_read32(ast, 0x12088);
/* multi-pins for DVO single-edge */
data |= 0x000fffff;
ast_write32(ast, 0x12088, data);
data = ast_read32(ast, 0x12090);
/* multi-pins for DVO single-edge */
data &= 0xffffffcf;
data |= 0x00000020;
ast_write32(ast, 0x12090, data);
} else { /* AST2400 */
data = ast_read32(ast, 0x12088);
/* multi-pins for DVO single-edge */
data |= 0x30000000;
ast_write32(ast, 0x12088, data);
data = ast_read32(ast, 0x1208c);
/* multi-pins for DVO single-edge */
data |= 0x000000cf;
ast_write32(ast, 0x1208c, data);
data = ast_read32(ast, 0x120a4);
/* multi-pins for DVO single-edge */
data |= 0xffff0000;
ast_write32(ast, 0x120a4, data);
data = ast_read32(ast, 0x120a8);
/* multi-pins for DVO single-edge */
data |= 0x0000000f;
ast_write32(ast, 0x120a8, data);
data = ast_read32(ast, 0x12094);
/* multi-pins for DVO single-edge */
data |= 0x00000002;
ast_write32(ast, 0x12094, data);
}
}
/* Force to DVO */
data = ast_read32(ast, 0x1202c);
data &= 0xfffbffff;
ast_write32(ast, 0x1202c, data);
/* Init VGA DVO Settings */
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
return true;
}
static void ast_init_analog(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
u32 data;
/*
* Set DAC source to VGA mode in SCU2C via the P2A
* bridge. First configure the P2U to target the SCU
* in case it isn't at this stage.
*/
ast_write32(ast, 0xf004, 0x1e6e0000);
ast_write32(ast, 0xf000, 0x1);
/* Then unlock the SCU with the magic password */
ast_write32(ast, 0x12000, 0x1688a8a8);
ast_write32(ast, 0x12000, 0x1688a8a8);
ast_write32(ast, 0x12000, 0x1688a8a8);
/* Finally, clear bits [17:16] of SCU2c */
data = ast_read32(ast, 0x1202c);
data &= 0xfffcffff;
ast_write32(ast, 0, data);
/* Disable DVO */
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
}
void ast_init_3rdtx(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
u8 jreg;
if (ast->chip == AST2300 || ast->chip == AST2400) {
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1,
0xff);
switch (jreg & 0x0e) {
case 0x04:
ast_init_dvo(dev);
break;
case 0x08:
ast_launch_m68k(dev);
break;
case 0x0c:
ast_init_dvo(dev);
break;
default:
if (ast->tx_chip_types & BIT(AST_TX_SIL164))
ast_init_dvo(dev);
else
ast_init_analog(dev);
}
}
}

View File

@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef AST_DRAM_TABLES_H
#define AST_DRAM_TABLES_H
/* DRAM timing tables */
struct ast_dramstruct {
u16 index;
u32 data;
};
static const struct ast_dramstruct ast2000_dram_table_data[] = {
{ 0x0108, 0x00000000 }, { 0x0120, 0x00004a21 }, { 0xFF00, 0x00000043 },
{ 0x0000, 0xFFFFFFFF }, { 0x0004, 0x00000089 }, { 0x0008, 0x22331353 },
{ 0x000C, 0x0d07000b }, { 0x0010, 0x11113333 }, { 0x0020, 0x00110350 },
{ 0x0028, 0x1e0828f0 }, { 0x0024, 0x00000001 }, { 0x001C, 0x00000000 },
{ 0x0014, 0x00000003 }, { 0xFF00, 0x00000043 }, { 0x0018, 0x00000131 },
{ 0x0014, 0x00000001 }, { 0xFF00, 0x00000043 }, { 0x0018, 0x00000031 },
{ 0x0014, 0x00000001 }, { 0xFF00, 0x00000043 }, { 0x0028, 0x1e0828f1 },
{ 0x0024, 0x00000003 }, { 0x002C, 0x1f0f28fb }, { 0x0030, 0xFFFFFE01 },
{ 0xFFFF, 0xFFFFFFFF }
};
static const struct ast_dramstruct ast1100_dram_table_data[] = {
{ 0x2000, 0x1688a8a8 }, { 0x2020, 0x000041f0 }, { 0xFF00, 0x00000043 },
{ 0x0000, 0xfc600309 }, { 0x006C, 0x00909090 }, { 0x0064, 0x00050000 },
{ 0x0004, 0x00000585 }, { 0x0008, 0x0011030f }, { 0x0010, 0x22201724 },
{ 0x0018, 0x1e29011a }, { 0x0020, 0x00c82222 }, { 0x0014, 0x01001523 },
{ 0x001C, 0x1024010d }, { 0x0024, 0x00cb2522 }, { 0x0038, 0xffffff82 },
{ 0x003C, 0x00000000 }, { 0x0040, 0x00000000 }, { 0x0044, 0x00000000 },
{ 0x0048, 0x00000000 }, { 0x004C, 0x00000000 }, { 0x0050, 0x00000000 },
{ 0x0054, 0x00000000 }, { 0x0058, 0x00000000 }, { 0x005C, 0x00000000 },
{ 0x0060, 0x032aa02a }, { 0x0064, 0x002d3000 }, { 0x0068, 0x00000000 },
{ 0x0070, 0x00000000 }, { 0x0074, 0x00000000 }, { 0x0078, 0x00000000 },
{ 0x007C, 0x00000000 }, { 0x0034, 0x00000001 }, { 0xFF00, 0x00000043 },
{ 0x002C, 0x00000732 }, { 0x0030, 0x00000040 }, { 0x0028, 0x00000005 },
{ 0x0028, 0x00000007 }, { 0x0028, 0x00000003 }, { 0x0028, 0x00000001 },
{ 0x000C, 0x00005a08 }, { 0x002C, 0x00000632 }, { 0x0028, 0x00000001 },
{ 0x0030, 0x000003c0 }, { 0x0028, 0x00000003 }, { 0x0030, 0x00000040 },
{ 0x0028, 0x00000003 }, { 0x000C, 0x00005a21 }, { 0x0034, 0x00007c03 },
{ 0x0120, 0x00004c41 }, { 0xffff, 0xffffffff },
};
static const struct ast_dramstruct ast2100_dram_table_data[] = {
{ 0x2000, 0x1688a8a8 }, { 0x2020, 0x00004120 }, { 0xFF00, 0x00000043 },
{ 0x0000, 0xfc600309 }, { 0x006C, 0x00909090 }, { 0x0064, 0x00070000 },
{ 0x0004, 0x00000489 }, { 0x0008, 0x0011030f }, { 0x0010, 0x32302926 },
{ 0x0018, 0x274c0122 }, { 0x0020, 0x00ce2222 }, { 0x0014, 0x01001523 },
{ 0x001C, 0x1024010d }, { 0x0024, 0x00cb2522 }, { 0x0038, 0xffffff82 },
{ 0x003C, 0x00000000 }, { 0x0040, 0x00000000 }, { 0x0044, 0x00000000 },
{ 0x0048, 0x00000000 }, { 0x004C, 0x00000000 }, { 0x0050, 0x00000000 },
{ 0x0054, 0x00000000 }, { 0x0058, 0x00000000 }, { 0x005C, 0x00000000 },
{ 0x0060, 0x0f2aa02a }, { 0x0064, 0x003f3005 }, { 0x0068, 0x02020202 },
{ 0x0070, 0x00000000 }, { 0x0074, 0x00000000 }, { 0x0078, 0x00000000 },
{ 0x007C, 0x00000000 }, { 0x0034, 0x00000001 }, { 0xFF00, 0x00000043 },
{ 0x002C, 0x00000942 }, { 0x0030, 0x00000040 }, { 0x0028, 0x00000005 },
{ 0x0028, 0x00000007 }, { 0x0028, 0x00000003 }, { 0x0028, 0x00000001 },
{ 0x000C, 0x00005a08 }, { 0x002C, 0x00000842 }, { 0x0028, 0x00000001 },
{ 0x0030, 0x000003c0 }, { 0x0028, 0x00000003 }, { 0x0030, 0x00000040 },
{ 0x0028, 0x00000003 }, { 0x000C, 0x00005a21 }, { 0x0034, 0x00007c03 },
{ 0x0120, 0x00005061 }, { 0xffff, 0xffffffff },
};
/*
* AST2500 DRAM settings modules
*/
#define REGTBL_NUM 17
#define REGIDX_010 0
#define REGIDX_014 1
#define REGIDX_018 2
#define REGIDX_020 3
#define REGIDX_024 4
#define REGIDX_02C 5
#define REGIDX_030 6
#define REGIDX_214 7
#define REGIDX_2E0 8
#define REGIDX_2E4 9
#define REGIDX_2E8 10
#define REGIDX_2EC 11
#define REGIDX_2F0 12
#define REGIDX_2F4 13
#define REGIDX_2F8 14
#define REGIDX_RFC 15
#define REGIDX_PLL 16
static const u32 ast2500_ddr3_1600_timing_table[REGTBL_NUM] = {
0x64604D38, /* 0x010 */
0x29690599, /* 0x014 */
0x00000300, /* 0x018 */
0x00000000, /* 0x020 */
0x00000000, /* 0x024 */
0x02181E70, /* 0x02C */
0x00000040, /* 0x030 */
0x00000024, /* 0x214 */
0x02001300, /* 0x2E0 */
0x0E0000A0, /* 0x2E4 */
0x000E001B, /* 0x2E8 */
0x35B8C105, /* 0x2EC */
0x08090408, /* 0x2F0 */
0x9B000800, /* 0x2F4 */
0x0E400A00, /* 0x2F8 */
0x9971452F, /* tRFC */
0x000071C1 /* PLL */
};
static const u32 ast2500_ddr4_1600_timing_table[REGTBL_NUM] = {
0x63604E37, /* 0x010 */
0xE97AFA99, /* 0x014 */
0x00019000, /* 0x018 */
0x08000000, /* 0x020 */
0x00000400, /* 0x024 */
0x00000410, /* 0x02C */
0x00000101, /* 0x030 */
0x00000024, /* 0x214 */
0x03002900, /* 0x2E0 */
0x0E0000A0, /* 0x2E4 */
0x000E001C, /* 0x2E8 */
0x35B8C106, /* 0x2EC */
0x08080607, /* 0x2F0 */
0x9B000900, /* 0x2F4 */
0x0E400A00, /* 0x2F8 */
0x99714545, /* tRFC */
0x000071C1 /* PLL */
};
#endif

View File

@ -0,0 +1,231 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors: Dave Airlie <airlied@redhat.com>
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_fbdev_generic.h>
#include "ast_drv.h"
static int ast_modeset = -1;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, ast_modeset, int, 0400);
/*
* DRM driver
*/
DEFINE_DRM_GEM_FOPS(ast_fops);
static const struct drm_driver ast_driver = { .driver_features = DRIVER_ATOMIC |
DRIVER_GEM |
DRIVER_MODESET,
.fops = &ast_fops,
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
DRM_GEM_VRAM_DRIVER };
/*
* PCI driver
*/
#define PCI_VENDOR_ASPEED 0x1a03
#define AST_VGA_DEVICE(id, info) \
{ .class = PCI_BASE_CLASS_DISPLAY << 16, \
.class_mask = 0xff0000, \
.vendor = PCI_VENDOR_ASPEED, \
.device = id, \
.subvendor = PCI_ANY_ID, \
.subdevice = PCI_ANY_ID, \
.driver_data = (unsigned long)info }
static const struct pci_device_id ast_pciidlist[] = {
AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
{ 0, 0, 0 },
};
MODULE_DEVICE_TABLE(pci, ast_pciidlist);
static int ast_remove_conflicting_framebuffers(struct pci_dev *pdev)
{
resource_size_t base, size;
base = pci_resource_start(pdev, 0);
size = pci_resource_len(pdev, 0);
return drm_aperture_remove_conflicting_framebuffers(base, size,
&ast_driver);
}
static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct ast_private *ast;
struct drm_device *dev;
int ret;
ret = ast_remove_conflicting_framebuffers(pdev);
if (ret)
return ret;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
ast = ast_device_create(&ast_driver, pdev, ent->driver_data);
if (IS_ERR(ast))
return PTR_ERR(ast);
dev = &ast->base;
ret = drm_dev_register(dev, ent->driver_data);
if (ret)
return ret;
drm_fbdev_generic_setup(dev, 32);
return 0;
}
static void ast_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_dev_unregister(dev);
drm_atomic_helper_shutdown(dev);
}
static int ast_drm_freeze(struct drm_device *dev)
{
int error;
error = drm_mode_config_helper_suspend(dev);
if (error)
return error;
pci_save_state(to_pci_dev(dev->dev));
return 0;
}
static int ast_drm_thaw(struct drm_device *dev)
{
ast_post_gpu(dev);
return drm_mode_config_helper_resume(dev);
}
static int ast_drm_resume(struct drm_device *dev)
{
if (pci_enable_device(to_pci_dev(dev->dev)))
return -EIO;
return ast_drm_thaw(dev);
}
static int ast_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
int error;
error = ast_drm_freeze(ddev);
if (error)
return error;
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int ast_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
return ast_drm_resume(ddev);
}
static int ast_pm_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
return ast_drm_freeze(ddev);
}
static int ast_pm_thaw(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
return ast_drm_thaw(ddev);
}
static int ast_pm_poweroff(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *ddev = pci_get_drvdata(pdev);
return ast_drm_freeze(ddev);
}
static const struct dev_pm_ops ast_pm_ops = {
.suspend = ast_pm_suspend,
.resume = ast_pm_resume,
.freeze = ast_pm_freeze,
.thaw = ast_pm_thaw,
.poweroff = ast_pm_poweroff,
.restore = ast_pm_resume,
};
static struct pci_driver ast_pci_driver = {
.name = DRIVER_NAME,
.id_table = ast_pciidlist,
.probe = ast_pci_probe,
.remove = ast_pci_remove,
.driver.pm = &ast_pm_ops,
};
drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");

View File

@ -0,0 +1,528 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors: Dave Airlie <airlied@redhat.com>
*/
#ifndef __AST_DRV_H__
#define __AST_DRV_H__
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/io.h>
#include <linux/types.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_mode.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_fb_helper.h>
#define DRIVER_AUTHOR "Dave Airlie"
#define DRIVER_NAME "ast"
#define DRIVER_DESC "AST"
#define DRIVER_DATE "20120228"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0
#define PCI_CHIP_AST2000 0x2000
#define PCI_CHIP_AST2100 0x2010
enum ast_chip {
AST2000,
AST2100,
AST1100,
AST2200,
AST2150,
AST2300,
AST2400,
AST2500,
AST2600,
};
enum ast_tx_chip {
AST_TX_NONE,
AST_TX_SIL164,
AST_TX_DP501,
AST_TX_ASTDP,
};
#define AST_TX_NONE_BIT BIT(AST_TX_NONE)
#define AST_TX_SIL164_BIT BIT(AST_TX_SIL164)
#define AST_TX_DP501_BIT BIT(AST_TX_DP501)
#define AST_TX_ASTDP_BIT BIT(AST_TX_ASTDP)
#define AST_DRAM_512Mx16 0
#define AST_DRAM_1Gx16 1
#define AST_DRAM_512Mx32 2
#define AST_DRAM_1Gx32 3
#define AST_DRAM_2Gx16 6
#define AST_DRAM_4Gx16 7
#define AST_DRAM_8Gx16 8
/*
* Hardware cursor
*/
#define AST_MAX_HWC_WIDTH 64
#define AST_MAX_HWC_HEIGHT 64
#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2)
#define AST_HWC_SIGNATURE_SIZE 32
/* define for signature structure */
#define AST_HWC_SIGNATURE_CHECKSUM 0x00
#define AST_HWC_SIGNATURE_SizeX 0x04
#define AST_HWC_SIGNATURE_SizeY 0x08
#define AST_HWC_SIGNATURE_X 0x0C
#define AST_HWC_SIGNATURE_Y 0x10
#define AST_HWC_SIGNATURE_HOTSPOTX 0x14
#define AST_HWC_SIGNATURE_HOTSPOTY 0x18
/*
* Planes
*/
struct ast_plane {
struct drm_plane base;
struct drm_gem_vram_object *gbo;
struct iosys_map map;
u64 off;
};
static inline struct ast_plane *to_ast_plane(struct drm_plane *plane)
{
return container_of(plane, struct ast_plane, base);
}
/*
* Connector with i2c channel
*/
struct ast_i2c_chan {
struct i2c_adapter adapter;
struct drm_device *dev;
struct i2c_algo_bit_data bit;
};
struct ast_vga_connector {
struct drm_connector base;
struct ast_i2c_chan *i2c;
};
static inline struct ast_vga_connector *
to_ast_vga_connector(struct drm_connector *connector)
{
return container_of(connector, struct ast_vga_connector, base);
}
struct ast_sil164_connector {
struct drm_connector base;
struct ast_i2c_chan *i2c;
};
static inline struct ast_sil164_connector *
to_ast_sil164_connector(struct drm_connector *connector)
{
return container_of(connector, struct ast_sil164_connector, base);
}
/*
* Device
*/
struct ast_private {
struct drm_device base;
struct mutex ioregs_lock; /* Protects access to I/O registers in ioregs */
void __iomem *regs;
void __iomem *ioregs;
void __iomem *dp501_fw_buf;
enum ast_chip chip;
bool vga2_clone;
uint32_t dram_bus_width;
uint32_t dram_type;
uint32_t mclk;
struct drm_plane primary_plane;
struct ast_plane cursor_plane;
struct drm_crtc crtc;
struct {
struct {
struct drm_encoder encoder;
struct ast_vga_connector vga_connector;
} vga;
struct {
struct drm_encoder encoder;
struct ast_sil164_connector sil164_connector;
} sil164;
struct {
struct drm_encoder encoder;
struct drm_connector connector;
} dp501;
struct {
struct drm_encoder encoder;
struct drm_connector connector;
} astdp;
} output;
bool support_wide_screen;
enum { ast_use_p2a, ast_use_dt, ast_use_defaults } config_mode;
unsigned long tx_chip_types; /* bitfield of enum ast_chip_type */
u8 *dp501_fw_addr;
const struct firmware *dp501_fw; /* dp501 fw */
};
static inline struct ast_private *to_ast_private(struct drm_device *dev)
{
return container_of(dev, struct ast_private, base);
}
struct ast_private *ast_device_create(const struct drm_driver *drv,
struct pci_dev *pdev,
unsigned long flags);
#define AST_IO_AR_PORT_WRITE (0x40)
#define AST_IO_MISC_PORT_WRITE (0x42)
#define AST_IO_VGA_ENABLE_PORT (0x43)
#define AST_IO_SEQ_PORT (0x44)
#define AST_IO_DAC_INDEX_READ (0x47)
#define AST_IO_DAC_INDEX_WRITE (0x48)
#define AST_IO_DAC_DATA (0x49)
#define AST_IO_GR_PORT (0x4E)
#define AST_IO_CRTC_PORT (0x54)
#define AST_IO_INPUT_STATUS1_READ (0x5A)
#define AST_IO_MISC_PORT_READ (0x4C)
#define AST_IO_MM_OFFSET (0x380)
#define AST_IO_VGAIR1_VREFRESH BIT(3)
#define AST_IO_VGACRCB_HWC_ENABLED BIT(1)
#define AST_IO_VGACRCB_HWC_16BPP \
BIT(0) /* set: ARGB4444, cleared: 2bpp palette */
static inline u8 ast_read8(struct ast_private *ast, u32 reg)
{
u8 val = 0;
val = ioread8(ast->regs + reg);
return val;
}
static inline u16 ast_read16(struct ast_private *ast, u32 reg)
{
u16 val = 0;
val = ioread16(ast->regs + reg);
return val;
}
static inline u32 ast_read32(struct ast_private *ast, u32 reg)
{
u32 val = 0;
val = ioread32(ast->regs + reg);
return val;
}
static inline u8 ast_io_read8(struct ast_private *ast, u32 reg)
{
u8 val = 0;
val = ioread8(ast->ioregs + reg);
return val;
}
static inline u16 ast_io_read16(struct ast_private *ast, u32 reg)
{
u16 val = 0;
val = ioread16(ast->ioregs + reg);
return val;
}
static inline u32 ast_io_read32(struct ast_private *ast, u32 reg)
{
u32 val = 0;
val = ioread32(ast->ioregs + reg);
return val;
}
#define __ast_write(x) \
static inline void ast_write##x(struct ast_private *ast, u32 reg, \
u##x val) \
{ \
iowrite##x(val, ast->regs + reg); \
}
__ast_write(8);
__ast_write(16);
__ast_write(32);
#define __ast_io_write(x) \
static inline void ast_io_write##x(struct ast_private *ast, u32 reg, \
u##x val) \
{ \
iowrite##x(val, ast->ioregs + reg); \
}
__ast_io_write(8);
__ast_io_write(16);
#undef __ast_io_write
static inline void ast_set_index_reg(struct ast_private *ast, uint32_t base,
uint8_t index, uint8_t val)
{
ast_io_write16(ast, base, ((u16)val << 8) | index);
}
void ast_set_index_reg_mask(struct ast_private *ast, uint32_t base,
uint8_t index, uint8_t mask, uint8_t val);
uint8_t ast_get_index_reg(struct ast_private *ast, uint32_t base,
uint8_t index);
uint8_t ast_get_index_reg_mask(struct ast_private *ast, uint32_t base,
uint8_t index, uint8_t mask);
static inline void ast_open_key(struct ast_private *ast)
{
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x80, 0xA8);
}
#define AST_VIDMEM_SIZE_8M 0x00800000
#define AST_VIDMEM_SIZE_16M 0x01000000
#define AST_VIDMEM_SIZE_32M 0x02000000
#define AST_VIDMEM_SIZE_64M 0x04000000
#define AST_VIDMEM_SIZE_128M 0x08000000
#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
struct ast_vbios_stdtable {
u8 misc;
u8 seq[4];
u8 crtc[25];
u8 ar[20];
u8 gr[9];
};
struct ast_vbios_enhtable {
u32 ht;
u32 hde;
u32 hfp;
u32 hsync;
u32 vt;
u32 vde;
u32 vfp;
u32 vsync;
u32 dclk_index;
u32 flags;
u32 refresh_rate;
u32 refresh_rate_index;
u32 mode_id;
};
struct ast_vbios_dclk_info {
u8 param1;
u8 param2;
u8 param3;
};
struct ast_vbios_mode_info {
const struct ast_vbios_stdtable *std_table;
const struct ast_vbios_enhtable *enh_table;
};
struct ast_crtc_state {
struct drm_crtc_state base;
/* Last known format of primary plane */
const struct drm_format_info *format;
struct ast_vbios_mode_info vbios_mode_info;
};
#define to_ast_crtc_state(state) \
container_of(state, struct ast_crtc_state, base)
int ast_mode_config_init(struct ast_private *ast);
#define AST_MM_ALIGN_SHIFT 4
#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1)
#define AST_DP501_FW_VERSION_MASK GENMASK(7, 4)
#define AST_DP501_FW_VERSION_1 BIT(4)
#define AST_DP501_PNP_CONNECTED BIT(1)
#define AST_DP501_DEFAULT_DCLK 65
#define AST_DP501_GBL_VERSION 0xf000
#define AST_DP501_PNPMONITOR 0xf010
#define AST_DP501_LINKRATE 0xf014
#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_AND_CLEAR_MASK 0x00
/*
* 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 */
void ast_enable_vga(struct drm_device *dev);
void ast_enable_mmio(struct drm_device *dev);
bool ast_is_vga_enabled(struct drm_device *dev);
void ast_post_gpu(struct drm_device *dev);
u32 ast_mindwm(struct ast_private *ast, u32 r);
void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
void ast_patch_ahb_2500(struct ast_private *ast);
/* ast dp501 */
void ast_set_dp501_video_output(struct drm_device *dev, u8 mode);
bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
u8 ast_get_dp501_max_clk(struct drm_device *dev);
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

View File

@ -0,0 +1,170 @@
// SPDX-License-Identifier: MIT
/*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*/
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "ast_drv.h"
static void ast_i2c_setsda(void *i2c_priv, int data)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1,
ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7,
0x04);
if (ujcrb7 == jtemp)
break;
}
}
static void ast_i2c_setscl(void *i2c_priv, int clock)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
int i;
u8 ujcrb7, jtemp;
for (i = 0; i < 0x10000; i++) {
ujcrb7 = ((clock & 0x01) ? 0 : 1);
ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4,
ujcrb7);
jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7,
0x01);
if (ujcrb7 == jtemp)
break;
}
}
static int ast_i2c_getsda(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) &
0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7,
0x20) >>
5) &
0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
0xb7, 0x20) >>
5) &
0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static int ast_i2c_getscl(void *i2c_priv)
{
struct ast_i2c_chan *i2c = i2c_priv;
struct ast_private *ast = to_ast_private(i2c->dev);
uint32_t val, val2, count, pass;
count = 0;
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) &
0x01;
do {
val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7,
0x10) >>
4) &
0x01;
if (val == val2) {
pass++;
} else {
pass = 0;
val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
0xb7, 0x10) >>
4) &
0x01;
}
} while ((pass < 5) && (count++ < 0x10000));
return val & 1 ? 1 : 0;
}
static void ast_i2c_release(struct drm_device *dev, void *res)
{
struct ast_i2c_chan *i2c = res;
i2c_del_adapter(&i2c->adapter);
kfree(i2c);
}
struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
{
struct ast_i2c_chan *i2c;
int ret;
i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
if (!i2c)
return NULL;
i2c->adapter.owner = THIS_MODULE;
i2c->adapter.class = I2C_CLASS_DDC;
i2c->adapter.dev.parent = dev->dev;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"AST i2c bit bus");
i2c->adapter.algo_data = &i2c->bit;
i2c->bit.udelay = 20;
i2c->bit.timeout = 2;
i2c->bit.data = i2c;
i2c->bit.setsda = ast_i2c_setsda;
i2c->bit.setscl = ast_i2c_setscl;
i2c->bit.getsda = ast_i2c_getsda;
i2c->bit.getscl = ast_i2c_getscl;
ret = i2c_bit_add_bus(&i2c->adapter);
if (ret) {
drm_err(dev, "Failed to register bit i2c\n");
goto out_kfree;
}
ret = drmm_add_action_or_reset(dev, ast_i2c_release, i2c);
if (ret)
return NULL;
return i2c;
out_kfree:
kfree(i2c);
return NULL;
}

View File

@ -0,0 +1,486 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors: Dave Airlie <airlied@redhat.com>
*/
#include <linux/pci.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_managed.h>
#include "ast_drv.h"
void ast_set_index_reg_mask(struct ast_private *ast, uint32_t base,
uint8_t index, uint8_t mask, uint8_t val)
{
u8 tmp;
ast_io_write8(ast, base, index);
tmp = (ast_io_read8(ast, base + 1) & mask) | val;
ast_set_index_reg(ast, base, index, tmp);
}
uint8_t ast_get_index_reg(struct ast_private *ast, uint32_t base, uint8_t index)
{
uint8_t ret;
ast_io_write8(ast, base, index);
ret = ast_io_read8(ast, base + 1);
return ret;
}
uint8_t ast_get_index_reg_mask(struct ast_private *ast, uint32_t base,
uint8_t index, uint8_t mask)
{
uint8_t ret;
ast_io_write8(ast, base, index);
ret = ast_io_read8(ast, base + 1) & mask;
return ret;
}
static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev)
{
struct device_node *np = dev->dev->of_node;
struct ast_private *ast = to_ast_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
uint32_t data, jregd0, jregd1;
/* Defaults */
ast->config_mode = ast_use_defaults;
*scu_rev = 0xffffffff;
/* Check if we have device-tree properties */
if (np &&
!of_property_read_u32(np, "aspeed,scu-revision-id", scu_rev)) {
/* We do, disable P2A access */
ast->config_mode = ast_use_dt;
drm_info(dev, "Using device-tree for configuration\n");
return;
}
/* Not all families have a P2A bridge */
if (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)) {
/* Patch AST2500 */
if (((pdev->revision & 0xF0) == 0x40) &&
((jregd0 & AST_VRAM_INIT_STATUS_MASK) == 0))
ast_patch_ahb_2500(ast);
/* Double check it's actually working */
data = ast_read32(ast, 0xf004);
if ((data != 0xFFFFFFFF) && (data != 0x00)) {
/* P2A works, grab silicon revision */
ast->config_mode = ast_use_p2a;
drm_info(dev, "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(dev, "P2A bridge disabled, using default configuration\n");
}
static int ast_detect_chip(struct drm_device *dev, bool *need_post)
{
struct ast_private *ast = to_ast_private(dev);
struct pci_dev *pdev = to_pci_dev(dev->dev);
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(dev,
"VGA not enabled on entry, requesting chip POST\n");
*need_post = true;
} else
*need_post = false;
/* Enable extended register access */
ast_open_key(ast);
ast_enable_mmio(dev);
/* Find out whether P2A works or whether to use device-tree */
ast_detect_config_mode(dev, &scu_rev);
/* Identify chipset */
if (pdev->revision >= 0x50) {
ast->chip = AST2600;
drm_info(dev, "AST 2600 detected\n");
} else if (pdev->revision >= 0x40) {
ast->chip = AST2500;
drm_info(dev, "AST 2500 detected\n");
} else if (pdev->revision >= 0x30) {
ast->chip = AST2400;
drm_info(dev, "AST 2400 detected\n");
} else if (pdev->revision >= 0x20) {
ast->chip = AST2300;
drm_info(dev, "AST 2300 detected\n");
} else if (pdev->revision >= 0x10) {
switch (scu_rev & 0x0300) {
case 0x0200:
ast->chip = AST1100;
drm_info(dev, "AST 1100 detected\n");
break;
case 0x0100:
ast->chip = AST2200;
drm_info(dev, "AST 2200 detected\n");
break;
case 0x0000:
ast->chip = AST2150;
drm_info(dev, "AST 2150 detected\n");
break;
default:
ast->chip = AST2100;
drm_info(dev, "AST 2100 detected\n");
break;
}
ast->vga2_clone = false;
} else {
ast->chip = AST2000;
drm_info(dev, "AST 2000 detected\n");
}
/* Check if we support wide screen */
switch (ast->chip) {
case AST2000:
ast->support_wide_screen = false;
break;
default:
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0,
0xff);
if (!(jreg & 0x80))
ast->support_wide_screen = true;
else if (jreg & 0x01)
ast->support_wide_screen = true;
else {
ast->support_wide_screen = false;
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;
if (ast->chip == AST2500 &&
scu_rev == 0x100) /* ast2510 */
ast->support_wide_screen = true;
if (ast->chip == AST2600) /* ast2600 */
ast->support_wide_screen = true;
}
break;
}
/* Check 3rd Tx option (digital output afaik) */
ast->tx_chip_types |= AST_TX_NONE_BIT;
/*
* VGACRA3 Enhanced Color Mode Register, check if DVO is already
* enabled, in that case, assume we have a SIL164 TMDS transmitter
*
* Don't make that assumption if we the chip wasn't enabled and
* is at power-on reset, otherwise we'll incorrectly "detect" a
* SIL164 when there is none.
*/
if (!*need_post) {
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3,
0xff);
if (jreg & 0x80)
ast->tx_chip_types = AST_TX_SIL164_BIT;
}
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
* as "reserved" in the spec)
*/
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1,
0xff);
switch (jreg) {
case 0x04:
ast->tx_chip_types = AST_TX_SIL164_BIT;
break;
case 0x08:
ast->dp501_fw_addr =
drmm_kzalloc(dev, 32 * 1024, GFP_KERNEL);
if (ast->dp501_fw_addr) {
/* backup firmware */
if (ast_backup_fw(dev, ast->dp501_fw_addr,
32 * 1024)) {
drmm_kfree(dev, ast->dp501_fw_addr);
ast->dp501_fw_addr = NULL;
}
}
fallthrough;
case 0x0c:
ast->tx_chip_types = AST_TX_DP501_BIT;
}
} else if (ast->chip == AST2600)
ast_dp_launch(&ast->base, 0);
/* Print stuff for diagnostic purposes */
if (ast->tx_chip_types & AST_TX_NONE_BIT)
drm_info(dev, "Using analog VGA\n");
if (ast->tx_chip_types & AST_TX_SIL164_BIT)
drm_info(dev, "Using Sil164 TMDS transmitter\n");
if (ast->tx_chip_types & AST_TX_DP501_BIT)
drm_info(dev, "Using DP501 DisplayPort transmitter\n");
return 0;
}
static int ast_get_dram_info(struct drm_device *dev)
{
struct device_node *np = dev->dev->of_node;
struct ast_private *ast = to_ast_private(dev);
uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap;
uint32_t denum, num, div, ref_pll, dsel;
switch (ast->config_mode) {
case ast_use_dt:
/*
* If some properties are missing, use reasonable
* defaults for AST2400
*/
if (of_property_read_u32(np, "aspeed,mcr-configuration",
&mcr_cfg))
mcr_cfg = 0x00000577;
if (of_property_read_u32(np, "aspeed,mcr-scu-mpll",
&mcr_scu_mpll))
mcr_scu_mpll = 0x000050C0;
if (of_property_read_u32(np, "aspeed,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;
if (ast->chip == AST2500)
ast->mclk = 800;
else
ast->mclk = 396;
return 0;
}
if (mcr_cfg & 0x40)
ast->dram_bus_width = 16;
else
ast->dram_bus_width = 32;
if (ast->chip == AST2500) {
switch (mcr_cfg & 0x03) {
case 0:
ast->dram_type = AST_DRAM_1Gx16;
break;
default:
case 1:
ast->dram_type = AST_DRAM_2Gx16;
break;
case 2:
ast->dram_type = AST_DRAM_4Gx16;
break;
case 3:
ast->dram_type = AST_DRAM_8Gx16;
break;
}
} else if (ast->chip == AST2300 || ast->chip == AST2400) {
switch (mcr_cfg & 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 (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;
}
/*
* Run this function as part of the HW device cleanup; not
* when the DRM device gets released.
*/
static void ast_device_release(void *data)
{
struct ast_private *ast = data;
/* enable standard VGA decode */
ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04);
}
struct ast_private *ast_device_create(const struct drm_driver *drv,
struct pci_dev *pdev, unsigned long flags)
{
struct drm_device *dev;
struct ast_private *ast;
bool need_post;
int ret = 0;
ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base);
if (IS_ERR(ast))
return ast;
dev = &ast->base;
pci_set_drvdata(pdev, dev);
ret = drmm_mutex_init(dev, &ast->ioregs_lock);
if (ret)
return ERR_PTR(ret);
ast->regs = pcim_iomap(pdev, 1, 0);
if (!ast->regs)
return ERR_PTR(-EIO);
/*
* If we don't have IO space at all, use MMIO now and
* assume the chip has MMIO enabled by default (rev 0x20
* and higher).
*/
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) {
drm_info(dev, "platform has no IO space, trying MMIO\n");
ast->ioregs = ast->regs + AST_IO_MM_OFFSET;
}
/* "map" IO regs if the above hasn't done so already */
if (!ast->ioregs) {
ast->ioregs = pcim_iomap(pdev, 2, 0);
if (!ast->ioregs)
return ERR_PTR(-EIO);
}
ast_detect_chip(dev, &need_post);
ret = ast_get_dram_info(dev);
if (ret)
return ERR_PTR(ret);
drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", ast->mclk,
ast->dram_type, ast->dram_bus_width);
if (need_post)
ast_post_gpu(dev);
ret = ast_mm_init(ast);
if (ret)
return ERR_PTR(ret);
/* map reserved buffer */
ast->dp501_fw_buf = NULL;
if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) {
ast->dp501_fw_buf =
pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0);
if (!ast->dp501_fw_buf)
drm_info(dev, "failed to map reserved buffer!\n");
}
ret = ast_mode_config_init(ast);
if (ret)
return ERR_PTR(ret);
ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast);
if (ret)
return ERR_PTR(ret);
return ast;
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/*
* Authors: Dave Airlie <airlied@redhat.com>
*/
#include <linux/pci.h>
#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "ast_drv.h"
static u32 ast_get_vram_size(struct ast_private *ast)
{
u8 jreg;
u32 vram_size;
ast_open_key(ast);
vram_size = AST_VIDMEM_DEFAULT_SIZE;
jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
switch (jreg & 3) {
case 0:
vram_size = AST_VIDMEM_SIZE_8M;
break;
case 1:
vram_size = AST_VIDMEM_SIZE_16M;
break;
case 2:
vram_size = AST_VIDMEM_SIZE_32M;
break;
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;
}
int ast_mm_init(struct ast_private *ast)
{
struct drm_device *dev = &ast->base;
struct pci_dev *pdev = to_pci_dev(dev->dev);
resource_size_t base, size;
u32 vram_size;
int ret;
base = pci_resource_start(pdev, 0);
size = pci_resource_len(pdev, 0);
/* Don't fail on errors, but performance might be reduced. */
devm_arch_io_reserve_memtype_wc(dev->dev, base, size);
devm_arch_phys_wc_add(dev->dev, base, size);
vram_size = ast_get_vram_size(ast);
ret = drmm_vram_helper_init(dev, base, vram_size);
if (ret) {
drm_err(dev, "Error initializing VRAM MM; %d\n", ret);
return ret;
}
return 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,342 @@
/*
* Copyright (c) 2005 ASPEED Technology Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the authors not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. The authors makes no representations
* about the suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*
* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* Ported from xf86-video-ast driver */
#ifndef AST_TABLES_H
#define AST_TABLES_H
/* Std. Table Index Definition */
#define TextModeIndex 0
#define EGAModeIndex 1
#define VGAModeIndex 2
#define HiCModeIndex 3
#define TrueCModeIndex 4
#define Charx8Dot 0x00000001
#define HalfDCLK 0x00000002
#define DoubleScanMode 0x00000004
#define LineCompareOff 0x00000008
#define HBorder 0x00000020
#define VBorder 0x00000010
#define WideScreenMode 0x00000100
#define NewModeInfo 0x00000200
#define NHSync 0x00000400
#define PHSync 0x00000800
#define NVSync 0x00001000
#define PVSync 0x00002000
#define SyncPP (PVSync | PHSync)
#define SyncPN (PVSync | NHSync)
#define SyncNP (NVSync | PHSync)
#define SyncNN (NVSync | NHSync)
#define AST2500PreCatchCRT 0x00004000
/* DCLK Index */
#define VCLK25_175 0x00
#define VCLK28_322 0x01
#define VCLK31_5 0x02
#define VCLK36 0x03
#define VCLK40 0x04
#define VCLK49_5 0x05
#define VCLK50 0x06
#define VCLK56_25 0x07
#define VCLK65 0x08
#define VCLK75 0x09
#define VCLK78_75 0x0A
#define VCLK94_5 0x0B
#define VCLK108 0x0C
#define VCLK135 0x0D
#define VCLK157_5 0x0E
#define VCLK162 0x0F
#define VCLK154 0x10
#define VCLK83_5 0x11
#define VCLK106_5 0x12
#define VCLK146_25 0x13
#define VCLK148_5 0x14
#define VCLK71 0x15
#define VCLK88_75 0x16
#define VCLK119 0x17
#define VCLK85_5 0x18
#define VCLK97_75 0x19
#define VCLK118_25 0x1A
static const struct ast_vbios_dclk_info dclk_table[] = {
{ 0x2C, 0xE7, 0x03 }, /* 00: VCLK25_175 */
{ 0x95, 0x62, 0x03 }, /* 01: VCLK28_322 */
{ 0x67, 0x63, 0x01 }, /* 02: VCLK31_5 */
{ 0x76, 0x63, 0x01 }, /* 03: VCLK36 */
{ 0xEE, 0x67, 0x01 }, /* 04: VCLK40 */
{ 0x82, 0x62, 0x01 }, /* 05: VCLK49_5 */
{ 0xC6, 0x64, 0x01 }, /* 06: VCLK50 */
{ 0x94, 0x62, 0x01 }, /* 07: VCLK56_25 */
{ 0x80, 0x64, 0x00 }, /* 08: VCLK65 */
{ 0x7B, 0x63, 0x00 }, /* 09: VCLK75 */
{ 0x67, 0x62, 0x00 }, /* 0A: VCLK78_75 */
{ 0x7C, 0x62, 0x00 }, /* 0B: VCLK94_5 */
{ 0x8E, 0x62, 0x00 }, /* 0C: VCLK108 */
{ 0x85, 0x24, 0x00 }, /* 0D: VCLK135 */
{ 0x67, 0x22, 0x00 }, /* 0E: VCLK157_5 */
{ 0x6A, 0x22, 0x00 }, /* 0F: VCLK162 */
{ 0x4d, 0x4c, 0x80 }, /* 10: VCLK154 */
{ 0x68, 0x6f, 0x80 }, /* 11: VCLK83.5 */
{ 0x28, 0x49, 0x80 }, /* 12: VCLK106.5 */
{ 0x37, 0x49, 0x80 }, /* 13: VCLK146.25 */
{ 0x1f, 0x45, 0x80 }, /* 14: VCLK148.5 */
{ 0x47, 0x6c, 0x80 }, /* 15: VCLK71 */
{ 0x25, 0x65, 0x80 }, /* 16: VCLK88.75 */
{ 0x77, 0x58, 0x80 }, /* 17: VCLK119 */
{ 0x32, 0x67, 0x80 }, /* 18: VCLK85_5 */
{ 0x6a, 0x6d, 0x80 }, /* 19: VCLK97_75 */
{ 0x3b, 0x2c, 0x81 }, /* 1A: VCLK118_25 */
};
static const struct ast_vbios_dclk_info dclk_table_ast2500[] = {
{ 0x2C, 0xE7, 0x03 }, /* 00: VCLK25_175 */
{ 0x95, 0x62, 0x03 }, /* 01: VCLK28_322 */
{ 0x67, 0x63, 0x01 }, /* 02: VCLK31_5 */
{ 0x76, 0x63, 0x01 }, /* 03: VCLK36 */
{ 0xEE, 0x67, 0x01 }, /* 04: VCLK40 */
{ 0x82, 0x62, 0x01 }, /* 05: VCLK49_5 */
{ 0xC6, 0x64, 0x01 }, /* 06: VCLK50 */
{ 0x94, 0x62, 0x01 }, /* 07: VCLK56_25 */
{ 0x80, 0x64, 0x00 }, /* 08: VCLK65 */
{ 0x7B, 0x63, 0x00 }, /* 09: VCLK75 */
{ 0x67, 0x62, 0x00 }, /* 0A: VCLK78_75 */
{ 0x7C, 0x62, 0x00 }, /* 0B: VCLK94_5 */
{ 0x8E, 0x62, 0x00 }, /* 0C: VCLK108 */
{ 0x85, 0x24, 0x00 }, /* 0D: VCLK135 */
{ 0x67, 0x22, 0x00 }, /* 0E: VCLK157_5 */
{ 0x6A, 0x22, 0x00 }, /* 0F: VCLK162 */
{ 0x4d, 0x4c, 0x80 }, /* 10: VCLK154 */
{ 0x68, 0x6f, 0x80 }, /* 11: VCLK83.5 */
{ 0x28, 0x49, 0x80 }, /* 12: VCLK106.5 */
{ 0x37, 0x49, 0x80 }, /* 13: VCLK146.25 */
{ 0x1f, 0x45, 0x80 }, /* 14: VCLK148.5 */
{ 0x47, 0x6c, 0x80 }, /* 15: VCLK71 */
{ 0x25, 0x65, 0x80 }, /* 16: VCLK88.75 */
{ 0x58, 0x01, 0x42 }, /* 17: VCLK119 */
{ 0x32, 0x67, 0x80 }, /* 18: VCLK85_5 */
{ 0x6a, 0x6d, 0x80 }, /* 19: VCLK97_75 */
{ 0x44, 0x20, 0x43 }, /* 1A: VCLK118_25 */
};
static const struct ast_vbios_stdtable vbios_stdtable[] = {
/* MD_2_3_400 */
{ 0x67,
{ 0x00, 0x03, 0x00, 0x02 },
{ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00,
0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e,
0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, 0xff },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39,
0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff } },
/* Mode12/ExtEGATable */
{ 0xe3,
{ 0x01, 0x0f, 0x00, 0x06 },
{ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x8b,
0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39,
0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x01, 0x00, 0x0f, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } },
/* ExtVGATable */
{ 0x2f,
{ 0x01, 0x0f, 0x00, 0x0e },
{ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c,
0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff } },
/* ExtHiCTable */
{ 0x2f,
{ 0x01, 0x0f, 0x00, 0x0e },
{ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c,
0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } },
/* ExtTrueCTable */
{ 0x2f,
{ 0x01, 0x0f, 0x00, 0x0e },
{ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c,
0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } },
};
static const struct ast_vbios_enhtable res_640x480[] = {
{ 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175, /* 60Hz */
(SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E },
{ 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5, /* 72Hz */
(SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E },
{ 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5, /* 75Hz */
(SyncNN | Charx8Dot), 75, 3, 0x2E },
{ 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* 85Hz */
(SyncNN | Charx8Dot), 85, 4, 0x2E },
{ 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* end */
(SyncNN | Charx8Dot), 0xFF, 4, 0x2E },
};
static const struct ast_vbios_enhtable res_800x600[] = {
{ 1024, 800, 24, 72, 625, 600, 1, 2, VCLK36, /* 56Hz */
(SyncPP | Charx8Dot), 56, 1, 0x30 },
{ 1056, 800, 40, 128, 628, 600, 1, 4, VCLK40, /* 60Hz */
(SyncPP | Charx8Dot), 60, 2, 0x30 },
{ 1040, 800, 56, 120, 666, 600, 37, 6, VCLK50, /* 72Hz */
(SyncPP | Charx8Dot), 72, 3, 0x30 },
{ 1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5, /* 75Hz */
(SyncPP | Charx8Dot), 75, 4, 0x30 },
{ 1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* 85Hz */
(SyncPP | Charx8Dot), 84, 5, 0x30 },
{ 1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* end */
(SyncPP | Charx8Dot), 0xFF, 5, 0x30 },
};
static const struct ast_vbios_enhtable res_1024x768[] = {
{ 1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65, /* 60Hz */
(SyncNN | Charx8Dot), 60, 1, 0x31 },
{ 1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75, /* 70Hz */
(SyncNN | Charx8Dot), 70, 2, 0x31 },
{ 1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */
(SyncPP | Charx8Dot), 75, 3, 0x31 },
{ 1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* 85Hz */
(SyncPP | Charx8Dot), 84, 4, 0x31 },
{ 1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* end */
(SyncPP | Charx8Dot), 0xFF, 4, 0x31 },
};
static const struct ast_vbios_enhtable res_1280x1024[] = {
{ 1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108, /* 60Hz */
(SyncPP | Charx8Dot), 60, 1, 0x32 },
{ 1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135, /* 75Hz */
(SyncPP | Charx8Dot), 75, 2, 0x32 },
{ 1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* 85Hz */
(SyncPP | Charx8Dot), 85, 3, 0x32 },
{ 1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* end */
(SyncPP | Charx8Dot), 0xFF, 3, 0x32 },
};
static const struct ast_vbios_enhtable res_1600x1200[] = {
{ 2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* 60Hz */
(SyncPP | Charx8Dot), 60, 1, 0x33 },
{ 2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* end */
(SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
};
static const struct ast_vbios_enhtable res_1152x864[] = {
{ 1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* 75Hz */
(SyncPP | Charx8Dot | NewModeInfo), 75, 1, 0x3B },
{ 1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* end */
(SyncPP | Charx8Dot | NewModeInfo), 0xFF, 1, 0x3B },
};
/* 16:9 */
static const struct ast_vbios_enhtable res_1360x768[] = {
{ 1792, 1360, 64, 112, 795, 768, 3, 6, VCLK85_5, /* 60Hz */
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
60, 1, 0x39 },
{ 1792, 1360, 64, 112, 795, 768, 3, 6, VCLK85_5, /* end */
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
0xFF, 1, 0x39 },
};
static const struct ast_vbios_enhtable res_1600x900[] = {
{ 1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75, /* 60Hz CVT RB */
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x3A },
{ 2112, 1600, 88, 168, 934, 900, 3, 5, VCLK118_25, /* 60Hz CVT */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
60, 2, 0x3A },
{ 2112, 1600, 88, 168, 934, 900, 3, 5, VCLK118_25, /* 60Hz CVT */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
0xFF, 2, 0x3A },
};
static const struct ast_vbios_enhtable res_1920x1080[] = {
{ 2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x38 },
{ 2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
(SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
0xFF, 1, 0x38 },
};
/* 16:10 */
static const struct ast_vbios_enhtable res_1280x800[] = {
{ 1440, 1280, 48, 32, 823, 800, 3, 6, VCLK71, /* 60Hz RB */
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x35 },
{ 1680, 1280, 72, 128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
60, 2, 0x35 },
{ 1680, 1280, 72, 128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
0xFF, 2, 0x35 },
};
static const struct ast_vbios_enhtable res_1440x900[] = {
{ 1600, 1440, 48, 32, 926, 900, 3, 6, VCLK88_75, /* 60Hz RB */
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x36 },
{ 1904, 1440, 80, 152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
60, 2, 0x36 },
{ 1904, 1440, 80, 152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
0xFF, 2, 0x36 },
};
static const struct ast_vbios_enhtable res_1680x1050[] = {
{ 1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x37 },
{ 2240, 1680, 104, 176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
60, 2, 0x37 },
{ 2240, 1680, 104, 176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
(SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo),
0xFF, 2, 0x37 },
};
static const struct ast_vbios_enhtable res_1920x1200[] = {
{ 2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB*/
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
60, 1, 0x34 },
{ 2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB */
(SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo |
AST2500PreCatchCRT),
0xFF, 1, 0x34 },
};
#endif