[PATCH] New radeonfb

Here is the new radeonfb. It doesn't remove the old one, just in case,
though CONFIG_FB_RADEON now builds the new one.

The new driver supports recent cards, has better monitor detection,
including DDC2, fixes a couple of constants in the old driver, and a lot
more.

I had to add an empty fb_set_suspend() function to fbmem.c (the real
implementation is in James tree and will be here soon).  That means that
Power Management on Apple laptops isn't completely right yet until the
core fbdev fixes get in, but it's good enough for now.
parent 6aa2b73c
......@@ -614,6 +614,16 @@ config FB_MATROX_MULTIHEAD
There is no need for enabling 'Matrox multihead support' if you have
only one Matrox card in the box.
config FB_RADEON_OLD
tristate "ATI Radeon display support (Old driver)"
depends on FB && PCI
help
Choose this option if you want to use an ATI Radeon graphics card as
a framebuffer device. There are both PCI and AGP versions. You
don't need to choose this to run the Radeon in plain VGA mode.
There is a product page at
<http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
config FB_RADEON
tristate "ATI Radeon display support"
depends on FB && PCI
......@@ -621,9 +631,24 @@ config FB_RADEON
Choose this option if you want to use an ATI Radeon graphics card as
a framebuffer device. There are both PCI and AGP versions. You
don't need to choose this to run the Radeon in plain VGA mode.
If you say Y here and want DDC/I2C support you must first say Y to
"I2C support" and "I2C bit-banging support" in the character devices
section.
If you say M here then "I2C support" and "I2C bit-banging support"
can be build either as modules or built-in.
There is a product page at
<http://www.ati.com/na/pages/products/pc/radeon32/index.html>.
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
depends on FB_RADEON && (I2C_ALGOBIT=FB_RADEON || I2C_ALGOBIT=y)
default y
help
Say Y here if you want DDC/I2C support for your Radeon board.
config FB_ATY128
tristate "ATI Rage128 display support"
depends on FB && PCI
......
......@@ -21,7 +21,7 @@ obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_ATARI) += atafb.o
obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_RADEON) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_IGA) += igafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......@@ -60,6 +60,7 @@ obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_ATY128) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_RADEON) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_I810) += i810/ cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
......
obj-$(CONFIG_FB_ATY) += atyfb.o
obj-$(CONFIG_FB_ATY128) += aty128fb.o
obj-$(CONFIG_FB_RADEON) += radeonfb.o
atyfb-y := atyfb_base.o mach64_accel.o
atyfb-$(CONFIG_FB_ATY_GX) += mach64_gx.o
atyfb-$(CONFIG_FB_ATY_CT) += mach64_ct.o mach64_cursor.o
atyfb-objs := $(atyfb-y)
radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
radeonfb-objs := $(radeonfb-y)
/*
* ATI PCI IDs from XFree86, kept here to make sync'ing with
* XFree much simpler. Currently, this list is only used by
* radeonfb
*/
#define PCI_CHIP_RS100_4136 0x4136
#define PCI_CHIP_RS200_4137 0x4137
#define PCI_CHIP_R300_AD 0x4144
#define PCI_CHIP_R300_AE 0x4145
#define PCI_CHIP_R300_AF 0x4146
#define PCI_CHIP_R300_AG 0x4147
#define PCI_CHIP_R350_AH 0x4148
#define PCI_CHIP_R350_AI 0x4149
#define PCI_CHIP_R350_AJ 0x414A
#define PCI_CHIP_R350_AK 0x414B
#define PCI_CHIP_RV350_AP 0x4150
#define PCI_CHIP_RV350_AQ 0x4151
#define PCI_CHIP_RV360_AR 0x4152
#define PCI_CHIP_RV350_AS 0x4153
#define PCI_CHIP_RV350_AT 0x4154
#define PCI_CHIP_RV350_AV 0x4156
#define PCI_CHIP_MACH32 0x4158
#define PCI_CHIP_RS250_4237 0x4237
#define PCI_CHIP_R200_BB 0x4242
#define PCI_CHIP_R200_BC 0x4243
#define PCI_CHIP_RS100_4336 0x4336
#define PCI_CHIP_RS200_4337 0x4337
#define PCI_CHIP_MACH64CT 0x4354
#define PCI_CHIP_MACH64CX 0x4358
#define PCI_CHIP_RS250_4437 0x4437
#define PCI_CHIP_MACH64ET 0x4554
#define PCI_CHIP_MACH64GB 0x4742
#define PCI_CHIP_MACH64GD 0x4744
#define PCI_CHIP_MACH64GI 0x4749
#define PCI_CHIP_MACH64GL 0x474C
#define PCI_CHIP_MACH64GM 0x474D
#define PCI_CHIP_MACH64GN 0x474E
#define PCI_CHIP_MACH64GO 0x474F
#define PCI_CHIP_MACH64GP 0x4750
#define PCI_CHIP_MACH64GQ 0x4751
#define PCI_CHIP_MACH64GR 0x4752
#define PCI_CHIP_MACH64GS 0x4753
#define PCI_CHIP_MACH64GT 0x4754
#define PCI_CHIP_MACH64GU 0x4755
#define PCI_CHIP_MACH64GV 0x4756
#define PCI_CHIP_MACH64GW 0x4757
#define PCI_CHIP_MACH64GX 0x4758
#define PCI_CHIP_MACH64GY 0x4759
#define PCI_CHIP_MACH64GZ 0x475A
#define PCI_CHIP_RV250_Id 0x4964
#define PCI_CHIP_RV250_Ie 0x4965
#define PCI_CHIP_RV250_If 0x4966
#define PCI_CHIP_RV250_Ig 0x4967
#define PCI_CHIP_MACH64LB 0x4C42
#define PCI_CHIP_MACH64LD 0x4C44
#define PCI_CHIP_RAGE128LE 0x4C45
#define PCI_CHIP_RAGE128LF 0x4C46
#define PCI_CHIP_MACH64LG 0x4C47
#define PCI_CHIP_MACH64LI 0x4C49
#define PCI_CHIP_MACH64LM 0x4C4D
#define PCI_CHIP_MACH64LN 0x4C4E
#define PCI_CHIP_MACH64LP 0x4C50
#define PCI_CHIP_MACH64LQ 0x4C51
#define PCI_CHIP_MACH64LR 0x4C52
#define PCI_CHIP_MACH64LS 0x4C53
#define PCI_CHIP_RADEON_LW 0x4C57
#define PCI_CHIP_RADEON_LX 0x4C58
#define PCI_CHIP_RADEON_LY 0x4C59
#define PCI_CHIP_RADEON_LZ 0x4C5A
#define PCI_CHIP_RV250_Ld 0x4C64
#define PCI_CHIP_RV250_Le 0x4C65
#define PCI_CHIP_RV250_Lf 0x4C66
#define PCI_CHIP_RV250_Lg 0x4C67
#define PCI_CHIP_RAGE128MF 0x4D46
#define PCI_CHIP_RAGE128ML 0x4D4C
#define PCI_CHIP_R300_ND 0x4E44
#define PCI_CHIP_R300_NE 0x4E45
#define PCI_CHIP_R300_NF 0x4E46
#define PCI_CHIP_R300_NG 0x4E47
#define PCI_CHIP_R350_NH 0x4E48
#define PCI_CHIP_R350_NI 0x4E49
#define PCI_CHIP_R360_NJ 0x4E4A
#define PCI_CHIP_R350_NK 0x4E4B
#define PCI_CHIP_RV350_NP 0x4E50
#define PCI_CHIP_RV350_NQ 0x4E51
#define PCI_CHIP_RV350_NR 0x4E52
#define PCI_CHIP_RV350_NS 0x4E53
#define PCI_CHIP_RV350_NT 0x4E54
#define PCI_CHIP_RV350_NV 0x4E56
#define PCI_CHIP_RAGE128PA 0x5041
#define PCI_CHIP_RAGE128PB 0x5042
#define PCI_CHIP_RAGE128PC 0x5043
#define PCI_CHIP_RAGE128PD 0x5044
#define PCI_CHIP_RAGE128PE 0x5045
#define PCI_CHIP_RAGE128PF 0x5046
#define PCI_CHIP_RAGE128PG 0x5047
#define PCI_CHIP_RAGE128PH 0x5048
#define PCI_CHIP_RAGE128PI 0x5049
#define PCI_CHIP_RAGE128PJ 0x504A
#define PCI_CHIP_RAGE128PK 0x504B
#define PCI_CHIP_RAGE128PL 0x504C
#define PCI_CHIP_RAGE128PM 0x504D
#define PCI_CHIP_RAGE128PN 0x504E
#define PCI_CHIP_RAGE128PO 0x504F
#define PCI_CHIP_RAGE128PP 0x5050
#define PCI_CHIP_RAGE128PQ 0x5051
#define PCI_CHIP_RAGE128PR 0x5052
#define PCI_CHIP_RAGE128PS 0x5053
#define PCI_CHIP_RAGE128PT 0x5054
#define PCI_CHIP_RAGE128PU 0x5055
#define PCI_CHIP_RAGE128PV 0x5056
#define PCI_CHIP_RAGE128PW 0x5057
#define PCI_CHIP_RAGE128PX 0x5058
#define PCI_CHIP_RADEON_QD 0x5144
#define PCI_CHIP_RADEON_QE 0x5145
#define PCI_CHIP_RADEON_QF 0x5146
#define PCI_CHIP_RADEON_QG 0x5147
#define PCI_CHIP_R200_QH 0x5148
#define PCI_CHIP_R200_QI 0x5149
#define PCI_CHIP_R200_QJ 0x514A
#define PCI_CHIP_R200_QK 0x514B
#define PCI_CHIP_R200_QL 0x514C
#define PCI_CHIP_R200_QM 0x514D
#define PCI_CHIP_R200_QN 0x514E
#define PCI_CHIP_R200_QO 0x514F
#define PCI_CHIP_RV200_QW 0x5157
#define PCI_CHIP_RV200_QX 0x5158
#define PCI_CHIP_RV100_QY 0x5159
#define PCI_CHIP_RV100_QZ 0x515A
#define PCI_CHIP_RAGE128RE 0x5245
#define PCI_CHIP_RAGE128RF 0x5246
#define PCI_CHIP_RAGE128RG 0x5247
#define PCI_CHIP_RAGE128RK 0x524B
#define PCI_CHIP_RAGE128RL 0x524C
#define PCI_CHIP_RAGE128SE 0x5345
#define PCI_CHIP_RAGE128SF 0x5346
#define PCI_CHIP_RAGE128SG 0x5347
#define PCI_CHIP_RAGE128SH 0x5348
#define PCI_CHIP_RAGE128SK 0x534B
#define PCI_CHIP_RAGE128SL 0x534C
#define PCI_CHIP_RAGE128SM 0x534D
#define PCI_CHIP_RAGE128SN 0x534E
#define PCI_CHIP_RAGE128TF 0x5446
#define PCI_CHIP_RAGE128TL 0x544C
#define PCI_CHIP_RAGE128TR 0x5452
#define PCI_CHIP_RAGE128TS 0x5453
#define PCI_CHIP_RAGE128TT 0x5454
#define PCI_CHIP_RAGE128TU 0x5455
#define PCI_CHIP_MACH64VT 0x5654
#define PCI_CHIP_MACH64VU 0x5655
#define PCI_CHIP_MACH64VV 0x5656
#define PCI_CHIP_RS300_5834 0x5834
#define PCI_CHIP_RS300_5835 0x5835
#define PCI_CHIP_RS300_5836 0x5836
#define PCI_CHIP_RS300_5837 0x5837
#define PCI_CHIP_RV280_5960 0x5960
#define PCI_CHIP_RV280_5961 0x5961
#define PCI_CHIP_RV280_5962 0x5962
#define PCI_CHIP_RV280_5963 0x5963
#define PCI_CHIP_RV280_5964 0x5964
#define PCI_CHIP_RV280_5968 0x5968
#define PCI_CHIP_RV280_5969 0x5969
#define PCI_CHIP_RV280_596A 0x596A
#define PCI_CHIP_RV280_596B 0x596B
#define PCI_CHIP_RV280_5C61 0x5C61
#define PCI_CHIP_RV280_5C63 0x5C63
#include "radeonfb.h"
/* the accelerated functions here are patterned after the
* "ACCEL_MMIO" ifdef branches in XFree86
* --dte
*/
static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo,
const struct fb_fillrect *region)
{
radeon_fifo_wait(4);
OUTREG(DP_GUI_MASTER_CNTL,
rinfo->dp_gui_master_cntl /* contains, like GMC_DST_32BPP */
| GMC_BRUSH_SOLID_COLOR
| ROP3_P);
OUTREG(DP_BRUSH_FRGD_CLR, region->color);
OUTREG(DP_WRITE_MSK, 0xffffffff);
OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
radeon_fifo_wait(2);
OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
}
void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
{
struct radeonfb_info *rinfo = info->par;
struct fb_fillrect modded;
int vxres, vyres;
if (rinfo->asleep)
return;
if (radeon_accel_disabled()) {
cfb_fillrect(info, region);
return;
}
vxres = info->var.xres;
vyres = info->var.yres;
memcpy(&modded, region, sizeof(struct fb_fillrect));
if(!modded.width || !modded.height ||
modded.dx >= vxres || modded.dy >= vyres)
return;
if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
radeonfb_prim_fillrect(rinfo, &modded);
}
static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo,
const struct fb_copyarea *area)
{
radeon_fifo_wait(3);
OUTREG(DP_GUI_MASTER_CNTL,
rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */
| GMC_SRC_DSTCOLOR
| ROP3_S
| DP_SRC_RECT );
OUTREG(DP_WRITE_MSK, 0xffffffff);
OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
radeon_fifo_wait(3);
OUTREG(SRC_Y_X, (area->sy << 16) | area->sx);
OUTREG(DST_Y_X, (area->dy << 16) | area->dx);
OUTREG(DST_HEIGHT_WIDTH, (area->height << 16) | area->width);
}
void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
struct radeonfb_info *rinfo = info->par;
struct fb_copyarea modded;
u32 vxres, vyres;
modded.sx = area->sx;
modded.sy = area->sy;
modded.dx = area->dx;
modded.dy = area->dy;
modded.width = area->width;
modded.height = area->height;
if (rinfo->asleep)
return;
if (radeon_accel_disabled()) {
cfb_copyarea(info, area);
return;
}
vxres = info->var.xres;
vyres = info->var.yres;
if(!modded.width || !modded.height ||
modded.sx >= vxres || modded.sy >= vyres ||
modded.dx >= vxres || modded.dy >= vyres)
return;
if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx;
if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
radeonfb_prim_copyarea(rinfo, &modded);
}
void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep)
return;
radeon_engine_idle();
cfb_imageblit(info, image);
}
int radeonfb_sync(struct fb_info *info)
{
struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep)
return 0;
radeon_engine_idle();
return 0;
}
void radeon_engine_reset(struct radeonfb_info *rinfo)
{
u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
u32 host_path_cntl;
radeon_engine_flush (rinfo);
/* Some ASICs have bugs with dynamic-on feature, which are
* ASIC-version dependent, so we force all blocks on for now
* -- from XFree86
* We don't do that on macs, things just work here with dynamic
* clocking... --BenH
*/
#ifdef CONFIG_ALL_PPC
if (_machine != _MACH_Pmac && rinfo->hasCRTC2)
#else
if (rinfo->has_CRTC2)
#endif
{
u32 tmp;
tmp = INPLL(SCLK_CNTL);
OUTPLL(SCLK_CNTL, ((tmp & ~DYN_STOP_LAT_MASK) |
CP_MAX_DYN_STOP_LAT |
SCLK_FORCEON_MASK));
if (rinfo->family == CHIP_FAMILY_RV200)
{
tmp = INPLL(SCLK_MORE_CNTL);
OUTPLL(SCLK_MORE_CNTL, tmp | SCLK_MORE_FORCEON);
}
}
clock_cntl_index = INREG(CLOCK_CNTL_INDEX);
mclk_cntl = INPLL(MCLK_CNTL);
OUTPLL(MCLK_CNTL, (mclk_cntl |
FORCEON_MCLKA |
FORCEON_MCLKB |
FORCEON_YCLKA |
FORCEON_YCLKB |
FORCEON_MC |
FORCEON_AIC));
host_path_cntl = INREG(HOST_PATH_CNTL);
rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
if (rinfo->family == CHIP_FAMILY_R300 ||
rinfo->family == CHIP_FAMILY_R350 ||
rinfo->family == CHIP_FAMILY_RV350) {
u32 tmp;
OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
SOFT_RESET_CP |
SOFT_RESET_HI |
SOFT_RESET_E2));
INREG(RBBM_SOFT_RESET);
OUTREG(RBBM_SOFT_RESET, 0);
tmp = INREG(RB2D_DSTCACHE_MODE);
OUTREG(RB2D_DSTCACHE_MODE, tmp | (1 << 17)); /* FIXME */
} else {
OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset |
SOFT_RESET_CP |
SOFT_RESET_HI |
SOFT_RESET_SE |
SOFT_RESET_RE |
SOFT_RESET_PP |
SOFT_RESET_E2 |
SOFT_RESET_RB);
INREG(RBBM_SOFT_RESET);
OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset & (u32)
~(SOFT_RESET_CP |
SOFT_RESET_HI |
SOFT_RESET_SE |
SOFT_RESET_RE |
SOFT_RESET_PP |
SOFT_RESET_E2 |
SOFT_RESET_RB));
INREG(RBBM_SOFT_RESET);
}
OUTREG(HOST_PATH_CNTL, host_path_cntl | HDP_SOFT_RESET);
INREG(HOST_PATH_CNTL);
OUTREG(HOST_PATH_CNTL, host_path_cntl);
if (rinfo->family != CHIP_FAMILY_R300 ||
rinfo->family != CHIP_FAMILY_R350 ||
rinfo->family != CHIP_FAMILY_RV350)
OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
OUTPLL(MCLK_CNTL, mclk_cntl);
if (rinfo->R300_cg_workaround)
R300_cg_workardound(rinfo);
}
void radeon_engine_init (struct radeonfb_info *rinfo)
{
unsigned long temp;
/* disable 3D engine */
OUTREG(RB3D_CNTL, 0);
radeon_engine_reset(rinfo);
radeon_fifo_wait (1);
if ((rinfo->family != CHIP_FAMILY_R300) &&
(rinfo->family != CHIP_FAMILY_R350) &&
(rinfo->family != CHIP_FAMILY_RV350))
OUTREG(RB2D_DSTCACHE_MODE, 0);
radeon_fifo_wait (3);
/* We re-read MC_FB_LOCATION from card as it can have been
* modified by XFree drivers (ouch !)
*/
rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
(rinfo->fb_local_base >> 10));
OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
radeon_fifo_wait (1);
#if defined(__BIG_ENDIAN)
OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
#else
OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
#endif
radeon_fifo_wait (2);
OUTREG(DEFAULT_SC_TOP_LEFT, 0);
OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
DEFAULT_SC_BOTTOM_MAX));
temp = radeon_get_dstbpp(rinfo->depth);
rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
radeon_fifo_wait (1);
OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
GMC_BRUSH_SOLID_COLOR |
GMC_SRC_DATATYPE_COLOR));
radeon_fifo_wait (7);
/* clear line drawing regs */
OUTREG(DST_LINE_START, 0);
OUTREG(DST_LINE_END, 0);
/* set brush color regs */
OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
/* set source color regs */
OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
/* default write mask */
OUTREG(DP_WRITE_MSK, 0xffffffff);
radeon_engine_idle ();
}
This diff is collapsed.
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>
#include <video/radeon.h>
#include "radeonfb.h"
#include "../edid.h"
#define RADEON_DDC 0x50
static void radeon_gpio_setscl(void* data, int state)
{
struct radeon_i2c_chan *chan = data;
struct radeonfb_info *rinfo = chan->rinfo;
u32 val;
val = INREG(chan->ddc_reg) & ~(VGA_DDC_CLK_OUT_EN);
if (!state)
val |= VGA_DDC_CLK_OUT_EN;
OUTREG(chan->ddc_reg, val);
(void)INREG(chan->ddc_reg);
}
static void radeon_gpio_setsda(void* data, int state)
{
struct radeon_i2c_chan *chan = data;
struct radeonfb_info *rinfo = chan->rinfo;
u32 val;
val = INREG(chan->ddc_reg) & ~(VGA_DDC_DATA_OUT_EN);
if (!state)
val |= VGA_DDC_DATA_OUT_EN;
OUTREG(chan->ddc_reg, val);
(void)INREG(chan->ddc_reg);
}
static int radeon_gpio_getscl(void* data)
{
struct radeon_i2c_chan *chan = data;
struct radeonfb_info *rinfo = chan->rinfo;
u32 val;
val = INREG(chan->ddc_reg);
return (val & VGA_DDC_CLK_INPUT) ? 1 : 0;
}
static int radeon_gpio_getsda(void* data)
{
struct radeon_i2c_chan *chan = data;
struct radeonfb_info *rinfo = chan->rinfo;
u32 val;
val = INREG(chan->ddc_reg);
return (val & VGA_DDC_DATA_INPUT) ? 1 : 0;
}
static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name)
{
int rc;
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
chan->adapter.id = I2C_ALGO_ATI;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->rinfo->pdev->dev;
chan->algo.setsda = radeon_gpio_setsda;
chan->algo.setscl = radeon_gpio_setscl;
chan->algo.getsda = radeon_gpio_getsda;
chan->algo.getscl = radeon_gpio_getscl;
chan->algo.udelay = 40;
chan->algo.timeout = 20;
chan->algo.data = chan;
i2c_set_adapdata(&chan->adapter, chan);
/* Raise SCL and SDA */
radeon_gpio_setsda(chan, 1);
radeon_gpio_setscl(chan, 1);
udelay(20);
rc = i2c_bit_add_bus(&chan->adapter);
if (rc == 0)
dev_dbg(&chan->rinfo->pdev->dev, "I2C bus %s registered.\n", name);
else
dev_warn(&chan->rinfo->pdev->dev, "Failed to register I2C bus %s.\n", name);
return rc;
}
void radeon_create_i2c_busses(struct radeonfb_info *rinfo)
{
rinfo->i2c[0].rinfo = rinfo;
rinfo->i2c[0].ddc_reg = GPIO_MONID;
radeon_setup_i2c_bus(&rinfo->i2c[0], "monid");
rinfo->i2c[1].rinfo = rinfo;
rinfo->i2c[1].ddc_reg = GPIO_DVI_DDC;
radeon_setup_i2c_bus(&rinfo->i2c[1], "dvi");
rinfo->i2c[2].rinfo = rinfo;
rinfo->i2c[2].ddc_reg = GPIO_VGA_DDC;
radeon_setup_i2c_bus(&rinfo->i2c[2], "vga");
rinfo->i2c[3].rinfo = rinfo;
rinfo->i2c[3].ddc_reg = GPIO_CRT2_DDC;
radeon_setup_i2c_bus(&rinfo->i2c[3], "crt2");
}
void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
{
if (rinfo->i2c[0].rinfo)
i2c_bit_del_bus(&rinfo->i2c[0].adapter);
rinfo->i2c[0].rinfo = NULL;
if (rinfo->i2c[1].rinfo)
i2c_bit_del_bus(&rinfo->i2c[1].adapter);
rinfo->i2c[1].rinfo = NULL;
if (rinfo->i2c[2].rinfo)
i2c_bit_del_bus(&rinfo->i2c[2].adapter);
rinfo->i2c[2].rinfo = NULL;
if (rinfo->i2c[3].rinfo)
i2c_bit_del_bus(&rinfo->i2c[3].adapter);
rinfo->i2c[3].rinfo = NULL;
}
static u8 *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan)
{
u8 start = 0x0;
struct i2c_msg msgs[] = {
{
.addr = RADEON_DDC,
.len = 1,
.buf = &start,
}, {
.addr = RADEON_DDC,
.flags = I2C_M_RD,
.len = EDID_LENGTH,
},
};
u8 *buf;
buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (!buf) {
dev_warn(&chan->rinfo->pdev->dev, "Out of memory!\n");
return NULL;
}
msgs[1].buf = buf;
if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
return buf;
dev_dbg(&chan->rinfo->pdev->dev, "Unable to read EDID block.\n");
kfree(buf);
return NULL;
}
int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid)
{
u32 reg = rinfo->i2c[conn-1].ddc_reg;
u8 *edid = NULL;
int i, j;
OUTREG(reg, INREG(reg) &
~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
(void)INREG(reg);
for (i = 0; i < 3; i++) {
/* For some old monitors we need the
* following process to initialize/stop DDC
*/
OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
(void)INREG(reg);
wait_ms(13);
OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
(void)INREG(reg);
for (j = 0; j < 5; j++) {
wait_ms(10);
if (INREG(reg) & VGA_DDC_CLK_INPUT)
break;
}
if (j == 5)
continue;
OUTREG(reg, INREG(reg) | VGA_DDC_DATA_OUT_EN);
(void)INREG(reg);
wait_ms(15);
OUTREG(reg, INREG(reg) | VGA_DDC_CLK_OUT_EN);
(void)INREG(reg);
wait_ms(15);
OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
(void)INREG(reg);
wait_ms(15);
/* Do the real work */
edid = radeon_do_probe_i2c_edid(&rinfo->i2c[conn-1]);
OUTREG(reg, INREG(reg) |
(VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
(void)INREG(reg);
wait_ms(15);
OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
(void)INREG(reg);
for (j = 0; j < 10; j++) {
wait_ms(10);
if (INREG(reg) & VGA_DDC_CLK_INPUT)
break;
}
OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
(void)INREG(reg);
wait_ms(15);
OUTREG(reg, INREG(reg) |
(VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
(void)INREG(reg);
if (edid)
break;
}
if (out_edid)
*out_edid = edid;
if (!edid) {
RTRACE("radeonfb: I2C (port %d) ... not found\n", conn);
return MT_NONE;
}
if (edid[0x14] & 0x80) {
if (rinfo->is_mobility && conn == ddc_dvi &&
(INREG(LVDS_GEN_CNTL) & LVDS_ON)) {
RTRACE("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
return MT_LCD;
} else {
RTRACE("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
return MT_DFP;
}
}
RTRACE("radeonfb: I2C (port %d) ... found CRT display\n", conn);
return MT_CRT;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1283,6 +1283,9 @@ unregister_framebuffer(struct fb_info *fb_info)
return 0;
}
void fb_set_suspend(struct fb_info *info, int state)
{
}
/**
* fbmem_init - init frame buffer subsystem
......@@ -1399,5 +1402,6 @@ EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned);
EXPORT_SYMBOL(fb_set_suspend);
MODULE_LICENSE("GPL");
......@@ -838,7 +838,7 @@ static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg)
if (radeon_read_OF(rinfo)) {
unsigned int tmp, Nx, M, ref_div, xclk;
tmp = INPLL(M_SPLL_REF_FB_DIV);
tmp = INPLL(X_MPLL_REF_FB_DIV);
ref_div = INPLL(PPLL_REF_DIV) & 0x3ff;
Nx = (tmp & 0xff00) >> 8;
......@@ -926,7 +926,7 @@ static void radeon_get_moninfo (struct radeonfb_info *rinfo)
return;
}
tmp = INREG(RADEON_BIOS_4_SCRATCH);
tmp = INREG(BIOS_4_SCRATCH);
printk(KERN_DEBUG "radeon_get_moninfo: bios 4 scratch = %x\n", tmp);
if (rinfo->hasCRTC2) {
......@@ -2076,7 +2076,7 @@ static int radeonfb_set_par (struct fb_info *info)
/* DFP */
newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN);
newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST |
ICHCSEL | TMDS_PLL_EN) &
TMDS_ICHCSEL | TMDS_PLL_EN) &
~(TMDS_PLLRST);
newmode.crtc_ext_cntl &= ~CRTC_CRT_ON;
}
......
......@@ -526,6 +526,7 @@ extern void move_buf_unaligned(struct fb_info *info, u8 * dst, u8 * src,
u32 idx);
extern void move_buf_aligned(struct fb_info *info, u8 * dst, u8 * src,
u32 d_pitch, u32 s_pitch, u32 height);
extern void fb_set_suspend(struct fb_info *info, int state);
extern struct fb_info *registered_fb[FB_MAX];
extern int num_registered_fb;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment