forked from Minki/linux
fbdev changes for 4.4
* omap: fix hdmi audio configuration issue * ssd1307fb: add ssd1309 support * tridentfb: support DDC * gxt4500: enable support for non-PPC platforms -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWQdTmAAoJEPo9qoy8lh71X6EP/2nevzMgb3+9k0udX11AE9lJ PDVv9I5lPI7qOcQ3Lyi5Ke55KW7PcPHdbRew9pAumlbm79DSFb0Be6b1xh+94g4u nE7Bgi+5AJlHVcDLQbJCBZHD1ADv6UdQrRUuVT9jWTtoAPxHnzuEwpt77kT62VMK LAYObUId+h+SRWurKy5nRlVIzF8pykvB/QL0mgy1UqsQwGe8/9jVkmwhDlynUDxP c1LXoBlLEZ/SyXn1lXoGbAbmV3H7oYe/0Dv/dbKqm3J7V4FR2Jo/DJBba7Zft9li 3p6Wn5OqoXDsPMzIwPMtlPkYiw1kwgk2e1EpIy2RobugTR82YOaTYA+sNjl1lOqe DNEL06JPUANCKvlZx+OZTPbRagREWIaDzmGYhbn2l7+XpguqJ7oU7VO34x1eTIsI T42Xmxte5aPe24LtrONmZ7EpArTF5VRbuf9NVw0+T0TDpaXr/C3N+3s3bVgPnUgw SZ8fKSVGGzXgP6SxsVOnu/k4zaNvTO7AwFYZV3kC1VqM3jXp/1eMGC7SH4CTXMht AP5IcHMhLFGrH5aOrqKE3gPeenzZIwKe9JsKnEojiSU+UXxmxax37K5rjjpevzrL IBIKj79mzJ5Y7/0ZxiDNq6goPywbMUtipDEAIQGIMOefywI3q7qXT6fjjTrPbiC3 Nc7/b1ZqEXYYfMrMLzUl =zDAU -----END PGP SIGNATURE----- Merge tag 'fbdev-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux Pull fbdev updates from Tomi Valkeinen: - omap: fix hdmi audio configuration issue - ssd1307fb: add ssd1309 support - tridentfb: support DDC - gxt4500: enable support for non-PPC platforms * tag 'fbdev-4.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: radeonfb: Deinline large functions gxt4500: enable panning gxt4500: Use arch_phys_wc_* for framebuffer gxt4500: fix color order gxt4500: fix 16bpp 565 mode gxt4500: enable on non-PPC architectures tridentfb: Add DDC support fb_ddc: Allow I2C adapters without SCL read capability fbdev: ssd1307fb: add ssd1309 support fbdev: ssd1307fb: alphabetize headers video/omap: remove invalid check OMAPDSS: hdmi: Reconfigure and restart audio when display is enabled
This commit is contained in:
commit
3b13866869
@ -2,7 +2,8 @@
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
|
||||
now is i2c, and the supported chips are ssd1305, ssd1306 and ssd1307.
|
||||
now is i2c, and the supported chips are ssd1305, ssd1306, ssd1307 and
|
||||
ssd1309.
|
||||
- reg: Should contain address of the controller on the I2C bus. Most likely
|
||||
0x3c or 0x3d
|
||||
- pwm: Should contain the pwm to use according to the OF device tree PWM
|
||||
|
@ -1666,6 +1666,8 @@ config FB_TRIDENT
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB_DDC
|
||||
select FB_MODE_HELPERS
|
||||
---help---
|
||||
This is the frame buffer device driver for Trident PCI/AGP chipsets.
|
||||
Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D
|
||||
@ -2132,7 +2134,7 @@ config FB_UDL
|
||||
|
||||
config FB_IBM_GXT4500
|
||||
tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors"
|
||||
depends on FB && PPC
|
||||
depends on FB
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
@ -2140,7 +2142,8 @@ config FB_IBM_GXT4500
|
||||
Say Y here to enable support for the IBM GXT4000P/6000P and
|
||||
GXT4500P/6500P display adaptor based on Raster Engine RC1000,
|
||||
found on some IBM System P (pSeries) machines. This driver
|
||||
doesn't use Geometry Engine GT1000.
|
||||
doesn't use Geometry Engine GT1000. This driver also supports
|
||||
AGP Fire GL2/3/4 cards on x86.
|
||||
|
||||
config FB_PS3
|
||||
tristate "PS3 GPU framebuffer driver"
|
||||
|
@ -276,9 +276,138 @@ static int backlight = 1;
|
||||
static int backlight = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
/* Note about this function: we have some rare cases where we must not schedule,
|
||||
* this typically happen with our special "wake up early" hook which allows us to
|
||||
* wake up the graphic chip (and thus get the console back) before everything else
|
||||
* on some machines that support that mechanism. At this point, interrupts are off
|
||||
* and scheduling is not permitted
|
||||
*/
|
||||
void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
|
||||
{
|
||||
if (rinfo->no_schedule || oops_in_progress)
|
||||
mdelay(ms);
|
||||
else
|
||||
msleep(ms);
|
||||
}
|
||||
|
||||
void radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo)
|
||||
{
|
||||
/* Called if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS) is set */
|
||||
(void)INREG(CLOCK_CNTL_DATA);
|
||||
(void)INREG(CRTC_GEN_CNTL);
|
||||
}
|
||||
|
||||
void radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo)
|
||||
{
|
||||
if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
|
||||
/* we can't deal with posted writes here ... */
|
||||
_radeon_msleep(rinfo, 5);
|
||||
}
|
||||
if (rinfo->errata & CHIP_ERRATA_R300_CG) {
|
||||
u32 save, tmp;
|
||||
save = INREG(CLOCK_CNTL_INDEX);
|
||||
tmp = save & ~(0x3f | PLL_WR_EN);
|
||||
OUTREG(CLOCK_CNTL_INDEX, tmp);
|
||||
tmp = INREG(CLOCK_CNTL_DATA);
|
||||
OUTREG(CLOCK_CNTL_INDEX, save);
|
||||
}
|
||||
}
|
||||
|
||||
void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int tmp;
|
||||
|
||||
spin_lock_irqsave(&rinfo->reg_lock, flags);
|
||||
tmp = INREG(addr);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
OUTREG(addr, tmp);
|
||||
spin_unlock_irqrestore(&rinfo->reg_lock, flags);
|
||||
}
|
||||
|
||||
u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
|
||||
radeon_pll_errata_after_index(rinfo);
|
||||
data = INREG(CLOCK_CNTL_DATA);
|
||||
radeon_pll_errata_after_data(rinfo);
|
||||
return data;
|
||||
}
|
||||
|
||||
void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
|
||||
{
|
||||
OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
|
||||
radeon_pll_errata_after_index(rinfo);
|
||||
OUTREG(CLOCK_CNTL_DATA, val);
|
||||
radeon_pll_errata_after_data(rinfo);
|
||||
}
|
||||
|
||||
void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = __INPLL(rinfo, index);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
__OUTPLL(rinfo, index, tmp);
|
||||
}
|
||||
|
||||
void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
|
||||
}
|
||||
|
||||
void radeon_engine_flush(struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initiate flush */
|
||||
OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
|
||||
~RB2D_DC_FLUSH_ALL);
|
||||
|
||||
/* Ensure FIFO is empty, ie, make sure the flush commands
|
||||
* has reached the cache
|
||||
*/
|
||||
_radeon_fifo_wait(rinfo, 64);
|
||||
|
||||
/* Wait for the flush to complete */
|
||||
for (i=0; i < 2000000; i++) {
|
||||
if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: Flush Timeout !\n");
|
||||
}
|
||||
|
||||
void _radeon_engine_idle(struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* ensure FIFO is empty before waiting for idle */
|
||||
_radeon_fifo_wait(rinfo, 64);
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
|
||||
radeon_engine_flush(rinfo);
|
||||
return;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: Idle Timeout !\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
|
||||
{
|
||||
|
@ -370,20 +370,7 @@ struct radeonfb_info {
|
||||
* IO macros
|
||||
*/
|
||||
|
||||
/* Note about this function: we have some rare cases where we must not schedule,
|
||||
* this typically happen with our special "wake up early" hook which allows us to
|
||||
* wake up the graphic chip (and thus get the console back) before everything else
|
||||
* on some machines that support that mechanism. At this point, interrupts are off
|
||||
* and scheduling is not permitted
|
||||
*/
|
||||
static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
|
||||
{
|
||||
if (rinfo->no_schedule || oops_in_progress)
|
||||
mdelay(ms);
|
||||
else
|
||||
msleep(ms);
|
||||
}
|
||||
|
||||
void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms);
|
||||
|
||||
#define INREG8(addr) readb((rinfo->mmio_base)+addr)
|
||||
#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr)
|
||||
@ -392,19 +379,7 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
|
||||
#define INREG(addr) readl((rinfo->mmio_base)+addr)
|
||||
#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr)
|
||||
|
||||
static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int tmp;
|
||||
|
||||
spin_lock_irqsave(&rinfo->reg_lock, flags);
|
||||
tmp = INREG(addr);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
OUTREG(addr, tmp);
|
||||
spin_unlock_irqrestore(&rinfo->reg_lock, flags);
|
||||
}
|
||||
void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask);
|
||||
|
||||
#define OUTREGP(addr,val,mask) _OUTREGP(rinfo, addr, val,mask)
|
||||
|
||||
@ -425,64 +400,24 @@ static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
|
||||
* possible exception to this rule is the call to unblank(), which may
|
||||
* be done at irq time if an oops is in progress.
|
||||
*/
|
||||
void radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo);
|
||||
static inline void radeon_pll_errata_after_index(struct radeonfb_info *rinfo)
|
||||
{
|
||||
if (!(rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS))
|
||||
return;
|
||||
|
||||
(void)INREG(CLOCK_CNTL_DATA);
|
||||
(void)INREG(CRTC_GEN_CNTL);
|
||||
if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS)
|
||||
radeon_pll_errata_after_index_slow(rinfo);
|
||||
}
|
||||
|
||||
void radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo);
|
||||
static inline void radeon_pll_errata_after_data(struct radeonfb_info *rinfo)
|
||||
{
|
||||
if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
|
||||
/* we can't deal with posted writes here ... */
|
||||
_radeon_msleep(rinfo, 5);
|
||||
}
|
||||
if (rinfo->errata & CHIP_ERRATA_R300_CG) {
|
||||
u32 save, tmp;
|
||||
save = INREG(CLOCK_CNTL_INDEX);
|
||||
tmp = save & ~(0x3f | PLL_WR_EN);
|
||||
OUTREG(CLOCK_CNTL_INDEX, tmp);
|
||||
tmp = INREG(CLOCK_CNTL_DATA);
|
||||
OUTREG(CLOCK_CNTL_INDEX, save);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
|
||||
radeon_pll_errata_after_index(rinfo);
|
||||
data = INREG(CLOCK_CNTL_DATA);
|
||||
radeon_pll_errata_after_data(rinfo);
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val)
|
||||
{
|
||||
|
||||
OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
|
||||
radeon_pll_errata_after_index(rinfo);
|
||||
OUTREG(CLOCK_CNTL_DATA, val);
|
||||
radeon_pll_errata_after_data(rinfo);
|
||||
}
|
||||
|
||||
|
||||
static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = __INPLL(rinfo, index);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
__OUTPLL(rinfo, index, tmp);
|
||||
if (rinfo->errata & (CHIP_ERRATA_PLL_DELAY|CHIP_ERRATA_R300_CG))
|
||||
radeon_pll_errata_after_data_slow(rinfo);
|
||||
}
|
||||
|
||||
u32 __INPLL(struct radeonfb_info *rinfo, u32 addr);
|
||||
void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val);
|
||||
void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val, u32 mask);
|
||||
|
||||
#define INPLL(addr) __INPLL(rinfo, addr)
|
||||
#define OUTPLL(index, val) __OUTPLL(rinfo, index, val)
|
||||
@ -532,58 +467,9 @@ static inline u32 radeon_get_dstbpp(u16 depth)
|
||||
* 2D Engine helper routines
|
||||
*/
|
||||
|
||||
static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
|
||||
}
|
||||
|
||||
static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initiate flush */
|
||||
OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
|
||||
~RB2D_DC_FLUSH_ALL);
|
||||
|
||||
/* Ensure FIFO is empty, ie, make sure the flush commands
|
||||
* has reached the cache
|
||||
*/
|
||||
_radeon_fifo_wait (rinfo, 64);
|
||||
|
||||
/* Wait for the flush to complete */
|
||||
for (i=0; i < 2000000; i++) {
|
||||
if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: Flush Timeout !\n");
|
||||
}
|
||||
|
||||
|
||||
static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* ensure FIFO is empty before waiting for idle */
|
||||
_radeon_fifo_wait (rinfo, 64);
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
|
||||
radeon_engine_flush (rinfo);
|
||||
return;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
printk(KERN_ERR "radeonfb: Idle Timeout !\n");
|
||||
}
|
||||
|
||||
void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries);
|
||||
void radeon_engine_flush(struct radeonfb_info *rinfo);
|
||||
void _radeon_engine_idle(struct radeonfb_info *rinfo);
|
||||
|
||||
#define radeon_engine_idle() _radeon_engine_idle(rinfo)
|
||||
#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries)
|
||||
|
@ -67,13 +67,17 @@ unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
|
||||
msleep(13);
|
||||
|
||||
algo_data->setscl(algo_data->data, 1);
|
||||
for (j = 0; j < 5; j++) {
|
||||
msleep(10);
|
||||
if (algo_data->getscl(algo_data->data))
|
||||
break;
|
||||
if (algo_data->getscl) {
|
||||
for (j = 0; j < 5; j++) {
|
||||
msleep(10);
|
||||
if (algo_data->getscl(algo_data->data))
|
||||
break;
|
||||
}
|
||||
if (j == 5)
|
||||
continue;
|
||||
} else {
|
||||
udelay(algo_data->udelay);
|
||||
}
|
||||
if (j == 5)
|
||||
continue;
|
||||
|
||||
algo_data->setsda(algo_data->data, 0);
|
||||
msleep(15);
|
||||
@ -89,10 +93,14 @@ unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
|
||||
msleep(15);
|
||||
|
||||
algo_data->setscl(algo_data->data, 1);
|
||||
for (j = 0; j < 10; j++) {
|
||||
msleep(10);
|
||||
if (algo_data->getscl(algo_data->data))
|
||||
break;
|
||||
if (algo_data->getscl) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
msleep(10);
|
||||
if (algo_data->getscl(algo_data->data))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
udelay(algo_data->udelay);
|
||||
}
|
||||
|
||||
algo_data->setsda(algo_data->data, 1);
|
||||
|
@ -142,7 +142,7 @@ static const unsigned char watfmt[] = {
|
||||
|
||||
struct gxt4500_par {
|
||||
void __iomem *regs;
|
||||
|
||||
int wc_cookie;
|
||||
int pixfmt; /* pixel format, see DFA_PIX_* values */
|
||||
|
||||
/* PLL parameters */
|
||||
@ -347,11 +347,12 @@ static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,
|
||||
break;
|
||||
}
|
||||
if (pixfmt != DFA_PIX_8BIT) {
|
||||
var->green.offset = var->red.length;
|
||||
var->blue.offset = var->green.offset + var->green.length;
|
||||
var->blue.offset = 0;
|
||||
var->green.offset = var->blue.length;
|
||||
var->red.offset = var->green.offset + var->green.length;
|
||||
if (var->transp.length)
|
||||
var->transp.offset =
|
||||
var->blue.offset + var->blue.length;
|
||||
var->red.offset + var->red.length;
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +526,7 @@ static int gxt4500_setcolreg(unsigned int reg, unsigned int red,
|
||||
u32 val = reg;
|
||||
switch (par->pixfmt) {
|
||||
case DFA_PIX_16BIT_565:
|
||||
val |= (reg << 11) | (reg << 6);
|
||||
val |= (reg << 11) | (reg << 5);
|
||||
break;
|
||||
case DFA_PIX_16BIT_1555:
|
||||
val |= (reg << 10) | (reg << 5);
|
||||
@ -670,11 +671,22 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
pci_set_drvdata(pdev, info);
|
||||
|
||||
par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
|
||||
info->fix.smem_len);
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
/* Set byte-swapping for DFA aperture for all pixel sizes */
|
||||
pci_write_config_dword(pdev, CFG_ENDIAN0, 0x333300);
|
||||
#else /* __LITTLE_ENDIAN */
|
||||
/* not sure what this means but fgl23 driver does that */
|
||||
pci_write_config_dword(pdev, CFG_ENDIAN0, 0x2300);
|
||||
/* pci_write_config_dword(pdev, CFG_ENDIAN0 + 4, 0x400000);*/
|
||||
pci_write_config_dword(pdev, CFG_ENDIAN0 + 8, 0x98530000);
|
||||
#endif
|
||||
|
||||
info->fbops = &gxt4500_ops;
|
||||
info->flags = FBINFO_FLAG_DEFAULT;
|
||||
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_XPAN |
|
||||
FBINFO_HWACCEL_YPAN;
|
||||
|
||||
err = fb_alloc_cmap(&info->cmap, 256, 0);
|
||||
if (err) {
|
||||
@ -727,6 +739,7 @@ static void gxt4500_remove(struct pci_dev *pdev)
|
||||
return;
|
||||
par = info->par;
|
||||
unregister_framebuffer(info);
|
||||
arch_phys_wc_del(par->wc_cookie);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
iounmap(par->regs);
|
||||
iounmap(info->screen_base);
|
||||
|
@ -276,11 +276,6 @@ static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
|
||||
if (r != 0)
|
||||
break;
|
||||
|
||||
if (regno < 0) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (regno < 16) {
|
||||
u16 pal;
|
||||
pal = ((red >> (16 - var->red.length)) <<
|
||||
|
@ -351,13 +351,20 @@ struct omap_hdmi {
|
||||
struct regulator *vdda_reg;
|
||||
|
||||
bool core_enabled;
|
||||
bool display_enabled;
|
||||
|
||||
struct omap_dss_device output;
|
||||
|
||||
struct platform_device *audio_pdev;
|
||||
void (*audio_abort_cb)(struct device *dev);
|
||||
int wp_idlemode;
|
||||
|
||||
bool audio_configured;
|
||||
struct omap_dss_audio audio_config;
|
||||
|
||||
/* This lock should be taken when booleans bellow are touched. */
|
||||
spinlock_t audio_playing_lock;
|
||||
bool audio_playing;
|
||||
bool display_enabled;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -321,9 +321,22 @@ static int read_edid(u8 *buf, int len)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
|
||||
{
|
||||
hdmi_wp_audio_enable(&hd->wp, true);
|
||||
hdmi4_audio_start(&hd->core, &hd->wp);
|
||||
}
|
||||
|
||||
static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
|
||||
{
|
||||
hdmi4_audio_stop(&hd->core, &hd->wp);
|
||||
hdmi_wp_audio_enable(&hd->wp, false);
|
||||
}
|
||||
|
||||
static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
unsigned long flags;
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
@ -342,7 +355,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (hdmi.audio_configured) {
|
||||
r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
|
||||
hdmi.cfg.timings.pixelclock);
|
||||
if (r) {
|
||||
DSSERR("Error restoring audio configuration: %d", r);
|
||||
hdmi.audio_abort_cb(&hdmi.pdev->dev);
|
||||
hdmi.audio_configured = false;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
|
||||
if (hdmi.audio_configured && hdmi.audio_playing)
|
||||
hdmi_start_audio_stream(&hdmi);
|
||||
hdmi.display_enabled = true;
|
||||
spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
@ -354,17 +381,19 @@ err0:
|
||||
|
||||
static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DSSDBG("Enter hdmi_display_disable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
|
||||
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
|
||||
spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
|
||||
hdmi_stop_audio_stream(&hdmi);
|
||||
hdmi.display_enabled = false;
|
||||
spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
|
||||
|
||||
hdmi_power_off_full(dssdev);
|
||||
|
||||
hdmi.display_enabled = false;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
@ -568,6 +597,8 @@ static int hdmi_audio_shutdown(struct device *dev)
|
||||
|
||||
mutex_lock(&hd->lock);
|
||||
hd->audio_abort_cb = NULL;
|
||||
hd->audio_configured = false;
|
||||
hd->audio_playing = false;
|
||||
mutex_unlock(&hd->lock);
|
||||
|
||||
return 0;
|
||||
@ -576,25 +607,34 @@ static int hdmi_audio_shutdown(struct device *dev)
|
||||
static int hdmi_audio_start(struct device *dev)
|
||||
{
|
||||
struct omap_hdmi *hd = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
|
||||
WARN_ON(!hd->display_enabled);
|
||||
|
||||
hdmi_wp_audio_enable(&hd->wp, true);
|
||||
hdmi4_audio_start(&hd->core, &hd->wp);
|
||||
spin_lock_irqsave(&hd->audio_playing_lock, flags);
|
||||
|
||||
if (hd->display_enabled)
|
||||
hdmi_start_audio_stream(hd);
|
||||
hd->audio_playing = true;
|
||||
|
||||
spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_audio_stop(struct device *dev)
|
||||
{
|
||||
struct omap_hdmi *hd = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
|
||||
WARN_ON(!hd->display_enabled);
|
||||
|
||||
hdmi4_audio_stop(&hd->core, &hd->wp);
|
||||
hdmi_wp_audio_enable(&hd->wp, false);
|
||||
spin_lock_irqsave(&hd->audio_playing_lock, flags);
|
||||
|
||||
if (hd->display_enabled)
|
||||
hdmi_stop_audio_stream(hd);
|
||||
hd->audio_playing = false;
|
||||
|
||||
spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
|
||||
}
|
||||
|
||||
static int hdmi_audio_config(struct device *dev,
|
||||
@ -612,7 +652,10 @@ static int hdmi_audio_config(struct device *dev,
|
||||
|
||||
ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
|
||||
hd->cfg.timings.pixelclock);
|
||||
|
||||
if (!ret) {
|
||||
hd->audio_configured = true;
|
||||
hd->audio_config = *dss_audio;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&hd->lock);
|
||||
|
||||
@ -657,6 +700,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
|
||||
dev_set_drvdata(&pdev->dev, &hdmi);
|
||||
|
||||
mutex_init(&hdmi.lock);
|
||||
spin_lock_init(&hdmi.audio_playing_lock);
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
r = hdmi_probe_of(pdev);
|
||||
|
@ -349,9 +349,24 @@ static int read_edid(u8 *buf, int len)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_start_audio_stream(struct omap_hdmi *hd)
|
||||
{
|
||||
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
|
||||
hdmi_wp_audio_enable(&hd->wp, true);
|
||||
hdmi_wp_audio_core_req_enable(&hd->wp, true);
|
||||
}
|
||||
|
||||
static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
|
||||
{
|
||||
hdmi_wp_audio_core_req_enable(&hd->wp, false);
|
||||
hdmi_wp_audio_enable(&hd->wp, false);
|
||||
REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
|
||||
}
|
||||
|
||||
static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *out = &hdmi.output;
|
||||
unsigned long flags;
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
@ -370,7 +385,21 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (hdmi.audio_configured) {
|
||||
r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, &hdmi.audio_config,
|
||||
hdmi.cfg.timings.pixelclock);
|
||||
if (r) {
|
||||
DSSERR("Error restoring audio configuration: %d", r);
|
||||
hdmi.audio_abort_cb(&hdmi.pdev->dev);
|
||||
hdmi.audio_configured = false;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
|
||||
if (hdmi.audio_configured && hdmi.audio_playing)
|
||||
hdmi_start_audio_stream(&hdmi);
|
||||
hdmi.display_enabled = true;
|
||||
spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
@ -382,17 +411,19 @@ err0:
|
||||
|
||||
static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
DSSDBG("Enter hdmi_display_disable\n");
|
||||
|
||||
mutex_lock(&hdmi.lock);
|
||||
|
||||
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
|
||||
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
|
||||
spin_lock_irqsave(&hdmi.audio_playing_lock, flags);
|
||||
hdmi_stop_audio_stream(&hdmi);
|
||||
hdmi.display_enabled = false;
|
||||
spin_unlock_irqrestore(&hdmi.audio_playing_lock, flags);
|
||||
|
||||
hdmi_power_off_full(dssdev);
|
||||
|
||||
hdmi.display_enabled = false;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
@ -596,6 +627,8 @@ static int hdmi_audio_shutdown(struct device *dev)
|
||||
|
||||
mutex_lock(&hd->lock);
|
||||
hd->audio_abort_cb = NULL;
|
||||
hd->audio_configured = false;
|
||||
hd->audio_playing = false;
|
||||
mutex_unlock(&hd->lock);
|
||||
|
||||
return 0;
|
||||
@ -604,32 +637,34 @@ static int hdmi_audio_shutdown(struct device *dev)
|
||||
static int hdmi_audio_start(struct device *dev)
|
||||
{
|
||||
struct omap_hdmi *hd = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
|
||||
WARN_ON(!hd->display_enabled);
|
||||
|
||||
/* No-idle while playing audio, store the old value */
|
||||
hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
|
||||
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
|
||||
spin_lock_irqsave(&hd->audio_playing_lock, flags);
|
||||
|
||||
hdmi_wp_audio_enable(&hd->wp, true);
|
||||
hdmi_wp_audio_core_req_enable(&hd->wp, true);
|
||||
if (hd->display_enabled)
|
||||
hdmi_start_audio_stream(hd);
|
||||
hd->audio_playing = true;
|
||||
|
||||
spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hdmi_audio_stop(struct device *dev)
|
||||
{
|
||||
struct omap_hdmi *hd = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
|
||||
WARN_ON(!hd->display_enabled);
|
||||
|
||||
hdmi_wp_audio_core_req_enable(&hd->wp, false);
|
||||
hdmi_wp_audio_enable(&hd->wp, false);
|
||||
spin_lock_irqsave(&hd->audio_playing_lock, flags);
|
||||
|
||||
/* Playback stopped, restore original idlemode */
|
||||
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
|
||||
if (hd->display_enabled)
|
||||
hdmi_stop_audio_stream(hd);
|
||||
hd->audio_playing = false;
|
||||
|
||||
spin_unlock_irqrestore(&hd->audio_playing_lock, flags);
|
||||
}
|
||||
|
||||
static int hdmi_audio_config(struct device *dev,
|
||||
@ -648,6 +683,10 @@ static int hdmi_audio_config(struct device *dev,
|
||||
ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
|
||||
hd->cfg.timings.pixelclock);
|
||||
|
||||
if (!ret) {
|
||||
hd->audio_configured = true;
|
||||
hd->audio_config = *dss_audio;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&hd->lock);
|
||||
|
||||
@ -678,6 +717,11 @@ static int hdmi_audio_register(struct device *dev)
|
||||
if (IS_ERR(hdmi.audio_pdev))
|
||||
return PTR_ERR(hdmi.audio_pdev);
|
||||
|
||||
hdmi_runtime_get();
|
||||
hdmi.wp_idlemode =
|
||||
REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
|
||||
hdmi_runtime_put();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -692,6 +736,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
|
||||
dev_set_drvdata(&pdev->dev, &hdmi);
|
||||
|
||||
mutex_init(&hdmi.lock);
|
||||
spin_lock_init(&hdmi.audio_playing_lock);
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
r = hdmi_probe_of(pdev);
|
||||
|
@ -6,16 +6,16 @@
|
||||
* Licensed under the GPLv2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define SSD1307FB_DATA 0x40
|
||||
#define SSD1307FB_COMMAND 0x80
|
||||
@ -495,6 +495,12 @@ static struct ssd1307fb_deviceinfo ssd1307fb_ssd1307_deviceinfo = {
|
||||
.need_pwm = 1,
|
||||
};
|
||||
|
||||
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
|
||||
.default_vcomh = 0x34,
|
||||
.default_dclk_div = 1,
|
||||
.default_dclk_frq = 10,
|
||||
};
|
||||
|
||||
static const struct of_device_id ssd1307fb_of_match[] = {
|
||||
{
|
||||
.compatible = "solomon,ssd1305fb-i2c",
|
||||
@ -508,6 +514,10 @@ static const struct of_device_id ssd1307fb_of_match[] = {
|
||||
.compatible = "solomon,ssd1307fb-i2c",
|
||||
.data = (void *)&ssd1307fb_ssd1307_deviceinfo,
|
||||
},
|
||||
{
|
||||
.compatible = "solomon,ssd1309fb-i2c",
|
||||
.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
|
||||
@ -709,6 +719,7 @@ static const struct i2c_device_id ssd1307fb_i2c_id[] = {
|
||||
{ "ssd1305fb", 0 },
|
||||
{ "ssd1306fb", 0 },
|
||||
{ "ssd1307fb", 0 },
|
||||
{ "ssd1309fb", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include <video/vga.h>
|
||||
#include <video/trident.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
|
||||
struct tridentfb_par {
|
||||
void __iomem *io_virt; /* iospace virtual memory address */
|
||||
u32 pseudo_pal[16];
|
||||
@ -40,6 +43,9 @@ struct tridentfb_par {
|
||||
(struct tridentfb_par *par, const char*,
|
||||
u32, u32, u32, u32, u32, u32);
|
||||
unsigned char eng_oper; /* engine operation... */
|
||||
bool ddc_registered;
|
||||
struct i2c_adapter ddc_adapter;
|
||||
struct i2c_algo_bit_data ddc_algo;
|
||||
};
|
||||
|
||||
static struct fb_fix_screeninfo tridentfb_fix = {
|
||||
@ -53,7 +59,7 @@ static struct fb_fix_screeninfo tridentfb_fix = {
|
||||
/* defaults which are normally overriden by user values */
|
||||
|
||||
/* video mode */
|
||||
static char *mode_option = "640x480-8@60";
|
||||
static char *mode_option;
|
||||
static int bpp = 8;
|
||||
|
||||
static int noaccel;
|
||||
@ -174,6 +180,121 @@ static inline u32 readmmr(struct tridentfb_par *par, u16 r)
|
||||
return fb_readl(par->io_virt + r);
|
||||
}
|
||||
|
||||
#define DDC_SDA_TGUI BIT(0)
|
||||
#define DDC_SCL_TGUI BIT(1)
|
||||
#define DDC_SCL_DRIVE_TGUI BIT(2)
|
||||
#define DDC_SDA_DRIVE_TGUI BIT(3)
|
||||
#define DDC_MASK_TGUI (DDC_SCL_DRIVE_TGUI | DDC_SDA_DRIVE_TGUI)
|
||||
|
||||
static void tridentfb_ddc_setscl_tgui(void *data, int val)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI;
|
||||
|
||||
if (val)
|
||||
reg &= ~DDC_SCL_DRIVE_TGUI; /* disable drive - don't drive hi */
|
||||
else
|
||||
reg |= DDC_SCL_DRIVE_TGUI; /* drive low */
|
||||
|
||||
vga_mm_wcrt(par->io_virt, I2C, reg);
|
||||
}
|
||||
|
||||
static void tridentfb_ddc_setsda_tgui(void *data, int val)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
u8 reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK_TGUI;
|
||||
|
||||
if (val)
|
||||
reg &= ~DDC_SDA_DRIVE_TGUI; /* disable drive - don't drive hi */
|
||||
else
|
||||
reg |= DDC_SDA_DRIVE_TGUI; /* drive low */
|
||||
|
||||
vga_mm_wcrt(par->io_virt, I2C, reg);
|
||||
}
|
||||
|
||||
static int tridentfb_ddc_getsda_tgui(void *data)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
|
||||
return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_TGUI);
|
||||
}
|
||||
|
||||
#define DDC_SDA_IN BIT(0)
|
||||
#define DDC_SCL_OUT BIT(1)
|
||||
#define DDC_SDA_OUT BIT(3)
|
||||
#define DDC_SCL_IN BIT(6)
|
||||
#define DDC_MASK (DDC_SCL_OUT | DDC_SDA_OUT)
|
||||
|
||||
static void tridentfb_ddc_setscl(void *data, int val)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
unsigned char reg;
|
||||
|
||||
reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK;
|
||||
if (val)
|
||||
reg |= DDC_SCL_OUT;
|
||||
else
|
||||
reg &= ~DDC_SCL_OUT;
|
||||
vga_mm_wcrt(par->io_virt, I2C, reg);
|
||||
}
|
||||
|
||||
static void tridentfb_ddc_setsda(void *data, int val)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
unsigned char reg;
|
||||
|
||||
reg = vga_mm_rcrt(par->io_virt, I2C) & DDC_MASK;
|
||||
if (!val)
|
||||
reg |= DDC_SDA_OUT;
|
||||
else
|
||||
reg &= ~DDC_SDA_OUT;
|
||||
vga_mm_wcrt(par->io_virt, I2C, reg);
|
||||
}
|
||||
|
||||
static int tridentfb_ddc_getscl(void *data)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
|
||||
return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SCL_IN);
|
||||
}
|
||||
|
||||
static int tridentfb_ddc_getsda(void *data)
|
||||
{
|
||||
struct tridentfb_par *par = data;
|
||||
|
||||
return !!(vga_mm_rcrt(par->io_virt, I2C) & DDC_SDA_IN);
|
||||
}
|
||||
|
||||
static int tridentfb_setup_ddc_bus(struct fb_info *info)
|
||||
{
|
||||
struct tridentfb_par *par = info->par;
|
||||
|
||||
strlcpy(par->ddc_adapter.name, info->fix.id,
|
||||
sizeof(par->ddc_adapter.name));
|
||||
par->ddc_adapter.owner = THIS_MODULE;
|
||||
par->ddc_adapter.class = I2C_CLASS_DDC;
|
||||
par->ddc_adapter.algo_data = &par->ddc_algo;
|
||||
par->ddc_adapter.dev.parent = info->device;
|
||||
if (is_oldclock(par->chip_id)) { /* not sure if this check is OK */
|
||||
par->ddc_algo.setsda = tridentfb_ddc_setsda_tgui;
|
||||
par->ddc_algo.setscl = tridentfb_ddc_setscl_tgui;
|
||||
par->ddc_algo.getsda = tridentfb_ddc_getsda_tgui;
|
||||
/* no getscl */
|
||||
} else {
|
||||
par->ddc_algo.setsda = tridentfb_ddc_setsda;
|
||||
par->ddc_algo.setscl = tridentfb_ddc_setscl;
|
||||
par->ddc_algo.getsda = tridentfb_ddc_getsda;
|
||||
par->ddc_algo.getscl = tridentfb_ddc_getscl;
|
||||
}
|
||||
par->ddc_algo.udelay = 10;
|
||||
par->ddc_algo.timeout = 20;
|
||||
par->ddc_algo.data = par;
|
||||
|
||||
i2c_set_adapdata(&par->ddc_adapter, par);
|
||||
|
||||
return i2c_bit_add_bus(&par->ddc_adapter);
|
||||
}
|
||||
|
||||
/*
|
||||
* Blade specific acceleration.
|
||||
*/
|
||||
@ -1346,6 +1467,7 @@ static int trident_pci_probe(struct pci_dev *dev,
|
||||
struct tridentfb_par *default_par;
|
||||
int chip3D;
|
||||
int chip_id;
|
||||
bool found = false;
|
||||
|
||||
err = pci_enable_device(dev);
|
||||
if (err)
|
||||
@ -1499,6 +1621,7 @@ static int trident_pci_probe(struct pci_dev *dev,
|
||||
info->pixmap.scan_align = 1;
|
||||
info->pixmap.access_align = 32;
|
||||
info->pixmap.flags = FB_PIXMAP_SYSTEM;
|
||||
info->var.bits_per_pixel = 8;
|
||||
|
||||
if (default_par->image_blit) {
|
||||
info->flags |= FBINFO_HWACCEL_IMAGEBLIT;
|
||||
@ -1511,11 +1634,56 @@ static int trident_pci_probe(struct pci_dev *dev,
|
||||
info->pixmap.scan_align = 1;
|
||||
}
|
||||
|
||||
if (!fb_find_mode(&info->var, info,
|
||||
mode_option, NULL, 0, NULL, bpp)) {
|
||||
err = -EINVAL;
|
||||
goto out_unmap2;
|
||||
if (tridentfb_setup_ddc_bus(info) == 0) {
|
||||
u8 *edid = fb_ddc_read(&default_par->ddc_adapter);
|
||||
|
||||
default_par->ddc_registered = true;
|
||||
if (edid) {
|
||||
fb_edid_to_monspecs(edid, &info->monspecs);
|
||||
kfree(edid);
|
||||
if (!info->monspecs.modedb)
|
||||
dev_err(info->device, "error getting mode database\n");
|
||||
else {
|
||||
const struct fb_videomode *m;
|
||||
|
||||
fb_videomode_to_modelist(info->monspecs.modedb,
|
||||
info->monspecs.modedb_len,
|
||||
&info->modelist);
|
||||
m = fb_find_best_display(&info->monspecs,
|
||||
&info->modelist);
|
||||
if (m) {
|
||||
fb_videomode_to_var(&info->var, m);
|
||||
/* fill all other info->var's fields */
|
||||
if (tridentfb_check_var(&info->var,
|
||||
info) == 0)
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mode_option && !found)
|
||||
mode_option = "640x480-8@60";
|
||||
|
||||
/* Prepare startup mode */
|
||||
if (mode_option) {
|
||||
err = fb_find_mode(&info->var, info, mode_option,
|
||||
info->monspecs.modedb,
|
||||
info->monspecs.modedb_len,
|
||||
NULL, info->var.bits_per_pixel);
|
||||
if (!err || err == 4) {
|
||||
err = -EINVAL;
|
||||
dev_err(info->device, "mode %s not found\n",
|
||||
mode_option);
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
info->monspecs.modedb = NULL;
|
||||
goto out_unmap2;
|
||||
}
|
||||
}
|
||||
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
info->monspecs.modedb = NULL;
|
||||
|
||||
err = fb_alloc_cmap(&info->cmap, 256, 0);
|
||||
if (err < 0)
|
||||
goto out_unmap2;
|
||||
@ -1536,6 +1704,8 @@ static int trident_pci_probe(struct pci_dev *dev,
|
||||
return 0;
|
||||
|
||||
out_unmap2:
|
||||
if (default_par->ddc_registered)
|
||||
i2c_del_adapter(&default_par->ddc_adapter);
|
||||
kfree(info->pixmap.addr);
|
||||
if (info->screen_base)
|
||||
iounmap(info->screen_base);
|
||||
@ -1555,6 +1725,8 @@ static void trident_pci_remove(struct pci_dev *dev)
|
||||
struct tridentfb_par *par = info->par;
|
||||
|
||||
unregister_framebuffer(info);
|
||||
if (par->ddc_registered)
|
||||
i2c_del_adapter(&par->ddc_adapter);
|
||||
iounmap(par->io_virt);
|
||||
iounmap(info->screen_base);
|
||||
release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
|
||||
|
Loading…
Reference in New Issue
Block a user