!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:
commit
41643eeac5
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -20,3 +20,4 @@ loongson-y += loongson_device.o \
|
|||
loongson_module.o
|
||||
|
||||
obj-$(CONFIG_DRM_LOONGSON) += loongson.o
|
||||
obj-$(CONFIG_DRM_AST_LOONGSON) += ast/
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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");
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue