2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-20 08:38:24 +08:00

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (27 commits)
  Staging: sep: return -EFAULT on copy_to_user errors
  Staging: rc2860: return -EFAULT on copy_to_user errors
  Staging: Eliminate a NULL pointer dereference
  staging: Use GFP_ATOMIC when a lock is held
  Staging: comedi - correct parameter gainlkup for DAQCard-6024E in driver ni_mio_cs.c
  Staging: comedi: fixing ni_labpc to mite dependancy
  Staging: wlags49_h2, wlags49_h25: fixed Kconfig dependencies
  Staging: phison: depends on ATA_BMDMA
  Staging: iio-utils: fix memory overflow for dynamically allocateded memory to hold filename
  Staging: adis16255: add proper section markings to hotplug funcs
  Staging: adis16255: fix typo in Kconfig
  Staging: batman-adv: Don't allocate icmp packet with GFP_KERNEL
  Staging: batman-adv: Don't call free_netdev twice
  Staging: batman-adv: Call unregister_netdev on failures to get rtnl lock
  Staging: batman-adv: fix rogue packets on shutdown
  Staging: add MSM framebuffer driver
  Staging: comedi: fixing ni_tio to mite PCI dependancy
  Staging: comedi: fix 8255 and DAS08 Kconfig dependancies.
  Staging: comedi: For COMEDI_BUFINFO, check access to command
  Staging: comedi: COMEDI_BUFINFO with no async - report no bytes read or written
  ...
This commit is contained in:
Linus Torvalds 2010-06-04 15:27:59 -07:00
commit a094c0afc3
135 changed files with 59831 additions and 113 deletions

View File

@ -141,5 +141,11 @@ source "drivers/staging/ti-st/Kconfig"
source "drivers/staging/adis16255/Kconfig"
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/mrst-touchscreen/Kconfig"
source "drivers/staging/msm/Kconfig"
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING

View File

@ -51,3 +51,6 @@ obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
obj-$(CONFIG_MSM_STAGING) += msm/

View File

@ -1,5 +1,5 @@
config ADIS16255
tristate "Ananlog Devices ADIS16250/16255"
tristate "Analog Devices ADIS16250/16255"
depends on SPI && SYSFS
---help---
If you say yes here you get support for the Analog Devices

View File

@ -361,7 +361,7 @@ err:
/*-------------------------------------------------------------------------*/
static int spi_adis16255_probe(struct spi_device *spi)
static int __devinit spi_adis16255_probe(struct spi_device *spi)
{
struct adis16255_init_data *init_data = spi->dev.platform_data;
@ -421,7 +421,7 @@ err:
return status;
}
static int spi_adis16255_remove(struct spi_device *spi)
static int __devexit spi_adis16255_remove(struct spi_device *spi)
{
struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev);

View File

@ -309,7 +309,7 @@ void bat_device_add_packet(struct device_client *device_client,
struct device_packet *device_packet;
unsigned long flags;
device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
device_packet = kmalloc(sizeof(struct device_packet), GFP_ATOMIC);
if (!device_packet)
return;

View File

@ -127,7 +127,10 @@ int init_module(void)
return 0;
unreg_soft_device:
unregister_netdevice(soft_device);
unregister_netdev(soft_device);
soft_device = NULL;
return -ENOMEM;
free_soft_device:
free_netdev(soft_device);
soft_device = NULL;

View File

@ -440,6 +440,9 @@ void send_outstanding_bcast_packet(struct work_struct *work)
hlist_del(&forw_packet->list);
spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
if (atomic_read(&module_state) == MODULE_DEACTIVATING)
goto out;
/* rebroadcast packet */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
@ -453,15 +456,15 @@ void send_outstanding_bcast_packet(struct work_struct *work)
forw_packet->num_packets++;
/* if we still have some more bcasts to send and we are not shutting
* down */
if ((forw_packet->num_packets < 3) &&
(atomic_read(&module_state) != MODULE_DEACTIVATING))
/* if we still have some more bcasts to send */
if (forw_packet->num_packets < 3) {
_add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000));
else {
forw_packet_free(forw_packet);
atomic_inc(&bcast_queue_left);
return;
}
out:
forw_packet_free(forw_packet);
atomic_inc(&bcast_queue_left);
}
void send_outstanding_bat_packet(struct work_struct *work)
@ -476,6 +479,9 @@ void send_outstanding_bat_packet(struct work_struct *work)
hlist_del(&forw_packet->list);
spin_unlock_irqrestore(&forw_bat_list_lock, flags);
if (atomic_read(&module_state) == MODULE_DEACTIVATING)
goto out;
send_packet(forw_packet);
/**
@ -483,10 +489,10 @@ void send_outstanding_bat_packet(struct work_struct *work)
* to determine the queues wake up time unless we are
* shutting down
*/
if ((forw_packet->own) &&
(atomic_read(&module_state) != MODULE_DEACTIVATING))
if (forw_packet->own)
schedule_own_packet(forw_packet->if_incoming);
out:
/* don't count own packet */
if (!forw_packet->own)
atomic_inc(&batman_queue_left);

View File

@ -100,15 +100,6 @@ menuconfig COMEDI_ISA_DRIVERS
if COMEDI_ISA_DRIVERS && ISA
config COMEDI_8255
tristate "Generic 8255 support"
default N
---help---
Enable generic 8255 support.
To compile this driver as a module, choose M here: the module will be
called 8255.
config COMEDI_ACL7225B
tristate "ADlink NuDAQ ACL-7225b and compatibles support"
default N
@ -130,6 +121,7 @@ config COMEDI_PCL711
config COMEDI_PCL724
tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
select COMEDI_8255
default N
---help---
Enable support for Advantech PCL-724, PCL-722, PCL-731 and
@ -198,6 +190,7 @@ config COMEDI_PCL818
config COMEDI_PCM3724
tristate "Advantech PCM-3724 PC/104 card support"
select COMEDI_8255
default N
---help---
Enable support for Advantech PCM-3724 PC/104 cards.
@ -232,18 +225,9 @@ config COMEDI_RTI802
To compile this driver as a module, choose M here: the module will be
called rti802.
config COMEDI_DAS08
tristate "DAS-08 compatible ISA, PC/104 and PCMCIA card support"
default N
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS08
and compatible ISA and PC/104 cards
To compile this driver as a module, choose M here: the module will be
called das08.
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
select COMEDI_FC
default N
---help---
@ -254,6 +238,7 @@ config COMEDI_DAS16M1
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
select COMEDI_8255
select COMEDI_FC
default N
---help---
@ -385,6 +370,7 @@ config COMEDI_FL512
config COMEDI_AIO_AIO12_8
tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
select COMEDI_8255
default N
---help---
Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
@ -466,6 +452,7 @@ config COMEDI_NI_ATMIO
config COMEDI_NI_ATMIO16D
tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_COMMON
select COMEDI_8255
default N
---help---
Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
@ -667,6 +654,7 @@ config COMEDI_ADDI_APCI_3XXX
config COMEDI_ADL_PCI6208
tristate "ADLink PCI-6208A support"
select COMEDI_8255
default N
---help---
Enable support for ADLink PCI-6208A cards
@ -751,6 +739,7 @@ config COMEDI_ADV_PCI1723
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8255
default N
---help---
Enable support for Advantech PCI DIO cards
@ -762,6 +751,7 @@ config COMEDI_ADV_PCI_DIO
config COMEDI_AMPLC_DIO200
tristate "Amplicon PC272E and PCI272 DIO board support"
select COMEDI_8255
default N
---help---
Enable support for Amplicon PC272E and PCI272 DIO boards
@ -771,6 +761,7 @@ config COMEDI_AMPLC_DIO200
config COMEDI_AMPLC_PC236
tristate "Amplicon PC36AT and PCI236 DIO board support"
select COMEDI_8255
default N
---help---
Enable support for Amplicon PC36AT and PCI236 DIO boards
@ -799,6 +790,7 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
select COMEDI_8255
default N
---help---
Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
@ -869,6 +861,7 @@ config COMEDI_II_PCI20KC
config COMEDI_DAQBOARD2000
tristate "IOtech DAQboard/2000 support"
select COMEDI_8255
default N
---help---
Enable support for the IOtech DAQboard/2000
@ -896,6 +889,7 @@ config COMEDI_KE_COUNTER
config COMEDI_CB_PCIDAS64
tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
select COMEDI_8255
select COMEDI_FC
default N
---help---
@ -907,6 +901,7 @@ config COMEDI_CB_PCIDAS64
config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
select COMEDI_8255
select COMEDI_FC
default N
---help---
@ -920,6 +915,7 @@ config COMEDI_CB_PCIDAS
config COMEDI_CB_PCIDDA
tristate "MeasurementComputing PCI-DDA series support"
select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DDA
@ -931,6 +927,7 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIDIO
tristate "MeasurementComputing PCI-DIO series support"
select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
@ -941,6 +938,7 @@ config COMEDI_CB_PCIDIO
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16 support"
select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI Migration
@ -951,6 +949,7 @@ config COMEDI_CB_PCIMDAS
config COMEDI_CB_PCIMDDA
tristate "MeasurementComputing PCIM-DDA06-16 support"
select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
@ -1026,6 +1025,7 @@ config COMEDI_NI_670X
config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
depends on COMEDI_MITE
select COMEDI_8255
default N
---help---
Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
@ -1058,6 +1058,7 @@ config COMEDI_NI_PCIMIO
config COMEDI_RTD520
tristate "Real Time Devices PCI4520/DM7520 support"
select COMEDI_8255
default N
---help---
Enable support for Real Time Devices PCI4520/DM7520
@ -1097,7 +1098,7 @@ endif # COMEDI_PCI_DRIVERS
menuconfig COMEDI_PCMCIA_DRIVERS
tristate "Comedi PCMCIA drivers"
depends on COMEDI && PCMCIA && PCCARD
depends on COMEDI && (PCMCIA || PCCARD)
default N
---help---
Enable comedi PCMCIA and PCCARD drivers to be built
@ -1142,6 +1143,7 @@ config COMEDI_NI_DAQ_700_CS
config COMEDI_NI_DAQ_DIO24_CS
tristate "NI DAQ-Card DIO-24 PCMCIA support"
depends on COMEDI_NI_COMMON
select COMEDI_8255
default N
---help---
Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@ -1162,8 +1164,8 @@ config COMEDI_NI_LABPC_CS
config COMEDI_NI_MIO_CS
tristate "NI DAQCard E series PCMCIA support"
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
default N
select COMEDI_FC
default N
---help---
Enable support for the National Instruments PCMCIA DAQCard E series
DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@ -1265,7 +1267,8 @@ config COMEDI_MITE
config COMEDI_NI_TIO
tristate "NI general purpose counter support"
select COMEDI_MITE
depends on COMEDI_MITE
select COMEDI_8255
default N
---help---
Enable support for National Instruments general purpose counters.
@ -1278,6 +1281,8 @@ config COMEDI_NI_TIO
config COMEDI_NI_LABPC
tristate "NI Lab-PC and compatibles ISA and PCI support"
depends on COMEDI_MITE
select COMEDI_8255
select COMEDI_FC
default N
---help---
@ -1291,8 +1296,40 @@ config COMEDI_NI_LABPC
endif # COMEDI_NI_COMMON
config COMEDI_8255
tristate "Generic 8255 support"
depends on COMEDI
default N
---help---
Enable generic 8255 support.
You should enable compilation this driver if you plan to use a board
that has an 8255 chip. For multifunction boards, the main driver will
configure the 8255 subdevice automatically.
Note that most PCI 8255 boards do NOT work with this driver, and
need a separate driver as a wrapper.
To compile this driver as a module, choose M here: the module will be
called 8255.
config COMEDI_DAS08
tristate "DAS-08 compatible support"
depends on COMEDI
select COMEDI_8255
default N
---help---
Enable support for DAS08 and compatible ISA, PC/104 and PCI cards.
Note that PCMCIA DAS08 cards are not directly supported by this
driver, and need a separate driver as a wrapper.
To compile this driver as a module, choose M here: the module will be
called das08.
config COMEDI_FC
tristate "Comedi shared functions for low-level driver support"
depends on COMEDI
default N
---help---
Enable support for shared functions for low-level drivers.

View File

@ -83,7 +83,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
static int do_chaninfo_ioctl(struct comedi_device *dev,
struct comedi_chaninfo __user *arg);
static int do_bufinfo_ioctl(struct comedi_device *dev,
struct comedi_bufinfo __user *arg);
struct comedi_bufinfo __user *arg, void *file);
static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file);
static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
@ -169,7 +169,8 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
break;
case COMEDI_BUFINFO:
rc = do_bufinfo_ioctl(dev,
(struct comedi_bufinfo __user *)arg);
(struct comedi_bufinfo __user *)arg,
file);
break;
case COMEDI_LOCK:
rc = do_lock_ioctl(dev, arg, file);
@ -563,7 +564,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
*/
static int do_bufinfo_ioctl(struct comedi_device *dev,
struct comedi_bufinfo __user *arg)
struct comedi_bufinfo __user *arg, void *file)
{
struct comedi_bufinfo bi;
struct comedi_subdevice *s;
@ -576,6 +577,10 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
return -EINVAL;
s = dev->subdevices + bi.subdevice;
if (s->lock && s->lock != file)
return -EACCES;
async = s->async;
if (!async) {
@ -584,8 +589,17 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
bi.buf_read_ptr = 0;
bi.buf_write_count = 0;
bi.buf_read_count = 0;
bi.bytes_read = 0;
bi.bytes_written = 0;
goto copyback;
}
if (!s->busy) {
bi.bytes_read = 0;
bi.bytes_written = 0;
goto copyback_position;
}
if (s->busy != file)
return -EACCES;
if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
@ -604,6 +618,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
comedi_buf_write_free(async, bi.bytes_written);
}
copyback_position:
bi.buf_write_count = async->buf_write_count;
bi.buf_write_ptr = async->buf_write_ptr;
bi.buf_read_count = async->buf_read_count;
@ -1576,6 +1591,19 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
while (nbytes > 0 && !retval) {
set_current_state(TASK_INTERRUPTIBLE);
if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
if (count == 0) {
if (comedi_get_subdevice_runflags(s) &
SRF_ERROR) {
retval = -EPIPE;
} else {
retval = 0;
}
do_become_nonbusy(dev, s);
}
break;
}
n = nbytes;
m = n;
@ -1588,16 +1616,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
n = m;
if (n == 0) {
if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
if (comedi_get_subdevice_runflags(s) &
SRF_ERROR) {
retval = -EPIPE;
} else {
retval = 0;
}
do_become_nonbusy(dev, s);
break;
}
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;

View File

@ -12,7 +12,6 @@ obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o
obj-$(CONFIG_COMEDI_SKEL) += skel.o
# Comedi ISA drivers
obj-$(CONFIG_COMEDI_8255) += 8255.o
obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o
obj-$(CONFIG_COMEDI_PCL711) += pcl711.o
obj-$(CONFIG_COMEDI_PCL724) += pcl724.o
@ -26,7 +25,6 @@ obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o
obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o
obj-$(CONFIG_COMEDI_RTI800) += rti800.o
obj-$(CONFIG_COMEDI_RTI802) += rti802.o
obj-$(CONFIG_COMEDI_DAS08) += das08.o
obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o
obj-$(CONFIG_COMEDI_DAS16) += das16.o
obj-$(CONFIG_COMEDI_DAS800) += das800.o
@ -135,4 +133,6 @@ obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o
obj-$(CONFIG_COMEDI_NI_TIO) += ni_tiocmd.o
obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o
obj-$(CONFIG_COMEDI_8255) += 8255.o
obj-$(CONFIG_COMEDI_DAS08) += das08.o
obj-$(CONFIG_COMEDI_FC) += comedi_fc.o

View File

@ -68,6 +68,10 @@ You should also find the complete GPL in the COPYING file accompanying this sour
#include "addi_common.h"
#include "addi_amcc_s5933.h"
#ifndef ADDIDATA_DRIVER_NAME
#define ADDIDATA_DRIVER_NAME "addi_common"
#endif
/* Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>"); */
/* Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); */
/* Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); */
@ -2528,7 +2532,7 @@ static const struct addi_board boardtypes[] = {
#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board))
static struct comedi_driver driver_addi = {
.driver_name = "addi_common",
.driver_name = ADDIDATA_DRIVER_NAME,
.module = THIS_MODULE,
.attach = i_ADDI_Attach,
.detach = i_ADDI_Detach,
@ -2570,10 +2574,6 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct pcilst_struct *card = NULL;
unsigned char pci_bus, pci_slot, pci_func;
int i_Dma = 0;
static char c_Identifier[150];
sprintf(c_Identifier, "Addi-Data GmbH Comedi %s",
this_board->pc_DriverName);
ret = alloc_private(dev, sizeof(struct addi_private));
if (ret < 0)
@ -2583,7 +2583,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
v_pci_card_list_init(this_board->i_VendorId, 1); /* 1 for displaying the list.. */
pci_list_builded = 1;
}
/* printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName); */
/* printk("comedi%d: "ADDIDATA_DRIVER_NAME": board=%s",dev->minor,this_board->pc_DriverName); */
if ((this_board->i_Dma) && (it->options[2] == 0)) {
i_Dma = 1;
@ -2648,7 +2648,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (irq > 0) {
if (request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED,
c_Identifier, dev) < 0) {
this_board->pc_DriverName, dev) < 0) {
printk(", unable to allocate IRQ %u, DISABLING IT",
irq);
irq = 0; /* Can't use IRQ */

View File

@ -2,4 +2,6 @@
#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */
#define ADDIDATA_DRIVER_NAME "addi_apci_035"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_1032 1
#define ADDIDATA_DRIVER_NAME "addi_apci_1032"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_1500 1
#define ADDIDATA_DRIVER_NAME "addi_apci_1500"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_1516 1
#define ADDIDATA_DRIVER_NAME "addi_apci_1516"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_1564 1
#define ADDIDATA_DRIVER_NAME "addi_apci_1564"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_16XX 1
#define ADDIDATA_DRIVER_NAME "addi_apci_16xx"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_1710 1
#define ADDIDATA_DRIVER_NAME "addi_apci_1710"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_2016 1
#define ADDIDATA_DRIVER_NAME "addi_apci_2016"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_2032 1
#define ADDIDATA_DRIVER_NAME "addi_apci_2032"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_2200 1
#define ADDIDATA_DRIVER_NAME "addi_apci_2200"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3001 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3001"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3120 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3120"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3200 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3200"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3300 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3300"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3501 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3501"
#include "addi-data/addi_common.c"

View File

@ -1,3 +1,5 @@
#define CONFIG_APCI_3XXX 1
#define ADDIDATA_DRIVER_NAME "addi_apci_3xxx"
#include "addi-data/addi_common.c"

View File

@ -7,17 +7,17 @@
*/
/*
Driver: adv_pci_dio
Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1736UP,
PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754,
PCI-1756, PCI-1762
Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
PCI-1754, PCI-1756, PCI-1762
Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
PCI-1734, PCI-1736UP, PCI-1750,
PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
PCI-1751, PCI-1752, PCI-1753,
PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
PCI-1760, PCI-1762
Status: untested
Updated: Mon, 14 Apr 2008 10:43:08 +0100
Updated: Tue, 04 May 2010 13:00:00 +0000
This driver supports now only insn interface for DI/DO/DIO.
@ -35,6 +35,7 @@ Configuration options:
#include "comedi_pci.h"
#include "8255.h"
#include "8253.h"
#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */
@ -49,7 +50,7 @@ Configuration options:
/* hardware types of the cards */
enum hw_cards_id {
TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1736,
TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
TYPE_PCI1750,
TYPE_PCI1751,
TYPE_PCI1752,
@ -67,7 +68,10 @@ enum hw_io_access {
#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */
#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */
/* (could be more than one 8254 per subdevice) */
#define SIZE_8254 4 /* 8254 IO space length */
#define SIZE_8255 4 /* 8255 IO space length */
#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
@ -85,6 +89,12 @@ enum hw_io_access {
#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
/* Advantech PCI-1735U */
#define PCI1735_DI 0 /* R: Digital input 0-31 */
#define PCI1735_DO 0 /* W: Digital output 0-31 */
#define PCI1735_C8254 4 /* R/W: 8254 counter */
#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */
/* Advantech PCI-1736UP */
#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */
#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */
@ -192,7 +202,8 @@ static int pci_dio_detach(struct comedi_device *dev);
struct diosubd_data {
int chans; /* num of chans */
int addr; /* PCI address ofset */
int regs; /* number of registers to read or 8255 subdevices */
int regs; /* number of registers to read or 8255
subdevices or 8254 chips */
unsigned int specflags; /* addon subdevice flags */
};
@ -206,6 +217,7 @@ struct dio_boardtype {
struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */
struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */
struct diosubd_data boardid; /* card supports board ID switch */
struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */
enum hw_io_access io_access;
};
@ -214,6 +226,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
@ -235,14 +248,15 @@ static const struct dio_boardtype boardtypes[] = {
{{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
IO_8b,
},
{{0, 0, 0, 0}},
IO_8b},
{"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
TYPE_PCI1733,
{{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_8b},
{"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
TYPE_PCI1734,
@ -250,6 +264,15 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_8b},
{"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
TYPE_PCI1735,
{{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}},
{{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{ 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
{{3, PCI1735_C8254, 1, 0}},
IO_8b},
{"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
TYPE_PCI1736,
@ -257,14 +280,15 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI1736_BOARDID, 1, SDF_INTERNAL},
IO_8b,
},
{{0, 0, 0, 0}},
IO_8b},
{"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
TYPE_PCI1750,
{{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
{{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
{{0, 0, 0, 0}},
IO_8b},
{"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
TYPE_PCI1751,
@ -272,6 +296,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
{{0, 0, 0, 0}},
IO_8b},
{"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
TYPE_PCI1752,
@ -279,6 +304,7 @@ static const struct dio_boardtype boardtypes[] = {
{{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_16b},
{"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753,
@ -286,6 +312,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
{{0, 0, 0, 0}},
IO_8b},
{"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753E,
@ -293,6 +320,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
{0, 0, 0, 0},
{{0, 0, 0, 0}},
IO_8b},
{"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
TYPE_PCI1754,
@ -300,6 +328,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_16b},
{"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
TYPE_PCI1756,
@ -307,6 +336,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_16b},
{"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
TYPE_PCI1760,
@ -314,6 +344,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
{{0, 0, 0, 0}},
IO_8b},
{"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
TYPE_PCI1762,
@ -321,6 +352,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI1762_BOARDID, 1, SDF_INTERNAL},
{{0, 0, 0, 0}},
IO_16b}
};
@ -437,6 +469,83 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
return 2;
}
/*
==============================================================================
*/
static int pci_8254_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
unsigned int chan, chip, chipchan;
unsigned long flags;
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
chip = chan / 3; /* chip on subdevice */
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
spin_lock_irqsave(&s->spin_lock, flags);
data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip),
0, chipchan);
spin_unlock_irqrestore(&s->spin_lock, flags);
return 1;
}
/*
==============================================================================
*/
static int pci_8254_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
unsigned int chan, chip, chipchan;
unsigned long flags;
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
chip = chan / 3; /* chip on subdevice */
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
spin_lock_irqsave(&s->spin_lock, flags);
i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip),
0, chipchan, data[0]);
spin_unlock_irqrestore(&s->spin_lock, flags);
return 1;
}
/*
==============================================================================
*/
static int pci_8254_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
unsigned int chan, chip, chipchan;
unsigned long iobase;
int ret = 0;
unsigned long flags;
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
chip = chan / 3; /* chip on subdevice */
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
iobase = dev->iobase + d->addr + (SIZE_8254 * chip);
spin_lock_irqsave(&s->spin_lock, flags);
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
ret = i8254_set_mode(iobase, 0, chipchan, data[1]);
if (ret < 0)
ret = -EINVAL;
break;
case INSN_CONFIG_8254_READ_STATUS:
data[1] = i8254_status(iobase, 0, chipchan);
break;
default:
ret = -EINVAL;
break;
}
spin_unlock_irqrestore(&s->spin_lock, flags);
return ret < 0 ? ret : insn->n;
}
/*
==============================================================================
*/
@ -708,6 +817,15 @@ static int pci_dio_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCI1734_IDO + 2);
outb(0, dev->iobase + PCI1734_IDO + 3);
break;
case TYPE_PCI1735:
outb(0, dev->iobase + PCI1735_DO); /* clear outputs */
outb(0, dev->iobase + PCI1735_DO + 1);
outb(0, dev->iobase + PCI1735_DO + 2);
outb(0, dev->iobase + PCI1735_DO + 3);
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0);
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0);
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0);
break;
case TYPE_PCI1736:
outb(0, dev->iobase + PCI1736_IDO);
@ -874,6 +992,26 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
/*
==============================================================================
*/
static int pci_dio_add_8254(struct comedi_device *dev,
struct comedi_subdevice * s,
const struct diosubd_data *d, int subdev)
{
s->type = COMEDI_SUBD_COUNTER;
s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
s->n_chan = d->chans;
s->maxdata = 65535;
s->len_chanlist = d->chans;
s->insn_read = pci_8254_insn_read;
s->insn_write = pci_8254_insn_write;
s->insn_config = pci_8254_insn_config;
s->private = (void *)d;
return 0;
}
/*
==============================================================================
*/
@ -979,6 +1117,9 @@ static int pci_dio_attach(struct comedi_device *dev,
n_subdevices += this_board->sdio[i].regs;
if (this_board->boardid.chans)
n_subdevices++;
for (i = 0; i < MAX_8254_SUBDEVS; i++)
if (this_board->s8254[i].chans)
n_subdevices++;
}
ret = alloc_subdevices(dev, n_subdevices);
@ -1022,6 +1163,13 @@ static int pci_dio_attach(struct comedi_device *dev,
subdev++;
}
for (i = 0; i < MAX_8254_SUBDEVS; i++)
if (this_board->s8254[i].chans) {
s = dev->subdevices + subdev;
pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev);
subdev++;
}
if (this_board->cardtype == TYPE_PCI1760)
pci1760_attach(dev, it);
@ -1067,6 +1215,16 @@ static int pci_dio_detach(struct comedi_device *dev)
}
}
if (this_board->boardid.chans) {
subdev++;
}
for (i = 0; i < MAX_8254_SUBDEVS; i++) {
if (this_board->s8254[i].chans) {
subdev++;
}
}
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
s->private = NULL;

View File

@ -460,6 +460,7 @@ struct dio200_subdev_8254 {
int has_clk_gat_sce;
unsigned clock_src[3]; /* Current clock sources */
unsigned gate_src[3]; /* Current gate sources */
spinlock_t spinlock;
};
struct dio200_subdev_intr {
@ -1042,8 +1043,11 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
unsigned long flags;
spin_lock_irqsave(&subpriv->spinlock, flags);
data[0] = i8254_read(subpriv->iobase, 0, chan);
spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
@ -1057,8 +1061,11 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
unsigned long flags;
spin_lock_irqsave(&subpriv->spinlock, flags);
i8254_write(subpriv->iobase, 0, chan, data[0]);
spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
@ -1151,14 +1158,16 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
int ret;
int ret = 0;
int chan = CR_CHAN(insn->chanspec);
unsigned long flags;
spin_lock_irqsave(&subpriv->spinlock, flags);
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
if (ret < 0)
return -EINVAL;
ret = -EINVAL;
break;
case INSN_CONFIG_8254_READ_STATUS:
data[1] = i8254_status(subpriv->iobase, 0, chan);
@ -1166,30 +1175,35 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
case INSN_CONFIG_SET_GATE_SRC:
ret = dio200_set_gate_src(subpriv, chan, data[2]);
if (ret < 0)
return -EINVAL;
ret = -EINVAL;
break;
case INSN_CONFIG_GET_GATE_SRC:
ret = dio200_get_gate_src(subpriv, chan);
if (ret < 0)
return -EINVAL;
if (ret < 0) {
ret = -EINVAL;
break;
}
data[2] = ret;
break;
case INSN_CONFIG_SET_CLOCK_SRC:
ret = dio200_set_clock_src(subpriv, chan, data[1]);
if (ret < 0)
return -EINVAL;
ret = -EINVAL;
break;
case INSN_CONFIG_GET_CLOCK_SRC:
ret = dio200_get_clock_src(subpriv, chan, &data[2]);
if (ret < 0)
return -EINVAL;
if (ret < 0) {
ret = -EINVAL;
break;
}
data[1] = ret;
break;
default:
return -EINVAL;
ret = -EINVAL;
break;
}
return insn->n;
spin_unlock_irqrestore(&subpriv->spinlock, flags);
return ret < 0 ? ret : insn->n;
}
/*
@ -1222,6 +1236,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
s->insn_write = dio200_subdev_8254_write;
s->insn_config = dio200_subdev_8254_config;
spin_lock_init(&subpriv->spinlock);
subpriv->iobase = offset + iobase;
subpriv->has_clk_gat_sce = has_clk_gat_sce;
if (has_clk_gat_sce) {

View File

@ -123,7 +123,7 @@ static const struct ni_board_struct ni_boards[] = {
.adbits = 12,
.ai_fifo_depth = 1024,
.alwaysdither = 0,
.gainlkup = ai_gain_16,
.gainlkup = ai_gain_4,
.ai_speed = 5000,
.n_aochan = 2,
.aobits = 12,

View File

@ -351,8 +351,7 @@ static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
int ret = 0;
if (!this_usbduxsub) {
dev_err(&this_usbduxsub->interface->dev,
"comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
return -EFAULT;
}
dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");

View File

@ -176,9 +176,7 @@ int allocator_free_dma(unsigned long address)
prev = ptr; ptr = ptr->next;
if (!ptr) {
printk(KERN_ERR ALL_MSG
"free_dma(0x%08lx) but add. not allocated\n",
ptr->address);
pr_err(ALL_MSG "free_dma but add. not allocated\n");
return -EINVAL;
}
PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,

View File

@ -62,9 +62,8 @@ inline int find_type_by_name(const char *name, const char *type)
1) != 0) {
filename = malloc(strlen(iio_dir)
+ strlen(type)
+ 1
+ numstrlen
+ 1);
+ 6);
if (filename == NULL)
return -ENOMEM;
sprintf(filename, "%s%s%d/name",

View File

@ -20,7 +20,7 @@ static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring,
if ((length == 0) || (bytes_per_datum == 0))
return -EINVAL;
__iio_update_ring_buffer(&ring->buf, bytes_per_datum, length);
ring->data = kmalloc(length*ring->buf.bpd, GFP_KERNEL);
ring->data = kmalloc(length*ring->buf.bpd, GFP_ATOMIC);
ring->read_p = NULL;
ring->write_p = NULL;
ring->last_written_p = NULL;

View File

@ -0,0 +1,7 @@
config TOUCHSCREEN_INTEL_MID
tristate "Intel MID platform resistive touchscreen"
depends on INTEL_SCU_IPC
default y
help
Say Y here if you have a Intel MID based touchscreen
If unsure, say N.

View File

@ -0,0 +1,3 @@
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o

View File

@ -0,0 +1,2 @@
- Move the driver to not think it is SPI (requires fixing some of the SFI
and firmware side)

View File

@ -0,0 +1,864 @@
/*
* intel_mid_touch.c - Intel MID Resistive Touch Screen Driver
*
* Copyright (C) 2008 Intel Corp
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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; version 2 of the License.
*
* 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; ifnot, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
* Ramesh Agarwal (ramesh.agarwal@intel.com)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* TODO:
* kill off mrstouch_debug eventually
* review conversion of r/m/w sequences
* Replace interrupt mutex abuse
* Kill of mrstouchdevp pointer
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/param.h>
#include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <asm/intel_scu_ipc.h>
#if defined(MRSTOUCH_DEBUG)
#define mrstouch_debug(fmt, args...)\
do { \
printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
printk(KERN_DEBUG fmt, ##args); \
} while (0);
#else
#define mrstouch_debug(fmt, args...)
#endif
/* PMIC Interrupt registers */
#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */
/* PMIC Interrupt registers */
#define PMIC_REG_INT 0x04 /*PMIC interrupt register */
#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */
/* ADC Interrupt registers */
#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */
#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */
/* ADC Control registers */
#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */
/* ADC Channel Selection registers */
#define PMICADDR0 0xA4
#define END_OF_CHANNEL 0x1F
/* ADC Result register */
#define PMIC_REG_ADCSNS0H 0x64
/* ADC channels for touch screen */
#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
/* Touch screen coordinate constants */
#define TOUCH_PRESSURE 50
#define TOUCH_PRESSURE_FS 100
#define XMOVE_LIMIT 5
#define YMOVE_LIMIT 5
#define XYMOVE_CNT 3
#define MAX_10BIT ((1<<10)-1)
/* Touch screen channel BIAS constants */
#define XBIAS 0x20
#define YBIAS 0x40
#define ZBIAS 0x80
/* Touch screen coordinates */
#define MIN_X 10
#define MAX_X 1024
#define MIN_Y 10
#define MAX_Y 1024
#define WAIT_ADC_COMPLETION 10
/* PMIC ADC round robin delays */
#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
/* PMIC Vendor Identifiers */
#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
/* Touch screen device structure */
struct mrstouch_dev {
struct spi_device *spi; /* SPI device associated with touch screen */
struct input_dev *input; /* input device for touchscreen*/
char phys[32]; /* Device name */
struct task_struct *pendet_thrd; /* PENDET interrupt handler */
struct mutex lock; /* Sync between interrupt and PENDET handler */
bool busy; /* Busy flag */
u16 asr; /* Address selection register */
int irq; /* Touch screen IRQ # */
uint vendor; /* PMIC vendor */
uint rev; /* PMIC revision */
bool suspended; /* Device suspended status */
bool disabled; /* Device disabled status */
u16 x; /* X coordinate */
u16 y; /* Y coordinate */
bool pendown; /* PEN position */
} ;
/* Global Pointer to Touch screen device */
static struct mrstouch_dev *mrstouchdevp;
/* Utility to read PMIC ID */
static int mrstouch_pmic_id(uint *vendor, uint *rev)
{
int err;
u8 r;
err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
if (err)
return err;
*vendor = r & 0x7;
*rev = (r >> 3) & 0x7;
return 0;
}
/*
* Parse ADC channels to find end of the channel configured by other ADC user
* NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
*/
static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
{
int err, i, j, found;
u32 r32;
found = -1;
for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
if (found >= 0)
break;
err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
if (err)
return err;
for (j = 0; j < 32; j+= 8) {
if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
found = i;
break;
}
}
}
if (found < 0)
return 0;
if (tsdev->vendor == PMIC_VENDOR_FS) {
if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
return -ENOSPC;
} else {
if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
return -ENOSPC;
}
return found;
}
/* Utility to enable/disable pendet.
* pendet set to true enables PENDET interrupt
* pendet set to false disables PENDET interrupt
* Also clears RND mask bit
*/
static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
{
u16 reg;
u8 r;
u8 pendet_enabled = 0;
int retry = 0;
int err;
err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
if (err)
return err;
if (pendet) {
reg &= ~0x0005;
reg |= 0x2000; /* Enable pendet */
} else
reg &= 0xDFFF; /* Disable pendet */
/* Set MADCINT and update ADCCNTL1 (next reg byte) */
err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
if (!pendet || err)
return err;
/*
* Sometimes even after the register write succeeds
* the PMIC register value is not updated. Retry few iterations
* to enable pendet.
*/
err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
pendet_enabled = (r >> 5) & 0x01;
retry = 0;
while (!err && !pendet_enabled) {
retry++;
msleep(10);
err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8);
if (err)
break;
err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
if (err == 0)
pendet_enabled = (r >> 5) & 0x01;
if (retry >= 10) {
dev_err(&tsdev->spi->dev, "Touch screen disabled.\n");
return -EIO;
}
}
return 0;
}
/* To read PMIC ADC touch screen result
* Reads ADC storage registers for higher 7 and lower 3 bits
* converts the two readings to single value and turns off gain bit
*/
static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
{
int err;
u16 result;
u32 res;
result = PMIC_REG_ADCSNS0H + offset;
if (chan == MRST_TS_CHAN12)
result += 4;
err = intel_scu_ipc_ioread32(result, &res);
if (err)
return err;
/* Mash the bits up */
*vp = (res & 0xFF) << 3; /* Highest 7 bits */
*vp |= (res >> 8) & 0x07; /* Lower 3 bits */
*vp &= 0x3FF;
res >>= 16;
*vm = (res & 0xFF) << 3; /* Highest 7 bits */
*vm |= (res >> 8) & 0x07; /* Lower 3 bits */
*vm &= 0x3FF;
return 0;
}
/* To configure touch screen channels
* Writes touch screen channels to ADC address selection registers
*/
static int mrstouch_ts_chan_set(uint offset)
{
int count;
u16 chan;
u16 reg[5];
u8 data[5];
chan = PMICADDR0 + offset;
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = MRST_TS_CHAN10 + count;
}
reg[count] = chan;
data[count] = END_OF_CHANNEL;
return intel_scu_ipc_writev(reg, data, 5);
}
/* Initialize ADC */
static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
{
int err, start;
u8 ra, rm;
err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
if (err) {
dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
return err;
}
start = mrstouch_chan_parse(tsdev);
if (start < 0) {
dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
return start;
}
tsdev->asr = start;
mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
/* ADC power on, start, enable PENDET and set loop delay
* ADC loop delay is set to 4.5 ms approximately
* Loop delay more than this results in jitter in adc readings
* Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
* interrupt generation sometimes.
*/
if (tsdev->vendor == PMIC_VENDOR_FS) {
ra = 0xE0 | ADC_LOOP_DELAY0;
rm = 0x5;
} else {
/* NEC and MAXIm not consistent with loop delay 0 */
ra = 0xE0 | ADC_LOOP_DELAY1;
rm = 0x0;
/* configure touch screen channels */
err = mrstouch_ts_chan_set(tsdev->asr);
if (err)
return err;
}
err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
if (err == 0)
err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
return err;
}
/* Reports x,y coordinates to event subsystem */
static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
{
int xdiff, ydiff;
if (tsdev->pendown && z <= TOUCH_PRESSURE) {
/* Pen removed, report button release */
mrstouch_debug("BTN REL(%d)", z);
input_report_key(tsdev->input, BTN_TOUCH, 0);
tsdev->pendown = false;
}
xdiff = abs(x - tsdev->x);
ydiff = abs(y - tsdev->y);
/*
if x and y values changes for XYMOVE_CNT readings it is considered
as stylus is moving. This is required to differentiate between stylus
movement and jitter
*/
if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
/* Spurious values, release button if touched and return */
if (tsdev->pendown) {
mrstouch_debug("BTN REL(%d)", z);
input_report_key(tsdev->input, BTN_TOUCH, 0);
tsdev->pendown = false;
}
return;
} else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
tsdev->x = x;
tsdev->y = y;
input_report_abs(tsdev->input, ABS_X, x);
input_report_abs(tsdev->input, ABS_Y, y);
input_sync(tsdev->input);
}
if (!tsdev->pendown && z > TOUCH_PRESSURE) {
/* Pen touched, report button touch */
mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
input_report_key(tsdev->input, BTN_TOUCH, 1);
tsdev->pendown = true;
}
}
/* Utility to start ADC, used by freescale handler */
static int pendet_mask(void)
{
return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
}
/* Utility to stop ADC, used by freescale handler */
static int pendet_umask(void)
{
return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
}
/* Utility to read ADC, used by freescale handler */
static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
{
int err;
u16 x, y, z, result;
u16 reg[4];
u8 data[4];
result = PMIC_REG_ADCSNS0H + tsdev->asr;
reg[0] = result + 4;
reg[1] = result + 5;
reg[2] = result + 16;
reg[3] = result + 17;
err = intel_scu_ipc_readv(reg, data, 4);
if (err)
goto ipc_error;
x = data[0] << 3; /* Higher 7 bits */
x |= data[1] & 0x7; /* Lower 3 bits */
x &= 0x3FF;
y = data[2] << 3; /* Higher 7 bits */
y |= data[3] & 0x7; /* Lower 3 bits */
y &= 0x3FF;
/* Read Z value */
reg[0] = result + 28;
reg[1] = result + 29;
err = intel_scu_ipc_readv(reg, data, 4);
if (err)
goto ipc_error;
z = data[0] << 3; /* Higher 7 bits */
z |= data[1] & 0x7; /* Lower 3 bits */
z &= 0x3FF;
#if defined(MRSTOUCH_PRINT_XYZP)
mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
#endif
if (z >= TOUCH_PRESSURE_FS) {
mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
return TOUCH_PRESSURE - 1;
} else {
mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
return TOUCH_PRESSURE + 1;
}
return 0;
ipc_error:
dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n");
return err;
}
/* To handle free scale pmic pendet interrupt */
static int pmic0_pendet(void *dev_id)
{
int err, count;
u16 chan;
unsigned int touched;
struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
u16 reg[5];
u8 data[5];
chan = PMICADDR0 + tsdev->asr;
/* Set X BIAS */
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = 0x2A;
}
reg[count] = chan++; /* Dummy */
data[count] = 0;
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* Set Y BIAS */
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = 0x4A;
}
reg[count] = chan++; /* Dummy */
data[count] = 0;
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* Set Z BIAS */
err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/*Read touch screen channels till pen removed
* Freescale reports constant value of z for all points
* z is high when screen is not touched and low when touched
* Map high z value to not touched and low z value to pen touched
*/
touched = mrstouch_pmic_fs_adc_read(tsdev);
while (touched > TOUCH_PRESSURE) {
touched = mrstouch_pmic_fs_adc_read(tsdev);
msleep(WAIT_ADC_COMPLETION);
}
/* Clear all TS channels */
chan = PMICADDR0 + tsdev->asr;
for (count = 0; count <= 4; count++) {
reg[count] = chan++;
data[count] = 0;
}
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
for (count = 0; count <= 4; count++) {
reg[count] = chan++;
data[count] = 0;
}
err = intel_scu_ipc_writev(reg, data, 5);
if (err)
goto ipc_error;
err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
if (err)
goto ipc_error;
return 0;
ipc_error:
dev_err(&tsdev->spi->dev, "ipc error during pendet\n");
return err;
}
/* To enable X, Y and Z bias values
* Enables YPYM for X channels and XPXM for Y channels
*/
static int mrstouch_ts_bias_set(uint offset, uint bias)
{
int count;
u16 chan, start;
u16 reg[4];
u8 data[4];
chan = PMICADDR0 + offset;
start = MRST_TS_CHAN10;
for (count = 0; count <= 3; count++) {
reg[count] = chan++;
data[count] = bias | (start + count);
}
return intel_scu_ipc_writev(reg, data, 4);
}
/* To read touch screen channel values */
static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
{
int err;
u16 xp, xm, yp, ym, zp, zm;
/* configure Y bias for X channels */
err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read x+ and x- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
if (err)
goto ipc_error;
/* configure x bias for y channels */
err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read y+ and y- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
if (err)
goto ipc_error;
/* configure z bias for x and y channels */
err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
if (err)
goto ipc_error;
msleep(WAIT_ADC_COMPLETION);
/* read z+ and z- channels */
err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
if (err)
goto ipc_error;
#if defined(MRSTOUCH_PRINT_XYZP)
printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
#endif
#if defined(MRSTOUCH_PRINT_XYZM)
printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
#endif
mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
return zp;
ipc_error:
dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
return err;
}
/* PENDET interrupt handler function for NEC and MAXIM */
static void pmic12_pendet(void *data)
{
unsigned int touched;
struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
/* read touch screen channels till pen removed */
do {
touched = mrstouch_adc_read(tsdev);
} while (touched > TOUCH_PRESSURE);
}
/* Handler to process PENDET interrupt */
int mrstouch_pendet(void *data)
{
struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
while (1) {
/* Wait for PENDET interrupt */
if (mutex_lock_interruptible(&tsdev->lock)) {
msleep(WAIT_ADC_COMPLETION);
continue;
}
if (tsdev->busy)
return 0;
tsdev->busy = true;
if (tsdev->vendor == PMIC_VENDOR_NEC ||
tsdev->vendor == PMIC_VENDOR_MAXIM) {
/* PENDET must be disabled in NEC before reading ADC */
pendet_enable(tsdev,false); /* Disbale PENDET */
pmic12_pendet(tsdev);
pendet_enable(tsdev, true); /*Enable PENDET */
} else if (tsdev->vendor == PMIC_VENDOR_FS) {
pendet_umask(); /* Stop ADC */
pmic0_pendet(tsdev);
pendet_mask(); /* Stop ADC */
} else
dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
tsdev->vendor);
tsdev->busy = false;
}
return 0;
}
/* PENDET interrupt handler */
static irqreturn_t pendet_intr_handler(int irq, void *handle)
{
struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
mutex_unlock(&tsdev->lock);
return IRQ_HANDLED;
}
/* Intializes input device and registers with input subsystem */
static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
{
int err = 0;
mrstouch_debug("%s", __func__);
tsdev->input = input_allocate_device();
if (!tsdev->input) {
dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n");
return -EINVAL;
}
tsdev->input->name = "mrst_touchscreen";
snprintf(tsdev->phys, sizeof(tsdev->phys),
"%s/input0", dev_name(&spi->dev));
tsdev->input->phys = tsdev->phys;
tsdev->input->dev.parent = &spi->dev;
tsdev->input->id.vendor = tsdev->vendor;
tsdev->input->id.version = tsdev->rev;
tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
err = input_register_device(tsdev->input);
if (err) {
dev_err(&tsdev->spi->dev, "unable to register input device\n");
input_free_device(tsdev->input);
return err;
}
mrstouch_debug("%s", "mrstouch initialized");
return 0;
}
/* Probe function for touch screen driver */
static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
{
int err;
unsigned int myirq;
struct mrstouch_dev *tsdev;
mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
mrstouchdevp = NULL;
myirq = mrstouch_spi->irq;
if (!mrstouch_spi->irq) {
dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
return -EINVAL;
}
tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
if (!tsdev) {
dev_err(&mrstouch_spi->dev, "unable to allocate memory\n");
return -ENOMEM;
}
tsdev->irq = myirq;
mrstouchdevp = tsdev;
err = mrstouch_adc_init(tsdev);
if (err) {
dev_err(&mrstouch_spi->dev, "ADC init failed\n");
goto mrstouch_err_free_mem;
}
dev_set_drvdata(&mrstouch_spi->dev, tsdev);
tsdev->spi = mrstouch_spi;
err = ts_input_dev_init(tsdev, mrstouch_spi);
if (err) {
dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
goto mrstouch_err_free_mem;
}
mutex_init(&tsdev->lock);
mutex_lock(&tsdev->lock)
mrstouch_debug("Requesting IRQ-%d", myirq);
err = request_irq(myirq, pendet_intr_handler,
0, "mrstouch", tsdev);
if (err) {
dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
goto mrstouch_err_free_mem;
}
tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
(void *)tsdev, "pendet handler");
if (IS_ERR(tsdev->pendet_thrd)) {
dev_err(&tsdev->spi->dev, "kthread_run failed\n");
err = PTR_ERR(tsdev->pendet_thrd);
goto mrstouch_err_free_mem;
}
mrstouch_debug("%s", "Driver initialized");
return 0;
mrstouch_err_free_mem:
kfree(tsdev);
return err;
}
static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
{
mrstouch_debug("%s", __func__);
mrstouchdevp->suspended = 1;
return 0;
}
static int mrstouch_resume(struct spi_device *spi)
{
mrstouch_debug("%s", __func__);
mrstouchdevp->suspended = 0;
return 0;
}
static int mrstouch_remove(struct spi_device *spi)
{
mrstouch_debug("%s", __func__);
free_irq(mrstouchdevp->irq, mrstouchdevp);
input_unregister_device(mrstouchdevp->input);
input_free_device(mrstouchdevp->input);
kfree(mrstouchdevp);
if (mrstouchdevp->pendet_thrd)
kthread_stop(mrstouchdevp->pendet_thrd);
return 0;
}
static struct spi_driver mrstouch_driver = {
.driver = {
.name = "pmic_touch",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = mrstouch_probe,
.suspend = mrstouch_suspend,
.resume = mrstouch_resume,
.remove = mrstouch_remove,
};
static int __init mrstouch_module_init(void)
{
int err;
mrstouch_debug("%s", __func__);
err = spi_register_driver(&mrstouch_driver);
if (err) {
mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
return -1;
}
return 0;
}
static void __exit mrstouch_module_exit(void)
{
mrstouch_debug("%s", __func__);
spi_unregister_driver(&mrstouch_driver);
return;
}
module_init(mrstouch_module_init);
module_exit(mrstouch_module_exit);
MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
MODULE_LICENSE("GPL");

134
drivers/staging/msm/Kconfig Normal file
View File

@ -0,0 +1,134 @@
config MSM_STAGING
tristate "MSM Frame Buffer Support"
depends on FB && ARCH_MSM && !FB_MSM
select FB_BACKLIGHT if FB_MSM_BACKLIGHT
select NEW_LEDS
select LEDS_CLASS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
Support for MSM Framebuffer.
if MSM_STAGING
config FB_MSM_LCDC_HW
bool
default n
choice
prompt "MDP HW version"
default FB_MSM_MDP31
config FB_MSM_MDP31
select FB_MSM_LCDC_HW
bool "MDP HW ver3.1"
---help---
Support for MSM MDP HW revision 3.1
Say Y here if this is msm8x50 variant platform.
endchoice
config FB_MSM_LCDC
bool
default n
config FB_MSM_TVOUT
bool
default n
config FB_MSM_LCDC_PANEL
bool
select FB_MSM_LCDC
default n
config FB_MSM_LCDC_PRISM_WVGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST1_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_ST15_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
config FB_MSM_LCDC_WXGA
bool
select FB_MSM_LCDC_PANEL
default n
choice
prompt "LCD Panel"
default FB_MSM_LCDC_ST15_PANEL
config FB_MSM_LCDC_PRISM_WVGA_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC Prism WVGA Panel"
select FB_MSM_LCDC_PRISM_WVGA
---help---
Support for LCDC Prism WVGA (800x480) panel
config FB_MSM_LCDC_ST15_PANEL
depends on FB_MSM_LCDC_HW
bool "LCDC ST1.5 Panel"
select FB_MSM_LCDC_ST15_WXGA
---help---
Support for ST1.5 WXGA (1366x768) panel
config FB_MSM_PANEL_NONE
bool "NONE"
---help---
This will disable LCD panel
endchoice
choice
prompt "Secondary LCD Panel"
depends on FB_MSM_MDP31
default FB_MSM_SECONDARY_PANEL_NONE
config FB_MSM_SECONDARY_PANEL_NONE
bool "NONE"
---help---
No secondary panel
endchoice
config FB_MSM_TVOUT_NTSC
bool
select FB_MSM_TVOUT
default n
config FB_MSM_TVOUT_PAL
bool
select FB_MSM_TVOUT
default n
choice
depends on (FB_MSM_MDP22 || FB_MSM_MDP31)
prompt "TVOut Region"
default FB_MSM_TVOUT_NTSC_M
config FB_MSM_TVOUT_NTSC_M
bool "NTSC M"
select FB_MSM_TVOUT_NTSC
---help---
Support for NTSC M region (North American and Korea)
config FB_MSM_TVOUT_NONE
bool "NONE"
---help---
This will disable TV Out functionality.
endchoice
config PMEM_KERNEL_SIZE
int "PMEM for kernel components (in MB)"
default 2
depends on ARCH_QSD8X50
help
Configures the amount of PMEM for use by kernel components
(in MB; minimum 2MB)
endif

View File

@ -0,0 +1,93 @@
obj-y := msm_fb.o staging-devices.o memory.o
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
# MDP
obj-y += mdp.o
ifeq ($(CONFIG_FB_MSM_MDP40),y)
obj-y += mdp4_util.o
obj-$(CONFIG_DEBUG_FS) += mdp4_debugfs.o
else
obj-y += mdp_hw_init.o
obj-y += mdp_ppp.o
ifeq ($(CONFIG_FB_MSM_MDP31),y)
obj-y += mdp_ppp_v31.o
obj-$(CONFIG_MDP_PPP_ASYNC_OP) += mdp_ppp_dq.o
else
obj-y += mdp_ppp_v20.o
endif
endif
ifeq ($(CONFIG_FB_MSM_OVERLAY),y)
obj-y += mdp4_overlay.o
obj-y += mdp4_overlay_lcdc.o
obj-y += mdp4_overlay_mddi.o
else
obj-y += mdp_dma_lcdc.o
endif
obj-y += mdp_dma.o
obj-y += mdp_dma_s.o
obj-y += mdp_vsync.o
obj-y += mdp_cursor.o
obj-y += mdp_dma_tv.o
# EBI2
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
# LCDC
obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
# MDDI
msm_mddi-objs := mddi.o mddihost.o mddihosti.o
obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
# External MDDI
msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
# TVEnc
obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o
# MSM FB Panel
obj-y += msm_fb_panel.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o
obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o
ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y)
obj-y += mddi_prism.o
obj-y += mddi_toshiba.o
obj-y += mddi_toshiba_vga.o
obj-y += mddi_toshiba_wvga_pt.o
obj-y += mddi_toshiba_wvga.o
obj-y += mddi_sharp.o
else
obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o
obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o
endif
obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o
obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o
obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o
obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o
obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o
obj-$(CONFIG_FB_MSM_TVOUT_NTSC) += tv_ntsc.o
obj-$(CONFIG_FB_MSM_TVOUT_PAL) += tv_pal.o
obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
clean:
rm *.o .*cmd

3
drivers/staging/msm/TODO Normal file
View File

@ -0,0 +1,3 @@
- Merge this code with the existing MSM framebuffer
- General style clean ups.

View File

@ -0,0 +1,569 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include <linux/memory.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
/* The following are for MSM5100 on Gator
*/
#ifdef FEATURE_PM1000
#include "pm1000.h"
#endif /* FEATURE_PM1000 */
/* The following are for MSM6050 on Bambi
*/
#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER
#include "pm.h"
#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */
#ifdef DISP_DEVICE_18BPP
#undef DISP_DEVICE_18BPP
#define DISP_DEVICE_16BPP
#endif
#define QCIF_WIDTH 176
#define QCIF_HEIGHT 220
static void *DISP_CMD_PORT;
static void *DISP_DATA_PORT;
#define DISP_CMD_DISON 0xaf
#define DISP_CMD_DISOFF 0xae
#define DISP_CMD_DISNOR 0xa6
#define DISP_CMD_DISINV 0xa7
#define DISP_CMD_DISCTL 0xca
#define DISP_CMD_GCP64 0xcb
#define DISP_CMD_GCP16 0xcc
#define DISP_CMD_GSSET 0xcd
#define DISP_GS_2 0x02
#define DISP_GS_16 0x01
#define DISP_GS_64 0x00
#define DISP_CMD_SLPIN 0x95
#define DISP_CMD_SLPOUT 0x94
#define DISP_CMD_SD_PSET 0x75
#define DISP_CMD_MD_PSET 0x76
#define DISP_CMD_SD_CSET 0x15
#define DISP_CMD_MD_CSET 0x16
#define DISP_CMD_DATCTL 0xbc
#define DISP_DATCTL_666 0x08
#define DISP_DATCTL_565 0x28
#define DISP_DATCTL_444 0x38
#define DISP_CMD_RAMWR 0x5c
#define DISP_CMD_RAMRD 0x5d
#define DISP_CMD_PTLIN 0xa8
#define DISP_CMD_PTLOUT 0xa9
#define DISP_CMD_ASCSET 0xaa
#define DISP_CMD_SCSTART 0xab
#define DISP_CMD_VOLCTL 0xc6
#define DISP_VOLCTL_TONE 0x80
#define DISP_CMD_NOp 0x25
#define DISP_CMD_OSSEL 0xd0
#define DISP_CMD_3500KSET 0xd1
#define DISP_CMD_3500KEND 0xd2
#define DISP_CMD_14MSET 0xd3
#define DISP_CMD_14MEND 0xd4
#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd);
#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data);
#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
/* Epson device column number starts at 2
*/
#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
DISP_CMD_OUT(DISP_CMD_SD_PSET) \
DISP_DATA_OUT((ulhc_row) & 0xFF) \
DISP_DATA_OUT((ulhc_row) >> 8) \
DISP_DATA_OUT((lrhc_row) & 0xFF) \
DISP_DATA_OUT((lrhc_row) >> 8) \
DISP_CMD_OUT(DISP_CMD_SD_CSET) \
DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \
DISP_DATA_OUT(((ulhc_col)+2) >> 8) \
DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \
DISP_DATA_OUT(((lrhc_col)+2) >> 8)
#define DISP_MIN_CONTRAST 0
#define DISP_MAX_CONTRAST 127
#define DISP_DEFAULT_CONTRAST 80
#define DISP_MIN_BACKLIGHT 0
#define DISP_MAX_BACKLIGHT 15
#define DISP_DEFAULT_BACKLIGHT 2
#define WAIT_SEC(sec) mdelay((sec)/1000)
static word disp_area_start_row;
static word disp_area_end_row;
static byte disp_contrast = DISP_DEFAULT_CONTRAST;
static boolean disp_powered_up;
static boolean disp_initialized = FALSE;
/* For some reason the contrast set at init time is not good. Need to do
* it again
*/
static boolean display_on = FALSE;
static void epsonQcif_disp_init(struct platform_device *pdev);
static void epsonQcif_disp_set_contrast(word contrast);
static void epsonQcif_disp_set_display_area(word start_row, word end_row);
static int epsonQcif_disp_off(struct platform_device *pdev);
static int epsonQcif_disp_on(struct platform_device *pdev);
static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres);
volatile word databack;
static void epsonQcif_disp_init(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
int i;
if (disp_initialized)
return;
mfd = platform_get_drvdata(pdev);
DISP_CMD_PORT = mfd->cmd_port;
DISP_DATA_PORT = mfd->data_port;
/* Sleep in */
DISP_CMD_OUT(DISP_CMD_SLPIN);
/* Display off */
DISP_CMD_OUT(DISP_CMD_DISOFF);
/* Display normal */
DISP_CMD_OUT(DISP_CMD_DISNOR);
/* Set data mode */
DISP_CMD_OUT(DISP_CMD_DATCTL);
DISP_DATA_OUT(DISP_DATCTL_565);
/* Set display timing */
DISP_CMD_OUT(DISP_CMD_DISCTL);
DISP_DATA_OUT(0x1c); /* p1 */
DISP_DATA_OUT(0x02); /* p1 */
DISP_DATA_OUT(0x82); /* p2 */
DISP_DATA_OUT(0x00); /* p3 */
DISP_DATA_OUT(0x00); /* p4 */
DISP_DATA_OUT(0xe0); /* p5 */
DISP_DATA_OUT(0x00); /* p5 */
DISP_DATA_OUT(0xdc); /* p6 */
DISP_DATA_OUT(0x00); /* p6 */
DISP_DATA_OUT(0x02); /* p7 */
DISP_DATA_OUT(0x00); /* p8 */
/* Set 64 gray scale level */
DISP_CMD_OUT(DISP_CMD_GCP64);
DISP_DATA_OUT(0x08); /* p01 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x2a); /* p02 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x4e); /* p03 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x6b); /* p04 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x88); /* p05 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xa3); /* p06 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xba); /* p07 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xd1); /* p08 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xe5); /* p09 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0xf3); /* p10 */
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x03); /* p11 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x13); /* p12 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x22); /* p13 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x2f); /* p14 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x3b); /* p15 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x46); /* p16 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x51); /* p17 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x5b); /* p18 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x64); /* p19 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x6c); /* p20 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x74); /* p21 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x7c); /* p22 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x83); /* p23 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x8a); /* p24 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x91); /* p25 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x98); /* p26 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x9f); /* p27 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xa6); /* p28 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xac); /* p29 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xb2); /* p30 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xb7); /* p31 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xbc); /* p32 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xc1); /* p33 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xc6); /* p34 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xcb); /* p35 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd0); /* p36 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd4); /* p37 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xd8); /* p38 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xdc); /* p39 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe0); /* p40 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe4); /* p41 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xe8); /* p42 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xec); /* p43 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf0); /* p44 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf4); /* p45 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xf8); /* p46 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xfb); /* p47 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xfe); /* p48 */
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0x01); /* p49 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x03); /* p50 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x05); /* p51 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x07); /* p52 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x09); /* p53 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0b); /* p54 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0d); /* p55 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x0f); /* p56 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x11); /* p57 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x13); /* p58 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x15); /* p59 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x17); /* p60 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x19); /* p61 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x1b); /* p62 */
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x1c); /* p63 */
DISP_DATA_OUT(0x02);
/* Set 16 gray scale level */
DISP_CMD_OUT(DISP_CMD_GCP16);
DISP_DATA_OUT(0x1a); /* p01 */
DISP_DATA_OUT(0x32); /* p02 */
DISP_DATA_OUT(0x42); /* p03 */
DISP_DATA_OUT(0x4c); /* p04 */
DISP_DATA_OUT(0x58); /* p05 */
DISP_DATA_OUT(0x5f); /* p06 */
DISP_DATA_OUT(0x66); /* p07 */
DISP_DATA_OUT(0x6b); /* p08 */
DISP_DATA_OUT(0x70); /* p09 */
DISP_DATA_OUT(0x74); /* p10 */
DISP_DATA_OUT(0x78); /* p11 */
DISP_DATA_OUT(0x7b); /* p12 */
DISP_DATA_OUT(0x7e); /* p13 */
DISP_DATA_OUT(0x80); /* p14 */
DISP_DATA_OUT(0x82); /* p15 */
/* Set DSP column */
DISP_CMD_OUT(DISP_CMD_MD_CSET);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x03);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x03);
/* Set DSP page */
DISP_CMD_OUT(DISP_CMD_MD_PSET);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x01);
DISP_DATA_OUT(0xff);
DISP_DATA_OUT(0x01);
/* Set ARM column */
DISP_CMD_OUT(DISP_CMD_SD_CSET);
DISP_DATA_OUT(0x02);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF);
DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8);
/* Set ARM page */
DISP_CMD_OUT(DISP_CMD_SD_PSET);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT(0x00);
DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF);
DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8);
/* Set 64 gray scales */
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_64);
DISP_CMD_OUT(DISP_CMD_OSSEL);
DISP_DATA_OUT(0);
/* Sleep out */
DISP_CMD_OUT(DISP_CMD_SLPOUT);
WAIT_SEC(40000);
/* Initialize power IC */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_VOLCTL_TONE);
WAIT_SEC(40000);
/* Set electronic volume, d'xx */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_DEFAULT_CONTRAST); /* value from 0 to 127 */
/* Initialize display data */
DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1));
DISP_CMD_OUT(DISP_CMD_RAMWR);
for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++)
DISP_DATA_OUT(0xffff);
DISP_CMD_OUT(DISP_CMD_RAMRD);
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
databack = DISP_DATA_IN();
WAIT_SEC(80000);
DISP_CMD_OUT(DISP_CMD_DISON);
disp_area_start_row = 0;
disp_area_end_row = QCIF_HEIGHT - 1;
disp_powered_up = TRUE;
disp_initialized = TRUE;
epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1);
display_on = TRUE;
}
static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres)
{
if (!disp_initialized)
return;
DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1);
DISP_CMD_OUT(DISP_CMD_RAMWR);
}
static void epsonQcif_disp_set_display_area(word start_row, word end_row)
{
if (!disp_initialized)
return;
if ((start_row == disp_area_start_row)
&& (end_row == disp_area_end_row))
return;
disp_area_start_row = start_row;
disp_area_end_row = end_row;
/* Range checking
*/
if (end_row >= QCIF_HEIGHT)
end_row = QCIF_HEIGHT - 1;
if (start_row > end_row)
start_row = end_row;
/* When display is not the full screen, gray scale is set to
** 2; otherwise it is set to 64.
*/
if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) {
/* The whole screen */
DISP_CMD_OUT(DISP_CMD_PTLOUT);
WAIT_SEC(10000);
DISP_CMD_OUT(DISP_CMD_DISOFF);
WAIT_SEC(100000);
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_64);
WAIT_SEC(100000);
DISP_CMD_OUT(DISP_CMD_DISON);
} else {
/* partial screen */
DISP_CMD_OUT(DISP_CMD_PTLIN);
DISP_DATA_OUT(start_row);
DISP_DATA_OUT(start_row >> 8);
DISP_DATA_OUT(end_row);
DISP_DATA_OUT(end_row >> 8);
DISP_CMD_OUT(DISP_CMD_GSSET);
DISP_DATA_OUT(DISP_GS_2);
}
}
static int epsonQcif_disp_off(struct platform_device *pdev)
{
if (!disp_initialized)
epsonQcif_disp_init(pdev);
if (display_on) {
DISP_CMD_OUT(DISP_CMD_DISOFF);
DISP_CMD_OUT(DISP_CMD_SLPIN);
display_on = FALSE;
}
return 0;
}
static int epsonQcif_disp_on(struct platform_device *pdev)
{
if (!disp_initialized)
epsonQcif_disp_init(pdev);
if (!display_on) {
DISP_CMD_OUT(DISP_CMD_SLPOUT);
WAIT_SEC(40000);
DISP_CMD_OUT(DISP_CMD_DISON);
epsonQcif_disp_set_contrast(disp_contrast);
display_on = TRUE;
}
return 0;
}
static void epsonQcif_disp_set_contrast(word contrast)
{
if (!disp_initialized)
return;
/* Initialize power IC, d'24 */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
DISP_DATA_OUT(DISP_VOLCTL_TONE);
WAIT_SEC(40000);
/* Set electronic volume, d'xx */
DISP_CMD_OUT(DISP_CMD_VOLCTL);
if (contrast > 127)
contrast = 127;
DISP_DATA_OUT(contrast); /* value from 0 to 127 */
disp_contrast = (byte) contrast;
} /* End disp_set_contrast */
static void epsonQcif_disp_clear_screen_area(
word start_row, word end_row, word start_column, word end_column) {
int32 i;
/* Clear the display screen */
DISP_SET_RECT(start_row, end_row, start_column, end_column);
DISP_CMD_OUT(DISP_CMD_RAMWR);
i = (end_row - start_row + 1) * (end_column - start_column + 1);
for (; i > 0; i--)
DISP_DATA_OUT(0xffff);
}
static int __init epsonQcif_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = epsonQcif_probe,
.driver = {
.name = "ebi2_epson_qcif",
},
};
static struct msm_fb_panel_data epsonQcif_panel_data = {
.on = epsonQcif_disp_on,
.off = epsonQcif_disp_off,
.set_rect = epsonQcif_disp_set_rect,
};
static struct platform_device this_device = {
.name = "ebi2_epson_qcif",
.id = 0,
.dev = {
.platform_data = &epsonQcif_panel_data,
}
};
static int __init epsonQcif_init(void)
{
int ret;
struct msm_panel_info *pinfo;
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &epsonQcif_panel_data.panel_info;
pinfo->xres = QCIF_WIDTH;
pinfo->yres = QCIF_HEIGHT;
pinfo->type = EBI2_PANEL;
pinfo->pdest = DISPLAY_2;
pinfo->wait_cycle = 0x808000;
pinfo->bpp = 16;
pinfo->fb_num = 2;
pinfo->lcd.vsync_enable = FALSE;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(epsonQcif_init);

View File

@ -0,0 +1,250 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include "msm_fb.h"
static int ebi2_lcd_probe(struct platform_device *pdev);
static int ebi2_lcd_remove(struct platform_device *pdev);
static struct platform_driver ebi2_lcd_driver = {
.probe = ebi2_lcd_probe,
.remove = ebi2_lcd_remove,
.suspend = NULL,
.suspend_late = NULL,
.resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "ebi2_lcd",
},
};
static void *ebi2_base;
static void *ebi2_lcd_cfg0;
static void *ebi2_lcd_cfg1;
static void __iomem *lcd01_base;
static void __iomem *lcd02_base;
static int ebi2_lcd_resource_initialized;
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static int ebi2_lcd_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc, i;
if (pdev->id == 0) {
for (i = 0; i < pdev->num_resources; i++) {
if (!strncmp(pdev->resource[i].name, "base", 4)) {
ebi2_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!ebi2_base) {
printk(KERN_ERR
"ebi2_base ioremap failed!\n");
return -ENOMEM;
}
ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20);
ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
} else if (!strncmp(pdev->resource[i].name,
"lcd01", 5)) {
lcd01_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd01_base) {
printk(KERN_ERR
"lcd01_base ioremap failed!\n");
return -ENOMEM;
}
} else if (!strncmp(pdev->resource[i].name,
"lcd02", 5)) {
lcd02_base = ioremap(pdev->resource[i].start,
pdev->resource[i].end -
pdev->resource[i].start + 1);
if (!lcd02_base) {
printk(KERN_ERR
"lcd02_base ioremap failed!\n");
return -ENOMEM;
}
}
}
ebi2_lcd_resource_initialized = 1;
return 0;
}
if (!ebi2_lcd_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
if (ebi2_base == NULL)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/* link to the latest pdev */
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/* add panel data */
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/* data chain */
pdata = mdp_dev->dev.platform_data;
pdata->on = panel_next_on;
pdata->off = panel_next_off;
pdata->next = pdev;
/* get/set panel specific fb info */
mfd->panel_info = pdata->panel_info;
if (mfd->panel_info.bpp == 24)
mfd->fb_imgType = MDP_RGB_888;
else
mfd->fb_imgType = MDP_RGB_565;
/* config msm ebi2 lcd register */
if (mfd->panel_info.pdest == DISPLAY_1) {
outp32(ebi2_base,
(inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) |
EBI2_PRIM_LCD_SEL);
/*
* current design has one set of cfg0/1 register to control
* both EBI2 channels. so, we're using the PRIM channel to
* configure both.
*/
outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
if (mfd->panel_info.bpp == 18)
outp32(ebi2_lcd_cfg1, 0x01000000);
else
outp32(ebi2_lcd_cfg1, 0x0);
} else {
#ifdef DEBUG_EBI2_LCD
/*
* confliting with QCOM SURF FPGA CS.
* OEM should enable below for their CS mapping
*/
outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR)))
|EBI2_SECD_LCD_SEL);
#endif
}
/*
* map cs (chip select) address
*/
if (mfd->panel_info.pdest == DISPLAY_1) {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
} else {
mfd->cmd_port = lcd01_base;
mfd->data_port =
(void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN);
mfd->data_port_phys =
(void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN);
}
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc) {
goto ebi2_lcd_probe_err;
}
pdev_list[pdev_list_cnt++] = pdev;
return 0;
ebi2_lcd_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int ebi2_lcd_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return 0;
if (mfd->key != MFD_KEY)
return 0;
iounmap(mfd->cmd_port);
return 0;
}
static int ebi2_lcd_register_driver(void)
{
return platform_driver_register(&ebi2_lcd_driver);
}
static int __init ebi2_lcd_driver_init(void)
{
return ebi2_lcd_register_driver();
}
module_init(ebi2_lcd_driver_init);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init hdmi_sii_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("hdmi_sii9022"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = HDMI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0;
pinfo.lcdc.underflow_clr = 0xff;
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
static void __exit hdmi_sii_exit(void)
{
i2c_del_driver(&hdmi_sii_i2c_driver);
}
module_init(hdmi_sii_init);
module_exit(hdmi_sii_exit);
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
MODULE_DESCRIPTION("SiI9022 HDMI driver");
MODULE_ALIAS("platform:hdmi-sii9022");

239
drivers/staging/msm/lcdc.c Normal file
View File

@ -0,0 +1,239 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_qos_params.h>
#include "msm_fb.h"
static int lcdc_probe(struct platform_device *pdev);
static int lcdc_remove(struct platform_device *pdev);
static int lcdc_off(struct platform_device *pdev);
static int lcdc_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mdp_lcdc_pclk_clk;
static struct clk *mdp_lcdc_pad_pclk_clk;
int mdp_lcdc_pclk_clk_rate;
int mdp_lcdc_pad_pclk_clk_rate;
static struct platform_driver lcdc_driver = {
.probe = lcdc_probe,
.remove = lcdc_remove,
.suspend = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "lcdc",
},
};
static struct lcdc_platform_data *lcdc_pdata;
static int lcdc_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
clk_disable(mdp_lcdc_pclk_clk);
clk_disable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(0);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(0);
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return ret;
}
static int lcdc_on(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_data_type *mfd;
unsigned long panel_pixclock_freq , pm_qos_freq;
mfd = platform_get_drvdata(pdev);
panel_pixclock_freq = mfd->fbi->var.pixclock;
if (panel_pixclock_freq > 58000000)
/* pm_qos_freq should be in Khz */
pm_qos_freq = panel_pixclock_freq / 1000 ;
else
pm_qos_freq = 58000;
// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// pm_qos_freq);
mfd = platform_get_drvdata(pdev);
clk_enable(mdp_lcdc_pclk_clk);
clk_enable(mdp_lcdc_pad_pclk_clk);
if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
lcdc_pdata->lcdc_power_save(1);
if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
ret = lcdc_pdata->lcdc_gpio_config(1);
clk_set_rate(mdp_lcdc_pclk_clk, mfd->fbi->var.pixclock);
clk_set_rate(mdp_lcdc_pad_pclk_clk, mfd->fbi->var.pixclock);
mdp_lcdc_pclk_clk_rate = clk_get_rate(mdp_lcdc_pclk_clk);
mdp_lcdc_pad_pclk_clk_rate = clk_get_rate(mdp_lcdc_pad_pclk_clk);
ret = panel_next_on(pdev);
return ret;
}
static int lcdc_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
if (pdev->id == 0) {
lcdc_pdata = pdev->dev.platform_data;
return 0;
}
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCDC;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "lcdc_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
pdata->on = lcdc_on;
pdata->off = lcdc_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
fbi = mfd->fbi;
fbi->var.pixclock = mfd->panel_info.clk_rate;
fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto lcdc_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
return 0;
lcdc_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int lcdc_remove(struct platform_device *pdev)
{
// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc");
return 0;
}
static int lcdc_register_driver(void)
{
return platform_driver_register(&lcdc_driver);
}
static int __init lcdc_driver_init(void)
{
mdp_lcdc_pclk_clk = clk_get(NULL, "mdp_lcdc_pclk_clk");
if (IS_ERR(mdp_lcdc_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pclk_clk);
}
mdp_lcdc_pad_pclk_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk");
if (IS_ERR(mdp_lcdc_pad_pclk_clk)) {
printk(KERN_ERR "error: can't get mdp_lcdc_pad_pclk_clk!\n");
return IS_ERR(mdp_lcdc_pad_pclk_clk);
}
// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
// PM_QOS_DEFAULT_VALUE);
return lcdc_register_driver();
}
module_init(lcdc_driver_init);

View File

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_external_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_external"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_external_init);

View File

@ -0,0 +1,446 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#include <mach/gpio.h>
#include "msm_fb.h"
/* registers */
#define GORDON_REG_NOP 0x00
#define GORDON_REG_IMGCTL1 0x10
#define GORDON_REG_IMGCTL2 0x11
#define GORDON_REG_IMGSET1 0x12
#define GORDON_REG_IMGSET2 0x13
#define GORDON_REG_IVBP1 0x14
#define GORDON_REG_IHBP1 0x15
#define GORDON_REG_IVNUM1 0x16
#define GORDON_REG_IHNUM1 0x17
#define GORDON_REG_IVBP2 0x18
#define GORDON_REG_IHBP2 0x19
#define GORDON_REG_IVNUM2 0x1A
#define GORDON_REG_IHNUM2 0x1B
#define GORDON_REG_LCDIFCTL1 0x30
#define GORDON_REG_VALTRAN 0x31
#define GORDON_REG_AVCTL 0x33
#define GORDON_REG_LCDIFCTL2 0x34
#define GORDON_REG_LCDIFCTL3 0x35
#define GORDON_REG_LCDIFSET1 0x36
#define GORDON_REG_PCCTL 0x3C
#define GORDON_REG_TPARAM1 0x40
#define GORDON_REG_TLCDIF1 0x41
#define GORDON_REG_TSSPB_ST1 0x42
#define GORDON_REG_TSSPB_ED1 0x43
#define GORDON_REG_TSCK_ST1 0x44
#define GORDON_REG_TSCK_WD1 0x45
#define GORDON_REG_TGSPB_VST1 0x46
#define GORDON_REG_TGSPB_VED1 0x47
#define GORDON_REG_TGSPB_CH1 0x48
#define GORDON_REG_TGCK_ST1 0x49
#define GORDON_REG_TGCK_ED1 0x4A
#define GORDON_REG_TPCTL_ST1 0x4B
#define GORDON_REG_TPCTL_ED1 0x4C
#define GORDON_REG_TPCHG_ED1 0x4D
#define GORDON_REG_TCOM_CH1 0x4E
#define GORDON_REG_THBP1 0x4F
#define GORDON_REG_TPHCTL1 0x50
#define GORDON_REG_EVPH1 0x51
#define GORDON_REG_EVPL1 0x52
#define GORDON_REG_EVNH1 0x53
#define GORDON_REG_EVNL1 0x54
#define GORDON_REG_TBIAS1 0x55
#define GORDON_REG_TPARAM2 0x56
#define GORDON_REG_TLCDIF2 0x57
#define GORDON_REG_TSSPB_ST2 0x58
#define GORDON_REG_TSSPB_ED2 0x59
#define GORDON_REG_TSCK_ST2 0x5A
#define GORDON_REG_TSCK_WD2 0x5B
#define GORDON_REG_TGSPB_VST2 0x5C
#define GORDON_REG_TGSPB_VED2 0x5D
#define GORDON_REG_TGSPB_CH2 0x5E
#define GORDON_REG_TGCK_ST2 0x5F
#define GORDON_REG_TGCK_ED2 0x60
#define GORDON_REG_TPCTL_ST2 0x61
#define GORDON_REG_TPCTL_ED2 0x62
#define GORDON_REG_TPCHG_ED2 0x63
#define GORDON_REG_TCOM_CH2 0x64
#define GORDON_REG_THBP2 0x65
#define GORDON_REG_TPHCTL2 0x66
#define GORDON_REG_POWCTL 0x80
static int lcdc_gordon_panel_off(struct platform_device *pdev);
static int spi_cs;
static int spi_sclk;
static int spi_sdo;
static int spi_sdi;
static int spi_dac;
static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
(1 << 6),
(1 << 5),
(1 << 4),
(1 << 3),
(1 << 2),
(1 << 1),
(1 << 0) /* LSB */
};
struct gordon_state_type{
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
static struct gordon_state_type gordon_state = { 0 };
static struct msm_panel_common_pdata *lcdc_gordon_pdata;
static void serigo(uint16 reg, uint8 data)
{
unsigned int tx_val = ((0x00FF & reg) << 8) | data;
unsigned char i, val = 0;
/* Enable the Chip Select */
gpio_set_value(spi_cs, 1);
udelay(33);
/* Transmit it in two parts, Higher Byte first, then Lower Byte */
val = (unsigned char)((tx_val & 0xFF00) >> 8);
/* Clock should be Low before entering ! */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_sdi, 1);
else
gpio_set_value(spi_sdi, 0);
/* #2: Drive the Clk High and then Low */
udelay(33);
gpio_set_value(spi_sclk, 1);
udelay(33);
gpio_set_value(spi_sclk, 0);
}
/* Idle state of SDO (MOSI) is Low */
gpio_set_value(spi_sdi, 0);
/* ..then Lower Byte */
val = (uint8) (tx_val & 0x00FF);
/* Before we enter here the Clock should be Low ! */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_sdi, 1);
else
gpio_set_value(spi_sdi, 0);
/* #2: Drive the Clk High and then Low */
udelay(33);
gpio_set_value(spi_sclk, 1);
udelay(33);
gpio_set_value(spi_sclk, 0);
}
/* Idle state of SDO (MOSI) is Low */
gpio_set_value(spi_sdi, 0);
/* Now Disable the Chip Select */
udelay(33);
gpio_set_value(spi_cs, 0);
}
static void spi_init(void)
{
/* Setting the Default GPIO's */
spi_sclk = *(lcdc_gordon_pdata->gpio_num);
spi_cs = *(lcdc_gordon_pdata->gpio_num + 1);
spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2);
spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3);
/* Set the output so that we dont disturb the slave device */
gpio_set_value(spi_sclk, 0);
gpio_set_value(spi_sdi, 0);
/* Set the Chip Select De-asserted */
gpio_set_value(spi_cs, 0);
}
static void gordon_disp_powerup(void)
{
if (!gordon_state.disp_powered_up && !gordon_state.display_on) {
/* Reset the hardware first */
/* Include DAC power up implementation here */
gordon_state.disp_powered_up = TRUE;
}
}
static void gordon_init(void)
{
/* Image interface settings */
serigo(GORDON_REG_IMGCTL2, 0x00);
serigo(GORDON_REG_IMGSET1, 0x00);
/* Exchange the RGB signal for J510(Softbank mobile) */
serigo(GORDON_REG_IMGSET2, 0x12);
serigo(GORDON_REG_LCDIFSET1, 0x00);
/* Pre-charge settings */
serigo(GORDON_REG_PCCTL, 0x09);
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
mdelay(1);
}
static void gordon_disp_on(void)
{
if (gordon_state.disp_powered_up && !gordon_state.display_on) {
gordon_init();
mdelay(20);
/* gordon_dispmode setting */
serigo(GORDON_REG_TPARAM1, 0x30);
serigo(GORDON_REG_TLCDIF1, 0x00);
serigo(GORDON_REG_TSSPB_ST1, 0x8B);
serigo(GORDON_REG_TSSPB_ED1, 0x93);
serigo(GORDON_REG_TSCK_ST1, 0x88);
serigo(GORDON_REG_TSCK_WD1, 0x00);
serigo(GORDON_REG_TGSPB_VST1, 0x01);
serigo(GORDON_REG_TGSPB_VED1, 0x02);
serigo(GORDON_REG_TGSPB_CH1, 0x5E);
serigo(GORDON_REG_TGCK_ST1, 0x80);
serigo(GORDON_REG_TGCK_ED1, 0x3C);
serigo(GORDON_REG_TPCTL_ST1, 0x50);
serigo(GORDON_REG_TPCTL_ED1, 0x74);
serigo(GORDON_REG_TPCHG_ED1, 0x78);
serigo(GORDON_REG_TCOM_CH1, 0x50);
serigo(GORDON_REG_THBP1, 0x84);
serigo(GORDON_REG_TPHCTL1, 0x00);
serigo(GORDON_REG_EVPH1, 0x70);
serigo(GORDON_REG_EVPL1, 0x64);
serigo(GORDON_REG_EVNH1, 0x56);
serigo(GORDON_REG_EVNL1, 0x48);
serigo(GORDON_REG_TBIAS1, 0x88);
/* QVGA settings */
serigo(GORDON_REG_TPARAM2, 0x28);
serigo(GORDON_REG_TLCDIF2, 0x14);
serigo(GORDON_REG_TSSPB_ST2, 0x49);
serigo(GORDON_REG_TSSPB_ED2, 0x4B);
serigo(GORDON_REG_TSCK_ST2, 0x4A);
serigo(GORDON_REG_TSCK_WD2, 0x02);
serigo(GORDON_REG_TGSPB_VST2, 0x02);
serigo(GORDON_REG_TGSPB_VED2, 0x03);
serigo(GORDON_REG_TGSPB_CH2, 0x2F);
serigo(GORDON_REG_TGCK_ST2, 0x40);
serigo(GORDON_REG_TGCK_ED2, 0x1E);
serigo(GORDON_REG_TPCTL_ST2, 0x2C);
serigo(GORDON_REG_TPCTL_ED2, 0x3A);
serigo(GORDON_REG_TPCHG_ED2, 0x3C);
serigo(GORDON_REG_TCOM_CH2, 0x28);
serigo(GORDON_REG_THBP2, 0x4D);
serigo(GORDON_REG_TPHCTL2, 0x1A);
/* VGA settings */
serigo(GORDON_REG_IVBP1, 0x02);
serigo(GORDON_REG_IHBP1, 0x90);
serigo(GORDON_REG_IVNUM1, 0xA0);
serigo(GORDON_REG_IHNUM1, 0x78);
/* QVGA settings */
serigo(GORDON_REG_IVBP2, 0x02);
serigo(GORDON_REG_IHBP2, 0x48);
serigo(GORDON_REG_IVNUM2, 0x50);
serigo(GORDON_REG_IHNUM2, 0x3C);
/* Gordon Charge pump settings and ON */
serigo(GORDON_REG_POWCTL, 0x03);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x07);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x0F);
mdelay(15);
serigo(GORDON_REG_AVCTL, 0x03);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x1F);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x5F);
mdelay(15);
serigo(GORDON_REG_POWCTL, 0x7F);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL1, 0x02);
mdelay(15);
serigo(GORDON_REG_IMGCTL1, 0x00);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL3, 0x00);
mdelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
mdelay(15);
serigo(GORDON_REG_LCDIFCTL1, 0x03);
mdelay(1);
gordon_state.display_on = TRUE;
}
}
static int lcdc_gordon_panel_on(struct platform_device *pdev)
{
if (!gordon_state.disp_initialized) {
/* Configure reset GPIO that drives DAC */
lcdc_gordon_pdata->panel_config_gpio(1);
spi_dac = *(lcdc_gordon_pdata->gpio_num + 4);
gpio_set_value(spi_dac, 0);
udelay(15);
gpio_set_value(spi_dac, 1);
spi_init(); /* LCD needs SPI */
gordon_disp_powerup();
gordon_disp_on();
gordon_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_gordon_panel_off(struct platform_device *pdev)
{
if (gordon_state.disp_powered_up && gordon_state.display_on) {
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
serigo(GORDON_REG_VALTRAN, 0x01);
serigo(GORDON_REG_LCDIFCTL1, 0x02);
serigo(GORDON_REG_LCDIFCTL3, 0x01);
mdelay(20);
serigo(GORDON_REG_VALTRAN, 0x01);
serigo(GORDON_REG_IMGCTL1, 0x01);
serigo(GORDON_REG_LCDIFCTL1, 0x00);
mdelay(20);
serigo(GORDON_REG_POWCTL, 0x1F);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x07);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x03);
mdelay(40);
serigo(GORDON_REG_POWCTL, 0x00);
mdelay(40);
lcdc_gordon_pdata->panel_config_gpio(0);
gordon_state.display_on = FALSE;
gordon_state.disp_initialized = FALSE;
}
return 0;
}
static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level = mfd->bl_level;
if (bl_level <= 1) {
/* keep back light OFF */
serigo(GORDON_REG_LCDIFCTL2, 0x0B);
udelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
} else {
/* keep back light ON */
serigo(GORDON_REG_LCDIFCTL2, 0x7B);
udelay(15);
serigo(GORDON_REG_VALTRAN, 0x01);
}
}
static int __init gordon_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_gordon_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = gordon_probe,
.driver = {
.name = "lcdc_gordon_vga",
},
};
static struct msm_fb_panel_data gordon_panel_data = {
.on = lcdc_gordon_panel_on,
.off = lcdc_gordon_panel_off,
.set_backlight = lcdc_gordon_set_backlight,
};
static struct platform_device this_device = {
.name = "lcdc_gordon_vga",
.id = 1,
.dev = {
.platform_data = &gordon_panel_data,
}
};
static int __init lcdc_gordon_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (msm_fb_detect_client("lcdc_gordon_vga"))
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &gordon_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 640;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 24;
pinfo->fb_num = 2;
pinfo->clk_rate = 24500000;
pinfo->bl_max = 4;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 84;
pinfo->lcdc.h_front_porch = 33;
pinfo->lcdc.h_pulse_width = 60;
pinfo->lcdc.v_back_porch = 0;
pinfo->lcdc.v_front_porch = 2;
pinfo->lcdc.v_pulse_width = 2;
pinfo->lcdc.border_clr = 0; /* blk */
pinfo->lcdc.underflow_clr = 0xff; /* blue */
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
module_init(lcdc_gordon_panel_init);

View File

@ -0,0 +1,60 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_grapefruit_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (msm_fb_detect_client("lcdc_grapefruit_vga"))
return 0;
#endif
pinfo.xres = 1024;
pinfo.yres = 600;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 40000000;
pinfo.lcdc.h_back_porch = 88;
pinfo.lcdc.h_front_porch = 40;
pinfo.lcdc.h_pulse_width = 128;
pinfo.lcdc.v_back_porch = 23;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 4;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_grapefruit_init);

View File

@ -0,0 +1,88 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int lcdc_panel_on(struct platform_device *pdev)
{
return 0;
}
static int lcdc_panel_off(struct platform_device *pdev)
{
return 0;
}
static int __init lcdc_panel_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = lcdc_panel_probe,
.driver = {
.name = "lcdc_panel",
},
};
static struct msm_fb_panel_data lcdc_panel_data = {
.on = lcdc_panel_on,
.off = lcdc_panel_off,
};
static int lcdc_dev_id;
int lcdc_device_register(struct msm_panel_info *pinfo)
{
struct platform_device *pdev = NULL;
int ret;
pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id);
if (!pdev)
return -ENOMEM;
lcdc_panel_data.panel_info = *pinfo;
ret = platform_device_add_data(pdev, &lcdc_panel_data,
sizeof(lcdc_panel_data));
if (ret) {
printk(KERN_ERR
"%s: platform_device_add_data failed!\n", __func__);
goto err_device_put;
}
ret = platform_device_add(pdev);
if (ret) {
printk(KERN_ERR
"%s: platform_device_register failed!\n", __func__);
goto err_device_put;
}
return 0;
err_device_put:
platform_device_put(pdev);
return ret;
}
static int __init lcdc_panel_init(void)
{
return platform_driver_register(&this_driver);
}
module_init(lcdc_panel_init);

View File

@ -0,0 +1,64 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int __init lcdc_prism_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
ret = msm_fb_detect_client("lcdc_prism_wvga");
if (ret == -ENODEV)
return 0;
if (ret && (mddi_get_client_id() != 0))
return 0;
#endif
pinfo.xres = 800;
pinfo.yres = 480;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 38460000;
pinfo.lcdc.h_back_porch = 21;
pinfo.lcdc.h_front_porch = 81;
pinfo.lcdc.h_pulse_width = 60;
pinfo.lcdc.v_back_porch = 18;
pinfo.lcdc.v_front_porch = 27;
pinfo.lcdc.v_pulse_width = 2;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_prism_init);

View File

@ -0,0 +1,290 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#ifdef CONFIG_ARCH_MSM7X30
#include <linux/mfd/pmic8058.h>
#endif
#include <mach/gpio.h>
#include "msm_fb.h"
static int lcdc_sharp_panel_off(struct platform_device *pdev);
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
(1 << 6),
(1 << 5),
(1 << 4),
(1 << 3),
(1 << 2),
(1 << 1),
(1 << 0) /* LSB */
};
struct sharp_state_type {
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
struct sharp_spi_data {
u8 addr;
u8 data;
};
static struct sharp_spi_data init_sequence[] = {
{ 15, 0x01 },
{ 5, 0x01 },
{ 7, 0x10 },
{ 9, 0x1E },
{ 10, 0x04 },
{ 17, 0xFF },
{ 21, 0x8A },
{ 22, 0x00 },
{ 23, 0x82 },
{ 24, 0x24 },
{ 25, 0x22 },
{ 26, 0x6D },
{ 27, 0xEB },
{ 28, 0xB9 },
{ 29, 0x3A },
{ 49, 0x1A },
{ 50, 0x16 },
{ 51, 0x05 },
{ 55, 0x7F },
{ 56, 0x15 },
{ 57, 0x7B },
{ 60, 0x05 },
{ 61, 0x0C },
{ 62, 0x80 },
{ 63, 0x00 },
{ 92, 0x90 },
{ 97, 0x01 },
{ 98, 0xFF },
{ 113, 0x11 },
{ 114, 0x02 },
{ 115, 0x08 },
{ 123, 0xAB },
{ 124, 0x04 },
{ 6, 0x02 },
{ 133, 0x00 },
{ 134, 0xFE },
{ 135, 0x22 },
{ 136, 0x0B },
{ 137, 0xFF },
{ 138, 0x0F },
{ 139, 0x00 },
{ 140, 0xFE },
{ 141, 0x22 },
{ 142, 0x0B },
{ 143, 0xFF },
{ 144, 0x0F },
{ 145, 0x00 },
{ 146, 0xFE },
{ 147, 0x22 },
{ 148, 0x0B },
{ 149, 0xFF },
{ 150, 0x0F },
{ 202, 0x30 },
{ 30, 0x01 },
{ 4, 0x01 },
{ 31, 0x41 },
};
static struct sharp_state_type sharp_state = { 0 };
static struct msm_panel_common_pdata *lcdc_sharp_pdata;
static void sharp_spi_write_byte(u8 val)
{
int i;
/* Clock should be Low before entering */
for (i = 0; i < 8; i++) {
/* #1: Drive the Data (High or Low) */
if (val & bit_shift[i])
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
/* #2: Drive the Clk High and then Low */
gpio_set_value(spi_sclk, 1);
gpio_set_value(spi_sclk, 0);
}
}
static void serigo(u8 reg, u8 data)
{
/* Enable the Chip Select - low */
gpio_set_value(spi_cs, 0);
udelay(1);
/* Transmit register address first, then data */
sharp_spi_write_byte(reg);
/* Idle state of MOSI is Low */
gpio_set_value(spi_mosi, 0);
udelay(1);
sharp_spi_write_byte(data);
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_cs, 1);
}
static void sharp_spi_init(void)
{
spi_sclk = *(lcdc_sharp_pdata->gpio_num);
spi_cs = *(lcdc_sharp_pdata->gpio_num + 1);
spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2);
spi_miso = *(lcdc_sharp_pdata->gpio_num + 3);
/* Set the output so that we don't disturb the slave device */
gpio_set_value(spi_sclk, 0);
gpio_set_value(spi_mosi, 0);
/* Set the Chip Select deasserted (active low) */
gpio_set_value(spi_cs, 1);
}
static void sharp_disp_powerup(void)
{
if (!sharp_state.disp_powered_up && !sharp_state.display_on)
sharp_state.disp_powered_up = TRUE;
}
static void sharp_disp_on(void)
{
int i;
if (sharp_state.disp_powered_up && !sharp_state.display_on) {
for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
serigo(init_sequence[i].addr,
init_sequence[i].data);
}
mdelay(10);
serigo(31, 0xC1);
mdelay(10);
serigo(31, 0xD9);
serigo(31, 0xDF);
sharp_state.display_on = TRUE;
}
}
static int lcdc_sharp_panel_on(struct platform_device *pdev)
{
if (!sharp_state.disp_initialized) {
lcdc_sharp_pdata->panel_config_gpio(1);
sharp_spi_init();
sharp_disp_powerup();
sharp_disp_on();
sharp_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_sharp_panel_off(struct platform_device *pdev)
{
if (sharp_state.disp_powered_up && sharp_state.display_on) {
serigo(4, 0x00);
mdelay(40);
serigo(31, 0xC1);
mdelay(40);
serigo(31, 0x00);
mdelay(100);
sharp_state.display_on = FALSE;
sharp_state.disp_initialized = FALSE;
}
return 0;
}
static int __init sharp_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_sharp_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = sharp_probe,
.driver = {
.name = "lcdc_sharp_wvga",
},
};
static struct msm_fb_panel_data sharp_panel_data = {
.on = lcdc_sharp_panel_on,
.off = lcdc_sharp_panel_off,
};
static struct platform_device this_device = {
.name = "lcdc_sharp_wvga",
.id = 1,
.dev = {
.platform_data = &sharp_panel_data,
}
};
static int __init lcdc_sharp_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_sharp_wvga_pt"))
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &sharp_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 24500000;
pinfo->bl_max = 4;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 20;
pinfo->lcdc.h_front_porch = 10;
pinfo->lcdc.h_pulse_width = 10;
pinfo->lcdc.v_back_porch = 2;
pinfo->lcdc.v_front_porch = 2;
pinfo->lcdc.v_pulse_width = 2;
pinfo->lcdc.border_clr = 0;
pinfo->lcdc.underflow_clr = 0xff;
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
module_init(lcdc_sharp_panel_init);

View File

@ -0,0 +1,237 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/i2c.h>
#include <linux/delay.h>
#include "msm_fb.h"
#define DEVICE_NAME "sii9022"
#define SII9022_DEVICE_ID 0xB0
struct sii9022_i2c_addr_data{
u8 addr;
u8 data;
};
/* video mode data */
static u8 video_mode_data[] = {
0x00,
0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
};
static u8 avi_io_format[] = {
0x09,
0x00, 0x00,
};
/* power state */
static struct sii9022_i2c_addr_data regset0[] = {
{ 0x60, 0x04 },
{ 0x63, 0x00 },
{ 0x1E, 0x00 },
};
static u8 video_infoframe[] = {
0x0C,
0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
};
/* configure audio */
static struct sii9022_i2c_addr_data regset1[] = {
{ 0x26, 0x90 },
{ 0x20, 0x90 },
{ 0x1F, 0x80 },
{ 0x26, 0x80 },
{ 0x24, 0x02 },
{ 0x25, 0x0B },
{ 0xBC, 0x02 },
{ 0xBD, 0x24 },
{ 0xBE, 0x02 },
};
/* enable audio */
static u8 misc_infoframe[] = {
0xBF,
0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* set HDMI, active */
static struct sii9022_i2c_addr_data regset2[] = {
{ 0x1A, 0x01 },
{ 0x3D, 0x00 },
};
static int send_i2c_data(struct i2c_client *client,
struct sii9022_i2c_addr_data *regset,
int size)
{
int i;
int rc = 0;
for (i = 0; i < size; i++) {
rc = i2c_smbus_write_byte_data(
client,
regset[i].addr, regset[i].data);
if (rc)
break;
}
return rc;
}
static int hdmi_sii_enable(struct i2c_client *client)
{
int rc;
int retries = 10;
int count;
rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
if (rc)
goto enable_exit;
do {
msleep(1);
rc = i2c_smbus_read_byte_data(client, 0x1B);
} while ((rc != SII9022_DEVICE_ID) && retries--);
if (rc != SII9022_DEVICE_ID)
return -ENODEV;
rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_mode_data);
rc = i2c_master_send(client, video_mode_data, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
if (rc)
goto enable_exit;
count = ARRAY_SIZE(avi_io_format);
rc = i2c_master_send(client, avi_io_format, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(video_infoframe);
rc = i2c_master_send(client, video_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
if (rc)
goto enable_exit;
count = ARRAY_SIZE(misc_infoframe);
rc = i2c_master_send(client, misc_infoframe, count);
if (rc != count) {
rc = -EIO;
goto enable_exit;
}
rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
if (rc)
goto enable_exit;
return 0;
enable_exit:
printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
return rc;
}
static const struct i2c_device_id hmdi_sii_id[] = {
{ DEVICE_NAME, 0 },
{ }
};
static int hdmi_sii_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -ENODEV;
rc = hdmi_sii_enable(client);
return rc;
}
static struct i2c_driver hdmi_sii_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = hdmi_sii_probe,
.remove = __exit_p(hdmi_sii_remove),
.id_table = hmdi_sii_id,
};
static int __init lcdc_st15_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st15"))
return 0;
pinfo.xres = 1366;
pinfo.yres = 768;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 120;
pinfo.lcdc.h_front_porch = 20;
pinfo.lcdc.h_pulse_width = 40;
pinfo.lcdc.v_back_porch = 25;
pinfo.lcdc.v_front_porch = 1;
pinfo.lcdc.v_pulse_width = 7;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
goto init_exit;
}
ret = i2c_add_driver(&hdmi_sii_i2c_driver);
if (ret)
printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
init_exit:
return ret;
}
module_init(lcdc_st15_init);

View File

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_st1_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
if (msm_fb_detect_client("lcdc_st1_wxga"))
return 0;
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_st1_wxga_init);

View File

@ -0,0 +1,374 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <mach/gpio.h>
#include <mach/pmic.h>
#include "msm_fb.h"
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
#include "mddihosti.h"
#endif
static int spi_cs;
static int spi_sclk;
static int spi_mosi;
static int spi_miso;
struct toshiba_state_type{
boolean disp_initialized;
boolean display_on;
boolean disp_powered_up;
};
static struct toshiba_state_type toshiba_state = { 0 };
static struct msm_panel_common_pdata *lcdc_toshiba_pdata;
static void toshiba_spi_write_byte(char dc, uint8 data)
{
uint32 bit;
int bnum;
gpio_set_value(spi_sclk, 0); /* clk low */
/* dc: 0 for command, 1 for parameter */
gpio_set_value(spi_mosi, dc);
udelay(1); /* at least 20 ns */
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1); /* at least 20 ns */
bnum = 8; /* 8 data bits */
bit = 0x80;
while (bnum) {
gpio_set_value(spi_sclk, 0); /* clk low */
if (data & bit)
gpio_set_value(spi_mosi, 1);
else
gpio_set_value(spi_mosi, 0);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
udelay(1);
bit >>= 1;
bnum--;
}
}
static void toshiba_spi_write(char cmd, uint32 data, int num)
{
char *bp;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
/* followed by parameter bytes */
if (num) {
bp = (char *)&data;;
bp += (num - 1);
while (num) {
toshiba_spi_write_byte(1, *bp);
num--;
bp--;
}
}
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
void toshiba_spi_read_bytes(char cmd, uint32 *data, int num)
{
uint32 dbit, bits;
int bnum;
gpio_set_value(spi_cs, 1); /* cs high */
/* command byte first */
toshiba_spi_write_byte(0, cmd);
if (num > 1) {
/* extra dc bit */
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);/* dc bit */
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
}
/* followed by data bytes */
bnum = num * 8; /* number of bits */
bits = 0;
while (bnum) {
bits <<= 1;
gpio_set_value(spi_sclk, 0); /* clk low */
udelay(1);
dbit = gpio_get_value(spi_miso);
udelay(1);
gpio_set_value(spi_sclk, 1); /* clk high */
bits |= dbit;
bnum--;
}
*data = bits;
udelay(1);
gpio_set_value(spi_cs, 0); /* cs low */
udelay(1);
}
static void spi_pin_assign(void)
{
/* Setting the Default GPIO's */
spi_sclk = *(lcdc_toshiba_pdata->gpio_num);
spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1);
spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2);
spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3);
}
static void toshiba_disp_powerup(void)
{
if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) {
/* Reset the hardware first */
/* Include DAC power up implementation here */
toshiba_state.disp_powered_up = TRUE;
}
}
static void toshiba_disp_on(void)
{
uint32 data;
gpio_set_value(spi_cs, 0); /* low */
gpio_set_value(spi_sclk, 1); /* high */
gpio_set_value(spi_mosi, 0);
gpio_set_value(spi_miso, 0);
if (toshiba_state.disp_powered_up && !toshiba_state.display_on) {
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0, 0, 0);
mdelay(7);
toshiba_spi_write(0xba, 0x11, 1);
toshiba_spi_write(0x36, 0x00, 1);
mdelay(1);
toshiba_spi_write(0x3a, 0x60, 1);
toshiba_spi_write(0xb1, 0x5d, 1);
mdelay(1);
toshiba_spi_write(0xb2, 0x33, 1);
toshiba_spi_write(0xb3, 0x22, 1);
mdelay(1);
toshiba_spi_write(0xb4, 0x02, 1);
toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */
mdelay(1);
toshiba_spi_write(0xb6, 0x27, 1);
toshiba_spi_write(0xb7, 0x03, 1);
mdelay(1);
toshiba_spi_write(0xb9, 0x24, 1);
toshiba_spi_write(0xbd, 0xa1, 1);
mdelay(1);
toshiba_spi_write(0xbb, 0x00, 1);
toshiba_spi_write(0xbf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xbe, 0x00, 1);
toshiba_spi_write(0xc0, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc1, 0x11, 1);
toshiba_spi_write(0xc2, 0x11, 1);
mdelay(1);
toshiba_spi_write(0xc3, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc4, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc5, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc6, 0x3232, 2);
mdelay(1);
toshiba_spi_write(0xc7, 0x6445, 2);
mdelay(1);
toshiba_spi_write(0xc8, 0x44, 1);
toshiba_spi_write(0xc9, 0x52, 1);
mdelay(1);
toshiba_spi_write(0xca, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */
mdelay(1);
toshiba_spi_write(0xcf, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */
mdelay(1);
toshiba_spi_write(0xd1, 0x01, 1);
mdelay(1);
toshiba_spi_write(0xd2, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd3, 0x0028, 2);
mdelay(1);
toshiba_spi_write(0xd4, 0x26a4, 2);
mdelay(1);
toshiba_spi_write(0xd5, 0x20, 1);
mdelay(1);
toshiba_spi_write(0xef, 0x3200, 2);
mdelay(32);
toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */
toshiba_spi_write(0x3b, 0x00, 1);
mdelay(1);
toshiba_spi_write(0xb0, 0x16, 1);
mdelay(1);
toshiba_spi_write(0xb8, 0xfff5, 2);
mdelay(1);
toshiba_spi_write(0x11, 0, 0);
mdelay(5);
toshiba_spi_write(0x29, 0, 0);
mdelay(5);
toshiba_state.display_on = TRUE;
}
data = 0;
toshiba_spi_read_bytes(0x04, &data, 3);
printk(KERN_INFO "toshiba_disp_on: id=%x\n", data);
}
static int lcdc_toshiba_panel_on(struct platform_device *pdev)
{
if (!toshiba_state.disp_initialized) {
/* Configure reset GPIO that drives DAC */
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(1);
toshiba_disp_powerup();
toshiba_disp_on();
toshiba_state.disp_initialized = TRUE;
}
return 0;
}
static int lcdc_toshiba_panel_off(struct platform_device *pdev)
{
if (toshiba_state.disp_powered_up && toshiba_state.display_on) {
/* Main panel power off (Deep standby in) */
toshiba_spi_write(0x28, 0, 0); /* display off */
mdelay(1);
toshiba_spi_write(0xb8, 0x8002, 2); /* output control */
mdelay(1);
toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */
mdelay(85); /* wait 85 msec */
toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */
mdelay(1);
if (lcdc_toshiba_pdata->panel_config_gpio)
lcdc_toshiba_pdata->panel_config_gpio(0);
toshiba_state.display_on = FALSE;
toshiba_state.disp_initialized = FALSE;
}
return 0;
}
static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
int ret = -EPERM;
bl_level = mfd->bl_level;
ret = pmic_set_led_intensity(LED_LCD, bl_level);
if (ret)
printk(KERN_WARNING "%s: can't set lcd backlight!\n",
__func__);
}
static int __init toshiba_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
lcdc_toshiba_pdata = pdev->dev.platform_data;
spi_pin_assign();
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = toshiba_probe,
.driver = {
.name = "lcdc_toshiba_wvga",
},
};
static struct msm_fb_panel_data toshiba_panel_data = {
.on = lcdc_toshiba_panel_on,
.off = lcdc_toshiba_panel_off,
.set_backlight = lcdc_toshiba_set_backlight,
};
static struct platform_device this_device = {
.name = "lcdc_toshiba_wvga",
.id = 1,
.dev = {
.platform_data = &toshiba_panel_data,
}
};
static int __init lcdc_toshiba_panel_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
if (mddi_get_client_id() != 0)
return 0;
ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt");
if (ret)
return 0;
#endif
ret = platform_driver_register(&this_driver);
if (ret)
return ret;
pinfo = &toshiba_panel_data.panel_info;
pinfo->xres = 480;
pinfo->yres = 800;
pinfo->type = LCDC_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
/* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */
pinfo->clk_rate = 27648000;
pinfo->bl_max = 15;
pinfo->bl_min = 1;
pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */
pinfo->lcdc.h_front_porch = 4;
pinfo->lcdc.h_pulse_width = 8;
pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */
pinfo->lcdc.v_front_porch = 3;
pinfo->lcdc.v_pulse_width = 1;
pinfo->lcdc.border_clr = 0; /* blk */
pinfo->lcdc.underflow_clr = 0xff; /* blue */
pinfo->lcdc.hsync_skew = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
return ret;
}
device_initcall(lcdc_toshiba_panel_init);

View File

@ -0,0 +1,56 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
static int __init lcdc_wxga_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("lcdc_wxga"))
return 0;
#endif
pinfo.xres = 1280;
pinfo.yres = 720;
pinfo.type = LCDC_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.wait_cycle = 0;
pinfo.bpp = 24;
pinfo.fb_num = 2;
pinfo.clk_rate = 74250000;
pinfo.lcdc.h_back_porch = 124;
pinfo.lcdc.h_front_porch = 110;
pinfo.lcdc.h_pulse_width = 136;
pinfo.lcdc.v_back_porch = 19;
pinfo.lcdc.v_front_porch = 5;
pinfo.lcdc.v_pulse_width = 6;
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
ret = lcdc_device_register(&pinfo);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(lcdc_wxga_init);

View File

@ -0,0 +1,98 @@
/* drivers/video/msm/logo.c
*
* Show Logo in RLE 565 format
*
* Copyright (C) 2008 Google Incorporated
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fb.h>
#include <linux/vt_kern.h>
#include <linux/unistd.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
#include <asm/system.h>
#define fb_width(fb) ((fb)->var.xres)
#define fb_height(fb) ((fb)->var.yres)
#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2)
static void memset16(void *_ptr, unsigned short val, unsigned count)
{
unsigned short *ptr = _ptr;
count >>= 1;
while (count--)
*ptr++ = val;
}
/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
int load_565rle_image(char *filename)
{
struct fb_info *info;
int fd, err = 0;
unsigned count, max;
unsigned short *data, *bits, *ptr;
info = registered_fb[0];
if (!info) {
printk(KERN_WARNING "%s: Can not access framebuffer\n",
__func__);
return -ENODEV;
}
fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0) {
printk(KERN_WARNING "%s: Can not open %s\n",
__func__, filename);
return -ENOENT;
}
count = (unsigned)sys_lseek(fd, (off_t)0, 2);
if (count == 0) {
sys_close(fd);
err = -EIO;
goto err_logo_close_file;
}
sys_lseek(fd, (off_t)0, 0);
data = kmalloc(count, GFP_KERNEL);
if (!data) {
printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
err = -ENOMEM;
goto err_logo_close_file;
}
if ((unsigned)sys_read(fd, (char *)data, count) != count) {
err = -EIO;
goto err_logo_free_data;
}
max = fb_width(info) * fb_height(info);
ptr = data;
bits = (unsigned short *)(info->screen_base);
while (count > 3) {
unsigned n = ptr[0];
if (n > max)
break;
memset16(bits, ptr[1], n << 1);
bits += n;
max -= n;
ptr += 2;
count -= 4;
}
err_logo_free_data:
kfree(data);
err_logo_close_file:
sys_close(fd);
return err;
}
EXPORT_SYMBOL(load_565rle_image);

375
drivers/staging/msm/mddi.c Normal file
View File

@ -0,0 +1,375 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include "msm_fb.h"
#include "mddihosti.h"
#include "mddihost.h"
#include <mach/gpio.h>
#include <mach/clk.h>
static int mddi_probe(struct platform_device *pdev);
static int mddi_remove(struct platform_device *pdev);
static int mddi_off(struct platform_device *pdev);
static int mddi_on(struct platform_device *pdev);
static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
static int mddi_resume(struct platform_device *pdev);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h);
static void mddi_early_resume(struct early_suspend *h);
#endif
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static struct clk *mddi_clk;
static struct clk *mddi_pclk;
static struct mddi_platform_data *mddi_pdata;
static struct platform_driver mddi_driver = {
.probe = mddi_probe,
.remove = mddi_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend = mddi_suspend,
.resume = mddi_resume,
#endif
#endif
.suspend_late = NULL,
.resume_early = NULL,
.shutdown = NULL,
.driver = {
.name = "mddi",
},
};
extern int int_mddi_pri_flag;
static int mddi_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
return ret;
}
static int mddi_on(struct platform_device *pdev)
{
int ret = 0;
u32 clk_rate;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n",
__func__);
ret = panel_next_on(pdev);
return ret;
}
static int mddi_resource_initialized;
static int mddi_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
resource_size_t size ;
u32 clk_rate;
if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
mddi_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
msm_pmdh_base = ioremap(pdev->resource[0].start, size);
MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
pdev->resource[0].start, (int) msm_pmdh_base);
if (unlikely(!msm_pmdh_base))
return -ENOMEM;
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(1);
mddi_resource_initialized = 1;
return 0;
}
if (!mddi_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_LCD;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = mddi_on;
pdata->off = mddi_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
clk_rate = mfd->panel_info.clk_max;
if (mddi_pdata &&
mddi_pdata->mddi_sel_clk &&
mddi_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto mddi_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
mfd->mddi_early_suspend.suspend = mddi_early_suspend;
mfd->mddi_early_suspend.resume = mddi_early_resume;
register_early_suspend(&mfd->mddi_early_suspend);
#endif
return 0;
mddi_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int mddi_pad_ctrl;
static int mddi_power_locked;
static int mddi_is_in_suspend;
void mddi_disable(int lock)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (mddi_power_locked)
return;
if (lock)
mddi_power_locked = 1;
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
mddi_host_reg_out(PAD_CTL, 0x0);
if (clk_set_min_rate(mddi_clk, 0) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
clk_disable(mddi_clk);
if (mddi_pclk)
clk_disable(mddi_pclk);
disable_irq(INT_MDDI_PRI);
if (mddi_pdata && mddi_pdata->mddi_power_save)
mddi_pdata->mddi_power_save(0);
}
static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
{
if (mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 1;
mddi_disable(0);
return 0;
}
static int mddi_resume(struct platform_device *pdev)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
if (!mddi_is_in_suspend)
return 0;
mddi_is_in_suspend = 0;
if (mddi_power_locked)
return 0;
enable_irq(INT_MDDI_PRI);
clk_enable(mddi_clk);
if (mddi_pclk)
clk_enable(mddi_pclk);
mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
if (mddi_host_timer.function)
mddi_host_timer_service(0);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_early_suspend(struct early_suspend *h)
{
pm_message_t state;
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
state.event = PM_EVENT_SUSPEND;
mddi_suspend(mfd->pdev, state);
}
static void mddi_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_early_suspend);
mddi_resume(mfd->pdev);
}
#endif
static int mddi_remove(struct platform_device *pdev)
{
if (mddi_host_timer.function)
del_timer_sync(&mddi_host_timer);
iounmap(msm_pmdh_base);
return 0;
}
static int mddi_register_driver(void)
{
return platform_driver_register(&mddi_driver);
}
static int __init mddi_driver_init(void)
{
int ret;
mddi_clk = clk_get(NULL, "mddi_clk");
if (IS_ERR(mddi_clk)) {
printk(KERN_ERR "can't find mddi_clk \n");
return PTR_ERR(mddi_clk);
}
clk_enable(mddi_clk);
mddi_pclk = clk_get(NULL, "mddi_pclk");
if (IS_ERR(mddi_pclk))
mddi_pclk = NULL;
else
clk_enable(mddi_pclk);
ret = mddi_register_driver();
if (ret) {
clk_disable(mddi_clk);
clk_put(mddi_clk);
if (mddi_pclk) {
clk_disable(mddi_pclk);
clk_put(mddi_pclk);
}
printk(KERN_ERR "mddi_register_driver() failed!\n");
return ret;
}
mddi_init();
return ret;
}
module_init(mddi_driver_init);

View File

@ -0,0 +1,320 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <mach/clk.h>
#include <linux/platform_device.h>
#include "msm_fb.h"
#include "mddihosti.h"
static int mddi_ext_probe(struct platform_device *pdev);
static int mddi_ext_remove(struct platform_device *pdev);
static int mddi_ext_off(struct platform_device *pdev);
static int mddi_ext_on(struct platform_device *pdev);
static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
static int pdev_list_cnt;
static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state);
static int mddi_ext_resume(struct platform_device *pdev);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_ext_early_suspend(struct early_suspend *h);
static void mddi_ext_early_resume(struct early_suspend *h);
#endif
static struct platform_driver mddi_ext_driver = {
.probe = mddi_ext_probe,
.remove = mddi_ext_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend = mddi_ext_suspend,
.resume = mddi_ext_resume,
#endif
#endif
.resume_early = NULL,
.resume = NULL,
.shutdown = NULL,
.driver = {
.name = "mddi_ext",
},
};
static struct clk *mddi_ext_clk;
static struct mddi_platform_data *mddi_ext_pdata;
extern int int_mddi_ext_flag;
static int mddi_ext_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
mddi_host_stop_ext_display();
return ret;
}
static int mddi_ext_on(struct platform_device *pdev)
{
int ret = 0;
u32 clk_rate;
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
clk_rate = mfd->fbi->var.pixclock;
clk_rate = min(clk_rate, mfd->panel_info.clk_max);
if (mddi_ext_pdata &&
mddi_ext_pdata->mddi_sel_clk &&
mddi_ext_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n",
__func__);
mddi_host_start_ext_display();
ret = panel_next_on(pdev);
return ret;
}
static int mddi_ext_resource_initialized;
static int mddi_ext_probe(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct platform_device *mdp_dev = NULL;
struct msm_fb_panel_data *pdata = NULL;
int rc;
resource_size_t size ;
u32 clk_rate;
if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
mddi_ext_pdata = pdev->dev.platform_data;
size = resource_size(&pdev->resource[0]);
msm_emdh_base = ioremap(pdev->resource[0].start, size);
MSM_FB_INFO("external mddi base address = 0x%x\n",
pdev->resource[0].start);
if (unlikely(!msm_emdh_base))
return -ENOMEM;
mddi_ext_resource_initialized = 1;
return 0;
}
if (!mddi_ext_resource_initialized)
return -EPERM;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
return -ENOMEM;
mdp_dev = platform_device_alloc("mdp", pdev->id);
if (!mdp_dev)
return -ENOMEM;
/*
* link to the latest pdev
*/
mfd->pdev = mdp_dev;
mfd->dest = DISPLAY_EXT_MDDI;
/*
* alloc panel device data
*/
if (platform_device_add_data
(mdp_dev, pdev->dev.platform_data,
sizeof(struct msm_fb_panel_data))) {
printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n");
platform_device_put(mdp_dev);
return -ENOMEM;
}
/*
* data chain
*/
pdata = mdp_dev->dev.platform_data;
pdata->on = mddi_ext_on;
pdata->off = mddi_ext_off;
pdata->next = pdev;
/*
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
mfd->fb_imgType = MDP_RGB_565;
clk_rate = mfd->panel_info.clk_max;
if (mddi_ext_pdata &&
mddi_ext_pdata->mddi_sel_clk &&
mddi_ext_pdata->mddi_sel_clk(&clk_rate))
printk(KERN_ERR
"%s: can't select mddi io clk targate rate = %d\n",
__func__, clk_rate);
if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0)
printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
/*
* set driver data
*/
platform_set_drvdata(mdp_dev, mfd);
/*
* register in mdp driver
*/
rc = platform_device_add(mdp_dev);
if (rc)
goto mddi_ext_probe_err;
pdev_list[pdev_list_cnt++] = pdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend;
mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume;
register_early_suspend(&mfd->mddi_ext_early_suspend);
#endif
return 0;
mddi_ext_probe_err:
platform_device_put(mdp_dev);
return rc;
}
static int mddi_ext_is_in_suspend;
static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state)
{
if (mddi_ext_is_in_suspend)
return 0;
mddi_ext_is_in_suspend = 1;
if (clk_set_min_rate(mddi_ext_clk, 0) < 0)
printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
clk_disable(mddi_ext_clk);
disable_irq(INT_MDDI_EXT);
return 0;
}
static int mddi_ext_resume(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mddi_ext_is_in_suspend)
return 0;
mddi_ext_is_in_suspend = 0;
enable_irq(INT_MDDI_EXT);
clk_enable(mddi_ext_clk);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void mddi_ext_early_suspend(struct early_suspend *h)
{
pm_message_t state;
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_ext_early_suspend);
state.event = PM_EVENT_SUSPEND;
mddi_ext_suspend(mfd->pdev, state);
}
static void mddi_ext_early_resume(struct early_suspend *h)
{
struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
mddi_ext_early_suspend);
mddi_ext_resume(mfd->pdev);
}
#endif
static int mddi_ext_remove(struct platform_device *pdev)
{
iounmap(msm_emdh_base);
return 0;
}
static int mddi_ext_register_driver(void)
{
return platform_driver_register(&mddi_ext_driver);
}
static int __init mddi_ext_driver_init(void)
{
int ret;
mddi_ext_clk = clk_get(NULL, "emdh_clk");
if (IS_ERR(mddi_ext_clk)) {
printk(KERN_ERR "can't find emdh_clk\n");
return PTR_ERR(mddi_ext_clk);
}
clk_enable(mddi_ext_clk);
ret = mddi_ext_register_driver();
if (ret) {
clk_disable(mddi_ext_clk);
clk_put(mddi_ext_clk);
printk(KERN_ERR "mddi_ext_register_driver() failed!\n");
return ret;
}
mddi_init();
return ret;
}
module_init(mddi_ext_driver_init);

View File

@ -0,0 +1,91 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
static int mddi_ext_lcd_on(struct platform_device *pdev);
static int mddi_ext_lcd_off(struct platform_device *pdev);
static int mddi_ext_lcd_on(struct platform_device *pdev)
{
return 0;
}
static int mddi_ext_lcd_off(struct platform_device *pdev)
{
return 0;
}
static int __init mddi_ext_lcd_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = mddi_ext_lcd_probe,
.driver = {
.name = "extmddi_svga",
},
};
static struct msm_fb_panel_data mddi_ext_lcd_panel_data = {
.panel_info.xres = 800,
.panel_info.yres = 600,
.panel_info.type = EXT_MDDI_PANEL,
.panel_info.pdest = DISPLAY_1,
.panel_info.wait_cycle = 0,
.panel_info.bpp = 18,
.panel_info.fb_num = 2,
.panel_info.clk_rate = 122880000,
.panel_info.clk_min = 120000000,
.panel_info.clk_max = 125000000,
.on = mddi_ext_lcd_on,
.off = mddi_ext_lcd_off,
};
static struct platform_device this_device = {
.name = "extmddi_svga",
.id = 0,
.dev = {
.platform_data = &mddi_ext_lcd_panel_data,
}
};
static int __init mddi_ext_lcd_init(void)
{
int ret;
struct msm_panel_info *pinfo;
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &mddi_ext_lcd_panel_data.panel_info;
pinfo->lcd.vsync_enable = FALSE;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(mddi_ext_lcd_init);

View File

@ -0,0 +1,114 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
static int prism_lcd_on(struct platform_device *pdev);
static int prism_lcd_off(struct platform_device *pdev);
static int prism_lcd_on(struct platform_device *pdev)
{
/* Set the MDP pixel data attributes for Primary Display */
mddi_host_write_pix_attr_reg(0x00C3);
return 0;
}
static int prism_lcd_off(struct platform_device *pdev)
{
return 0;
}
static int __init prism_probe(struct platform_device *pdev)
{
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = prism_probe,
.driver = {
.name = "mddi_prism_wvga",
},
};
static struct msm_fb_panel_data prism_panel_data = {
.on = prism_lcd_on,
.off = prism_lcd_off,
};
static struct platform_device this_device = {
.name = "mddi_prism_wvga",
.id = 0,
.dev = {
.platform_data = &prism_panel_data,
}
};
static int __init prism_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_prism_wvga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (((id >> 16) != 0x4474) || ((id & 0xffff) == 0x8960))
return 0;
}
#endif
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &prism_panel_data.panel_info;
pinfo->xres = 800;
pinfo->yres = 480;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 153600000;
pinfo->clk_min = 150000000;
pinfo->clk_max = 160000000;
pinfo->lcd.vsync_enable = TRUE;
pinfo->lcd.refx100 = 6050;
pinfo->lcd.v_back_porch = 23;
pinfo->lcd.v_front_porch = 20;
pinfo->lcd.v_pulse_width = 105;
pinfo->lcd.hw_vsync_mode = TRUE;
pinfo->lcd.vsync_notifier_period = 0;
ret = platform_device_register(&this_device);
if (ret)
platform_driver_unregister(&this_driver);
}
return ret;
}
module_init(prism_init);

View File

@ -0,0 +1,892 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#define SHARP_QVGA_PRIM 1
#define SHARP_128X128_SECD 2
extern uint32 mddi_host_core_version;
static boolean mddi_debug_prim_wait = FALSE;
static boolean mddi_sharp_vsync_wake = TRUE;
static boolean mddi_sharp_monitor_refresh_value = TRUE;
static boolean mddi_sharp_report_refresh_measurements = FALSE;
static uint32 mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
static uint32 mddi_sharp_rows_per_refresh = 338;
static uint32 mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
static boolean mddi_sharp_debug_60hz_refresh = FALSE;
extern mddi_gpio_info_type mddi_gpio;
extern boolean mddi_vsync_detect_enabled;
static msm_fb_vsync_handler_type mddi_sharp_vsync_handler;
static void *mddi_sharp_vsync_handler_arg;
static uint16 mddi_sharp_vsync_attempts;
static void mddi_sharp_prim_lcd_init(void);
static void mddi_sharp_sub_lcd_init(void);
static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd);
static void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler,
void *);
static void mddi_sharp_lcd_vsync_detected(boolean detected);
static struct msm_panel_common_pdata *mddi_sharp_pdata;
#define REG_SYSCTL 0x0000
#define REG_INTR 0x0006
#define REG_CLKCNF 0x000C
#define REG_CLKDIV1 0x000E
#define REG_CLKDIV2 0x0010
#define REG_GIOD 0x0040
#define REG_GIOA 0x0042
#define REG_AGM 0x010A
#define REG_FLFT 0x0110
#define REG_FRGT 0x0112
#define REG_FTOP 0x0114
#define REG_FBTM 0x0116
#define REG_FSTRX 0x0118
#define REG_FSTRY 0x011A
#define REG_VRAM 0x0202
#define REG_SSDCTL 0x0330
#define REG_SSD0 0x0332
#define REG_PSTCTL1 0x0400
#define REG_PSTCTL2 0x0402
#define REG_PTGCTL 0x042A
#define REG_PTHP 0x042C
#define REG_PTHB 0x042E
#define REG_PTHW 0x0430
#define REG_PTHF 0x0432
#define REG_PTVP 0x0434
#define REG_PTVB 0x0436
#define REG_PTVW 0x0438
#define REG_PTVF 0x043A
#define REG_VBLKS 0x0458
#define REG_VBLKE 0x045A
#define REG_SUBCTL 0x0700
#define REG_SUBTCMD 0x0702
#define REG_SUBTCMDD 0x0704
#define REG_REVBYTE 0x0A02
#define REG_REVCNT 0x0A04
#define REG_REVATTR 0x0A06
#define REG_REVFMT 0x0A08
#define SHARP_SUB_UNKNOWN 0xffffffff
#define SHARP_SUB_HYNIX 1
#define SHARP_SUB_ROHM 2
static uint32 sharp_subpanel_type = SHARP_SUB_UNKNOWN;
static void sub_through_write(int sub_rs, uint32 sub_data)
{
mddi_queue_register_write(REG_SUBTCMDD, sub_data, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=0,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0004 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
}
static uint32 sub_through_read(int sub_rs)
{
uint32 sub_data;
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=0,RD=1,WE=0,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0002 | sub_rs, TRUE, 0);
mddi_queue_register_read(REG_SUBTCMDD, &sub_data, TRUE, 0);
/* CS=0,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=sub_rs */
mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
return sub_data;
}
static void serigo(uint32 ssd)
{
uint32 ssdctl;
mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
ssdctl = ((ssdctl & 0xE7) | 0x02);
mddi_queue_register_write(REG_SSD0, ssd, FALSE, 0);
mddi_queue_register_write(REG_SSDCTL, ssdctl, TRUE, 0);
do {
mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
} while ((ssdctl & 0x0002) != 0);
if (mddi_debug_prim_wait)
mddi_wait(2);
}
static void mddi_sharp_lcd_powerdown(void)
{
serigo(0x0131);
serigo(0x0300);
mddi_wait(40);
serigo(0x0135);
mddi_wait(20);
serigo(0x2122);
mddi_wait(20);
serigo(0x0201);
mddi_wait(20);
serigo(0x2100);
mddi_wait(20);
serigo(0x2000);
mddi_wait(20);
mddi_queue_register_write(REG_PSTCTL1, 0x1, TRUE, 0);
mddi_wait(100);
mddi_queue_register_write(REG_PSTCTL1, 0x0, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_SYSCTL, 0x1, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_CLKDIV1, 0x3, TRUE, 0);
mddi_wait(2);
mddi_queue_register_write(REG_SSDCTL, 0x0000, TRUE, 0); /* SSDRESET */
mddi_queue_register_write(REG_SYSCTL, 0x0, TRUE, 0);
mddi_wait(2);
}
static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd)
{
uint32 regdata;
int32 level;
int max = mfd->panel_info.bl_max;
int min = mfd->panel_info.bl_min;
if (mddi_sharp_pdata && mddi_sharp_pdata->backlight_level) {
level = mddi_sharp_pdata->backlight_level(mfd->bl_level,
max,
min);
if (level < 0)
return;
/* use Rodem GPIO(2:0) to give 8 levels of backlight (7-0) */
/* Set lower 3 GPIOs as Outputs (set to 0) */
mddi_queue_register_read(REG_GIOA, &regdata, TRUE, 0);
mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0);
/* Set lower 3 GPIOs as level */
mddi_queue_register_read(REG_GIOD, &regdata, TRUE, 0);
mddi_queue_register_write(REG_GIOD,
(regdata & 0xfff8) | (0x07 & level), TRUE, 0);
}
}
static void mddi_sharp_prim_lcd_init(void)
{
mddi_queue_register_write(REG_SYSCTL, 0x4000, TRUE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
mddi_wait(5);
mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
/* new reg write below */
if (mddi_sharp_debug_60hz_refresh)
mddi_queue_register_write(REG_CLKCNF, 0x070d, FALSE, 0);
else
mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
mddi_queue_register_write(REG_PTHW, 240, FALSE, 0);
if (mddi_sharp_debug_60hz_refresh)
mddi_queue_register_write(REG_PTHF, 12, FALSE, 0);
else
mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
mddi_queue_register_write(REG_PTVW, 320, FALSE, 0);
mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
mddi_wait(1);
/* vram_color set REG_AGM???? */
mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
mddi_queue_register_write(REG_SSDCTL, 0x0000, FALSE, 0);
mddi_queue_register_write(REG_SSDCTL, 0x0001, TRUE, 0);
mddi_wait(1);
mddi_queue_register_write(REG_PSTCTL1, 0x0001, TRUE, 0);
mddi_wait(10);
serigo(0x0701);
/* software reset */
mddi_wait(1);
/* Wait over 50us */
serigo(0x0400);
/* DCLK~ACHSYNC~ACVSYNC polarity setting */
serigo(0x2900);
/* EEPROM start read address setting */
serigo(0x2606);
/* EEPROM start read register setting */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x0503);
/* Horizontal timing setting */
serigo(0x062C);
/* Veritical timing setting */
serigo(0x2001);
/* power initialize setting(VDC2) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2120);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2130);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x2132);
/* Initialize power setting(CPS) */
mddi_wait(10);
/* Wait over 10ms */
serigo(0x2133);
/* Initialize power setting(CPS) */
mddi_wait(20);
/* Wait over 20ms */
serigo(0x0200);
/* Panel initialize release(INIT) */
mddi_wait(1);
/* Wait over 1ms */
serigo(0x0131);
/* Panel setting(CPS) */
mddi_wait(1);
/* Wait over 1ms */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, TRUE, 0);
/* if (FFA LCD is upside down) -> serigo(0x0100); */
serigo(0x0130);
/* Black mask release(display ON) */
mddi_wait(1);
/* Wait over 1ms */
if (mddi_sharp_vsync_wake) {
mddi_queue_register_write(REG_VBLKS, 0x1001, TRUE, 0);
mddi_queue_register_write(REG_VBLKE, 0x1002, TRUE, 0);
}
/* Set the MDP pixel data attributes for Primary Display */
mddi_host_write_pix_attr_reg(0x00C3);
return;
}
void mddi_sharp_sub_lcd_init(void)
{
mddi_queue_register_write(REG_SYSCTL, 0x4000, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
mddi_wait(100);
mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
mddi_queue_register_write(REG_PTHW, 128, FALSE, 0);
mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
mddi_queue_register_write(REG_PTVW, 128, FALSE, 0);
mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
/* Now the sub display..... */
/* Reset High */
mddi_queue_register_write(REG_SUBCTL, 0x0200, FALSE, 0);
/* CS=1,RD=1,WE=1,RS=1 */
mddi_queue_register_write(REG_SUBTCMD, 0x000f, TRUE, 0);
mddi_wait(1);
/* Wait 5us */
if (sharp_subpanel_type == SHARP_SUB_UNKNOWN) {
uint32 data;
sub_through_write(1, 0x05);
sub_through_write(1, 0x6A);
sub_through_write(1, 0x1D);
sub_through_write(1, 0x05);
data = sub_through_read(1);
if (data == 0x6A) {
sharp_subpanel_type = SHARP_SUB_HYNIX;
} else {
sub_through_write(0, 0x36);
sub_through_write(1, 0xA8);
sub_through_write(0, 0x09);
data = sub_through_read(1);
data = sub_through_read(1);
if (data == 0x54) {
sub_through_write(0, 0x36);
sub_through_write(1, 0x00);
sharp_subpanel_type = SHARP_SUB_ROHM;
}
}
}
if (sharp_subpanel_type == SHARP_SUB_HYNIX) {
sub_through_write(1, 0x00); /* Display setting 1 */
sub_through_write(1, 0x04);
sub_through_write(1, 0x01);
sub_through_write(1, 0x05);
sub_through_write(1, 0x0280);
sub_through_write(1, 0x0301);
sub_through_write(1, 0x0402);
sub_through_write(1, 0x0500);
sub_through_write(1, 0x0681);
sub_through_write(1, 0x077F);
sub_through_write(1, 0x08C0);
sub_through_write(1, 0x0905);
sub_through_write(1, 0x0A02);
sub_through_write(1, 0x0B00);
sub_through_write(1, 0x0C00);
sub_through_write(1, 0x0D00);
sub_through_write(1, 0x0E00);
sub_through_write(1, 0x0F00);
sub_through_write(1, 0x100B); /* Display setting 2 */
sub_through_write(1, 0x1103);
sub_through_write(1, 0x1237);
sub_through_write(1, 0x1300);
sub_through_write(1, 0x1400);
sub_through_write(1, 0x1500);
sub_through_write(1, 0x1605);
sub_through_write(1, 0x1700);
sub_through_write(1, 0x1800);
sub_through_write(1, 0x192E);
sub_through_write(1, 0x1A00);
sub_through_write(1, 0x1B00);
sub_through_write(1, 0x1C00);
sub_through_write(1, 0x151A); /* Power setting */
sub_through_write(1, 0x2002); /* Gradation Palette setting */
sub_through_write(1, 0x2107);
sub_through_write(1, 0x220C);
sub_through_write(1, 0x2310);
sub_through_write(1, 0x2414);
sub_through_write(1, 0x2518);
sub_through_write(1, 0x261C);
sub_through_write(1, 0x2720);
sub_through_write(1, 0x2824);
sub_through_write(1, 0x2928);
sub_through_write(1, 0x2A2B);
sub_through_write(1, 0x2B2E);
sub_through_write(1, 0x2C31);
sub_through_write(1, 0x2D34);
sub_through_write(1, 0x2E37);
sub_through_write(1, 0x2F3A);
sub_through_write(1, 0x303C);
sub_through_write(1, 0x313E);
sub_through_write(1, 0x323F);
sub_through_write(1, 0x3340);
sub_through_write(1, 0x3441);
sub_through_write(1, 0x3543);
sub_through_write(1, 0x3646);
sub_through_write(1, 0x3749);
sub_through_write(1, 0x384C);
sub_through_write(1, 0x394F);
sub_through_write(1, 0x3A52);
sub_through_write(1, 0x3B59);
sub_through_write(1, 0x3C60);
sub_through_write(1, 0x3D67);
sub_through_write(1, 0x3E6E);
sub_through_write(1, 0x3F7F);
sub_through_write(1, 0x4001);
sub_through_write(1, 0x4107);
sub_through_write(1, 0x420C);
sub_through_write(1, 0x4310);
sub_through_write(1, 0x4414);
sub_through_write(1, 0x4518);
sub_through_write(1, 0x461C);
sub_through_write(1, 0x4720);
sub_through_write(1, 0x4824);
sub_through_write(1, 0x4928);
sub_through_write(1, 0x4A2B);
sub_through_write(1, 0x4B2E);
sub_through_write(1, 0x4C31);
sub_through_write(1, 0x4D34);
sub_through_write(1, 0x4E37);
sub_through_write(1, 0x4F3A);
sub_through_write(1, 0x503C);
sub_through_write(1, 0x513E);
sub_through_write(1, 0x523F);
sub_through_write(1, 0x5340);
sub_through_write(1, 0x5441);
sub_through_write(1, 0x5543);
sub_through_write(1, 0x5646);
sub_through_write(1, 0x5749);
sub_through_write(1, 0x584C);
sub_through_write(1, 0x594F);
sub_through_write(1, 0x5A52);
sub_through_write(1, 0x5B59);
sub_through_write(1, 0x5C60);
sub_through_write(1, 0x5D67);
sub_through_write(1, 0x5E6E);
sub_through_write(1, 0x5F7E);
sub_through_write(1, 0x6000);
sub_through_write(1, 0x6107);
sub_through_write(1, 0x620C);
sub_through_write(1, 0x6310);
sub_through_write(1, 0x6414);
sub_through_write(1, 0x6518);
sub_through_write(1, 0x661C);
sub_through_write(1, 0x6720);
sub_through_write(1, 0x6824);
sub_through_write(1, 0x6928);
sub_through_write(1, 0x6A2B);
sub_through_write(1, 0x6B2E);
sub_through_write(1, 0x6C31);
sub_through_write(1, 0x6D34);
sub_through_write(1, 0x6E37);
sub_through_write(1, 0x6F3A);
sub_through_write(1, 0x703C);
sub_through_write(1, 0x713E);
sub_through_write(1, 0x723F);
sub_through_write(1, 0x7340);
sub_through_write(1, 0x7441);
sub_through_write(1, 0x7543);
sub_through_write(1, 0x7646);
sub_through_write(1, 0x7749);
sub_through_write(1, 0x784C);
sub_through_write(1, 0x794F);
sub_through_write(1, 0x7A52);
sub_through_write(1, 0x7B59);
sub_through_write(1, 0x7C60);
sub_through_write(1, 0x7D67);
sub_through_write(1, 0x7E6E);
sub_through_write(1, 0x7F7D);
sub_through_write(1, 0x1851); /* Display on */
mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
/* 1 pixel / 1 post clock */
mddi_queue_register_write(REG_CLKDIV2, 0x3b00, FALSE, 0);
/* SUB LCD select */
mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
/* RS=0,command initiate number=0,select master mode */
mddi_queue_register_write(REG_SUBCTL, 0x0202, FALSE, 0);
/* Sub LCD Data transform start */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
} else if (sharp_subpanel_type == SHARP_SUB_ROHM) {
sub_through_write(0, 0x01); /* Display setting */
sub_through_write(1, 0x00);
mddi_wait(1);
/* Wait 100us <----- ******* Update 2005/01/24 */
sub_through_write(0, 0xB6);
sub_through_write(1, 0x0C);
sub_through_write(1, 0x4A);
sub_through_write(1, 0x20);
sub_through_write(0, 0x3A);
sub_through_write(1, 0x05);
sub_through_write(0, 0xB7);
sub_through_write(1, 0x01);
sub_through_write(0, 0xBA);
sub_through_write(1, 0x20);
sub_through_write(1, 0x02);
sub_through_write(0, 0x25);
sub_through_write(1, 0x4F);
sub_through_write(0, 0xBB);
sub_through_write(1, 0x00);
sub_through_write(0, 0x36);
sub_through_write(1, 0x00);
sub_through_write(0, 0xB1);
sub_through_write(1, 0x05);
sub_through_write(0, 0xBE);
sub_through_write(1, 0x80);
sub_through_write(0, 0x26);
sub_through_write(1, 0x01);
sub_through_write(0, 0x2A);
sub_through_write(1, 0x02);
sub_through_write(1, 0x81);
sub_through_write(0, 0x2B);
sub_through_write(1, 0x00);
sub_through_write(1, 0x7F);
sub_through_write(0, 0x2C);
sub_through_write(0, 0x11); /* Sleep mode off */
mddi_wait(1);
/* Wait 100 ms <----- ******* Update 2005/01/24 */
sub_through_write(0, 0x29); /* Display on */
sub_through_write(0, 0xB3);
sub_through_write(1, 0x20);
sub_through_write(1, 0xAA);
sub_through_write(1, 0xA0);
sub_through_write(1, 0x20);
sub_through_write(1, 0x30);
sub_through_write(1, 0xA6);
sub_through_write(1, 0xFF);
sub_through_write(1, 0x9A);
sub_through_write(1, 0x9F);
sub_through_write(1, 0xAF);
sub_through_write(1, 0xBC);
sub_through_write(1, 0xCF);
sub_through_write(1, 0xDF);
sub_through_write(1, 0x20);
sub_through_write(1, 0x9C);
sub_through_write(1, 0x8A);
sub_through_write(0, 0x002C); /* Display on */
/* 1 pixel / 2 post clock */
mddi_queue_register_write(REG_CLKDIV2, 0x7b00, FALSE, 0);
/* SUB LCD select */
mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
/* RS=1,command initiate number=0,select master mode */
mddi_queue_register_write(REG_SUBCTL, 0x0242, FALSE, 0);
/* Sub LCD Data transform start */
mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
}
/* Set the MDP pixel data attributes for Sub Display */
mddi_host_write_pix_attr_reg(0x00C0);
}
void mddi_sharp_lcd_vsync_detected(boolean detected)
{
/* static timetick_type start_time = 0; */
static struct timeval start_time;
static boolean first_time = TRUE;
/* uint32 mdp_cnt_val = 0; */
/* timetick_type elapsed_us; */
struct timeval now;
uint32 elapsed_us;
uint32 num_vsyncs;
if ((detected) || (mddi_sharp_vsync_attempts > 5)) {
if ((detected) && (mddi_sharp_monitor_refresh_value)) {
/* if (start_time != 0) */
if (!first_time) {
jiffies_to_timeval(jiffies, &now);
elapsed_us =
(now.tv_sec - start_time.tv_sec) * 1000000 +
now.tv_usec - start_time.tv_usec;
/*
* LCD is configured for a refresh every usecs,
* so to determine the number of vsyncs that
* have occurred since the last measurement add
* half that to the time difference and divide
* by the refresh rate.
*/
num_vsyncs = (elapsed_us +
(mddi_sharp_usecs_per_refresh >>
1)) /
mddi_sharp_usecs_per_refresh;
/*
* LCD is configured for * hsyncs (rows) per
* refresh cycle. Calculate new rows_per_second
* value based upon these new measurements.
* MDP can update with this new value.
*/
mddi_sharp_rows_per_second =
(mddi_sharp_rows_per_refresh * 1000 *
num_vsyncs) / (elapsed_us / 1000);
}
/* start_time = timetick_get(); */
first_time = FALSE;
jiffies_to_timeval(jiffies, &start_time);
if (mddi_sharp_report_refresh_measurements) {
/* mdp_cnt_val = MDP_LINE_COUNT; */
}
}
/* if detected = TRUE, client initiated wakeup was detected */
if (mddi_sharp_vsync_handler != NULL) {
(*mddi_sharp_vsync_handler)
(mddi_sharp_vsync_handler_arg);
mddi_sharp_vsync_handler = NULL;
}
mddi_vsync_detect_enabled = FALSE;
mddi_sharp_vsync_attempts = 0;
/* need to clear this vsync wakeup */
if (!mddi_queue_register_write_int(REG_INTR, 0x0000)) {
MDDI_MSG_ERR("Vsync interrupt clear failed!\n");
}
if (!detected) {
/* give up after 5 failed attempts but show error */
MDDI_MSG_NOTICE("Vsync detection failed!\n");
} else if ((mddi_sharp_monitor_refresh_value) &&
(mddi_sharp_report_refresh_measurements)) {
MDDI_MSG_NOTICE(" Lines Per Second=%d!\n",
mddi_sharp_rows_per_second);
}
} else
/* if detected = FALSE, we woke up from hibernation, but did not
* detect client initiated wakeup.
*/
mddi_sharp_vsync_attempts++;
}
/* ISR to be executed */
void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg)
{
boolean error = FALSE;
unsigned long flags;
/* Disable interrupts */
spin_lock_irqsave(&mddi_host_spin_lock, flags);
/* INTLOCK(); */
if (mddi_sharp_vsync_handler != NULL)
error = TRUE;
/* Register the handler for this particular GROUP interrupt source */
mddi_sharp_vsync_handler = handler;
mddi_sharp_vsync_handler_arg = arg;
/* Restore interrupts */
spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
/* INTFREE(); */
if (error)
MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n");
/* Enable the vsync wakeup */
mddi_queue_register_write(REG_INTR, 0x8100, FALSE, 0);
mddi_sharp_vsync_attempts = 1;
mddi_vsync_detect_enabled = TRUE;
} /* mddi_sharp_vsync_set_handler */
static int mddi_sharp_lcd_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
if (mfd->panel.id == SHARP_QVGA_PRIM)
mddi_sharp_prim_lcd_init();
else
mddi_sharp_sub_lcd_init();
return 0;
}
static int mddi_sharp_lcd_off(struct platform_device *pdev)
{
mddi_sharp_lcd_powerdown();
return 0;
}
static int __init mddi_sharp_probe(struct platform_device *pdev)
{
if (pdev->id == 0) {
mddi_sharp_pdata = pdev->dev.platform_data;
return 0;
}
msm_fb_add_device(pdev);
return 0;
}
static struct platform_driver this_driver = {
.probe = mddi_sharp_probe,
.driver = {
.name = "mddi_sharp_qvga",
},
};
static struct msm_fb_panel_data mddi_sharp_panel_data0 = {
.on = mddi_sharp_lcd_on,
.off = mddi_sharp_lcd_off,
.set_backlight = mddi_sharp_lcd_set_backlight,
.set_vsync_notifier = mddi_sharp_vsync_set_handler,
};
static struct platform_device this_device_0 = {
.name = "mddi_sharp_qvga",
.id = SHARP_QVGA_PRIM,
.dev = {
.platform_data = &mddi_sharp_panel_data0,
}
};
static struct msm_fb_panel_data mddi_sharp_panel_data1 = {
.on = mddi_sharp_lcd_on,
.off = mddi_sharp_lcd_off,
};
static struct platform_device this_device_1 = {
.name = "mddi_sharp_qvga",
.id = SHARP_128X128_SECD,
.dev = {
.platform_data = &mddi_sharp_panel_data1,
}
};
static int __init mddi_sharp_init(void)
{
int ret;
struct msm_panel_info *pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_sharp_qvga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (((id >> 16) != 0x0) || ((id & 0xffff) != 0x8835))
return 0;
}
#endif
if (mddi_host_core_version > 8) {
/* can use faster refresh with newer hw revisions */
mddi_sharp_debug_60hz_refresh = TRUE;
/* Timing variables for tracking vsync */
/* dot_clock = 6.00MHz
* horizontal count = 296
* vertical count = 338
* refresh rate = 6000000/(296+338) = 60Hz
*/
mddi_sharp_rows_per_second = 20270; /* 6000000/296 */
mddi_sharp_rows_per_refresh = 338;
mddi_sharp_usecs_per_refresh = 16674; /* (296+338)/6000000 */
} else {
/* Timing variables for tracking vsync */
/* dot_clock = 5.20MHz
* horizontal count = 376
* vertical count = 338
* refresh rate = 5200000/(376+338) = 41Hz
*/
mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
mddi_sharp_rows_per_refresh = 338;
mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
}
ret = platform_driver_register(&this_driver);
if (!ret) {
pinfo = &mddi_sharp_panel_data0.panel_info;
pinfo->xres = 240;
pinfo->yres = 320;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_1;
pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->fb_num = 2;
pinfo->clk_rate = 122880000;
pinfo->clk_min = 120000000;
pinfo->clk_max = 125000000;
pinfo->lcd.vsync_enable = TRUE;
pinfo->lcd.refx100 =
(mddi_sharp_rows_per_second * 100) /
mddi_sharp_rows_per_refresh;
pinfo->lcd.v_back_porch = 12;
pinfo->lcd.v_front_porch = 6;
pinfo->lcd.v_pulse_width = 0;
pinfo->lcd.hw_vsync_mode = FALSE;
pinfo->lcd.vsync_notifier_period = (1 * HZ);
pinfo->bl_max = 7;
pinfo->bl_min = 1;
ret = platform_device_register(&this_device_0);
if (ret)
platform_driver_unregister(&this_driver);
pinfo = &mddi_sharp_panel_data1.panel_info;
pinfo->xres = 128;
pinfo->yres = 128;
pinfo->type = MDDI_PANEL;
pinfo->pdest = DISPLAY_2;
pinfo->mddi.vdopkt = 0x400;
pinfo->wait_cycle = 0;
pinfo->bpp = 18;
pinfo->clk_rate = 122880000;
pinfo->clk_min = 120000000;
pinfo->clk_max = 125000000;
pinfo->fb_num = 2;
ret = platform_device_register(&this_device_1);
if (ret) {
platform_device_unregister(&this_device_0);
platform_driver_unregister(&this_driver);
}
}
if (!ret)
mddi_lcd.vsync_detected = mddi_sharp_lcd_vsync_detected;
return ret;
}
module_init(mddi_sharp_init);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDI_TOSHIBA_H
#define MDDI_TOSHIBA_H
#define TOSHIBA_VGA_PRIM 1
#define TOSHIBA_VGA_SECD 2
#define LCD_TOSHIBA_2P4_VGA 0
#define LCD_TOSHIBA_2P4_WVGA 1
#define LCD_TOSHIBA_2P4_WVGA_PT 2
#define LCD_SHARP_2P4_VGA 3
#define GPIO_BLOCK_BASE 0x150000
#define SYSTEM_BLOCK2_BASE 0x170000
#define GPIODIR (GPIO_BLOCK_BASE|0x04)
#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
#define GPIOPC (GPIO_BLOCK_BASE|0x28)
#define GPIODATA (GPIO_BLOCK_BASE|0x00)
#define write_client_reg(__X, __Y, __Z) {\
mddi_queue_register_write(__X, __Y, TRUE, 0);\
}
#endif /* MDDI_TOSHIBA_H */

View File

@ -0,0 +1,136 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include "mddi_toshiba.h"
static uint32 read_client_reg(uint32 addr)
{
uint32 val;
mddi_queue_register_read(addr, &val, TRUE, 0);
return val;
}
static uint32 toshiba_lcd_gpio_read(void)
{
uint32 val;
write_client_reg(GPIODIR, 0x0000000C, TRUE);
write_client_reg(GPIOSEL, 0x00000000, TRUE);
write_client_reg(GPIOSEL, 0x00000000, TRUE);
write_client_reg(GPIOPC, 0x03CF00C0, TRUE);
val = read_client_reg(GPIODATA) & 0x2C0;
return val;
}
static u32 mddi_toshiba_panel_detect(void)
{
mddi_host_type host_idx = MDDI_HOST_PRIM;
uint32 lcd_gpio;
u32 mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
/* Toshiba display requires larger drive_lo value */
mddi_host_reg_out(DRIVE_LO, 0x0050);
lcd_gpio = toshiba_lcd_gpio_read();
switch (lcd_gpio) {
case 0x0080:
mddi_toshiba_lcd = LCD_SHARP_2P4_VGA;
break;
case 0x00C0:
default:
mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
break;
}
return mddi_toshiba_lcd;
}
static int __init mddi_toshiba_vga_init(void)
{
int ret;
struct msm_panel_info pinfo;
u32 panel;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
ret = msm_fb_detect_client("mddi_toshiba_vga");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if ((id >> 16) != 0xD263)
return 0;
}
#endif
panel = mddi_toshiba_panel_detect();
pinfo.xres = 480;
pinfo.yres = 640;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = TRUE;
pinfo.lcd.refx100 = 6118;
pinfo.lcd.v_back_porch = 6;
pinfo.lcd.v_front_porch = 0;
pinfo.lcd.v_pulse_width = 0;
pinfo.lcd.hw_vsync_mode = FALSE;
pinfo.lcd.vsync_notifier_period = (1 * HZ);
pinfo.bl_max = 99;
pinfo.bl_min = 1;
pinfo.clk_rate = 122880000;
pinfo.clk_min = 120000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, panel);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
pinfo.xres = 176;
pinfo.yres = 220;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_2;
pinfo.mddi.vdopkt = 0x400;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.clk_rate = 122880000;
pinfo.clk_min = 120000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_SECD, panel);
if (ret)
printk(KERN_WARNING
"%s: failed to register device!\n", __func__);
return ret;
}
module_init(mddi_toshiba_vga_init);

View File

@ -0,0 +1,63 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddi_toshiba.h"
static int __init mddi_toshiba_wvga_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
if (msm_fb_detect_client("mddi_toshiba_wvga"))
return 0;
#endif
pinfo.xres = 800;
pinfo.yres = 480;
pinfo.pdest = DISPLAY_2;
pinfo.type = MDDI_PANEL;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = TRUE;
pinfo.lcd.refx100 = 6118;
pinfo.lcd.v_back_porch = 6;
pinfo.lcd.v_front_porch = 0;
pinfo.lcd.v_pulse_width = 0;
pinfo.lcd.hw_vsync_mode = FALSE;
pinfo.lcd.vsync_notifier_period = (1 * HZ);
pinfo.bl_max = 4;
pinfo.bl_min = 1;
pinfo.clk_rate = 192000000;
pinfo.clk_min = 190000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
LCD_TOSHIBA_2P4_WVGA);
if (ret) {
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
return ret;
}
module_init(mddi_toshiba_wvga_init);

View File

@ -0,0 +1,64 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include "mddi_toshiba.h"
static int __init mddi_toshiba_wvga_pt_init(void)
{
int ret;
struct msm_panel_info pinfo;
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
uint id;
ret = msm_fb_detect_client("mddi_toshiba_wvga_pt");
if (ret == -ENODEV)
return 0;
if (ret) {
id = mddi_get_client_id();
if (id != 0xd2638722)
return 0;
}
#endif
pinfo.xres = 480;
pinfo.yres = 800;
pinfo.type = MDDI_PANEL;
pinfo.pdest = DISPLAY_1;
pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
pinfo.wait_cycle = 0;
pinfo.bpp = 18;
pinfo.lcd.vsync_enable = FALSE;
pinfo.bl_max = 15;
pinfo.bl_min = 1;
pinfo.clk_rate = 192000000;
pinfo.clk_min = 190000000;
pinfo.clk_max = 200000000;
pinfo.fb_num = 2;
ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
LCD_TOSHIBA_2P4_WVGA_PT);
if (ret)
printk(KERN_ERR "%s: failed to register device!\n", __func__);
return ret;
}
module_init(mddi_toshiba_wvga_pt_init);

View File

@ -0,0 +1,377 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include <linux/clk.h>
#include <mach/clk.h>
struct semaphore mddi_host_mutex;
struct clk *mddi_io_clk;
static boolean mddi_host_powered = FALSE;
static boolean mddi_host_initialized = FALSE;
extern uint32 *mddi_reg_read_value_ptr;
mddi_lcd_func_type mddi_lcd;
extern mddi_client_capability_type mddi_client_capability_pkt;
#ifdef FEATURE_MDDI_HITACHI
extern void mddi_hitachi_window_adjust(uint16 x1,
uint16 x2, uint16 y1, uint16 y2);
#endif
extern void mddi_toshiba_lcd_init(void);
#ifdef FEATURE_MDDI_S6D0142
extern void mddi_s6d0142_lcd_init(void);
extern void mddi_s6d0142_window_adjust(uint16 x1,
uint16 x2,
uint16 y1,
uint16 y2,
mddi_llist_done_cb_type done_cb);
#endif
void mddi_init(void)
{
if (mddi_host_initialized)
return;
mddi_host_initialized = TRUE;
init_MUTEX(&mddi_host_mutex);
if (!mddi_host_powered) {
down(&mddi_host_mutex);
mddi_host_init(MDDI_HOST_PRIM);
mddi_host_powered = TRUE;
up(&mddi_host_mutex);
mdelay(10);
}
}
int mddi_host_register_read(uint32 reg_addr,
uint32 *reg_value_ptr, boolean wait, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
int ret = 0;
if (in_interrupt())
MDDI_MSG_CRIT("Called from ISR context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
mddi_init();
}
down(&mddi_host_mutex);
mddi_reg_read_value_ptr = reg_value_ptr;
curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
/* need to change this to some sort of wait */
MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
return -EINVAL;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 0x11;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 0;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->packet_data_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x8001;
regacc_pkt_ptr->register_address = reg_addr;
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
NULL, host);
/* need to check if we can write the pointer or not */
up(&mddi_host_mutex);
if (wait) {
int wait_ret;
mddi_linked_list_notify_type *llist_notify_ptr;
llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
wait_ret = wait_for_completion_timeout(
&(llist_notify_ptr->done_comp), 5 * HZ);
if (wait_ret <= 0)
ret = -EBUSY;
if (wait_ret < 0)
printk(KERN_ERR "%s: failed to wait for completion!\n",
__func__);
else if (!wait_ret)
printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
}
MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr);
return ret;
} /* mddi_host_register_read */
int mddi_host_register_write(uint32 reg_addr,
uint32 reg_val, enum mddi_data_packet_size_type packet_size,
boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_linked_list_type *curr_llist_dma_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
int ret = 0;
if (in_interrupt())
MDDI_MSG_CRIT("Called from ISR context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
mddi_init();
}
down(&mddi_host_mutex);
curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 1;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 4;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count +
(uint16)packet_size;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x0001;
regacc_pkt_ptr->register_address = reg_addr;
regacc_pkt_ptr->register_data_list = reg_val;
MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n",
regacc_pkt_ptr->register_address,
regacc_pkt_ptr->register_data_list);
regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
curr_llist_ptr->packet_data_pointer =
(void *)(&regacc_pkt_ptr->register_data_list);
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
done_cb, host);
up(&mddi_host_mutex);
if (wait) {
int wait_ret;
mddi_linked_list_notify_type *llist_notify_ptr;
llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
wait_ret = wait_for_completion_timeout(
&(llist_notify_ptr->done_comp), 5 * HZ);
if (wait_ret <= 0)
ret = -EBUSY;
if (wait_ret < 0)
printk(KERN_ERR "%s: failed to wait for completion!\n",
__func__);
else if (!wait_ret)
printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
}
return ret;
} /* mddi_host_register_write */
boolean mddi_host_register_read_int
(uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
if (!in_interrupt())
MDDI_MSG_CRIT("Called from TASK context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
return FALSE;
}
if (down_trylock(&mddi_host_mutex) != 0)
return FALSE;
mddi_reg_read_value_ptr = reg_value_ptr;
curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
return FALSE;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 0x11;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 0;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->packet_data_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x8001;
regacc_pkt_ptr->register_address = reg_addr;
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
NULL, host);
/* need to check if we can write the pointer or not */
up(&mddi_host_mutex);
return TRUE;
} /* mddi_host_register_read */
boolean mddi_host_register_write_int
(uint32 reg_addr,
uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
mddi_linked_list_type *curr_llist_ptr;
mddi_linked_list_type *curr_llist_dma_ptr;
mddi_register_access_packet_type *regacc_pkt_ptr;
uint16 curr_llist_idx;
if (!in_interrupt())
MDDI_MSG_CRIT("Called from TASK context\n");
if (!mddi_host_powered) {
MDDI_MSG_ERR("MDDI powered down!\n");
return FALSE;
}
if (down_trylock(&mddi_host_mutex) != 0)
return FALSE;
curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE);
if (curr_llist_idx == UNASSIGNED_INDEX) {
up(&mddi_host_mutex);
return FALSE;
}
curr_llist_ptr = &llist_extern[host][curr_llist_idx];
curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
curr_llist_ptr->link_controller_flags = 1;
curr_llist_ptr->packet_header_count = 14;
curr_llist_ptr->packet_data_count = 4;
curr_llist_ptr->next_packet_pointer = NULL;
curr_llist_ptr->reserved = 0;
regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4;
regacc_pkt_ptr->packet_type = 146; /* register access packet */
regacc_pkt_ptr->bClient_ID = 0;
regacc_pkt_ptr->read_write_info = 0x0001;
regacc_pkt_ptr->register_address = reg_addr;
regacc_pkt_ptr->register_data_list = reg_val;
regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
curr_llist_ptr->packet_data_pointer =
(void *)(&(regacc_pkt_ptr->register_data_list));
/* now adjust pointers */
mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
done_cb, host);
up(&mddi_host_mutex);
return TRUE;
} /* mddi_host_register_write */
void mddi_wait(uint16 time_ms)
{
mdelay(time_ms);
}
void mddi_client_lcd_vsync_detected(boolean detected)
{
if (mddi_lcd.vsync_detected)
(*mddi_lcd.vsync_detected) (detected);
}
/* extended version of function includes done callback */
void mddi_window_adjust_ext(struct msm_fb_data_type *mfd,
uint16 x1,
uint16 x2,
uint16 y1,
uint16 y2, mddi_llist_done_cb_type done_cb)
{
#ifdef FEATURE_MDDI_HITACHI
if (mfd->panel.id == HITACHI)
mddi_hitachi_window_adjust(x1, x2, y1, y2);
#elif defined(FEATURE_MDDI_S6D0142)
if (mfd->panel.id == MDDI_LCD_S6D0142)
mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb);
#else
/* Do nothing then... except avoid lint/compiler warnings */
(void)x1;
(void)x2;
(void)y1;
(void)y2;
(void)done_cb;
#endif
}
void mddi_window_adjust(struct msm_fb_data_type *mfd,
uint16 x1, uint16 x2, uint16 y1, uint16 y2)
{
mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL);
}

View File

@ -0,0 +1,225 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDIHOST_H
#define MDDIHOST_H
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/types.h>
#include <linux/dma-mapping.h>
#include "msm_fb_panel.h"
#undef FEATURE_MDDI_MC4
#undef FEATURE_MDDI_S6D0142
#undef FEATURE_MDDI_HITACHI
#define FEATURE_MDDI_SHARP
#define FEATURE_MDDI_TOSHIBA
#undef FEATURE_MDDI_E751
#define FEATURE_MDDI_CORONA
#define FEATURE_MDDI_PRISM
#define T_MSM7500
typedef enum {
format_16bpp,
format_18bpp,
format_24bpp
} mddi_video_format;
typedef enum {
MDDI_LCD_NONE = 0,
MDDI_LCD_MC4,
MDDI_LCD_S6D0142,
MDDI_LCD_SHARP,
MDDI_LCD_E751,
MDDI_LCD_CORONA,
MDDI_LCD_HITACHI,
MDDI_LCD_TOSHIBA,
MDDI_LCD_PRISM,
MDDI_LCD_TP2,
MDDI_NUM_LCD_TYPES,
MDDI_LCD_DEFAULT = MDDI_LCD_TOSHIBA
} mddi_lcd_type;
typedef enum {
MDDI_HOST_PRIM = 0,
MDDI_HOST_EXT,
MDDI_NUM_HOST_CORES
} mddi_host_type;
typedef enum {
MDDI_DRIVER_RESET, /* host core registers have not been written. */
MDDI_DRIVER_DISABLED, /* registers written, interrupts disabled. */
MDDI_DRIVER_ENABLED /* registers written, interrupts enabled. */
} mddi_host_driver_state_type;
typedef enum {
MDDI_GPIO_INT_0 = 0,
MDDI_GPIO_INT_1,
MDDI_GPIO_INT_2,
MDDI_GPIO_INT_3,
MDDI_GPIO_INT_4,
MDDI_GPIO_INT_5,
MDDI_GPIO_INT_6,
MDDI_GPIO_INT_7,
MDDI_GPIO_INT_8,
MDDI_GPIO_INT_9,
MDDI_GPIO_INT_10,
MDDI_GPIO_INT_11,
MDDI_GPIO_INT_12,
MDDI_GPIO_INT_13,
MDDI_GPIO_INT_14,
MDDI_GPIO_INT_15,
MDDI_GPIO_NUM_INTS
} mddi_gpio_int_type;
enum mddi_data_packet_size_type {
MDDI_DATA_PACKET_4_BYTES = 4,
MDDI_DATA_PACKET_8_BYTES = 8,
MDDI_DATA_PACKET_12_BYTES = 12,
MDDI_DATA_PACKET_16_BYTES = 16,
MDDI_DATA_PACKET_24_BYTES = 24
};
typedef struct {
uint32 addr;
uint32 value;
} mddi_reg_write_type;
boolean mddi_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg);
typedef void (*mddi_llist_done_cb_type) (void);
typedef void (*mddi_rev_handler_type) (void *);
boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type);
#define MDDI_DEFAULT_PRIM_PIX_ATTR 0xC3
#define MDDI_DEFAULT_SECD_PIX_ATTR 0xC0
typedef int gpio_int_polarity_type;
typedef int gpio_int_handler_type;
typedef struct {
void (*vsync_detected) (boolean);
} mddi_lcd_func_type;
extern mddi_lcd_func_type mddi_lcd;
void mddi_init(void);
void mddi_powerdown(void);
void mddi_host_start_ext_display(void);
void mddi_host_stop_ext_display(void);
extern spinlock_t mddi_host_spin_lock;
#ifdef T_MSM7500
void mddi_reset(void);
#ifdef FEATURE_DUAL_PROC_MODEM_DISPLAY
void mddi_host_switch_proc_control(boolean on);
#endif
#endif
void mddi_host_exit_power_collapse(void);
void mddi_queue_splash_screen
(void *buf_ptr,
boolean clear_area,
int16 src_width,
int16 src_starting_row,
int16 src_starting_column,
int16 num_of_rows,
int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
void mddi_queue_image
(void *buf_ptr,
uint8 stereo_video,
boolean clear_area,
int16 src_width,
int16 src_starting_row,
int16 src_starting_column,
int16 num_of_rows,
int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
int mddi_host_register_read
(uint32 reg_addr,
uint32 *reg_value_ptr, boolean wait, mddi_host_type host_idx);
int mddi_host_register_write
(uint32 reg_addr, uint32 reg_val,
enum mddi_data_packet_size_type packet_size,
boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host);
boolean mddi_host_register_write_int
(uint32 reg_addr,
uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host);
boolean mddi_host_register_read_int
(uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host_idx);
void mddi_queue_register_write_static
(uint32 reg_addr,
uint32 reg_val, boolean wait, mddi_llist_done_cb_type done_cb);
void mddi_queue_static_window_adjust
(const mddi_reg_write_type *reg_write,
uint16 num_writes, mddi_llist_done_cb_type done_cb);
#define mddi_queue_register_read(reg, val_ptr, wait, sig) \
mddi_host_register_read(reg, val_ptr, wait, MDDI_HOST_PRIM)
#define mddi_queue_register_write(reg, val, wait, sig) \
mddi_host_register_write(reg, val, MDDI_DATA_PACKET_4_BYTES,\
wait, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_write_extn(reg, val, pkt_size, wait, sig) \
mddi_host_register_write(reg, val, pkt_size, \
wait, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_write_int(reg, val) \
mddi_host_register_write_int(reg, val, NULL, MDDI_HOST_PRIM)
#define mddi_queue_register_read_int(reg, val_ptr) \
mddi_host_register_read_int(reg, val_ptr, MDDI_HOST_PRIM)
#define mddi_queue_register_writes(reg_ptr, val, wait, sig) \
mddi_host_register_writes(reg_ptr, val, wait, sig, MDDI_HOST_PRIM)
void mddi_wait(uint16 time_ms);
void mddi_assign_max_pkt_dimensions(uint16 image_cols,
uint16 image_rows,
uint16 bpp,
uint16 *max_cols, uint16 * max_rows);
uint16 mddi_assign_pkt_height(uint16 pkt_width, uint16 pkt_height, uint16 bpp);
void mddi_queue_reverse_encapsulation(boolean wait);
void mddi_disable(int lock);
#endif /* MDDIHOST_H */

View File

@ -0,0 +1,63 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include "msm_fb.h"
#include "mddihost.h"
#include "mddihosti.h"
#include <linux/clk.h>
#include <mach/clk.h>
extern struct semaphore mddi_host_mutex;
static boolean mddi_host_ext_powered = FALSE;
void mddi_host_start_ext_display(void)
{
down(&mddi_host_mutex);
if (!mddi_host_ext_powered) {
mddi_host_init(MDDI_HOST_EXT);
mddi_host_ext_powered = TRUE;
}
up(&mddi_host_mutex);
}
void mddi_host_stop_ext_display(void)
{
down(&mddi_host_mutex);
if (mddi_host_ext_powered) {
mddi_host_powerdown(MDDI_HOST_EXT);
mddi_host_ext_powered = FALSE;
}
up(&mddi_host_mutex);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,547 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDDIHOSTI_H
#define MDDIHOSTI_H
#include "msm_fb.h"
#include "mddihost.h"
#include <linux/clk.h>
/* Register offsets in MDDI, applies to both msm_pmdh_base and
* (u32)msm_emdh_base. */
#define MDDI_CMD 0x0000
#define MDDI_VERSION 0x0004
#define MDDI_PRI_PTR 0x0008
#define MDDI_BPS 0x0010
#define MDDI_SPM 0x0014
#define MDDI_INT 0x0018
#define MDDI_INTEN 0x001c
#define MDDI_REV_PTR 0x0020
#define MDDI_REV_SIZE 0x0024
#define MDDI_STAT 0x0028
#define MDDI_REV_RATE_DIV 0x002c
#define MDDI_REV_CRC_ERR 0x0030
#define MDDI_TA1_LEN 0x0034
#define MDDI_TA2_LEN 0x0038
#define MDDI_TEST 0x0040
#define MDDI_REV_PKT_CNT 0x0044
#define MDDI_DRIVE_HI 0x0048
#define MDDI_DRIVE_LO 0x004c
#define MDDI_DISP_WAKE 0x0050
#define MDDI_REV_ENCAP_SZ 0x0054
#define MDDI_RTD_VAL 0x0058
#define MDDI_PAD_CTL 0x0068
#define MDDI_DRIVER_START_CNT 0x006c
#define MDDI_CORE_VER 0x008c
#define MDDI_FIFO_ALLOC 0x0090
#define MDDI_PAD_IO_CTL 0x00a0
#define MDDI_PAD_CAL 0x00a4
extern u32 mddi_msg_level;
/* No longer need to write to clear these registers */
#define xxxx_mddi_host_reg_outm(reg, mask, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
mddi_host_reg_outm_pmdh(reg, mask, val); \
else \
mddi_host_reg_outm_emdh(reg, mask, val); \
} while (0)
#define mddi_host_reg_outm(reg, mask, val) \
do { \
unsigned long __addr; \
if (host_idx == MDDI_HOST_PRIM) \
__addr = (u32)msm_pmdh_base + MDDI_##reg; \
else \
__addr = (u32)msm_emdh_base + MDDI_##reg; \
writel((readl(__addr) & ~(mask)) | ((val) & (mask)), __addr); \
} while (0)
#define xxxx_mddi_host_reg_out(reg, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
mddi_host_reg_out_pmdh(reg, val); \
else \
mddi_host_reg_out_emdh(reg, val); \
} while (0)
#define mddi_host_reg_out(reg, val) \
do { \
if (host_idx == MDDI_HOST_PRIM) \
writel(val, (u32)msm_pmdh_base + MDDI_##reg); \
else \
writel(val, (u32)msm_emdh_base + MDDI_##reg); \
} while (0)
#define xxxx_mddi_host_reg_in(reg) \
((host_idx) ? \
mddi_host_reg_in_emdh(reg) : mddi_host_reg_in_pmdh(reg));
#define mddi_host_reg_in(reg) \
((host_idx) ? \
readl((u32)msm_emdh_base + MDDI_##reg) : \
readl((u32)msm_pmdh_base + MDDI_##reg)) \
#define xxxx_mddi_host_reg_inm(reg, mask) \
((host_idx) ? \
mddi_host_reg_inm_emdh(reg, mask) : \
mddi_host_reg_inm_pmdh(reg, mask);)
#define mddi_host_reg_inm(reg, mask) \
((host_idx) ? \
readl((u32)msm_emdh_base + MDDI_##reg) & (mask) : \
readl((u32)msm_pmdh_base + MDDI_##reg) & (mask)) \
/* Using non-cacheable pmem, so do nothing */
#define mddi_invalidate_cache_lines(addr_start, num_bytes)
/*
* Using non-cacheable pmem, so do nothing with cache
* but, ensure write goes out to memory
*/
#define mddi_flush_cache_lines(addr_start, num_bytes) \
(void) addr_start; \
(void) num_bytes; \
memory_barrier()
/* Since this translates to Remote Procedure Calls to check on clock status
* just use a local variable to keep track of io_clock */
#define MDDI_HOST_IS_IO_CLOCK_ON mddi_host_io_clock_on
#define MDDI_HOST_ENABLE_IO_CLOCK
#define MDDI_HOST_DISABLE_IO_CLOCK
#define MDDI_HOST_IS_HCLK_ON mddi_host_hclk_on
#define MDDI_HOST_ENABLE_HCLK
#define MDDI_HOST_DISABLE_HCLK
#define FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE
#define FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
#define TRAMP_MDDI_HOST_ISR TRAMP_MDDI_PRI_ISR
#define TRAMP_MDDI_HOST_EXT_ISR TRAMP_MDDI_EXT_ISR
#define MDP_LINE_COUNT_BMSK 0x3ff
#define MDP_SYNC_STATUS 0x000c
#define MDP_LINE_COUNT \
(readl(msm_mdp_base + MDP_SYNC_STATUS) & MDP_LINE_COUNT_BMSK)
/* MDP sends 256 pixel packets, so lower value hibernates more without
* significantly increasing latency of waiting for next subframe */
#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00
#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
#define MDDI_HOST_TA2_LEN 0x001a
#define MDDI_HOST_REV_RATE_DIV 0x0004
#else
#define MDDI_HOST_TA2_LEN 0x000c
#define MDDI_HOST_REV_RATE_DIV 0x0002
#endif
#define MDDI_MSG_EMERG(msg, ...) \
if (mddi_msg_level > 0) \
printk(KERN_EMERG msg, ## __VA_ARGS__);
#define MDDI_MSG_ALERT(msg, ...) \
if (mddi_msg_level > 1) \
printk(KERN_ALERT msg, ## __VA_ARGS__);
#define MDDI_MSG_CRIT(msg, ...) \
if (mddi_msg_level > 2) \
printk(KERN_CRIT msg, ## __VA_ARGS__);
#define MDDI_MSG_ERR(msg, ...) \
if (mddi_msg_level > 3) \
printk(KERN_ERR msg, ## __VA_ARGS__);
#define MDDI_MSG_WARNING(msg, ...) \
if (mddi_msg_level > 4) \
printk(KERN_WARNING msg, ## __VA_ARGS__);
#define MDDI_MSG_NOTICE(msg, ...) \
if (mddi_msg_level > 5) \
printk(KERN_NOTICE msg, ## __VA_ARGS__);
#define MDDI_MSG_INFO(msg, ...) \
if (mddi_msg_level > 6) \
printk(KERN_INFO msg, ## __VA_ARGS__);
#define MDDI_MSG_DEBUG(msg, ...) \
if (mddi_msg_level > 7) \
printk(KERN_DEBUG msg, ## __VA_ARGS__);
#define GCC_PACKED __attribute__((packed))
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 70 identifies the packet as
a Client status Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall
be set to zero. */
} mddi_rev_packet_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 70 identifies the packet as
a Client status Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall
be set to zero. */
uint16 reverse_link_request;
/* 16 bit unsigned integer with number of bytes client
needs in the * reverse encapsulation message
to transmit data. */
uint8 crc_error_count;
uint8 capability_change;
uint16 graphics_busy_flags;
uint16 parameter_CRC;
/* 16-bit CRC of all the bytes in the packet
including Packet Length. */
} mddi_client_status_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including
the packet_length field. */
uint16 packet_type;
/* A Packet Type of 66 identifies the packet as
a Client Capability Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and
shall be set to zero. */
uint16 Protocol_Version;
uint16 Minimum_Protocol_Version;
uint16 Data_Rate_Capability;
uint8 Interface_Type_Capability;
uint8 Number_of_Alt_Displays;
uint16 PostCal_Data_Rate;
uint16 Bitmap_Width;
uint16 Bitmap_Height;
uint16 Display_Window_Width;
uint16 Display_Window_Height;
uint32 Color_Map_Size;
uint16 Color_Map_RGB_Width;
uint16 RGB_Capability;
uint8 Monochrome_Capability;
uint8 Reserved_1;
uint16 Y_Cb_Cr_Capability;
uint16 Bayer_Capability;
uint16 Alpha_Cursor_Image_Planes;
uint32 Client_Feature_Capability_Indicators;
uint8 Maximum_Video_Frame_Rate_Capability;
uint8 Minimum_Video_Frame_Rate_Capability;
uint16 Minimum_Sub_frame_Rate;
uint16 Audio_Buffer_Depth;
uint16 Audio_Channel_Capability;
uint16 Audio_Sample_Rate_Capability;
uint8 Audio_Sample_Resolution;
uint8 Mic_Audio_Sample_Resolution;
uint16 Mic_Sample_Rate_Capability;
uint8 Keyboard_Data_Format;
uint8 pointing_device_data_format;
uint16 content_protection_type;
uint16 Mfr_Name;
uint16 Product_Code;
uint16 Reserved_3;
uint32 Serial_Number;
uint8 Week_of_Manufacture;
uint8 Year_of_Manufacture;
uint16 parameter_CRC;
/* 16-bit CRC of all the bytes in the packet including Packet Length. */
} mddi_client_capability_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including the packet_length field. */
uint16 packet_type;
/* A Packet Type of 16 identifies the packet as a Video Stream Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall be set to zero. */
uint16 video_data_format_descriptor;
/* format of each pixel in the Pixel Data in the present stream in the
* present packet.
* If bits [15:13] = 000 monochrome
* If bits [15:13] = 001 color pixels (palette).
* If bits [15:13] = 010 color pixels in raw RGB
* If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format
* If bits [15:13] = 100 Bayer pixels
*/
uint16 pixel_data_attributes;
/* interpreted as follows:
* Bits [1:0] = 11 pixel data is displayed to both eyes
* Bits [1:0] = 10 pixel data is routed to the left eye only.
* Bits [1:0] = 01 pixel data is routed to the right eye only.
* Bits [1:0] = 00 pixel data is routed to the alternate display.
* Bit 2 is 0 Pixel Data is in the standard progressive format.
* Bit 2 is 1 Pixel Data is in interlace format.
* Bit 3 is 0 Pixel Data is in the standard progressive format.
* Bit 3 is 1 Pixel Data is in alternate pixel format.
* Bit 4 is 0 Pixel Data is to or from the display frame buffer.
* Bit 4 is 1 Pixel Data is to or from the camera.
* Bit 5 is 0 pixel data contains the next consecutive row of pixels.
* Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge,
* X Start, and Y Start parameters are not defined and
* shall be ignored by the client.
* Bits [7:6] = 01 Pixel data is written to the offline image buffer.
* Bits [7:6] = 00 Pixel data is written to the buffer to refresh display.
* Bits [7:6] = 11 Pixel data is written to all image buffers.
* Bits [7:6] = 10 Invalid. Reserved for future use.
* Bits 8 through 11 alternate display number.
* Bits 12 through 14 are reserved for future use and shall be set to zero.
* Bit 15 is 1 the row of pixels is the last row of pixels in a frame.
*/
uint16 x_left_edge;
uint16 y_top_edge;
/* X,Y coordinate of the top left edge of the screen window */
uint16 x_right_edge;
uint16 y_bottom_edge;
/* X,Y coordinate of the bottom right edge of the window being updated. */
uint16 x_start;
uint16 y_start;
/* (X Start, Y Start) is the first pixel in the Pixel Data field below. */
uint16 pixel_count;
/* number of pixels in the Pixel Data field below. */
uint16 parameter_CRC;
/* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */
uint16 reserved;
/* 16-bit variable to make structure align on 4 byte boundary */
} mddi_video_stream_packet_type;
typedef struct GCC_PACKED {
uint16 packet_length;
/* total # of bytes in the packet not including the packet_length field. */
uint16 packet_type;
/* A Packet Type of 146 identifies the packet as a Register Access Packet. */
uint16 bClient_ID;
/* This field is reserved for future use and shall be set to zero. */
uint16 read_write_info;
/* Bits 13:0 a 14-bit unsigned integer that specifies the number of
* 32-bit Register Data List items to be transferred in the
* Register Data List field.
* Bits[15:14] = 00 Write to register(s);
* Bits[15:14] = 10 Read from register(s);
* Bits[15:14] = 11 Response to a Read.
* Bits[15:14] = 01 this value is reserved for future use. */
uint32 register_address;
/* the register address that is to be written to or read from. */
uint16 parameter_CRC;
/* 16-bit CRC of all bytes from the Packet Length to the Register Address. */
uint32 register_data_list;
/* list of 4-byte register data values for/from client registers */
} mddi_register_access_packet_type;
typedef union GCC_PACKED {
mddi_video_stream_packet_type video_pkt;
mddi_register_access_packet_type register_pkt;
/* add 48 byte pad to ensure 64 byte llist struct, that can be
* manipulated easily with cache */
uint32 alignment_pad[12]; /* 48 bytes */
} mddi_packet_header_type;
typedef struct GCC_PACKED mddi_host_llist_struct {
uint16 link_controller_flags;
uint16 packet_header_count;
uint16 packet_data_count;
void *packet_data_pointer;
struct mddi_host_llist_struct *next_packet_pointer;
uint16 reserved;
mddi_packet_header_type packet_header;
} mddi_linked_list_type;
typedef struct {
struct completion done_comp;
mddi_llist_done_cb_type done_cb;
uint16 next_idx;
boolean waiting;
boolean in_use;
} mddi_linked_list_notify_type;
#define MDDI_LLIST_POOL_SIZE 0x1000
#define MDDI_MAX_NUM_LLIST_ITEMS (MDDI_LLIST_POOL_SIZE / \
sizeof(mddi_linked_list_type))
#define UNASSIGNED_INDEX MDDI_MAX_NUM_LLIST_ITEMS
#define MDDI_FIRST_DYNAMIC_LLIST_IDX 0
/* Static llist items can be used for applications that frequently send
* the same set of packets using the linked list interface. */
/* Here we configure for 6 static linked list items:
* The 1st is used for a the adaptive backlight setting.
* and the remaining 5 are used for sending window adjustments for
* MDDI clients that need windowing info sent separate from video
* packets. */
#define MDDI_NUM_STATIC_ABL_ITEMS 1
#define MDDI_NUM_STATIC_WINDOW_ITEMS 5
#define MDDI_NUM_STATIC_LLIST_ITEMS (MDDI_NUM_STATIC_ABL_ITEMS + \
MDDI_NUM_STATIC_WINDOW_ITEMS)
#define MDDI_NUM_DYNAMIC_LLIST_ITEMS (MDDI_MAX_NUM_LLIST_ITEMS - \
MDDI_NUM_STATIC_LLIST_ITEMS)
#define MDDI_FIRST_STATIC_LLIST_IDX MDDI_NUM_DYNAMIC_LLIST_ITEMS
#define MDDI_FIRST_STATIC_ABL_IDX MDDI_FIRST_STATIC_LLIST_IDX
#define MDDI_FIRST_STATIC_WINDOW_IDX (MDDI_FIRST_STATIC_LLIST_IDX + \
MDDI_NUM_STATIC_ABL_ITEMS)
/* GPIO registers */
#define VSYNC_WAKEUP_REG 0x80
#define GPIO_REG 0x81
#define GPIO_OUTPUT_REG 0x82
#define GPIO_INTERRUPT_REG 0x83
#define GPIO_INTERRUPT_ENABLE_REG 0x84
#define GPIO_POLARITY_REG 0x85
/* Interrupt Bits */
#define MDDI_INT_PRI_PTR_READ 0x0001
#define MDDI_INT_SEC_PTR_READ 0x0002
#define MDDI_INT_REV_DATA_AVAIL 0x0004
#define MDDI_INT_DISP_REQ 0x0008
#define MDDI_INT_PRI_UNDERFLOW 0x0010
#define MDDI_INT_SEC_UNDERFLOW 0x0020
#define MDDI_INT_REV_OVERFLOW 0x0040
#define MDDI_INT_CRC_ERROR 0x0080
#define MDDI_INT_MDDI_IN 0x0100
#define MDDI_INT_PRI_OVERWRITE 0x0200
#define MDDI_INT_SEC_OVERWRITE 0x0400
#define MDDI_INT_REV_OVERWRITE 0x0800
#define MDDI_INT_DMA_FAILURE 0x1000
#define MDDI_INT_LINK_ACTIVE 0x2000
#define MDDI_INT_IN_HIBERNATION 0x4000
#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000
#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000
#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000
#define MDDI_INT_RTD_FAILURE 0x40000
#define MDDI_INT_ERROR_CONDITIONS ( \
MDDI_INT_PRI_UNDERFLOW | MDDI_INT_SEC_UNDERFLOW | \
MDDI_INT_REV_OVERFLOW | MDDI_INT_CRC_ERROR | \
MDDI_INT_PRI_OVERWRITE | MDDI_INT_SEC_OVERWRITE | \
MDDI_INT_RTD_FAILURE | \
MDDI_INT_REV_OVERWRITE | MDDI_INT_DMA_FAILURE)
#define MDDI_INT_LINK_STATE_CHANGES ( \
MDDI_INT_LINK_ACTIVE | MDDI_INT_IN_HIBERNATION)
/* Status Bits */
#define MDDI_STAT_LINK_ACTIVE 0x0001
#define MDDI_STAT_NEW_REV_PTR 0x0002
#define MDDI_STAT_NEW_PRI_PTR 0x0004
#define MDDI_STAT_NEW_SEC_PTR 0x0008
#define MDDI_STAT_IN_HIBERNATION 0x0010
#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020
#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040
#define MDDI_STAT_PENDING_TIMING_PKT 0x0080
#define MDDI_STAT_PENDING_REV_ENCAP 0x0100
#define MDDI_STAT_PENDING_POWERDOWN 0x0200
#define MDDI_STAT_RTD_MEAS_FAIL 0x0800
#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000
/* Command Bits */
#define MDDI_CMD_POWERDOWN 0x0100
#define MDDI_CMD_POWERUP 0x0200
#define MDDI_CMD_HIBERNATE 0x0300
#define MDDI_CMD_RESET 0x0400
#define MDDI_CMD_DISP_IGNORE 0x0501
#define MDDI_CMD_DISP_LISTEN 0x0500
#define MDDI_CMD_SEND_REV_ENCAP 0x0600
#define MDDI_CMD_GET_CLIENT_CAP 0x0601
#define MDDI_CMD_GET_CLIENT_STATUS 0x0602
#define MDDI_CMD_SEND_RTD 0x0700
#define MDDI_CMD_LINK_ACTIVE 0x0900
#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00
extern void mddi_host_init(mddi_host_type host);
extern void mddi_host_powerdown(mddi_host_type host);
extern uint16 mddi_get_next_free_llist_item(mddi_host_type host, boolean wait);
extern uint16 mddi_get_reg_read_llist_item(mddi_host_type host, boolean wait);
extern void mddi_queue_forward_packets(uint16 first_llist_idx,
uint16 last_llist_idx,
boolean wait,
mddi_llist_done_cb_type llist_done_cb,
mddi_host_type host);
extern void mddi_host_write_pix_attr_reg(uint32 value);
extern void mddi_client_lcd_gpio_poll(uint32 poll_reg_val);
extern void mddi_client_lcd_vsync_detected(boolean detected);
extern void mddi_host_disable_hibernation(boolean disable);
extern mddi_linked_list_type *llist_extern[];
extern mddi_linked_list_type *llist_dma_extern[];
extern mddi_linked_list_notify_type *llist_extern_notify[];
extern struct timer_list mddi_host_timer;
typedef struct {
uint16 transmitting_start_idx;
uint16 transmitting_end_idx;
uint16 waiting_start_idx;
uint16 waiting_end_idx;
uint16 reg_read_idx;
uint16 next_free_idx;
boolean reg_read_waiting;
} mddi_llist_info_type;
extern mddi_llist_info_type mddi_llist;
#define MDDI_GPIO_DEFAULT_POLLING_INTERVAL 200
typedef struct {
uint32 polling_reg;
uint32 polling_val;
uint32 polling_interval;
boolean polling_enabled;
} mddi_gpio_info_type;
uint32 mddi_get_client_id(void);
void mddi_mhctl_remove(mddi_host_type host_idx);
void mddi_host_timer_service(unsigned long data);
#endif /* MDDIHOSTI_H */

1113
drivers/staging/msm/mdp.c Normal file

File diff suppressed because it is too large Load Diff

695
drivers/staging/msm/mdp.h Normal file
View File

@ -0,0 +1,695 @@
/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP_H
#define MDP_H
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/hrtimer.h>
#include "msm_mdp.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include "msm_fb_panel.h"
#ifdef CONFIG_MDP_PPP_ASYNC_OP
#include "mdp_ppp_dq.h"
#endif
#ifdef BIT
#undef BIT
#endif
#define BIT(x) (1<<(x))
#define MDPOP_NOP 0
#define MDPOP_LR BIT(0) /* left to right flip */
#define MDPOP_UD BIT(1) /* up and down flip */
#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */
#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR)
#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
#define MDPOP_ASCALE BIT(7)
#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */
#define MDPOP_TRANSP BIT(9) /* enable transparency */
#define MDPOP_DITHER BIT(10) /* enable dither */
#define MDPOP_SHARPENING BIT(11) /* enable sharpening */
#define MDPOP_BLUR BIT(12) /* enable blur */
#define MDPOP_FG_PM_ALPHA BIT(13)
struct mdp_table_entry {
uint32_t reg;
uint32_t val;
};
extern struct mdp_ccs mdp_ccs_yuv2rgb ;
extern struct mdp_ccs mdp_ccs_rgb2yuv ;
/*
* MDP Image Structure
*/
typedef struct mdpImg_ {
uint32 imgType; /* Image type */
uint32 *bmy_addr; /* bitmap or y addr */
uint32 *cbcr_addr; /* cbcr addr */
uint32 width; /* image width */
uint32 mdpOp; /* image opertion (rotation,flip up/down, alpha/tp) */
uint32 tpVal; /* transparency color */
uint32 alpha; /* alpha percentage 0%(0x0) ~ 100%(0x100) */
int sp_value; /* sharpening strength */
} MDPIMG;
#ifdef CONFIG_MDP_PPP_ASYNC_OP
#define MDP_OUTP(addr, data) mdp_ppp_outdw((uint32_t)(addr), \
(uint32_t)(data))
#else
#define MDP_OUTP(addr, data) outpdw((addr), (data))
#endif
#define MDP_KTIME2USEC(kt) (kt.tv.sec*1000000 + kt.tv.nsec/1000)
#define MDP_BASE msm_mdp_base
typedef enum {
MDP_BC_SCALE_POINT2_POINT4,
MDP_BC_SCALE_POINT4_POINT6,
MDP_BC_SCALE_POINT6_POINT8,
MDP_BC_SCALE_POINT8_1,
MDP_BC_SCALE_UP,
MDP_PR_SCALE_POINT2_POINT4,
MDP_PR_SCALE_POINT4_POINT6,
MDP_PR_SCALE_POINT6_POINT8,
MDP_PR_SCALE_POINT8_1,
MDP_PR_SCALE_UP,
MDP_SCALE_BLUR,
MDP_INIT_SCALE
} MDP_SCALE_MODE;
typedef enum {
MDP_BLOCK_POWER_OFF,
MDP_BLOCK_POWER_ON
} MDP_BLOCK_POWER_STATE;
typedef enum {
MDP_MASTER_BLOCK,
MDP_CMD_BLOCK,
MDP_PPP_BLOCK,
MDP_DMA2_BLOCK,
MDP_DMA3_BLOCK,
MDP_DMA_S_BLOCK,
MDP_DMA_E_BLOCK,
MDP_OVERLAY0_BLOCK,
MDP_OVERLAY1_BLOCK,
MDP_MAX_BLOCK
} MDP_BLOCK_TYPE;
/* Let's keep Q Factor power of 2 for optimization */
#define MDP_SCALE_Q_FACTOR 512
#ifdef CONFIG_FB_MSM_MDP31
#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
#else
#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
#endif
/* SHIM Q Factor */
#define PHI_Q_FACTOR 29
#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
#define MDP_CONVTP(tpVal) (((tpVal&0xF800)<<8)|((tpVal&0x7E0)<<5)|((tpVal&0x1F)<<3))
#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
#define MDP_CHKBIT(val, bit) ((bit) == ((val) & (bit)))
/* overlay interface API defines */
typedef enum {
MORE_IBUF,
FINAL_IBUF,
COMPLETE_IBUF
} MDP_IBUF_STATE;
struct mdp_dirty_region {
__u32 xoffset; /* source origin in the x-axis */
__u32 yoffset; /* source origin in the y-axis */
__u32 width; /* number of pixels in the x-axis */
__u32 height; /* number of pixels in the y-axis */
};
/*
* MDP extended data types
*/
typedef struct mdp_roi_s {
uint32 x;
uint32 y;
uint32 width;
uint32 height;
int32 lcd_x;
int32 lcd_y;
uint32 dst_width;
uint32 dst_height;
} MDP_ROI;
typedef struct mdp_ibuf_s {
uint8 *buf;
uint32 bpp;
uint32 ibuf_type;
uint32 ibuf_width;
uint32 ibuf_height;
MDP_ROI roi;
MDPIMG mdpImg;
int32 dma_x;
int32 dma_y;
uint32 dma_w;
uint32 dma_h;
uint32 vsync_enable;
uint32 visible_swapped;
} MDPIBUF;
struct mdp_dma_data {
boolean busy;
boolean waiting;
struct mutex ov_mutex;
struct semaphore mutex;
struct completion comp;
};
#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000)
#define MDP_DMA2_TERM 0x1
#define MDP_DMA3_TERM 0x2
#define MDP_PPP_TERM 0x4
#define MDP_DMA_S_TERM 0x8
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_DMA_E_TERM 0x10
#define MDP_OVERLAY0_TERM 0x20
#define MDP_OVERLAY1_TERM 0x40
#endif
#define ACTIVE_START_X_EN BIT(31)
#define ACTIVE_START_Y_EN BIT(31)
#define ACTIVE_HIGH 0
#define ACTIVE_LOW 1
#define MDP_DMA_S_DONE BIT(2)
#define LCDC_FRAME_START BIT(15)
#define LCDC_UNDERFLOW BIT(16)
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_DMA_P_DONE BIT(2)
#else
#define MDP_DMA_P_DONE BIT(14)
#endif
#define MDP_PPP_DONE BIT(0)
#define TV_OUT_DMA3_DONE BIT(6)
#define TV_ENC_UNDERRUN BIT(7)
#define TV_OUT_DMA3_START BIT(13)
#define MDP_HIST_DONE BIT(20)
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
MDP_DMA_P_DONE| \
TV_ENC_UNDERRUN)
#else
#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
MDP_DMA_P_DONE| \
MDP_DMA_S_DONE| \
LCDC_UNDERFLOW| \
MDP_HIST_DONE| \
TV_ENC_UNDERRUN)
#endif
#define MDP_TOP_LUMA 16
#define MDP_TOP_CHROMA 0
#define MDP_BOTTOM_LUMA 19
#define MDP_BOTTOM_CHROMA 3
#define MDP_LEFT_LUMA 22
#define MDP_LEFT_CHROMA 6
#define MDP_RIGHT_LUMA 25
#define MDP_RIGHT_CHROMA 9
#define CLR_G 0x0
#define CLR_B 0x1
#define CLR_R 0x2
#define CLR_ALPHA 0x3
#define CLR_Y CLR_G
#define CLR_CB CLR_B
#define CLR_CR CLR_R
/* from lsb to msb */
#define MDP_GET_PACK_PATTERN(a,x,y,z,bit) (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
/*
* 0x0000 0x0004 0x0008 MDP sync config
*/
#ifdef CONFIG_FB_MSM_MDP22
#define MDP_SYNCFG_HGT_LOC 22
#define MDP_SYNCFG_VSYNC_EXT_EN BIT(21)
#define MDP_SYNCFG_VSYNC_INT_EN BIT(20)
#else
#define MDP_SYNCFG_HGT_LOC 21
#define MDP_SYNCFG_VSYNC_EXT_EN BIT(20)
#define MDP_SYNCFG_VSYNC_INT_EN BIT(19)
#define MDP_HW_VSYNC
#endif
/*
* 0x0018 MDP VSYNC THREASH
*/
#define MDP_PRIM_BELOW_LOC 0
#define MDP_PRIM_ABOVE_LOC 8
/*
* MDP_PRIMARY_VSYNC_OUT_CTRL
* 0x0080,84,88 internal vsync pulse config
*/
#define VSYNC_PULSE_EN BIT(31)
#define VSYNC_PULSE_INV BIT(30)
/*
* 0x008c MDP VSYNC CONTROL
*/
#define DISP0_VSYNC_MAP_VSYNC0 0
#define DISP0_VSYNC_MAP_VSYNC1 BIT(0)
#define DISP0_VSYNC_MAP_VSYNC2 BIT(0)|BIT(1)
#define DISP1_VSYNC_MAP_VSYNC0 0
#define DISP1_VSYNC_MAP_VSYNC1 BIT(2)
#define DISP1_VSYNC_MAP_VSYNC2 BIT(2)|BIT(3)
#define PRIMARY_LCD_SYNC_EN BIT(4)
#define PRIMARY_LCD_SYNC_DISABLE 0
#define SECONDARY_LCD_SYNC_EN BIT(5)
#define SECONDARY_LCD_SYNC_DISABLE 0
#define EXTERNAL_LCD_SYNC_EN BIT(6)
#define EXTERNAL_LCD_SYNC_DISABLE 0
/*
* 0x101f0 MDP VSYNC Threshold
*/
#define VSYNC_THRESHOLD_ABOVE_LOC 0
#define VSYNC_THRESHOLD_BELOW_LOC 16
#define VSYNC_ANTI_TEAR_EN BIT(31)
/*
* 0x10004 command config
*/
#define MDP_CMD_DBGBUS_EN BIT(0)
/*
* 0x10124 or 0x101d4PPP source config
*/
#define PPP_SRC_C0G_8BITS (BIT(1)|BIT(0))
#define PPP_SRC_C1B_8BITS (BIT(3)|BIT(2))
#define PPP_SRC_C2R_8BITS (BIT(5)|BIT(4))
#define PPP_SRC_C3A_8BITS (BIT(7)|BIT(6))
#define PPP_SRC_C0G_6BITS BIT(1)
#define PPP_SRC_C1B_6BITS BIT(3)
#define PPP_SRC_C2R_6BITS BIT(5)
#define PPP_SRC_C0G_5BITS BIT(0)
#define PPP_SRC_C1B_5BITS BIT(2)
#define PPP_SRC_C2R_5BITS BIT(4)
#define PPP_SRC_C3_ALPHA_EN BIT(8)
#define PPP_SRC_BPP_INTERLVD_1BYTES 0
#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
/*
* RGB666 unpack format
* TIGHT means R6+G6+B6 together
* LOOSE means R6+2 +G6+2+ B6+2 (with MSB)
* or 2+R6 +2+G6 +2+B6 (with LSB)
*/
#define PPP_SRC_UNPACK_TIGHT BIT(17)
#define PPP_SRC_UNPACK_LOOSE 0
#define PPP_SRC_UNPACK_ALIGN_LSB 0
#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
#define PPP_SRC_FETCH_PLANES_INTERLVD 0
#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
#define PPP_SRC_WMV9_MODE BIT(21) /* window media version 9 */
/*
* 0x10138 PPP operation config
*/
#define PPP_OP_SCALE_X_ON BIT(0)
#define PPP_OP_SCALE_Y_ON BIT(1)
#define PPP_OP_CONVERT_RGB2YCBCR 0
#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
#define PPP_OP_CONVERT_ON BIT(3)
#define PPP_OP_CONVERT_MATRIX_PRIMARY 0
#define PPP_OP_CONVERT_MATRIX_SECONDARY BIT(4)
#define PPP_OP_LUT_C0_ON BIT(5)
#define PPP_OP_LUT_C1_ON BIT(6)
#define PPP_OP_LUT_C2_ON BIT(7)
/* rotate or blend enable */
#define PPP_OP_ROT_ON BIT(8)
#define PPP_OP_ROT_90 BIT(9)
#define PPP_OP_FLIP_LR BIT(10)
#define PPP_OP_FLIP_UD BIT(11)
#define PPP_OP_BLEND_ON BIT(12)
#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
#define PPP_OP_BLEND_DSTPIXEL_ALPHA BIT(13)
#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
#define PPP_OP_BLEND_SRCPIXEL_TRANSP (BIT(13)|BIT(14))
#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
#define PPP_OP_DITHER_EN BIT(16)
#define PPP_OP_COLOR_SPACE_RGB 0
#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
#define PPP_OP_SRC_CHROMA_RGB 0
#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
#define PPP_OP_SRC_CHROMA_COSITE 0
#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
#define PPP_OP_DST_CHROMA_RGB 0
#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
#define PPP_OP_DST_CHROMA_H1V2 BIT(22)
#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
#define PPP_OP_DST_CHROMA_COSITE 0
#define PPP_OP_DST_CHROMA_OFFSITE BIT(23)
#define PPP_BLEND_CALPHA_TRNASP BIT(24)
#define PPP_OP_BG_CHROMA_RGB 0
#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
#define PPP_OP_BG_CHROMA_H1V2 BIT(26)
#define PPP_OP_BG_CHROMA_420 BIT(25)|BIT(26)
#define PPP_OP_BG_CHROMA_SITE_COSITE 0
#define PPP_OP_BG_CHROMA_SITE_OFFSITE BIT(27)
#define PPP_OP_DEINT_EN BIT(29)
#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0)
#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3)
#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1)
#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1)
#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1)
#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
#define PPP_OP_DST_RGB 0
#define PPP_OP_DST_YCBCR BIT(30)
/*
* 0x10150 PPP destination config
*/
#define PPP_DST_C0G_8BIT (BIT(0)|BIT(1))
#define PPP_DST_C1B_8BIT (BIT(3)|BIT(2))
#define PPP_DST_C2R_8BIT (BIT(5)|BIT(4))
#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
#define PPP_DST_C0G_6BIT BIT(1)
#define PPP_DST_C1B_6BIT BIT(3)
#define PPP_DST_C2R_6BIT BIT(5)
#define PPP_DST_C0G_5BIT BIT(0)
#define PPP_DST_C1B_5BIT BIT(2)
#define PPP_DST_C2R_5BIT BIT(4)
#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
#define PPP_DST_C3ALPHA_EN BIT(8)
#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
#define PPP_DST_PACK_LOOSE 0
#define PPP_DST_PACK_TIGHT BIT(13)
#define PPP_DST_PACK_ALIGN_LSB 0
#define PPP_DST_PACK_ALIGN_MSB BIT(14)
#define PPP_DST_OUT_SEL_AXI 0
#define PPP_DST_OUT_SEL_MDDI BIT(15)
#define PPP_DST_BPP_2BYTES BIT(16)
#define PPP_DST_BPP_3BYTES BIT(17)
#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
#define PPP_DST_PLANE_INTERLVD 0
#define PPP_DST_PLANE_PLANAR BIT(18)
#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
#define PPP_DST_TO_TV BIT(20)
#define PPP_DST_MDDI_PRIMARY 0
#define PPP_DST_MDDI_SECONDARY BIT(21)
#define PPP_DST_MDDI_EXTERNAL BIT(22)
/*
* 0x10180 DMA config
*/
#define DMA_DSTC0G_8BITS (BIT(1)|BIT(0))
#define DMA_DSTC1B_8BITS (BIT(3)|BIT(2))
#define DMA_DSTC2R_8BITS (BIT(5)|BIT(4))
#define DMA_DSTC0G_6BITS BIT(1)
#define DMA_DSTC1B_6BITS BIT(3)
#define DMA_DSTC2R_6BITS BIT(5)
#define DMA_DSTC0G_5BITS BIT(0)
#define DMA_DSTC1B_5BITS BIT(2)
#define DMA_DSTC2R_5BITS BIT(4)
#define DMA_PACK_TIGHT BIT(6)
#define DMA_PACK_LOOSE 0
#define DMA_PACK_ALIGN_LSB 0
/*
* use DMA_PACK_ALIGN_MSB if the upper 6 bits from 8 bits output
* from LCDC block maps into 6 pins out to the panel
*/
#define DMA_PACK_ALIGN_MSB BIT(7)
#define DMA_PACK_PATTERN_RGB \
(MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8)
#define DMA_PACK_PATTERN_BGR \
(MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 2)<<8)
#define DMA_OUT_SEL_AHB 0
#define DMA_OUT_SEL_LCDC BIT(20)
#define DMA_IBUF_FORMAT_RGB888 0
#define DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888 BIT(26)
#ifdef CONFIG_FB_MSM_MDP22
#define DMA_OUT_SEL_MDDI BIT(14)
#define DMA_AHBM_LCD_SEL_PRIMARY 0
#define DMA_AHBM_LCD_SEL_SECONDARY BIT(15)
#define DMA_IBUF_C3ALPHA_EN BIT(16)
#define DMA_DITHER_EN BIT(17)
#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY BIT(18)
#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL BIT(19)
#define DMA_IBUF_FORMAT_RGB565 BIT(20)
#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0
#define DMA_IBUF_NONCONTIGUOUS BIT(21)
#else
#define DMA_OUT_SEL_MDDI BIT(19)
#define DMA_AHBM_LCD_SEL_PRIMARY 0
#define DMA_AHBM_LCD_SEL_SECONDARY 0
#define DMA_IBUF_C3ALPHA_EN 0
#define DMA_DITHER_EN BIT(24)
#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY 0
#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL 0
#define DMA_IBUF_FORMAT_RGB565 BIT(25)
#define DMA_IBUF_NONCONTIGUOUS 0
#endif
/*
* MDDI Register
*/
#define MDDI_VDO_PACKET_DESC 0x5666
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0050)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0054)
#define MDP_INTR_CLEAR (msm_mdp_base + 0x0058)
#define MDP_EBI2_LCD0 (msm_mdp_base + 0x0060)
#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0064)
#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x0070)
#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x95014)
#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x95018)
#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9501C)
#else
#define MDP_INTR_ENABLE (msm_mdp_base + 0x0020)
#define MDP_INTR_STATUS (msm_mdp_base + 0x0024)
#define MDP_INTR_CLEAR (msm_mdp_base + 0x0028)
#define MDP_EBI2_LCD0 (msm_mdp_base + 0x003c)
#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0040)
#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x005c)
#endif
#define MDP_FULL_BYPASS_WORD43 (msm_mdp_base + 0x101ac)
#define MDP_CSC_PFMVn(n) (msm_mdp_base + 0x40400 + 4 * (n))
#define MDP_CSC_PRMVn(n) (msm_mdp_base + 0x40440 + 4 * (n))
#define MDP_CSC_PRE_BV1n(n) (msm_mdp_base + 0x40500 + 4 * (n))
#define MDP_CSC_PRE_BV2n(n) (msm_mdp_base + 0x40540 + 4 * (n))
#define MDP_CSC_POST_BV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
#define MDP_CSC_POST_BV2n(n) (msm_mdp_base + 0x405c0 + 4 * (n))
#ifdef CONFIG_FB_MSM_MDP31
#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40600 + 4 * (n))
#define MDP_CSC_PRE_LV2n(n) (msm_mdp_base + 0x40640 + 4 * (n))
#define MDP_CSC_POST_LV1n(n) (msm_mdp_base + 0x40680 + 4 * (n))
#define MDP_CSC_POST_LV2n(n) (msm_mdp_base + 0x406c0 + 4 * (n))
#define MDP_PPP_SCALE_COEFF_LSBn(n) (msm_mdp_base + 0x50400 + 8 * (n))
#define MDP_PPP_SCALE_COEFF_MSBn(n) (msm_mdp_base + 0x50404 + 8 * (n))
#define SCALE_D0_SET 0
#define SCALE_D1_SET BIT(0)
#define SCALE_D2_SET BIT(1)
#define SCALE_U1_SET (BIT(0)|BIT(1))
#else
#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
#endif
#define MDP_CURSOR_WIDTH 64
#define MDP_CURSOR_HEIGHT 64
#define MDP_CURSOR_SIZE (MDP_CURSOR_WIDTH*MDP_CURSOR_WIDTH*4)
#define MDP_DMA_P_LUT_C0_EN BIT(0)
#define MDP_DMA_P_LUT_C1_EN BIT(1)
#define MDP_DMA_P_LUT_C2_EN BIT(2)
#define MDP_DMA_P_LUT_POST BIT(4)
void mdp_hw_init(void);
int mdp_ppp_pipe_wait(void);
void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd);
void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
boolean isr);
void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
boolean sync);
void mdp_dma_pan_update(struct fb_info *info);
void mdp_refresh_screen(unsigned long data);
int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
struct file **pp_src, struct file **pp_dest);
void mdp_lcd_update_workqueue_handler(struct work_struct *work);
void mdp_vsync_resync_workqueue_handler(struct work_struct *work);
void mdp_dma2_update(struct msm_fb_data_type *mfd);
void mdp_config_vsync(struct msm_fb_data_type *);
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd);
enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht);
void mdp_set_scale(MDPIBUF *iBuf,
uint32 dst_roi_width,
uint32 dst_roi_height,
boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr);
void mdp_init_scale_table(void);
void mdp_adjust_start_addr(uint8 **src0,
uint8 **src1,
int v_slice,
int h_slice,
int x,
int y,
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer);
void mdp_set_blend_attr(MDPIBUF *iBuf,
uint32 *alpha,
uint32 *tpVal,
uint32 perPixelAlpha, uint32 *pppop_reg_ptr);
int mdp_dma3_on(struct platform_device *pdev);
int mdp_dma3_off(struct platform_device *pdev);
void mdp_dma3_update(struct msm_fb_data_type *mfd);
int mdp_lcdc_on(struct platform_device *pdev);
int mdp_lcdc_off(struct platform_device *pdev);
void mdp_lcdc_update(struct msm_fb_data_type *mfd);
int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor);
void mdp_enable_irq(uint32 term);
void mdp_disable_irq(uint32 term);
void mdp_disable_irq_nolock(uint32 term);
uint32_t mdp_get_bytes_per_pixel(uint32_t format);
#ifdef MDP_HW_VSYNC
void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd);
void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd);
#endif
void mdp_dma_s_update(struct msm_fb_data_type *mfd);
/* Added to support flipping */
void mdp_set_offset_info(struct fb_info *info, uint32 address, uint32 interval);
int get_gem_img(struct mdp_img *img, unsigned long *start,
unsigned long *len);
int get_img(struct mdp_img *img, struct fb_info *info,
unsigned long *start, unsigned long *len,
struct file **pp_file);
/*int get_img(struct msmfb_data *img, struct fb_info *info,
unsigned long *start, unsigned long *len, struct file **pp_file);*/
#endif /* MDP_H */

352
drivers/staging/msm/mdp4.h Normal file
View File

@ -0,0 +1,352 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP4_H
#define MDP4_H
extern struct mdp_dma_data dma2_data;
extern struct mdp_dma_data dma_s_data;
extern struct mdp_dma_data dma_e_data;
extern struct mdp_histogram mdp_hist;
extern struct completion mdp_hist_comp;
extern boolean mdp_is_in_isr;
extern uint32 mdp_intr_mask;
extern spinlock_t mdp_spin_lock;
#define MDP4_NONBLOCKING /* enable non blocking ioctl */
#define MDP4_OVERLAYPROC0_BASE 0x10000
#define MDP4_OVERLAYPROC1_BASE 0x18000
#define MDP4_VIDEO_BASE 0x20000
#define MDP4_VIDEO_OFF 0x10000
#define MDP4_RGB_BASE 0x40000
#define MDP4_RGB_OFF 0x10000
enum { /* display */
PRIMARY_INTF_SEL,
SECONDARY_INTF_SEL,
EXTERNAL_INTF_SEL
};
enum {
LCDC_RGB_INTF,
DTV_INTF = LCDC_RGB_INTF,
MDDI_LCDC_INTF,
MDDI_INTF,
EBI2_INTF
};
enum {
MDDI_PRIMARY_SET,
MDDI_SECONDARY_SET,
MDDI_EXTERNAL_SET
};
enum {
EBI2_LCD0,
EBI2_LCD1
};
enum {
OVERLAY_MODE_NONE,
OVERLAY_MODE_BLT
};
enum {
OVERLAY_REFRESH_ON_DEMAND,
OVERLAY_REFRESH_VSYNC,
OVERLAY_REFRESH_VSYNC_HALF,
OVERLAY_REFRESH_VSYNC_QUARTER
};
enum {
OVERLAY_FRAMEBUF,
OVERLAY_DIRECTOUT
};
/* system interrupts */
#define INTR_OVERLAY0_DONE BIT(0)
#define INTR_OVERLAY1_DONE BIT(1)
#define INTR_DMA_S_DONE BIT(2)
#define INTR_DMA_E_DONE BIT(3)
#define INTR_DMA_P_DONE BIT(4)
#define INTR_VG1_HISTOGRAM BIT(5)
#define INTR_VG2_HISTOGRAM BIT(6)
#define INTR_PRIMARY_VSYNC BIT(7)
#define INTR_PRIMARY_INTF_UDERRUN BIT(8)
#define INTR_EXTERNAL_VSYNC BIT(9)
#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
#define INTR_DMA_P_HISTOGRAM BIT(17)
/* histogram interrupts */
#define INTR_HIST_DONE BIT(0)
#define INTR_HIST_RESET_SEQ_DONE BIT(1)
#ifdef CONFIG_FB_MSM_OVERLAY
#define MDP4_ANY_INTR_MASK (INTR_OVERLAY0_DONE)
#else
#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE)
#endif
enum {
OVERLAY_PIPE_RGB1,
OVERLAY_PIPE_RGB2,
};
enum {
OVERLAY_PIPE_VG1, /* video/graphic */
OVERLAY_PIPE_VG2
};
enum {
OVERLAY_TYPE_RGB,
OVERLAY_TYPE_VG /* video/graphic */
};
enum {
MDP4_MIXER0,
MDP4_MIXER1
};
#define MDP4_MAX_MIXER 2
enum {
OVERLAY_PLANE_INTERLEAVED,
OVERLAY_PLANE_PLANAR,
OVERLAY_PLANE_PSEUDO_PLANAR
};
enum {
MDP4_MIXER_STAGE_UNUNSED, /* pipe not used */
MDP4_MIXER_STAGE_BASE,
MDP4_MIXER_STAGE0, /* zorder 0 */
MDP4_MIXER_STAGE1, /* zorder 1 */
MDP4_MIXER_STAGE2 /* zorder 2 */
};
#define MDP4_MAX_STAGE 4
enum {
MDP4_FRAME_FORMAT_LINEAR,
MDP4_FRAME_FORMAT_ARGB_TILE,
MDP4_FRAME_FORMAT_VIDEO_SUPERTILE
};
enum {
MDP4_CHROMA_RGB,
MDP4_CHROMA_H2V1,
MDP4_CHROMA_H1V2,
MDP4_CHROMA_420
};
#define MDP4_BLEND_BG_TRANSP_EN BIT(9)
#define MDP4_BLEND_FG_TRANSP_EN BIT(8)
#define MDP4_BLEND_BG_MOD_ALPHA BIT(7)
#define MDP4_BLEND_BG_INV_ALPHA BIT(6)
#define MDP4_BLEND_BG_ALPHA_FG_CONST (0 << 4)
#define MDP4_BLEND_BG_ALPHA_BG_CONST (1 << 4)
#define MDP4_BLEND_BG_ALPHA_FG_PIXEL (2 << 4)
#define MDP4_BLEND_BG_ALPHA_BG_PIXEL (3 << 4)
#define MDP4_BLEND_FG_MOD_ALPHA BIT(3)
#define MDP4_BLEND_FG_INV_ALPHA BIT(2)
#define MDP4_BLEND_FG_ALPHA_FG_CONST (0 << 0)
#define MDP4_BLEND_FG_ALPHA_BG_CONST (1 << 0)
#define MDP4_BLEND_FG_ALPHA_FG_PIXEL (2 << 0)
#define MDP4_BLEND_FG_ALPHA_BG_PIXEL (3 << 0)
#define MDP4_FORMAT_SOLID_FILL BIT(22)
#define MDP4_FORMAT_UNPACK_ALIGN_MSB BIT(18)
#define MDP4_FORMAT_UNPACK_TIGHT BIT(17)
#define MDP4_FORMAT_90_ROTATED BIT(12)
#define MDP4_FORMAT_ALPHA_ENABLE BIT(8)
#define MDP4_OP_DEINT_ODD_REF BIT(19)
#define MDP4_OP_IGC_LUT_EN BIT(16)
#define MDP4_OP_DITHER_EN BIT(15)
#define MDP4_OP_FLIP_UD BIT(14)
#define MDP4_OP_FLIP_LR BIT(13)
#define MDP4_OP_CSC_EN BIT(11)
#define MDP4_OP_SRC_DATA_YCBCR BIT(9)
#define MDP4_OP_SCALEY_FIR (0 << 4)
#define MDP4_OP_SCALEY_MN_PHASE (1 << 4)
#define MDP4_OP_SCALEY_PIXEL_RPT (2 << 4)
#define MDP4_OP_SCALEX_FIR (0 << 2)
#define MDP4_OP_SCALEX_MN_PHASE (1 << 2)
#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2)
#define MDP4_OP_SCALEY_EN BIT(1)
#define MDP4_OP_SCALEX_EN BIT(0)
#define MDP4_PIPE_PER_MIXER 2
#define MDP4_MAX_PLANE 4
#define MDP4_MAX_VIDEO_PIPE 2
#define MDP4_MAX_RGB_PIPE 2
#define MDP4_MAX_OVERLAY_PIPE 16
struct mdp4_overlay_pipe {
uint32 pipe_type; /* rgb, video/graphic */
uint32 pipe_num;
uint32 pipe_ndx;
uint32 mixer_num; /* which mixer used */
uint32 mixer_stage; /* which stage of mixer used */
uint32 src_format;
uint32 src_width; /* source img width */
uint32 src_height; /* source img height */
uint32 src_w; /* roi */
uint32 src_h; /* roi */
uint32 src_x; /* roi */
uint32 src_y; /* roi */
uint32 dst_w; /* roi */
uint32 dst_h; /* roi */
uint32 dst_x; /* roi */
uint32 dst_y; /* roi */
uint32 op_mode;
uint32 transp;
uint32 blend_op;
uint32 phasex_step;
uint32 phasey_step;
uint32 alpha;
uint32 is_fg; /* control alpha & color key */
uint32 srcp0_addr; /* interleave, luma */
uint32 srcp0_ystride;
uint32 srcp1_addr; /* pseudoplanar, chroma plane */
uint32 srcp1_ystride;
uint32 srcp2_addr; /* planar color 2*/
uint32 srcp2_ystride;
uint32 srcp3_addr; /* alpha/color 3 */
uint32 srcp3_ystride;
uint32 fetch_plane;
uint32 frame_format; /* video */
uint32 chroma_site; /* video */
uint32 chroma_sample; /* video */
uint32 solid_fill;
uint32 vc1_reduce; /* video */
uint32 fatch_planes; /* video */
uint32 unpack_align_msb;/* 0 to LSB, 1 to MSB */
uint32 unpack_tight;/* 0 for loose, 1 for tight */
uint32 unpack_count;/* 0 = 1 component, 1 = 2 component ... */
uint32 rotated_90; /* has been rotated 90 degree */
uint32 bpp; /* byte per pixel */
uint32 alpha_enable;/* source has alpha */
/*
* number of bits for source component,
* 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
*/
uint32 a_bit; /* component 3, alpha */
uint32 r_bit; /* component 2, R_Cr */
uint32 b_bit; /* component 1, B_Cb */
uint32 g_bit; /* component 0, G_lumz */
/*
* unpack pattern
* A = C3, R = C2, B = C1, G = C0
*/
uint32 element3; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element2; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element1; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
uint32 element0; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
struct completion comp;
struct mdp_overlay req_data;
};
void mdp4_sw_reset(unsigned long bits);
void mdp4_display_intf_sel(int output, unsigned long intf);
void mdp4_overlay_cfg(int layer, int blt_mode, int refresh, int direct_out);
void mdp4_ebi2_lcd_setup(int lcd, unsigned long base, int ystride);
void mdp4_mddi_setup(int which, unsigned long id);
unsigned long mdp4_display_status(void);
void mdp4_enable_clk_irq(void);
void mdp4_disable_clk_irq(void);
void mdp4_dma_p_update(struct msm_fb_data_type *mfd);
void mdp4_dma_s_update(struct msm_fb_data_type *mfd);
void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
boolean isr);
void mdp4_pipe_kickoff(uint32 pipe, struct msm_fb_data_type *mfd);
int mdp4_lcdc_on(struct platform_device *pdev);
int mdp4_lcdc_off(struct platform_device *pdev);
void mdp4_lcdc_update(struct msm_fb_data_type *mfd);
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
void mdp4_mixer_blend_init(int mixer_num);
void mdp4_vg_qseed_init(int vg_num);
void mdp4_vg_csc_mv_setup(int vp_num);
void mdp4_vg_csc_pre_bv_setup(int vp_num);
void mdp4_vg_csc_post_bv_setup(int vp_num);
void mdp4_vg_csc_pre_lv_setup(int vp_num);
void mdp4_vg_csc_post_lv_setup(int vp_num);
irqreturn_t mdp4_isr(int irq, void *ptr);
void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe);
void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe);
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd);
int mdp4_overlay_format2type(uint32 format);
int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_unset(struct fb_info *info, int ndx);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req,
struct file **pp_src_file);
struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void);
void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc);
void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_active(int mixer);
void mdp4_overlay0_done_lcdc(void);
void mdp4_overlay0_done_mddi(void);
void mdp4_mddi_overlay_restore(void);
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_rgb_igc_lut_setup(int num);
void mdp4_vg_igc_lut_setup(int num);
void mdp4_mixer_gc_lut_setup(int mixer_num);
#ifdef CONFIG_DEBUG_FS
int mdp4_debugfs_init(void);
#endif
int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
struct file **pp_src_file, struct file **pp_dst_file);
#endif /* MDP_H */

View File

@ -0,0 +1,181 @@
/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/hrtimer.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#define MDP4_DEBUG_BUF 128
static char mdp4_debug_buf[MDP4_DEBUG_BUF];
static ulong mdp4_debug_offset;
static ulong mdp4_base_addr;
static int mdp4_offset_set(void *data, u64 val)
{
mdp4_debug_offset = (int)val;
return 0;
}
static int mdp4_offset_get(void *data, u64 *val)
{
*val = (u64)mdp4_debug_offset;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(
mdp4_offset_fops,
mdp4_offset_get,
mdp4_offset_set,
"%llx\n");
static int mdp4_debugfs_open(struct inode *inode, struct file *file)
{
/* non-seekable */
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
return 0;
}
static int mdp4_debugfs_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t mdp4_debugfs_write(
struct file *file,
const char __user *buff,
size_t count,
loff_t *ppos)
{
int cnt;
unsigned int data;
printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
__func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
if (count > sizeof(mdp4_debug_buf))
return -EFAULT;
if (copy_from_user(mdp4_debug_buf, buff, count))
return -EFAULT;
mdp4_debug_buf[count] = 0; /* end of string */
cnt = sscanf(mdp4_debug_buf, "%x", &data);
if (cnt < 1) {
printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
return -EINVAL;
}
writel(&data, mdp4_base_addr + mdp4_debug_offset);
return 0;
}
static ssize_t mdp4_debugfs_read(
struct file *file,
char __user *buff,
size_t count,
loff_t *ppos)
{
int len = 0;
unsigned int data;
printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
__func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
if (*ppos)
return 0; /* the end */
data = readl(mdp4_base_addr + mdp4_debug_offset);
len = snprintf(mdp4_debug_buf, 4, "%x\n", data);
if (len > 0) {
if (len > count)
len = count;
if (copy_to_user(buff, mdp4_debug_buf, len))
return -EFAULT;
}
printk(KERN_INFO "%s: len=%d\n", __func__, len);
if (len < 0)
return 0;
*ppos += len; /* increase offset */
return len;
}
static const struct file_operations mdp4_debugfs_fops = {
.open = mdp4_debugfs_open,
.release = mdp4_debugfs_release,
.read = mdp4_debugfs_read,
.write = mdp4_debugfs_write,
};
int mdp4_debugfs_init(void)
{
struct dentry *dent = debugfs_create_dir("mdp4", NULL);
if (IS_ERR(dent)) {
printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
__FILE__, __LINE__, PTR_ERR(dent));
return -1;
}
if (debugfs_create_file("offset", 0644, dent, 0, &mdp4_offset_fops)
== NULL) {
printk(KERN_ERR "%s(%d): debugfs_create_file: offset fail\n",
__FILE__, __LINE__);
return -1;
}
if (debugfs_create_file("regs", 0644, dent, 0, &mdp4_debugfs_fops)
== NULL) {
printk(KERN_ERR "%s(%d): debugfs_create_file: regs fail\n",
__FILE__, __LINE__);
return -1;
}
mdp4_debug_offset = 0;
mdp4_base_addr = (ulong) msm_mdp_base; /* defined at msm_fb_def.h */
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,313 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#ifdef CONFIG_FB_MSM_MDP40
#define LCDC_BASE 0xC0000
#else
#define LCDC_BASE 0xE0000
#endif
int first_pixel_start_x;
int first_pixel_start_y;
static struct mdp4_overlay_pipe *lcdc_pipe;
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
int lcdc_height;
int lcdc_bpp;
int lcdc_border_clr;
int lcdc_underflow_clr;
int lcdc_hsync_skew;
int hsync_period;
int hsync_ctrl;
int vsync_period;
int display_hctl;
int display_v_start;
int display_v_end;
int active_hctl;
int active_h_start;
int active_h_end;
int active_v_start;
int active_v_end;
int ctrl_polarity;
int h_back_porch;
int h_front_porch;
int v_back_porch;
int v_front_porch;
int hsync_pulse_width;
int vsync_pulse_width;
int hsync_polarity;
int vsync_polarity;
int data_en_polarity;
int hsync_start_x;
int hsync_end_x;
uint8 *buf;
int bpp, ptype;
uint32 format;
struct fb_info *fbi;
struct fb_var_screeninfo *var;
struct msm_fb_data_type *mfd;
struct mdp4_overlay_pipe *pipe;
int ret;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
var = &fbi->var;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
if (bpp == 2)
format = MDP_RGB_565;
else if (bpp == 3)
format = MDP_RGB_888;
else
format = MDP_ARGB_8888;
if (lcdc_pipe == NULL) {
ptype = mdp4_overlay_format2type(format);
pipe = mdp4_overlay_pipe_alloc();
pipe->pipe_type = ptype;
/* use RGB1 pipe */
pipe->pipe_num = OVERLAY_PIPE_RGB1;
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = format;
mdp4_overlay_format2pipe(pipe);
lcdc_pipe = pipe; /* keep it */
} else {
pipe = lcdc_pipe;
}
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->srcp0_addr = (uint32) buf;
pipe->srcp0_ystride = fbi->fix.line_length;
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
/*
* LCDC timing setting
*/
h_back_porch = var->left_margin;
h_front_porch = var->right_margin;
v_back_porch = var->upper_margin;
v_front_porch = var->lower_margin;
hsync_pulse_width = var->hsync_len;
vsync_pulse_width = var->vsync_len;
lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
lcdc_width = mfd->panel_info.xres;
lcdc_height = mfd->panel_info.yres;
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
hsync_start_x = hsync_pulse_width + h_back_porch;
hsync_end_x = hsync_period - h_front_porch - 1;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
vsync_period =
(vsync_pulse_width + v_back_porch + lcdc_height +
v_front_porch) * hsync_period;
display_v_start =
(vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
display_v_end =
vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
if (lcdc_width != var->xres) {
active_h_start = hsync_start_x + first_pixel_start_x;
active_h_end = active_h_start + var->xres - 1;
active_hctl =
ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
} else {
active_hctl = 0;
}
if (lcdc_height != var->yres) {
active_v_start =
display_v_start + first_pixel_start_y * hsync_period;
active_v_end = active_v_start + (var->yres) * hsync_period - 1;
active_v_start |= ACTIVE_START_Y_EN;
} else {
active_v_start = 0;
active_v_end = 0;
}
#ifdef CONFIG_FB_MSM_MDP40
hsync_polarity = 1;
vsync_polarity = 1;
lcdc_underflow_clr |= 0x80000000; /* enable recovery */
#else
hsync_polarity = 0;
vsync_polarity = 0;
#endif
data_en_polarity = 0;
ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start);
MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */
MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
}
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
int mdp_lcdc_off(struct platform_device *pdev)
{
int ret = 0;
struct mdp4_overlay_pipe *pipe;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_off(pdev);
/* delay to make sure the last frame finishes */
mdelay(100);
/* dis-engage rgb0 from mixer */
pipe = lcdc_pipe;
mdp4_mixer_stage_down(pipe);
return ret;
}
/*
* mdp4_overlay0_done_lcdc: called from isr
*/
void mdp4_overlay0_done_lcdc()
{
complete(&lcdc_pipe->comp);
}
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
struct mdp4_overlay_pipe *pipe;
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since it's lcdc mode */
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
mutex_lock(&mfd->dma->ov_mutex);
pipe = lcdc_pipe;
pipe->srcp0_addr = (uint32) buf;
mdp4_overlay_rgb_setup(pipe);
mdp4_overlay_reg_flush(pipe, 1); /* rgb1 and mixer0 */
/* enable irq */
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(MDP_OVERLAY0_TERM);
INIT_COMPLETION(lcdc_pipe->comp);
mfd->dma->waiting = TRUE;
outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
mdp_intr_mask |= INTR_OVERLAY0_DONE;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&lcdc_pipe->comp);
mdp_disable_irq(MDP_OVERLAY0_TERM);
mutex_unlock(&mfd->dma->ov_mutex);
}

View File

@ -0,0 +1,254 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
static struct mdp4_overlay_pipe *mddi_pipe;
static struct mdp4_overlay_pipe *pending_pipe;
static struct msm_fb_data_type *mddi_mfd;
#define WHOLESCREEN
void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
uint8 *src;
int bpp, ptype;
uint32 format;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct mdp4_overlay_pipe *pipe;
if (mfd->key != MFD_KEY)
return;
mddi_mfd = mfd; /* keep it */
bpp = iBuf->bpp;
if (bpp == 2)
format = MDP_RGB_565;
else if (bpp == 3)
format = MDP_RGB_888;
else
format = MDP_ARGB_8888;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
if (mddi_pipe == NULL) {
ptype = mdp4_overlay_format2type(format);
pipe = mdp4_overlay_pipe_alloc();
pipe->pipe_type = ptype;
/* use RGB1 pipe */
pipe->pipe_num = OVERLAY_PIPE_RGB1;
pipe->mixer_num = MDP4_MIXER0;
pipe->src_format = format;
mdp4_overlay_format2pipe(pipe);
mddi_pipe = pipe; /* keep it */
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
if (mfd->panel_info.type == MDDI_PANEL) {
if (mfd->panel_info.pdest == DISPLAY_1)
mddi_ld_param = 0;
else
mddi_ld_param = 1;
} else {
mddi_ld_param = 2;
}
MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
} else {
pipe = mddi_pipe;
}
src = (uint8 *) iBuf->buf;
#ifdef WHOLESCREEN
{
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32)src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
}
#else
if (mdp4_overlay_active(MDP4_MIXER0)) {
struct fb_info *fbi;
fbi = mfd->fbi;
pipe->src_height = fbi->var.yres;
pipe->src_width = fbi->var.xres;
pipe->src_h = fbi->var.yres;
pipe->src_w = fbi->var.xres;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = fbi->var.yres;
pipe->dst_w = fbi->var.xres;
pipe->dst_y = 0;
pipe->dst_x = 0;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
} else {
/* starting input address */
src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp;
pipe->src_height = iBuf->dma_h;
pipe->src_width = iBuf->dma_w;
pipe->src_h = iBuf->dma_h;
pipe->src_w = iBuf->dma_w;
pipe->src_y = 0;
pipe->src_x = 0;
pipe->dst_h = iBuf->dma_h;
pipe->dst_w = iBuf->dma_w;
pipe->dst_y = iBuf->dma_y;
pipe->dst_x = iBuf->dma_x;
pipe->srcp0_addr = (uint32) src;
pipe->srcp0_ystride = iBuf->ibuf_width * bpp;
}
#endif
pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
mdp4_overlay_rgb_setup(pipe);
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
mdp4_overlay_dmap_xy(pipe);
mdp4_overlay_dmap_cfg(mfd, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
/*
* mdp4_overlay0_done_mddi: called from isr
*/
void mdp4_overlay0_done_mddi()
{
if (pending_pipe)
complete(&pending_pipe->comp);
}
void mdp4_mddi_overlay_restore(void)
{
/* mutex holded by caller */
mdp4_overlay_update_lcd(mddi_mfd);
mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
}
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
#ifdef MDP4_NONBLOCKING
unsigned long flag;
spin_lock_irqsave(&mdp_spin_lock, flag);
if (mfd->dma->busy == TRUE) {
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
}
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (pending_pipe != NULL) {
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
pending_pipe = NULL;
}
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
#else
down(&mfd->sem);
mdp_enable_irq(MDP_OVERLAY0_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(pipe->comp);
pending_pipe = pipe;
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&pipe->comp);
mdp_disable_irq(MDP_OVERLAY0_TERM);
#endif
}
void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
{
mutex_lock(&mfd->dma->ov_mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
mdp4_overlay_update_lcd(mfd);
mdp4_mddi_overlay_kickoff(mfd, mddi_pipe);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
mutex_unlock(&mfd->dma->ov_mutex);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
static int cursor_enabled;
int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
struct fb_image *img = &cursor->image;
int calpha_en, transp_en;
int alpha;
int ret = 0;
if ((img->width > MDP_CURSOR_WIDTH) ||
(img->height > MDP_CURSOR_HEIGHT) ||
(img->depth != 32))
return -EINVAL;
if (cursor->set & FB_CUR_SETPOS)
MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
if (cursor->set & FB_CUR_SETIMAGE) {
ret = copy_from_user(mfd->cursor_buf, img->data,
img->width*img->height*4);
if (ret)
return ret;
if (img->bg_color == 0xffffffff)
transp_en = 0;
else
transp_en = 1;
alpha = (img->fg_color & 0xff000000) >> 24;
if (alpha)
calpha_en = 0x2; /* xrgb */
else
calpha_en = 0x1; /* argb */
MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width);
MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys);
/* order the writes the cursor_buf before updating the
* hardware */
// dma_coherent_pre_ops();
MDP_OUTP(MDP_BASE + 0x90060,
(transp_en << 3) | (calpha_en << 1) |
(inp32(MDP_BASE + 0x90060) & 0x1));
#ifdef CONFIG_FB_MSM_MDP40
MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color));
MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color));
#else
MDP_OUTP(MDP_BASE + 0x90064,
(alpha << 24) | (0xffffff & img->bg_color));
MDP_OUTP(MDP_BASE + 0x90068, 0);
#endif
}
if ((cursor->enable) && (!cursor_enabled)) {
cursor_enabled = 1;
MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
} else if ((!cursor->enable) && (cursor_enabled)) {
cursor_enabled = 0;
MDP_OUTP(MDP_BASE + 0x90060,
inp32(MDP_BASE + 0x90060) & (~0x1));
}
return 0;
}

View File

@ -0,0 +1,561 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mddihost.h"
static uint32 mdp_last_dma2_update_width;
static uint32 mdp_last_dma2_update_height;
static uint32 mdp_curr_dma2_update_width;
static uint32 mdp_curr_dma2_update_height;
ktime_t mdp_dma2_last_update_time = { 0 };
int mdp_lcd_rd_cnt_offset_slow = 20;
int mdp_lcd_rd_cnt_offset_fast = 20;
int mdp_vsync_usec_wait_line_too_short = 5;
uint32 mdp_dma2_update_time_in_usec;
uint32 mdp_total_vdopkts;
extern u32 msm_fb_debug_enabled;
extern struct workqueue_struct *mdp_dma_wq;
int vsync_start_y_adjust = 4;
static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
int mddi_dest = FALSE;
uint32 outBpp = iBuf->bpp;
uint32 dma2_cfg_reg;
uint8 *src;
uint32 mddi_ld_param;
uint16 mddi_vdo_packet_reg;
struct msm_fb_panel_data *pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
uint32 ystride = mfd->fbi->fix.line_length;
dma2_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
#ifdef CONFIG_FB_MSM_MDP30
/*
* Software workaround: On 7x25/7x27, the MDP will not
* respond if dma_w is 1 pixel. Set the update width to
* 2 pixels and adjust the x offset if needed.
*/
if (iBuf->dma_w == 1) {
iBuf->dma_w = 2;
if (iBuf->dma_x == (iBuf->ibuf_width - 2))
iBuf->dma_x--;
}
#endif
if (mfd->fb_imgType == MDP_BGR_565)
dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (outBpp == 4)
dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
if (outBpp == 2)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
if ((mfd->panel_info.type == MDDI_PANEL) ||
(mfd->panel_info.type == EXT_MDDI_PANEL)) {
dma2_cfg_reg |= DMA_OUT_SEL_MDDI;
mddi_dest = TRUE;
if (mfd->panel_info.type == MDDI_PANEL) {
mdp_total_vdopkts++;
if (mfd->panel_info.pdest == DISPLAY_1) {
dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
mddi_ld_param = 0;
#ifdef MDDI_HOST_WINDOW_WORKAROUND
mddi_window_adjust(mfd, iBuf->dma_x,
iBuf->dma_w - 1, iBuf->dma_y,
iBuf->dma_h - 1);
#endif
} else {
dma2_cfg_reg |=
DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY;
mddi_ld_param = 1;
#ifdef MDDI_HOST_WINDOW_WORKAROUND
mddi_window_adjust(mfd, iBuf->dma_x,
iBuf->dma_w - 1, iBuf->dma_y,
iBuf->dma_h - 1);
#endif
}
} else {
dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL;
mddi_ld_param = 2;
}
} else {
if (mfd->panel_info.pdest == DISPLAY_1) {
dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY;
outp32(MDP_EBI2_LCD0, mfd->data_port_phys);
} else {
dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
}
}
dma2_cfg_reg |= DMA_DITHER_EN;
src = (uint8 *) iBuf->buf;
/* starting input address */
src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride;
mdp_curr_dma2_update_width = iBuf->dma_w;
mdp_curr_dma2_update_height = iBuf->dma_h;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184,
(iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride);
#else
MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_BASE + 0x90008, src);
MDP_OUTP(MDP_BASE + 0x9000c, ystride);
#endif
if (mfd->panel_info.bpp == 18) {
dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
} else {
dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
}
if (mddi_dest) {
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194,
(iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
#else
MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
#endif
} else {
/* setting EBI2 LCDC write window */
pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
iBuf->dma_h);
}
/* dma2 config register */
#ifdef MDP_HW_VSYNC
MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
if ((mfd->use_mdp_vsync) &&
(mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) {
uint32 start_y;
if (vsync_start_y_adjust <= iBuf->dma_y)
start_y = iBuf->dma_y - vsync_start_y_adjust;
else
start_y =
(mfd->total_lcd_lines - 1) - (vsync_start_y_adjust -
iBuf->dma_y);
/*
* MDP VSYNC clock must be On by now so, we don't have to
* re-enable it
*/
MDP_OUTP(MDP_BASE + 0x210, start_y);
MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */
} else {
MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */
}
#else
#ifdef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg);
#else
MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
#endif
#endif /* MDP_HW_VSYNC */
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
static ktime_t vt = { 0 };
int mdp_usec_diff_threshold = 100;
int mdp_expected_usec_wait;
enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht)
{
struct msm_fb_data_type *mfd = NULL;
mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer);
mdp_pipe_kickoff(MDP_DMA2_TERM, mfd);
if (msm_fb_debug_enabled) {
ktime_t t;
int usec_diff;
int actual_wait;
t = ktime_get_real();
actual_wait =
(t.tv.sec - vt.tv.sec) * 1000000 + (t.tv.nsec -
vt.tv.nsec) / 1000;
usec_diff = actual_wait - mdp_expected_usec_wait;
if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0))
MSM_FB_DEBUG
("HRT Diff = %d usec Exp=%d usec Act=%d usec\n",
usec_diff, mdp_expected_usec_wait, actual_wait);
}
return HRTIMER_NORESTART;
}
static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term)
{
/*
* dma2 configure VSYNC block
* vsync supported on Primary LCD only for now
*/
int32 mdp_lcd_rd_cnt;
uint32 usec_wait_time;
uint32 start_y;
/*
* ToDo: if we can move HRT timer callback to workqueue, we can
* move DMA2 power on under mdp_pipe_kickoff().
* This will save a power for hrt time wait.
* However if the latency for context switch (hrt irq -> workqueue)
* is too big, we will miss the vsync timing.
*/
if (term == MDP_DMA2_TERM)
mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_dma2_update_time_in_usec =
MDP_KTIME2USEC(mdp_dma2_last_update_time);
if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable)
|| (mfd->use_mdp_vsync)) {
mdp_pipe_kickoff(term, mfd);
return;
}
/* SW vsync logic starts here */
/* get current rd counter */
mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd);
if (mdp_dma2_update_time_in_usec != 0) {
uint32 num, den;
/*
* roi width boundary calculation to know the size of pixel
* width that MDP can send faster or slower than LCD read
* pointer
*/
num = mdp_last_dma2_update_width * mdp_last_dma2_update_height;
den =
(((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) /
1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000;
if (den == 0)
mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
mfd->panel_info.xres + 1;
else
mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
(int)(num / den);
}
if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] >
mdp_curr_dma2_update_width) {
/* MDP wrp is faster than LCD rdp */
mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast;
} else {
/* MDP wrp is slower than LCD rdp */
mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow;
}
if (mdp_lcd_rd_cnt < 0)
mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt;
else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines)
mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1;
/* get wrt pointer position */
start_y = mfd->ibuf.dma_y;
/* measure line difference between start_y and rd counter */
if (start_y > mdp_lcd_rd_cnt) {
/*
* *100 for lcd_ref_hzx100 was already multiplied by 100
* *1000000 is for usec conversion
*/
if ((start_y - mdp_lcd_rd_cnt) <=
mdp_vsync_usec_wait_line_too_short)
usec_wait_time = 0;
else
usec_wait_time =
((start_y -
mdp_lcd_rd_cnt) * 1000000) /
((mfd->total_lcd_lines *
mfd->panel_info.lcd.refx100) / 100);
} else {
if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <=
mdp_vsync_usec_wait_line_too_short)
usec_wait_time = 0;
else
usec_wait_time =
((start_y +
(mfd->total_lcd_lines -
mdp_lcd_rd_cnt)) * 1000000) /
((mfd->total_lcd_lines *
mfd->panel_info.lcd.refx100) / 100);
}
mdp_last_dma2_update_width = mdp_curr_dma2_update_width;
mdp_last_dma2_update_height = mdp_curr_dma2_update_height;
if (usec_wait_time == 0) {
mdp_pipe_kickoff(term, mfd);
} else {
ktime_t wait_time;
wait_time.tv.sec = 0;
wait_time.tv.nsec = usec_wait_time * 1000;
if (msm_fb_debug_enabled) {
vt = ktime_get_real();
mdp_expected_usec_wait = usec_wait_time;
}
hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL);
}
}
#ifdef MDDI_HOST_WINDOW_WORKAROUND
void mdp_dma2_update(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf;
uint32 upper_height;
if (mfd->panel.type == EXT_MDDI_PANEL) {
mdp_dma2_update_sub(mfd);
return;
}
iBuf = &mfd->ibuf;
upper_height =
(uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w,
(uint16) iBuf->dma_h, 18);
if (upper_height >= iBuf->dma_h) {
mdp_dma2_update_sub(mfd);
} else {
MDPIBUF lower_height;
/* sending the upper region first */
lower_height = iBuf->dma_h - upper_height;
iBuf->dma_h = upper_height;
mdp_dma2_update_sub(mfd);
/* sending the lower region second */
iBuf->dma_h = lower_height;
iBuf->dma_y += lower_height;
iBuf->vsync_enable = FALSE;
mdp_dma2_update_sub(mfd);
}
}
void mdp_dma2_update_sub(struct msm_fb_data_type *mfd)
#else
void mdp_dma2_update(struct msm_fb_data_type *mfd)
#endif
{
down(&mfd->dma->mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
down(&mfd->sem);
mfd->ibuf_flushed = TRUE;
mdp_dma2_update_lcd(mfd);
mdp_enable_irq(MDP_DMA2_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(mfd->dma->comp);
/* schedule DMA to start */
mdp_dma_schedule(mfd, MDP_DMA2_TERM);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA2_TERM);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
up(&mfd->dma->mutex);
}
void mdp_lcd_update_workqueue_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd = NULL;
mfd = container_of(work, struct msm_fb_data_type, dma_update_worker);
if (mfd)
mfd->dma_fnc(mfd);
}
void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
boolean sync)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
int bpp = info->var.bits_per_pixel / 8;
down(&mfd->sem);
iBuf = &mfd->ibuf;
iBuf->buf = (uint8 *) info->fix.smem_start;
iBuf->buf += info->var.xoffset * bpp +
info->var.yoffset * info->fix.line_length;
iBuf->ibuf_width = info->var.xres_virtual;
iBuf->bpp = bpp;
iBuf->vsync_enable = sync;
if (dirty) {
/*
* ToDo: dirty region check inside var.xoffset+xres
* <-> var.yoffset+yres
*/
iBuf->dma_x = dirty->xoffset % info->var.xres;
iBuf->dma_y = dirty->yoffset % info->var.yres;
iBuf->dma_w = dirty->width;
iBuf->dma_h = dirty->height;
} else {
iBuf->dma_x = 0;
iBuf->dma_y = 0;
iBuf->dma_w = info->var.xres;
iBuf->dma_h = info->var.yres;
}
mfd->ibuf_flushed = FALSE;
up(&mfd->sem);
}
void mdp_set_offset_info(struct fb_info *info, uint32 addr, uint32 sync)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
int bpp = info->var.bits_per_pixel / 8;
down(&mfd->sem);
iBuf = &mfd->ibuf;
iBuf->ibuf_width = info->var.xres_virtual;
iBuf->bpp = bpp;
iBuf->vsync_enable = sync;
iBuf->dma_x = 0;
iBuf->dma_y = 0;
iBuf->dma_w = info->var.xres;
iBuf->dma_h = info->var.yres;
iBuf->buf = (uint8 *) addr;
mfd->ibuf_flushed = FALSE;
up(&mfd->sem);
}
void mdp_dma_pan_update(struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
MDPIBUF *iBuf;
iBuf = &mfd->ibuf;
if (mfd->sw_currently_refreshing) {
/* we need to wait for the pending update */
mfd->pan_waiting = TRUE;
if (!mfd->ibuf_flushed) {
wait_for_completion_killable(&mfd->pan_comp);
}
/* waiting for this update to complete */
mfd->pan_waiting = TRUE;
wait_for_completion_killable(&mfd->pan_comp);
} else
mfd->dma_fnc(mfd);
}
void mdp_refresh_screen(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
init_timer(&mfd->refresh_timer);
mfd->refresh_timer.function = mdp_refresh_screen;
mfd->refresh_timer.data = data;
if (mfd->dma->busy)
/* come back in 1 msec */
mfd->refresh_timer.expires = jiffies + (HZ / 1000);
else
mfd->refresh_timer.expires =
jiffies + mfd->refresh_timer_duration;
add_timer(&mfd->refresh_timer);
if (!mfd->dma->busy) {
if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) {
MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \
MDP/MDDI/LCD clock speed needs to be increased\n");
}
}
} else {
if (!mfd->hw_refresh)
complete(&mfd->refresher_comp);
}
}

View File

@ -0,0 +1,379 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mdp4.h"
#ifdef CONFIG_FB_MSM_MDP40
#define LCDC_BASE 0xC0000
#define DTV_BASE 0xD0000
#define DMA_E_BASE 0xB0000
#else
#define LCDC_BASE 0xE0000
#endif
#define DMA_P_BASE 0x90000
extern spinlock_t mdp_spin_lock;
#ifndef CONFIG_FB_MSM_MDP40
extern uint32 mdp_intr_mask;
#endif
int first_pixel_start_x;
int first_pixel_start_y;
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
int lcdc_height;
int lcdc_bpp;
int lcdc_border_clr;
int lcdc_underflow_clr;
int lcdc_hsync_skew;
int hsync_period;
int hsync_ctrl;
int vsync_period;
int display_hctl;
int display_v_start;
int display_v_end;
int active_hctl;
int active_h_start;
int active_h_end;
int active_v_start;
int active_v_end;
int ctrl_polarity;
int h_back_porch;
int h_front_porch;
int v_back_porch;
int v_front_porch;
int hsync_pulse_width;
int vsync_pulse_width;
int hsync_polarity;
int vsync_polarity;
int data_en_polarity;
int hsync_start_x;
int hsync_end_x;
uint8 *buf;
int bpp;
uint32 dma2_cfg_reg;
struct fb_info *fbi;
struct fb_var_screeninfo *var;
struct msm_fb_data_type *mfd;
uint32 dma_base;
uint32 timer_base = LCDC_BASE;
uint32 block = MDP_DMA2_BLOCK;
int ret;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
var = &fbi->var;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length;
dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_DITHER_EN | DMA_OUT_SEL_LCDC;
if (mfd->fb_imgType == MDP_BGR_565)
dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (bpp == 2)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
else if (bpp == 3)
dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888;
else
dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888;
switch (mfd->panel_info.bpp) {
case 24:
dma2_cfg_reg |= DMA_DSTC0G_8BITS |
DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
break;
case 18:
dma2_cfg_reg |= DMA_DSTC0G_6BITS |
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
break;
case 16:
dma2_cfg_reg |= DMA_DSTC0G_6BITS |
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
break;
default:
printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n",
mfd->panel_info.bpp);
return -ENODEV;
}
/* DMA register config */
dma_base = DMA_P_BASE;
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL)
dma_base = DMA_E_BASE;
#endif
/* starting address */
MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
/* active window width and height */
MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) |
(fbi->var.xres));
/* buffer ystride */
MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length);
/* x/y coordinate = always 0 for lcdc */
MDP_OUTP(MDP_BASE + dma_base + 0x10, 0);
/* dma config */
MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg);
/*
* LCDC timing setting
*/
h_back_porch = var->left_margin;
h_front_porch = var->right_margin;
v_back_porch = var->upper_margin;
v_front_porch = var->lower_margin;
hsync_pulse_width = var->hsync_len;
vsync_pulse_width = var->vsync_len;
lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
lcdc_width = mfd->panel_info.xres;
lcdc_height = mfd->panel_info.yres;
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
hsync_start_x = hsync_pulse_width + h_back_porch;
hsync_end_x = hsync_period - h_front_porch - 1;
display_hctl = (hsync_end_x << 16) | hsync_start_x;
vsync_period =
(vsync_pulse_width + v_back_porch + lcdc_height +
v_front_porch) * hsync_period;
display_v_start =
(vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
display_v_end =
vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
if (lcdc_width != var->xres) {
active_h_start = hsync_start_x + first_pixel_start_x;
active_h_end = active_h_start + var->xres - 1;
active_hctl =
ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
} else {
active_hctl = 0;
}
if (lcdc_height != var->yres) {
active_v_start =
display_v_start + first_pixel_start_y * hsync_period;
active_v_end = active_v_start + (var->yres) * hsync_period - 1;
active_v_start |= ACTIVE_START_Y_EN;
} else {
active_v_start = 0;
active_v_end = 0;
}
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
block = MDP_DMA_E_BLOCK;
timer_base = DTV_BASE;
hsync_polarity = 0;
vsync_polarity = 0;
} else {
hsync_polarity = 1;
vsync_polarity = 1;
}
lcdc_underflow_clr |= 0x80000000; /* enable recovery */
#else
hsync_polarity = 0;
vsync_polarity = 0;
#endif
data_en_polarity = 0;
ctrl_polarity =
(data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
if (timer_base == LCDC_BASE) {
MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end);
MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end);
} else {
MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end);
MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr);
MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew);
MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity);
MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl);
MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start);
MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end);
}
ret = panel_next_on(pdev);
if (ret == 0) {
/* enable LCDC block */
MDP_OUTP(MDP_BASE + timer_base, 1);
mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE);
}
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
return ret;
}
int mdp_lcdc_off(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_data_type *mfd;
uint32 timer_base = LCDC_BASE;
uint32 block = MDP_DMA2_BLOCK;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
block = MDP_DMA_E_BLOCK;
timer_base = DTV_BASE;
}
#endif
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + timer_base, 0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_off(pdev);
/* delay to make sure the last frame finishes */
mdelay(100);
return ret;
}
void mdp_lcdc_update(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
uint32 dma_base;
int irq_block = MDP_DMA2_TERM;
#ifdef CONFIG_FB_MSM_MDP40
int intr = INTR_DMA_P_DONE;
#endif
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since it's lcdc mode */
if (!mfd->ibuf.visible_swapped) {
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
} else {
/* we've done something to update the pointer. */
bpp = mfd->ibuf.bpp;
buf = mfd->ibuf.buf;
}
dma_base = DMA_P_BASE;
#ifdef CONFIG_FB_MSM_MDP40
if (mfd->panel.type == HDMI_PANEL) {
intr = INTR_DMA_E_DONE;
irq_block = MDP_DMA_E_TERM;
dma_base = DMA_E_BASE;
}
#endif
/* starting address */
MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
/* enable LCDC irq */
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(irq_block);
INIT_COMPLETION(mfd->dma->comp);
mfd->dma->waiting = TRUE;
#ifdef CONFIG_FB_MSM_MDP40
outp32(MDP_INTR_CLEAR, intr);
mdp_intr_mask |= intr;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
#else
outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
mdp_intr_mask |= LCDC_FRAME_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
#endif
spin_unlock_irqrestore(&mdp_spin_lock, flag);
if (mfd->ibuf.vsync_enable)
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(irq_block);
}

View File

@ -0,0 +1,139 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
int mddi_dest = FALSE;
uint32 outBpp = iBuf->bpp;
uint32 dma_s_cfg_reg;
uint8 *src;
struct msm_fb_panel_data *pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
dma_s_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
if (mfd->fb_imgType == MDP_BGR_565)
dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR;
else
dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB;
if (outBpp == 4)
dma_s_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
if (outBpp == 2)
dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
if (mfd->panel_info.pdest != DISPLAY_2) {
printk(KERN_ERR "error: non-secondary type through dma_s!\n");
return;
}
if (mfd->panel_info.type == MDDI_PANEL) {
dma_s_cfg_reg |= DMA_OUT_SEL_MDDI;
mddi_dest = TRUE;
} else {
dma_s_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
}
dma_s_cfg_reg |= DMA_DITHER_EN;
src = (uint8 *) iBuf->buf;
/* starting input address */
src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * outBpp;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* PIXELSIZE */
MDP_OUTP(MDP_BASE + 0xa0004, (iBuf->dma_h << 16 | iBuf->dma_w));
MDP_OUTP(MDP_BASE + 0xa0008, src); /* ibuf address */
MDP_OUTP(MDP_BASE + 0xa000c, iBuf->ibuf_width * outBpp);/* ystride */
if (mfd->panel_info.bpp == 18) {
dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
} else {
dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
}
if (mddi_dest) {
MDP_OUTP(MDP_BASE + 0xa0010, (iBuf->dma_y << 16) | iBuf->dma_x);
MDP_OUTP(MDP_BASE + 0x00090, 1);
MDP_OUTP(MDP_BASE + 0x00094,
(MDDI_VDO_PACKET_DESC << 16) |
mfd->panel_info.mddi.vdopkt);
} else {
/* setting LCDC write window */
pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
iBuf->dma_h);
}
MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
}
void mdp_dma_s_update(struct msm_fb_data_type *mfd)
{
down(&mfd->dma->mutex);
if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
down(&mfd->sem);
mdp_enable_irq(MDP_DMA_S_TERM);
mfd->dma->busy = TRUE;
INIT_COMPLETION(mfd->dma->comp);
mfd->ibuf_flushed = TRUE;
mdp_dma_s_update_lcd(mfd);
up(&mfd->sem);
/* wait until DMA finishes the current job */
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA_S_TERM);
/* signal if pan function is waiting for the update completion */
if (mfd->pan_waiting) {
mfd->pan_waiting = FALSE;
complete(&mfd->pan_comp);
}
}
up(&mfd->dma->mutex);
}

View File

@ -0,0 +1,142 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/fb.h>
#include "mdp.h"
#include "msm_fb.h"
extern spinlock_t mdp_spin_lock;
extern uint32 mdp_intr_mask;
int mdp_dma3_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct fb_info *fbi;
uint8 *buf;
int bpp;
int ret = 0;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
if (mfd->key != MFD_KEY)
return -EINVAL;
fbi = mfd->fbi;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
/* starting address[31..8] of Video frame buffer is CS0 */
MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0xC0004, 0x4c60674); /* flicker filter enabled */
MDP_OUTP(MDP_BASE + 0xC0010, 0x20); /* sobel treshold */
MDP_OUTP(MDP_BASE + 0xC0018, 0xeb0010); /* Y Max, Y min */
MDP_OUTP(MDP_BASE + 0xC001C, 0xf00010); /* Cb Max, Cb min */
MDP_OUTP(MDP_BASE + 0xC0020, 0xf00010); /* Cb Max, Cb min */
MDP_OUTP(MDP_BASE + 0xC000C, 0x67686970); /* add a few chars for CC */
MDP_OUTP(MDP_BASE + 0xC0000, 0x1); /* MDP tv out enable */
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
ret = panel_next_on(pdev);
return ret;
}
int mdp_dma3_off(struct platform_device *pdev)
{
int ret = 0;
ret = panel_next_off(pdev);
if (ret)
return ret;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
MDP_OUTP(MDP_BASE + 0xC0000, 0x0);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
/* delay to make sure the last frame finishes */
mdelay(100);
return ret;
}
void mdp_dma3_update(struct msm_fb_data_type *mfd)
{
struct fb_info *fbi = mfd->fbi;
uint8 *buf;
int bpp;
unsigned long flag;
if (!mfd->panel_power_on)
return;
/* no need to power on cmd block since dma3 is running */
bpp = fbi->var.bits_per_pixel / 8;
buf = (uint8 *) fbi->fix.smem_start;
buf += fbi->var.xoffset * bpp +
fbi->var.yoffset * fbi->fix.line_length;
MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
spin_lock_irqsave(&mdp_spin_lock, flag);
mdp_enable_irq(MDP_DMA3_TERM);
INIT_COMPLETION(mfd->dma->comp);
mfd->dma->waiting = TRUE;
outp32(MDP_INTR_CLEAR, TV_OUT_DMA3_START);
mdp_intr_mask |= TV_OUT_DMA3_START;
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
spin_unlock_irqrestore(&mdp_spin_lock, flag);
wait_for_completion_killable(&mfd->dma->comp);
mdp_disable_irq(MDP_DMA3_TERM);
}

View File

@ -0,0 +1,720 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "mdp.h"
/* mdp primary csc limit vector */
uint32 mdp_plv[] = { 0x10, 0xeb, 0x10, 0xf0 };
/* Color Coefficient matrix for YUV -> RGB */
struct mdp_ccs mdp_ccs_yuv2rgb = {
MDP_CCS_YUV2RGB,
{
0x254,
0x000,
0x331,
0x254,
0xff38,
0xfe61,
0x254,
0x409,
0x000,
},
{
#ifdef CONFIG_FB_MSM_MDP31
0x1f0,
0x180,
0x180
#else
0x10,
0x80,
0x80
#endif
}
};
/* Color Coefficient matrix for RGB -> YUV */
struct mdp_ccs mdp_ccs_rgb2yuv = {
MDP_CCS_RGB2YUV,
{
0x83,
0x102,
0x32,
0xffb5,
0xff6c,
0xe1,
0xe1,
0xff45,
0xffdc,
},
#ifdef CONFIG_FB_MSM_MDP31
{
0x10,
0x80,
0x80
}
#endif
};
static void mdp_load_lut_param(void)
{
outpdw(MDP_BASE + 0x40800, 0x0);
outpdw(MDP_BASE + 0x40804, 0x151515);
outpdw(MDP_BASE + 0x40808, 0x1d1d1d);
outpdw(MDP_BASE + 0x4080c, 0x232323);
outpdw(MDP_BASE + 0x40810, 0x272727);
outpdw(MDP_BASE + 0x40814, 0x2b2b2b);
outpdw(MDP_BASE + 0x40818, 0x2f2f2f);
outpdw(MDP_BASE + 0x4081c, 0x333333);
outpdw(MDP_BASE + 0x40820, 0x363636);
outpdw(MDP_BASE + 0x40824, 0x393939);
outpdw(MDP_BASE + 0x40828, 0x3b3b3b);
outpdw(MDP_BASE + 0x4082c, 0x3e3e3e);
outpdw(MDP_BASE + 0x40830, 0x404040);
outpdw(MDP_BASE + 0x40834, 0x434343);
outpdw(MDP_BASE + 0x40838, 0x454545);
outpdw(MDP_BASE + 0x4083c, 0x474747);
outpdw(MDP_BASE + 0x40840, 0x494949);
outpdw(MDP_BASE + 0x40844, 0x4b4b4b);
outpdw(MDP_BASE + 0x40848, 0x4d4d4d);
outpdw(MDP_BASE + 0x4084c, 0x4f4f4f);
outpdw(MDP_BASE + 0x40850, 0x515151);
outpdw(MDP_BASE + 0x40854, 0x535353);
outpdw(MDP_BASE + 0x40858, 0x555555);
outpdw(MDP_BASE + 0x4085c, 0x565656);
outpdw(MDP_BASE + 0x40860, 0x585858);
outpdw(MDP_BASE + 0x40864, 0x5a5a5a);
outpdw(MDP_BASE + 0x40868, 0x5b5b5b);
outpdw(MDP_BASE + 0x4086c, 0x5d5d5d);
outpdw(MDP_BASE + 0x40870, 0x5e5e5e);
outpdw(MDP_BASE + 0x40874, 0x606060);
outpdw(MDP_BASE + 0x40878, 0x616161);
outpdw(MDP_BASE + 0x4087c, 0x636363);
outpdw(MDP_BASE + 0x40880, 0x646464);
outpdw(MDP_BASE + 0x40884, 0x666666);
outpdw(MDP_BASE + 0x40888, 0x676767);
outpdw(MDP_BASE + 0x4088c, 0x686868);
outpdw(MDP_BASE + 0x40890, 0x6a6a6a);
outpdw(MDP_BASE + 0x40894, 0x6b6b6b);
outpdw(MDP_BASE + 0x40898, 0x6c6c6c);
outpdw(MDP_BASE + 0x4089c, 0x6e6e6e);
outpdw(MDP_BASE + 0x408a0, 0x6f6f6f);
outpdw(MDP_BASE + 0x408a4, 0x707070);
outpdw(MDP_BASE + 0x408a8, 0x717171);
outpdw(MDP_BASE + 0x408ac, 0x727272);
outpdw(MDP_BASE + 0x408b0, 0x747474);
outpdw(MDP_BASE + 0x408b4, 0x757575);
outpdw(MDP_BASE + 0x408b8, 0x767676);
outpdw(MDP_BASE + 0x408bc, 0x777777);
outpdw(MDP_BASE + 0x408c0, 0x787878);
outpdw(MDP_BASE + 0x408c4, 0x797979);
outpdw(MDP_BASE + 0x408c8, 0x7a7a7a);
outpdw(MDP_BASE + 0x408cc, 0x7c7c7c);
outpdw(MDP_BASE + 0x408d0, 0x7d7d7d);
outpdw(MDP_BASE + 0x408d4, 0x7e7e7e);
outpdw(MDP_BASE + 0x408d8, 0x7f7f7f);
outpdw(MDP_BASE + 0x408dc, 0x808080);
outpdw(MDP_BASE + 0x408e0, 0x818181);
outpdw(MDP_BASE + 0x408e4, 0x828282);
outpdw(MDP_BASE + 0x408e8, 0x838383);
outpdw(MDP_BASE + 0x408ec, 0x848484);
outpdw(MDP_BASE + 0x408f0, 0x858585);
outpdw(MDP_BASE + 0x408f4, 0x868686);
outpdw(MDP_BASE + 0x408f8, 0x878787);
outpdw(MDP_BASE + 0x408fc, 0x888888);
outpdw(MDP_BASE + 0x40900, 0x898989);
outpdw(MDP_BASE + 0x40904, 0x8a8a8a);
outpdw(MDP_BASE + 0x40908, 0x8b8b8b);
outpdw(MDP_BASE + 0x4090c, 0x8c8c8c);
outpdw(MDP_BASE + 0x40910, 0x8d8d8d);
outpdw(MDP_BASE + 0x40914, 0x8e8e8e);
outpdw(MDP_BASE + 0x40918, 0x8f8f8f);
outpdw(MDP_BASE + 0x4091c, 0x8f8f8f);
outpdw(MDP_BASE + 0x40920, 0x909090);
outpdw(MDP_BASE + 0x40924, 0x919191);
outpdw(MDP_BASE + 0x40928, 0x929292);
outpdw(MDP_BASE + 0x4092c, 0x939393);
outpdw(MDP_BASE + 0x40930, 0x949494);
outpdw(MDP_BASE + 0x40934, 0x959595);
outpdw(MDP_BASE + 0x40938, 0x969696);
outpdw(MDP_BASE + 0x4093c, 0x969696);
outpdw(MDP_BASE + 0x40940, 0x979797);
outpdw(MDP_BASE + 0x40944, 0x989898);
outpdw(MDP_BASE + 0x40948, 0x999999);
outpdw(MDP_BASE + 0x4094c, 0x9a9a9a);
outpdw(MDP_BASE + 0x40950, 0x9b9b9b);
outpdw(MDP_BASE + 0x40954, 0x9c9c9c);
outpdw(MDP_BASE + 0x40958, 0x9c9c9c);
outpdw(MDP_BASE + 0x4095c, 0x9d9d9d);
outpdw(MDP_BASE + 0x40960, 0x9e9e9e);
outpdw(MDP_BASE + 0x40964, 0x9f9f9f);
outpdw(MDP_BASE + 0x40968, 0xa0a0a0);
outpdw(MDP_BASE + 0x4096c, 0xa0a0a0);
outpdw(MDP_BASE + 0x40970, 0xa1a1a1);
outpdw(MDP_BASE + 0x40974, 0xa2a2a2);
outpdw(MDP_BASE + 0x40978, 0xa3a3a3);
outpdw(MDP_BASE + 0x4097c, 0xa4a4a4);
outpdw(MDP_BASE + 0x40980, 0xa4a4a4);
outpdw(MDP_BASE + 0x40984, 0xa5a5a5);
outpdw(MDP_BASE + 0x40988, 0xa6a6a6);
outpdw(MDP_BASE + 0x4098c, 0xa7a7a7);
outpdw(MDP_BASE + 0x40990, 0xa7a7a7);
outpdw(MDP_BASE + 0x40994, 0xa8a8a8);
outpdw(MDP_BASE + 0x40998, 0xa9a9a9);
outpdw(MDP_BASE + 0x4099c, 0xaaaaaa);
outpdw(MDP_BASE + 0x409a0, 0xaaaaaa);
outpdw(MDP_BASE + 0x409a4, 0xababab);
outpdw(MDP_BASE + 0x409a8, 0xacacac);
outpdw(MDP_BASE + 0x409ac, 0xadadad);
outpdw(MDP_BASE + 0x409b0, 0xadadad);
outpdw(MDP_BASE + 0x409b4, 0xaeaeae);
outpdw(MDP_BASE + 0x409b8, 0xafafaf);
outpdw(MDP_BASE + 0x409bc, 0xafafaf);
outpdw(MDP_BASE + 0x409c0, 0xb0b0b0);
outpdw(MDP_BASE + 0x409c4, 0xb1b1b1);
outpdw(MDP_BASE + 0x409c8, 0xb2b2b2);
outpdw(MDP_BASE + 0x409cc, 0xb2b2b2);
outpdw(MDP_BASE + 0x409d0, 0xb3b3b3);
outpdw(MDP_BASE + 0x409d4, 0xb4b4b4);
outpdw(MDP_BASE + 0x409d8, 0xb4b4b4);
outpdw(MDP_BASE + 0x409dc, 0xb5b5b5);
outpdw(MDP_BASE + 0x409e0, 0xb6b6b6);
outpdw(MDP_BASE + 0x409e4, 0xb6b6b6);
outpdw(MDP_BASE + 0x409e8, 0xb7b7b7);
outpdw(MDP_BASE + 0x409ec, 0xb8b8b8);
outpdw(MDP_BASE + 0x409f0, 0xb8b8b8);
outpdw(MDP_BASE + 0x409f4, 0xb9b9b9);
outpdw(MDP_BASE + 0x409f8, 0xbababa);
outpdw(MDP_BASE + 0x409fc, 0xbababa);
outpdw(MDP_BASE + 0x40a00, 0xbbbbbb);
outpdw(MDP_BASE + 0x40a04, 0xbcbcbc);
outpdw(MDP_BASE + 0x40a08, 0xbcbcbc);
outpdw(MDP_BASE + 0x40a0c, 0xbdbdbd);
outpdw(MDP_BASE + 0x40a10, 0xbebebe);
outpdw(MDP_BASE + 0x40a14, 0xbebebe);
outpdw(MDP_BASE + 0x40a18, 0xbfbfbf);
outpdw(MDP_BASE + 0x40a1c, 0xc0c0c0);
outpdw(MDP_BASE + 0x40a20, 0xc0c0c0);
outpdw(MDP_BASE + 0x40a24, 0xc1c1c1);
outpdw(MDP_BASE + 0x40a28, 0xc1c1c1);
outpdw(MDP_BASE + 0x40a2c, 0xc2c2c2);
outpdw(MDP_BASE + 0x40a30, 0xc3c3c3);
outpdw(MDP_BASE + 0x40a34, 0xc3c3c3);
outpdw(MDP_BASE + 0x40a38, 0xc4c4c4);
outpdw(MDP_BASE + 0x40a3c, 0xc5c5c5);
outpdw(MDP_BASE + 0x40a40, 0xc5c5c5);
outpdw(MDP_BASE + 0x40a44, 0xc6c6c6);
outpdw(MDP_BASE + 0x40a48, 0xc6c6c6);
outpdw(MDP_BASE + 0x40a4c, 0xc7c7c7);
outpdw(MDP_BASE + 0x40a50, 0xc8c8c8);
outpdw(MDP_BASE + 0x40a54, 0xc8c8c8);
outpdw(MDP_BASE + 0x40a58, 0xc9c9c9);
outpdw(MDP_BASE + 0x40a5c, 0xc9c9c9);
outpdw(MDP_BASE + 0x40a60, 0xcacaca);
outpdw(MDP_BASE + 0x40a64, 0xcbcbcb);
outpdw(MDP_BASE + 0x40a68, 0xcbcbcb);
outpdw(MDP_BASE + 0x40a6c, 0xcccccc);
outpdw(MDP_BASE + 0x40a70, 0xcccccc);
outpdw(MDP_BASE + 0x40a74, 0xcdcdcd);
outpdw(MDP_BASE + 0x40a78, 0xcecece);
outpdw(MDP_BASE + 0x40a7c, 0xcecece);
outpdw(MDP_BASE + 0x40a80, 0xcfcfcf);
outpdw(MDP_BASE + 0x40a84, 0xcfcfcf);
outpdw(MDP_BASE + 0x40a88, 0xd0d0d0);
outpdw(MDP_BASE + 0x40a8c, 0xd0d0d0);
outpdw(MDP_BASE + 0x40a90, 0xd1d1d1);
outpdw(MDP_BASE + 0x40a94, 0xd2d2d2);
outpdw(MDP_BASE + 0x40a98, 0xd2d2d2);
outpdw(MDP_BASE + 0x40a9c, 0xd3d3d3);
outpdw(MDP_BASE + 0x40aa0, 0xd3d3d3);
outpdw(MDP_BASE + 0x40aa4, 0xd4d4d4);
outpdw(MDP_BASE + 0x40aa8, 0xd4d4d4);
outpdw(MDP_BASE + 0x40aac, 0xd5d5d5);
outpdw(MDP_BASE + 0x40ab0, 0xd6d6d6);
outpdw(MDP_BASE + 0x40ab4, 0xd6d6d6);
outpdw(MDP_BASE + 0x40ab8, 0xd7d7d7);
outpdw(MDP_BASE + 0x40abc, 0xd7d7d7);
outpdw(MDP_BASE + 0x40ac0, 0xd8d8d8);
outpdw(MDP_BASE + 0x40ac4, 0xd8d8d8);
outpdw(MDP_BASE + 0x40ac8, 0xd9d9d9);
outpdw(MDP_BASE + 0x40acc, 0xd9d9d9);
outpdw(MDP_BASE + 0x40ad0, 0xdadada);
outpdw(MDP_BASE + 0x40ad4, 0xdbdbdb);
outpdw(MDP_BASE + 0x40ad8, 0xdbdbdb);
outpdw(MDP_BASE + 0x40adc, 0xdcdcdc);
outpdw(MDP_BASE + 0x40ae0, 0xdcdcdc);
outpdw(MDP_BASE + 0x40ae4, 0xdddddd);
outpdw(MDP_BASE + 0x40ae8, 0xdddddd);
outpdw(MDP_BASE + 0x40aec, 0xdedede);
outpdw(MDP_BASE + 0x40af0, 0xdedede);
outpdw(MDP_BASE + 0x40af4, 0xdfdfdf);
outpdw(MDP_BASE + 0x40af8, 0xdfdfdf);
outpdw(MDP_BASE + 0x40afc, 0xe0e0e0);
outpdw(MDP_BASE + 0x40b00, 0xe0e0e0);
outpdw(MDP_BASE + 0x40b04, 0xe1e1e1);
outpdw(MDP_BASE + 0x40b08, 0xe1e1e1);
outpdw(MDP_BASE + 0x40b0c, 0xe2e2e2);
outpdw(MDP_BASE + 0x40b10, 0xe3e3e3);
outpdw(MDP_BASE + 0x40b14, 0xe3e3e3);
outpdw(MDP_BASE + 0x40b18, 0xe4e4e4);
outpdw(MDP_BASE + 0x40b1c, 0xe4e4e4);
outpdw(MDP_BASE + 0x40b20, 0xe5e5e5);
outpdw(MDP_BASE + 0x40b24, 0xe5e5e5);
outpdw(MDP_BASE + 0x40b28, 0xe6e6e6);
outpdw(MDP_BASE + 0x40b2c, 0xe6e6e6);
outpdw(MDP_BASE + 0x40b30, 0xe7e7e7);
outpdw(MDP_BASE + 0x40b34, 0xe7e7e7);
outpdw(MDP_BASE + 0x40b38, 0xe8e8e8);
outpdw(MDP_BASE + 0x40b3c, 0xe8e8e8);
outpdw(MDP_BASE + 0x40b40, 0xe9e9e9);
outpdw(MDP_BASE + 0x40b44, 0xe9e9e9);
outpdw(MDP_BASE + 0x40b48, 0xeaeaea);
outpdw(MDP_BASE + 0x40b4c, 0xeaeaea);
outpdw(MDP_BASE + 0x40b50, 0xebebeb);
outpdw(MDP_BASE + 0x40b54, 0xebebeb);
outpdw(MDP_BASE + 0x40b58, 0xececec);
outpdw(MDP_BASE + 0x40b5c, 0xececec);
outpdw(MDP_BASE + 0x40b60, 0xededed);
outpdw(MDP_BASE + 0x40b64, 0xededed);
outpdw(MDP_BASE + 0x40b68, 0xeeeeee);
outpdw(MDP_BASE + 0x40b6c, 0xeeeeee);
outpdw(MDP_BASE + 0x40b70, 0xefefef);
outpdw(MDP_BASE + 0x40b74, 0xefefef);
outpdw(MDP_BASE + 0x40b78, 0xf0f0f0);
outpdw(MDP_BASE + 0x40b7c, 0xf0f0f0);
outpdw(MDP_BASE + 0x40b80, 0xf1f1f1);
outpdw(MDP_BASE + 0x40b84, 0xf1f1f1);
outpdw(MDP_BASE + 0x40b88, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b8c, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b90, 0xf2f2f2);
outpdw(MDP_BASE + 0x40b94, 0xf3f3f3);
outpdw(MDP_BASE + 0x40b98, 0xf3f3f3);
outpdw(MDP_BASE + 0x40b9c, 0xf4f4f4);
outpdw(MDP_BASE + 0x40ba0, 0xf4f4f4);
outpdw(MDP_BASE + 0x40ba4, 0xf5f5f5);
outpdw(MDP_BASE + 0x40ba8, 0xf5f5f5);
outpdw(MDP_BASE + 0x40bac, 0xf6f6f6);
outpdw(MDP_BASE + 0x40bb0, 0xf6f6f6);
outpdw(MDP_BASE + 0x40bb4, 0xf7f7f7);
outpdw(MDP_BASE + 0x40bb8, 0xf7f7f7);
outpdw(MDP_BASE + 0x40bbc, 0xf8f8f8);
outpdw(MDP_BASE + 0x40bc0, 0xf8f8f8);
outpdw(MDP_BASE + 0x40bc4, 0xf9f9f9);
outpdw(MDP_BASE + 0x40bc8, 0xf9f9f9);
outpdw(MDP_BASE + 0x40bcc, 0xfafafa);
outpdw(MDP_BASE + 0x40bd0, 0xfafafa);
outpdw(MDP_BASE + 0x40bd4, 0xfafafa);
outpdw(MDP_BASE + 0x40bd8, 0xfbfbfb);
outpdw(MDP_BASE + 0x40bdc, 0xfbfbfb);
outpdw(MDP_BASE + 0x40be0, 0xfcfcfc);
outpdw(MDP_BASE + 0x40be4, 0xfcfcfc);
outpdw(MDP_BASE + 0x40be8, 0xfdfdfd);
outpdw(MDP_BASE + 0x40bec, 0xfdfdfd);
outpdw(MDP_BASE + 0x40bf0, 0xfefefe);
outpdw(MDP_BASE + 0x40bf4, 0xfefefe);
outpdw(MDP_BASE + 0x40bf8, 0xffffff);
outpdw(MDP_BASE + 0x40bfc, 0xffffff);
outpdw(MDP_BASE + 0x40c00, 0x0);
outpdw(MDP_BASE + 0x40c04, 0x0);
outpdw(MDP_BASE + 0x40c08, 0x0);
outpdw(MDP_BASE + 0x40c0c, 0x0);
outpdw(MDP_BASE + 0x40c10, 0x0);
outpdw(MDP_BASE + 0x40c14, 0x0);
outpdw(MDP_BASE + 0x40c18, 0x0);
outpdw(MDP_BASE + 0x40c1c, 0x0);
outpdw(MDP_BASE + 0x40c20, 0x0);
outpdw(MDP_BASE + 0x40c24, 0x0);
outpdw(MDP_BASE + 0x40c28, 0x0);
outpdw(MDP_BASE + 0x40c2c, 0x0);
outpdw(MDP_BASE + 0x40c30, 0x0);
outpdw(MDP_BASE + 0x40c34, 0x0);
outpdw(MDP_BASE + 0x40c38, 0x0);
outpdw(MDP_BASE + 0x40c3c, 0x0);
outpdw(MDP_BASE + 0x40c40, 0x10101);
outpdw(MDP_BASE + 0x40c44, 0x10101);
outpdw(MDP_BASE + 0x40c48, 0x10101);
outpdw(MDP_BASE + 0x40c4c, 0x10101);
outpdw(MDP_BASE + 0x40c50, 0x10101);
outpdw(MDP_BASE + 0x40c54, 0x10101);
outpdw(MDP_BASE + 0x40c58, 0x10101);
outpdw(MDP_BASE + 0x40c5c, 0x10101);
outpdw(MDP_BASE + 0x40c60, 0x10101);
outpdw(MDP_BASE + 0x40c64, 0x10101);
outpdw(MDP_BASE + 0x40c68, 0x20202);
outpdw(MDP_BASE + 0x40c6c, 0x20202);
outpdw(MDP_BASE + 0x40c70, 0x20202);
outpdw(MDP_BASE + 0x40c74, 0x20202);
outpdw(MDP_BASE + 0x40c78, 0x20202);
outpdw(MDP_BASE + 0x40c7c, 0x20202);
outpdw(MDP_BASE + 0x40c80, 0x30303);
outpdw(MDP_BASE + 0x40c84, 0x30303);
outpdw(MDP_BASE + 0x40c88, 0x30303);
outpdw(MDP_BASE + 0x40c8c, 0x30303);
outpdw(MDP_BASE + 0x40c90, 0x30303);
outpdw(MDP_BASE + 0x40c94, 0x40404);
outpdw(MDP_BASE + 0x40c98, 0x40404);
outpdw(MDP_BASE + 0x40c9c, 0x40404);
outpdw(MDP_BASE + 0x40ca0, 0x40404);
outpdw(MDP_BASE + 0x40ca4, 0x40404);
outpdw(MDP_BASE + 0x40ca8, 0x50505);
outpdw(MDP_BASE + 0x40cac, 0x50505);
outpdw(MDP_BASE + 0x40cb0, 0x50505);
outpdw(MDP_BASE + 0x40cb4, 0x50505);
outpdw(MDP_BASE + 0x40cb8, 0x60606);
outpdw(MDP_BASE + 0x40cbc, 0x60606);
outpdw(MDP_BASE + 0x40cc0, 0x60606);
outpdw(MDP_BASE + 0x40cc4, 0x70707);
outpdw(MDP_BASE + 0x40cc8, 0x70707);
outpdw(MDP_BASE + 0x40ccc, 0x70707);
outpdw(MDP_BASE + 0x40cd0, 0x70707);
outpdw(MDP_BASE + 0x40cd4, 0x80808);
outpdw(MDP_BASE + 0x40cd8, 0x80808);
outpdw(MDP_BASE + 0x40cdc, 0x80808);
outpdw(MDP_BASE + 0x40ce0, 0x90909);
outpdw(MDP_BASE + 0x40ce4, 0x90909);
outpdw(MDP_BASE + 0x40ce8, 0xa0a0a);
outpdw(MDP_BASE + 0x40cec, 0xa0a0a);
outpdw(MDP_BASE + 0x40cf0, 0xa0a0a);
outpdw(MDP_BASE + 0x40cf4, 0xb0b0b);
outpdw(MDP_BASE + 0x40cf8, 0xb0b0b);
outpdw(MDP_BASE + 0x40cfc, 0xb0b0b);
outpdw(MDP_BASE + 0x40d00, 0xc0c0c);
outpdw(MDP_BASE + 0x40d04, 0xc0c0c);
outpdw(MDP_BASE + 0x40d08, 0xd0d0d);
outpdw(MDP_BASE + 0x40d0c, 0xd0d0d);
outpdw(MDP_BASE + 0x40d10, 0xe0e0e);
outpdw(MDP_BASE + 0x40d14, 0xe0e0e);
outpdw(MDP_BASE + 0x40d18, 0xe0e0e);
outpdw(MDP_BASE + 0x40d1c, 0xf0f0f);
outpdw(MDP_BASE + 0x40d20, 0xf0f0f);
outpdw(MDP_BASE + 0x40d24, 0x101010);
outpdw(MDP_BASE + 0x40d28, 0x101010);
outpdw(MDP_BASE + 0x40d2c, 0x111111);
outpdw(MDP_BASE + 0x40d30, 0x111111);
outpdw(MDP_BASE + 0x40d34, 0x121212);
outpdw(MDP_BASE + 0x40d38, 0x121212);
outpdw(MDP_BASE + 0x40d3c, 0x131313);
outpdw(MDP_BASE + 0x40d40, 0x131313);
outpdw(MDP_BASE + 0x40d44, 0x141414);
outpdw(MDP_BASE + 0x40d48, 0x151515);
outpdw(MDP_BASE + 0x40d4c, 0x151515);
outpdw(MDP_BASE + 0x40d50, 0x161616);
outpdw(MDP_BASE + 0x40d54, 0x161616);
outpdw(MDP_BASE + 0x40d58, 0x171717);
outpdw(MDP_BASE + 0x40d5c, 0x171717);
outpdw(MDP_BASE + 0x40d60, 0x181818);
outpdw(MDP_BASE + 0x40d64, 0x191919);
outpdw(MDP_BASE + 0x40d68, 0x191919);
outpdw(MDP_BASE + 0x40d6c, 0x1a1a1a);
outpdw(MDP_BASE + 0x40d70, 0x1b1b1b);
outpdw(MDP_BASE + 0x40d74, 0x1b1b1b);
outpdw(MDP_BASE + 0x40d78, 0x1c1c1c);
outpdw(MDP_BASE + 0x40d7c, 0x1c1c1c);
outpdw(MDP_BASE + 0x40d80, 0x1d1d1d);
outpdw(MDP_BASE + 0x40d84, 0x1e1e1e);
outpdw(MDP_BASE + 0x40d88, 0x1f1f1f);
outpdw(MDP_BASE + 0x40d8c, 0x1f1f1f);
outpdw(MDP_BASE + 0x40d90, 0x202020);
outpdw(MDP_BASE + 0x40d94, 0x212121);
outpdw(MDP_BASE + 0x40d98, 0x212121);
outpdw(MDP_BASE + 0x40d9c, 0x222222);
outpdw(MDP_BASE + 0x40da0, 0x232323);
outpdw(MDP_BASE + 0x40da4, 0x242424);
outpdw(MDP_BASE + 0x40da8, 0x242424);
outpdw(MDP_BASE + 0x40dac, 0x252525);
outpdw(MDP_BASE + 0x40db0, 0x262626);
outpdw(MDP_BASE + 0x40db4, 0x272727);
outpdw(MDP_BASE + 0x40db8, 0x272727);
outpdw(MDP_BASE + 0x40dbc, 0x282828);
outpdw(MDP_BASE + 0x40dc0, 0x292929);
outpdw(MDP_BASE + 0x40dc4, 0x2a2a2a);
outpdw(MDP_BASE + 0x40dc8, 0x2b2b2b);
outpdw(MDP_BASE + 0x40dcc, 0x2c2c2c);
outpdw(MDP_BASE + 0x40dd0, 0x2c2c2c);
outpdw(MDP_BASE + 0x40dd4, 0x2d2d2d);
outpdw(MDP_BASE + 0x40dd8, 0x2e2e2e);
outpdw(MDP_BASE + 0x40ddc, 0x2f2f2f);
outpdw(MDP_BASE + 0x40de0, 0x303030);
outpdw(MDP_BASE + 0x40de4, 0x313131);
outpdw(MDP_BASE + 0x40de8, 0x323232);
outpdw(MDP_BASE + 0x40dec, 0x333333);
outpdw(MDP_BASE + 0x40df0, 0x333333);
outpdw(MDP_BASE + 0x40df4, 0x343434);
outpdw(MDP_BASE + 0x40df8, 0x353535);
outpdw(MDP_BASE + 0x40dfc, 0x363636);
outpdw(MDP_BASE + 0x40e00, 0x373737);
outpdw(MDP_BASE + 0x40e04, 0x383838);
outpdw(MDP_BASE + 0x40e08, 0x393939);
outpdw(MDP_BASE + 0x40e0c, 0x3a3a3a);
outpdw(MDP_BASE + 0x40e10, 0x3b3b3b);
outpdw(MDP_BASE + 0x40e14, 0x3c3c3c);
outpdw(MDP_BASE + 0x40e18, 0x3d3d3d);
outpdw(MDP_BASE + 0x40e1c, 0x3e3e3e);
outpdw(MDP_BASE + 0x40e20, 0x3f3f3f);
outpdw(MDP_BASE + 0x40e24, 0x404040);
outpdw(MDP_BASE + 0x40e28, 0x414141);
outpdw(MDP_BASE + 0x40e2c, 0x424242);
outpdw(MDP_BASE + 0x40e30, 0x434343);
outpdw(MDP_BASE + 0x40e34, 0x444444);
outpdw(MDP_BASE + 0x40e38, 0x464646);
outpdw(MDP_BASE + 0x40e3c, 0x474747);
outpdw(MDP_BASE + 0x40e40, 0x484848);
outpdw(MDP_BASE + 0x40e44, 0x494949);
outpdw(MDP_BASE + 0x40e48, 0x4a4a4a);
outpdw(MDP_BASE + 0x40e4c, 0x4b4b4b);
outpdw(MDP_BASE + 0x40e50, 0x4c4c4c);
outpdw(MDP_BASE + 0x40e54, 0x4d4d4d);
outpdw(MDP_BASE + 0x40e58, 0x4f4f4f);
outpdw(MDP_BASE + 0x40e5c, 0x505050);
outpdw(MDP_BASE + 0x40e60, 0x515151);
outpdw(MDP_BASE + 0x40e64, 0x525252);
outpdw(MDP_BASE + 0x40e68, 0x535353);
outpdw(MDP_BASE + 0x40e6c, 0x545454);
outpdw(MDP_BASE + 0x40e70, 0x565656);
outpdw(MDP_BASE + 0x40e74, 0x575757);
outpdw(MDP_BASE + 0x40e78, 0x585858);
outpdw(MDP_BASE + 0x40e7c, 0x595959);
outpdw(MDP_BASE + 0x40e80, 0x5b5b5b);
outpdw(MDP_BASE + 0x40e84, 0x5c5c5c);
outpdw(MDP_BASE + 0x40e88, 0x5d5d5d);
outpdw(MDP_BASE + 0x40e8c, 0x5e5e5e);
outpdw(MDP_BASE + 0x40e90, 0x606060);
outpdw(MDP_BASE + 0x40e94, 0x616161);
outpdw(MDP_BASE + 0x40e98, 0x626262);
outpdw(MDP_BASE + 0x40e9c, 0x646464);
outpdw(MDP_BASE + 0x40ea0, 0x656565);
outpdw(MDP_BASE + 0x40ea4, 0x666666);
outpdw(MDP_BASE + 0x40ea8, 0x686868);
outpdw(MDP_BASE + 0x40eac, 0x696969);
outpdw(MDP_BASE + 0x40eb0, 0x6a6a6a);
outpdw(MDP_BASE + 0x40eb4, 0x6c6c6c);
outpdw(MDP_BASE + 0x40eb8, 0x6d6d6d);
outpdw(MDP_BASE + 0x40ebc, 0x6f6f6f);
outpdw(MDP_BASE + 0x40ec0, 0x707070);
outpdw(MDP_BASE + 0x40ec4, 0x717171);
outpdw(MDP_BASE + 0x40ec8, 0x737373);
outpdw(MDP_BASE + 0x40ecc, 0x747474);
outpdw(MDP_BASE + 0x40ed0, 0x767676);
outpdw(MDP_BASE + 0x40ed4, 0x777777);
outpdw(MDP_BASE + 0x40ed8, 0x797979);
outpdw(MDP_BASE + 0x40edc, 0x7a7a7a);
outpdw(MDP_BASE + 0x40ee0, 0x7c7c7c);
outpdw(MDP_BASE + 0x40ee4, 0x7d7d7d);
outpdw(MDP_BASE + 0x40ee8, 0x7f7f7f);
outpdw(MDP_BASE + 0x40eec, 0x808080);
outpdw(MDP_BASE + 0x40ef0, 0x828282);
outpdw(MDP_BASE + 0x40ef4, 0x838383);
outpdw(MDP_BASE + 0x40ef8, 0x858585);
outpdw(MDP_BASE + 0x40efc, 0x868686);
outpdw(MDP_BASE + 0x40f00, 0x888888);
outpdw(MDP_BASE + 0x40f04, 0x898989);
outpdw(MDP_BASE + 0x40f08, 0x8b8b8b);
outpdw(MDP_BASE + 0x40f0c, 0x8d8d8d);
outpdw(MDP_BASE + 0x40f10, 0x8e8e8e);
outpdw(MDP_BASE + 0x40f14, 0x909090);
outpdw(MDP_BASE + 0x40f18, 0x919191);
outpdw(MDP_BASE + 0x40f1c, 0x939393);
outpdw(MDP_BASE + 0x40f20, 0x959595);
outpdw(MDP_BASE + 0x40f24, 0x969696);
outpdw(MDP_BASE + 0x40f28, 0x989898);
outpdw(MDP_BASE + 0x40f2c, 0x9a9a9a);
outpdw(MDP_BASE + 0x40f30, 0x9b9b9b);
outpdw(MDP_BASE + 0x40f34, 0x9d9d9d);
outpdw(MDP_BASE + 0x40f38, 0x9f9f9f);
outpdw(MDP_BASE + 0x40f3c, 0xa1a1a1);
outpdw(MDP_BASE + 0x40f40, 0xa2a2a2);
outpdw(MDP_BASE + 0x40f44, 0xa4a4a4);
outpdw(MDP_BASE + 0x40f48, 0xa6a6a6);
outpdw(MDP_BASE + 0x40f4c, 0xa7a7a7);
outpdw(MDP_BASE + 0x40f50, 0xa9a9a9);
outpdw(MDP_BASE + 0x40f54, 0xababab);
outpdw(MDP_BASE + 0x40f58, 0xadadad);
outpdw(MDP_BASE + 0x40f5c, 0xafafaf);
outpdw(MDP_BASE + 0x40f60, 0xb0b0b0);
outpdw(MDP_BASE + 0x40f64, 0xb2b2b2);
outpdw(MDP_BASE + 0x40f68, 0xb4b4b4);
outpdw(MDP_BASE + 0x40f6c, 0xb6b6b6);
outpdw(MDP_BASE + 0x40f70, 0xb8b8b8);
outpdw(MDP_BASE + 0x40f74, 0xbababa);
outpdw(MDP_BASE + 0x40f78, 0xbbbbbb);
outpdw(MDP_BASE + 0x40f7c, 0xbdbdbd);
outpdw(MDP_BASE + 0x40f80, 0xbfbfbf);
outpdw(MDP_BASE + 0x40f84, 0xc1c1c1);
outpdw(MDP_BASE + 0x40f88, 0xc3c3c3);
outpdw(MDP_BASE + 0x40f8c, 0xc5c5c5);
outpdw(MDP_BASE + 0x40f90, 0xc7c7c7);
outpdw(MDP_BASE + 0x40f94, 0xc9c9c9);
outpdw(MDP_BASE + 0x40f98, 0xcbcbcb);
outpdw(MDP_BASE + 0x40f9c, 0xcdcdcd);
outpdw(MDP_BASE + 0x40fa0, 0xcfcfcf);
outpdw(MDP_BASE + 0x40fa4, 0xd1d1d1);
outpdw(MDP_BASE + 0x40fa8, 0xd3d3d3);
outpdw(MDP_BASE + 0x40fac, 0xd5d5d5);
outpdw(MDP_BASE + 0x40fb0, 0xd7d7d7);
outpdw(MDP_BASE + 0x40fb4, 0xd9d9d9);
outpdw(MDP_BASE + 0x40fb8, 0xdbdbdb);
outpdw(MDP_BASE + 0x40fbc, 0xdddddd);
outpdw(MDP_BASE + 0x40fc0, 0xdfdfdf);
outpdw(MDP_BASE + 0x40fc4, 0xe1e1e1);
outpdw(MDP_BASE + 0x40fc8, 0xe3e3e3);
outpdw(MDP_BASE + 0x40fcc, 0xe5e5e5);
outpdw(MDP_BASE + 0x40fd0, 0xe7e7e7);
outpdw(MDP_BASE + 0x40fd4, 0xe9e9e9);
outpdw(MDP_BASE + 0x40fd8, 0xebebeb);
outpdw(MDP_BASE + 0x40fdc, 0xeeeeee);
outpdw(MDP_BASE + 0x40fe0, 0xf0f0f0);
outpdw(MDP_BASE + 0x40fe4, 0xf2f2f2);
outpdw(MDP_BASE + 0x40fe8, 0xf4f4f4);
outpdw(MDP_BASE + 0x40fec, 0xf6f6f6);
outpdw(MDP_BASE + 0x40ff0, 0xf8f8f8);
outpdw(MDP_BASE + 0x40ff4, 0xfbfbfb);
outpdw(MDP_BASE + 0x40ff8, 0xfdfdfd);
outpdw(MDP_BASE + 0x40ffc, 0xffffff);
}
#define IRQ_EN_1__MDP_IRQ___M 0x00000800
void mdp_hw_init(void)
{
int i;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* debug interface write access */
outpdw(MDP_BASE + 0x60, 1);
outp32(MDP_INTR_ENABLE, MDP_ANY_INTR_MASK);
outp32(MDP_EBI2_PORTMAP_MODE, 0x3);
outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8, 0x0);
outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc, 0x0);
outpdw(MDP_BASE + 0x60, 0x1);
mdp_load_lut_param();
/*
* clear up unused fg/main registers
*/
/* comp.plane 2&3 ystride */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0120, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x012c, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0130, 0x0);
/* unpacked pattern */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0134, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0158, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x15c, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0160, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0170, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0174, 0x0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x017c, 0x0);
/* comp.plane 2 */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0114, 0x0);
/* comp.plane 3 */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0118, 0x0);
/* clear up unused bg registers */
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0);
#ifndef CONFIG_FB_MSM_MDP22
MDP_OUTP(MDP_BASE + 0xE0000, 0);
MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
MDP_OUTP(MDP_BASE + 0x90070, 0);
MDP_OUTP(MDP_BASE + 0x94010, 1);
MDP_OUTP(MDP_BASE + 0x9401c, 2);
#endif
/*
* limit vector
* pre gets applied before color matrix conversion
* post is after ccs
*/
writel(mdp_plv[0], MDP_CSC_PRE_LV1n(0));
writel(mdp_plv[1], MDP_CSC_PRE_LV1n(1));
writel(mdp_plv[2], MDP_CSC_PRE_LV1n(2));
writel(mdp_plv[3], MDP_CSC_PRE_LV1n(3));
#ifdef CONFIG_FB_MSM_MDP31
writel(mdp_plv[2], MDP_CSC_PRE_LV1n(4));
writel(mdp_plv[3], MDP_CSC_PRE_LV1n(5));
writel(0, MDP_CSC_POST_LV1n(0));
writel(0xff, MDP_CSC_POST_LV1n(1));
writel(0, MDP_CSC_POST_LV1n(2));
writel(0xff, MDP_CSC_POST_LV1n(3));
writel(0, MDP_CSC_POST_LV1n(4));
writel(0xff, MDP_CSC_POST_LV1n(5));
writel(0, MDP_CSC_PRE_LV2n(0));
writel(0xff, MDP_CSC_PRE_LV2n(1));
writel(0, MDP_CSC_PRE_LV2n(2));
writel(0xff, MDP_CSC_PRE_LV2n(3));
writel(0, MDP_CSC_PRE_LV2n(4));
writel(0xff, MDP_CSC_PRE_LV2n(5));
writel(mdp_plv[0], MDP_CSC_POST_LV2n(0));
writel(mdp_plv[1], MDP_CSC_POST_LV2n(1));
writel(mdp_plv[2], MDP_CSC_POST_LV2n(2));
writel(mdp_plv[3], MDP_CSC_POST_LV2n(3));
writel(mdp_plv[2], MDP_CSC_POST_LV2n(4));
writel(mdp_plv[3], MDP_CSC_POST_LV2n(5));
#endif
/* primary forward matrix */
for (i = 0; i < MDP_CCS_SIZE; i++)
writel(mdp_ccs_rgb2yuv.ccs[i], MDP_CSC_PFMVn(i));
#ifdef CONFIG_FB_MSM_MDP31
for (i = 0; i < MDP_BV_SIZE; i++)
writel(mdp_ccs_rgb2yuv.bv[i], MDP_CSC_POST_BV2n(i));
writel(0, MDP_CSC_PRE_BV2n(0));
writel(0, MDP_CSC_PRE_BV2n(1));
writel(0, MDP_CSC_PRE_BV2n(2));
#endif
/* primary reverse matrix */
for (i = 0; i < MDP_CCS_SIZE; i++)
writel(mdp_ccs_yuv2rgb.ccs[i], MDP_CSC_PRMVn(i));
for (i = 0; i < MDP_BV_SIZE; i++)
writel(mdp_ccs_yuv2rgb.bv[i], MDP_CSC_PRE_BV1n(i));
#ifdef CONFIG_FB_MSM_MDP31
writel(0, MDP_CSC_POST_BV1n(0));
writel(0, MDP_CSC_POST_BV1n(1));
writel(0, MDP_CSC_POST_BV1n(2));
outpdw(MDP_BASE + 0x30010, 0x03e0);
outpdw(MDP_BASE + 0x30014, 0x0360);
outpdw(MDP_BASE + 0x30018, 0x0120);
outpdw(MDP_BASE + 0x3001c, 0x0140);
#endif
mdp_init_scale_table();
#ifndef CONFIG_FB_MSM_MDP31
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0104,
((16 << 6) << 16) | (16) << 6);
#endif
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,347 @@
/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "mdp.h"
static boolean mdp_ppp_intr_flag = FALSE;
static boolean mdp_ppp_busy_flag = FALSE;
/* Queue to keep track of the completed jobs for cleaning */
static LIST_HEAD(mdp_ppp_djob_clnrq);
static DEFINE_SPINLOCK(mdp_ppp_djob_clnrq_lock);
/* Worker to cleanup Display Jobs */
static struct workqueue_struct *mdp_ppp_djob_clnr;
/* Display Queue (DQ) for MDP PPP Block */
static LIST_HEAD(mdp_ppp_dq);
static DEFINE_SPINLOCK(mdp_ppp_dq_lock);
/* Current Display Job for MDP PPP */
static struct mdp_ppp_djob *curr_djob;
/* Track ret code for the last opeartion */
static int mdp_ppp_ret_code;
inline int mdp_ppp_get_ret_code(void)
{
return mdp_ppp_ret_code;
}
/* Push <Reg, Val> pair into DQ (if available) to later
* program the MDP PPP Block */
inline void mdp_ppp_outdw(uint32_t addr, uint32_t data)
{
if (curr_djob) {
/* get the last node of the list. */
struct mdp_ppp_roi_cmd_set *node =
list_entry(curr_djob->roi_cmd_list.prev,
struct mdp_ppp_roi_cmd_set, node);
/* If a node is already full, create a new one and add it to
* the list (roi_cmd_list).
*/
if (node->ncmds == MDP_PPP_ROI_NODE_SIZE) {
node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set),
GFP_KERNEL);
if (!node) {
printk(KERN_ERR
"MDP_PPP: not enough memory.\n");
mdp_ppp_ret_code = -EINVAL;
return;
}
/* no ROI commands initially */
node->ncmds = 0;
/* add one node to roi_cmd_list. */
list_add_tail(&node->node, &curr_djob->roi_cmd_list);
}
/* register ROI commands */
node->cmd[node->ncmds].reg = addr;
node->cmd[node->ncmds].val = data;
node->ncmds++;
} else
/* program MDP PPP block now */
outpdw((addr), (data));
}
/* Initialize DQ */
inline void mdp_ppp_dq_init(void)
{
mdp_ppp_djob_clnr = create_singlethread_workqueue("MDPDJobClnrThrd");
}
/* Release resources of a job (DJob). */
static void mdp_ppp_del_djob(struct mdp_ppp_djob *job)
{
struct mdp_ppp_roi_cmd_set *node, *tmp;
/* release mem */
mdp_ppp_put_img(job->p_src_file, job->p_dst_file);
/* release roi_cmd_list */
list_for_each_entry_safe(node, tmp, &job->roi_cmd_list, node) {
list_del(&node->node);
kfree(node);
}
/* release job struct */
kfree(job);
}
/* Worker thread to reclaim resources once a display job is done */
static void mdp_ppp_djob_cleaner(struct work_struct *work)
{
struct mdp_ppp_djob *job;
MDP_PPP_DEBUG_MSG("mdp ppp display job cleaner started \n");
/* cleanup display job */
job = container_of(work, struct mdp_ppp_djob, cleaner.work);
if (likely(work && job))
mdp_ppp_del_djob(job);
}
/* Create a new Display Job (DJob) */
inline struct mdp_ppp_djob *mdp_ppp_new_djob(void)
{
struct mdp_ppp_djob *job;
struct mdp_ppp_roi_cmd_set *node;
/* create a new djob */
job = kmalloc(sizeof(struct mdp_ppp_djob), GFP_KERNEL);
if (!job)
return NULL;
/* add the first node to curr_djob->roi_cmd_list */
node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set), GFP_KERNEL);
if (!node) {
kfree(job);
return NULL;
}
/* make this current djob container to keep track of the curr djob not
* used in the async path i.e. no sync needed
*
* Should not contain any references from the past djob
*/
BUG_ON(curr_djob);
curr_djob = job;
INIT_LIST_HEAD(&curr_djob->roi_cmd_list);
/* no ROI commands initially */
node->ncmds = 0;
INIT_LIST_HEAD(&node->node);
list_add_tail(&node->node, &curr_djob->roi_cmd_list);
/* register this djob with the djob cleaner
* initializes 'work' data struct
*/
INIT_DELAYED_WORK(&curr_djob->cleaner, mdp_ppp_djob_cleaner);
INIT_LIST_HEAD(&curr_djob->entry);
curr_djob->p_src_file = 0;
curr_djob->p_dst_file = 0;
return job;
}
/* Undo the effect of mdp_ppp_new_djob() */
inline void mdp_ppp_clear_curr_djob(void)
{
if (likely(curr_djob)) {
mdp_ppp_del_djob(curr_djob);
curr_djob = NULL;
}
}
/* Cleanup dirty djobs */
static void mdp_ppp_flush_dirty_djobs(void *cond)
{
unsigned long flags;
struct mdp_ppp_djob *job;
/* Flush the jobs from the djob clnr queue */
while (cond && test_bit(0, (unsigned long *)cond)) {
/* Until we are done with the cleanup queue */
spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
if (list_empty(&mdp_ppp_djob_clnrq)) {
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
break;
}
MDP_PPP_DEBUG_MSG("flushing djobs ... loop \n");
/* Retrieve the job that needs to be cleaned */
job = list_entry(mdp_ppp_djob_clnrq.next,
struct mdp_ppp_djob, entry);
list_del_init(&job->entry);
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
/* Keep mem state coherent */
msm_fb_ensure_mem_coherency_after_dma(job->info, &job->req, 1);
/* Schedule jobs for cleanup
* A seperate worker thread does this */
queue_delayed_work(mdp_ppp_djob_clnr, &job->cleaner,
mdp_timer_duration);
}
}
/* If MDP PPP engine is busy, wait until it is available again */
void mdp_ppp_wait(void)
{
unsigned long flags;
int cond = 1;
/* keep flushing dirty djobs as long as MDP PPP engine is busy */
mdp_ppp_flush_dirty_djobs(&mdp_ppp_busy_flag);
/* block if MDP PPP engine is still busy */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (test_bit(0, (unsigned long *)&mdp_ppp_busy_flag)) {
/* prepare for the wakeup event */
test_and_set_bit(0, (unsigned long *)&mdp_ppp_waiting);
INIT_COMPLETION(mdp_ppp_comp);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* block uninterruptibly until available */
MDP_PPP_DEBUG_MSG("waiting for mdp... \n");
wait_for_completion_killable(&mdp_ppp_comp);
/* if MDP PPP engine is still free,
* disable INT_MDP if enabled
*/
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (!test_bit(0, (unsigned long *)&mdp_ppp_busy_flag) &&
test_and_clear_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
mdp_disable_irq(MDP_PPP_TERM);
}
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* flush remaining dirty djobs, if any */
mdp_ppp_flush_dirty_djobs(&cond);
}
/* Program MDP PPP block to process this ROI */
static void mdp_ppp_process_roi(struct list_head *roi_cmd_list)
{
/* program PPP engine with registered ROI commands */
struct mdp_ppp_roi_cmd_set *node;
list_for_each_entry(node, roi_cmd_list, node) {
int i = 0;
for (; i < node->ncmds; i++) {
MDP_PPP_DEBUG_MSG("%d: reg: 0x%x val: 0x%x \n",
i, node->cmd[i].reg, node->cmd[i].val);
outpdw(node->cmd[i].reg, node->cmd[i].val);
}
}
/* kickoff MDP PPP engine */
MDP_PPP_DEBUG_MSG("kicking off mdp \n");
outpdw(MDP_BASE + 0x30, 0x1000);
}
/* Submit this display job to MDP PPP engine */
static void mdp_ppp_dispatch_djob(struct mdp_ppp_djob *job)
{
/* enable INT_MDP if disabled */
if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
mdp_enable_irq(MDP_PPP_TERM);
/* turn on PPP and CMD blocks */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
/* process this ROI */
mdp_ppp_process_roi(&job->roi_cmd_list);
}
/* Enqueue this display job to be cleaned up later in "mdp_ppp_djob_done" */
static inline void mdp_ppp_enqueue_djob(struct mdp_ppp_djob *job)
{
unsigned long flags;
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
list_add_tail(&job->entry, &mdp_ppp_dq);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
}
/* First enqueue display job for cleanup and dispatch immediately
* if MDP PPP engine is free */
void mdp_ppp_process_curr_djob(void)
{
/* enqueue djob */
mdp_ppp_enqueue_djob(curr_djob);
/* dispatch now if MDP PPP engine is free */
if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_busy_flag))
mdp_ppp_dispatch_djob(curr_djob);
/* done with the current djob */
curr_djob = NULL;
}
/* Called from mdp_isr - cleanup finished job and start with next
* if available else set MDP PPP engine free */
void mdp_ppp_djob_done(void)
{
struct mdp_ppp_djob *curr, *next;
unsigned long flags;
/* dequeue current */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
curr = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob, entry);
list_del_init(&curr->entry);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* cleanup current - enqueue in the djob clnr queue */
spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
list_add_tail(&curr->entry, &mdp_ppp_djob_clnrq);
spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
/* grab next pending */
spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
if (!list_empty(&mdp_ppp_dq)) {
next = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob,
entry);
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* process next in the queue */
mdp_ppp_process_roi(&next->roi_cmd_list);
} else {
/* no pending display job */
spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
/* turn off PPP and CMD blocks - "in_isr" is TRUE */
mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
/* notify if waiting */
if (test_and_clear_bit(0, (unsigned long *)&mdp_ppp_waiting))
complete(&mdp_ppp_comp);
/* set free */
test_and_clear_bit(0, (unsigned long *)&mdp_ppp_busy_flag);
}
}

View File

@ -0,0 +1,86 @@
/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MDP_PPP_DQ_H
#define MDP_PPP_DQ_H
#include "msm_fb_def.h"
#define MDP_PPP_DEBUG_MSG MSM_FB_DEBUG
/* The maximum number of <Reg,Val> pairs in an mdp_ppp_roi_cmd_set structure (a
* node)
*/
#define MDP_PPP_ROI_NODE_SIZE 32
/* ROI config command (<Reg,Val> pair) for MDP PPP block */
struct mdp_ppp_roi_cmd {
uint32_t reg;
uint32_t val;
};
/* ROI config commands for MDP PPP block are stored in a list of
* mdp_ppp_roi_cmd_set structures (nodes).
*/
struct mdp_ppp_roi_cmd_set {
struct list_head node;
uint32_t ncmds; /* number of commands in this set (node). */
struct mdp_ppp_roi_cmd cmd[MDP_PPP_ROI_NODE_SIZE];
};
/* MDP PPP Display Job (DJob) */
struct mdp_ppp_djob {
struct list_head entry;
/* One ROI per MDP PPP DJob */
struct list_head roi_cmd_list;
struct mdp_blit_req req;
struct fb_info *info;
struct delayed_work cleaner;
struct file *p_src_file, *p_dst_file;
};
extern struct completion mdp_ppp_comp;
extern boolean mdp_ppp_waiting;
extern unsigned long mdp_timer_duration;
unsigned int mdp_ppp_async_op_get(void);
void mdp_ppp_async_op_set(unsigned int flag);
void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info,
struct mdp_blit_req *req_list, int req_list_count);
void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file);
void mdp_ppp_dq_init(void);
void mdp_ppp_outdw(uint32_t addr, uint32_t data);
struct mdp_ppp_djob *mdp_ppp_new_djob(void);
void mdp_ppp_clear_curr_djob(void);
void mdp_ppp_process_curr_djob(void);
int mdp_ppp_get_ret_code(void);
void mdp_ppp_djob_done(void);
void mdp_ppp_wait(void);
#endif /* MDP_PPP_DQ_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,828 @@
/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <asm/div64.h>
#include "mdp.h"
#include "msm_fb.h"
#define MDP_SCALE_COEFF_NUM 32
#define MDP_SCALE_0P2_TO_0P4_INDEX 0
#define MDP_SCALE_0P4_TO_0P6_INDEX 32
#define MDP_SCALE_0P6_TO_0P8_INDEX 64
#define MDP_SCALE_0P8_TO_8P0_INDEX 96
#define MDP_SCALE_COEFF_MASK 0x3ff
#define MDP_SCALE_PR 0
#define MDP_SCALE_FIR 1
static uint32 mdp_scale_0p8_to_8p0_mode;
static uint32 mdp_scale_0p6_to_0p8_mode;
static uint32 mdp_scale_0p4_to_0p6_mode;
static uint32 mdp_scale_0p2_to_0p4_mode;
/* -------- All scaling range, "pixel repeat" -------- */
static int16 mdp_scale_pixel_repeat_C0[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static int16 mdp_scale_pixel_repeat_C1[MDP_SCALE_COEFF_NUM] = {
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511,
511, 511, 511, 511, 511, 511, 511, 511
};
static int16 mdp_scale_pixel_repeat_C2[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static int16 mdp_scale_pixel_repeat_C3[MDP_SCALE_COEFF_NUM] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/* --------------------------- FIR ------------------------------------- */
/* -------- Downscale, ranging from 0.8x to 8.0x of original size -------- */
static int16 mdp_scale_0p8_to_8p0_C0[MDP_SCALE_COEFF_NUM] = {
0, -7, -13, -19, -24, -28, -32, -34, -37, -39,
-40, -41, -41, -41, -40, -40, -38, -37, -35, -33,
-31, -29, -26, -24, -21, -18, -15, -13, -10, -7,
-5, -2
};
static int16 mdp_scale_0p8_to_8p0_C1[MDP_SCALE_COEFF_NUM] = {
511, 507, 501, 494, 485, 475, 463, 450, 436, 422,
405, 388, 370, 352, 333, 314, 293, 274, 253, 233,
213, 193, 172, 152, 133, 113, 95, 77, 60, 43,
28, 13
};
static int16 mdp_scale_0p8_to_8p0_C2[MDP_SCALE_COEFF_NUM] = {
0, 13, 28, 43, 60, 77, 95, 113, 133, 152,
172, 193, 213, 233, 253, 274, 294, 314, 333, 352,
370, 388, 405, 422, 436, 450, 463, 475, 485, 494,
501, 507,
};
static int16 mdp_scale_0p8_to_8p0_C3[MDP_SCALE_COEFF_NUM] = {
0, -2, -5, -7, -10, -13, -15, -18, -21, -24,
-26, -29, -31, -33, -35, -37, -38, -40, -40, -41,
-41, -41, -40, -39, -37, -34, -32, -28, -24, -19,
-13, -7
};
/* -------- Downscale, ranging from 0.6x to 0.8x of original size -------- */
static int16 mdp_scale_0p6_to_0p8_C0[MDP_SCALE_COEFF_NUM] = {
104, 96, 89, 82, 75, 68, 61, 55, 49, 43,
38, 33, 28, 24, 20, 16, 12, 9, 6, 4,
2, 0, -2, -4, -5, -6, -7, -7, -8, -8,
-8, -8
};
static int16 mdp_scale_0p6_to_0p8_C1[MDP_SCALE_COEFF_NUM] = {
303, 303, 302, 300, 298, 296, 293, 289, 286, 281,
276, 270, 265, 258, 252, 245, 238, 230, 223, 214,
206, 197, 189, 180, 172, 163, 154, 145, 137, 128,
120, 112
};
static int16 mdp_scale_0p6_to_0p8_C2[MDP_SCALE_COEFF_NUM] = {
112, 120, 128, 137, 145, 154, 163, 172, 180, 189,
197, 206, 214, 223, 230, 238, 245, 252, 258, 265,
270, 276, 281, 286, 289, 293, 296, 298, 300, 302,
303, 303
};
static int16 mdp_scale_0p6_to_0p8_C3[MDP_SCALE_COEFF_NUM] = {
-8, -8, -8, -8, -7, -7, -6, -5, -4, -2,
0, 2, 4, 6, 9, 12, 16, 20, 24, 28,
33, 38, 43, 49, 55, 61, 68, 75, 82, 89,
96, 104
};
/* -------- Downscale, ranging from 0.4x to 0.6x of original size -------- */
static int16 mdp_scale_0p4_to_0p6_C0[MDP_SCALE_COEFF_NUM] = {
136, 132, 128, 123, 119, 115, 111, 107, 103, 98,
95, 91, 87, 84, 80, 76, 73, 69, 66, 62,
59, 57, 54, 50, 47, 44, 41, 39, 36, 33,
32, 29
};
static int16 mdp_scale_0p4_to_0p6_C1[MDP_SCALE_COEFF_NUM] = {
206, 205, 204, 204, 201, 200, 199, 197, 196, 194,
191, 191, 189, 185, 184, 182, 180, 178, 176, 173,
170, 168, 165, 162, 160, 157, 155, 152, 148, 146,
142, 140
};
static int16 mdp_scale_0p4_to_0p6_C2[MDP_SCALE_COEFF_NUM] = {
140, 142, 146, 148, 152, 155, 157, 160, 162, 165,
168, 170, 173, 176, 178, 180, 182, 184, 185, 189,
191, 191, 194, 196, 197, 199, 200, 201, 204, 204,
205, 206
};
static int16 mdp_scale_0p4_to_0p6_C3[MDP_SCALE_COEFF_NUM] = {
29, 32, 33, 36, 39, 41, 44, 47, 50, 54,
57, 59, 62, 66, 69, 73, 76, 80, 84, 87,
91, 95, 98, 103, 107, 111, 115, 119, 123, 128,
132, 136
};
/* -------- Downscale, ranging from 0.2x to 0.4x of original size -------- */
static int16 mdp_scale_0p2_to_0p4_C0[MDP_SCALE_COEFF_NUM] = {
131, 131, 130, 129, 128, 127, 127, 126, 125, 125,
124, 123, 123, 121, 120, 119, 119, 118, 117, 117,
116, 115, 115, 114, 113, 112, 111, 110, 109, 109,
108, 107
};
static int16 mdp_scale_0p2_to_0p4_C1[MDP_SCALE_COEFF_NUM] = {
141, 140, 140, 140, 140, 139, 138, 138, 138, 137,
137, 137, 136, 137, 137, 137, 136, 136, 136, 135,
135, 135, 134, 134, 134, 134, 134, 133, 133, 132,
132, 132
};
static int16 mdp_scale_0p2_to_0p4_C2[MDP_SCALE_COEFF_NUM] = {
132, 132, 132, 133, 133, 134, 134, 134, 134, 134,
135, 135, 135, 136, 136, 136, 137, 137, 137, 136,
137, 137, 137, 138, 138, 138, 139, 140, 140, 140,
140, 141
};
static int16 mdp_scale_0p2_to_0p4_C3[MDP_SCALE_COEFF_NUM] = {
107, 108, 109, 109, 110, 111, 112, 113, 114, 115,
115, 116, 117, 117, 118, 119, 119, 120, 121, 123,
123, 124, 125, 125, 126, 127, 127, 128, 129, 130,
131, 131
};
static void mdp_update_scale_table(int index, int16 *c0, int16 *c1,
int16 *c2, int16 *c3)
{
int i, val;
for (i = 0; i < MDP_SCALE_COEFF_NUM; i++) {
val =
((MDP_SCALE_COEFF_MASK & c1[i]) << 16) |
(MDP_SCALE_COEFF_MASK & c0[i]);
MDP_OUTP(MDP_PPP_SCALE_COEFF_LSBn(index), val);
val =
((MDP_SCALE_COEFF_MASK & c3[i]) << 16) |
(MDP_SCALE_COEFF_MASK & c2[i]);
MDP_OUTP(MDP_PPP_SCALE_COEFF_MSBn(index), val);
index++;
}
}
void mdp_init_scale_table(void)
{
mdp_scale_0p2_to_0p4_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
mdp_scale_0p4_to_0p6_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
mdp_scale_0p6_to_0p8_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
mdp_scale_0p8_to_8p0_mode = MDP_SCALE_FIR;
mdp_update_scale_table(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
static long long mdp_do_div(long long num, long long den)
{
do_div(num, den);
return num;
}
#define SCALER_PHASE_BITS 29
#define HAL_MDP_PHASE_STEP_2P50 0x50000000
#define HAL_MDP_PHASE_STEP_1P66 0x35555555
#define HAL_MDP_PHASE_STEP_1P25 0x28000000
struct phase_val {
int phase_init_x;
int phase_init_y;
int phase_step_x;
int phase_step_y;
};
static void mdp_calc_scaleInitPhase_3p1(uint32 in_w,
uint32 in_h,
uint32 out_w,
uint32 out_h,
boolean is_rotate,
boolean is_pp_x,
boolean is_pp_y, struct phase_val *pval)
{
uint64 dst_ROI_width;
uint64 dst_ROI_height;
uint64 src_ROI_width;
uint64 src_ROI_height;
/*
* phase_step_x, phase_step_y, phase_init_x and phase_init_y
* are represented in fixed-point, unsigned 3.29 format
*/
uint32 phase_step_x = 0;
uint32 phase_step_y = 0;
uint32 phase_init_x = 0;
uint32 phase_init_y = 0;
uint32 yscale_filter_sel, xscale_filter_sel;
uint32 scale_unit_sel_x, scale_unit_sel_y;
uint64 numerator, denominator;
uint64 temp_dim;
src_ROI_width = in_w;
src_ROI_height = in_h;
dst_ROI_width = out_w;
dst_ROI_height = out_h;
/* if there is a 90 degree rotation */
if (is_rotate) {
/* decide whether to use FIR or M/N for scaling */
/* if down-scaling by a factor smaller than 1/4 */
if (src_ROI_width > (4 * dst_ROI_height))
scale_unit_sel_x = 1; /* use M/N scalar */
else
scale_unit_sel_x = 0; /* use FIR scalar */
/* if down-scaling by a factor smaller than 1/4 */
if (src_ROI_height > (4 * dst_ROI_width))
scale_unit_sel_y = 1; /* use M/N scalar */
else
scale_unit_sel_y = 0; /* use FIR scalar */
} else {
/* decide whether to use FIR or M/N for scaling */
if (src_ROI_width > (4 * dst_ROI_width))
scale_unit_sel_x = 1; /* use M/N scalar */
else
scale_unit_sel_x = 0; /* use FIR scalar */
if (src_ROI_height > (4 * dst_ROI_height))
scale_unit_sel_y = 1; /* use M/N scalar */
else
scale_unit_sel_y = 0; /* use FIR scalar */
}
/* if there is a 90 degree rotation */
if (is_rotate) {
/* swap the width and height of dst ROI */
temp_dim = dst_ROI_width;
dst_ROI_width = dst_ROI_height;
dst_ROI_height = temp_dim;
}
/* calculate phase step for the x direction */
/* if destination is only 1 pixel wide, the value of phase_step_x
is unimportant. Assigning phase_step_x to src ROI width
as an arbitrary value. */
if (dst_ROI_width == 1)
phase_step_x = (uint32) ((src_ROI_width) << SCALER_PHASE_BITS);
/* if using FIR scalar */
else if (scale_unit_sel_x == 0) {
/* Calculate the quotient ( src_ROI_width - 1 ) / ( dst_ROI_width - 1)
with u3.29 precision. Quotient is rounded up to the larger
29th decimal point. */
numerator = (src_ROI_width - 1) << SCALER_PHASE_BITS;
denominator = (dst_ROI_width - 1); /* never equals to 0 because of the "( dst_ROI_width == 1 ) case" */
phase_step_x = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* divide and round up to the larger 29th decimal point. */
}
/* if M/N scalar */
else if (scale_unit_sel_x == 1) {
/* Calculate the quotient ( src_ROI_width ) / ( dst_ROI_width)
with u3.29 precision. Quotient is rounded down to the
smaller 29th decimal point. */
numerator = (src_ROI_width) << SCALER_PHASE_BITS;
denominator = (dst_ROI_width);
phase_step_x = (uint32) mdp_do_div(numerator, denominator);
}
/* calculate phase step for the y direction */
/* if destination is only 1 pixel wide, the value of
phase_step_x is unimportant. Assigning phase_step_x
to src ROI width as an arbitrary value. */
if (dst_ROI_height == 1)
phase_step_y = (uint32) ((src_ROI_height) << SCALER_PHASE_BITS);
/* if FIR scalar */
else if (scale_unit_sel_y == 0) {
/* Calculate the quotient ( src_ROI_height - 1 ) / ( dst_ROI_height - 1)
with u3.29 precision. Quotient is rounded up to the larger
29th decimal point. */
numerator = (src_ROI_height - 1) << SCALER_PHASE_BITS;
denominator = (dst_ROI_height - 1); /* never equals to 0 because of the "( dst_ROI_height == 1 )" case */
phase_step_y = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* Quotient is rounded up to the larger 29th decimal point. */
}
/* if M/N scalar */
else if (scale_unit_sel_y == 1) {
/* Calculate the quotient ( src_ROI_height ) / ( dst_ROI_height)
with u3.29 precision. Quotient is rounded down to the smaller
29th decimal point. */
numerator = (src_ROI_height) << SCALER_PHASE_BITS;
denominator = (dst_ROI_height);
phase_step_y = (uint32) mdp_do_div(numerator, denominator);
}
/* decide which set of FIR coefficients to use */
if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
xscale_filter_sel = 0;
else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
xscale_filter_sel = 1;
else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
xscale_filter_sel = 2;
else
xscale_filter_sel = 3;
if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
yscale_filter_sel = 0;
else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
yscale_filter_sel = 1;
else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
yscale_filter_sel = 2;
else
yscale_filter_sel = 3;
/* calculate phase init for the x direction */
/* if using FIR scalar */
if (scale_unit_sel_x == 0) {
if (dst_ROI_width == 1)
phase_init_x =
(uint32) ((src_ROI_width - 1) << SCALER_PHASE_BITS);
else
phase_init_x = 0;
}
/* M over N scalar */
else if (scale_unit_sel_x == 1)
phase_init_x = 0;
/* calculate phase init for the y direction
if using FIR scalar */
if (scale_unit_sel_y == 0) {
if (dst_ROI_height == 1)
phase_init_y =
(uint32) ((src_ROI_height -
1) << SCALER_PHASE_BITS);
else
phase_init_y = 0;
}
/* M over N scalar */
else if (scale_unit_sel_y == 1)
phase_init_y = 0;
/* write registers */
pval->phase_step_x = (uint32) phase_step_x;
pval->phase_step_y = (uint32) phase_step_y;
pval->phase_init_x = (uint32) phase_init_x;
pval->phase_init_y = (uint32) phase_init_y;
return;
}
void mdp_set_scale(MDPIBUF *iBuf,
uint32 dst_roi_width,
uint32 dst_roi_height,
boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr)
{
uint32 dst_roi_width_scale;
uint32 dst_roi_height_scale;
struct phase_val pval;
boolean use_pr;
uint32 ppp_scale_config = 0;
if (!inputRGB)
ppp_scale_config |= BIT(6);
if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) {
if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
dst_roi_width_scale = dst_roi_height;
dst_roi_height_scale = dst_roi_width;
} else {
dst_roi_width_scale = dst_roi_width;
dst_roi_height_scale = dst_roi_height;
}
if ((dst_roi_width_scale != iBuf->roi.width) ||
(dst_roi_height_scale != iBuf->roi.height) ||
(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr |=
(PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
mdp_calc_scaleInitPhase_3p1(iBuf->roi.width,
iBuf->roi.height,
dst_roi_width,
dst_roi_height,
iBuf->mdpImg.
mdpOp & MDPOP_ROT90, 1, 1,
&pval);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
pval.phase_init_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
pval.phase_init_y);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144,
pval.phase_step_x);
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148,
pval.phase_step_y);
use_pr = (inputRGB) && (outputRGB);
/* x-direction */
if ((dst_roi_width_scale == iBuf->roi.width) &&
!(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr &= ~PPP_OP_SCALE_X_ON;
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
8) {
if ((use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
ppp_scale_config |= (SCALE_U1_SET << 2);
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
6) {
if ((use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
}
ppp_scale_config |= (SCALE_D2_SET << 2);
} else
if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
4) {
if ((use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
}
ppp_scale_config |= (SCALE_D1_SET << 2);
} else
if (((dst_roi_width_scale * 4) / iBuf->roi.width) >=
1) {
if ((use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
}
ppp_scale_config |= (SCALE_D0_SET << 2);
} else
ppp_scale_config |= BIT(0);
/* y-direction */
if ((dst_roi_height_scale == iBuf->roi.height) &&
!(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
*pppop_reg_ptr &= ~PPP_OP_SCALE_Y_ON;
} else if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 8) {
if ((use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p8_to_8p0_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p8_to_8p0_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P8_TO_8P0_INDEX,
mdp_scale_0p8_to_8p0_C0,
mdp_scale_0p8_to_8p0_C1,
mdp_scale_0p8_to_8p0_C2,
mdp_scale_0p8_to_8p0_C3);
}
ppp_scale_config |= (SCALE_U1_SET << 4);
} else
if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 6) {
if ((use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p6_to_0p8_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p6_to_0p8_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P6_TO_0P8_INDEX,
mdp_scale_0p6_to_0p8_C0,
mdp_scale_0p6_to_0p8_C1,
mdp_scale_0p6_to_0p8_C2,
mdp_scale_0p6_to_0p8_C3);
}
ppp_scale_config |= (SCALE_D2_SET << 4);
} else
if (((dst_roi_height_scale * 10) /
iBuf->roi.height) > 4) {
if ((use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p4_to_0p6_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p4_to_0p6_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P4_TO_0P6_INDEX,
mdp_scale_0p4_to_0p6_C0,
mdp_scale_0p4_to_0p6_C1,
mdp_scale_0p4_to_0p6_C2,
mdp_scale_0p4_to_0p6_C3);
}
ppp_scale_config |= (SCALE_D1_SET << 4);
} else
if (((dst_roi_height_scale * 4) /
iBuf->roi.height) >= 1) {
if ((use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_PR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_PR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_pixel_repeat_C0,
mdp_scale_pixel_repeat_C1,
mdp_scale_pixel_repeat_C2,
mdp_scale_pixel_repeat_C3);
} else if ((!use_pr)
&& (mdp_scale_0p2_to_0p4_mode !=
MDP_SCALE_FIR)) {
mdp_scale_0p2_to_0p4_mode =
MDP_SCALE_FIR;
mdp_update_scale_table
(MDP_SCALE_0P2_TO_0P4_INDEX,
mdp_scale_0p2_to_0p4_C0,
mdp_scale_0p2_to_0p4_C1,
mdp_scale_0p2_to_0p4_C2,
mdp_scale_0p2_to_0p4_C3);
}
ppp_scale_config |= (SCALE_D0_SET << 4);
} else
ppp_scale_config |= BIT(1);
if (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING) {
ppp_scale_config |= BIT(7);
MDP_OUTP(MDP_BASE + 0x50020,
iBuf->mdpImg.sp_value);
}
MDP_OUTP(MDP_BASE + 0x10230, ppp_scale_config);
} else {
iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE);
}
}
}
void mdp_adjust_start_addr(uint8 **src0,
uint8 **src1,
int v_slice,
int h_slice,
int x,
int y,
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer)
{
switch (layer) {
case 0:
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0200, (y << 16) | (x));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0208,
(height << 16) | (width));
break;
case 1:
/* MDP 3.1 HW bug workaround */
if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) {
*src0 += (x + y * width) * bpp;
x = y = 0;
width = iBuf->roi.dst_width;
height = iBuf->roi.dst_height;
}
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0204, (y << 16) | (x));
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x020c,
(height << 16) | (width));
break;
case 2:
MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x019c, (y << 16) | (x));
break;
}
}
void mdp_set_blend_attr(MDPIBUF *iBuf,
uint32 *alpha,
uint32 *tpVal,
uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
{
int bg_alpha;
*alpha = iBuf->mdpImg.alpha;
*tpVal = iBuf->mdpImg.tpVal;
if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) {
*pppop_reg_ptr |= PPP_OP_ROT_ON |
PPP_OP_BLEND_ON | PPP_OP_BLEND_CONSTANT_ALPHA;
bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
PPP_BLEND_BG_ALPHA_REVERSE;
if (perPixelAlpha)
bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
else
bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
outpdw(MDP_BASE + 0x70010, bg_alpha);
if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
} else if (perPixelAlpha) {
*pppop_reg_ptr |= PPP_OP_ROT_ON |
PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
} else {
if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
&& (iBuf->mdpImg.alpha == 0xff)) {
iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
}
if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
|| (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
*pppop_reg_ptr |=
PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
PPP_OP_BLEND_CONSTANT_ALPHA |
PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
}
if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
*pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
}
}

View File

@ -0,0 +1,389 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/hrtimer.h>
#include <linux/vmalloc.h>
#include <linux/clk.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <mach/gpio.h>
#include "mdp.h"
#include "msm_fb.h"
#include "mddihost.h"
#ifdef CONFIG_FB_MSM_MDP40
#define MDP_SYNC_CFG_0 0x100
#define MDP_SYNC_STATUS_0 0x10c
#define MDP_PRIM_VSYNC_OUT_CTRL 0x118
#define MDP_PRIM_VSYNC_INIT_VAL 0x128
#else
#define MDP_SYNC_CFG_0 0x300
#define MDP_SYNC_STATUS_0 0x30c
#define MDP_PRIM_VSYNC_OUT_CTRL 0x318
#define MDP_PRIM_VSYNC_INIT_VAL 0x328
#endif
extern mddi_lcd_type mddi_lcd_idx;
extern spinlock_t mdp_spin_lock;
extern struct workqueue_struct *mdp_vsync_wq;
extern int lcdc_mode;
extern int vsync_mode;
#ifdef MDP_HW_VSYNC
int vsync_above_th = 4;
int vsync_start_th = 1;
int vsync_load_cnt;
struct clk *mdp_vsync_clk;
void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd)
{
if (mfd->use_mdp_vsync)
clk_enable(mdp_vsync_clk);
}
void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd)
{
if (mfd->use_mdp_vsync)
clk_disable(mdp_vsync_clk);
}
#endif
static void mdp_set_vsync(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
struct msm_fb_panel_data *pdata = NULL;
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_vsync_notifier == NULL))
return;
init_timer(&mfd->vsync_resync_timer);
mfd->vsync_resync_timer.function = mdp_set_vsync;
mfd->vsync_resync_timer.data = data;
mfd->vsync_resync_timer.expires =
jiffies + mfd->panel_info.lcd.vsync_notifier_period;
add_timer(&mfd->vsync_resync_timer);
if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on)
&& (!mfd->vsync_handler_pending)) {
mfd->vsync_handler_pending = TRUE;
if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) {
MSM_FB_INFO
("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n");
}
} else {
MSM_FB_DEBUG
("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n",
mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on,
mfd->vsync_handler_pending);
}
}
static void mdp_vsync_handler(void *data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
if (mfd->use_mdp_vsync) {
#ifdef MDP_HW_VSYNC
if (mfd->panel_power_on)
MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_0, vsync_load_cnt);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
#endif
} else {
mfd->last_vsync_timetick = ktime_get_real();
}
mfd->vsync_handler_pending = FALSE;
}
irqreturn_t mdp_hw_vsync_handler_proxy(int irq, void *data)
{
/*
* ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
* but getting inaccurate timing in mdp_vsync_handler()
* disable_irq(MDP_HW_VSYNC_IRQ);
*/
mdp_vsync_handler(data);
return IRQ_HANDLED;
}
#ifdef MDP_HW_VSYNC
static void mdp_set_sync_cfg_0(struct msm_fb_data_type *mfd, int vsync_cnt)
{
unsigned long cfg;
cfg = mfd->total_lcd_lines - 1;
cfg <<= MDP_SYNCFG_HGT_LOC;
if (mfd->panel_info.lcd.hw_vsync_mode)
cfg |= MDP_SYNCFG_VSYNC_EXT_EN;
cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt);
MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_0, cfg);
}
#endif
void mdp_config_vsync(struct msm_fb_data_type *mfd)
{
/* vsync on primary lcd only for now */
if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1)
|| (!vsync_mode)) {
goto err_handle;
}
if (mfd->panel_info.lcd.vsync_enable) {
mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch +
mfd->panel_info.lcd.v_front_porch +
mfd->panel_info.lcd.v_pulse_width;
mfd->total_lcd_lines =
mfd->panel_info.yres + mfd->total_porch_lines;
mfd->lcd_ref_usec_time =
100000000 / mfd->panel_info.lcd.refx100;
mfd->vsync_handler_pending = FALSE;
mfd->last_vsync_timetick.tv.sec = 0;
mfd->last_vsync_timetick.tv.nsec = 0;
#ifdef MDP_HW_VSYNC
if (mdp_vsync_clk == NULL)
mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk");
if (IS_ERR(mdp_vsync_clk)) {
printk(KERN_ERR "error: can't get mdp_vsync_clk!\n");
mfd->use_mdp_vsync = 0;
} else
mfd->use_mdp_vsync = 1;
if (mfd->use_mdp_vsync) {
uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem;
uint32 mdp_vsync_clk_speed_hz;
mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk);
if (mdp_vsync_clk_speed_hz == 0) {
mfd->use_mdp_vsync = 0;
} else {
/*
* Do this calculation in 2 steps for
* rounding uint32 properly.
*/
vsync_cnt_cfg_dem =
(mfd->panel_info.lcd.refx100 *
mfd->total_lcd_lines) / 100;
vsync_cnt_cfg =
(mdp_vsync_clk_speed_hz) /
vsync_cnt_cfg_dem;
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
FALSE);
mdp_hw_vsync_clk_enable(mfd);
mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg);
/*
* load the last line + 1 to be in the
* safety zone
*/
vsync_load_cnt = mfd->panel_info.yres;
/* line counter init value at the next pulse */
MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL,
vsync_load_cnt);
/*
* external vsync source pulse width and
* polarity flip
*/
MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL,
BIT(30) | BIT(0));
/* threshold */
MDP_OUTP(MDP_BASE + 0x200,
(vsync_above_th << 16) |
(vsync_start_th));
mdp_hw_vsync_clk_disable(mfd);
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK,
MDP_BLOCK_POWER_OFF, FALSE);
}
}
#else
mfd->use_mdp_vsync = 0;
hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler;
mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4);
#endif
mfd->channel_irq = 0;
if (mfd->panel_info.lcd.hw_vsync_mode) {
u32 vsync_gpio = mfd->vsync_gpio;
u32 ret;
if (vsync_gpio == -1) {
MSM_FB_INFO("vsync_gpio not defined!\n");
goto err_handle;
}
ret = gpio_tlmm_config(GPIO_CFG
(vsync_gpio,
(mfd->use_mdp_vsync) ? 1 : 0,
GPIO_INPUT,
GPIO_PULL_DOWN,
GPIO_2MA),
GPIO_ENABLE);
if (ret)
goto err_handle;
if (!mfd->use_mdp_vsync) {
mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio);
if (request_irq
(mfd->channel_irq,
&mdp_hw_vsync_handler_proxy,
IRQF_TRIGGER_FALLING, "VSYNC_GPIO",
(void *)mfd)) {
MSM_FB_INFO
("irq=%d failed! vsync_gpio=%d\n",
mfd->channel_irq,
vsync_gpio);
goto err_handle;
}
}
}
mdp_set_vsync((unsigned long)mfd);
}
return;
err_handle:
if (mfd->vsync_width_boundary)
vfree(mfd->vsync_width_boundary);
mfd->panel_info.lcd.vsync_enable = FALSE;
printk(KERN_ERR "%s: failed!\n", __func__);
}
void mdp_vsync_resync_workqueue_handler(struct work_struct *work)
{
struct msm_fb_data_type *mfd = NULL;
int vsync_fnc_enabled = FALSE;
struct msm_fb_panel_data *pdata = NULL;
mfd = container_of(work, struct msm_fb_data_type, vsync_resync_worker);
if (mfd) {
if (mfd->panel_power_on) {
pdata =
(struct msm_fb_panel_data *)mfd->pdev->dev.
platform_data;
/*
* we need to turn on MDP power if it uses MDP vsync
* HW block in SW mode
*/
if ((!mfd->panel_info.lcd.hw_vsync_mode) &&
(mfd->use_mdp_vsync) &&
(pdata) && (pdata->set_vsync_notifier != NULL)) {
/*
* enable pwr here since we can't enable it in
* vsync callback in isr mode
*/
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
FALSE);
}
if (pdata->set_vsync_notifier != NULL) {
vsync_fnc_enabled = TRUE;
pdata->set_vsync_notifier(mdp_vsync_handler,
(void *)mfd);
}
}
}
if ((mfd) && (!vsync_fnc_enabled))
mfd->vsync_handler_pending = FALSE;
}
boolean mdp_hw_vsync_set_handler(msm_fb_vsync_handler_type handler, void *data)
{
/*
* ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
* but getting inaccurate timing in mdp_vsync_handler()
* enable_irq(MDP_HW_VSYNC_IRQ);
*/
return TRUE;
}
uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd)
{
uint32 elapsed_usec_time;
uint32 lcd_line;
ktime_t last_vsync_timetick_local;
ktime_t curr_time;
unsigned long flag;
if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode))
return 0;
spin_lock_irqsave(&mdp_spin_lock, flag);
last_vsync_timetick_local = mfd->last_vsync_timetick;
spin_unlock_irqrestore(&mdp_spin_lock, flag);
curr_time = ktime_get_real();
elapsed_usec_time =
((curr_time.tv.sec - last_vsync_timetick_local.tv.sec) * 1000000) +
((curr_time.tv.nsec - last_vsync_timetick_local.tv.nsec) / 1000);
elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time;
/* lcd line calculation referencing to line counter = 0 */
lcd_line =
(elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time;
/* lcd line adjusment referencing to the actual line counter at vsync */
lcd_line =
(mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch +
lcd_line) % (mfd->total_lcd_lines + 1);
if (lcd_line > mfd->total_lcd_lines) {
MSM_FB_INFO
("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n");
}
return lcd_line;
}

View File

@ -0,0 +1,214 @@
/* arch/arm/mach-msm/memory.c
*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/mach/map.h>
#include "memory_ll.h"
#include <asm/cacheflush.h>
#if defined(CONFIG_MSM_NPA_REMOTE)
#include "npa_remote.h"
#include <linux/completion.h>
#include <linux/err.h>
#endif
int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
unsigned long pfn_addr = pfn << PAGE_SHIFT;
/*
if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
prot = pgprot_device(prot);
printk("remapping device %lx\n", prot);
}
*/
panic("Memory remap PFN stuff not done\n");
return remap_pfn_range(vma, addr, pfn, size, prot);
}
void *zero_page_strongly_ordered;
static void map_zero_page_strongly_ordered(void)
{
if (zero_page_strongly_ordered)
return;
/*
zero_page_strongly_ordered =
ioremap_strongly_ordered(page_to_pfn(empty_zero_page)
<< PAGE_SHIFT, PAGE_SIZE);
*/
panic("Strongly ordered memory functions not implemented\n");
}
void write_to_strongly_ordered_memory(void)
{
map_zero_page_strongly_ordered();
*(int *)zero_page_strongly_ordered = 0;
}
EXPORT_SYMBOL(write_to_strongly_ordered_memory);
void flush_axi_bus_buffer(void)
{
__asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
: : "r" (0) : "memory");
write_to_strongly_ordered_memory();
}
#define CACHE_LINE_SIZE 32
/* These cache related routines make the assumption that the associated
* physical memory is contiguous. They will operate on all (L1
* and L2 if present) caches.
*/
void clean_and_invalidate_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c14, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_flush_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void clean_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c10, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_clean_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void invalidate_caches(unsigned long vstart,
unsigned long length, unsigned long pstart)
{
unsigned long vaddr;
for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (vaddr));
#ifdef CONFIG_OUTER_CACHE
outer_inv_range(pstart, pstart + length);
#endif
asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
flush_axi_bus_buffer();
}
void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
{
void *unused_addr = NULL;
unsigned long addr, tmp_size, unused_size;
/* Allocate maximum size needed, see where it ends up.
* Then free it -- in this path there are no other allocators
* so we can depend on getting the same address back
* when we allocate a smaller piece that is aligned
* at the end (if necessary) and the piece we really want,
* then free the unused first piece.
*/
tmp_size = size + alignment - PAGE_SIZE;
addr = (unsigned long)alloc_bootmem(tmp_size);
free_bootmem(__pa(addr), tmp_size);
unused_size = alignment - (addr % alignment);
if (unused_size)
unused_addr = alloc_bootmem(unused_size);
addr = (unsigned long)alloc_bootmem(size);
if (unused_size)
free_bootmem(__pa(unused_addr), unused_size);
return (void *)addr;
}
#if defined(CONFIG_MSM_NPA_REMOTE)
struct npa_client *npa_memory_client;
#endif
static int change_memory_power_state(unsigned long start_pfn,
unsigned long nr_pages, int state)
{
#if defined(CONFIG_MSM_NPA_REMOTE)
static atomic_t node_created_flag = ATOMIC_INIT(1);
#else
unsigned long start;
unsigned long size;
unsigned long virtual;
#endif
int rc = 0;
#if defined(CONFIG_MSM_NPA_REMOTE)
if (atomic_dec_and_test(&node_created_flag)) {
/* Create NPA 'required' client. */
npa_memory_client = npa_create_sync_client(NPA_MEMORY_NODE_NAME,
"memory node", NPA_CLIENT_REQUIRED);
if (IS_ERR(npa_memory_client)) {
rc = PTR_ERR(npa_memory_client);
return rc;
}
}
rc = npa_issue_required_request(npa_memory_client, state);
#else
if (state == MEMORY_DEEP_POWERDOWN) {
/* simulate turning off memory by writing bit pattern into it */
start = start_pfn << PAGE_SHIFT;
size = nr_pages << PAGE_SHIFT;
virtual = __phys_to_virt(start);
memset((void *)virtual, 0x27, size);
}
#endif
return rc;
}
int platform_physical_remove_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages,
MEMORY_DEEP_POWERDOWN);
}
int platform_physical_add_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages, MEMORY_ACTIVE);
}
int platform_physical_low_power_pages(unsigned long start_pfn,
unsigned long nr_pages)
{
return change_memory_power_state(start_pfn, nr_pages,
MEMORY_SELF_REFRESH);
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#ifndef __ASM_ARCH_MEMORY_LL_H
#define __ASM_ARCH_MEMORY_LL_H
#define MAX_PHYSMEM_BITS 32
#define SECTION_SIZE_BITS 25
#define HAS_ARCH_IO_REMAP_PFN_RANGE
#ifndef __ASSEMBLY__
void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
void clean_caches(unsigned long, unsigned long, unsigned long);
void invalidate_caches(unsigned long, unsigned long, unsigned long);
int platform_physical_remove_pages(unsigned long, unsigned long);
int platform_physical_add_pages(unsigned long, unsigned long);
int platform_physical_low_power_pages(unsigned long, unsigned long);
#ifdef CONFIG_ARCH_MSM_ARM11
void write_to_strongly_ordered_memory(void);
#include <asm/mach-types.h>
#define arch_barrier_extra() do \
{ if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \
write_to_strongly_ordered_memory(); \
} while (0)
#endif
#ifdef CONFIG_CACHE_L2X0
extern void l2x0_cache_sync(void);
#define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0)
#endif
#endif
#ifdef CONFIG_ARCH_MSM_SCORPION
#define arch_has_speculative_dfetch() 1
#endif
#endif
/* these correspond to values known by the modem */
#define MEMORY_DEEP_POWERDOWN 0
#define MEMORY_SELF_REFRESH 1
#define MEMORY_ACTIVE 2
#define NPA_MEMORY_NODE_NAME "/mem/ebi1/cs1"

2354
drivers/staging/msm/msm_fb.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_H
#define MSM_FB_H
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <mach/board.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <mach/memory.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
#include <linux/fb.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include "msm_fb_panel.h"
#include "mdp.h"
#define MSM_FB_DEFAULT_PAGE_SIZE 2
#define MFD_KEY 0x11161126
#define MSM_FB_MAX_DEV_LIST 32
struct disp_info_type_suspend {
boolean op_enable;
boolean sw_refreshing_enable;
boolean panel_power_on;
};
struct msm_fb_data_type {
__u32 key;
__u32 index;
__u32 ref_cnt;
__u32 fb_page;
panel_id_type panel;
struct msm_panel_info panel_info;
DISP_TARGET dest;
struct fb_info *fbi;
boolean op_enable;
uint32 fb_imgType;
boolean sw_currently_refreshing;
boolean sw_refreshing_enable;
boolean hw_refresh;
MDPIBUF ibuf;
boolean ibuf_flushed;
struct timer_list refresh_timer;
struct completion refresher_comp;
boolean pan_waiting;
struct completion pan_comp;
/* vsync */
boolean use_mdp_vsync;
__u32 vsync_gpio;
__u32 total_lcd_lines;
__u32 total_porch_lines;
__u32 lcd_ref_usec_time;
__u32 refresh_timer_duration;
struct hrtimer dma_hrtimer;
boolean panel_power_on;
struct work_struct dma_update_worker;
struct semaphore sem;
struct timer_list vsync_resync_timer;
boolean vsync_handler_pending;
struct work_struct vsync_resync_worker;
ktime_t last_vsync_timetick;
__u32 *vsync_width_boundary;
unsigned int pmem_id;
struct disp_info_type_suspend suspend;
__u32 channel_irq;
struct mdp_dma_data *dma;
void (*dma_fnc) (struct msm_fb_data_type *mfd);
int (*cursor_update) (struct fb_info *info,
struct fb_cursor *cursor);
int (*lut_update) (struct fb_info *info,
struct fb_cmap *cmap);
int (*do_histogram) (struct fb_info *info,
struct mdp_histogram *hist);
void *cursor_buf;
void *cursor_buf_phys;
void *cmd_port;
void *data_port;
void *data_port_phys;
__u32 bl_level;
struct platform_device *pdev;
__u32 var_xres;
__u32 var_yres;
__u32 var_pixclock;
#ifdef MSM_FB_ENABLE_DBGFS
struct dentry *sub_dir;
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
struct early_suspend mddi_early_suspend;
struct early_suspend mddi_ext_early_suspend;
#endif
u32 mdp_fb_page_protection;
int allow_set_offset;
};
struct dentry *msm_fb_get_debugfs_root(void);
void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
u32 *var);
void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl,
u32 save);
void msm_fb_add_device(struct platform_device *pdev);
int msm_fb_detect_client(const char *name);
#ifdef CONFIG_FB_BACKLIGHT
void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
#endif
#endif /* MSM_FB_H */

View File

@ -0,0 +1,79 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/backlight.h>
#include "msm_fb.h"
static int msm_fb_bl_get_brightness(struct backlight_device *pbd)
{
return pbd->props.brightness;
}
static int msm_fb_bl_update_status(struct backlight_device *pbd)
{
struct msm_fb_data_type *mfd = bl_get_data(pbd);
__u32 bl_lvl;
bl_lvl = pbd->props.brightness;
bl_lvl = mfd->fbi->bl_curve[bl_lvl];
msm_fb_set_backlight(mfd, bl_lvl, 1);
return 0;
}
static struct backlight_ops msm_fb_bl_ops = {
.get_brightness = msm_fb_bl_get_brightness,
.update_status = msm_fb_bl_update_status,
};
void msm_fb_config_backlight(struct msm_fb_data_type *mfd)
{
struct msm_fb_panel_data *pdata;
struct backlight_device *pbd;
struct fb_info *fbi;
char name[16];
fbi = mfd->fbi;
pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if ((pdata) && (pdata->set_backlight)) {
snprintf(name, sizeof(name), "msmfb_bl%d", mfd->index);
pbd =
backlight_device_register(name, fbi->dev, mfd,
&msm_fb_bl_ops);
if (!IS_ERR(pbd)) {
fbi->bl_dev = pbd;
fb_bl_default_curve(fbi,
0,
mfd->panel_info.bl_min,
mfd->panel_info.bl_max);
pbd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
pbd->props.brightness = FB_BACKLIGHT_LEVELS - 1;
backlight_update_status(pbd);
} else {
fbi->bl_dev = NULL;
printk(KERN_ERR "msm_fb: backlight_device_register failed!\n");
}
}
}

View File

@ -0,0 +1,201 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_DEF_H
#define MSM_FB_DEF_H
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include "msm_mdp.h"
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include "linux/proc_fs.h"
#include <mach/hardware.h>
#include <linux/io.h>
#include <linux/fb.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <linux/platform_device.h>
typedef s64 int64;
typedef s32 int32;
typedef s16 int16;
typedef s8 int8;
typedef u64 uint64;
typedef u32 uint32;
typedef u16 uint16;
typedef u8 uint8;
typedef s32 int4;
typedef s16 int2;
typedef s8 int1;
typedef u32 uint4;
typedef u16 uint2;
typedef u8 uint1;
typedef u32 dword;
typedef u16 word;
typedef u8 byte;
typedef unsigned int boolean;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define MSM_FB_ENABLE_DBGFS
#define FEATURE_MDDI
#define outp32(addr, val) writel(val, addr)
#define outp16(addr, val) writew(val, addr)
#define outp8(addr, val) writeb(val, addr)
#define outp(addr, val) outp32(addr, val)
#ifndef MAX
#define MAX( x, y ) (((x) > (y)) ? (x) : (y))
#endif
#ifndef MIN
#define MIN( x, y ) (((x) < (y)) ? (x) : (y))
#endif
/*--------------------------------------------------------------------------*/
#define inp32(addr) readl(addr)
#define inp16(addr) readw(addr)
#define inp8(addr) readb(addr)
#define inp(addr) inp32(addr)
#define inpw(port) readw(port)
#define outpw(port, val) writew(val, port)
#define inpdw(port) readl(port)
#define outpdw(port, val) writel(val, port)
#define clk_busy_wait(x) msleep_interruptible((x)/1000)
#define memory_barrier()
#define assert(expr) \
if(!(expr)) { \
printk(KERN_ERR "msm_fb: assertion failed! %s,%s,%s,line=%d\n",\
#expr, __FILE__, __func__, __LINE__); \
}
#define ASSERT(x) assert(x)
#define DISP_EBI2_LOCAL_DEFINE
#ifdef DISP_EBI2_LOCAL_DEFINE
#define LCD_PRIM_BASE_PHYS 0x98000000
#define LCD_SECD_BASE_PHYS 0x9c000000
#define EBI2_PRIM_LCD_RS_PIN 0x20000
#define EBI2_SECD_LCD_RS_PIN 0x20000
#define EBI2_PRIM_LCD_CLR 0xC0
#define EBI2_PRIM_LCD_SEL 0x40
#define EBI2_SECD_LCD_CLR 0x300
#define EBI2_SECD_LCD_SEL 0x100
#endif
extern u32 msm_fb_msg_level;
/*
* Message printing priorities:
* LEVEL 0 KERN_EMERG (highest priority)
* LEVEL 1 KERN_ALERT
* LEVEL 2 KERN_CRIT
* LEVEL 3 KERN_ERR
* LEVEL 4 KERN_WARNING
* LEVEL 5 KERN_NOTICE
* LEVEL 6 KERN_INFO
* LEVEL 7 KERN_DEBUG (Lowest priority)
*/
#define MSM_FB_EMERG(msg, ...) \
if (msm_fb_msg_level > 0) \
printk(KERN_EMERG msg, ## __VA_ARGS__);
#define MSM_FB_ALERT(msg, ...) \
if (msm_fb_msg_level > 1) \
printk(KERN_ALERT msg, ## __VA_ARGS__);
#define MSM_FB_CRIT(msg, ...) \
if (msm_fb_msg_level > 2) \
printk(KERN_CRIT msg, ## __VA_ARGS__);
#define MSM_FB_ERR(msg, ...) \
if (msm_fb_msg_level > 3) \
printk(KERN_ERR msg, ## __VA_ARGS__);
#define MSM_FB_WARNING(msg, ...) \
if (msm_fb_msg_level > 4) \
printk(KERN_WARNING msg, ## __VA_ARGS__);
#define MSM_FB_NOTICE(msg, ...) \
if (msm_fb_msg_level > 5) \
printk(KERN_NOTICE msg, ## __VA_ARGS__);
#define MSM_FB_INFO(msg, ...) \
if (msm_fb_msg_level > 6) \
printk(KERN_INFO msg, ## __VA_ARGS__);
#define MSM_FB_DEBUG(msg, ...) \
if (msm_fb_msg_level > 7) \
printk(KERN_DEBUG msg, ## __VA_ARGS__);
#ifdef MSM_FB_C
unsigned char *msm_mdp_base;
unsigned char *msm_pmdh_base;
unsigned char *msm_emdh_base;
#else
extern unsigned char *msm_mdp_base;
extern unsigned char *msm_pmdh_base;
extern unsigned char *msm_emdh_base;
#endif
#endif /* MSM_FB_DEF_H */

View File

@ -0,0 +1,136 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include "msm_fb_panel.h"
int panel_next_on(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_panel_data *pdata;
struct msm_fb_panel_data *next_pdata;
struct platform_device *next_pdev;
pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
if (pdata) {
next_pdev = pdata->next;
if (next_pdev) {
next_pdata =
(struct msm_fb_panel_data *)next_pdev->dev.
platform_data;
if ((next_pdata) && (next_pdata->on))
ret = next_pdata->on(next_pdev);
}
}
return ret;
}
int panel_next_off(struct platform_device *pdev)
{
int ret = 0;
struct msm_fb_panel_data *pdata;
struct msm_fb_panel_data *next_pdata;
struct platform_device *next_pdev;
pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
if (pdata) {
next_pdev = pdata->next;
if (next_pdev) {
next_pdata =
(struct msm_fb_panel_data *)next_pdev->dev.
platform_data;
if ((next_pdata) && (next_pdata->on))
ret = next_pdata->off(next_pdev);
}
}
return ret;
}
struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
u32 type, u32 id)
{
struct platform_device *this_dev = NULL;
char dev_name[16];
switch (type) {
case EBI2_PANEL:
snprintf(dev_name, sizeof(dev_name), "ebi2_lcd");
break;
case MDDI_PANEL:
snprintf(dev_name, sizeof(dev_name), "mddi");
break;
case EXT_MDDI_PANEL:
snprintf(dev_name, sizeof(dev_name), "mddi_ext");
break;
case TV_PANEL:
snprintf(dev_name, sizeof(dev_name), "tvenc");
break;
case HDMI_PANEL:
case LCDC_PANEL:
snprintf(dev_name, sizeof(dev_name), "lcdc");
break;
default:
return NULL;
}
if (pdata != NULL)
pdata->next = NULL;
else
return NULL;
this_dev =
platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id);
if (this_dev) {
if (platform_device_add_data
(this_dev, pdata, sizeof(struct msm_fb_panel_data))) {
printk
("msm_fb_device_alloc: platform_device_add_data failed!\n");
platform_device_put(this_dev);
return NULL;
}
}
return this_dev;
}

View File

@ -0,0 +1,145 @@
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef MSM_FB_PANEL_H
#define MSM_FB_PANEL_H
#include "msm_fb_def.h"
struct msm_fb_data_type;
typedef void (*msm_fb_vsync_handler_type) (void *arg);
/* panel id type */
typedef struct panel_id_s {
uint16 id;
uint16 type;
} panel_id_type;
/* panel type list */
#define NO_PANEL 0xffff /* No Panel */
#define MDDI_PANEL 1 /* MDDI */
#define EBI2_PANEL 2 /* EBI2 */
#define LCDC_PANEL 3 /* internal LCDC type */
#define EXT_MDDI_PANEL 4 /* Ext.MDDI */
#define TV_PANEL 5 /* TV */
#define HDMI_PANEL 6 /* HDMI TV */
/* panel class */
typedef enum {
DISPLAY_LCD = 0, /* lcd = ebi2/mddi */
DISPLAY_LCDC, /* lcdc */
DISPLAY_TV, /* TV Out */
DISPLAY_EXT_MDDI, /* External MDDI */
} DISP_TARGET;
/* panel device locaiton */
typedef enum {
DISPLAY_1 = 0, /* attached as first device */
DISPLAY_2, /* attached on second device */
MAX_PHYS_TARGET_NUM,
} DISP_TARGET_PHYS;
/* panel info type */
struct lcd_panel_info {
__u32 vsync_enable;
__u32 refx100;
__u32 v_back_porch;
__u32 v_front_porch;
__u32 v_pulse_width;
__u32 hw_vsync_mode;
__u32 vsync_notifier_period;
};
struct lcdc_panel_info {
__u32 h_back_porch;
__u32 h_front_porch;
__u32 h_pulse_width;
__u32 v_back_porch;
__u32 v_front_porch;
__u32 v_pulse_width;
__u32 border_clr;
__u32 underflow_clr;
__u32 hsync_skew;
};
struct mddi_panel_info {
__u32 vdopkt;
};
struct msm_panel_info {
__u32 xres;
__u32 yres;
__u32 bpp;
__u32 type;
__u32 wait_cycle;
DISP_TARGET_PHYS pdest;
__u32 bl_max;
__u32 bl_min;
__u32 fb_num;
__u32 clk_rate;
__u32 clk_min;
__u32 clk_max;
__u32 frame_count;
union {
struct mddi_panel_info mddi;
};
union {
struct lcd_panel_info lcd;
struct lcdc_panel_info lcdc;
};
};
struct msm_fb_panel_data {
struct msm_panel_info panel_info;
void (*set_rect) (int x, int y, int xres, int yres);
void (*set_vsync_notifier) (msm_fb_vsync_handler_type, void *arg);
void (*set_backlight) (struct msm_fb_data_type *);
/* function entry chain */
int (*on) (struct platform_device *pdev);
int (*off) (struct platform_device *pdev);
struct platform_device *next;
};
/*===========================================================================
FUNCTIONS PROTOTYPES
============================================================================*/
struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
u32 type, u32 id);
int panel_next_on(struct platform_device *pdev);
int panel_next_off(struct platform_device *pdev);
int lcdc_device_register(struct msm_panel_info *pinfo);
int mddi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
#endif /* MSM_FB_PANEL_H */

Some files were not shown because too many files have changed in this diff Show More