add missing files not taken with github import
This commit is contained in:
474
radeon/i2c-algo-bit.c
Normal file
474
radeon/i2c-algo-bit.c
Normal file
@@ -0,0 +1,474 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Copyright (C) 1995-2000 Simon G. Vogl
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Ky<4B>sti M<>lkki
|
||||
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
|
||||
|
||||
#include "wait.h"
|
||||
#include "i2c.h"
|
||||
#include "i2c-algo-bit.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
extern void start_timeout(void);
|
||||
extern int end_timeout(long msec);
|
||||
|
||||
/* --- setting states on the bus with the right timing: --------------- */
|
||||
|
||||
#define setsda(adap,val) adap->setsda(adap->data, val)
|
||||
#define setscl(adap,val) adap->setscl(adap->data, val)
|
||||
#define getsda(adap) adap->getsda(adap->data)
|
||||
#define getscl(adap) adap->getscl(adap->data)
|
||||
|
||||
static inline void sdalo(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setsda(adap,0);
|
||||
wait_us(adap->udelay);
|
||||
}
|
||||
|
||||
static inline void sdahi(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setsda(adap,1);
|
||||
wait_us(adap->udelay);
|
||||
}
|
||||
|
||||
static inline void scllo(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setscl(adap,0);
|
||||
wait_us(adap->udelay);
|
||||
}
|
||||
|
||||
/*
|
||||
* Raise scl line, and do checking for delays. This is necessary for slower
|
||||
* devices.
|
||||
*/
|
||||
static inline int sclhi(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
setscl(adap, 1);
|
||||
/* Not all adapters have scl sense line... */
|
||||
if(adap->getscl == NULL )
|
||||
{
|
||||
wait_us(adap->udelay);
|
||||
return 0;
|
||||
}
|
||||
start_timeout();
|
||||
while (! getscl(adap))
|
||||
{
|
||||
/* the hw knows how to read the clock line,
|
||||
* so we wait until it actually gets high.
|
||||
* This is safer as some chips may hold it low
|
||||
* while they are processing data internally.
|
||||
*/
|
||||
if (end_timeout((long)adap->timeout))
|
||||
return -110;
|
||||
}
|
||||
wait_us(adap->udelay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* --- other auxiliary functions -------------------------------------- */
|
||||
void i2c_start(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
/* assert: scl, sda are high */
|
||||
sdalo(adap);
|
||||
scllo(adap);
|
||||
}
|
||||
|
||||
static void i2c_repstart(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
/* scl, sda may not be high */
|
||||
setsda(adap, 1);
|
||||
sclhi(adap);
|
||||
wait_us(adap->udelay);
|
||||
sdalo(adap);
|
||||
scllo(adap);
|
||||
}
|
||||
|
||||
static void i2c_stop(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
/* assert: scl is low */
|
||||
sdalo(adap);
|
||||
sclhi(adap);
|
||||
sdahi(adap);
|
||||
}
|
||||
|
||||
/*
|
||||
* send a byte without start cond., look for arbitration,
|
||||
* check ackn. from slave
|
||||
*
|
||||
* returns:
|
||||
* 1 if the device acknowledged
|
||||
* 0 if the device did not ack
|
||||
* -ETIMEDOUT if an error occurred (while raising the scl line)
|
||||
*/
|
||||
static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
|
||||
{
|
||||
int i;
|
||||
int sb;
|
||||
int ack;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
/* assert: scl is low */
|
||||
|
||||
for (i = 7; i >= 0; i--)
|
||||
{
|
||||
sb = c & (1 << i);
|
||||
setsda(adap,sb);
|
||||
wait_us(adap->udelay);
|
||||
if (sclhi(adap) < 0)
|
||||
{
|
||||
/* timed out */
|
||||
sdahi(adap); /* we don't want to block the net */
|
||||
#ifdef DEBUG
|
||||
dbg("ETIMEDOUT\r\n");
|
||||
#endif
|
||||
return -110;
|
||||
};
|
||||
/* do arbitration here:
|
||||
* if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
|
||||
*/
|
||||
setscl(adap, 0 );
|
||||
wait_us(adap->udelay);
|
||||
}
|
||||
sdahi(adap);
|
||||
if(sclhi(adap)<0)
|
||||
{
|
||||
/* timeout */
|
||||
|
||||
dbg("ETIMEDOUT\r\n");
|
||||
|
||||
return -110;
|
||||
}
|
||||
/* read ack: SDA should be pulled down by slave */
|
||||
ack = getsda(adap); /* ack: sda is pulled low ->success. */
|
||||
scllo(adap);
|
||||
|
||||
dbg("0x%02x, ack=0x%02x\r\n", (unsigned long)(c & 0xff), ack);
|
||||
|
||||
return 0 == ack; /* return 1 if device acked */
|
||||
/* assert: scl is low (sda undef) */
|
||||
}
|
||||
|
||||
static int i2c_inb(struct i2c_adapter *i2c_adap)
|
||||
{
|
||||
/* read byte via i2c port, without start/stop sequence */
|
||||
/* acknowledge is sent in i2c_read. */
|
||||
int i;
|
||||
unsigned char indata = 0;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
/* assert: scl is low */
|
||||
sdahi(adap);
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
if (sclhi(adap) < 0)
|
||||
{
|
||||
/* timeout */
|
||||
dbg("i2c_inb TIMEDOUT\r\n");
|
||||
return -110;
|
||||
}
|
||||
indata *= 2;
|
||||
if (getsda(adap))
|
||||
indata |= 0x01;
|
||||
scllo(adap);
|
||||
}
|
||||
/* assert: scl is low */
|
||||
dbg("0x%02x\r\n", (unsigned long)(indata & 0xff));
|
||||
|
||||
return (int) (indata & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check for the adapter hardware - check the reaction of
|
||||
* the bus lines only if it seems to be idle.
|
||||
*/
|
||||
static int test_bus(struct i2c_algo_bit_data *adap)
|
||||
{
|
||||
int scl, sda;
|
||||
sda = getsda(adap);
|
||||
scl = (adap->getscl == NULL ? 1 : getscl(adap));
|
||||
if (!scl || !sda )
|
||||
goto bailout;
|
||||
sdalo(adap);
|
||||
sda = getsda(adap);
|
||||
scl = (adap->getscl == NULL ? 1 : getscl(adap));
|
||||
if (sda !=0 || scl == 0)
|
||||
goto bailout;
|
||||
sdahi(adap);
|
||||
sda = getsda(adap);
|
||||
scl = (adap->getscl == NULL ? 1 : getscl(adap));
|
||||
if (sda == 0 || scl ==0)
|
||||
goto bailout;
|
||||
scllo(adap);
|
||||
sda = getsda(adap);
|
||||
scl = (adap->getscl == NULL ? 0 : getscl(adap));
|
||||
if (scl !=0 || sda == 0)
|
||||
goto bailout;
|
||||
sclhi(adap);
|
||||
sda = getsda(adap);
|
||||
scl = (adap->getscl == NULL ? 1 : getscl(adap));
|
||||
if (scl == 0 || sda ==0)
|
||||
goto bailout;
|
||||
return 0;
|
||||
bailout:
|
||||
sdahi(adap);
|
||||
sclhi(adap);
|
||||
return -110;
|
||||
}
|
||||
|
||||
/* ----- Utility functions
|
||||
*/
|
||||
|
||||
/* try_address tries to contact a chip for a number of
|
||||
* times before it gives up.
|
||||
* return values:
|
||||
* 1 chip answered
|
||||
* 0 chip did not answer
|
||||
* -x transmission error
|
||||
*/
|
||||
static inline int try_address(struct i2c_adapter *i2c_adap,
|
||||
unsigned char addr, int retries)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
int i, ret = -1;
|
||||
for (i = 0; i <= retries; i++)
|
||||
{
|
||||
ret = i2c_outb(i2c_adap, addr);
|
||||
if (ret == 1)
|
||||
break; /* success! */
|
||||
i2c_stop(adap);
|
||||
wait_us(5);
|
||||
if (i == retries) /* no success */
|
||||
break;
|
||||
i2c_start(adap);
|
||||
wait_us(adap->udelay);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
char c;
|
||||
const char *temp = (const char *)msg->buf;
|
||||
int count = msg->len;
|
||||
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
|
||||
int retval;
|
||||
int wrcount=0;
|
||||
while(count > 0)
|
||||
{
|
||||
c = *temp;
|
||||
retval = i2c_outb(i2c_adap,c);
|
||||
if ((retval > 0) || (nak_ok && (retval==0)))
|
||||
{ /* ok or ignored NAK */
|
||||
count--;
|
||||
temp++;
|
||||
wrcount++;
|
||||
}
|
||||
else
|
||||
{ /* arbitration or no acknowledge */
|
||||
i2c_stop(adap);
|
||||
return (retval < 0)? retval : -110;
|
||||
/* got a better one ?? */
|
||||
}
|
||||
}
|
||||
return wrcount;
|
||||
}
|
||||
|
||||
static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
int inval;
|
||||
int rdcount=0; /* counts bytes read */
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
char *temp = (char *)msg->buf;
|
||||
int count = msg->len;
|
||||
while(count > 0)
|
||||
{
|
||||
inval = i2c_inb(i2c_adap);
|
||||
if (inval >= 0)
|
||||
{
|
||||
*temp = inval;
|
||||
rdcount++;
|
||||
}
|
||||
else
|
||||
/* read timed out */
|
||||
break;
|
||||
temp++;
|
||||
count--;
|
||||
if (msg->flags & I2C_M_NO_RD_ACK)
|
||||
continue;
|
||||
if (count > 0)
|
||||
/* send ack */
|
||||
sdalo(adap);
|
||||
else
|
||||
sdahi(adap); /* neg. ack on last byte */
|
||||
if (sclhi(adap) < 0)
|
||||
{
|
||||
/* timeout */
|
||||
sdahi(adap);
|
||||
return -1;
|
||||
};
|
||||
scllo(adap);
|
||||
sdahi(adap);
|
||||
}
|
||||
return rdcount;
|
||||
}
|
||||
|
||||
/* doAddress initiates the transfer by generating the start condition (in
|
||||
* try_address) and transmits the address in the necessary format to handle
|
||||
* reads, writes as well as 10bit-addresses.
|
||||
* returns:
|
||||
* 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
|
||||
* -x an error occurred (like: -EREMOTEIO if the device did not answer, or
|
||||
* -ETIMEDOUT, for example if the lines are stuck...)
|
||||
*/
|
||||
static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
unsigned short flags = msg->flags;
|
||||
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
unsigned char addr;
|
||||
int ret, retries;
|
||||
retries = nak_ok ? 0 : i2c_adap->retries;
|
||||
if (flags & I2C_M_TEN)
|
||||
{
|
||||
/* a ten bit address */
|
||||
addr = 0xf0 | (( msg->addr >> 7) & 0x03);
|
||||
/* try extended address code...*/
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret != 1) && !nak_ok)
|
||||
return -1;
|
||||
/* the remaining 8 bit address */
|
||||
ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
|
||||
if ((ret != 1) && !nak_ok)
|
||||
/* the chip did not ack / xmission error occurred */
|
||||
return -1;
|
||||
if (flags & I2C_M_RD)
|
||||
{
|
||||
i2c_repstart(adap);
|
||||
/* okay, now switch into reading mode */
|
||||
addr |= 0x01;
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret != 1) && !nak_ok)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* normal 7bit address */
|
||||
addr = (msg->addr << 1);
|
||||
if (flags & I2C_M_RD )
|
||||
addr |= 1;
|
||||
if (flags & I2C_M_REV_DIR_ADDR )
|
||||
addr ^= 1;
|
||||
ret = try_address(i2c_adap, addr, retries);
|
||||
if ((ret != 1) && !nak_ok)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct i2c_msg *pmsg;
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
int i,ret;
|
||||
unsigned short nak_ok;
|
||||
i2c_start(adap);
|
||||
for(i=0;i<num;i++)
|
||||
{
|
||||
pmsg = &msgs[i];
|
||||
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
|
||||
if(!(pmsg->flags & I2C_M_NOSTART))
|
||||
{
|
||||
if (i)
|
||||
i2c_repstart(adap);
|
||||
ret = bit_doAddress(i2c_adap, pmsg);
|
||||
if ((ret != 0) && !nak_ok)
|
||||
return (ret < 0) ? ret : -1;
|
||||
}
|
||||
if(pmsg->flags & I2C_M_RD )
|
||||
{
|
||||
/* read bytes into buffer*/
|
||||
ret = readbytes(i2c_adap, pmsg);
|
||||
if(ret < pmsg->len)
|
||||
return (ret < 0)? ret : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write bytes from buffer */
|
||||
ret = sendbytes(i2c_adap, pmsg);
|
||||
if (ret < pmsg->len )
|
||||
return (ret < 0) ? ret : -1;
|
||||
}
|
||||
}
|
||||
i2c_stop(adap);
|
||||
return num;
|
||||
}
|
||||
|
||||
/* -----exported algorithm data: ------------------------------------- */
|
||||
|
||||
static struct i2c_algorithm i2c_bit_algo = {
|
||||
.master_xfer = bit_xfer,
|
||||
};
|
||||
|
||||
/*
|
||||
* registering functions to load algorithms at runtime
|
||||
*/
|
||||
int i2c_bit_add_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
|
||||
if (1)
|
||||
{
|
||||
int ret = test_bus(bit_adap);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
}
|
||||
/* register new adapter to i2c module... */
|
||||
adap->algo = &i2c_bit_algo;
|
||||
adap->timeout = 10; /* default values, should */
|
||||
adap->retries = 3; /* be replaced by defines */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_bit_del_bus(struct i2c_adapter *adap)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------
|
||||
* the functional interface to the i2c busses.
|
||||
* ----------------------------------------------------
|
||||
*/
|
||||
|
||||
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
int ret;
|
||||
if (adap->algo->master_xfer)
|
||||
{
|
||||
ret = adap->algo->master_xfer(adap, msgs, num);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
1036
radeon/radeon_accel.c
Normal file
1036
radeon/radeon_accel.c
Normal file
File diff suppressed because it is too large
Load Diff
2457
radeon/radeon_base.c
Normal file
2457
radeon/radeon_base.c
Normal file
File diff suppressed because it is too large
Load Diff
335
radeon/radeon_cursor.c
Normal file
335
radeon/radeon_cursor.c
Normal file
@@ -0,0 +1,335 @@
|
||||
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_cursor.c,v 1.26 2003/11/10 18:41:22 tsi Exp $ */
|
||||
/*
|
||||
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
|
||||
* VA Linux Systems Inc., Fremont, California.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* 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 on the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, 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 above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* 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 ATI, VA LINUX SYSTEMS AND/OR
|
||||
* THEIR 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Kevin E. Martin <martin@xfree86.org>
|
||||
* Rickard E. Faith <faith@valinux.com>
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* !!!! FIXME !!!!
|
||||
* RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
|
||||
* Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
|
||||
* 1999.
|
||||
*
|
||||
* RAGE 128 Software Development Manual (Technical Reference Manual P/N
|
||||
* SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bas_types.h"
|
||||
#include "bas_printf.h"
|
||||
#include "radeonfb.h"
|
||||
|
||||
#define DBG_RADEON
|
||||
#ifdef DBG_RADEON
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_RADEON */
|
||||
|
||||
|
||||
#define CURSOR_WIDTH 64
|
||||
#define CURSOR_HEIGHT 64
|
||||
|
||||
/*
|
||||
* The cursor bits are always 32bpp. On MSBFirst buses,
|
||||
* configure byte swapping to swap 32 bit units when writing
|
||||
* the cursor image. Byte swapping must always be returned
|
||||
* to its previous value before returning.
|
||||
*/
|
||||
#define CURSOR_SWAPPING_DECL_MMIO
|
||||
#define CURSOR_SWAPPING_DECL unsigned long __surface_cntl=0;
|
||||
#define CURSOR_SWAPPING_START() \
|
||||
if (rinfo->big_endian) \
|
||||
OUTREG(SURFACE_CNTL, \
|
||||
((__surface_cntl = INREG(SURFACE_CNTL)) | \
|
||||
NONSURF_AP0_SWP_32BPP) & \
|
||||
~NONSURF_AP0_SWP_16BPP);
|
||||
#define CURSOR_SWAPPING_END() \
|
||||
if (rinfo->big_endian) \
|
||||
(OUTREG(SURFACE_CNTL, __surface_cntl));
|
||||
|
||||
/* Set cursor foreground and background colors */
|
||||
void radeon_set_cursor_colors(struct fb_info *info, int32_t bg, int32_t fg)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
unsigned long *pixels = (unsigned long *)((unsigned long) rinfo->fb_base + rinfo->cursor_start);
|
||||
int pixel, i;
|
||||
CURSOR_SWAPPING_DECL_MMIO
|
||||
CURSOR_SWAPPING_DECL
|
||||
// DPRINTVALHEX("radeonfb: RADEONSetCursorColors: cursor_start ",rinfo->cursor_start);
|
||||
// DPRINT("\r\n");
|
||||
fg |= 0xff000000;
|
||||
bg |= 0xff000000;
|
||||
/* Don't recolour the image if we don't have to. */
|
||||
if (fg == rinfo->cursor_fg && bg == rinfo->cursor_bg)
|
||||
return;
|
||||
CURSOR_SWAPPING_START();
|
||||
|
||||
/*
|
||||
* Note: We assume that the pixels are either fully opaque or fully
|
||||
* transparent, so we won't premultiply them, and we can just
|
||||
* check for non-zero pixel values; those are either fg or bg
|
||||
*/
|
||||
for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++)
|
||||
if ((pixel = *pixels))
|
||||
*pixels = (pixel == rinfo->cursor_fg) ? fg : bg;
|
||||
CURSOR_SWAPPING_END();
|
||||
rinfo->cursor_fg = fg;
|
||||
rinfo->cursor_bg = bg;
|
||||
}
|
||||
|
||||
/* Set cursor position to (x,y) with offset into cursor bitmap at
|
||||
* (xorigin,yorigin)
|
||||
*/
|
||||
void radeon_set_cursor_position(struct fb_info *info, int32_t x, int32_t y)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
struct fb_var_screeninfo *mode = &info->var;
|
||||
int xorigin = 0;
|
||||
int yorigin = 0;
|
||||
if (mode->vmode & FB_VMODE_DOUBLE)
|
||||
y <<= 1;
|
||||
if (x < 0)
|
||||
xorigin = 1 - x;
|
||||
if (y < 0)
|
||||
yorigin = 1 - y;
|
||||
|
||||
// DPRINTVALHEX("radeonfb: RADEONSetCursorPosition: cursor_start ",rinfo->cursor_start);
|
||||
// DPRINTVAL(" x ",x);
|
||||
// DPRINTVAL(" y ",y);
|
||||
// DPRINT("\r\n");
|
||||
|
||||
OUTREG(CUR_HORZ_VERT_OFF, (CUR_LOCK | (xorigin << 16) | yorigin));
|
||||
OUTREG(CUR_HORZ_VERT_POSN, (CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y)));
|
||||
OUTREG(CUR_OFFSET, rinfo->cursor_start + yorigin * 256);
|
||||
rinfo->cursor_x = (unsigned long)x;
|
||||
if (mode->vmode & FB_VMODE_DOUBLE)
|
||||
rinfo->cursor_y = (unsigned long) y >> 1;
|
||||
else
|
||||
rinfo->cursor_y = (unsigned long) y;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy cursor image from `image' to video memory. RADEONSetCursorPosition
|
||||
* will be called after this, so we can ignore xorigin and yorigin.
|
||||
*/
|
||||
void radeon_load_cursor_image(struct fb_info *info, unsigned short *mask, unsigned short *data, int32_t zoom)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
unsigned long *d = (unsigned long *)((unsigned long)rinfo->fb_base+rinfo->cursor_start);
|
||||
unsigned long save = 0;
|
||||
unsigned short chunk, mchunk;
|
||||
unsigned long i, j, k;
|
||||
CURSOR_SWAPPING_DECL
|
||||
|
||||
// DPRINTVALHEX("radeonfb: RADEONLoadCursorImage: cursor_start ",rinfo->cursor_start);
|
||||
// DPRINT("\r\n");
|
||||
|
||||
save = INREG(CRTC_GEN_CNTL) & ~(unsigned long) (3 << 20);
|
||||
save |= (unsigned long) (2 << 20);
|
||||
OUTREG(CRTC_GEN_CNTL, save & (unsigned long)~CRTC_CUR_EN);
|
||||
|
||||
/*
|
||||
* Convert the bitmap to ARGB32.
|
||||
*/
|
||||
CURSOR_SWAPPING_START();
|
||||
#define ARGB_PER_CHUNK (8 * sizeof (chunk))
|
||||
switch(zoom)
|
||||
{
|
||||
case 1:
|
||||
default:
|
||||
for (i = 0; i < CURSOR_HEIGHT; i++)
|
||||
{
|
||||
if (i < 16)
|
||||
{
|
||||
mchunk = *mask++;
|
||||
chunk = *data++;
|
||||
}
|
||||
else
|
||||
mchunk = chunk = 0;
|
||||
for (j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j++)
|
||||
{
|
||||
for (k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1)
|
||||
{
|
||||
if (mchunk & 0x8000)
|
||||
{
|
||||
if (chunk & 0x8000)
|
||||
*d++ = 0xff000000; /* Black, fully opaque. */
|
||||
else
|
||||
*d++ = 0xffffffff; /* White, fully opaque. */
|
||||
}
|
||||
else
|
||||
*d++ = 0x00000000; /* White/Black, fully transparent. */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (i = 0; i < CURSOR_HEIGHT; i++)
|
||||
{
|
||||
if (i < 16*2)
|
||||
{
|
||||
mchunk = *mask;
|
||||
chunk = *data;
|
||||
if ((i & 1) == 1)
|
||||
{
|
||||
mask++;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
else
|
||||
mchunk = chunk = 0;
|
||||
for (j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j+=2)
|
||||
{
|
||||
for (k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1)
|
||||
{
|
||||
if (mchunk & 0x8000)
|
||||
{
|
||||
if (chunk & 0x8000)
|
||||
{
|
||||
*d++ = 0xff000000; /* Black, fully opaque. */
|
||||
*d++ = 0xff000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
*d++ = 0xffffffff; /* White, fully opaque. */
|
||||
*d++ = 0xffffffff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*d++ = 0x00000000; /* White/Black, fully transparent. */
|
||||
*d++ = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (i = 0; i < CURSOR_HEIGHT; i++)
|
||||
{
|
||||
if (i < 16 * 4)
|
||||
{
|
||||
mchunk = *mask;
|
||||
chunk = *data;
|
||||
if ((i & 3) == 3)
|
||||
{
|
||||
mask++;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
else
|
||||
mchunk = chunk = 0;
|
||||
for (j = 0; j < CURSOR_WIDTH / ARGB_PER_CHUNK; j+=4)
|
||||
{
|
||||
for (k = 0; k < ARGB_PER_CHUNK; k++, chunk <<= 1, mchunk <<= 1)
|
||||
{
|
||||
if (mchunk & 0x8000)
|
||||
{
|
||||
if (chunk & 0x8000)
|
||||
{
|
||||
*d++ = 0xff000000; /* Black, fully opaque. */
|
||||
*d++ = 0xff000000;
|
||||
*d++ = 0xff000000;
|
||||
*d++ = 0xff000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
*d++ = 0xffffffff; /* White, fully opaque. */
|
||||
*d++ = 0xffffffff;
|
||||
*d++ = 0xffffffff;
|
||||
*d++ = 0xffffffff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*d++ = 0x00000000; /* White/Black, fully transparent. */
|
||||
*d++ = 0x00000000;
|
||||
*d++ = 0x00000000;
|
||||
*d++ = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CURSOR_SWAPPING_END();
|
||||
rinfo->cursor_bg = 0xffffffff; /* White, fully opaque. */
|
||||
rinfo->cursor_fg = 0xff000000; /* Black, fully opaque. */
|
||||
OUTREG(CRTC_GEN_CNTL, save);
|
||||
}
|
||||
|
||||
/* Hide hardware cursor. */
|
||||
void radeon_hide_cursor(struct fb_info *info)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
|
||||
// DPRINT("radeonfb: RADEONHideCursor\r\n");
|
||||
OUTREGP(CRTC_GEN_CNTL, 0, ~CRTC_CUR_EN);
|
||||
rinfo->cursor_show = 0;
|
||||
}
|
||||
|
||||
/* Show hardware cursor. */
|
||||
void radeon_show_cursor(struct fb_info *info)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
|
||||
// DPRINT("radeonfb: RADEONShowCursor\r\n");
|
||||
OUTREGP(CRTC_GEN_CNTL, CRTC_CUR_EN, ~CRTC_CUR_EN);
|
||||
rinfo->cursor_show = 1;
|
||||
}
|
||||
|
||||
/* Initialize hardware cursor support. */
|
||||
long radeon_cursor_init(struct fb_info *info)
|
||||
{
|
||||
struct radeonfb_info *rinfo = info->par;
|
||||
int size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
|
||||
unsigned long fbarea = offscreen_alloc(rinfo->info, size_bytes + 256);
|
||||
|
||||
dbg("radeonfb: %s: fbarea: %p\r\n", fbarea);
|
||||
|
||||
if (!fbarea)
|
||||
rinfo->cursor_start = 0;
|
||||
else
|
||||
{
|
||||
unsigned short data[16], mask[16];
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
memset(mask, 0, sizeof(data));
|
||||
rinfo->cursor_start = RADEON_ALIGN(fbarea - (unsigned long) rinfo->fb_base, 256);
|
||||
rinfo->cursor_end = rinfo->cursor_start + size_bytes;
|
||||
radeon_load_cursor_image(info, mask, data, 1);
|
||||
}
|
||||
dbg("radeonfb: %s cursor_start: %p\r\n", rinfo->cursor_start);
|
||||
|
||||
return (rinfo->cursor_start ? fbarea : 0);
|
||||
}
|
||||
237
radeon/radeon_i2c.c
Normal file
237
radeon/radeon_i2c.c
Normal file
@@ -0,0 +1,237 @@
|
||||
#include "video.h"
|
||||
#include "radeonfb.h"
|
||||
#include "edid.h"
|
||||
#include "i2c.h"
|
||||
#include "driver_mem.h"
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define CONFIG_FB_RADEON_I2C
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
|
||||
#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;
|
||||
unsigned long 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;
|
||||
unsigned long 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;
|
||||
unsigned long 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;
|
||||
unsigned long 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)
|
||||
{
|
||||
int rc;
|
||||
chan->adapter.algo_data = &chan->algo;
|
||||
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;
|
||||
/* Raise SCL and SDA */
|
||||
radeon_gpio_setsda(chan, 1);
|
||||
radeon_gpio_setscl(chan, 1);
|
||||
udelay(20);
|
||||
rc = i2c_bit_add_bus(&chan->adapter);
|
||||
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]);
|
||||
rinfo->i2c[1].rinfo = rinfo;
|
||||
rinfo->i2c[1].ddc_reg = GPIO_DVI_DDC;
|
||||
radeon_setup_i2c_bus(&rinfo->i2c[1]);
|
||||
rinfo->i2c[2].rinfo = rinfo;
|
||||
rinfo->i2c[2].ddc_reg = GPIO_VGA_DDC;
|
||||
radeon_setup_i2c_bus(&rinfo->i2c[2]);
|
||||
rinfo->i2c[3].rinfo = rinfo;
|
||||
rinfo->i2c[3].ddc_reg = GPIO_CRT2_DDC;
|
||||
radeon_setup_i2c_bus(&rinfo->i2c[3]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned char *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan)
|
||||
{
|
||||
unsigned char start = 0x0;
|
||||
struct i2c_msg msgs[] =
|
||||
{
|
||||
{
|
||||
.addr = RADEON_DDC,
|
||||
.len = 1,
|
||||
.buf = &start,
|
||||
},
|
||||
{
|
||||
.addr = RADEON_DDC,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EDID_LENGTH,
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char *buf;
|
||||
|
||||
buf = driver_mem_alloc(EDID_LENGTH * 3);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
msgs[1].buf = buf;
|
||||
if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
|
||||
return buf;
|
||||
else
|
||||
dbg("i2c_transfer() failed\r\n");
|
||||
|
||||
driver_mem_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int32_t conn, uint8_t **out_edid)
|
||||
{
|
||||
unsigned long reg = rinfo->i2c[conn - 1].ddc_reg;
|
||||
unsigned char *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;
|
||||
}
|
||||
/* Release the DDC lines when done or the Apple Cinema HD display
|
||||
* will switch off */
|
||||
OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN));
|
||||
(void) INREG(reg);
|
||||
|
||||
if (out_edid)
|
||||
*out_edid = edid;
|
||||
|
||||
if (!edid)
|
||||
return MT_NONE;
|
||||
|
||||
if (edid[0x14] & 0x80)
|
||||
{
|
||||
/* Fix detection using BIOS tables */
|
||||
if(rinfo->is_mobility /*&& conn == ddc_dvi*/ && (INREG(LVDS_GEN_CNTL) & LVDS_ON))
|
||||
return MT_LCD;
|
||||
else
|
||||
return MT_DFP;
|
||||
}
|
||||
return MT_CRT;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_FB_RADEON_I2C */
|
||||
748
radeon/radeon_monitor.c
Normal file
748
radeon/radeon_monitor.c
Normal file
@@ -0,0 +1,748 @@
|
||||
#include "radeonfb.h"
|
||||
#include "wait.h"
|
||||
#include "edid.h"
|
||||
#include "driver_mem.h"
|
||||
#include "bas_printf.h"
|
||||
#include "bas_string.h"
|
||||
#include "video.h"
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX ((int) (~0U >> 1))
|
||||
#endif
|
||||
|
||||
static struct fb_var_screeninfo radeonfb_default_var =
|
||||
{
|
||||
.xres = 640,
|
||||
.yres = 480,
|
||||
.xres_virtual = 640,
|
||||
.yres_virtual = 480,
|
||||
.bits_per_pixel = 8,
|
||||
.red = { .length = 8 },
|
||||
.green = { .length = 8 },
|
||||
.blue = { .length = 8 },
|
||||
.activate = FB_ACTIVATE_NOW,
|
||||
.height = -1,
|
||||
.width = -1,
|
||||
.pixclock = 9295,
|
||||
.left_margin = 40,
|
||||
.right_margin = 24,
|
||||
.upper_margin = 32,
|
||||
.lower_margin = 11,
|
||||
.hsync_len = 96,
|
||||
.vsync_len = 2,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
char *radeon_get_mon_name(int type)
|
||||
{
|
||||
char *pret = NULL;
|
||||
switch(type)
|
||||
{
|
||||
case MT_NONE:
|
||||
pret = "no";
|
||||
break;
|
||||
case MT_CRT:
|
||||
pret = "CRT";
|
||||
break;
|
||||
case MT_DFP:
|
||||
pret = "DFP";
|
||||
break;
|
||||
case MT_LCD:
|
||||
pret = "LCD";
|
||||
break;
|
||||
case MT_CTV:
|
||||
pret = "CTV";
|
||||
break;
|
||||
case MT_STV:
|
||||
pret = "STV";
|
||||
break;
|
||||
}
|
||||
return pret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe physical connection of a CRT. This code comes from XFree
|
||||
* as well and currently is only implemented for the CRT DAC, the
|
||||
* code for the TVDAC is commented out in XFree as "non working"
|
||||
*/
|
||||
static int radeon_crt_is_connected(struct radeonfb_info *rinfo, int is_crt_dac)
|
||||
{
|
||||
int connected = 0;
|
||||
/*
|
||||
* the monitor either wasn't connected or it is a non-DDC CRT.
|
||||
* try to probe it
|
||||
*/
|
||||
if (is_crt_dac)
|
||||
{
|
||||
unsigned long ulOrigVCLK_ECP_CNTL;
|
||||
unsigned long ulOrigDAC_CNTL;
|
||||
unsigned long ulOrigDAC_EXT_CNTL;
|
||||
unsigned long ulOrigCRTC_EXT_CNTL;
|
||||
unsigned long ulData;
|
||||
unsigned long ulMask;
|
||||
|
||||
ulOrigVCLK_ECP_CNTL = INPLL(VCLK_ECP_CNTL);
|
||||
ulData = ulOrigVCLK_ECP_CNTL;
|
||||
ulData &= ~(PIXCLK_ALWAYS_ONb | PIXCLK_DAC_ALWAYS_ONb);
|
||||
ulMask = ~(PIXCLK_ALWAYS_ONb | PIXCLK_DAC_ALWAYS_ONb);
|
||||
OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask);
|
||||
ulOrigCRTC_EXT_CNTL = INREG(CRTC_EXT_CNTL);
|
||||
ulData = ulOrigCRTC_EXT_CNTL;
|
||||
ulData |= CRTC_CRT_ON;
|
||||
OUTREG(CRTC_EXT_CNTL, ulData);
|
||||
ulOrigDAC_EXT_CNTL = INREG(DAC_EXT_CNTL);
|
||||
ulData = ulOrigDAC_EXT_CNTL;
|
||||
ulData &= ~DAC_FORCE_DATA_MASK;
|
||||
ulData |= (DAC_FORCE_BLANK_OFF_EN | DAC_FORCE_DATA_EN | DAC_FORCE_DATA_SEL_MASK);
|
||||
if ((rinfo->family == CHIP_FAMILY_RV250) || (rinfo->family == CHIP_FAMILY_RV280))
|
||||
ulData |= (0x01b6 << DAC_FORCE_DATA_SHIFT);
|
||||
else
|
||||
ulData |= (0x01ac << DAC_FORCE_DATA_SHIFT);
|
||||
OUTREG(DAC_EXT_CNTL, ulData);
|
||||
ulOrigDAC_CNTL = INREG(DAC_CNTL);
|
||||
ulData = ulOrigDAC_CNTL;
|
||||
ulData |= DAC_CMP_EN;
|
||||
ulData &= ~(DAC_RANGE_CNTL_MASK | DAC_PDWN);
|
||||
ulData |= 0x2;
|
||||
OUTREG(DAC_CNTL, ulData);
|
||||
wait_ms(1);
|
||||
ulData = INREG(DAC_CNTL);
|
||||
connected = (DAC_CMP_OUTPUT & ulData) ? 1 : 0;
|
||||
ulData = ulOrigVCLK_ECP_CNTL;
|
||||
ulMask = 0xFFFFFFFFL;
|
||||
OUTPLLP(VCLK_ECP_CNTL, ulData, ulMask);
|
||||
OUTREG(DAC_CNTL, ulOrigDAC_CNTL);
|
||||
OUTREG(DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL );
|
||||
OUTREG(CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL);
|
||||
}
|
||||
return connected ? MT_CRT : MT_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the "monitor_layout" string if any. This code is mostly
|
||||
* copied from XFree's radeon driver
|
||||
*/
|
||||
static int radeon_parse_monitor_layout(struct radeonfb_info *rinfo, const char *monitor_layout)
|
||||
{
|
||||
char s1[5], s2[5];
|
||||
int i = 0, second = 0;
|
||||
const char *s;
|
||||
|
||||
if ((monitor_layout == NULL) || (*monitor_layout == '\0'))
|
||||
{
|
||||
dbg("monitor_layout missing\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s = monitor_layout;
|
||||
do
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case ',':
|
||||
s1[i] = '\0';
|
||||
i = 0;
|
||||
second = 1;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\0':
|
||||
break;
|
||||
|
||||
default:
|
||||
if (i >= 4)
|
||||
break;
|
||||
if (second)
|
||||
s2[i] = *s;
|
||||
else
|
||||
s1[i] = *s;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
} while(*s++);
|
||||
|
||||
if (second)
|
||||
s2[i] = '\0';
|
||||
else
|
||||
{
|
||||
s1[i] = '\0';
|
||||
s2[0] = '\0';
|
||||
}
|
||||
|
||||
dbg("s1=%s, s2=%s \r\n", s1, s2);
|
||||
|
||||
if (!strcmp(s1, "CRT"))
|
||||
{
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
dbg("monitor 1 set to CRT\r\n");
|
||||
}
|
||||
else if (!strcmp(s1, "TMDS"))
|
||||
{
|
||||
rinfo->mon1_type = MT_DFP;
|
||||
dbg("monitor 1 set to TMDS\r\n");
|
||||
}
|
||||
else if (!strcmp(s1, "LVDS"))
|
||||
{
|
||||
rinfo->mon1_type = MT_LCD;
|
||||
dbg("monitor 1 set to LVDS\r\n");
|
||||
}
|
||||
|
||||
if (!strcmp(s2, "CRT"))
|
||||
{
|
||||
rinfo->mon2_type = MT_CRT;
|
||||
dbg("monitor 2 set to CRT\r\n");
|
||||
}
|
||||
else if (!strcmp(s2, "TMDS"))
|
||||
{
|
||||
rinfo->mon2_type = MT_DFP;
|
||||
dbg("monitor 2 set to TMDS\r\n");
|
||||
}
|
||||
else if (!strcmp(s2, "LVDS"))
|
||||
{
|
||||
rinfo->mon2_type = MT_LCD;
|
||||
dbg("monitor 2 set to LVDS\r\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe display on both primary and secondary card's connector (if any)
|
||||
* by i2c and try to retreive EDID. The algorithm here comes from XFree's * radeon driver
|
||||
*/
|
||||
void radeon_probe_screens(struct radeonfb_info *rinfo, const char *monitor_layout, int32_t ignore_edid)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
int ddc_crt2_used = 0;
|
||||
#endif
|
||||
|
||||
dbg("monitor_layout=%s\r\n", monitor_layout);
|
||||
if (radeon_parse_monitor_layout(rinfo, monitor_layout))
|
||||
{
|
||||
/*
|
||||
* If user specified a monitor_layout option, use it instead
|
||||
* of auto-detecting. Maybe we should only use this argument
|
||||
* on the first radeon card probed or provide a way to specify
|
||||
* a layout for each card ?
|
||||
*/
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
dbg("use monitor layout\r\n");
|
||||
if (!ignore_edid)
|
||||
{
|
||||
if (rinfo->mon1_type != MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_dvi on MON1\r\n");
|
||||
if (!radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID))
|
||||
{
|
||||
dbg("probe ddc_crt2 on MON1\r\n");
|
||||
radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID);
|
||||
ddc_crt2_used = 1;
|
||||
}
|
||||
}
|
||||
if (rinfo->mon2_type != MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_vga on MON2\r\n");
|
||||
if (!radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon2_EDID) && !ddc_crt2_used)
|
||||
{
|
||||
dbg("probe ddc_crt2 on MON2\r\n");
|
||||
radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon2_EDID);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_FB_RADEON_I2C */
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
if (rinfo->mon2_type != MT_NONE)
|
||||
{
|
||||
rinfo->mon1_type = rinfo->mon2_type;
|
||||
rinfo->mon1_EDID = rinfo->mon2_EDID;
|
||||
}
|
||||
else
|
||||
{
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
dbg("No valid monitor, assuming CRT on first port\r\n");
|
||||
}
|
||||
rinfo->mon2_type = MT_NONE;
|
||||
rinfo->mon2_EDID = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Auto-detecting display type (well... trying to ...)
|
||||
*/
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
dbg("Auto-detecting\r\n");
|
||||
#endif
|
||||
#if 0 //#if DEBUG && defined(CONFIG_FB_RADEON_I2C)
|
||||
{
|
||||
unsigned char *EDIDs[4] = { NULL, NULL, NULL, NULL };
|
||||
int mon_types[4] = {MT_NONE, MT_NONE, MT_NONE, MT_NONE};
|
||||
int i;
|
||||
for(i = 0; i < 4; i++)
|
||||
mon_types[i] = radeon_probe_i2c_connector(rinfo, i+1, &EDIDs[i]);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
/*
|
||||
* Old single head cards
|
||||
*/
|
||||
if (!rinfo->has_CRTC2)
|
||||
{
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_dvi on MON1\r\n");
|
||||
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID);
|
||||
}
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_vga on MON1\r\n");
|
||||
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon1_EDID);
|
||||
}
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_crt2 on MON1\r\n");
|
||||
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID);
|
||||
}
|
||||
#endif /* CONFIG_FB_RADEON_I2C */
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
goto bail;
|
||||
}
|
||||
/*
|
||||
* Probe primary head (DVI or laptop internal panel)
|
||||
*/
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_dvi on MON1\r\n");
|
||||
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi, &rinfo->mon1_EDID);
|
||||
}
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_crt2 on MON1\r\n");
|
||||
rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon1_EDID);
|
||||
if (rinfo->mon1_type != MT_NONE)
|
||||
ddc_crt2_used = 1;
|
||||
}
|
||||
#endif /* CONFIG_FB_RADEON_I2C */
|
||||
if (rinfo->mon1_type == MT_NONE && rinfo->is_mobility
|
||||
&& (INREG(LVDS_GEN_CNTL) & LVDS_ON))
|
||||
{
|
||||
rinfo->mon1_type = MT_LCD;
|
||||
dbg("Non-DDC laptop panel detected\r\n");
|
||||
}
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
rinfo->mon1_type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC);
|
||||
/*
|
||||
* Probe secondary head (mostly VGA, can be DVI)
|
||||
*/
|
||||
#ifdef CONFIG_FB_RADEON_I2C
|
||||
if (rinfo->mon2_type == MT_NONE)
|
||||
{
|
||||
dbg("probe ddc_vga on MON2\r\n");
|
||||
rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga, &rinfo->mon2_EDID);
|
||||
}
|
||||
if (rinfo->mon2_type == MT_NONE && !ddc_crt2_used)
|
||||
{
|
||||
dbg("probe ddc_crt2 on MON2\r\n");
|
||||
rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_crt2, &rinfo->mon2_EDID);
|
||||
}
|
||||
#endif /* CONFIG_FB_RADEON_I2C */
|
||||
if (rinfo->mon2_type == MT_NONE)
|
||||
rinfo->mon2_type = radeon_crt_is_connected(rinfo, !rinfo->reversed_DAC);
|
||||
/*
|
||||
* If we only detected port 2, we swap them, if none detected,
|
||||
* assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look
|
||||
* at FP registers ?)
|
||||
*/
|
||||
if (rinfo->mon1_type == MT_NONE)
|
||||
{
|
||||
if (rinfo->mon2_type != MT_NONE)
|
||||
{
|
||||
rinfo->mon1_type = rinfo->mon2_type;
|
||||
rinfo->mon1_EDID = rinfo->mon2_EDID;
|
||||
}
|
||||
else
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
|
||||
rinfo->mon2_type = MT_NONE;
|
||||
rinfo->mon2_EDID = NULL;
|
||||
}
|
||||
/*
|
||||
* Deal with reversed TMDS
|
||||
*/
|
||||
if (rinfo->reversed_TMDS)
|
||||
{
|
||||
/* Always keep internal TMDS as primary head */
|
||||
if (rinfo->mon1_type == MT_DFP || rinfo->mon2_type == MT_DFP)
|
||||
{
|
||||
int tmp_type = rinfo->mon1_type;
|
||||
unsigned char *tmp_EDID = rinfo->mon1_EDID;
|
||||
rinfo->mon1_type = rinfo->mon2_type;
|
||||
rinfo->mon1_EDID = rinfo->mon2_EDID;
|
||||
rinfo->mon2_type = tmp_type;
|
||||
rinfo->mon2_EDID = tmp_EDID;
|
||||
if (rinfo->mon1_type == MT_CRT || rinfo->mon2_type == MT_CRT)
|
||||
rinfo->reversed_DAC ^= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ignore_edid)
|
||||
{
|
||||
driver_mem_free(rinfo->mon1_EDID);
|
||||
rinfo->mon1_EDID = NULL;
|
||||
driver_mem_free(rinfo->mon2_EDID);
|
||||
rinfo->mon2_EDID = NULL;
|
||||
}
|
||||
|
||||
bail:
|
||||
dbg("Monitor 1 type %s found\r\n", radeon_get_mon_name(rinfo->mon1_type));
|
||||
if (rinfo->mon1_EDID)
|
||||
{
|
||||
dbg("EDID probed\r\n");
|
||||
}
|
||||
|
||||
if (!rinfo->has_CRTC2)
|
||||
return;
|
||||
dbg("Monitor 2 type %s\r\n", radeon_get_mon_name(rinfo->mon2_type));
|
||||
if (rinfo->mon2_EDID)
|
||||
{
|
||||
dbg("EDID probed\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill up panel infos from a mode definition, either returned by the EDID
|
||||
* or from the default mode when we can't do any better
|
||||
*/
|
||||
static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var)
|
||||
{
|
||||
rinfo->panel_info.xres = var->xres;
|
||||
rinfo->panel_info.yres = var->yres;
|
||||
rinfo->panel_info.clock = 100000000 / var->pixclock;
|
||||
rinfo->panel_info.hOver_plus = var->right_margin;
|
||||
rinfo->panel_info.hSync_width = var->hsync_len;
|
||||
rinfo->panel_info.hblank = var->left_margin + (var->right_margin + var->hsync_len);
|
||||
rinfo->panel_info.vOver_plus = var->lower_margin;
|
||||
rinfo->panel_info.vSync_width = var->vsync_len;
|
||||
rinfo->panel_info.vblank = var->upper_margin + (var->lower_margin + var->vsync_len);
|
||||
rinfo->panel_info.hAct_high = (var->sync & FB_SYNC_HOR_HIGH_ACT) != 0;
|
||||
rinfo->panel_info.vAct_high = (var->sync & FB_SYNC_VERT_HIGH_ACT) != 0;
|
||||
rinfo->panel_info.valid = 1;
|
||||
|
||||
/*
|
||||
* We use a default of 200ms for the panel power delay,
|
||||
* I need to have a real schedule() instead of mdelay's in the panel code.
|
||||
* we might be possible to figure out a better power delay either from
|
||||
* MacOS OF tree or from the EDID block (proprietary extensions ?)
|
||||
*/
|
||||
rinfo->panel_info.pwr_delay = 200;
|
||||
}
|
||||
|
||||
static void radeon_videomode_to_var(struct fb_var_screeninfo *var,
|
||||
const struct fb_videomode *mode)
|
||||
{
|
||||
var->xres = mode->xres;
|
||||
var->yres = mode->yres;
|
||||
var->xres_virtual = mode->xres;
|
||||
var->yres_virtual = mode->yres;
|
||||
var->xoffset = 0;
|
||||
var->yoffset = 0;
|
||||
var->pixclock = mode->pixclock;
|
||||
var->left_margin = mode->left_margin;
|
||||
var->right_margin = mode->right_margin;
|
||||
var->upper_margin = mode->upper_margin;
|
||||
var->lower_margin = mode->lower_margin;
|
||||
var->hsync_len = mode->hsync_len;
|
||||
var->vsync_len = mode->vsync_len;
|
||||
var->sync = mode->sync;
|
||||
var->vmode = mode->vmode;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the modedb for head 1 (head 2 will come later), check panel infos
|
||||
* from either BIOS or EDID, and pick up the default mode
|
||||
*/
|
||||
void radeon_check_modes(struct radeonfb_info *rinfo, struct mode_option *resolution)
|
||||
{
|
||||
struct fb_info *info = rinfo->info;
|
||||
int has_default_mode = 0;
|
||||
struct mode_option xres_yres;
|
||||
dbg("\r\n");
|
||||
|
||||
/*
|
||||
* Fill default var first
|
||||
*/
|
||||
memcpy(&info->var, &radeonfb_default_var, sizeof(struct fb_var_screeninfo));
|
||||
|
||||
/*
|
||||
* Parse EDID detailed timings and deduce panel infos if any. Right now
|
||||
* we only deal with first entry returned by parse_EDID, we may do better
|
||||
* some day...
|
||||
*/
|
||||
if (!rinfo->panel_info.use_bios_dividers
|
||||
&& rinfo->mon1_type != MT_CRT && rinfo->mon1_EDID)
|
||||
{
|
||||
struct fb_var_screeninfo var;
|
||||
|
||||
dbg("fb_parse_edid\r\n");
|
||||
if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0)
|
||||
{
|
||||
if ((var.xres >= rinfo->panel_info.xres) && (var.yres >= rinfo->panel_info.yres))
|
||||
radeon_var_to_panel_info(rinfo, &var);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg("no data to parse\r\n");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we have some valid panel infos, we setup the default mode based on
|
||||
* those
|
||||
*/
|
||||
if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid)
|
||||
{
|
||||
struct fb_var_screeninfo *var = &info->var;
|
||||
|
||||
dbg("setup the default mode based on panel info\r\n");
|
||||
var->xres = rinfo->panel_info.xres;
|
||||
var->yres = rinfo->panel_info.yres;
|
||||
var->xres_virtual = rinfo->panel_info.xres;
|
||||
var->yres_virtual = rinfo->panel_info.yres;
|
||||
var->xoffset = var->yoffset = 0;
|
||||
var->bits_per_pixel = 8;
|
||||
var->pixclock = 100000000 / rinfo->panel_info.clock;
|
||||
var->left_margin = (rinfo->panel_info.hblank - rinfo->panel_info.hOver_plus - rinfo->panel_info.hSync_width);
|
||||
var->right_margin = rinfo->panel_info.hOver_plus;
|
||||
var->upper_margin = (rinfo->panel_info.vblank - rinfo->panel_info.vOver_plus - rinfo->panel_info.vSync_width);
|
||||
var->lower_margin = rinfo->panel_info.vOver_plus;
|
||||
var->hsync_len = rinfo->panel_info.hSync_width;
|
||||
var->vsync_len = rinfo->panel_info.vSync_width;
|
||||
var->sync = 0;
|
||||
|
||||
if (rinfo->panel_info.hAct_high)
|
||||
var->sync |= FB_SYNC_HOR_HIGH_ACT;
|
||||
|
||||
if (rinfo->panel_info.vAct_high)
|
||||
var->sync |= FB_SYNC_VERT_HIGH_ACT;
|
||||
|
||||
var->vmode = 0;
|
||||
has_default_mode = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now build modedb from EDID
|
||||
*/
|
||||
if (rinfo->mon1_EDID)
|
||||
{
|
||||
fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs);
|
||||
rinfo->mon1_modedb = info->monspecs.modedb;
|
||||
rinfo->mon1_dbsize = info->monspecs.modedb_len;
|
||||
}
|
||||
/*
|
||||
* Finally, if we don't have panel infos we need to figure some (or
|
||||
* we try to read it from card), we try to pick a default mode
|
||||
* and create some panel infos. Whatever...
|
||||
*/
|
||||
if (rinfo->mon1_type != MT_CRT && !rinfo->panel_info.valid)
|
||||
{
|
||||
struct fb_videomode *modedb;
|
||||
int dbsize;
|
||||
|
||||
if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0)
|
||||
{
|
||||
unsigned long tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE;
|
||||
|
||||
rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8;
|
||||
|
||||
tmp = INREG(FP_VERT_STRETCH) & VERT_PANEL_SIZE;
|
||||
rinfo->panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1;
|
||||
}
|
||||
|
||||
if ((rinfo->panel_info.xres <= 8) || (rinfo->panel_info.yres <= 1))
|
||||
{
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
goto pickup_default;
|
||||
}
|
||||
modedb = rinfo->mon1_modedb;
|
||||
dbsize = rinfo->mon1_dbsize;
|
||||
xres_yres.used = 1;
|
||||
xres_yres.width = rinfo->panel_info.xres;
|
||||
xres_yres.height = rinfo->panel_info.yres;
|
||||
xres_yres.bpp = xres_yres.freq = 0;
|
||||
if (fb_find_mode(&info->var, info, &xres_yres, modedb, dbsize, NULL,
|
||||
(resolution->bpp >= 8) ? (unsigned int)resolution->bpp : 8) == 0)
|
||||
{
|
||||
rinfo->mon1_type = MT_CRT;
|
||||
goto pickup_default;
|
||||
}
|
||||
has_default_mode = 1;
|
||||
radeon_var_to_panel_info(rinfo, &info->var);
|
||||
}
|
||||
|
||||
pickup_default:
|
||||
|
||||
/*
|
||||
* Apply passed-in mode option if any
|
||||
*/
|
||||
if (resolution->used)
|
||||
{
|
||||
if (fb_find_mode(&info->var, info, resolution, info->monspecs.modedb,
|
||||
info->monspecs.modedb_len, NULL, (resolution->bpp >= 8) ? (unsigned int)resolution->bpp : 8) != 0)
|
||||
has_default_mode = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Still no mode, let's pick up a default from the db
|
||||
*/
|
||||
if (!has_default_mode && info->monspecs.modedb != NULL)
|
||||
{
|
||||
struct fb_monspecs *specs = &info->monspecs;
|
||||
struct fb_videomode *modedb = NULL;
|
||||
|
||||
/* get preferred timing */
|
||||
if (specs->misc & FB_MISC_1ST_DETAIL)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < specs->modedb_len; i++)
|
||||
{
|
||||
if (specs->modedb[i].flag & FB_MODE_IS_FIRST)
|
||||
{
|
||||
modedb = &specs->modedb[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, get first mode in database */
|
||||
modedb = &specs->modedb[0];
|
||||
}
|
||||
|
||||
if (modedb != NULL)
|
||||
{
|
||||
info->var.bits_per_pixel = 8;
|
||||
radeon_videomode_to_var(&info->var, modedb);
|
||||
has_default_mode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The code below is used to pick up a mode in check_var and
|
||||
* set_var. It should be made generic
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is used when looking for modes. We assign a "distance" value
|
||||
* to a mode in the modedb depending how "close" it is from what we
|
||||
* are looking for.
|
||||
* Currently, we don't compare that much, we could do better but
|
||||
* the current fbcon doesn't quite mind ;)
|
||||
*/
|
||||
static int radeon_compare_modes(const struct fb_var_screeninfo *var,
|
||||
const struct fb_videomode *mode)
|
||||
{
|
||||
int distance = 0;
|
||||
|
||||
distance = mode->yres - var->yres;
|
||||
distance += (mode->xres - var->xres)/2;
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by check_var, it gets the passed in mode parameter, and
|
||||
* outputs a valid mode matching the passed-in one as closely as possible.
|
||||
* We need something better ultimately.
|
||||
*/
|
||||
int32_t radeon_match_mode(struct radeonfb_info *rinfo,
|
||||
struct fb_var_screeninfo *dest,
|
||||
const struct fb_var_screeninfo *src)
|
||||
{
|
||||
const struct fb_videomode *db = vesa_modes;
|
||||
int i, dbsize = 34;
|
||||
int has_rmx, native_db = 0;
|
||||
int distance = INT_MAX;
|
||||
const struct fb_videomode *candidate = NULL;
|
||||
|
||||
dbg("\r\n");
|
||||
|
||||
/* Start with a copy of the requested mode */
|
||||
memcpy(dest, src, sizeof(struct fb_var_screeninfo));
|
||||
|
||||
/* Check if we have a modedb built from EDID */
|
||||
if (rinfo->mon1_modedb)
|
||||
{
|
||||
db = rinfo->mon1_modedb;
|
||||
dbsize = rinfo->mon1_dbsize;
|
||||
native_db = 1;
|
||||
}
|
||||
/* Check if we have a scaler allowing any fancy mode */
|
||||
has_rmx = (rinfo->mon1_type == MT_LCD) || (rinfo->mon1_type == MT_DFP);
|
||||
|
||||
/* If we have a scaler and are passed FB_ACTIVATE_TEST or
|
||||
* FB_ACTIVATE_NOW, just do basic checking and return if the
|
||||
* mode match
|
||||
*/
|
||||
if ((src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST
|
||||
|| (src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
|
||||
{
|
||||
/* We don't have an RMX, validate timings. If we don't have
|
||||
* monspecs, we should be paranoid and not let use go above
|
||||
* 640x480-60, but I assume userland knows what it's doing here
|
||||
* (though I may be proven wrong...)
|
||||
*/
|
||||
if ((has_rmx == 0) && rinfo->mon1_modedb)
|
||||
{
|
||||
if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info))
|
||||
return -1; //-EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
dbg("look for a mode in the database\r\n");
|
||||
|
||||
/* Now look for a mode in the database */
|
||||
while(db)
|
||||
{
|
||||
for (i = 0; i < dbsize; i++)
|
||||
{
|
||||
int d;
|
||||
|
||||
if ((db[i].yres < src->yres) || (db[i].xres < src->xres))
|
||||
continue;
|
||||
d = radeon_compare_modes(src, &db[i]);
|
||||
/* If the new mode is at least as good as the previous one,
|
||||
* then it's our new candidate
|
||||
*/
|
||||
if (d < distance)
|
||||
{
|
||||
candidate = &db[i];
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
db = NULL;
|
||||
/* If we have a scaler, we allow any mode from the database */
|
||||
if (native_db && has_rmx)
|
||||
{
|
||||
db = vesa_modes;
|
||||
dbsize = 34;
|
||||
native_db = 0;
|
||||
}
|
||||
}
|
||||
/* If we have found a match, return it */
|
||||
if (candidate != NULL)
|
||||
{
|
||||
radeon_videomode_to_var(dest, candidate);
|
||||
return 0;
|
||||
}
|
||||
/* If we haven't and don't have a scaler, fail */
|
||||
if (!has_rmx)
|
||||
return -1; //-EINVAL;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user